#include "WebSMUserLoginDialog.hpp" #include #include "I18N.hpp" #include "libslic3r/AppConfig.hpp" #include "slic3r/GUI/wxExtensions.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "common_func/common_func.hpp" #include #include #include #include #include #include #include #include #include #include #include "MainFrame.hpp" #include #include #include #include "sentry_wrapper/SentryWrapper.hpp" using namespace std; using namespace nlohmann; namespace Slic3r { namespace GUI { #define NETWORK_OFFLINE_TIMER_ID 10001 BEGIN_EVENT_TABLE(SMUserLogin, wxDialog) EVT_TIMER(NETWORK_OFFLINE_TIMER_ID, SMUserLogin::OnTimer) END_EVENT_TABLE() int SMUserLogin::web_sequence_id = 20000; SMUserLogin::SMUserLogin(bool isLogout) : wxDialog((wxWindow *) (wxGetApp().mainframe), wxID_ANY, "Snapmaker Orca") { // url auto region = wxGetApp().app_config->get_country_code(); if (region.find("CN") == std::string::npos) { TargetUrl = "https://id.snapmaker.com?from=orca"; LogoutUrl = "https://id.snapmaker.com/logout?from=orca"; m_hostUrl = "https://id.snapmaker.com"; m_accountUrl = "https://id.snapmaker.com"; m_userInfoUrl = "https://id.snapmaker.com/api/common/accounts/current"; m_home_url = "https://www.snapmaker.com/"; } else { TargetUrl = "https://id.snapmaker.cn?from=orca"; LogoutUrl = "https://id.snapmaker.cn/logout?from=orca"; m_hostUrl = "https://id.snapmaker.cn"; m_accountUrl = "https://api.snapmaker.cn"; m_userInfoUrl = "https://api.snapmaker.cn/api/common/accounts/current"; m_home_url = "https://www.snapmaker.cn/"; } SetBackgroundColour(*wxWHITE); BOOST_LOG_TRIVIAL(info) << "login url = " << TargetUrl.ToStdString(); m_sm_user_agent = wxString::Format("SM-Slicer/v%s", SLIC3R_VERSION); // set the frame icon // Create the webview m_browser = WebView::CreateWebView(this, isLogout ? LogoutUrl : TargetUrl); if (m_browser == nullptr) { wxLogError("Could not init m_browser"); return; } m_browser->Hide(); m_browser->SetSize(0, 0); // Log backend information // wxLogMessage(wxWebView::GetBackendVersionInfo().ToString()); // wxLogMessage("Backend: %s Version: %s", // m_browser->GetClassInfo()->GetClassName(),wxWebView::GetBackendVersionInfo().ToString()); // wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); // Connect the webview events Bind(wxEVT_WEBVIEW_NAVIGATING, &SMUserLogin::OnNavigationRequest, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_NAVIGATED, &SMUserLogin::OnNavigationComplete, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_LOADED, &SMUserLogin::OnDocumentLoaded, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_ERROR, &SMUserLogin::OnError, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_NEWWINDOW, &SMUserLogin::OnNewWindow, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &SMUserLogin::OnTitleChanged, this, m_browser->GetId()); Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &SMUserLogin::OnFullScreenChanged, this, m_browser->GetId()); //Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &SMUserLogin::OnScriptMessage, this, m_browser->GetId()); // Connect the idle events // Bind(wxEVT_IDLE, &SMUserLogin::OnIdle, this); // Bind(wxEVT_CLOSE_WINDOW, &SMUserLogin::OnClose, this); // UI SetTitle(isLogout ? _L("Log out") : _L("Login")); // Set a more sensible size for web browsing wxSize pSize = FromDIP(wxSize(650, 840)); SetSize(pSize); int screenheight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, NULL); int screenwidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, NULL); int MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0; wxPoint tmpPT((screenwidth - pSize.x) / 2, MaxY); Move(tmpPT); wxGetApp().UpdateDlgDarkUI(this); } SMUserLogin::~SMUserLogin() { if (m_timer != NULL) { m_timer->Stop(); delete m_timer; m_timer = NULL; } } void SMUserLogin::OnTimer(wxTimerEvent &event) { m_timer->Stop(); if (m_networkOk == false) { ShowErrorPage(); } } bool SMUserLogin::run() { m_timer = new wxTimer(this, NETWORK_OFFLINE_TIMER_ID); m_timer->Start(8000); if (this->ShowModal() == wxID_OK) { return true; } else { return false; } } void SMUserLogin::load_url(wxString &url) { m_browser->LoadURL(url); m_browser->SetFocus(); UpdateState(); } /** * Method that retrieves the current state from the web control and updates * the GUI the reflect this current state. */ void SMUserLogin::UpdateState() { // SetTitle(m_browser->GetCurrentTitle()); } void SMUserLogin::OnIdle(wxIdleEvent &WXUNUSED(evt)) { if (m_browser->IsBusy()) { wxSetCursor(wxCURSOR_ARROWWAIT); } else { wxSetCursor(wxNullCursor); } } // void SMUserLogin::OnClose(wxCloseEvent& evt) //{ // this->Hide(); //} /** * Callback invoked when there is a request to load a new page (for instance * when the user clicks a link) */ void SMUserLogin::OnNavigationRequest(wxWebViewEvent &evt) { wxString tmpUrl = evt.GetURL(); size_t start = tmpUrl.find("token="); if (start != std::string::npos) { std::string token; start += std::string("token=").size(); // 跳过"token="的长度 size_t end = tmpUrl.find("?", start); if (end != std::string::npos) { token = tmpUrl.substr(start, end - start).ToStdString(); } else { token = tmpUrl.substr(start).ToStdString(); } this->EndModal(wxID_OK); wxGetApp().CallAfter([token, this]() { std::string url = m_userInfoUrl.ToStdString(); auto http = Http::get(url); http.header("Authorization",token); http.on_complete([&](std::string body, unsigned status) { if (status == 200) { std::string user_id = ""; json response = json::parse(body); if (response.count("data")) { json data = response["data"]; if (data.count("id")) { wxGetApp().sm_get_userinfo()->set_user_id(std::to_string(data["id"].get())); user_id = std::to_string(data["id"].get()); } if (data.count("nickname")) { wxGetApp().sm_get_userinfo()->set_user_name(data["nickname"].get()); } if (data.count("icon")) { wxGetApp().sm_get_userinfo()->set_user_icon_url(data["icon"].get()); } if (data.count("account")) { wxGetApp().sm_get_userinfo()->set_user_account(data["account"].get()); } } string userInfo = BP_LOGIN_USER_ID + std::string(":") + user_id; sentryReportLog(SENTRY_LOG_TRACE, userInfo, BP_LOGIN); wxGetApp().sm_get_userinfo()->set_user_token(token); wxGetApp().sm_get_userinfo()->set_user_login(true); } }) .on_error([&](std::string body, std::string error, unsigned status) { std::string http_code = BP_LOGIN_HTTP_CODE + string(":") + std::to_string(status) + "\n" + error + "\n" + body; sentryReportLog(SENTRY_LOG_TRACE, http_code, BP_LOGIN); }) .perform_sync(); }); } UpdateState(); } /** * Callback invoked when a navigation request was accepted */ void SMUserLogin::OnNavigationComplete(wxWebViewEvent &evt) { // wxLogMessage("%s", "Navigation complete; url='" + evt.GetURL() + "'"); m_browser->Show(); Layout(); UpdateState(); } /** * Callback invoked when a page is finished loading */ void SMUserLogin::OnDocumentLoaded(wxWebViewEvent &evt) { // Only notify if the document is the main frame, not a subframe wxString tmpUrl = evt.GetURL(); std::string strHost = "https://id.snapmaker.com"; if ( tmpUrl.Contains(strHost) ) { m_networkOk = true; // wxLogMessage("%s", "Document loaded; url='" + evt.GetURL() + "'"); } UpdateState(); } /** * On new window, we veto to stop extra windows appearing */ void SMUserLogin::OnNewWindow(wxWebViewEvent &evt) { wxString flag = " (other)"; if (evt.GetNavigationAction() == wxWEBVIEW_NAV_ACTION_USER) { flag = " (user)"; } // wxLogMessage("%s", "New window; url='" + evt.GetURL() + "'" + flag); // If we handle new window events then just load them in this window as we // are a single window browser m_browser->LoadURL(evt.GetURL()); UpdateState(); } void SMUserLogin::OnTitleChanged(wxWebViewEvent &evt) { // SetTitle(evt.GetString()); // wxLogMessage("%s", "Title changed; title='" + evt.GetString() + "'"); } void SMUserLogin::OnFullScreenChanged(wxWebViewEvent &evt) { // wxLogMessage("Full screen changed; status = %d", evt.GetInt()); ShowFullScreen(evt.GetInt() != 0); } void SMUserLogin::OnScriptMessage(wxWebViewEvent &evt) { wxString str_input = evt.GetString(); try { json j = json::parse(into_u8(str_input)); wxString strCmd = j["command"]; if (strCmd == "autotest_token") { m_AutotestToken = j["data"]["token"]; } if (strCmd == "user_login") { j["data"]["autotest_token"] = m_AutotestToken; Close(); } else if (strCmd == "get_localhost_url") { BOOST_LOG_TRIVIAL(info) << "thirdparty_login: get_localhost_url"; wxGetApp().start_http_server(); std::string sequence_id = j["sequence_id"].get(); CallAfter([this, sequence_id] { json ack_j; ack_j["command"] = "get_localhost_url"; ack_j["response"]["base_url"] = std::string(LOCALHOST_URL) + std::to_string(LOCALHOST_PORT); ack_j["response"]["result"] = "success"; ack_j["sequence_id"] = sequence_id; wxString str_js = wxString::Format("window.postMessage(%s)", ack_j.dump()); this->RunScript(str_js); }); } else if (strCmd == "thirdparty_login") { BOOST_LOG_TRIVIAL(info) << "thirdparty_login: thirdparty_login"; if (j["data"].contains("url")) { std::string jump_url = j["data"]["url"].get(); CallAfter([this, jump_url] { wxString url = wxString::FromUTF8(jump_url); wxLaunchDefaultBrowser(url); }); } } else if (strCmd == "new_webpage") { if (j["data"].contains("url")) { std::string jump_url = j["data"]["url"].get(); CallAfter([this, jump_url] { wxString url = wxString::FromUTF8(jump_url); wxLaunchDefaultBrowser(url); }); } return; } } catch (std::exception &e) { wxMessageBox(e.what(), "parse json failed", wxICON_WARNING); Close(); } } void SMUserLogin::RunScript(const wxString &javascript) { // Remember the script we run in any case, so the next time the user opens // the "Run Script" dialog box, it is shown there for convenient updating. m_javascript = javascript; if (!m_browser) return; WebView::RunScript(m_browser, javascript); } #if wxUSE_WEBVIEW_IE void SMUserLogin::OnRunScriptObjectWithEmulationLevel(wxCommandEvent &WXUNUSED(evt)) { wxWebViewIE::MSWSetModernEmulationLevel(); RunScript("function f(){var person = new Object();person.name = 'Foo'; \ person.lastName = 'Bar';return person;}f();"); wxWebViewIE::MSWSetModernEmulationLevel(false); } void SMUserLogin::OnRunScriptDateWithEmulationLevel(wxCommandEvent &WXUNUSED(evt)) { wxWebViewIE::MSWSetModernEmulationLevel(); RunScript("function f(){var d = new Date('10/08/2017 21:30:40'); \ var tzoffset = d.getTimezoneOffset() * 60000; return \ new Date(d.getTime() - tzoffset);}f();"); wxWebViewIE::MSWSetModernEmulationLevel(false); } void SMUserLogin::OnRunScriptArrayWithEmulationLevel(wxCommandEvent &WXUNUSED(evt)) { wxWebViewIE::MSWSetModernEmulationLevel(); RunScript("function f(){ return [\"foo\", \"bar\"]; }f();"); wxWebViewIE::MSWSetModernEmulationLevel(false); } #endif /** * Callback invoked when a loading error occurs */ void SMUserLogin::OnError(wxWebViewEvent &event) { auto e = "unknown error"; switch (event.GetInt()) { case wxWEBVIEW_NAV_ERR_CONNECTION: e = "wxWEBVIEW_NAV_ERR_CONNECTION"; break; case wxWEBVIEW_NAV_ERR_CERTIFICATE: e = "wxWEBVIEW_NAV_ERR_CERTIFICATE"; break; case wxWEBVIEW_NAV_ERR_AUTH: e = "wxWEBVIEW_NAV_ERR_AUTH"; break; case wxWEBVIEW_NAV_ERR_SECURITY: e = "wxWEBVIEW_NAV_ERR_SECURITY"; break; case wxWEBVIEW_NAV_ERR_NOT_FOUND: e = "wxWEBVIEW_NAV_ERR_NOT_FOUND"; break; case wxWEBVIEW_NAV_ERR_REQUEST: e = "wxWEBVIEW_NAV_ERR_REQUEST"; break; case wxWEBVIEW_NAV_ERR_USER_CANCELLED: e = "wxWEBVIEW_NAV_ERR_USER_CANCELLED"; break; case wxWEBVIEW_NAV_ERR_OTHER: e = "wxWEBVIEW_NAV_ERR_OTHER"; break; } BOOST_LOG_TRIVIAL(fatal) << __FUNCTION__<< boost::format(":SMUserLogin error loading page %1% %2% %3% %4%") % event.GetURL() % event.GetTarget() %e % event.GetString(); } void SMUserLogin::OnScriptResponseMessage(wxCommandEvent &WXUNUSED(evt)) { // if (!m_response_js.empty()) //{ // RunScript(m_response_js); //} // RunScript("This is a message to Web!"); // RunScript("postMessage(\"AABBCCDD\");"); } bool SMUserLogin::ShowErrorPage() { wxString ErrorUrl = from_u8((boost::filesystem::path(resources_dir()) / "web\\login\\error.html").make_preferred().string()); wxString strlang = wxGetApp().current_language_code_safe(); if (strlang != "") ErrorUrl = wxString::Format("file://%s/web/login/error.html?lang=%s", from_u8(resources_dir()), strlang); load_url(ErrorUrl); return true; } }} // namespace Slic3r::GUI