mirror of
https://github.com/ClusterM/open-bamboo-networking.git
synced 2026-10-21 10:39:52 -05:00
356 lines
11 KiB
C++
356 lines
11 KiB
C++
// Smoke test: ensures every symbol Bambu Studio resolves via GetProcAddress
|
|
// (Windows) or dlsym (POSIX) is present in the built plugin, that
|
|
// bambu_network_get_version() returns a non-empty, SLIC3R_VERSION-compatible
|
|
// string, and that bambu_network_create_agent / destroy_agent round-trip a
|
|
// std::string across the DLL boundary without crashing.
|
|
//
|
|
// Dual purpose: (a) cheap CI sanity check that mirrors what Studio does at
|
|
// load time; (b) lets us validate Windows builds without depending on
|
|
// Studio's GUI starting up successfully (it has its own pre-existing
|
|
// initialization issues unrelated to this plugin).
|
|
|
|
#if defined(_WIN32)
|
|
# ifndef WIN32_LEAN_AND_MEAN
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# endif
|
|
# ifndef NOMINMAX
|
|
# define NOMINMAX
|
|
# endif
|
|
# include <windows.h>
|
|
#else
|
|
# include <dlfcn.h>
|
|
#endif
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
#if defined(_WIN32)
|
|
using lib_handle_t = HMODULE;
|
|
|
|
lib_handle_t open_lib(const char* path)
|
|
{
|
|
return ::LoadLibraryA(path);
|
|
}
|
|
|
|
void* lookup_sym(lib_handle_t h, const char* name)
|
|
{
|
|
return reinterpret_cast<void*>(::GetProcAddress(h, name));
|
|
}
|
|
|
|
void close_lib(lib_handle_t h) { ::FreeLibrary(h); }
|
|
|
|
const char* last_error_str()
|
|
{
|
|
static char buf[512];
|
|
DWORD err = ::GetLastError();
|
|
char* msg = nullptr;
|
|
const DWORD n = ::FormatMessageA(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
reinterpret_cast<LPSTR>(&msg), 0, nullptr);
|
|
if (n > 0 && msg) {
|
|
std::snprintf(buf, sizeof(buf), "win32 error %lu (%.*s)",
|
|
static_cast<unsigned long>(err),
|
|
static_cast<int>(n), msg);
|
|
::LocalFree(msg);
|
|
} else {
|
|
std::snprintf(buf, sizeof(buf), "win32 error %lu",
|
|
static_cast<unsigned long>(err));
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void add_plugin_dir_to_dll_search(const char* plugin_path)
|
|
{
|
|
const std::filesystem::path dir =
|
|
std::filesystem::path(plugin_path).parent_path();
|
|
if (dir.empty()) return;
|
|
// Let LoadLibrary resolve deps colocated with the plugin (CI build dir).
|
|
::SetDllDirectoryA(dir.string().c_str());
|
|
}
|
|
#else
|
|
using lib_handle_t = void*;
|
|
|
|
lib_handle_t open_lib(const char* path)
|
|
{
|
|
return ::dlopen(path, RTLD_LAZY);
|
|
}
|
|
|
|
void* lookup_sym(lib_handle_t h, const char* name)
|
|
{
|
|
return ::dlsym(h, name);
|
|
}
|
|
|
|
void close_lib(lib_handle_t h) { ::dlclose(h); }
|
|
|
|
const char* last_error_str()
|
|
{
|
|
const char* e = ::dlerror();
|
|
return e ? e : "(null)";
|
|
}
|
|
#endif
|
|
|
|
} // namespace
|
|
|
|
namespace {
|
|
|
|
// Canonical list copied from BambuStudio's NetworkAgent.cpp resolver and the
|
|
// real plugin's ELF exports. Keep this list in sync when Studio changes.
|
|
const char* kBambuNetworkSymbols[] = {
|
|
"bambu_network_check_debug_consistent",
|
|
"bambu_network_get_version",
|
|
"bambu_network_create_agent",
|
|
"bambu_network_destroy_agent",
|
|
"bambu_network_init_log",
|
|
"bambu_network_set_config_dir",
|
|
"bambu_network_set_cert_file",
|
|
"bambu_network_set_country_code",
|
|
"bambu_network_start",
|
|
"bambu_network_set_on_ssdp_msg_fn",
|
|
"bambu_network_set_on_user_login_fn",
|
|
"bambu_network_set_on_printer_connected_fn",
|
|
"bambu_network_set_on_server_connected_fn",
|
|
"bambu_network_set_on_http_error_fn",
|
|
"bambu_network_set_get_country_code_fn",
|
|
"bambu_network_set_on_subscribe_failure_fn",
|
|
"bambu_network_set_on_message_fn",
|
|
"bambu_network_set_on_user_message_fn",
|
|
"bambu_network_set_on_local_connect_fn",
|
|
"bambu_network_set_on_local_message_fn",
|
|
"bambu_network_set_queue_on_main_fn",
|
|
"bambu_network_set_server_callback",
|
|
"bambu_network_connect_server",
|
|
"bambu_network_is_server_connected",
|
|
"bambu_network_refresh_connection",
|
|
"bambu_network_start_subscribe",
|
|
"bambu_network_stop_subscribe",
|
|
"bambu_network_add_subscribe",
|
|
"bambu_network_del_subscribe",
|
|
"bambu_network_enable_multi_machine",
|
|
"bambu_network_send_message",
|
|
"bambu_network_connect_printer",
|
|
"bambu_network_disconnect_printer",
|
|
"bambu_network_send_message_to_printer",
|
|
"bambu_network_update_cert",
|
|
"bambu_network_install_device_cert",
|
|
"bambu_network_start_discovery",
|
|
"bambu_network_change_user",
|
|
"bambu_network_is_user_login",
|
|
"bambu_network_user_logout",
|
|
"bambu_network_get_user_id",
|
|
"bambu_network_get_user_name",
|
|
"bambu_network_get_user_avatar",
|
|
"bambu_network_get_user_nickanme",
|
|
"bambu_network_build_login_cmd",
|
|
"bambu_network_build_logout_cmd",
|
|
"bambu_network_build_login_info",
|
|
"bambu_network_get_my_profile",
|
|
"bambu_network_get_my_token",
|
|
"bambu_network_get_user_info",
|
|
"bambu_network_ping_bind",
|
|
"bambu_network_bind_detect",
|
|
"bambu_network_bind",
|
|
"bambu_network_unbind",
|
|
"bambu_network_request_bind_ticket",
|
|
"bambu_network_query_bind_status",
|
|
"bambu_network_modify_printer_name",
|
|
"bambu_network_report_consent",
|
|
"bambu_network_get_bambulab_host",
|
|
"bambu_network_get_user_selected_machine",
|
|
"bambu_network_set_user_selected_machine",
|
|
"bambu_network_start_print",
|
|
"bambu_network_start_local_print_with_record",
|
|
"bambu_network_start_send_gcode_to_sdcard",
|
|
"bambu_network_start_local_print",
|
|
"bambu_network_start_sdcard_print",
|
|
"bambu_network_get_user_presets",
|
|
"bambu_network_request_setting_id",
|
|
"bambu_network_put_setting",
|
|
"bambu_network_get_setting_list",
|
|
"bambu_network_get_setting_list2",
|
|
"bambu_network_delete_setting",
|
|
"bambu_network_get_studio_info_url",
|
|
"bambu_network_set_extra_http_header",
|
|
"bambu_network_get_my_message",
|
|
"bambu_network_check_user_task_report",
|
|
"bambu_network_get_user_print_info",
|
|
"bambu_network_get_user_tasks",
|
|
"bambu_network_get_filament_spools",
|
|
"bambu_network_create_filament_spool",
|
|
"bambu_network_update_filament_spool",
|
|
"bambu_network_delete_filament_spools",
|
|
"bambu_network_get_filament_config",
|
|
#if ABI_VERSION >= 0x020801
|
|
"bambu_network_sync_ams_filaments",
|
|
#endif
|
|
#if ABI_VERSION >= 0x020802
|
|
"bambu_network_sync_slot_mappings",
|
|
#endif
|
|
#if ABI_VERSION >= 0x020803
|
|
"bambu_network_get_soft_match_pending",
|
|
"bambu_network_post_soft_match_pending",
|
|
#endif
|
|
#if ABI_VERSION >= 0x020804
|
|
"bambu_network_post_device_region",
|
|
#endif
|
|
"bambu_network_get_printer_firmware",
|
|
"bambu_network_get_task_plate_index",
|
|
"bambu_network_get_subtask_info",
|
|
"bambu_network_get_slice_info",
|
|
"bambu_network_get_camera_url",
|
|
"bambu_network_get_camera_url_for_golive",
|
|
"bambu_network_get_hms_snapshot",
|
|
"bambu_network_get_design_staffpick",
|
|
"bambu_network_start_publish",
|
|
"bambu_network_get_model_publish_url",
|
|
"bambu_network_get_subtask",
|
|
"bambu_network_get_model_mall_home_url",
|
|
"bambu_network_get_model_mall_detail_url",
|
|
"bambu_network_put_model_mall_rating",
|
|
"bambu_network_get_oss_config",
|
|
"bambu_network_put_rating_picture_oss",
|
|
"bambu_network_get_model_mall_rating",
|
|
"bambu_network_get_mw_user_preference",
|
|
"bambu_network_get_mw_user_4ulist",
|
|
"bambu_network_track_enable",
|
|
"bambu_network_track_remove_files",
|
|
"bambu_network_track_event",
|
|
"bambu_network_track_header",
|
|
"bambu_network_track_update_property",
|
|
"bambu_network_track_get_property",
|
|
};
|
|
|
|
const char* kFtSymbols[] = {
|
|
"ft_abi_version",
|
|
"ft_free",
|
|
"ft_job_result_destroy",
|
|
"ft_job_msg_destroy",
|
|
"ft_tunnel_create",
|
|
"ft_tunnel_retain",
|
|
"ft_tunnel_release",
|
|
"ft_tunnel_start_connect",
|
|
"ft_tunnel_sync_connect",
|
|
"ft_tunnel_set_status_cb",
|
|
"ft_tunnel_shutdown",
|
|
"ft_job_create",
|
|
"ft_job_retain",
|
|
"ft_job_release",
|
|
"ft_job_set_result_cb",
|
|
"ft_job_get_result",
|
|
"ft_tunnel_start_job",
|
|
"ft_job_cancel",
|
|
"ft_job_set_msg_cb",
|
|
"ft_job_try_get_msg",
|
|
"ft_job_get_msg",
|
|
};
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
if (argc != 2) {
|
|
std::fprintf(stderr,
|
|
"usage: %s <path-to-bambu_networking.{so,dll}>\n",
|
|
argv[0]);
|
|
return 2;
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
add_plugin_dir_to_dll_search(argv[1]);
|
|
#endif
|
|
lib_handle_t h = open_lib(argv[1]);
|
|
if (!h) {
|
|
std::fprintf(stderr, "open_lib failed: %s\n", last_error_str());
|
|
return 1;
|
|
}
|
|
|
|
int missing = 0;
|
|
for (const char* name : kBambuNetworkSymbols) {
|
|
if (!lookup_sym(h, name)) {
|
|
std::fprintf(stderr, "MISSING: %s\n", name);
|
|
++missing;
|
|
}
|
|
}
|
|
for (const char* name : kFtSymbols) {
|
|
if (!lookup_sym(h, name)) {
|
|
std::fprintf(stderr, "MISSING: %s\n", name);
|
|
++missing;
|
|
}
|
|
}
|
|
|
|
using fn_ver = std::string (*)();
|
|
using fn_dbg = bool (*)(bool);
|
|
using fn_create = void* (*)(std::string);
|
|
using fn_destroy = int (*)(void*);
|
|
using fn_set_dir = int (*)(void*, std::string);
|
|
|
|
auto ver = reinterpret_cast<fn_ver>(lookup_sym(h, "bambu_network_get_version"));
|
|
auto dbg = reinterpret_cast<fn_dbg>(lookup_sym(h, "bambu_network_check_debug_consistent"));
|
|
auto create_a = reinterpret_cast<fn_create>(lookup_sym(h, "bambu_network_create_agent"));
|
|
auto destroy_a = reinterpret_cast<fn_destroy>(lookup_sym(h, "bambu_network_destroy_agent"));
|
|
auto set_dir = reinterpret_cast<fn_set_dir>(lookup_sym(h, "bambu_network_set_config_dir"));
|
|
|
|
if (ver) {
|
|
std::string v = ver();
|
|
std::printf("version: %s\n", v.c_str());
|
|
if (v.size() < 8) {
|
|
std::fprintf(stderr, "VERSION TOO SHORT (need >=8 chars)\n");
|
|
++missing;
|
|
}
|
|
}
|
|
if (dbg) {
|
|
std::printf("debug_consistent(false)=%d true=%d\n", dbg(false), dbg(true));
|
|
}
|
|
|
|
// Round-trip std::string across the DLL boundary. Same flow Studio uses:
|
|
// create_agent("<log_dir>") -> set_config_dir(agent, "<data_dir>") ->
|
|
// destroy_agent(agent). On Windows this also exercises the heap shared
|
|
// between the host (test exe) and the plugin DLL via MSVCRT/UCRT, which
|
|
// is the most common ABI pitfall when mixing /MT and /MD or different
|
|
// toolsets.
|
|
if (create_a && destroy_a) {
|
|
std::string log_dir = ".";
|
|
void* agent = create_a(log_dir);
|
|
std::printf("create_agent(\"%s\") -> %p\n", log_dir.c_str(), agent);
|
|
if (!agent) {
|
|
std::fprintf(stderr, "create_agent returned null\n");
|
|
++missing;
|
|
} else {
|
|
if (set_dir) {
|
|
int rc = set_dir(agent, std::string("."));
|
|
std::printf("set_config_dir(\".\") -> %d\n", rc);
|
|
}
|
|
int rc = destroy_a(agent);
|
|
std::printf("destroy_agent -> %d\n", rc);
|
|
}
|
|
}
|
|
|
|
// ft_abi_version must be 1 per FileTransferUtils.hpp.
|
|
using fn_ft = int (*)();
|
|
auto ft_ver = reinterpret_cast<fn_ft>(lookup_sym(h, "ft_abi_version"));
|
|
if (ft_ver) {
|
|
int v = ft_ver();
|
|
std::printf("ft_abi_version: %d\n", v);
|
|
if (v != 1) {
|
|
std::fprintf(stderr, "ft_abi_version must be 1 (got %d)\n", v);
|
|
++missing;
|
|
}
|
|
}
|
|
|
|
close_lib(h);
|
|
if (missing) {
|
|
std::fprintf(stderr, "%d problem(s) found\n", missing);
|
|
return 1;
|
|
}
|
|
std::printf("OK (all %zu + %zu symbols present)\n",
|
|
sizeof(kBambuNetworkSymbols) / sizeof(*kBambuNetworkSymbols),
|
|
sizeof(kFtSymbols) / sizeof(*kFtSymbols));
|
|
return 0;
|
|
}
|