macOS: 支持通过API接口进行远程调用,支持通过API接口进行录像回放。

feature/assist-websocket
Apex Liu 2022-05-19 17:39:34 +08:00
parent f870298e5d
commit dcadf399a4
12 changed files with 130 additions and 69 deletions

View File

@ -13,7 +13,6 @@
7A18188F1F7D5D7F00F3C882 /* AppDelegate-C-Interface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A18188E1F7D5D7F00F3C882 /* AppDelegate-C-Interface.cpp */; };
7A1F87B1215D5A1600B69F88 /* StatusIconAlt@2X.png in Resources */ = {isa = PBXBuildFile; fileRef = 7A1F87AF215D5A1600B69F88 /* StatusIconAlt@2X.png */; };
7A1F87B2215D5A1600B69F88 /* StatusIcon@2X.png in Resources */ = {isa = PBXBuildFile; fileRef = 7A1F87B0215D5A1600B69F88 /* StatusIcon@2X.png */; };
7A2034FB2833F355009E1491 /* tp-player.app in Resources */ = {isa = PBXBuildFile; fileRef = 7A2034FA2833F355009E1491 /* tp-player.app */; };
7A27E4A91F6A8EEC004FDE5D /* ts_env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A27E4A71F6A8EEC004FDE5D /* ts_env.cpp */; };
7A7C6C9121973C24006869D9 /* StatusIconAlt@3X.png in Resources */ = {isa = PBXBuildFile; fileRef = 7A7C6C8F21973C24006869D9 /* StatusIconAlt@3X.png */; };
7A7C6C9221973C24006869D9 /* StatusIcon@3X.png in Resources */ = {isa = PBXBuildFile; fileRef = 7A7C6C9021973C24006869D9 /* StatusIcon@3X.png */; };
@ -36,6 +35,7 @@
7AAE4B242390EE5C007EDDE7 /* libmbedtls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF222199E32B00BE5DBC /* libmbedtls.a */; };
7AAE4B252390EE7D007EDDE7 /* libmbedcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF232199E32B00BE5DBC /* libmbedcrypto.a */; };
7AAE4B262390EE7D007EDDE7 /* libmbedx509.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF212199E32B00BE5DBC /* libmbedx509.a */; };
7AC630342835EB9A0080333D /* tp-player.app in Resources */ = {isa = PBXBuildFile; fileRef = 7AC630332835EB9A0080333D /* tp-player.app */; };
7AF6593E27398C7400057A00 /* ts_ws_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AF6593C27398C7400057A00 /* ts_ws_client.cpp */; };
A1B7B9DD1DB53ED200809327 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A1B7B9DF1DB53ED200809327 /* Localizable.strings */; };
A1D700071A5DCE8D003563E4 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = A1D700061A5DCE8D003563E4 /* AboutWindowController.m */; };
@ -73,7 +73,6 @@
7A1F87AA215D574500B69F88 /* version.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; name = version.h; path = ../../../../external/jsoncpp/include/json/version.h; sourceTree = "<group>"; };
7A1F87AF215D5A1600B69F88 /* StatusIconAlt@2X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "StatusIconAlt@2X.png"; sourceTree = "<group>"; };
7A1F87B0215D5A1600B69F88 /* StatusIcon@2X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "StatusIcon@2X.png"; sourceTree = "<group>"; };
7A2034FA2833F355009E1491 /* tp-player.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = "tp-player.app"; sourceTree = "<group>"; };
7A27E4A61F6A899B004FDE5D /* ts_const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts_const.h; sourceTree = "<group>"; };
7A27E4A71F6A8EEC004FDE5D /* ts_env.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ts_env.cpp; sourceTree = "<group>"; };
7A27E4A81F6A8EEC004FDE5D /* ts_env.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts_env.h; sourceTree = "<group>"; };
@ -101,6 +100,7 @@
7AA2CD501F6AB9F10074C92B /* json_writer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json_writer.cpp; path = ../../../../external/jsoncpp/src/lib_json/json_writer.cpp; sourceTree = "<group>"; };
7AA2CD561F6ABA2E0074C92B /* mongoose.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mongoose.c; path = ../../../../external/mongoose/mongoose.c; sourceTree = "<group>"; };
7AAE4B232390E642007EDDE7 /* mongoose.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mongoose.h; path = ../../../../external/mongoose/mongoose.h; sourceTree = "<group>"; };
7AC630332835EB9A0080333D /* tp-player.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; name = "tp-player.app"; path = "../../../out/client/x64/release/tp-player.app"; sourceTree = "<group>"; };
7AF6593C27398C7400057A00 /* ts_ws_client.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ts_ws_client.cpp; sourceTree = "<group>"; };
7AF6593D27398C7400057A00 /* ts_ws_client.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ts_ws_client.h; sourceTree = "<group>"; };
7AF9BF212199E32B00BE5DBC /* libmbedx509.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedx509.a; path = ../../external/macos/release/lib/libmbedx509.a; sourceTree = "<group>"; };
@ -314,7 +314,7 @@
C149EC0415D5214600B1F558 /* Supporting Files */ = {
isa = PBXGroup;
children = (
7A2034FA2833F355009E1491 /* tp-player.app */,
7AC630332835EB9A0080333D /* tp-player.app */,
C159DC2715D5DE7F00F5DE24 /* teleport.icns */,
C149EC0515D5214600B1F558 /* TP-Assist-Info.plist */,
C149EC0615D5214600B1F558 /* InfoPlist.strings */,
@ -396,7 +396,7 @@
0ADB3B0D178EF8DB004E9BB9 /* StatusIcon.png in Resources */,
7A1F87B2215D5A1600B69F88 /* StatusIcon@2X.png in Resources */,
7A7C6C9221973C24006869D9 /* StatusIcon@3X.png in Resources */,
7A2034FB2833F355009E1491 /* tp-player.app in Resources */,
7AC630342835EB9A0080333D /* tp-player.app in Resources */,
0ADB3B0C178EF8DB004E9BB9 /* StatusIconAlt.png in Resources */,
7A1F87B1215D5A1600B69F88 /* StatusIconAlt@2X.png in Resources */,
7A7C6C9121973C24006869D9 /* StatusIconAlt@3X.png in Resources */,

View File

@ -30,19 +30,7 @@ int cpp_main(void* _self, const char* bundle_path, const char* cfg_file, const c
if(!g_cfg.init())
return -2;
TsWsClient::init_app(_self);
g_ws_client.init_app(_self);
return 0;
}
//uint64_t cpp_getpid()
//{
// pid_t pid = getpid();
//
// return static_cast<uint64_t>(pid);
//}
void url_scheme_handler(const std::string& url)
{
TsWsClient::url_scheme_handler(url);
}

View File

@ -18,9 +18,4 @@ int AppDelegate_select_app (void *_self);
// for cpp global object initialize.
int cpp_main(void* _self, const char* bundle_path, const char* cfg_file, const char* res_path, const char* log_path);
//unsigned long long cpp_getpid();
void url_scheme_handler(const std::string& url);
#endif /* wrap_c_objc_h */

View File

@ -54,12 +54,14 @@ int AppDelegate_select_app (void *_self) {
// An error has occurred, do something to handle it
NSLog(@"Failed to create directory \"%@\". Error: %@", logPath, error);
NSAlert *alert = [[NSAlert alloc] init];
alert.icon = [NSImage imageNamed:@"tpassist"];
[alert addButtonWithTitle:@"确定"];
[alert setMessageText:@"无法启动Teleport助手"];
[alert setInformativeText:@"无法创建目录 ~/tp-assist 来存储配置文件及日志文件。"];
[alert runModal];
// NSAlert *alert = [[NSAlert alloc] init];
// alert.icon = [NSImage imageNamed:@"tpassist"];
// [alert addButtonWithTitle:@"确定"];
// [alert setMessageText:@"无法启动Teleport助手"];
// [alert setInformativeText:@"无法创建目录 ~/tp-assist 来存储配置文件及日志文件。"];
// [alert runModal];
[self my_alert:@"无法启动Teleport助手" msg:@"无法创建目录 ~/tp-assist 来存储配置文件及日志文件。"];
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
[NSApp terminate:NSApp];
@ -102,7 +104,7 @@ int AppDelegate_select_app (void *_self) {
int ret = cpp_main((__bridge void*)self, bundle_path.c_str(), cpp_cfg_file.c_str(), cpp_res_path.c_str(), cpp_log_path.c_str());
if(ret != 0) {
// http_rpc_stop();
TsWsClient::stop_all_client();
g_ws_client.stop_all_client();
NSString *msg = Nil;
if(ret == -1)
@ -112,12 +114,13 @@ int AppDelegate_select_app (void *_self) {
else
msg = @"发生未知错误!";
NSAlert *alert = [[NSAlert alloc] init];
alert.icon = [NSImage imageNamed:@"tpassist"];
[alert addButtonWithTitle:@"确定"];
[alert setMessageText:@"无法启动Teleport助手"];
[alert setInformativeText:msg];
[alert runModal];
// NSAlert *alert = [[NSAlert alloc] init];
// alert.icon = [NSImage imageNamed:@"tpassist"];
// [alert addButtonWithTitle:@"确定"];
// [alert setMessageText:@"无法启动Teleport助手"];
// [alert setInformativeText:msg];
// [alert runModal];
[self my_alert:@"无法启动Teleport助手" msg:msg];
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
[NSApp terminate:NSApp];
@ -232,13 +235,19 @@ int AppDelegate_select_app (void *_self) {
}
- (IBAction)quit:(id)sender {
TsWsClient::stop_all_client();
g_ws_client.stop_all_client();
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
[NSApp terminate:NSApp];
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification
//- (void)applicationDidFinishLaunching:(NSNotification *)notification
//{
// // once the program start, register URL scheme handler.
// [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
//}
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
// once the program start, register URL scheme handler.
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
@ -258,7 +267,7 @@ int AppDelegate_select_app (void *_self) {
//
// [self my_alert:@"URL Request" msg:url];
std::string _url = [url cStringUsingEncoding:NSUTF8StringEncoding];
url_scheme_handler(_url);
g_ws_client.url_scheme_handler(_url);
}
- (void)my_alert:(NSString*) title msg:(NSString*)message {

View File

@ -27,7 +27,7 @@ bool TsEnv::init(const char* bundle_path, const char* cfg_file, const char* res_
#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";
//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);

View File

@ -14,11 +14,9 @@
#include "ts_cfg.h"
TsWsClient g_ws_client;
TsWsClient g_wss_client;
void* g_app = NULL;
// static
void TsWsClient::init_app(void* app)
{
g_app = app;
@ -27,15 +25,17 @@ void TsWsClient::init_app(void* app)
void TsWsClient::stop_all_client()
{
g_ws_client.stop();
g_wss_client.stop();
}
// ============================================================================
// static
void TsWsClient::url_scheme_handler(const std::string& url)
{
// e.g.:
// url: teleport://register?param={"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"}
EXLOGV("url-schema: %s\n", url.c_str());
std::string protocol;
std::string method;
std::string param;
@ -61,11 +61,10 @@ void TsWsClient::url_scheme_handler(const std::string& url)
return;
}
// now we support 'register' method only.
method.assign(url, pos_protocol + 3, pos_method - pos_protocol - 3);
if (method != "register")
if(method.empty())
{
EXLOGE("[ws] unknown method: %s\n", method.c_str());
EXLOGE("[ws] no method, what should I do now?\n");
return;
}
@ -108,11 +107,25 @@ void TsWsClient::url_scheme_handler(const std::string& url)
return;
}
// now we support 'register' method only.
_process_register(param, js_root);
if (method == "register")
{
_process_register(param, js_root);
}
else if(method == "run")
{
_process_run(param, js_root);
}
else if(method == "replay_rdp")
{
_process_replay_rdp(param, js_root);
}
else
{
EXLOGE("[ws] unknown method: %s\n", method.c_str());
return;
}
}
// static
void TsWsClient::_process_register(const std::string& param, Json::Value& js_root)
{
// {"ws_url":"ws://127.0.0.1:7190/ws/assist/","assist_id":1234,"session_id":"tp_5678"}
@ -129,15 +142,11 @@ void TsWsClient::_process_register(const std::string& param, Json::Value& js_roo
std::string session_id = js_root["session_id"].asCString();
std::string protocol;
protocol.assign(ws_url, 0, 3);
if (protocol == "ws:")
protocol.assign(ws_url, 0, 5);
if (protocol == "ws://" || protocol == "wss:/")
{
g_ws_client._register(ws_url, assist_id, session_id);
}
else if (protocol == "wss")
{
g_wss_client._register(ws_url, assist_id, session_id);
}
else
{
EXLOGE("[ws] invalid ws_url: %s\n", ws_url.c_str());
@ -145,6 +154,31 @@ void TsWsClient::_process_register(const std::string& param, Json::Value& js_roo
}
}
void TsWsClient::_process_run(const std::string& param, Json::Value& js_root)
{
// wrapper for _rpc_func_run_client().
Json::Value js_param;
js_param["method"] = "run";
js_param["param"] = js_root;
AssistMessage msg_req;
std::string buf;
_rpc_func_run_client(buf, msg_req, js_param);
}
void TsWsClient::_process_replay_rdp(const std::string& param, Json::Value& js_root)
{
// wrapper for _rpc_func_replay_rdp().
Json::Value js_param;
js_param["method"] = "replay_rdp";
js_param["param"] = js_root;
AssistMessage msg_req;
std::string buf;
_rpc_func_replay_rdp(buf, msg_req, js_param);
}
// ============================================================================
@ -466,6 +500,7 @@ void TsWsClient::_rpc_func_replay_rdp(ex_astr& buf, AssistMessage& msg_req, Json
ex_wstr w_exec_file = g_env.m_bundle_path;
ex_path_join(w_exec_file, false, L"Contents", L"Resources", L"tp-player.app", L"Contents", L"MacOS", L"tp-player", nullptr);
// 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);

View File

@ -33,10 +33,10 @@ public:
~TsWsClient();
static void init_app(void* app);
static void stop_all_client();
void init_app(void* app);
void stop_all_client();
static void url_scheme_handler(const std::string& url);
void url_scheme_handler(const std::string& url);
protected:
void _thread_loop(void);
@ -60,23 +60,18 @@ private:
void _send_result(int err_code, Json::Value& jr_root);
void _create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code);
void _create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code, const std::string& message);
void _create_response(ex_astr& buf, const AssistMessage& msg_ret, int err_code, const std::string& message, Json::Value& data);
// void _rpc_func_check(const ex_astr& func_args, ex_astr& buf);
// void _rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf);
// void _rpc_func_file_action(const ex_astr& func_args, ex_astr& buf);
// void _rpc_func_get_version(const ex_astr& func_args, ex_astr& buf);
static void _mg_event_handler(struct mg_connection* nc, int ev, void* ev_data);
static void _process_register(const std::string& param, Json::Value& js_root);
void _process_register(const std::string& param, Json::Value& js_root);
void _process_run(const std::string& param, Json::Value& js_root);
void _process_replay_rdp(const std::string& param, Json::Value& js_root);
private:
struct mg_mgr m_mg_mgr;
@ -84,4 +79,6 @@ private:
uint32_t m_assist_id;
};
extern TsWsClient g_ws_client;
#endif // __TS_WS_CLIENT_H__

View File

@ -64,7 +64,7 @@ let $tp = {
options: {}
, on_init: function (cb_stack) {
cb_stack.exec();
} // should be overwrite.
} // should be overwritten.
}
, assist_checked: null

View File

@ -235,7 +235,7 @@ $assist._on_ret_run = function (code, message, ret) {
return;
}
$tp.notify_success('已启动本地客户端进行远程连接!');
$tp.notify_success('已通知助手启动本地客户端进行远程连接!');
}
$assist._on_ret_replay_rdp = function (code, message, ret) {
@ -247,7 +247,7 @@ $assist._on_ret_replay_rdp = function (code, message, ret) {
return;
}
$tp.notify_success('已启动本地RDP录像播放器!');
$tp.notify_success('已通知助手启动本地RDP录像播放器!');
}
$assist.check_assist = function () {

View File

@ -101,6 +101,10 @@ class TPBaseHandler(tornado.web.RequestHandler):
# x = self.xsrf_token
self._s_id = self.get_cookie('_sid')
if self._s_id is None:
print(self.request.headers)
if 'Teleport-Session-Id' in self.request.headers:
self._s_id = self.request.headers['Teleport-Session-Id']
if self._s_id is None:
self._s_id = 'tp_{}_{}'.format(int(time.time()), binascii.b2a_hex(os.urandom(8)).decode())
self.set_cookie('_sid', self._s_id)

View File

@ -302,6 +302,7 @@ controllers = [
# api v2
(r'/api/v2/request_session', api_v2.RequestSessionHandler),
(r'/api/v2/request_access_token', api_v2.RequestAccessTokenHandler),
(r'/.*', index.CatchAllHandler),
]

View File

@ -93,6 +93,7 @@ def _parse_api_args(handler):
return False, handler.write_json(TPE_JSON_FORMAT)
args['_srv_name_'] = sec_info['name']
args['_privilege'] = sec_info['privilege']
return True, args
@ -128,3 +129,34 @@ class RequestSessionHandler(TPBaseJsonHandler):
return self.write_json(ret['code'], ret['message'])
return self.write_json(TPE_OK, data=ret['data'])
class RequestAccessTokenHandler(TPBaseJsonHandler):
@tornado.gen.coroutine
def post(self):
ok, args = yield _parse_api_args(self)
if not ok:
return
try:
operator = args['operator']
privilege = args['_privilege']
except:
return self.write_json(TPE_PARAM)
operator_surname = '[{}] {}'.format(args['_srv_name_'], operator)
_user = {
'id': 0,
'username': operator,
'surname': operator_surname,
'role_id': 0,
'role': '',
'privilege': privilege,
'_is_login': True
}
self.set_session('user', _user, 60)
self._user = _user
return self.write_json(TPE_OK, data={'sid': self._s_id})