diff --git a/build/build.py b/build/build.py index 9916afa..ddea7be 100644 --- a/build/build.py +++ b/build/build.py @@ -226,10 +226,10 @@ def make_options(): # options = list() # options_idx = 0 - if ctx.host_os in ['windows', 'macos']: + if ctx.host_os in ['windows']: add_option('x86', 'ver', 'Update version setting') add_option('x86', 'pysrt', 'Make Python-Runtime for python%s-x86' % env.py_ver_str) - add_option('x64', 'external', 'Build external dependency') + add_option('x86', 'external', 'Build external dependency') add_split() add_option('x86', 'assist-exe', 'Assist Execute [%s]' % ctx.target_path) # add_option('x86', 'assist-rdp', 'Teleport RDP [%s]' % ctx.target_path) @@ -238,6 +238,9 @@ def make_options(): add_option('x86', 'server', 'Teleport Server [%s]' % ctx.target_path) add_split() add_option('x86', 'installer', 'Teleport Installer for %s' % ctx.host_os) + elif ctx.host_os == 'macos': + add_option('x64', 'assist-exe', 'Assist Execute [%s]' % ctx.target_path) + add_option('x64', 'assist-installer', 'Assist Installer') else: add_option('x64', 'ver', 'Update version setting') add_option('x64', 'pysrt', 'Make Python-Runtime for python%s-x64' % env.py_ver_str) diff --git a/build/builder/build-assist.py b/build/builder/build-assist.py index 3bbf012..d28f332 100644 --- a/build/builder/build-assist.py +++ b/build/builder/build-assist.py @@ -45,7 +45,7 @@ class BuilderWin(BuilderBase): out_file = os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path, 'tp-player.exe') if os.path.exists(out_file): utils.remove(out_file) - utils.qt_build_win(prj_path, 'tp-player', ctx.bits_path, ctx.target_path) + utils.qt_build(prj_path, 'tp-player', ctx.bits_path, ctx.target_path) utils.ensure_file_exists(out_file) # def build_rdp(self): @@ -72,7 +72,6 @@ class BuilderWin(BuilderBase): utils.ensure_file_exists(out_file) - @staticmethod def _build_installer(): tmp_path = os.path.join(env.root_path, 'dist', 'client', 'windows', 'assist') @@ -155,13 +154,28 @@ class BuilderMacOS(BuilderBase): utils.ensure_file_exists(os.path.join(out_file, 'Contents', 'Info.plist')) def build_player(self): - cc.o('skip build tp_player now...') + cc.i('build tp-player...') + prj_path = os.path.join(env.root_path, 'client', 'tp-player') + out_file = os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path, 'tp-player.app') + if os.path.exists(out_file): + utils.remove(out_file) + utils.qt_build(prj_path, 'tp-player', ctx.bits_path, ctx.target_path) + utils.ensure_file_exists(os.path.join(out_file, 'Contents', 'Info.plist')) + + # for deployment + utils.qt_deploy(out_file) def build_installer(self): cc.i('make tp_assist dmg file...') + # copy all files of tp-player. + configuration = ctx.target_path.capitalize() + player_path = os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path) + assist_path = os.path.join(env.root_path, 'client', 'tp_assist_macos', 'build', configuration, 'TP-Assist.app') + utils.copy_ex(player_path, assist_path, 'tp-player.app') + json_file = os.path.join(env.root_path, 'dist', 'client', 'macos', 'dmg.json') - dmg_file = os.path.join(env.root_path, 'out', 'client', 'macos', 'teleport-assist-macos-{}.dmg'.format(VER_TP_ASSIST)) + dmg_file = os.path.join(env.root_path, 'out', 'installer', 'teleport-assist-macos-{}.dmg'.format(VER_TP_ASSIST)) if os.path.exists(dmg_file): utils.remove(dmg_file) diff --git a/build/builder/core/env.py b/build/builder/core/env.py index 4a89e73..52aa8c1 100644 --- a/build/builder/core/env.py +++ b/build/builder/core/env.py @@ -153,7 +153,11 @@ class Env(object): else: self.qt = None - elif self.is_linux or self.is_macos: + if self.qt is None or not os.path.exists(self.qt): + if warn_miss_tool: + cc.w(' - can not locate `qt`, so I can not build tp-player.') + + elif self.is_linux: if 'cmake' in _tmp: self.cmake = _tmp['cmake'] else: @@ -163,6 +167,16 @@ class Env(object): if warn_miss_tool: cc.e(' - can not locate `cmake`, so I can not build binary from source.') + elif self.is_macos: + if 'qt' in _tmp: + self.qt = _tmp['qt'] + else: + self.qt = None + + if self.qt is None or not os.path.exists(self.qt): + if warn_miss_tool: + cc.w(' - can not locate `qt`, so I can not build tp-player.') + return True def _load_version(self): diff --git a/build/builder/core/utils.py b/build/builder/core/utils.py index 3aacf62..0043938 100644 --- a/build/builder/core/utils.py +++ b/build/builder/core/utils.py @@ -300,7 +300,7 @@ def sys_exec(cmd, direct_output=False, output_codec=None): ret = p.wait() - return (ret, output) + return ret, output def msvc_build(sln_file, proj_name, target, platform, force_rebuild): @@ -320,19 +320,43 @@ def msvc_build(sln_file, proj_name, target, platform, force_rebuild): raise RuntimeError('build MSVC project `{}` failed.'.format(proj_name)) -def qt_build_win(prj_path, prj_name, bit_path, target_path): - cc.n(env.visual_studio_path) +def qt_build(prj_path, prj_name, bit_path, target_path): + # cc.n(env.qt) if env.qt is None: raise RuntimeError('where is `qt`?') if env.is_win: tmp_path = os.path.join(env.root_path, 'out', '_tmp_', prj_name, bit_path) # C:\Windows\System32\cmd.exe /A /Q /K C:\Qt\Qt5.12.0\5.12.0\msvc2017\bin\qtenv2.bat - cmd = 'C:\\Windows\\System32\\cmd.exe /A /Q /C ""{}\qt-helper.bat" "{}\\bin\\qtenv2.bat" "{}VC\\Auxiliary\\Build\\vcvarsall.bat" {} "{}" "{}" {}"'.format(env.build_path, env.qt, env.visual_studio_path, bit_path, tmp_path, prj_path, target_path) + cmd = 'C:\\Windows\\System32\\cmd.exe /A /Q /C ""{}\\qt-helper.bat" "{}\\bin\\qtenv2.bat" "{}VC\\Auxiliary\\Build\\vcvarsall.bat" {} "{}" "{}" {}"'.format(env.build_path, env.qt, env.visual_studio_path, bit_path, tmp_path, prj_path, target_path) ret, _ = sys_exec(cmd, direct_output=True) if ret != 0: - raise RuntimeError('build XCode project `{}` failed.'.format(proj_name)) + raise RuntimeError('build XCode project `{}` failed.'.format(prj_name)) + elif env.is_macos: + qmake = os.path.join(env.qt, 'qmake') + pro_file = prj_name + '.pro' + old_p = os.getcwd() + os.chdir(prj_path) + + cmd = '"{}" "{}"; make'.format(qmake, pro_file) + ret, _ = sys_exec(cmd, direct_output=True) + if ret != 0: + raise RuntimeError('make Makefile for build `{}` failed.'.format(prj_name)) + + os.chdir(old_p) + + +def qt_deploy(app): + if env.qt is None: + raise RuntimeError('where is `qt`?') + + if env.is_macos: + qmake = os.path.join(env.qt, 'macdeployqt') + cmd = '"{}" "{}"'.format(qmake, app) + ret, _ = sys_exec(cmd, direct_output=True) + if ret != 0: + raise RuntimeError('make deploy for QT failed.') def xcode_build(proj_file, proj_name, target, force_rebuild): diff --git a/client/tp-player/mainwindow.cpp b/client/tp-player/mainwindow.cpp index 2e2e458..fca70e2 100644 --- a/client/tp-player/mainwindow.cpp +++ b/client/tp-player/mainwindow.cpp @@ -48,6 +48,8 @@ MainWindow::MainWindow(QWidget *parent) : // setWindowFlags(Qt::FramelessWindowHint | Qt::MSWindowsFixedSizeDialogHint | windowFlags()); //#endif //__APPLE__ + setWindowIcon(QIcon(":/tp-player/res/tp-player.png")); + m_pt_normal.load(":/tp-player/res/cursor.png"); m_default_bg.load(":/tp-player/res/bg.png"); diff --git a/client/tp-player/res/tp-player.png b/client/tp-player/res/tp-player.png new file mode 100644 index 0000000..0e73347 Binary files /dev/null and b/client/tp-player/res/tp-player.png differ diff --git a/client/tp-player/thr_data.cpp b/client/tp-player/thr_data.cpp index af9526f..71da262 100644 --- a/client/tp-player/thr_data.cpp +++ b/client/tp-player/thr_data.cpp @@ -107,8 +107,8 @@ ThrData::ThrData(MainWindow* mainwin, const QString& res) { m_offset = 0; #ifdef __APPLE__ - m_data_path_base = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - m_data_path_base += "/tp-testdata/"; + m_data_path_base = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + m_data_path_base += "/tp-record/"; #else m_data_path_base = QCoreApplication::applicationDirPath() + "/record"; #endif diff --git a/client/tp-player/tp-player.pro b/client/tp-player/tp-player.pro index ba65483..8524c2f 100644 --- a/client/tp-player/tp-player.pro +++ b/client/tp-player/tp-player.pro @@ -36,7 +36,12 @@ RC_FILE += \ FORMS += \ mainwindow.ui - +win32: { + INCLUDEPATH += $$PWD/../../external/zlib + INCLUDEPATH += $$PWD/../../external/zlib/build + DEPENDPATH += $$PWD/../../external/zlib + DEPENDPATH += $$PWD/../../external/zlib/build +} win32:CONFIG(release, debug|release): { DEFINES += QT_NO_DEBUG_OUTPUT LIBS += -L$$PWD/../../external/zlib/build/release/ -lzlib @@ -48,21 +53,30 @@ else:win32:CONFIG(debug, debug|release): { } +macx: { + INCLUDEPATH += $$PWD/../../external/macos/release/include +} macx:CONFIG(release, debug|release): { DEFINES += QT_NO_DEBUG_OUTPUT - LIBS += -L$$PWD/../../external/zlib/build/release/ -lzlib - DESTDIR = $$PWD/../../out/client/x86/Release + LIBS += -L$$PWD/../../external/macos/release/lib/ -lz + DESTDIR = $$PWD/../../out/client/x64/release + + UI_DIR += $$PWD/../../out/_tmp_/tp-player/debug + RCC_DIR += $$PWD/../../out/_tmp_/tp-player/debug + MOC_DIR += $$PWD/../../out/_tmp_/tp-player/debug + OBJECTS_DIR += $$PWD/../../out/_tmp_/tp-player/debug } else:macx:CONFIG(debug, debug|release): { - LIBS += -L$$PWD/../../external/zlib/build/debug/ -lzlibd - DESTDIR = $$PWD/../../out/client/x86/Debug + LIBS += -L$$PWD/../../external/macos/release/lib/ -lz + DESTDIR = $$PWD/../../out/client/x64/debug + + UI_DIR += $$PWD/../../out/_tmp_/tp-player/release + RCC_DIR += $$PWD/../../out/_tmp_/tp-player/release + MOC_DIR += $$PWD/../../out/_tmp_/tp-player/release + OBJECTS_DIR += $$PWD/../../out/_tmp_/tp-player/release } -INCLUDEPATH += $$PWD/../../external/zlib -INCLUDEPATH += $$PWD/../../external/zlib/build -DEPENDPATH += $$PWD/../../external/zlib -DEPENDPATH += $$PWD/../../external/zlib/build #win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/../../external/zlib/build/release/libzlibstatic.a #else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/../../external/zlib/build/debug/libzlibstaticd.a diff --git a/client/tp-player/tp-player.qrc b/client/tp-player/tp-player.qrc index f79019d..b953fb2 100644 --- a/client/tp-player/tp-player.qrc +++ b/client/tp-player/tp-player.qrc @@ -2,6 +2,7 @@ res/bg.png res/cursor.png + res/tp-player.png res/bar/bg-left.png res/bar/bg-mid.png diff --git a/client/tp_assist_macos/src/AppDelegate-C-Interface.cpp b/client/tp_assist_macos/src/AppDelegate-C-Interface.cpp index bc942ba..8463e1a 100644 --- a/client/tp_assist_macos/src/AppDelegate-C-Interface.cpp +++ b/client/tp_assist_macos/src/AppDelegate-C-Interface.cpp @@ -10,8 +10,8 @@ #include "csrc/ts_cfg.h" #include "csrc/ts_http_rpc.h" -int cpp_main(void* _self, const char* cfg_file, const char* res_path) { - if(!g_env.init(cfg_file, res_path)) +int cpp_main(void* _self, const char* bundle_path, const char* cfg_file, const char* res_path) { + if(!g_env.init(bundle_path, cfg_file, res_path)) return -1; if(!g_cfg.init()) return -2; diff --git a/client/tp_assist_macos/src/AppDelegate-C-Interface.h b/client/tp_assist_macos/src/AppDelegate-C-Interface.h index d7b455e..f6c289f 100644 --- a/client/tp_assist_macos/src/AppDelegate-C-Interface.h +++ b/client/tp_assist_macos/src/AppDelegate-C-Interface.h @@ -12,6 +12,6 @@ int AppDelegate_start_ssh_client (void *_self, const char* cmd_line, const char* int AppDelegate_select_app (void *_self); // for cpp global object initialize. -int cpp_main(void* _self, const char* cfg_file, const char* res_path); +int cpp_main(void* _self, const char* bundle_path, const char* cfg_file, const char* res_path); #endif /* wrap_c_objc_h */ diff --git a/client/tp_assist_macos/src/AppDelegate.mm b/client/tp_assist_macos/src/AppDelegate.mm index e01461f..0f25ae0 100644 --- a/client/tp_assist_macos/src/AppDelegate.mm +++ b/client/tp_assist_macos/src/AppDelegate.mm @@ -70,11 +70,14 @@ int AppDelegate_select_app (void *_self) { // Needed to trigger the menuWillOpen event [menu setDelegate:self]; - NSString *resPath = [[NSBundle mainBundle] resourcePath]; + NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; + std::string bundle_path = [bundlePath cStringUsingEncoding:NSUTF8StringEncoding]; + + NSString *resPath = [[NSBundle mainBundle] resourcePath]; std::string cpp_res_path = [resPath cStringUsingEncoding:NSUTF8StringEncoding]; std::string cpp_cfg_file = [cfgFile cStringUsingEncoding:NSUTF8StringEncoding]; - int ret = cpp_main((__bridge void*)self, cpp_cfg_file.c_str(), cpp_res_path.c_str()); + int ret = cpp_main((__bridge void*)self, bundle_path.c_str(), cpp_cfg_file.c_str(), cpp_res_path.c_str()); if(ret != 0) { http_rpc_stop(); diff --git a/client/tp_assist_macos/src/csrc/ts_env.cpp b/client/tp_assist_macos/src/csrc/ts_env.cpp index b5c9173..0a993e7 100644 --- a/client/tp_assist_macos/src/csrc/ts_env.cpp +++ b/client/tp_assist_macos/src/csrc/ts_env.cpp @@ -18,13 +18,15 @@ TsEnv::TsEnv() TsEnv::~TsEnv() {} -bool TsEnv::init(const char* cfg_file, const char* res_path) +bool TsEnv::init(const char* bundle_path, const char* cfg_file, const char* res_path) { - ex_astr2wstr(cfg_file, m_cfg_file); + ex_astr2wstr(bundle_path, m_bundle_path); + ex_astr2wstr(cfg_file, m_cfg_file); ex_astr2wstr(res_path, m_res_path); #ifdef EX_DEBUG m_site_path = L"/Users/apex/work/tp4a/teleport/client/tp_assist_macos/site"; + m_bundle_path = L"/Users/apex/work/tp4a/teleport/out/client/x64/release"; #else m_site_path = m_res_path; ex_path_join(m_site_path, false, L"site", NULL); diff --git a/client/tp_assist_macos/src/csrc/ts_env.h b/client/tp_assist_macos/src/csrc/ts_env.h index 9d4c8f5..2beb12a 100644 --- a/client/tp_assist_macos/src/csrc/ts_env.h +++ b/client/tp_assist_macos/src/csrc/ts_env.h @@ -9,9 +9,10 @@ public: TsEnv(); ~TsEnv(); - bool init(const char* cfg_file, const char* res_path); + bool init(const char* bundle_path, const char* cfg_file, const char* res_path); public: + ex_wstr m_bundle_path; ex_wstr m_cfg_file; ex_wstr m_res_path; diff --git a/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp b/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp index 4430c4a..2b62c82 100644 --- a/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp +++ b/client/tp_assist_macos/src/csrc/ts_http_rpc.cpp @@ -227,7 +227,7 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat bool b_is_html = false; // if (uri == "/") { -// ex_wstr page = L"Teleport\n\n
Teleport Assistor works fine.
"; +// ex_wstr page = L"Teleport÷˙ ÷\n\n
Teleport Assistor works fine.
"; // ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8); // // mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]); @@ -839,7 +839,102 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) { } void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) { - _create_json_ret(buf, TPE_NOT_IMPLEMENT); + Json::Value jsRoot; + + Json::CharReaderBuilder jcrb; + std::unique_ptr const jreader(jcrb.newCharReader()); + const char *str_json_begin = func_args.c_str(); + ex_astr err; + + if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err)) { + _create_json_ret(buf, TPE_JSON_FORMAT); + return; + } + + // 判断参数是否正确 + if (!jsRoot["rid"].isInt() + || !jsRoot["web"].isString() + || !jsRoot["sid"].isString() + ) { + _create_json_ret(buf, TPE_PARAM); + return; + } + + ex_astrs s_argv; + + ex_wstr w_exec_file = g_env.m_bundle_path; + ex_path_join(w_exec_file, false, L"tp-player.app", L"Contents", L"MacOS", L"tp-player", nullptr); + ex_astr exec_file; + ex_wstr2astr(w_exec_file, exec_file); + + s_argv.push_back(exec_file); + + + int rid = jsRoot["rid"].asInt(); + ex_astr a_url_base = jsRoot["web"].asCString(); + ex_astr a_sid = jsRoot["sid"].asCString(); + + char cmd_args[1024] = { 0 }; + ex_strformat(cmd_args, 1023, "%s/%s/%d", a_url_base.c_str(), a_sid.c_str(), rid); + s_argv.push_back(cmd_args); + + ex_wstr w_cmd_args; + ex_astr2wstr(cmd_args, w_cmd_args); + + char total_cmd[1024] = {0}; + ex_strformat(total_cmd, 1023, "%s %s", exec_file.c_str(), cmd_args); + +// ex_wstr w_url_base; +// ex_astr2wstr(a_url_base, w_url_base); +// ex_wstr w_cmd_args; +// ex_astr2wstr(cmd_args, w_cmd_args); +// +// ex_wstr w_exe_path; +// w_exe_path = _T("\""); +// w_exe_path += g_env.m_exec_path + _T("\\tp-player.exe\""); +// w_exe_path += _T(" \""); +// w_exe_path += w_url_base; +// w_exe_path += _T("/"); +// w_exe_path += w_cmd_args; + + Json::Value root_ret; + ex_astr utf8_path; + //ex_wstr2astr(total_cmd, utf8_path, EX_CODEPAGE_UTF8); + root_ret["cmdline"] = total_cmd; + + // EXLOGD(utf8_path.c_str()); + + // for macOS, Create Process should be fork()/exec()... + pid_t processId; + if ((processId = fork()) == 0) { + + int i = 0; + char** _argv = (char**)calloc(s_argv.size()+1, sizeof(char*)); + if (!_argv) + return; + + for (i = 0; i < s_argv.size(); ++i) + { + _argv[i] = ex_strdup(s_argv[i].c_str()); + } + _argv[i] = NULL; + + execv(exec_file.c_str(), _argv); + + for(i = 0; i < s_argv.size(); ++i) { + if(_argv[i] != NULL) { + free(_argv[i]); + } + } + free(_argv); + + } else if (processId < 0) { + root_ret["code"] = TPE_FAILED; + } else { + root_ret["code"] = TPE_OK; + } + + _create_json_ret(buf, root_ret); } void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) { diff --git a/config.ini.in b/config.ini.in index 27cb9fa..bb963ae 100644 --- a/config.ini.in +++ b/config.ini.in @@ -22,13 +22,19 @@ wget = C:\Program Files (x86)\wget\wget.exe # if not set msbuild path, default to get it by register. #msbuild = C:\Program Files (x86)\MSBuild\14.0\bin\MSBuild.exe -# need qt to build tp-player. +# need Qt >= 5.12 to build recorder player. qt = C:\Qt\Qt5.12.0\5.12.0\msvc2017 # ============================================ -# for Linux and macOS +# for Linux # ============================================ # if not set cmake path, default to '/usr/bin/cmake' cmake = /opt/cmake/bin/cmake +# ============================================ +# for MacOS +# ============================================ + +# need Qt >= 5.12 to build recorder player. +qt = /Users/apex/apps/qt5.13.1/5.13.1/clang_64/bin