bridge
This commit is contained in:
parent
9a78a706fb
commit
836be36a48
26 changed files with 924 additions and 604 deletions
40
.github/workflows/build_windows_bridge.yml
vendored
40
.github/workflows/build_windows_bridge.yml
vendored
|
|
@ -146,49 +146,19 @@ jobs:
|
|||
run: .\build_release_vs.bat slicer
|
||||
|
||||
|
||||
- name: Ensure WSL is available for runtime validation
|
||||
|
||||
- name: Note about hosted-runner WSL validation
|
||||
shell: pwsh
|
||||
run: |
|
||||
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
|
||||
if (!(Test-Path $wsl)) { throw 'wsl.exe not found' }
|
||||
|
||||
$ready = $false
|
||||
try {
|
||||
& $wsl --status
|
||||
if ($LASTEXITCODE -eq 0) { $ready = $true }
|
||||
} catch {}
|
||||
|
||||
if (-not $ready) {
|
||||
& $wsl --install --no-distribution
|
||||
if ($LASTEXITCODE -ne 0) { throw 'wsl --install --no-distribution failed' }
|
||||
}
|
||||
|
||||
& $wsl --update
|
||||
if ($LASTEXITCODE -ne 0) { throw 'wsl --update failed' }
|
||||
|
||||
& $wsl --status
|
||||
if ($LASTEXITCODE -ne 0) { throw 'WSL is still not ready after install/update' }
|
||||
Write-Host 'Hosted GitHub Windows runners are packaging-only for this bridge.'
|
||||
Write-Host 'Real WSL validation must run on a self-hosted Windows machine or on the end user machine at first launch.'
|
||||
Write-Host 'The bundled install_runtime.ps1 still performs first-run install and repair.'
|
||||
|
||||
- name: Show packaged Orca runtime files
|
||||
shell: pwsh
|
||||
run: |
|
||||
Get-ChildItem -Force "$env:GITHUB_WORKSPACE\build\OrcaSlicer" | Format-Table Name, Length -AutoSize
|
||||
|
||||
- name: Install bundled WSL2 Orca runtime into live plugins dir
|
||||
shell: pwsh
|
||||
run: |
|
||||
& "$env:GITHUB_WORKSPACE\build\OrcaSlicer\install_runtime.ps1" -ReplaceExisting
|
||||
|
||||
- name: Show live Orca plugin dir after installer
|
||||
shell: pwsh
|
||||
run: |
|
||||
Get-ChildItem -Force "$env:APPDATA\OrcaSlicer\plugins" | Format-Table Name, Length -AutoSize
|
||||
|
||||
- name: Validate live Orca plugin dir bootstrap package
|
||||
shell: pwsh
|
||||
run: |
|
||||
& "$env:APPDATA\OrcaSlicer\plugins\verify_runtime.ps1" -PackageDir "$env:APPDATA\OrcaSlicer\plugins" -PluginCacheDir "$env:APPDATA\OrcaSlicer\plugins" -AllowMissingLinuxPlugin
|
||||
|
||||
- name: Create installer Win
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
shell: pwsh
|
||||
|
|
|
|||
56
shared/BambuBridge/Auth/BridgeAuthPayload.hpp
Normal file
56
shared/BambuBridge/Auth/BridgeAuthPayload.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace Slic3r::BambuBridge {
|
||||
|
||||
inline bool looks_like_change_user_data(const nlohmann::json& j)
|
||||
{
|
||||
if (!j.is_object())
|
||||
return false;
|
||||
return j.contains("token") ||
|
||||
j.contains("access_token") ||
|
||||
j.contains("refresh_token") ||
|
||||
j.contains("code") ||
|
||||
j.contains("user") ||
|
||||
j.contains("user_id") ||
|
||||
j.contains("uidStr");
|
||||
}
|
||||
|
||||
inline nlohmann::json normalize_change_user_payload(const nlohmann::json& input)
|
||||
{
|
||||
if (!input.is_object())
|
||||
return input;
|
||||
|
||||
const auto command = input.value("command", std::string());
|
||||
if ((command == "user_login" || command == "login_token") && input.contains("data") && input["data"].is_object())
|
||||
return input;
|
||||
|
||||
auto data_it = input.find("data");
|
||||
if (data_it != input.end() && looks_like_change_user_data(*data_it))
|
||||
return {
|
||||
{"command", command.empty() ? "user_login" : command},
|
||||
{"data", *data_it},
|
||||
};
|
||||
|
||||
if (looks_like_change_user_data(input))
|
||||
return {
|
||||
{"command", "user_login"},
|
||||
{"data", input},
|
||||
};
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
inline std::string normalize_change_user_payload_string(const std::string& input)
|
||||
{
|
||||
try {
|
||||
const auto parsed = nlohmann::json::parse(input);
|
||||
return normalize_change_user_payload(parsed).dump();
|
||||
} catch (...) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "../BambuBridge/Auth/BridgeAuthPayload.hpp"
|
||||
|
||||
namespace Slic3r::PJarczakLinuxBridge {
|
||||
using Slic3r::BambuBridge::looks_like_change_user_data;
|
||||
using Slic3r::BambuBridge::normalize_change_user_payload;
|
||||
using Slic3r::BambuBridge::normalize_change_user_payload_string;
|
||||
}
|
||||
|
|
@ -57,6 +57,9 @@
|
|||
#include <wx/fontutil.h>
|
||||
#include <wx/glcanvas.h>
|
||||
#include <wx/utils.h>
|
||||
#ifdef __WXMSW__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
|
|
@ -3169,6 +3172,79 @@ static const char* pjarczak_legacy_bootstrap_script_name()
|
|||
return "pjarczak-wsl-run-host.sh";
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool pjarczak_run_hidden_sync(const wxString& command, std::string* combined_output)
|
||||
{
|
||||
wxArrayString output;
|
||||
wxArrayString errors;
|
||||
const long rc = wxExecute(command, output, errors, wxEXEC_SYNC | wxEXEC_HIDE_CONSOLE);
|
||||
std::ostringstream oss;
|
||||
for (const auto& line : output)
|
||||
oss << into_u8(line) << "\n";
|
||||
for (const auto& line : errors)
|
||||
oss << into_u8(line) << "\n";
|
||||
if (combined_output)
|
||||
*combined_output = oss.str();
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
static void pjarczak_log_multiline(const char* prefix, const std::string& text)
|
||||
{
|
||||
std::istringstream iss(text);
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
if (!line.empty())
|
||||
BOOST_LOG_TRIVIAL(info) << prefix << line;
|
||||
}
|
||||
}
|
||||
|
||||
static bool pjarczak_ensure_windows_wsl_runtime_ready(const boost::filesystem::path& plugin_folder)
|
||||
{
|
||||
#ifndef WIN32
|
||||
(void)plugin_folder;
|
||||
return true;
|
||||
#else
|
||||
static bool attempted = false;
|
||||
if (attempted)
|
||||
return true;
|
||||
attempted = true;
|
||||
|
||||
const auto verify_script = plugin_folder / Slic3r::PJarczakLinuxBridge::windows_wsl_validate_script_file_name();
|
||||
const auto install_cmd = plugin_folder / "install_runtime.cmd";
|
||||
const auto cache_dir = boost::filesystem::path(wxGetApp().data_dir()) / "ota";
|
||||
|
||||
if (!boost::filesystem::exists(verify_script) || !boost::filesystem::exists(install_cmd)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "[pjarczak_wsl] missing runtime verification or installer script in " << plugin_folder.string();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string verify_output;
|
||||
const wxString verify_cmd = wxString::Format(
|
||||
"powershell -NoProfile -ExecutionPolicy Bypass -File \"%s\" -PackageDir \"%s\" -PluginCacheDir \"%s\" -AllowMissingLinuxPlugin",
|
||||
from_u8(verify_script.string()),
|
||||
from_u8(plugin_folder.string()),
|
||||
from_u8(cache_dir.string()));
|
||||
if (pjarczak_run_hidden_sync(verify_cmd, &verify_output)) {
|
||||
pjarczak_log_multiline("[pjarczak_wsl][verify] ", verify_output);
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(warning) << "[pjarczak_wsl] verify_runtime.ps1 failed, running installer/repair";
|
||||
pjarczak_log_multiline("[pjarczak_wsl][verify] ", verify_output);
|
||||
|
||||
std::string install_output;
|
||||
const wxString install_cmdline = wxString::Format(
|
||||
"cmd.exe /S /C \"\"%s\" -PackageDir \"%s\" -PluginDir \"%s\"\"",
|
||||
from_u8(install_cmd.string()),
|
||||
from_u8(plugin_folder.string()),
|
||||
from_u8(plugin_folder.string()));
|
||||
const bool install_ok = pjarczak_run_hidden_sync(install_cmdline, &install_output);
|
||||
pjarczak_log_multiline("[pjarczak_wsl][install] ", install_output);
|
||||
return install_ok;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool pjarczak_bridge_payload_ready(const boost::filesystem::path& plugin_folder, std::string* reason)
|
||||
{
|
||||
if (!Slic3r::PJarczakLinuxBridge::enabled()) {
|
||||
|
|
@ -3184,6 +3260,8 @@ bool pjarczak_bridge_payload_ready(const boost::filesystem::path& plugin_folder,
|
|||
const std::string required_files[] = {
|
||||
Slic3r::PJarczakLinuxBridge::bridge_network_current_dir_name(),
|
||||
Slic3r::PJarczakLinuxBridge::host_executable_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::host_executable_abi1_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::host_executable_abi0_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::windows_wsl_distro_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::windows_wsl_validate_script_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::windows_wsl_rootfs_file_name(),
|
||||
|
|
@ -3289,6 +3367,8 @@ void pjarczak_copy_local_overlay_runtime(const boost::filesystem::path& plugin_f
|
|||
const std::string runtime_files[] = {
|
||||
Slic3r::PJarczakLinuxBridge::bridge_network_current_dir_name(),
|
||||
Slic3r::PJarczakLinuxBridge::host_executable_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::host_executable_abi1_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::host_executable_abi0_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::windows_wsl_distro_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::windows_wsl_import_script_file_name(),
|
||||
Slic3r::PJarczakLinuxBridge::windows_wsl_validate_script_file_name(),
|
||||
|
|
@ -3497,6 +3577,10 @@ bool GUI_App::on_init_network(bool try_backup)
|
|||
auto should_load_networking_plugin = app_config->get_bool("installed_networking");
|
||||
const bool bridge_mode = Slic3r::PJarczakLinuxBridge::enabled();
|
||||
const boost::filesystem::path bridge_plugin_folder = boost::filesystem::path(data_dir()) / "plugins";
|
||||
if (bridge_mode) {
|
||||
pjarczak_copy_local_overlay_runtime(bridge_plugin_folder);
|
||||
pjarczak_ensure_windows_wsl_runtime_ready(bridge_plugin_folder);
|
||||
}
|
||||
std::string bridge_payload_reason;
|
||||
const bool bridge_payload_ready = !bridge_mode || pjarczak_bridge_payload_ready(bridge_plugin_folder, &bridge_payload_reason);
|
||||
bool create_network_agent = false;
|
||||
|
|
|
|||
|
|
@ -182,14 +182,76 @@ std::shared_ptr<HttpServer::Response> HttpServer::bbl_auth_handle_request(const
|
|||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "thirdparty_login: get_response";
|
||||
|
||||
NetworkAgent* agent = wxGetApp().getAgent();
|
||||
if (!agent)
|
||||
return std::make_shared<ResponseNotFound>();
|
||||
|
||||
const std::string ticket = url_get_param(url, "ticket");
|
||||
if (!ticket.empty()) {
|
||||
unsigned int token_http_code = 0;
|
||||
std::string token_http_body;
|
||||
const int token_result = agent->get_my_token(ticket, &token_http_code, &token_http_body);
|
||||
BOOST_LOG_TRIVIAL(info) << "thirdparty_login ticket exchange result=" << token_result << ", http_code=" << token_http_code;
|
||||
if (token_result == 0) {
|
||||
std::string access_token;
|
||||
try {
|
||||
json token_j = json::parse(token_http_body);
|
||||
if (token_j.contains("access_token"))
|
||||
access_token = token_j["access_token"].get<std::string>();
|
||||
} catch (...) {}
|
||||
|
||||
unsigned int profile_http_code = 0;
|
||||
std::string profile_http_body;
|
||||
const int profile_result = access_token.empty() ? -1 : agent->get_my_profile(access_token, &profile_http_code, &profile_http_body);
|
||||
BOOST_LOG_TRIVIAL(info) << "thirdparty_login profile result=" << profile_result << ", http_code=" << profile_http_code;
|
||||
if (profile_result == 0) {
|
||||
json payload;
|
||||
payload["command"] = "user_login";
|
||||
try {
|
||||
payload["data"] = json::parse(token_http_body);
|
||||
} catch (...) {
|
||||
payload["data"]["token"] = access_token;
|
||||
}
|
||||
try {
|
||||
const auto profile_j = json::parse(profile_http_body);
|
||||
payload["data"]["user"] = profile_j;
|
||||
} catch (...) {}
|
||||
|
||||
agent->change_user(payload.dump());
|
||||
const bool login_ok = agent->is_user_login();
|
||||
if (login_ok) {
|
||||
wxGetApp().request_user_login(1);
|
||||
GUI::wxGetApp().CallAfter([] { wxGetApp().ShowUserLogin(false); });
|
||||
}
|
||||
|
||||
const std::string title = login_ok ? "Authentication complete" : "Authentication failed";
|
||||
const std::string message = login_ok
|
||||
? "You can return to OrcaSlicer. This window will close automatically."
|
||||
: "Something went wrong. Please return to OrcaSlicer and try again.";
|
||||
const std::string html =
|
||||
"<html><head><meta charset=\"utf-8\">"
|
||||
"<style>body{font-family:Arial,sans-serif;background:#f7f7f7;color:#222;margin:32px;}"
|
||||
"a.button{display:inline-block;padding:10px 16px;margin-top:12px;background:#0f8bff;color:#fff;text-decoration:none;border-radius:6px;}"
|
||||
"</style></head><body><div class=\"container\">"
|
||||
"<h2>" + title + "</h2>"
|
||||
"<p>" + message + "</p>"
|
||||
"<script>setTimeout(function(){try{window.close();}catch(e){}},1500);</script>"
|
||||
"</div></body></html>";
|
||||
return std::make_shared<ResponseHtml>(html);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string html =
|
||||
"<html><head><meta charset=\"utf-8\"></head><body>"
|
||||
"<h2>Authentication failed</h2>"
|
||||
"<p>Something went wrong. Please return to OrcaSlicer and try again.</p>"
|
||||
"</body></html>";
|
||||
return std::make_shared<ResponseHtml>(html);
|
||||
}
|
||||
|
||||
const std::string auth_code = url_get_param(url, "code");
|
||||
if (!auth_code.empty()) {
|
||||
std::string state = url_get_param(url, "state");
|
||||
NetworkAgent* agent = wxGetApp().getAgent();
|
||||
if (!agent) {
|
||||
return std::make_shared<ResponseNotFound>();
|
||||
}
|
||||
|
||||
json payload;
|
||||
payload["command"] = "user_login";
|
||||
payload["data"]["code"] = auth_code;
|
||||
|
|
@ -224,7 +286,6 @@ std::shared_ptr<HttpServer::Response> HttpServer::bbl_auth_handle_request(const
|
|||
std::string refresh_token = url_get_param(url, "refresh_token");
|
||||
std::string expires_in_str = url_get_param(url, "expires_in");
|
||||
std::string refresh_expires_in_str = url_get_param(url, "refresh_expires_in");
|
||||
NetworkAgent* agent = wxGetApp().getAgent();
|
||||
|
||||
unsigned int http_code;
|
||||
std::string http_body;
|
||||
|
|
@ -244,10 +305,9 @@ std::shared_ptr<HttpServer::Response> HttpServer::bbl_auth_handle_request(const
|
|||
user_avatar = user_j["avatar"].get<std::string>();
|
||||
if (user_j.contains("account"))
|
||||
user_account = user_j["account"].get<std::string>();
|
||||
} catch (...) {
|
||||
;
|
||||
}
|
||||
} catch (...) {}
|
||||
json j;
|
||||
j["command"] = "user_login";
|
||||
j["data"]["refresh_token"] = refresh_token;
|
||||
j["data"]["token"] = access_token;
|
||||
j["data"]["expires_in"] = expires_in_str;
|
||||
|
|
@ -263,14 +323,14 @@ std::shared_ptr<HttpServer::Response> HttpServer::bbl_auth_handle_request(const
|
|||
GUI::wxGetApp().CallAfter([] { wxGetApp().ShowUserLogin(false); });
|
||||
std::string location_str = (boost::format("%1%?result=success") % redirect_url).str();
|
||||
return std::make_shared<ResponseRedirect>(location_str);
|
||||
} else {
|
||||
std::string error_str = "get_user_profile_error_" + std::to_string(result);
|
||||
std::string location_str = (boost::format("%1%?result=fail&error=%2%") % redirect_url % error_str).str();
|
||||
return std::make_shared<ResponseRedirect>(location_str);
|
||||
}
|
||||
} else {
|
||||
return std::make_shared<ResponseNotFound>();
|
||||
|
||||
std::string error_str = "get_user_profile_error_" + std::to_string(result);
|
||||
std::string location_str = (boost::format("%1%?result=fail&error=%2%") % redirect_url % error_str).str();
|
||||
return std::make_shared<ResponseRedirect>(location_str);
|
||||
}
|
||||
|
||||
return std::make_shared<ResponseNotFound>();
|
||||
}
|
||||
|
||||
void HttpServer::ResponseNotFound::write_response(std::stringstream& ssOut)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
#include "slic3r/Utils/PJarczakLinuxBridge/PJarczakLinuxBridgeConfig.hpp"
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/toolbar.h>
|
||||
|
|
@ -32,6 +34,23 @@ using namespace nlohmann;
|
|||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
namespace {
|
||||
std::string pjarczak_browser_login_url(const std::string& host_value, const std::string& locale, const std::string& localhost_base)
|
||||
{
|
||||
std::string host = host_value;
|
||||
while (!host.empty() && host.back() == '/')
|
||||
host.pop_back();
|
||||
if (host.rfind("http://", 0) != 0 && host.rfind("https://", 0) != 0)
|
||||
host = "https://bambulab.com";
|
||||
std::string lang = locale.empty() ? "en" : locale;
|
||||
std::string callback = host + "/sign-in/callback?source=portal&locale=" + Http::url_encode(lang) +
|
||||
"&redirect_url=" + Http::url_encode(localhost_base) +
|
||||
"&openBy=suite&from=studio&slicerLoginType=ticket";
|
||||
return host + "/sign-in?&from=studio&source=portal&to=" + Http::url_encode(callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define NETWORK_OFFLINE_TIMER_ID 10001
|
||||
|
||||
BEGIN_EVENT_TABLE(ZUserLogin, wxDialog)
|
||||
|
|
@ -76,6 +95,20 @@ ZUserLogin::ZUserLogin() : wxDialog((wxWindow *) (wxGetApp().mainframe), wxID_AN
|
|||
CentreOnParent();
|
||||
}
|
||||
else {
|
||||
#ifdef WIN32
|
||||
if (Slic3r::PJarczakLinuxBridge::enabled()) {
|
||||
m_external_browser_mode = true;
|
||||
SetTitle(_L("Login"));
|
||||
wxBoxSizer* m_sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
auto* m_message = new wxStaticText(this, wxID_ANY, _L("Login opens in your default browser. Finish sign-in there and this dialog will close automatically."), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_message->Wrap(FromDIP(420));
|
||||
m_sizer_main->Add(m_message, 0, wxALL | wxEXPAND, FromDIP(16));
|
||||
SetSizer(m_sizer_main);
|
||||
m_sizer_main->SetSizeHints(this);
|
||||
SetSize(FromDIP(wxSize(460, 140)));
|
||||
CentreOnParent();
|
||||
} else {
|
||||
#endif
|
||||
// Get the login URL from the cloud service agent
|
||||
wxString strlang = wxGetApp().current_language_code_safe();
|
||||
strlang.Replace("_", "-");
|
||||
|
|
@ -128,6 +161,9 @@ ZUserLogin::ZUserLogin() : wxDialog((wxWindow *) (wxGetApp().mainframe), wxID_AN
|
|||
int MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0;
|
||||
wxPoint tmpPT((screenwidth - pSize.x) / 2, MaxY);
|
||||
Move(tmpPT);
|
||||
#ifdef WIN32
|
||||
}
|
||||
#endif
|
||||
}
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
}
|
||||
|
|
@ -151,7 +187,25 @@ void ZUserLogin::OnTimer(wxTimerEvent &event) {
|
|||
|
||||
bool ZUserLogin::run() {
|
||||
m_timer = new wxTimer(this, NETWORK_OFFLINE_TIMER_ID);
|
||||
m_timer->Start(8000);
|
||||
m_timer->Start(m_external_browser_mode ? 30000 : 8000);
|
||||
|
||||
#ifdef WIN32
|
||||
if (m_external_browser_mode) {
|
||||
NetworkAgent* agent = wxGetApp().getAgent();
|
||||
if (agent) {
|
||||
wxString strlang = wxGetApp().current_language_code_safe();
|
||||
strlang.Replace("_", "-");
|
||||
const std::string host = agent->get_cloud_service_host();
|
||||
m_loopback_port = LOCALHOST_PORT;
|
||||
wxGetApp().start_http_server(m_loopback_port);
|
||||
const std::string localhost = std::string(LOCALHOST_URL) + std::to_string(m_loopback_port);
|
||||
const std::string browser_url = pjarczak_browser_login_url(host, strlang.ToStdString(), localhost);
|
||||
BOOST_LOG_TRIVIAL(info) << "external login url = " << browser_url;
|
||||
wxLaunchDefaultBrowser(wxString::FromUTF8(browser_url));
|
||||
m_networkOk = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->ShowModal() == wxID_OK) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ private:
|
|||
|
||||
std::string m_AutotestToken;
|
||||
int m_loopback_port { 0 };
|
||||
bool m_external_browser_mode { false };
|
||||
|
||||
#if wxUSE_WEBVIEW_IE
|
||||
wxMenuItem *m_script_object_el;
|
||||
|
|
|
|||
|
|
@ -617,6 +617,17 @@ int BBLCloudServiceAgent::get_model_mall_detail_url(std::string* url, std::strin
|
|||
return -1;
|
||||
}
|
||||
|
||||
int BBLCloudServiceAgent::get_my_token(std::string ticket, unsigned int* http_code, std::string* http_body)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_get_my_token();
|
||||
if (func && agent) {
|
||||
return func(agent, ticket, http_code, http_body);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BBLCloudServiceAgent::get_my_profile(std::string token, unsigned int* http_code, std::string* http_body)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ public:
|
|||
int get_subtask(BBLModelTask* task, OnGetSubTaskFn getsub_fn) override;
|
||||
int get_model_mall_home_url(std::string* url) override;
|
||||
int get_model_mall_detail_url(std::string* url, std::string id) override;
|
||||
int get_my_token(std::string ticket, unsigned int* http_code, std::string* http_body) override;
|
||||
int get_my_profile(std::string token, unsigned int* http_code, std::string* http_body) override;
|
||||
|
||||
// Analytics & Tracking
|
||||
|
|
|
|||
|
|
@ -634,6 +634,7 @@ void BBLNetworkPlugin::load_all_function_pointers()
|
|||
m_get_subtask = reinterpret_cast<func_get_subtask>(get_function("bambu_network_get_subtask"));
|
||||
m_get_model_mall_home_url = reinterpret_cast<func_get_model_mall_home_url>(get_function("bambu_network_get_model_mall_home_url"));
|
||||
m_get_model_mall_detail_url = reinterpret_cast<func_get_model_mall_detail_url>(get_function("bambu_network_get_model_mall_detail_url"));
|
||||
m_get_my_token = reinterpret_cast<func_get_my_token>(get_function("bambu_network_get_my_token"));
|
||||
m_get_my_profile = reinterpret_cast<func_get_my_profile>(get_function("bambu_network_get_my_profile"));
|
||||
m_track_enable = reinterpret_cast<func_track_enable>(get_function("bambu_network_track_enable"));
|
||||
m_track_remove_files = reinterpret_cast<func_track_remove_files>(get_function("bambu_network_track_remove_files"));
|
||||
|
|
@ -737,6 +738,7 @@ void BBLNetworkPlugin::clear_all_function_pointers()
|
|||
m_get_subtask = nullptr;
|
||||
m_get_model_mall_home_url = nullptr;
|
||||
m_get_model_mall_detail_url = nullptr;
|
||||
m_get_my_token = nullptr;
|
||||
m_get_my_profile = nullptr;
|
||||
m_track_enable = nullptr;
|
||||
m_track_remove_files = nullptr;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ typedef int (*func_get_model_publish_url)(void *agent, std::string* url);
|
|||
typedef int (*func_get_subtask)(void *agent, BBLModelTask* task, OnGetSubTaskFn getsub_fn);
|
||||
typedef int (*func_get_model_mall_home_url)(void *agent, std::string* url);
|
||||
typedef int (*func_get_model_mall_detail_url)(void *agent, std::string* url, std::string id);
|
||||
typedef int (*func_get_my_token)(void *agent, std::string ticket, unsigned int *http_code, std::string *http_body);
|
||||
typedef int (*func_get_my_profile)(void *agent, std::string token, unsigned int *http_code, std::string *http_body);
|
||||
typedef int (*func_track_enable)(void *agent, bool enable);
|
||||
typedef int (*func_track_remove_files)(void *agent);
|
||||
|
|
@ -360,6 +361,7 @@ public:
|
|||
func_get_subtask get_get_subtask() const { return m_get_subtask; }
|
||||
func_get_model_mall_home_url get_get_model_mall_home_url() const { return m_get_model_mall_home_url; }
|
||||
func_get_model_mall_detail_url get_get_model_mall_detail_url() const { return m_get_model_mall_detail_url; }
|
||||
func_get_my_token get_get_my_token() const { return m_get_my_token; }
|
||||
func_get_my_profile get_get_my_profile() const { return m_get_my_profile; }
|
||||
func_track_enable get_track_enable() const { return m_track_enable; }
|
||||
func_track_remove_files get_track_remove_files() const { return m_track_remove_files; }
|
||||
|
|
@ -495,6 +497,7 @@ private:
|
|||
func_get_subtask m_get_subtask{nullptr};
|
||||
func_get_model_mall_home_url m_get_model_mall_home_url{nullptr};
|
||||
func_get_model_mall_detail_url m_get_model_mall_detail_url{nullptr};
|
||||
func_get_my_token m_get_my_token{nullptr};
|
||||
func_get_my_profile m_get_my_profile{nullptr};
|
||||
func_track_enable m_track_enable{nullptr};
|
||||
func_track_remove_files m_track_remove_files{nullptr};
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ public:
|
|||
/**
|
||||
* Retrieve user's model mall profile.
|
||||
*/
|
||||
virtual int get_my_token(std::string ticket, unsigned int* http_code, std::string* http_body) = 0;
|
||||
virtual int get_my_profile(std::string token, unsigned int* http_code, std::string* http_body) = 0;
|
||||
|
||||
// ========================================================================
|
||||
|
|
|
|||
|
|
@ -775,6 +775,12 @@ int NetworkAgent::get_model_mall_detail_url(std::string* url, std::string id)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_my_token(std::string ticket, unsigned int* http_code, std::string* http_body)
|
||||
{
|
||||
if (m_cloud_agent) return m_cloud_agent->get_my_token(ticket, http_code, http_body);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_my_profile(std::string token, unsigned int* http_code, std::string* http_body)
|
||||
{
|
||||
if (m_cloud_agent) return m_cloud_agent->get_my_profile(token, http_code, http_body);
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ public:
|
|||
int get_subtask(BBLModelTask* task, OnGetSubTaskFn getsub_fn);
|
||||
int get_model_mall_home_url(std::string* url);
|
||||
int get_model_mall_detail_url(std::string* url, std::string id);
|
||||
int get_my_token(std::string ticket, unsigned int* http_code, std::string* http_body);
|
||||
int get_my_profile(std::string token, unsigned int* http_code, std::string* http_body);
|
||||
int track_enable(bool enable);
|
||||
int track_remove_files();
|
||||
|
|
|
|||
|
|
@ -51,32 +51,41 @@ install(TARGETS pjarczak_bambu_networking_bridge
|
|||
)
|
||||
|
||||
if (UNIX AND NOT APPLE AND EXISTS "${PJARCZAK_LINUX_HOST_DIR}/main.cpp" AND EXISTS "${PJARCZAK_LINUX_HOST_DIR}/LinuxPluginHost.cpp")
|
||||
add_executable(pjarczak_bambu_linux_host
|
||||
${PJARCZAK_LINUX_HOST_DIR}/main.cpp
|
||||
${PJARCZAK_LINUX_HOST_DIR}/LinuxPluginHost.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/PJarczakLinuxBridgeConfig.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/PJarczakLinuxSoBridgeRpcProtocol.cpp
|
||||
)
|
||||
target_include_directories(pjarczak_bambu_linux_host PRIVATE ${PJARCZAK_LINUX_BRIDGE_INCLUDE_DIRS})
|
||||
target_compile_definitions(pjarczak_bambu_linux_host PRIVATE
|
||||
PJARCZAK_LINUX_BRIDGE_STANDALONE_HOST=1
|
||||
PJARCZAK_LINUX_BRIDGE_LIGHTWEIGHT_TASKS=1
|
||||
)
|
||||
find_package(nlohmann_json CONFIG QUIET)
|
||||
if (TARGET nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(pjarczak_bambu_linux_host PRIVATE nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
target_link_libraries(pjarczak_bambu_linux_host PRIVATE boost_headeronly boost_libs ${CMAKE_DL_LIBS} OpenSSL::Crypto)
|
||||
target_link_options(pjarczak_bambu_linux_host PRIVATE -static-libstdc++ -static-libgcc)
|
||||
set_target_properties(pjarczak_bambu_linux_host PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
|
||||
)
|
||||
install(TARGETS pjarczak_bambu_linux_host
|
||||
RUNTIME DESTINATION "."
|
||||
)
|
||||
function(pjarczak_add_linux_host_variant target_name abi_value)
|
||||
add_executable(${target_name}
|
||||
${PJARCZAK_LINUX_HOST_DIR}/main.cpp
|
||||
${PJARCZAK_LINUX_HOST_DIR}/LinuxPluginHost.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/PJarczakLinuxBridgeConfig.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/PJarczakLinuxSoBridgeRpcProtocol.cpp
|
||||
)
|
||||
target_include_directories(${target_name} PRIVATE ${PJARCZAK_LINUX_BRIDGE_INCLUDE_DIRS})
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
PJARCZAK_LINUX_BRIDGE_STANDALONE_HOST=1
|
||||
PJARCZAK_LINUX_BRIDGE_LIGHTWEIGHT_TASKS=1
|
||||
_GLIBCXX_USE_CXX11_ABI=${abi_value}
|
||||
)
|
||||
find_package(nlohmann_json CONFIG QUIET)
|
||||
if (TARGET nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(${target_name} PRIVATE nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
target_link_libraries(${target_name} PRIVATE boost_headeronly boost_libs ${CMAKE_DL_LIBS} OpenSSL::Crypto)
|
||||
set_target_properties(${target_name} PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
INSTALL_RPATH "$ORIGIN"
|
||||
)
|
||||
install(TARGETS ${target_name}
|
||||
RUNTIME DESTINATION "."
|
||||
)
|
||||
endfunction()
|
||||
|
||||
pjarczak_add_linux_host_variant(pjarczak_bambu_linux_host_abi1 1)
|
||||
pjarczak_add_linux_host_variant(pjarczak_bambu_linux_host_abi0 0)
|
||||
add_custom_target(pjarczak_bambu_linux_host DEPENDS pjarczak_bambu_linux_host_abi1 pjarczak_bambu_linux_host_abi0)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
set(PJARCZAK_MAC_WRAPPER_SCRIPT_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_macos_linux_wrapper/pjarczak_bambu_macos_linux_wrapper.sh)
|
||||
add_custom_command(TARGET pjarczak_bambu_networking_bridge POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
|
|
@ -91,6 +100,7 @@ endif()
|
|||
|
||||
if (WIN32)
|
||||
set(PJARCZAK_WSL_HELPER_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/pjarczak_wsl_run_host.sh)
|
||||
set(PJARCZAK_WSL_HOST_WRAPPER_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/pjarczak_bambu_linux_host)
|
||||
set(PJARCZAK_WSL_INSTALLER_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/install_runtime.ps1)
|
||||
set(PJARCZAK_WSL_INSTALLER_CMD_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/install_runtime.cmd)
|
||||
set(PJARCZAK_WSL_VERIFY_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/verify_runtime.ps1)
|
||||
|
|
@ -100,6 +110,9 @@ if (WIN32)
|
|||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${PJARCZAK_WSL_HELPER_SOURCE}
|
||||
$<TARGET_FILE_DIR:pjarczak_bambu_networking_bridge>/pjarczak_wsl_run_host.sh
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${PJARCZAK_WSL_HOST_WRAPPER_SOURCE}
|
||||
$<TARGET_FILE_DIR:pjarczak_bambu_networking_bridge>/pjarczak_bambu_linux_host
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${PJARCZAK_WSL_INSTALLER_SOURCE}
|
||||
$<TARGET_FILE_DIR:pjarczak_bambu_networking_bridge>/install_runtime.ps1
|
||||
|
|
@ -118,6 +131,7 @@ if (WIN32)
|
|||
)
|
||||
install(FILES
|
||||
${PJARCZAK_WSL_HELPER_SOURCE}
|
||||
${PJARCZAK_WSL_HOST_WRAPPER_SOURCE}
|
||||
${PJARCZAK_WSL_INSTALLER_SOURCE}
|
||||
${PJARCZAK_WSL_INSTALLER_CMD_SOURCE}
|
||||
${PJARCZAK_WSL_VERIFY_SOURCE}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,16 @@ std::string host_executable_file_name()
|
|||
return "pjarczak_bambu_linux_host";
|
||||
}
|
||||
|
||||
std::string host_executable_abi1_file_name()
|
||||
{
|
||||
return "pjarczak_bambu_linux_host_abi1";
|
||||
}
|
||||
|
||||
std::string host_executable_abi0_file_name()
|
||||
{
|
||||
return "pjarczak_bambu_linux_host_abi0";
|
||||
}
|
||||
|
||||
std::string mac_host_wrapper_file_name()
|
||||
{
|
||||
return "pjarczak-bambu-linux-host-wrapper";
|
||||
|
|
@ -231,12 +241,15 @@ bool is_overlay_runtime_filename(const std::string& file_name)
|
|||
return file_name == linux_payload_manifest_file_name() ||
|
||||
file_name == bridge_network_current_dir_name() ||
|
||||
file_name == host_executable_file_name() ||
|
||||
file_name == host_executable_abi1_file_name() ||
|
||||
file_name == host_executable_abi0_file_name() ||
|
||||
file_name == mac_host_wrapper_file_name() ||
|
||||
file_name == windows_wsl_distro_file_name() ||
|
||||
file_name == windows_wsl_import_script_file_name() ||
|
||||
file_name == windows_wsl_validate_script_file_name() ||
|
||||
file_name == windows_wsl_bootstrap_script_file_name() ||
|
||||
file_name == windows_wsl_rootfs_file_name() ||
|
||||
file_name == "install_runtime.cmd" ||
|
||||
is_linux_payload_filename(file_name);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ std::string bridge_network_library_path(const boost::filesystem::path& plugin_fo
|
|||
std::string linux_network_library_name();
|
||||
std::string linux_source_library_name();
|
||||
std::string host_executable_file_name();
|
||||
std::string host_executable_abi1_file_name();
|
||||
std::string host_executable_abi0_file_name();
|
||||
std::string mac_host_wrapper_file_name();
|
||||
std::string windows_wsl_distro_file_name();
|
||||
std::string windows_wsl_import_script_file_name();
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ std::filesystem::path configured_plugin_cache_dir()
|
|||
|
||||
const auto appdata = required_env("APPDATA");
|
||||
if (!appdata.empty())
|
||||
return std::filesystem::path(appdata) / "OrcaSlicer" / "plugins";
|
||||
return std::filesystem::path(appdata) / "OrcaSlicer" / "ota";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
@ -145,6 +145,8 @@ std::string first_missing_runtime_file(const std::filesystem::path& plugin_dir)
|
|||
{
|
||||
for (const auto& name : {
|
||||
host_executable_file_name(),
|
||||
host_executable_abi1_file_name(),
|
||||
host_executable_abi0_file_name(),
|
||||
windows_wsl_distro_file_name()
|
||||
}) {
|
||||
if (!std::filesystem::exists(plugin_dir / name))
|
||||
|
|
|
|||
|
|
@ -1,37 +1,46 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_policy(SET CMP0167 NEW)
|
||||
|
||||
project(pjarczak_bambu_linux_host_standalone LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
get_filename_component(REPO_ROOT "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(Boost CONFIG REQUIRED COMPONENTS filesystem)
|
||||
|
||||
add_executable(pjarczak_bambu_linux_host
|
||||
"${REPO_ROOT}/tools/pjarczak_bambu_linux_host/main.cpp"
|
||||
"${REPO_ROOT}/tools/pjarczak_bambu_linux_host/LinuxPluginHost.cpp"
|
||||
"${REPO_ROOT}/src/slic3r/Utils/PJarczakLinuxBridge/PJarczakLinuxBridgeConfig.cpp"
|
||||
"${REPO_ROOT}/src/slic3r/Utils/PJarczakLinuxBridge/PJarczakLinuxSoBridgeRpcProtocol.cpp"
|
||||
set(HOST_SOURCES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/main.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/LinuxPluginHost.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../../src/slic3r/Utils/PJarczakLinuxBridge/PJarczakLinuxBridgeConfig.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../../src/slic3r/Utils/PJarczakLinuxBridge/PJarczakLinuxSoBridgeRpcProtocol.cpp"
|
||||
)
|
||||
|
||||
target_include_directories(pjarczak_bambu_linux_host PRIVATE
|
||||
"${REPO_ROOT}"
|
||||
"${REPO_ROOT}/src"
|
||||
)
|
||||
function(add_host_variant target_name abi_value)
|
||||
add_executable(${target_name} ${HOST_SOURCES})
|
||||
set_target_properties(${target_name} PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tools/pjarczak_bambu_linux_host"
|
||||
OUTPUT_NAME ${target_name}
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
INSTALL_RPATH "$ORIGIN"
|
||||
)
|
||||
target_include_directories(${target_name} PRIVATE
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../.."
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../../src"
|
||||
)
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
PJARCZAK_LINUX_BRIDGE_STANDALONE_HOST=1
|
||||
PJARCZAK_LINUX_BRIDGE_LIGHTWEIGHT_TASKS=1
|
||||
_GLIBCXX_USE_CXX11_ABI=${abi_value}
|
||||
)
|
||||
target_link_libraries(${target_name} PRIVATE
|
||||
Boost::filesystem
|
||||
${CMAKE_DL_LIBS}
|
||||
OpenSSL::Crypto
|
||||
)
|
||||
endfunction()
|
||||
|
||||
target_link_libraries(pjarczak_bambu_linux_host PRIVATE
|
||||
Boost::filesystem
|
||||
Threads::Threads
|
||||
OpenSSL::Crypto
|
||||
${CMAKE_DL_LIBS}
|
||||
)
|
||||
add_host_variant(pjarczak_bambu_linux_host_abi1 1)
|
||||
add_host_variant(pjarczak_bambu_linux_host_abi0 0)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_link_options(pjarczak_bambu_linux_host PRIVATE -static-libstdc++ -static-libgcc)
|
||||
endif()
|
||||
add_custom_target(pjarczak_bambu_linux_host ALL
|
||||
DEPENDS pjarczak_bambu_linux_host_abi1 pjarczak_bambu_linux_host_abi0)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "LinuxPluginHost.hpp"
|
||||
|
||||
#include "../../shared/pjarczak_linux_plugin_bridge_core/BridgeCoreJson.hpp"
|
||||
#include "../../shared/pjarczak_linux_plugin_bridge_core/BridgeAuthPayload.hpp"
|
||||
#include "../../src/slic3r/Utils/bambu_networking.hpp"
|
||||
#include "../../src/slic3r/GUI/Printer/BambuTunnel.h"
|
||||
#include "../../src/slic3r/Utils/PJarczakLinuxBridge/PJarczakLinuxBridgeCompat.hpp"
|
||||
|
|
@ -14,7 +15,9 @@
|
|||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
|
@ -69,7 +72,7 @@ using fn_ft_job_set_msg_cb = ft_err (*)(FT_JobHandle *, void (*)(void *user, ft_
|
|||
using fn_ft_job_try_get_msg = ft_err (*)(FT_JobHandle *, ft_job_msg *out_msg);
|
||||
using fn_ft_job_get_msg = ft_err (*)(FT_JobHandle *, uint32_t timeout_ms, ft_job_msg *out_msg);
|
||||
|
||||
bool path_exists(const boost::filesystem::path& path)
|
||||
bool path_exists(const std::filesystem::path& path)
|
||||
{
|
||||
FILE* f = std::fopen(path.string().c_str(), "rb");
|
||||
if (!f)
|
||||
|
|
@ -85,37 +88,25 @@ std::string env_or(const char* name, const char* fallback)
|
|||
return fallback;
|
||||
}
|
||||
|
||||
std::string windows_path_to_wsl(std::string path)
|
||||
std::mutex g_host_log_mutex;
|
||||
|
||||
std::string trim_for_log(const std::string& value, std::size_t limit = 8192)
|
||||
{
|
||||
if (path.rfind("\\\\?\\", 0) == 0)
|
||||
path.erase(0, 4);
|
||||
|
||||
if (path.size() < 3)
|
||||
return path;
|
||||
|
||||
const char drive = path[0];
|
||||
const bool drive_ok =
|
||||
(drive >= 'A' && drive <= 'Z') ||
|
||||
(drive >= 'a' && drive <= 'z');
|
||||
|
||||
if (!drive_ok || path[1] != ':' || (path[2] != '\\' && path[2] != '/'))
|
||||
return path;
|
||||
|
||||
std::string out = "/mnt/";
|
||||
out.push_back((drive >= 'A' && drive <= 'Z') ? static_cast<char>(drive - 'A' + 'a') : drive);
|
||||
out.push_back('/');
|
||||
|
||||
for (std::size_t i = 3; i < path.size(); ++i)
|
||||
out.push_back(path[i] == '\\' ? '/' : path[i]);
|
||||
|
||||
return out;
|
||||
if (value.size() <= limit)
|
||||
return value;
|
||||
return value.substr(0, limit) + "...<truncated>";
|
||||
}
|
||||
|
||||
std::vector<std::string> windows_paths_to_wsl(std::vector<std::string> paths)
|
||||
void host_log_json(const std::string& kind, const nlohmann::json& payload)
|
||||
{
|
||||
for (auto& path : paths)
|
||||
path = windows_path_to_wsl(std::move(path));
|
||||
return paths;
|
||||
try {
|
||||
nlohmann::json line;
|
||||
line["kind"] = kind;
|
||||
line["payload"] = payload;
|
||||
std::lock_guard<std::mutex> lock(g_host_log_mutex);
|
||||
std::cerr << "[PJBRIDGE] " << trim_for_log(line.dump()) << std::endl;
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -226,8 +217,8 @@ BBL::PrintParams print_params_from_json(const nlohmann::json& j)
|
|||
p.task_name = j.value("task_name", std::string());
|
||||
p.project_name = j.value("project_name", std::string());
|
||||
p.preset_name = j.value("preset_name", std::string());
|
||||
p.filename = windows_path_to_wsl(j.value("filename", std::string()));
|
||||
p.config_filename = windows_path_to_wsl(j.value("config_filename", std::string()));
|
||||
p.filename = j.value("filename", std::string());
|
||||
p.config_filename = j.value("config_filename", std::string());
|
||||
p.plate_index = j.value("plate_index", 0);
|
||||
p.ftp_folder = j.value("ftp_folder", std::string());
|
||||
p.ftp_file = j.value("ftp_file", std::string());
|
||||
|
|
@ -243,7 +234,7 @@ BBL::PrintParams print_params_from_json(const nlohmann::json& j)
|
|||
p.stl_design_id = j.value("stl_design_id", 0);
|
||||
p.origin_model_id = j.value("origin_model_id", std::string());
|
||||
p.print_type = j.value("print_type", std::string());
|
||||
p.dst_file = windows_path_to_wsl(j.value("dst_file", std::string()));
|
||||
p.dst_file = j.value("dst_file", std::string());
|
||||
p.dev_name = j.value("dev_name", std::string());
|
||||
p.dev_ip = j.value("dev_ip", std::string());
|
||||
p.use_ssl_for_ftp = j.value("use_ssl_for_ftp", false);
|
||||
|
|
@ -464,7 +455,7 @@ bool LinuxPluginHost::consume_thread_reply_binary(std::vector<unsigned char>& ou
|
|||
|
||||
void LinuxPluginHost::load_modules()
|
||||
{
|
||||
const boost::filesystem::path plugin_folder = boost::filesystem::path(env_or("PJARCZAK_BAMBU_PLUGIN_DIR", "."));
|
||||
const std::filesystem::path plugin_folder = std::filesystem::path(env_or("PJARCZAK_BAMBU_PLUGIN_DIR", "."));
|
||||
std::string manifest_reason;
|
||||
const bool have_manifest = path_exists(linux_payload_manifest_path(plugin_folder));
|
||||
const bool manifest_ok = !have_manifest || validate_linux_payload_set_against_manifest(plugin_folder, &manifest_reason);
|
||||
|
|
@ -694,7 +685,7 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
return {{"ok", true}, {"value", 0}, {"result", refresh_agora_url_ptr_string()}};
|
||||
}
|
||||
if (method == "bridge.handshake") {
|
||||
const boost::filesystem::path plugin_folder = boost::filesystem::path(env_or("PJARCZAK_BAMBU_PLUGIN_DIR", "."));
|
||||
const std::filesystem::path plugin_folder = std::filesystem::path(env_or("PJARCZAK_BAMBU_PLUGIN_DIR", "."));
|
||||
nlohmann::json out = nlohmann::json::object();
|
||||
out["ok"] = true;
|
||||
out["protocol_version"] = 1;
|
||||
|
|
@ -717,6 +708,29 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
if (method == "bridge.capabilities") {
|
||||
return {{"ok", true}, {"agent_count", m_agents.size()}, {"auth_capabilities", auth_capabilities()}};
|
||||
}
|
||||
if (method == "bridge.runtime_info") {
|
||||
char cwd_buf[4096] = {0};
|
||||
std::string cwd;
|
||||
if (::getcwd(cwd_buf, sizeof(cwd_buf) - 1))
|
||||
cwd = cwd_buf;
|
||||
nlohmann::json out = nlohmann::json::object();
|
||||
out["ok"] = true;
|
||||
out["cwd"] = cwd;
|
||||
out["home"] = env_or("HOME", "");
|
||||
out["plugin_dir"] = env_or("PJARCZAK_BAMBU_PLUGIN_DIR", "");
|
||||
out["network_so"] = env_or("PJARCZAK_BAMBU_NETWORK_SO", "");
|
||||
out["source_so"] = env_or("PJARCZAK_BAMBU_SOURCE_SO", "");
|
||||
out["ssl_cert_file"] = env_or("SSL_CERT_FILE", "");
|
||||
out["ssl_cert_dir"] = env_or("SSL_CERT_DIR", "");
|
||||
out["curl_ca_bundle"] = env_or("CURL_CA_BUNDLE", "");
|
||||
out["ld_library_path"] = env_or("LD_LIBRARY_PATH", "");
|
||||
out["network_loaded"] = m_network != nullptr;
|
||||
out["source_loaded"] = m_source != nullptr;
|
||||
out["network_status"] = m_network_status;
|
||||
out["source_status"] = m_source_status;
|
||||
host_log_json("bridge.runtime_info", out);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (method == "bridge.job_cancel") {
|
||||
set_job_cancel(payload.value("job_id", 0LL), payload.value("cancel", true));
|
||||
|
|
@ -734,8 +748,7 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
if (method == "net.create_agent") {
|
||||
auto f = net<void* (*)(std::string)>("bambu_network_create_agent");
|
||||
if (!f) return not_supported(method);
|
||||
const std::string log_dir = windows_path_to_wsl(payload.value("log_dir", std::string()));
|
||||
void* raw = f(log_dir);
|
||||
void* raw = f(payload.value("log_dir", std::string()));
|
||||
const auto id = m_next_agent++;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_state_mutex);
|
||||
|
|
@ -796,14 +809,18 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
if (method == "net.set_config_dir") {
|
||||
auto f = net<int (*)(void*, std::string)>("bambu_network_set_config_dir");
|
||||
auto a = lookup_agent();
|
||||
const std::string config_dir = windows_path_to_wsl(payload.value("config_dir", std::string()));
|
||||
return f && a ? nlohmann::json{{"ok", true}, {"value", f(a, config_dir)}} : not_supported(method);
|
||||
return f && a ? nlohmann::json{{"ok", true}, {"value", f(a, payload.value("config_dir", std::string()))}} : not_supported(method);
|
||||
}
|
||||
if (method == "net.set_cert_file") {
|
||||
auto f = net<int (*)(void*, std::string, std::string)>("bambu_network_set_cert_file");
|
||||
auto a = lookup_agent();
|
||||
const std::string folder = windows_path_to_wsl(payload.value("folder", std::string()));
|
||||
return f && a ? nlohmann::json{{"ok", true}, {"value", f(a, folder, payload.value("filename", std::string()))}} : not_supported(method);
|
||||
if (!f || !a) return not_supported(method);
|
||||
const auto folder = payload.value("folder", std::string());
|
||||
const auto filename = payload.value("filename", std::string());
|
||||
const int ret = f(a, folder, filename);
|
||||
nlohmann::json r{{"ok", true}, {"value", ret}, {"folder", folder}, {"filename", filename}, {"ssl_cert_file", env_or("SSL_CERT_FILE", "")}, {"curl_ca_bundle", env_or("CURL_CA_BUNDLE", "")}};
|
||||
host_log_json("net.set_cert_file", r);
|
||||
return r;
|
||||
}
|
||||
if (method == "net.set_country_code") {
|
||||
auto f = net<int (*)(void*, std::string)>("bambu_network_set_country_code");
|
||||
|
|
@ -928,8 +945,10 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
auto f = net<int (*)(void*, std::string)>("bambu_network_change_user");
|
||||
auto a = lookup_agent();
|
||||
if (!f || !a) return not_supported(method);
|
||||
const int ret = f(a, payload.value("user_info", std::string()));
|
||||
nlohmann::json r{{"ok", true}, {"value", ret}};
|
||||
const auto original_user_info = payload.value("user_info", std::string());
|
||||
const auto normalized_user_info = normalize_change_user_payload_string(original_user_info);
|
||||
const int ret = f(a, normalized_user_info);
|
||||
nlohmann::json r{{"ok", true}, {"value", ret}, {"user_info_original", original_user_info}, {"user_info_normalized", normalized_user_info}, {"user_info_was_normalized", normalized_user_info != original_user_info}};
|
||||
auto g1 = net<bool (*)(void*)>("bambu_network_is_user_login"); if (g1) r["logged_in"] = g1(a);
|
||||
auto g2 = net<std::string (*)(void*)>("bambu_network_get_user_id"); if (g2) r["user_id"] = g2(a);
|
||||
auto g3 = net<std::string (*)(void*)>("bambu_network_get_user_name"); if (g3) r["user_name"] = g3(a);
|
||||
|
|
@ -939,6 +958,7 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
auto g7 = net<std::string (*)(void*)>("bambu_network_build_logout_cmd"); if (g7) r["logout_cmd"] = g7(a);
|
||||
auto g8 = net<std::string (*)(void*)>("bambu_network_build_login_info"); if (g8) r["login_info"] = g8(a);
|
||||
auto g9 = net<std::string (*)(void*)>("bambu_network_get_bambulab_host"); if (g9) r["bambulab_host"] = g9(a);
|
||||
host_log_json("net.change_user", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1104,7 +1124,7 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
if (method == "net.get_setting_list2") { auto f = net<int (*)(void*, std::string, CheckFn, ProgressFn, WasCancelledFn)>("bambu_network_get_setting_list2"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); const auto job_id = payload.value("client_job_id", 0LL); const auto params = payload.value("params", nlohmann::json::object()); auto job = std::make_shared<HostJobState>(); job->job_id = job_id; job->agent_handle = agent_id; job->kind = "get_setting_list2"; register_job(job); const int ret = f(a, params.value("bundle_version", std::string()), [this, job](std::map<std::string, std::string> info) { const auto request_id = m_next_wait_request.fetch_add(1); { std::lock_guard<std::mutex> lock(job->wait_mutex); job->wait_request_id = request_id; job->wait_reply_ready = false; job->wait_reply_value = true; } queue_event(job->agent_handle, "job.check", {{"job_id", job->job_id}, {"kind", job->kind}, {"request_id", request_id}, {"info", info}}); std::unique_lock<std::mutex> lock(job->wait_mutex); job->wait_cv.wait(lock, [&] { return job->wait_reply_ready && job->wait_request_id == request_id; }); return job->wait_reply_value; }, [this, job](int progress) { queue_event(job->agent_handle, "job.progress", {{"job_id", job->job_id}, {"kind", job->kind}, {"progress", progress}}); }, [job]() { return job->cancel_requested.load(); }); unregister_job(job_id); return {{"ok", true}, {"value", ret}, {"job_id", job_id}}; }
|
||||
if (method == "net.put_setting") { auto f = net<int (*)(void*, std::string, std::string, std::map<std::string, std::string>*, unsigned int*)>("bambu_network_put_setting"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); auto values = json_to_string_map(payload.value("values", nlohmann::json::object())); unsigned int http_code = 0; const int ret = f(a, payload.value("setting_id", std::string()), payload.value("name", std::string()), &values, &http_code); return {{"ok", true}, {"value", ret}, {"http_code", http_code}}; }
|
||||
if (method == "net.delete_setting") { auto f = net<int (*)(void*, std::string)>("bambu_network_delete_setting"); auto a = lookup_agent(); return f && a ? nlohmann::json{{"ok", true}, {"value", f(a, payload.value("setting_id", std::string()))}} : not_supported(method); }
|
||||
if (method == "net.set_extra_http_header") { auto f = net<int (*)(void*, std::map<std::string, std::string>)>("bambu_network_set_extra_http_header"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); auto headers = json_to_string_map(payload.value("headers", nlohmann::json::object())); return {{"ok", true}, {"value", f(a, headers)}}; }
|
||||
if (method == "net.set_extra_http_header") { auto f = net<int (*)(void*, std::map<std::string, std::string>)>("bambu_network_set_extra_http_header"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); auto headers = json_to_string_map(payload.value("headers", nlohmann::json::object())); const int ret = f(a, headers); nlohmann::json r{{"ok", true}, {"value", ret}, {"headers", headers}}; host_log_json("net.set_extra_http_header", r); return r; }
|
||||
if (method == "net.get_my_message") { auto f = net<int (*)(void*, int, int, int, unsigned int*, std::string*)>("bambu_network_get_my_message"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); unsigned int http_code = 0; std::string http_body; const int ret = f(a, payload.value("type", 0), payload.value("after", 0), payload.value("limit", 20), &http_code, &http_body); return {{"ok", true}, {"value", ret}, {"http_code", http_code}, {"http_body", http_body}}; }
|
||||
if (method == "net.check_user_task_report") { auto f = net<int (*)(void*, int*, bool*)>("bambu_network_check_user_task_report"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); int task_id = 0; bool printable = false; const int ret = f(a, &task_id, &printable); return {{"ok", true}, {"value", ret}, {"task_id", task_id}, {"printable", printable}}; }
|
||||
if (method == "net.get_user_print_info") { auto f = net<int (*)(void*, unsigned int*, std::string*)>("bambu_network_get_user_print_info"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); unsigned int http_code = 0; std::string http_body; const int ret = f(a, &http_code, &http_body); return {{"ok", true}, {"value", ret}, {"http_code", http_code}, {"http_body", http_body}}; }
|
||||
|
|
@ -1118,13 +1138,13 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
if (method == "net.get_model_mall_home_url") { auto f = net<int (*)(void*, std::string*)>("bambu_network_get_model_mall_home_url"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::string url; const int ret = f(a, &url); return {{"ok", true}, {"value", ret}, {"url", url}}; }
|
||||
if (method == "net.get_model_mall_detail_url") { auto f = net<int (*)(void*, std::string*, std::string)>("bambu_network_get_model_mall_detail_url"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::string url; const int ret = f(a, &url, payload.value("id", std::string())); return {{"ok", true}, {"value", ret}, {"url", url}}; }
|
||||
if (method == "net.get_subtask") { auto f = net<int (*)(void*, Slic3r::BBLModelTask*, OnGetSubTaskFn)>("bambu_network_get_subtask"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); Slic3r::BBLModelTask task{}; if (payload.contains("task") && payload["task"].is_object()) json_to_model_task(payload["task"], task); return wait_model_task_callback([&](auto cb) { return f(a, &task, cb); }); }
|
||||
if (method == "net.put_model_mall_rating") { auto f = net<int (*)(void*, int, int, std::string, std::vector<std::string>, unsigned int&, std::string&)>("bambu_network_put_model_mall_rating"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::vector<std::string> images = windows_paths_to_wsl(payload.value("images", std::vector<std::string>())); unsigned int http_code = 0; std::string http_error; const int ret = f(a, payload.value("rating_id", 0), payload.value("score", 0), payload.value("content", std::string()), images, http_code, http_error); return {{"ok", true}, {"value", ret}, {"http_code", http_code}, {"http_error", http_error}}; }
|
||||
if (method == "net.put_model_mall_rating") { auto f = net<int (*)(void*, int, int, std::string, std::vector<std::string>, unsigned int&, std::string&)>("bambu_network_put_model_mall_rating"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); unsigned int http_code = 0; std::string http_error; const int ret = f(a, payload.value("rating_id", 0), payload.value("score", 0), payload.value("content", std::string()), payload.value("images", std::vector<std::string>()), http_code, http_error); return {{"ok", true}, {"value", ret}, {"http_code", http_code}, {"http_error", http_error}}; }
|
||||
if (method == "net.get_oss_config") { auto f = net<int (*)(void*, std::string&, std::string, unsigned int&, std::string&)>("bambu_network_get_oss_config"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::string config; unsigned int http_code = 0; std::string http_error; const int ret = f(a, config, payload.value("country_code", std::string()), http_code, http_error); return {{"ok", true}, {"value", ret}, {"config", config}, {"http_code", http_code}, {"http_error", http_error}}; }
|
||||
if (method == "net.put_rating_picture_oss") { auto f = net<int (*)(void*, std::string&, std::string&, std::string, int, unsigned int&, std::string&)>("bambu_network_put_rating_picture_oss"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::string config = payload.value("config", std::string()); std::string pic_oss_path = windows_path_to_wsl(payload.value("pic_oss_path", std::string())); unsigned int http_code = 0; std::string http_error; const int ret = f(a, config, pic_oss_path, payload.value("model_id", std::string()), payload.value("profile_id", 0), http_code, http_error); return {{"ok", true}, {"value", ret}, {"config", config}, {"pic_oss_path", pic_oss_path}, {"http_code", http_code}, {"http_error", http_error}}; }
|
||||
if (method == "net.put_rating_picture_oss") { auto f = net<int (*)(void*, std::string&, std::string&, std::string, int, unsigned int&, std::string&)>("bambu_network_put_rating_picture_oss"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::string config = payload.value("config", std::string()); std::string pic_oss_path = payload.value("pic_oss_path", std::string()); unsigned int http_code = 0; std::string http_error; const int ret = f(a, config, pic_oss_path, payload.value("model_id", std::string()), payload.value("profile_id", 0), http_code, http_error); return {{"ok", true}, {"value", ret}, {"config", config}, {"pic_oss_path", pic_oss_path}, {"http_code", http_code}, {"http_error", http_error}}; }
|
||||
if (method == "net.get_model_mall_rating") { auto f = net<int (*)(void*, int, std::string&, unsigned int&, std::string&)>("bambu_network_get_model_mall_rating"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); std::string rating_result; unsigned int http_code = 0; std::string http_error; const int ret = f(a, payload.value("job_id", 0), rating_result, http_code, http_error); return {{"ok", true}, {"value", ret}, {"rating_result", rating_result}, {"http_code", http_code}, {"http_error", http_error}}; }
|
||||
if (method == "net.get_mw_user_preference") { auto f = net<int (*)(void*, std::function<void(std::string)>)>("bambu_network_get_mw_user_preference"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); return wait_string_callback([&](auto cb) { return f(a, cb); }); }
|
||||
if (method == "net.get_mw_user_4ulist") { auto f = net<int (*)(void*, int, int, std::function<void(std::string)>)>("bambu_network_get_mw_user_4ulist"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); return wait_string_callback([&](auto cb) { return f(a, payload.value("seed", 0), payload.value("limit", 0), cb); }); }
|
||||
if (method == "net.get_hms_snapshot") { auto f = net<int (*)(void*, std::string, std::string, std::function<void(std::string, int)>)>("bambu_network_get_hms_snapshot"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); const std::string file_name = windows_path_to_wsl(payload.value("file_name", std::string())); return wait_string_int_callback([&](auto cb) { return f(a, payload.value("dev_id", std::string()), file_name, cb); }); }
|
||||
if (method == "net.get_hms_snapshot") { auto f = net<int (*)(void*, std::string, std::string, std::function<void(std::string, int)>)>("bambu_network_get_hms_snapshot"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); return wait_string_int_callback([&](auto cb) { return f(a, payload.value("dev_id", std::string()), payload.value("file_name", std::string()), cb); }); }
|
||||
|
||||
if (method == "net.get_my_token") { auto f = net<int (*)(void*, std::string, unsigned int*, std::string*)>("bambu_network_get_my_token"); auto a = lookup_agent(); if (!f || !a) return not_supported(method); unsigned int http_code = 0; std::string http_body; const int ret = f(a, payload.value("ticket", std::string()), &http_code, &http_body); return {{"ok", true}, {"value", ret}, {"http_code", http_code}, {"http_body", http_body}}; }
|
||||
|
||||
|
|
@ -1374,8 +1394,7 @@ nlohmann::json LinuxPluginHost::handle(const std::string& method, const nlohmann
|
|||
auto f = src<int (*)(Bambu_Tunnel*, const char*)>("Bambu_Create");
|
||||
if (!f) return not_supported(method);
|
||||
Bambu_Tunnel tunnel = nullptr;
|
||||
const std::string path = windows_path_to_wsl(payload.value("path", std::string()));
|
||||
const int ret = f(&tunnel, path.c_str());
|
||||
const int ret = f(&tunnel, payload.value("path", std::string()).c_str());
|
||||
if (ret != 0)
|
||||
return {{"ok", true}, {"value", ret}, {"tunnel", 0}};
|
||||
const auto id = m_next_tunnel++;
|
||||
|
|
|
|||
|
|
@ -4,56 +4,43 @@ set -euo pipefail
|
|||
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||
PROJECT_DIR="$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)"
|
||||
RUNTIME_ROOT="$PROJECT_DIR/tools/pjarczak_bambu_linux_host/runtime/linux-x86_64"
|
||||
RUNTIME_LIB_DIR="$RUNTIME_ROOT/pjarczak_bambu_linux_host.runtime"
|
||||
|
||||
find_host_bin() {
|
||||
if [[ $# -gt 0 && -n "${1:-}" ]]; then
|
||||
if [[ -f "$1" ]]; then
|
||||
printf '%s\n' "$1"
|
||||
return 0
|
||||
fi
|
||||
if [[ -d "$1" ]]; then
|
||||
find "$1" -type f -name pjarczak_bambu_linux_host | head -n 1
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local name="$1"
|
||||
local candidate=""
|
||||
for candidate in \
|
||||
"$PROJECT_DIR/build/src/Release/pjarczak_bambu_linux_host" \
|
||||
"$PROJECT_DIR/build/pjarczak_bambu_linux_host" \
|
||||
"$PROJECT_DIR/build/src/pjarczak_bambu_linux_host"
|
||||
for candidate in "$PROJECT_DIR/build/src/Release/$name" "$PROJECT_DIR/build/$name" "$PROJECT_DIR/build/src/$name"
|
||||
do
|
||||
if [[ -f "$candidate" ]]; then
|
||||
printf '%s\n' "$candidate"
|
||||
printf '%s
|
||||
' "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
find "$PROJECT_DIR/build" -type f -name "$name" 2>/dev/null | head -n 1
|
||||
}
|
||||
|
||||
find "$PROJECT_DIR/build" -type f -name pjarczak_bambu_linux_host 2>/dev/null | head -n 1
|
||||
collect_runtime_libs() {
|
||||
local host_bin="$1"
|
||||
ldd "$host_bin" | awk '
|
||||
/=>/ && $3 ~ /^\// { print $3 }
|
||||
/^\// { print $1 }
|
||||
' | sort -u
|
||||
}
|
||||
|
||||
copy_runtime_libs() {
|
||||
local host_bin="$1"
|
||||
mkdir -p "$RUNTIME_LIB_DIR"
|
||||
|
||||
mapfile -t libs < <(
|
||||
ldd "$host_bin" | awk '
|
||||
/=>/ && $3 ~ /^\// { print $3 }
|
||||
/^\// { print $1 }
|
||||
' | sort -u
|
||||
)
|
||||
|
||||
local lib=""
|
||||
local base=""
|
||||
local host_abi1="$1"
|
||||
local host_abi0="$2"
|
||||
mkdir -p "$RUNTIME_ROOT"
|
||||
mapfile -t libs < <({ collect_runtime_libs "$host_abi1"; collect_runtime_libs "$host_abi0"; } | sort -u)
|
||||
local lib base
|
||||
for lib in "${libs[@]}"; do
|
||||
base="$(basename -- "$lib")"
|
||||
case "$base" in
|
||||
ld-linux*|libc.so.*|libm.so.*|libpthread.so.*|librt.so.*|libdl.so.*|libresolv.so.*|libnsl.so.*|libutil.so.*|libgcc_s.so.*)
|
||||
ld-linux*|libc.so.*|libm.so.*|libpthread.so.*|librt.so.*|libdl.so.*|libresolv.so.*|libnsl.so.*|libutil.so.*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
cp -Lf "$lib" "$RUNTIME_LIB_DIR/"
|
||||
cp -Lf "$lib" "$RUNTIME_ROOT/"
|
||||
done
|
||||
}
|
||||
|
||||
|
|
@ -62,21 +49,25 @@ if [[ "$(uname -m)" != "x86_64" ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
HOST_BIN="$(find_host_bin "${1:-}" || true)"
|
||||
if [[ -z "$HOST_BIN" || ! -f "$HOST_BIN" ]]; then
|
||||
echo "failed to find built pjarczak_bambu_linux_host under $PROJECT_DIR/build" >&2
|
||||
echo "build it first in the full Orca Linux build context, for example:" >&2
|
||||
HOST_ABI1="$(find_host_bin pjarczak_bambu_linux_host_abi1 || true)"
|
||||
HOST_ABI0="$(find_host_bin pjarczak_bambu_linux_host_abi0 || true)"
|
||||
if [[ -z "$HOST_ABI1" || ! -f "$HOST_ABI1" || -z "$HOST_ABI0" || ! -f "$HOST_ABI0" ]]; then
|
||||
echo "failed to find built pjarczak_bambu_linux_host_abi1/abi0 under $PROJECT_DIR/build" >&2
|
||||
echo "build them first in the full Orca Linux build context, for example:" >&2
|
||||
echo " cmake --build build --config Release --target pjarczak_bambu_linux_host" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf "$RUNTIME_ROOT"
|
||||
mkdir -p "$RUNTIME_ROOT" "$RUNTIME_LIB_DIR"
|
||||
mkdir -p "$RUNTIME_ROOT"
|
||||
|
||||
cp -f "$HOST_BIN" "$RUNTIME_ROOT/pjarczak_bambu_linux_host"
|
||||
chmod +x "$RUNTIME_ROOT/pjarczak_bambu_linux_host"
|
||||
cp -f "$PROJECT_DIR/tools/pjarczak_bambu_runtime/wsl/pjarczak_bambu_linux_host" "$RUNTIME_ROOT/pjarczak_bambu_linux_host"
|
||||
cp -f "$HOST_ABI1" "$RUNTIME_ROOT/pjarczak_bambu_linux_host_abi1"
|
||||
cp -f "$HOST_ABI0" "$RUNTIME_ROOT/pjarczak_bambu_linux_host_abi0"
|
||||
chmod +x "$RUNTIME_ROOT/pjarczak_bambu_linux_host" "$RUNTIME_ROOT/pjarczak_bambu_linux_host_abi1" "$RUNTIME_ROOT/pjarczak_bambu_linux_host_abi0"
|
||||
|
||||
copy_runtime_libs "$HOST_BIN"
|
||||
copy_runtime_libs "$HOST_ABI1" "$HOST_ABI0"
|
||||
|
||||
echo "linux host runtime packaged into:"
|
||||
echo " $RUNTIME_ROOT"
|
||||
find "$RUNTIME_ROOT" -maxdepth 1 -type f | sort
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
param(
|
||||
[Parameter(Mandatory = $true)][string]$OutputDir,
|
||||
[Parameter(Mandatory = $true)][string]$RootFs,
|
||||
[Parameter(Mandatory = $true)][string]$LinuxHostBinary,
|
||||
[string]$RuntimeDir = "",
|
||||
[Parameter(Mandatory = $true)][string]$LinuxHostAbi1,
|
||||
[Parameter(Mandatory = $true)][string]$LinuxHostAbi0,
|
||||
[string]$LinuxHostWrapper = "",
|
||||
[string]$BridgeDll = "",
|
||||
[string]$DistroName = "PJARCZAK-BAMBU"
|
||||
)
|
||||
|
|
@ -10,15 +11,9 @@ param(
|
|||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Get-ScriptDir {
|
||||
if ($PSScriptRoot) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if ($PSCommandPath) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation -and $MyInvocation.MyCommand -and $MyInvocation.MyCommand.Path) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
if ($PSScriptRoot) { return $PSScriptRoot }
|
||||
if ($PSCommandPath) { return (Split-Path -Parent $PSCommandPath) }
|
||||
if ($MyInvocation -and $MyInvocation.MyCommand -and $MyInvocation.MyCommand.Path) { return (Split-Path -Parent $MyInvocation.MyCommand.Path) }
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
|
|
@ -27,8 +22,12 @@ $toolsRoot = [System.IO.Path]::GetFullPath((Join-Path $scriptDir '..'))
|
|||
$wslRoot = Join-Path $toolsRoot 'wsl'
|
||||
|
||||
if (-not (Test-Path $RootFs)) { throw "RootFs not found: $RootFs" }
|
||||
if (-not (Test-Path $LinuxHostBinary)) { throw "LinuxHostBinary not found: $LinuxHostBinary" }
|
||||
if ($RuntimeDir -and -not (Test-Path $RuntimeDir)) { throw "RuntimeDir not found: $RuntimeDir" }
|
||||
if (-not (Test-Path $LinuxHostAbi1)) { throw "LinuxHostAbi1 not found: $LinuxHostAbi1" }
|
||||
if (-not (Test-Path $LinuxHostAbi0)) { throw "LinuxHostAbi0 not found: $LinuxHostAbi0" }
|
||||
if ([string]::IsNullOrWhiteSpace($LinuxHostWrapper)) {
|
||||
$LinuxHostWrapper = Join-Path $wslRoot 'pjarczak_bambu_linux_host'
|
||||
}
|
||||
if (-not (Test-Path $LinuxHostWrapper)) { throw "LinuxHostWrapper not found: $LinuxHostWrapper" }
|
||||
if ($BridgeDll -and -not (Test-Path $BridgeDll)) { throw "BridgeDll not found: $BridgeDll" }
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
|
||||
|
|
@ -42,20 +41,13 @@ Copy-Item -Force (Join-Path $wslRoot 'pjarczak_wsl_distro.txt') (Join-Path $Outp
|
|||
Set-Content -Path (Join-Path $OutputDir 'pjarczak_wsl_distro.txt') -Value ($DistroName + [Environment]::NewLine) -NoNewline:$false
|
||||
|
||||
Copy-Item -Force $RootFs (Join-Path $OutputDir 'windows-wsl2-rootfs.tar')
|
||||
Copy-Item -Force $LinuxHostBinary (Join-Path $OutputDir 'pjarczak_bambu_linux_host')
|
||||
Copy-Item -Force $LinuxHostWrapper (Join-Path $OutputDir 'pjarczak_bambu_linux_host')
|
||||
Copy-Item -Force $LinuxHostAbi1 (Join-Path $OutputDir 'pjarczak_bambu_linux_host_abi1')
|
||||
Copy-Item -Force $LinuxHostAbi0 (Join-Path $OutputDir 'pjarczak_bambu_linux_host_abi0')
|
||||
|
||||
if ($BridgeDll) {
|
||||
Copy-Item -Force $BridgeDll (Join-Path $OutputDir 'pjarczak_bambu_networking_bridge.dll')
|
||||
}
|
||||
|
||||
if ($RuntimeDir) {
|
||||
$destRuntime = Join-Path $OutputDir 'pjarczak_bambu_linux_host.runtime'
|
||||
if (Test-Path $destRuntime) {
|
||||
Remove-Item -Recurse -Force $destRuntime
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $destRuntime | Out-Null
|
||||
Copy-Item -Recurse -Force (Join-Path $RuntimeDir '*') $destRuntime
|
||||
}
|
||||
|
||||
Write-Host 'Bundle created:'
|
||||
Write-Host $OutputDir
|
||||
|
|
|
|||
|
|
@ -4,29 +4,32 @@ param(
|
|||
[string]$DistroName = "",
|
||||
[string]$InstallDir = "",
|
||||
[switch]$ReplaceExisting,
|
||||
[switch]$SkipCopyToPluginDir
|
||||
[switch]$SkipCopyToPluginDir,
|
||||
[switch]$CoreInstallOnly
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Get-ScriptDir {
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
if ($PSScriptRoot) { return $PSScriptRoot }
|
||||
if ($PSCommandPath) { return (Split-Path -Parent $PSCommandPath) }
|
||||
if ($MyInvocation.MyCommand -and $MyInvocation.MyCommand.Path) { return (Split-Path -Parent $MyInvocation.MyCommand.Path) }
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
function Convert-FileToLf([string]$Path) {
|
||||
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) {
|
||||
return
|
||||
}
|
||||
function Test-IsAdmin {
|
||||
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($id)
|
||||
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
function Invoke-Native([string]$FilePath, [string[]]$ArgumentList) {
|
||||
& $FilePath @ArgumentList
|
||||
return $LASTEXITCODE
|
||||
}
|
||||
|
||||
function Convert-FileToLf([string]$Path) {
|
||||
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) { return }
|
||||
$content = [System.IO.File]::ReadAllText($Path)
|
||||
$content = $content.Replace("`r`n", "`n").Replace("`r", "`n")
|
||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
||||
|
|
@ -34,82 +37,78 @@ function Convert-FileToLf([string]$Path) {
|
|||
}
|
||||
|
||||
function Copy-IfExists([string]$Source, [string]$Destination) {
|
||||
if (Test-Path $Source) {
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $Destination) | Out-Null
|
||||
Copy-Item -Force $Source $Destination
|
||||
}
|
||||
if (!(Test-Path $Source)) { return }
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $Destination) | Out-Null
|
||||
Copy-Item -Force $Source $Destination
|
||||
}
|
||||
|
||||
function Sync-Directory([string]$SourceDir, [string]$DestinationDir) {
|
||||
if (!(Test-Path $SourceDir)) {
|
||||
return
|
||||
}
|
||||
if (Test-Path $DestinationDir) {
|
||||
Remove-Item -Recurse -Force $DestinationDir
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null
|
||||
Copy-Item -Recurse -Force (Join-Path $SourceDir '*') $DestinationDir
|
||||
}
|
||||
|
||||
function Resolve-DistroName([string]$Dir, [string]$Current) {
|
||||
if (-not [string]::IsNullOrWhiteSpace($Current)) {
|
||||
return $Current
|
||||
}
|
||||
|
||||
$distroFile = Join-Path $Dir 'pjarczak_wsl_distro.txt'
|
||||
function Resolve-DistroName([string]$BaseDir, [string]$Current) {
|
||||
if (-not [string]::IsNullOrWhiteSpace($Current)) { return $Current }
|
||||
if ($env:PJARCZAK_WSL_DISTRO) { return $env:PJARCZAK_WSL_DISTRO.Trim() }
|
||||
$distroFile = Join-Path $BaseDir 'pjarczak_wsl_distro.txt'
|
||||
if (Test-Path $distroFile) {
|
||||
$value = (Get-Content $distroFile -Raw).Trim()
|
||||
if (-not [string]::IsNullOrWhiteSpace($value)) {
|
||||
return $value
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($value)) { return $value }
|
||||
}
|
||||
|
||||
if ($env:PJARCZAK_WSL_DISTRO) {
|
||||
return $env:PJARCZAK_WSL_DISTRO.Trim()
|
||||
}
|
||||
|
||||
return 'PJARCZAK-BAMBU'
|
||||
return 'BambuBridge-OrcaSlicer'
|
||||
}
|
||||
|
||||
$scriptDir = Get-ScriptDir
|
||||
$defaultPackageDir = $scriptDir
|
||||
if ([string]::IsNullOrWhiteSpace($PackageDir)) {
|
||||
$PackageDir = $defaultPackageDir
|
||||
$PackageDir = Get-ScriptDir
|
||||
}
|
||||
$PackageDir = [System.IO.Path]::GetFullPath($PackageDir)
|
||||
|
||||
$DistroName = Resolve-DistroName $PackageDir $DistroName
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($PluginDir)) {
|
||||
if (-not $env:APPDATA) {
|
||||
throw 'APPDATA is not available'
|
||||
}
|
||||
if (-not $env:APPDATA) { throw 'APPDATA is not available' }
|
||||
$PluginDir = Join-Path $env:APPDATA 'OrcaSlicer\plugins'
|
||||
}
|
||||
$PluginDir = [System.IO.Path]::GetFullPath($PluginDir)
|
||||
|
||||
$PluginCacheDir = if ($env:APPDATA) { Join-Path $env:APPDATA 'OrcaSlicer\ota' } else { '' }
|
||||
$DistroName = Resolve-DistroName $PackageDir $DistroName
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($InstallDir)) {
|
||||
if (-not $env:LOCALAPPDATA) {
|
||||
throw 'LOCALAPPDATA is not available'
|
||||
}
|
||||
if (-not $env:LOCALAPPDATA) { throw 'LOCALAPPDATA is not available' }
|
||||
$InstallDir = Join-Path $env:LOCALAPPDATA $DistroName
|
||||
}
|
||||
$InstallDir = [System.IO.Path]::GetFullPath($InstallDir)
|
||||
|
||||
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
|
||||
if (!(Test-Path $wsl)) {
|
||||
throw 'wsl.exe not found'
|
||||
throw 'wsl.exe not found. This Windows build does not expose WSL commands.'
|
||||
}
|
||||
|
||||
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
|
||||
if (Test-Path $bootstrapPath) {
|
||||
Convert-FileToLf $bootstrapPath
|
||||
}
|
||||
|
||||
$packageFiles = @(
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_bambu_linux_host_abi1',
|
||||
'pjarczak_bambu_linux_host_abi0',
|
||||
'pjarczak_wsl_run_host.sh',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'install_runtime.ps1',
|
||||
'install_runtime.cmd',
|
||||
'verify_runtime.ps1',
|
||||
'windows-wsl2-rootfs.tar'
|
||||
)
|
||||
foreach ($name in $packageFiles) {
|
||||
if (!(Test-Path (Join-Path $PackageDir $name))) {
|
||||
throw "Missing package file: $name"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipCopyToPluginDir) {
|
||||
New-Item -ItemType Directory -Force -Path $PluginDir | Out-Null
|
||||
|
||||
$fileNames = @(
|
||||
$copyNames = @(
|
||||
'pjarczak_bambu_networking_bridge.dll',
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'pjarczak_bambu_linux_host_abi1',
|
||||
'pjarczak_bambu_linux_host_abi0',
|
||||
'pjarczak_wsl_run_host.sh',
|
||||
'pjarczak-wsl-run-host.sh',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'install_runtime.ps1',
|
||||
'install_runtime.cmd',
|
||||
'verify_runtime.ps1',
|
||||
|
|
@ -121,74 +120,97 @@ if (-not $SkipCopyToPluginDir) {
|
|||
'libBambuSource.so',
|
||||
'liblive555.so',
|
||||
'libagora_rtc_sdk.so',
|
||||
'libagora-fdkaac.so'
|
||||
'libagora-fdkaac.so',
|
||||
'libz.so.1',
|
||||
'libzstd.so.1',
|
||||
'libcrypto.so.3',
|
||||
'libstdc++.so.6',
|
||||
'libgcc_s.so.1',
|
||||
'ca-certificates.crt',
|
||||
'slicer_base64.cer'
|
||||
)
|
||||
|
||||
foreach ($name in $fileNames) {
|
||||
foreach ($name in $copyNames) {
|
||||
Copy-IfExists (Join-Path $PackageDir $name) (Join-Path $PluginDir $name)
|
||||
}
|
||||
|
||||
Sync-Directory (Join-Path $PackageDir 'pjarczak_bambu_linux_host.runtime') (Join-Path $PluginDir 'pjarczak_bambu_linux_host.runtime')
|
||||
$PackageDir = $PluginDir
|
||||
}
|
||||
|
||||
$requiredFiles = @(
|
||||
'pjarczak_bambu_networking_bridge.dll',
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'install_runtime.ps1',
|
||||
'verify_runtime.ps1',
|
||||
'windows-wsl2-rootfs.tar'
|
||||
)
|
||||
|
||||
foreach ($name in $requiredFiles) {
|
||||
$path = Join-Path $PackageDir $name
|
||||
if (!(Test-Path $path)) {
|
||||
throw "Missing package file: $name"
|
||||
}
|
||||
}
|
||||
|
||||
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
|
||||
if (!(Test-Path $bootstrapPath)) { $bootstrapPath = Join-Path $PackageDir 'pjarczak-wsl-run-host.sh' }
|
||||
if (!(Test-Path $bootstrapPath)) {
|
||||
throw 'Missing package file: pjarczak_wsl_run_host.sh'
|
||||
}
|
||||
|
||||
$needCoreInstall = $false
|
||||
try {
|
||||
& $wsl --status | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { $needCoreInstall = $true }
|
||||
} catch {
|
||||
throw 'WSL is not ready. Run as Administrator once and execute: wsl --install --no-distribution ; wsl --update ; then reboot.'
|
||||
$needCoreInstall = $true
|
||||
}
|
||||
|
||||
Convert-FileToLf $bootstrapPath
|
||||
if ($needCoreInstall -and -not (Test-IsAdmin)) {
|
||||
$self = Join-Path $PackageDir 'install_runtime.ps1'
|
||||
$args = @(
|
||||
'-NoProfile',
|
||||
'-ExecutionPolicy', 'Bypass',
|
||||
'-File', ('"' + $self + '"'),
|
||||
'-PackageDir', ('"' + $PackageDir + '"'),
|
||||
'-PluginDir', ('"' + $PluginDir + '"'),
|
||||
'-DistroName', ('"' + $DistroName + '"'),
|
||||
'-InstallDir', ('"' + $InstallDir + '"'),
|
||||
'-SkipCopyToPluginDir',
|
||||
'-CoreInstallOnly'
|
||||
)
|
||||
$proc = Start-Process -FilePath 'powershell.exe' -Verb RunAs -ArgumentList $args -Wait -PassThru
|
||||
if ($proc.ExitCode -ne 0) { exit $proc.ExitCode }
|
||||
$needCoreInstall = $false
|
||||
}
|
||||
|
||||
$rebootRequired = $false
|
||||
if ($needCoreInstall) {
|
||||
Write-Host 'Installing or enabling WSL core components'
|
||||
$code = Invoke-Native $wsl @('--install', '--no-distribution')
|
||||
if ($code -eq 1641 -or $code -eq 3010) {
|
||||
$rebootRequired = $true
|
||||
} elseif ($code -ne 0) {
|
||||
throw "wsl --install --no-distribution failed with exit code $code"
|
||||
}
|
||||
$code = Invoke-Native $wsl @('--set-default-version', '2')
|
||||
if ($code -ne 0) { throw "wsl --set-default-version 2 failed with exit code $code" }
|
||||
$code = Invoke-Native $wsl @('--update')
|
||||
if ($code -ne 0) { throw "wsl --update failed with exit code $code" }
|
||||
}
|
||||
|
||||
if ($rebootRequired) {
|
||||
Write-Host 'WSL install requested a reboot.'
|
||||
exit 3010
|
||||
}
|
||||
|
||||
if ($CoreInstallOnly) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
& $wsl --status | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'WSL is still not ready after install/update'
|
||||
}
|
||||
|
||||
$distroList = & $wsl -l -q 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'Failed to query installed WSL distros'
|
||||
}
|
||||
$hasDistro = ($distroList | ForEach-Object { $_.Trim() } | Where-Object { $_ -eq $DistroName })
|
||||
|
||||
$alreadyInstalled = $distroList | ForEach-Object { $_.Trim() } | Where-Object { $_ -eq $DistroName }
|
||||
if ($alreadyInstalled) {
|
||||
if ($ReplaceExisting) {
|
||||
& $wsl --terminate $DistroName 2>$null | Out-Null
|
||||
& $wsl --unregister $DistroName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to unregister existing distro '$DistroName'"
|
||||
}
|
||||
$alreadyInstalled = $null
|
||||
}
|
||||
if ($hasDistro -and $ReplaceExisting) {
|
||||
& $wsl --terminate $DistroName 2>$null | Out-Null
|
||||
& $wsl --unregister $DistroName
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to unregister existing distro '$DistroName'" }
|
||||
$hasDistro = $false
|
||||
}
|
||||
|
||||
if (-not $alreadyInstalled) {
|
||||
if (-not $hasDistro) {
|
||||
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
||||
|
||||
$rootFsTar = Join-Path $PackageDir 'windows-wsl2-rootfs.tar'
|
||||
& $wsl --import $DistroName $InstallDir $rootFsTar --version 2
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "wsl --import failed for distro '$DistroName'"
|
||||
}
|
||||
if ($LASTEXITCODE -ne 0) { throw "wsl --import failed for distro '$DistroName'" }
|
||||
|
||||
$wslConf = @'
|
||||
$setupCmd = @"
|
||||
cat > /etc/wsl.conf <<'WSL_EOF'
|
||||
[automount]
|
||||
enabled=true
|
||||
root=/mnt/
|
||||
|
|
@ -197,24 +219,13 @@ mountFsTab=false
|
|||
[interop]
|
||||
enabled=true
|
||||
appendWindowsPath=false
|
||||
'@
|
||||
|
||||
$setupCmd = @"
|
||||
cat > /etc/wsl.conf <<'WSL_EOF'
|
||||
$wslConf
|
||||
WSL_EOF
|
||||
mkdir -p /root/.pjarczak-bambu-runtime
|
||||
"@
|
||||
|
||||
& $wsl -d $DistroName --user root -- sh -lc $setupCmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to initialize distro '$DistroName'"
|
||||
}
|
||||
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to initialize distro '$DistroName'" }
|
||||
& $wsl --terminate $DistroName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to terminate distro '$DistroName' after initialization"
|
||||
}
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to terminate distro '$DistroName' after initialization" }
|
||||
}
|
||||
|
||||
$verifyArgs = @(
|
||||
|
|
@ -223,25 +234,11 @@ $verifyArgs = @(
|
|||
'-File', (Join-Path $PackageDir 'verify_runtime.ps1'),
|
||||
'-PackageDir', $PackageDir,
|
||||
'-DistroName', $DistroName,
|
||||
'-PluginCacheDir', $PluginDir,
|
||||
'-AllowMissingLinuxPlugin'
|
||||
'-PluginCacheDir', $PluginCacheDir,
|
||||
'-AllowMissingLinuxPlugin',
|
||||
'-SkipProbe'
|
||||
)
|
||||
|
||||
$verifyShell = $null
|
||||
$pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||
if ($pwshCmd) {
|
||||
$verifyShell = $pwshCmd.Source
|
||||
} else {
|
||||
$powershellCmd = Get-Command powershell -ErrorAction SilentlyContinue
|
||||
if ($powershellCmd) {
|
||||
$verifyShell = $powershellCmd.Source
|
||||
}
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($verifyShell)) {
|
||||
throw 'No PowerShell host found to run verify_runtime.ps1'
|
||||
}
|
||||
|
||||
& $verifyShell @verifyArgs
|
||||
& powershell.exe @verifyArgs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'verify_runtime.ps1 failed'
|
||||
}
|
||||
|
|
@ -250,5 +247,4 @@ Write-Host ''
|
|||
Write-Host "WSL runtime installed to: $PackageDir"
|
||||
Write-Host "WSL distro: $DistroName"
|
||||
Write-Host "WSL install dir: $InstallDir"
|
||||
Write-Host 'Now start OrcaSlicer.'
|
||||
Write-Host 'On first run let it download bambunetwork, close the app completely, then start it again.'
|
||||
Write-Host 'On first run let Orca download bambunetwork if needed, then restart Orca.'
|
||||
|
|
|
|||
59
tools/pjarczak_bambu_runtime/wsl/pjarczak_bambu_linux_host
Normal file
59
tools/pjarczak_bambu_runtime/wsl/pjarczak_bambu_linux_host
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
CACHE_FILE="$DIR/.selected_host_abi"
|
||||
|
||||
run_probe() {
|
||||
bin="$1"
|
||||
[ -x "$bin" ] || return 1
|
||||
LD_LIBRARY_PATH="$DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
|
||||
PJARCZAK_BAMBU_PROBE_LOG_DIR="${PJARCZAK_BAMBU_PROBE_LOG_DIR:-$DIR}" \
|
||||
PJARCZAK_BAMBU_COUNTRY_CODE="${PJARCZAK_BAMBU_COUNTRY_CODE:-PL}" \
|
||||
"$bin" --probe-auth >/dev/null 2>&1
|
||||
}
|
||||
|
||||
choose_bin() {
|
||||
forced="${PJARCZAK_FORCE_HOST_ABI:-}"
|
||||
if [ -n "$forced" ] && [ -x "$DIR/pjarczak_bambu_linux_host_$forced" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$forced"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -f "$CACHE_FILE" ]; then
|
||||
cached=$(cat "$CACHE_FILE" 2>/dev/null || true)
|
||||
if [ -n "$cached" ] && [ -x "$DIR/pjarczak_bambu_linux_host_$cached" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$cached"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
for abi in abi1 abi0; do
|
||||
if run_probe "$DIR/pjarczak_bambu_linux_host_$abi"; then
|
||||
printf '%s' "$abi" > "$CACHE_FILE"
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$abi"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -x "$DIR/pjarczak_bambu_linux_host_abi1" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_abi1"
|
||||
return 0
|
||||
fi
|
||||
if [ -x "$DIR/pjarczak_bambu_linux_host_abi0" ]; then
|
||||
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_abi0"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
BIN=$(choose_bin) || {
|
||||
echo "no compatible host ABI variant found" >&2
|
||||
exit 127
|
||||
}
|
||||
if [ "${1:-}" = "--print-bin" ]; then
|
||||
printf '%s\n' "$BIN"
|
||||
exit 0
|
||||
fi
|
||||
export LD_LIBRARY_PATH="$DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
exec "$BIN" "$@"
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
log() {
|
||||
printf '%s\n' "[pjarczak_wsl_run_host] $*" >&2
|
||||
}
|
||||
|
||||
MODE="run"
|
||||
if [ "${1:-}" = "--probe" ]; then
|
||||
MODE="probe"
|
||||
|
|
@ -10,30 +14,22 @@ fi
|
|||
PACKAGE_DIR="${1:-${PJARCZAK_BAMBU_WINDOWS_PLUGIN_DIR:-}}"
|
||||
PLUGIN_CACHE_DIR="${2:-${PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR:-}}"
|
||||
if [ -z "$PACKAGE_DIR" ]; then
|
||||
echo "missing Windows package directory path" >&2
|
||||
log "missing Windows package directory path"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
RUNTIME_SUBDIR="$PACKAGE_DIR/pjarczak_bambu_linux_host.runtime"
|
||||
HOST_SRC="$PACKAGE_DIR/pjarczak_bambu_linux_host"
|
||||
if [ ! -f "$HOST_SRC" ] && [ -f "$RUNTIME_SUBDIR/pjarczak_bambu_linux_host" ]; then
|
||||
HOST_SRC="$RUNTIME_SUBDIR/pjarczak_bambu_linux_host"
|
||||
fi
|
||||
if [ ! -f "$HOST_SRC" ]; then
|
||||
echo "missing runtime file: $HOST_SRC" >&2
|
||||
log "missing runtime file: $HOST_SRC"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
find_payload_file() {
|
||||
local name="$1"
|
||||
find_preferred_file() {
|
||||
name="$1"
|
||||
if [ -f "$PACKAGE_DIR/$name" ]; then
|
||||
printf '%s\n' "$PACKAGE_DIR/$name"
|
||||
return 0
|
||||
fi
|
||||
if [ -f "$RUNTIME_SUBDIR/$name" ]; then
|
||||
printf '%s\n' "$RUNTIME_SUBDIR/$name"
|
||||
return 0
|
||||
fi
|
||||
if [ -n "$PLUGIN_CACHE_DIR" ] && [ -f "$PLUGIN_CACHE_DIR/$name" ]; then
|
||||
printf '%s\n' "$PLUGIN_CACHE_DIR/$name"
|
||||
return 0
|
||||
|
|
@ -42,138 +38,191 @@ find_payload_file() {
|
|||
}
|
||||
|
||||
resolve_payload_sources() {
|
||||
NETWORK_SRC="$(find_payload_file libbambu_networking.so || true)"
|
||||
SOURCE_SRC="$(find_payload_file libBambuSource.so || true)"
|
||||
LIVE555_SRC="$(find_payload_file liblive555.so || true)"
|
||||
MANIFEST_SRC=""
|
||||
if [ -f "$PACKAGE_DIR/linux_payload_manifest.json" ]; then
|
||||
MANIFEST_SRC="$PACKAGE_DIR/linux_payload_manifest.json"
|
||||
elif [ -f "$RUNTIME_SUBDIR/linux_payload_manifest.json" ]; then
|
||||
MANIFEST_SRC="$RUNTIME_SUBDIR/linux_payload_manifest.json"
|
||||
elif [ -n "$PLUGIN_CACHE_DIR" ] && [ -f "$PLUGIN_CACHE_DIR/linux_payload_manifest.json" ]; then
|
||||
MANIFEST_SRC="$PLUGIN_CACHE_DIR/linux_payload_manifest.json"
|
||||
fi
|
||||
NETWORK_SRC="$(find_preferred_file libbambu_networking.so || true)"
|
||||
SOURCE_SRC="$(find_preferred_file libBambuSource.so || true)"
|
||||
ABI1_SRC="$(find_preferred_file pjarczak_bambu_linux_host_abi1 || true)"
|
||||
ABI0_SRC="$(find_preferred_file pjarczak_bambu_linux_host_abi0 || true)"
|
||||
CA_BUNDLE_SRC="$(find_preferred_file ca-certificates.crt || true)"
|
||||
SLICER_CERT_SRC="$(find_preferred_file slicer_base64.cer || true)"
|
||||
MANIFEST_SRC="$(find_preferred_file linux_payload_manifest.json || true)"
|
||||
}
|
||||
|
||||
wait_for_payload_sources() {
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
WAIT_SECS="${PJARCZAK_BAMBU_PLUGIN_WAIT_SECS:-300}"
|
||||
SLEEP_SECS="${PJARCZAK_BAMBU_PLUGIN_WAIT_INTERVAL_SECS:-2}"
|
||||
DEADLINE=$(( $(date +%s) + WAIT_SECS ))
|
||||
|
||||
while :; do
|
||||
resolve_payload_sources
|
||||
if [ -n "$NETWORK_SRC" ] && [ -n "$SOURCE_SRC" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
NOW=$(date +%s)
|
||||
if [ "$NOW" -ge "$DEADLINE" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
[ "$NOW" -lt "$DEADLINE" ] || return 1
|
||||
sleep "$SLEEP_SECS"
|
||||
done
|
||||
}
|
||||
|
||||
resolve_payload_sources
|
||||
|
||||
if [ -z "$NETWORK_SRC" ] || [ -z "$SOURCE_SRC" ]; then
|
||||
echo "plugin_not_downloaded package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}" >&2
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
exit 3
|
||||
fi
|
||||
if ! wait_for_payload_sources; then
|
||||
echo "plugin_not_downloaded_timeout package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}" >&2
|
||||
exit 127
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v sha256sum >/dev/null 2>&1; then
|
||||
echo "sha256sum not found inside WSL distro" >&2
|
||||
exit 127
|
||||
fi
|
||||
|
||||
RUNTIME_BASE="${PJARCZAK_BAMBU_WSL_RUNTIME_DIR:-/root/.pjarczak-bambu-runtime}"
|
||||
mkdir -p "$RUNTIME_BASE"
|
||||
|
||||
RUNTIME_HASH="$({ sha256sum "$HOST_SRC" "$NETWORK_SRC" "$SOURCE_SRC"; [ -n "$LIVE555_SRC" ] && sha256sum "$LIVE555_SRC"; [ -n "$MANIFEST_SRC" ] && sha256sum "$MANIFEST_SRC"; } | sha256sum | cut -d ' ' -f1)"
|
||||
TARGET_DIR="$RUNTIME_BASE/$RUNTIME_HASH"
|
||||
CURRENT_DIR="$RUNTIME_BASE/current"
|
||||
|
||||
if [ ! -d "$TARGET_DIR" ]; then
|
||||
TMP_DIR="$RUNTIME_BASE/.tmp-$RUNTIME_HASH-$$"
|
||||
rm -rf "$TMP_DIR"
|
||||
mkdir -p "$TMP_DIR"
|
||||
|
||||
cp "$HOST_SRC" "$TMP_DIR/pjarczak_bambu_linux_host"
|
||||
cp "$NETWORK_SRC" "$TMP_DIR/libbambu_networking.so"
|
||||
cp "$SOURCE_SRC" "$TMP_DIR/libBambuSource.so"
|
||||
if [ -n "$LIVE555_SRC" ]; then
|
||||
cp "$LIVE555_SRC" "$TMP_DIR/liblive555.so"
|
||||
fi
|
||||
if [ -n "$MANIFEST_SRC" ]; then
|
||||
cp "$MANIFEST_SRC" "$TMP_DIR/linux_payload_manifest.json"
|
||||
fi
|
||||
append_source() {
|
||||
dst_name="$1"
|
||||
src_path="$2"
|
||||
[ -n "$src_path" ] || return 0
|
||||
[ -f "$src_path" ] || return 0
|
||||
printf '%s\t%s\n' "$dst_name" "$src_path" >> "$SOURCE_LIST"
|
||||
}
|
||||
|
||||
append_package_extras() {
|
||||
for path in "$PACKAGE_DIR"/*; do
|
||||
[ -f "$path" ] || continue
|
||||
base="$(basename "$path")"
|
||||
case "$base" in
|
||||
pjarczak_bambu_linux_host|libbambu_networking.so|libBambuSource.so|liblive555.so|linux_payload_manifest.json)
|
||||
pjarczak_bambu_linux_host|pjarczak_bambu_linux_host_abi1|pjarczak_bambu_linux_host_abi0|libbambu_networking.so|libBambuSource.so|linux_payload_manifest.json|ca-certificates.crt|slicer_base64.cer)
|
||||
continue
|
||||
;;
|
||||
*.dll|*.ps1|*.txt|*.tar|*.zip|*.cmd|*.bat|*.sh)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
cp "$path" "$TMP_DIR/$base"
|
||||
append_source "$base" "$path"
|
||||
done
|
||||
}
|
||||
|
||||
if [ -d "$RUNTIME_SUBDIR" ]; then
|
||||
for path in "$RUNTIME_SUBDIR"/*; do
|
||||
[ -f "$path" ] || continue
|
||||
base="$(basename "$path")"
|
||||
case "$base" in
|
||||
pjarczak_bambu_linux_host|libbambu_networking.so|libBambuSource.so|liblive555.so|linux_payload_manifest.json)
|
||||
continue
|
||||
;;
|
||||
*.dll|*.ps1|*.txt|*.tar|*.zip|*.cmd|*.bat|*.sh)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
cp "$path" "$TMP_DIR/$base"
|
||||
done
|
||||
copy_source_list() {
|
||||
while IFS="$(printf '\t')" read -r dst_name src_path; do
|
||||
[ -n "$dst_name" ] || continue
|
||||
cp "$src_path" "$TMP_DIR/$dst_name"
|
||||
done < "$SOURCE_LIST"
|
||||
}
|
||||
|
||||
compute_runtime_hash() {
|
||||
{
|
||||
while IFS="$(printf '\t')" read -r dst_name src_path; do
|
||||
[ -n "$dst_name" ] || continue
|
||||
printf '%s\n' "$dst_name"
|
||||
sha256sum "$src_path"
|
||||
done < "$SOURCE_LIST"
|
||||
} | sha256sum | cut -d ' ' -f1
|
||||
}
|
||||
|
||||
list_runtime_files() {
|
||||
find "$CURRENT_DIR" -maxdepth 1 -type f -printf '%f\n' | sort | tr '\n' ',' | sed 's/,$//'
|
||||
}
|
||||
|
||||
resolve_payload_sources
|
||||
if [ -z "$NETWORK_SRC" ] || [ -z "$SOURCE_SRC" ]; then
|
||||
log "plugin_not_downloaded package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
exit 3
|
||||
fi
|
||||
if ! wait_for_payload_sources; then
|
||||
log "plugin_not_downloaded_timeout package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
|
||||
exit 127
|
||||
fi
|
||||
fi
|
||||
|
||||
chmod 755 "$TMP_DIR/pjarczak_bambu_linux_host"
|
||||
if [ -z "$ABI1_SRC" ] && [ -z "$ABI0_SRC" ]; then
|
||||
log "missing host ABI binaries in package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
if ! command -v sha256sum >/dev/null 2>&1; then
|
||||
log "sha256sum not found inside WSL distro"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
export HOME="${HOME:-/root}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$XDG_DATA_HOME" "$HOME/.pjarczak-bambu-runtime"
|
||||
unset APPDATA LOCALAPPDATA USERPROFILE HOMEDRIVE HOMEPATH TEMP TMP TMPDIR
|
||||
|
||||
RUNTIME_BASE="${PJARCZAK_BAMBU_WSL_RUNTIME_DIR:-$HOME/.pjarczak-bambu-runtime}"
|
||||
mkdir -p "$RUNTIME_BASE"
|
||||
SOURCE_LIST="$(mktemp "$RUNTIME_BASE/.sources.XXXXXX")"
|
||||
trap 'rm -f "$SOURCE_LIST"' EXIT INT TERM
|
||||
|
||||
append_source "pjarczak_bambu_linux_host" "$HOST_SRC"
|
||||
append_source "libbambu_networking.so" "$NETWORK_SRC"
|
||||
append_source "libBambuSource.so" "$SOURCE_SRC"
|
||||
append_source "pjarczak_bambu_linux_host_abi1" "$ABI1_SRC"
|
||||
append_source "pjarczak_bambu_linux_host_abi0" "$ABI0_SRC"
|
||||
append_source "linux_payload_manifest.json" "$MANIFEST_SRC"
|
||||
append_source "ca-certificates.crt" "$CA_BUNDLE_SRC"
|
||||
append_source "slicer_base64.cer" "$SLICER_CERT_SRC"
|
||||
append_package_extras
|
||||
|
||||
RUNTIME_HASH="$(compute_runtime_hash)"
|
||||
TARGET_DIR="$RUNTIME_BASE/$RUNTIME_HASH"
|
||||
CURRENT_DIR="$RUNTIME_BASE/current"
|
||||
|
||||
log "mode=$MODE package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none} runtime_hash=$RUNTIME_HASH"
|
||||
log "wrapper_src=$HOST_SRC"
|
||||
log "network_src=${NETWORK_SRC:-missing}"
|
||||
log "source_src=${SOURCE_SRC:-missing}"
|
||||
log "abi1_src=${ABI1_SRC:-missing}"
|
||||
log "abi0_src=${ABI0_SRC:-missing}"
|
||||
log "manifest_src=${MANIFEST_SRC:-missing}"
|
||||
log "ca_bundle_src=${CA_BUNDLE_SRC:-missing}"
|
||||
log "slicer_cert_src=${SLICER_CERT_SRC:-missing}"
|
||||
|
||||
if [ ! -d "$TARGET_DIR" ]; then
|
||||
TMP_DIR="$RUNTIME_BASE/.tmp-$RUNTIME_HASH-$$"
|
||||
rm -rf "$TMP_DIR"
|
||||
mkdir -p "$TMP_DIR"
|
||||
copy_source_list
|
||||
chmod 755 "$TMP_DIR/pjarczak_bambu_linux_host" "$TMP_DIR"/pjarczak_bambu_linux_host_abi* 2>/dev/null || true
|
||||
mv "$TMP_DIR" "$TARGET_DIR"
|
||||
log "created_runtime_dir=$TARGET_DIR"
|
||||
else
|
||||
log "reusing_runtime_dir=$TARGET_DIR"
|
||||
fi
|
||||
|
||||
rm -rf "$CURRENT_DIR"
|
||||
ln -s "$TARGET_DIR" "$CURRENT_DIR"
|
||||
|
||||
export PJARCZAK_BAMBU_PLUGIN_DIR="$CURRENT_DIR"
|
||||
export PJARCZAK_BAMBU_NETWORK_SO="$CURRENT_DIR/libbambu_networking.so"
|
||||
export PJARCZAK_BAMBU_SOURCE_SO="$CURRENT_DIR/libBambuSource.so"
|
||||
if [ -f "$CURRENT_DIR/liblive555.so" ]; then
|
||||
export PJARCZAK_BAMBU_LIVE555_SO="$CURRENT_DIR/liblive555.so"
|
||||
fi
|
||||
export LD_LIBRARY_PATH="$CURRENT_DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
if [ -f "$CURRENT_DIR/ca-certificates.crt" ]; then
|
||||
export SSL_CERT_FILE="$CURRENT_DIR/ca-certificates.crt"
|
||||
export CURL_CA_BUNDLE="$CURRENT_DIR/ca-certificates.crt"
|
||||
fi
|
||||
if [ -d /etc/ssl/certs ]; then
|
||||
export SSL_CERT_DIR="/etc/ssl/certs"
|
||||
fi
|
||||
|
||||
BIN_PATH=$("$CURRENT_DIR/pjarczak_bambu_linux_host" --print-bin 2>/tmp/pjarczak-bin.txt || true)
|
||||
if [ -z "$BIN_PATH" ] || [ ! -x "$BIN_PATH" ]; then
|
||||
log "failed to resolve host binary"
|
||||
cat /tmp/pjarczak-bin.txt >&2 || true
|
||||
exit 127
|
||||
fi
|
||||
|
||||
log "selected_bin=$BIN_PATH"
|
||||
log "runtime_files=$(list_runtime_files)"
|
||||
|
||||
if command -v ldd >/dev/null 2>&1; then
|
||||
LDD_OUT="$(ldd "$BIN_PATH" 2>&1 || true)"
|
||||
if printf '%s\n' "$LDD_OUT" | grep -q 'not found'; then
|
||||
log "ldd reported missing libraries for $BIN_PATH"
|
||||
printf '%s\n' "$LDD_OUT" >&2
|
||||
exit 127
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "probe" ]; then
|
||||
if ! ldd "$CURRENT_DIR/pjarczak_bambu_linux_host" >/tmp/pjarczak-ldd.txt 2>&1; then
|
||||
cat /tmp/pjarczak-ldd.txt >&2 || true
|
||||
PROBE_LOG_DIR="/tmp/pjarczak-bambu-probe"
|
||||
mkdir -p "$PROBE_LOG_DIR"
|
||||
if ! PJARCZAK_BAMBU_PROBE_LOG_DIR="$PROBE_LOG_DIR" PJARCZAK_BAMBU_COUNTRY_CODE="${PJARCZAK_BAMBU_COUNTRY_CODE:-PL}" "$CURRENT_DIR/pjarczak_bambu_linux_host" --probe-auth >/tmp/pjarczak-probe.txt 2>&1; then
|
||||
log "probe_auth_failed"
|
||||
cat /tmp/pjarczak-probe.txt >&2 || true
|
||||
exit 127
|
||||
fi
|
||||
if grep -q 'not found' /tmp/pjarczak-ldd.txt; then
|
||||
cat /tmp/pjarczak-ldd.txt >&2
|
||||
exit 127
|
||||
fi
|
||||
echo "probe_ok runtime_dir=$CURRENT_DIR runtime_hash=$RUNTIME_HASH"
|
||||
echo "probe_ok runtime_dir=$CURRENT_DIR runtime_hash=$RUNTIME_HASH bin=$BIN_PATH"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -2,33 +2,21 @@ param(
|
|||
[string]$PackageDir = "",
|
||||
[string]$DistroName = "",
|
||||
[string]$PluginCacheDir = "",
|
||||
[switch]$AllowMissingLinuxPlugin
|
||||
[switch]$AllowMissingLinuxPlugin,
|
||||
[switch]$SkipProbe
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
|
||||
$script:__pj_prev_native_pref = $PSNativeCommandUseErrorActionPreference
|
||||
$PSNativeCommandUseErrorActionPreference = $false
|
||||
}
|
||||
|
||||
function Get-ScriptDir {
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
|
||||
return $PSScriptRoot
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
|
||||
return (Split-Path -Parent $PSCommandPath)
|
||||
}
|
||||
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
|
||||
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
}
|
||||
if ($PSScriptRoot) { return $PSScriptRoot }
|
||||
if ($PSCommandPath) { return (Split-Path -Parent $PSCommandPath) }
|
||||
if ($MyInvocation.MyCommand -and $MyInvocation.MyCommand.Path) { return (Split-Path -Parent $MyInvocation.MyCommand.Path) }
|
||||
return (Get-Location).Path
|
||||
}
|
||||
|
||||
function Convert-FileToLf([string]$Path) {
|
||||
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) {
|
||||
return
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) { return }
|
||||
$content = [System.IO.File]::ReadAllText($Path)
|
||||
$content = $content.Replace("`r`n", "`n").Replace("`r", "`n")
|
||||
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
||||
|
|
@ -39,71 +27,11 @@ function To-WslPath([string]$Path) {
|
|||
$full = [System.IO.Path]::GetFullPath($Path)
|
||||
if ($full.Length -ge 2 -and $full[1] -eq ':') {
|
||||
$drive = $full.Substring(0, 1).ToLowerInvariant()
|
||||
$tail = ($full.Substring(2) -replace '\\', '/')
|
||||
if ($tail.StartsWith('/')) {
|
||||
$tail = $tail.Substring(1)
|
||||
}
|
||||
$tail = $full.Substring(2).Replace('\', '/')
|
||||
if ($tail.StartsWith('/')) { $tail = $tail.Substring(1) }
|
||||
return "/mnt/$drive/$tail"
|
||||
}
|
||||
return ($full -replace '\\', '/')
|
||||
}
|
||||
|
||||
function Read-TextAuto([string]$Path) {
|
||||
if (!(Test-Path $Path)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
$bytes = [System.IO.File]::ReadAllBytes($Path)
|
||||
if ($bytes.Length -eq 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
|
||||
return ([System.Text.Encoding]::Unicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
|
||||
}
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
|
||||
return ([System.Text.Encoding]::BigEndianUnicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
|
||||
}
|
||||
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
|
||||
return ([System.Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) -replace "`0", '')
|
||||
}
|
||||
|
||||
for ($i = 1; $i -lt [Math]::Min($bytes.Length, 64); $i += 2) {
|
||||
if ($bytes[$i] -eq 0) {
|
||||
return ([System.Text.Encoding]::Unicode.GetString($bytes) -replace "`0", '')
|
||||
}
|
||||
}
|
||||
|
||||
return ([System.Text.Encoding]::UTF8.GetString($bytes) -replace "`0", '')
|
||||
}
|
||||
|
||||
function Normalize-NativeText([string]$Text) {
|
||||
if ([string]::IsNullOrEmpty($Text)) {
|
||||
return ''
|
||||
}
|
||||
$value = $Text -replace "`0", ''
|
||||
$value = $value -replace "`r`n", "`n"
|
||||
$value = $value -replace "`r", "`n"
|
||||
return $value
|
||||
}
|
||||
|
||||
function Invoke-NativeCapture([string]$FilePath, [string[]]$ArgumentList) {
|
||||
$stdoutPath = [System.IO.Path]::GetTempFileName()
|
||||
$stderrPath = [System.IO.Path]::GetTempFileName()
|
||||
try {
|
||||
$proc = Start-Process -FilePath $FilePath -ArgumentList $ArgumentList -Wait -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath -WindowStyle Hidden
|
||||
$stdoutText = if (Test-Path $stdoutPath) { Normalize-NativeText (Read-TextAuto $stdoutPath) } else { '' }
|
||||
$stderrText = if (Test-Path $stderrPath) { Normalize-NativeText (Read-TextAuto $stderrPath) } else { '' }
|
||||
$combined = (($stdoutText + "`n" + $stderrText).Trim())
|
||||
return @{
|
||||
ExitCode = $proc.ExitCode
|
||||
StdOut = $stdoutText
|
||||
StdErr = $stderrText
|
||||
Combined = $combined
|
||||
}
|
||||
} finally {
|
||||
Remove-Item -Force -ErrorAction SilentlyContinue $stdoutPath, $stderrPath
|
||||
}
|
||||
return $full.Replace('\', '/')
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($PackageDir)) {
|
||||
|
|
@ -115,7 +43,7 @@ if ([string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
|||
if ($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR) {
|
||||
$PluginCacheDir = $env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR
|
||||
} elseif ($env:APPDATA) {
|
||||
$PluginCacheDir = Join-Path $env:APPDATA 'OrcaSlicer\plugins'
|
||||
$PluginCacheDir = Join-Path $env:APPDATA 'OrcaSlicer\ota'
|
||||
}
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
||||
|
|
@ -123,9 +51,13 @@ if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
|||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($DistroName)) {
|
||||
$distroFile = Join-Path $PackageDir 'pjarczak_wsl_distro.txt'
|
||||
if (Test-Path $distroFile) {
|
||||
$DistroName = (Get-Content $distroFile -Raw).Trim()
|
||||
if ($env:PJARCZAK_WSL_DISTRO) {
|
||||
$DistroName = $env:PJARCZAK_WSL_DISTRO.Trim()
|
||||
} else {
|
||||
$distroFile = Join-Path $PackageDir 'pjarczak_wsl_distro.txt'
|
||||
if (Test-Path $distroFile) {
|
||||
$DistroName = (Get-Content $distroFile -Raw).Trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($DistroName)) {
|
||||
|
|
@ -133,64 +65,47 @@ if ([string]::IsNullOrWhiteSpace($DistroName)) {
|
|||
}
|
||||
|
||||
$requiredFiles = @(
|
||||
'pjarczak_bambu_networking_bridge.dll',
|
||||
'pjarczak_wsl_distro.txt',
|
||||
'install_runtime.ps1',
|
||||
'verify_runtime.ps1',
|
||||
'pjarczak_wsl_run_host.sh',
|
||||
'pjarczak_bambu_linux_host',
|
||||
'pjarczak_bambu_linux_host_abi1',
|
||||
'pjarczak_bambu_linux_host_abi0',
|
||||
'windows-wsl2-rootfs.tar'
|
||||
)
|
||||
|
||||
foreach ($name in $requiredFiles) {
|
||||
$path = Join-Path $PackageDir $name
|
||||
if (!(Test-Path $path)) {
|
||||
throw "Missing package file: $name"
|
||||
}
|
||||
if (!(Test-Path $path)) { throw "Missing package file: $name" }
|
||||
}
|
||||
|
||||
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
|
||||
if (!(Test-Path $bootstrapPath)) { $bootstrapPath = Join-Path $PackageDir 'pjarczak-wsl-run-host.sh' }
|
||||
if (!(Test-Path $bootstrapPath)) {
|
||||
throw 'Missing package file: pjarczak_wsl_run_host.sh'
|
||||
}
|
||||
Convert-FileToLf $bootstrapPath
|
||||
|
||||
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
|
||||
if (!(Test-Path $wsl)) {
|
||||
throw 'wsl.exe not found'
|
||||
}
|
||||
if (!(Test-Path $wsl)) { throw 'wsl.exe not found' }
|
||||
|
||||
$distroList = @()
|
||||
$normalizedDistros = @()
|
||||
for ($attempt = 0; $attempt -lt 10; $attempt++) {
|
||||
$distroQuery = Invoke-NativeCapture $wsl @('-l', '-q')
|
||||
if ($distroQuery.ExitCode -ne 0) {
|
||||
throw "Failed to query installed WSL distros: $($distroQuery.Combined)"
|
||||
}
|
||||
$distroList = @()
|
||||
if (-not [string]::IsNullOrWhiteSpace($distroQuery.StdOut)) {
|
||||
$distroList = $distroQuery.StdOut -split "`n"
|
||||
}
|
||||
$normalizedDistros = $distroList | ForEach-Object { ($_ -replace "`0", '').Trim() } | Where-Object { $_ }
|
||||
if ($normalizedDistros | Where-Object { $_ -eq $DistroName }) {
|
||||
break
|
||||
}
|
||||
Start-Sleep -Milliseconds 400
|
||||
}
|
||||
if (-not ($normalizedDistros | Where-Object { $_ -eq $DistroName })) {
|
||||
$distroList = & $wsl -l -q 2>$null
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Failed to query installed WSL distros' }
|
||||
if (-not ($distroList | ForEach-Object { $_.Trim() } | Where-Object { $_ -eq $DistroName })) {
|
||||
throw "WSL distro '$DistroName' is not installed"
|
||||
}
|
||||
|
||||
$packageDirWsl = To-WslPath $PackageDir
|
||||
$pluginCacheDirWsl = ""
|
||||
$pluginCacheDirWsl = ''
|
||||
if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
|
||||
$pluginCacheDirWsl = To-WslPath $PluginCacheDir
|
||||
}
|
||||
$bootstrapWsl = "$packageDirWsl/$([System.IO.Path]::GetFileName($bootstrapPath))"
|
||||
$bootstrapWsl = "$packageDirWsl/pjarczak_wsl_run_host.sh"
|
||||
|
||||
$probe = Invoke-NativeCapture $wsl @('-d', $DistroName, '--user', 'root', '--', 'sh', $bootstrapWsl, '--probe', $packageDirWsl, $pluginCacheDirWsl)
|
||||
if ($probe.ExitCode -ne 0) {
|
||||
$probeText = $probe.Combined
|
||||
if ($SkipProbe) {
|
||||
Write-Host 'WSL runtime core OK'
|
||||
exit 0
|
||||
}
|
||||
|
||||
$probe = & $wsl -d $DistroName --user root -- sh $bootstrapWsl --probe $packageDirWsl $pluginCacheDirWsl 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$probeText = ($probe | Out-String).Trim()
|
||||
if ($AllowMissingLinuxPlugin -and $probeText -match 'plugin_not_downloaded') {
|
||||
Write-Host 'WSL runtime package OK, linux plugin not downloaded yet.'
|
||||
Write-Host $probeText
|
||||
|
|
@ -200,4 +115,4 @@ if ($probe.ExitCode -ne 0) {
|
|||
}
|
||||
|
||||
Write-Host 'WSL runtime probe OK'
|
||||
Write-Host $probe.Combined
|
||||
Write-Host (($probe | Out-String).Trim())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue