From f9f9cde2b480533240c9c53fbf36373f3ff65c00 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 27 Dec 2020 22:14:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86webapi=E3=80=81webhook?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 223 ++++++++++++++++++++------------------------- server/WebApi.h | 99 +++++++++++++++++++- server/WebHook.cpp | 48 ++++------ server/WebHook.h | 21 ++++- 4 files changed, 229 insertions(+), 162 deletions(-) mode change 100644 => 100755 server/WebApi.cpp mode change 100644 => 100755 server/WebApi.h mode change 100644 => 100755 server/WebHook.cpp mode change 100644 => 100755 server/WebHook.h diff --git a/server/WebApi.cpp b/server/WebApi.cpp old mode 100644 new mode 100755 index fac9bd9d..2481ce42 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -13,7 +13,6 @@ #include #include #include -#include "jsoncpp/json.h" #include "Util/util.h" #include "Util/logger.h" #include "Util/onceToken.h" @@ -36,20 +35,11 @@ #if defined(ENABLE_RTPPROXY) #include "Rtp/RtpServer.h" #endif -using namespace Json; + using namespace toolkit; using namespace mediakit; namespace API { -typedef enum { - Exception = -400,//代码抛异常 - InvalidArgs = -300,//参数不合法 - SqlFailed = -200,//sql执行失败 - AuthFailed = -100,//鉴权失败 - OtherFailed = -1,//业务代码执行失败, - Success = 0//执行成功 -} ApiErr; - #define API_FIELD "api." const string kApiDebug = API_FIELD"apiDebug"; const string kSecret = API_FIELD"secret"; @@ -64,42 +54,7 @@ static onceToken token([]() { }); }//namespace API - -class ApiRetException: public std::runtime_error { -public: - ApiRetException(const char *str = "success" ,int code = API::Success):runtime_error(str){ - _code = code; - } - ~ApiRetException() = default; - int code(){ return _code; } -private: - int _code; -}; - -class AuthException : public ApiRetException { -public: - AuthException(const char *str):ApiRetException(str,API::AuthFailed){} - ~AuthException() = default; -}; - -class InvalidArgsException: public ApiRetException { -public: - InvalidArgsException(const char *str):ApiRetException(str,API::InvalidArgs){} - ~InvalidArgsException() = default; -}; - -class SuccessException: public ApiRetException { -public: - SuccessException():ApiRetException("success",API::Success){} - ~SuccessException() = default; -}; - -#define API_ARGS1 SockInfo &sender,HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, ApiArgsType &allArgs, Json::Value &val -#define API_ARGS2 API_ARGS1, const HttpSession::HttpResponseInvoker &invoker -#define API_ARGS_VALUE1 sender,headerIn,headerOut,allArgs,val - -typedef map ApiArgsType; -typedef function HttpApi; +using HttpApi = function; //http api列表 static map s_map_api; @@ -119,7 +74,7 @@ static void responseApi(int code, const string &msg, const HttpSession::HttpResp static ApiArgsType getAllArgs(const Parser &parser); -static HttpApi toApi(const function &cb) { +static HttpApi toApi(const function &cb) { return [cb](const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, SockInfo &sender) { GET_CONFIG(string, charSet, Http::kCharSet); HttpSession::KeyValue headerOut; @@ -128,23 +83,62 @@ static HttpApi toApi(const function &cb) { Json::Value val; val["code"] = API::Success; + //参数解析成map auto args = getAllArgs(parser); cb(sender, parser.getHeader(), headerOut, args, val, invoker); }; } -static HttpApi toApi(const function &cb) { - return toApi([cb](API_ARGS2) { - cb(API_ARGS_VALUE1); +static HttpApi toApi(const function &cb) { + return toApi([cb](API_ARGS_MAP_ASYNC) { + cb(API_ARGS_VALUE); invoker("200 OK", headerOut, val.toStyledString()); }); } -template -static void api_regist(const string &api_path, FUNC &&func) { - s_map_api.emplace(api_path, toApi(std::move(func))); +static HttpApi toApi(const function &cb) { + return [cb](const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, SockInfo &sender) { + GET_CONFIG(string, charSet, Http::kCharSet); + HttpSession::KeyValue headerOut; + headerOut["Content-Type"] = string("application/json; charset=") + charSet; + + Json::Value out; + out["code"] = API::Success; + + if (parser["Content-Type"].find("application/json") == string::npos) { + throw InvalidArgsException("该接口只支持json格式的请求"); + } + //参数解析成json对象然后处理 + Json::Value in; + Json::Reader reader; + reader.parse(parser.Content(), in); + + cb(sender, parser.getHeader(), headerOut, in, out, invoker); + }; } +static HttpApi toApi(const function &cb) { + return toApi([cb](API_ARGS_JSON_ASYNC) { + cb(API_ARGS_VALUE); + invoker("200 OK", headerOut, val.toStyledString()); + }); +} + +void api_regist(const string &api_path, const function &func) { + s_map_api.emplace(api_path, toApi(func)); +} + +void api_regist(const string &api_path, const function &func) { + s_map_api.emplace(api_path, toApi(func)); +} + +void api_regist(const string &api_path, const function &func) { + s_map_api.emplace(api_path, toApi(func)); +} + +void api_regist(const string &api_path, const function &func) { + s_map_api.emplace(api_path, toApi(func)); +} //获取HTTP请求中url参数、content参数 static ApiArgsType getAllArgs(const Parser &parser) { @@ -233,29 +227,6 @@ static inline void addHttpListener(){ }); } -template -bool checkArgs(Args &&args,First &&first){ - return !args[first].empty(); -} - -template -bool checkArgs(Args &&args,First &&first,KeyTypes && ...keys){ - return !args[first].empty() && checkArgs(std::forward(args),std::forward(keys)...); -} - -#define CHECK_ARGS(...) \ - if(!checkArgs(allArgs,##__VA_ARGS__)){ \ - throw InvalidArgsException("缺少必要参数:" #__VA_ARGS__); \ - } - -#define CHECK_SECRET() \ - if(sender.get_peer_ip() != "127.0.0.1"){ \ - CHECK_ARGS("secret"); \ - if(api_secret != allArgs["secret"]){ \ - throw AuthException("secret错误"); \ - } \ - } - //拉流代理器列表 static unordered_map s_proxyMap; static recursive_mutex s_proxyMapMtx; @@ -285,7 +256,7 @@ void installWebApi() { //获取线程负载 //测试url http://127.0.0.1/index/api/getThreadsLoad - api_regist("/index/api/getThreadsLoad",[](API_ARGS2){ + api_regist("/index/api/getThreadsLoad",[](API_ARGS_MAP_ASYNC){ EventPollerPool::Instance().getExecutorDelay([invoker, headerOut](const vector &vecDelay) { Value val; auto vec = EventPollerPool::Instance().getExecutorLoad(); @@ -303,7 +274,7 @@ void installWebApi() { //获取后台工作线程负载 //测试url http://127.0.0.1/index/api/getWorkThreadsLoad - api_regist("/index/api/getWorkThreadsLoad", [](API_ARGS2){ + api_regist("/index/api/getWorkThreadsLoad", [](API_ARGS_MAP_ASYNC){ WorkThreadPool::Instance().getExecutorDelay([invoker, headerOut](const vector &vecDelay) { Value val; auto vec = WorkThreadPool::Instance().getExecutorLoad(); @@ -321,7 +292,7 @@ void installWebApi() { //获取服务器配置 //测试url http://127.0.0.1/index/api/getServerConfig - api_regist("/index/api/getServerConfig",[](API_ARGS1){ + api_regist("/index/api/getServerConfig",[](API_ARGS_MAP){ CHECK_SECRET(); Value obj; for (auto &pr : mINI::Instance()) { @@ -333,7 +304,7 @@ void installWebApi() { //设置服务器配置 //测试url(比如关闭http api调试) http://127.0.0.1/index/api/setServerConfig?api.apiDebug=0 //你也可以通过http post方式传参,可以通过application/x-www-form-urlencoded或application/json方式传参 - api_regist("/index/api/setServerConfig",[](API_ARGS1){ + api_regist("/index/api/setServerConfig",[](API_ARGS_MAP){ CHECK_SECRET(); auto &ini = mINI::Instance(); int changed = API::Success; @@ -357,7 +328,7 @@ void installWebApi() { }); - static auto s_get_api_list = [](API_ARGS1){ + static auto s_get_api_list = [](API_ARGS_MAP){ CHECK_SECRET(); for(auto &pr : s_map_api){ val["data"].append(pr.first); @@ -366,20 +337,20 @@ void installWebApi() { //获取服务器api列表 //测试url http://127.0.0.1/index/api/getApiList - api_regist("/index/api/getApiList",[](API_ARGS1){ - s_get_api_list(API_ARGS_VALUE1); + api_regist("/index/api/getApiList",[](API_ARGS_MAP){ + s_get_api_list(API_ARGS_VALUE); }); //获取服务器api列表 //测试url http://127.0.0.1/index/ - api_regist("/index/",[](API_ARGS1){ - s_get_api_list(API_ARGS_VALUE1); + api_regist("/index/",[](API_ARGS_MAP){ + s_get_api_list(API_ARGS_VALUE); }); #if !defined(_WIN32) //重启服务器,只有Daemon方式才能重启,否则是直接关闭! //测试url http://127.0.0.1/index/api/restartServer - api_regist("/index/api/restartServer",[](API_ARGS1){ + api_regist("/index/api/restartServer",[](API_ARGS_MAP){ CHECK_SECRET(); EventPollerPool::Instance().getPoller()->doDelayTask(1000,[](){ //尝试正常退出 @@ -457,7 +428,7 @@ void installWebApi() { //测试url0(获取所有流) http://127.0.0.1/index/api/getMediaList //测试url1(获取虚拟主机为"__defaultVost__"的流) http://127.0.0.1/index/api/getMediaList?vhost=__defaultVost__ //测试url2(获取rtsp类型的流) http://127.0.0.1/index/api/getMediaList?schema=rtsp - api_regist("/index/api/getMediaList",[](API_ARGS1){ + api_regist("/index/api/getMediaList",[](API_ARGS_MAP){ CHECK_SECRET(); //获取所有MediaSource列表 MediaSource::for_each_media([&](const MediaSource::Ptr &media){ @@ -475,14 +446,14 @@ void installWebApi() { }); //测试url http://127.0.0.1/index/api/isMediaOnline?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs - api_regist("/index/api/isMediaOnline",[](API_ARGS1){ + api_regist("/index/api/isMediaOnline",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("schema","vhost","app","stream"); val["online"] = (bool) (MediaSource::find(allArgs["schema"],allArgs["vhost"],allArgs["app"],allArgs["stream"])); }); //测试url http://127.0.0.1/index/api/getMediaInfo?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs - api_regist("/index/api/getMediaInfo",[](API_ARGS1){ + api_regist("/index/api/getMediaInfo",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("schema","vhost","app","stream"); auto src = MediaSource::find(allArgs["schema"],allArgs["vhost"],allArgs["app"],allArgs["stream"]); @@ -497,7 +468,7 @@ void installWebApi() { //主动关断流,包括关断拉流、推流 //测试url http://127.0.0.1/index/api/close_stream?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1 - api_regist("/index/api/close_stream",[](API_ARGS1){ + api_regist("/index/api/close_stream",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("schema","vhost","app","stream"); //踢掉推流器 @@ -519,7 +490,7 @@ void installWebApi() { //批量主动关断流,包括关断拉流、推流 //测试url http://127.0.0.1/index/api/close_streams?schema=rtsp&vhost=__defaultVhost__&app=live&stream=obs&force=1 - api_regist("/index/api/close_streams",[](API_ARGS1){ + api_regist("/index/api/close_streams",[](API_ARGS_MAP){ CHECK_SECRET(); //筛选命中个数 int count_hit = 0; @@ -555,7 +526,7 @@ void installWebApi() { //获取所有TcpSession列表信息 //可以根据本地端口和远端ip来筛选 //测试url(筛选某端口下的tcp会话) http://127.0.0.1/index/api/getAllSession?local_port=1935 - api_regist("/index/api/getAllSession",[](API_ARGS1){ + api_regist("/index/api/getAllSession",[](API_ARGS_MAP){ CHECK_SECRET(); Value jsession; uint16_t local_port = allArgs["local_port"].as(); @@ -580,7 +551,7 @@ void installWebApi() { //断开tcp连接,比如说可以断开rtsp、rtmp播放器等 //测试url http://127.0.0.1/index/api/kick_session?id=123456 - api_regist("/index/api/kick_session",[](API_ARGS1){ + api_regist("/index/api/kick_session",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("id"); //踢掉tcp会话 @@ -594,7 +565,7 @@ void installWebApi() { //批量断开tcp连接,比如说可以断开rtsp、rtmp播放器等 //测试url http://127.0.0.1/index/api/kick_sessions?local_port=1935 - api_regist("/index/api/kick_sessions",[](API_ARGS1){ + api_regist("/index/api/kick_sessions",[](API_ARGS_MAP){ CHECK_SECRET(); uint16_t local_port = allArgs["local_port"].as(); string &peer_ip = allArgs["peer_ip"]; @@ -658,7 +629,7 @@ void installWebApi() { //动态添加rtsp/rtmp拉流代理 //测试url http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=proxy&enable_rtsp=1&enable_rtmp=1&stream=0&url=rtmp://127.0.0.1/live/obs - api_regist("/index/api/addStreamProxy",[](API_ARGS2){ + api_regist("/index/api/addStreamProxy",[](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); CHECK_ARGS("vhost","app","stream","url"); addStreamProxy(allArgs["vhost"], @@ -681,7 +652,7 @@ void installWebApi() { //关闭拉流代理 //测试url http://127.0.0.1/index/api/delStreamProxy?key=__defaultVhost__/proxy/0 - api_regist("/index/api/delStreamProxy",[](API_ARGS1){ + api_regist("/index/api/delStreamProxy",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("key"); lock_guard lck(s_proxyMapMtx); @@ -721,7 +692,7 @@ void installWebApi() { //动态添加rtsp/rtmp拉流代理 //测试url http://127.0.0.1/index/api/addFFmpegSource?src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://127.0.0.1/live/hks2&timeout_ms=10000 - api_regist("/index/api/addFFmpegSource",[](API_ARGS2){ + api_regist("/index/api/addFFmpegSource",[](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); CHECK_ARGS("src_url","dst_url","timeout_ms"); auto src_url = allArgs["src_url"]; @@ -744,7 +715,7 @@ void installWebApi() { //关闭拉流代理 //测试url http://127.0.0.1/index/api/delFFmepgSource?key=key - api_regist("/index/api/delFFmpegSource",[](API_ARGS1){ + api_regist("/index/api/delFFmpegSource",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("key"); lock_guard lck(s_ffmpegMapMtx); @@ -753,13 +724,13 @@ void installWebApi() { //新增http api下载可执行程序文件接口 //测试url http://127.0.0.1/index/api/downloadBin - api_regist("/index/api/downloadBin",[](API_ARGS2){ + api_regist("/index/api/downloadBin",[](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); invoker.responseFile(headerIn,StrCaseMap(),exePath()); }); #if defined(ENABLE_RTPPROXY) - api_regist("/index/api/getRtpInfo",[](API_ARGS1){ + api_regist("/index/api/getRtpInfo",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("stream_id"); @@ -775,7 +746,7 @@ void installWebApi() { val["local_ip"] = process->get_local_ip(); }); - api_regist("/index/api/openRtpServer",[](API_ARGS1){ + api_regist("/index/api/openRtpServer",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("port", "enable_tcp", "stream_id"); @@ -801,7 +772,7 @@ void installWebApi() { val["port"] = server->getPort(); }); - api_regist("/index/api/closeRtpServer",[](API_ARGS1){ + api_regist("/index/api/closeRtpServer",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("stream_id"); @@ -816,7 +787,7 @@ void installWebApi() { val["hit"] = 1; }); - api_regist("/index/api/listRtpServer",[](API_ARGS1){ + api_regist("/index/api/listRtpServer",[](API_ARGS_MAP){ CHECK_SECRET(); lock_guard lck(s_rtpServerMapMtx); @@ -828,7 +799,7 @@ void installWebApi() { } }); - api_regist("/index/api/startSendRtp",[](API_ARGS2){ + api_regist("/index/api/startSendRtp",[](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); CHECK_ARGS("vhost", "app", "stream", "ssrc", "dst_url", "dst_port", "is_udp"); @@ -847,7 +818,7 @@ void installWebApi() { }); }); - api_regist("/index/api/stopSendRtp",[](API_ARGS1){ + api_regist("/index/api/stopSendRtp",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("vhost", "app", "stream"); @@ -862,7 +833,7 @@ void installWebApi() { } }); - api_regist("/index/api/pauseRtpCheck", [](API_ARGS1) { + api_regist("/index/api/pauseRtpCheck", [](API_ARGS_MAP) { CHECK_SECRET(); CHECK_ARGS("stream_id"); //只是暂停流的检查,流媒体服务器做为流负载服务,收流就转发,RTSP/RTMP有自己暂停协议 @@ -877,7 +848,7 @@ void installWebApi() { val["hit"] = 1; }); - api_regist("/index/api/resumeRtpCheck", [](API_ARGS1) { + api_regist("/index/api/resumeRtpCheck", [](API_ARGS_MAP) { CHECK_SECRET(); CHECK_ARGS("stream_id"); @@ -895,7 +866,7 @@ void installWebApi() { #endif//ENABLE_RTPPROXY // 开始录制hls或MP4 - api_regist("/index/api/startRecord",[](API_ARGS1){ + api_regist("/index/api/startRecord",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("type","vhost","app","stream"); auto result = Recorder::startRecord((Recorder::type) allArgs["type"].as(), @@ -909,7 +880,7 @@ void installWebApi() { }); // 停止录制hls或MP4 - api_regist("/index/api/stopRecord",[](API_ARGS1){ + api_regist("/index/api/stopRecord",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("type","vhost","app","stream"); auto result = Recorder::stopRecord((Recorder::type) allArgs["type"].as(), @@ -922,7 +893,7 @@ void installWebApi() { }); // 获取hls或MP4录制状态 - api_regist("/index/api/isRecording",[](API_ARGS1){ + api_regist("/index/api/isRecording",[](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("type","vhost","app","stream"); val["status"] = Recorder::isRecording((Recorder::type) allArgs["type"].as(), @@ -933,7 +904,7 @@ void installWebApi() { //获取录像文件夹列表或mp4文件列表 //http://127.0.0.1/index/api/getMp4RecordFile?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01 - api_regist("/index/api/getMp4RecordFile", [](API_ARGS1){ + api_regist("/index/api/getMp4RecordFile", [](API_ARGS_MAP){ CHECK_SECRET(); CHECK_ARGS("vhost", "app", "stream"); auto record_path = Recorder::getRecordPath(Recorder::type_mp4, allArgs["vhost"], allArgs["app"],allArgs["stream"]); @@ -988,7 +959,7 @@ void installWebApi() { //获取截图缓存或者实时截图 //http://127.0.0.1/index/api/getSnap?url=rtmp://127.0.0.1/record/robot.mp4&timeout_sec=10&expire_sec=3 - api_regist("/index/api/getSnap", [](API_ARGS2){ + api_regist("/index/api/getSnap", [](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); CHECK_ARGS("url", "timeout_sec", "expire_sec"); GET_CONFIG(string, snap_root, API::kSnapRoot); @@ -1051,7 +1022,7 @@ void installWebApi() { }); ////////////以下是注册的Hook API//////////// - api_regist("/index/hook/on_publish",[](API_ARGS1){ + api_regist("/index/hook/on_publish",[](API_ARGS_MAP){ //开始推流事件 //转换成rtsp或rtmp val["enableRtxp"] = true; @@ -1061,21 +1032,21 @@ void installWebApi() { val["enableMP4"] = false; }); - api_regist("/index/hook/on_play",[](API_ARGS1){ + api_regist("/index/hook/on_play",[](API_ARGS_MAP){ //开始播放事件 }); - api_regist("/index/hook/on_flow_report",[](API_ARGS1){ + api_regist("/index/hook/on_flow_report",[](API_ARGS_MAP){ //流量统计hook api }); - api_regist("/index/hook/on_rtsp_realm",[](API_ARGS1){ + api_regist("/index/hook/on_rtsp_realm",[](API_ARGS_MAP){ //rtsp是否需要鉴权,默认需要鉴权 val["code"] = API::Success; val["realm"] = "zlmediakit_reaml"; }); - api_regist("/index/hook/on_rtsp_auth",[](API_ARGS1){ + api_regist("/index/hook/on_rtsp_auth",[](API_ARGS_MAP){ //rtsp鉴权密码,密码等于用户名 //rtsp可以有双重鉴权!后面还会触发on_play事件 CHECK_ARGS("user_name"); @@ -1084,13 +1055,13 @@ void installWebApi() { val["passwd"] = allArgs["user_name"].data(); }); - api_regist("/index/hook/on_stream_changed",[](API_ARGS1){ + api_regist("/index/hook/on_stream_changed",[](API_ARGS_MAP){ //媒体注册或反注册事件 }); #if !defined(_WIN32) - api_regist("/index/hook/on_stream_not_found_ffmpeg",[](API_ARGS2){ + api_regist("/index/hook/on_stream_not_found_ffmpeg",[](API_ARGS_MAP_ASYNC){ //媒体未找到事件,我们都及时拉流hks作为替代品,目的是为了测试按需拉流 CHECK_SECRET(); CHECK_ARGS("vhost","app","stream"); @@ -1122,7 +1093,7 @@ void installWebApi() { }); #endif//!defined(_WIN32) - api_regist("/index/hook/on_stream_not_found",[](API_ARGS2){ + api_regist("/index/hook/on_stream_not_found",[](API_ARGS_MAP_ASYNC){ //媒体未找到事件,我们都及时拉流hks作为替代品,目的是为了测试按需拉流 CHECK_SECRET(); CHECK_ARGS("vhost","app","stream"); @@ -1146,15 +1117,15 @@ void installWebApi() { }); }); - api_regist("/index/hook/on_record_mp4",[](API_ARGS1){ + api_regist("/index/hook/on_record_mp4",[](API_ARGS_MAP){ //录制mp4分片完毕事件 }); - api_regist("/index/hook/on_shell_login",[](API_ARGS1){ + api_regist("/index/hook/on_shell_login",[](API_ARGS_MAP){ //shell登录调试事件 }); - api_regist("/index/hook/on_stream_none_reader",[](API_ARGS1){ + api_regist("/index/hook/on_stream_none_reader",[](API_ARGS_MAP){ //无人观看流默认关闭 val["close"] = true; }); @@ -1164,7 +1135,7 @@ void installWebApi() { return true; }; - api_regist("/index/hook/on_http_access",[](API_ARGS1){ + api_regist("/index/hook/on_http_access",[](API_ARGS_MAP){ //在这里根据allArgs["params"](url参数)来判断该http客户端是否有权限访问该文件 if(!checkAccess(allArgs["params"])){ //无访问权限 @@ -1185,7 +1156,7 @@ void installWebApi() { }); - api_regist("/index/hook/on_server_started",[](API_ARGS1){ + api_regist("/index/hook/on_server_started",[](API_ARGS_MAP){ //服务器重启报告 }); } diff --git a/server/WebApi.h b/server/WebApi.h old mode 100644 new mode 100755 index 028a5445..6876d8d5 --- a/server/WebApi.h +++ b/server/WebApi.h @@ -12,10 +12,21 @@ #define ZLMEDIAKIT_WEBAPI_H #include +#include +#include "jsoncpp/json.h" +#include "Common/Parser.h" +#include "Network/Socket.h" +#include "Http/HttpSession.h" + using namespace std; +using namespace Json; +using namespace toolkit; +using namespace mediakit; + +//配置文件路径 +extern string g_ini_file; namespace mediakit { - ////////////RTSP服务器配置/////////// namespace Rtsp { extern const string kPort; @@ -25,13 +36,93 @@ extern const string kPort; namespace Rtmp { extern const string kPort; } //namespace RTMP - } // namespace mediakit +namespace API { +typedef enum { + NotFound = -500,//未找到 + Exception = -400,//代码抛异常 + InvalidArgs = -300,//参数不合法 + SqlFailed = -200,//sql执行失败 + AuthFailed = -100,//鉴权失败 + OtherFailed = -1,//业务代码执行失败, + Success = 0//执行成功 +} ApiErr; +}//namespace API + +class ApiRetException: public std::runtime_error { +public: + ApiRetException(const char *str = "success" ,int code = API::Success):runtime_error(str){ + _code = code; + } + ~ApiRetException() = default; + int code(){ return _code; } +private: + int _code; +}; + +class AuthException : public ApiRetException { +public: + AuthException(const char *str):ApiRetException(str,API::AuthFailed){} + ~AuthException() = default; +}; + +class InvalidArgsException: public ApiRetException { +public: + InvalidArgsException(const char *str):ApiRetException(str,API::InvalidArgs){} + ~InvalidArgsException() = default; +}; + +class SuccessException: public ApiRetException { +public: + SuccessException():ApiRetException("success",API::Success){} + ~SuccessException() = default; +}; + +using ApiArgsType = map; + +#define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, ApiArgsType &allArgs, Json::Value &val +#define API_ARGS_MAP_ASYNC API_ARGS_MAP, const HttpSession::HttpResponseInvoker &invoker +#define API_ARGS_JSON SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, Json::Value &allArgs, Json::Value &val +#define API_ARGS_JSON_ASYNC API_ARGS_JSON, const HttpSession::HttpResponseInvoker &invoker +#define API_ARGS_VALUE sender, headerIn, headerOut, allArgs, val + +//注册http请求参数是map类型的http api +void api_regist(const string &api_path, const function &func); +//注册http请求参数是map类型,但是可以异步回复的的http api +void api_regist(const string &api_path, const function &func); + +//注册http请求参数是Json::Value类型的http api(可以支持多级嵌套的json参数对象) +void api_regist(const string &api_path, const function &func); +//注册http请求参数是Json::Value类型,但是可以异步回复的的http api +void api_regist(const string &api_path, const function &func); + +template +bool checkArgs(Args &&args, First &&first) { + return !args[first].empty(); +} + +template +bool checkArgs(Args &&args, First &&first, KeyTypes &&...keys) { + return !args[first].empty() && checkArgs(std::forward(args), std::forward(keys)...); +} + +//检查http参数是否为空的宏 +#define CHECK_ARGS(...) \ + if(!checkArgs(allArgs,##__VA_ARGS__)){ \ + throw InvalidArgsException("缺少必要参数:" #__VA_ARGS__); \ + } + +//检查http参数中是否附带secret密钥的宏,127.0.0.1的ip不检查密钥 +#define CHECK_SECRET() \ + if(sender.get_peer_ip() != "127.0.0.1"){ \ + CHECK_ARGS("secret"); \ + if(api_secret != allArgs["secret"]){ \ + throw AuthException("secret错误"); \ + } \ + } void installWebApi(); void unInstallWebApi(); -//配置文件路径 -extern string g_ini_file; #endif //ZLMEDIAKIT_WEBAPI_H diff --git a/server/WebHook.cpp b/server/WebHook.cpp old mode 100644 new mode 100755 index eda1648d..128c2c83 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -9,9 +9,7 @@ */ #include -#include "jsoncpp/json.h" #include "Util/logger.h" -#include "Util/util.h" #include "Util/onceToken.h" #include "Util/NoticeCenter.h" #include "Common/config.h" @@ -22,21 +20,9 @@ #include "Http/HttpSession.h" #include "WebHook.h" -using namespace Json; using namespace toolkit; using namespace mediakit; - -//支持json或urlencoded方式传输参数 -#define JSON_ARGS - -#ifdef JSON_ARGS -typedef Value ArgsType; -#else -typedef HttpArgs ArgsType; -#endif - - namespace Hook { #define HOOK_FIELD "hook." @@ -126,35 +112,35 @@ const char *getContentType(const HttpArgs &value){ return "application/x-www-form-urlencoded"; } -static void do_http_hook(const string &url,const ArgsType &body,const function &fun){ - GET_CONFIG(string,mediaServerId,General::kMediaServerId); - const_cast(body)["mediaServerId"] = mediaServerId; +void do_http_hook(const string &url,const ArgsType &body,const function &func){ + GET_CONFIG(string, mediaServerId, General::kMediaServerId); + GET_CONFIG(float, hook_timeoutSec, Hook::kTimeoutSec); - GET_CONFIG(float,hook_timeoutSec,Hook::kTimeoutSec); + const_cast(body)["mediaServerId"] = mediaServerId; HttpRequester::Ptr requester(new HttpRequester); requester->setMethod("POST"); auto bodyStr = to_string(body); requester->setBody(bodyStr); - requester->addHeader("Content-Type",getContentType(body)); + requester->addHeader("Content-Type", getContentType(body)); std::shared_ptr pTicker(new Ticker); - requester->startRequester(url,[url,fun,bodyStr,requester,pTicker](const SockException &ex, - const string &status, - const HttpClient::HttpHeader &header, - const string &strRecvBody){ - onceToken token(nullptr,[&](){ + requester->startRequester(url, [url, func, bodyStr, requester, pTicker](const SockException &ex, + const string &status, + const HttpClient::HttpHeader &header, + const string &strRecvBody) { + onceToken token(nullptr, [&]() { const_cast(requester).reset(); }); parse_http_response(ex,status,header,strRecvBody,[&](const Value &obj,const string &err){ - if(fun){ - fun(obj,err); + if (func) { + func(obj, err); } - if(!err.empty()) { - WarnL << "hook " << url << " " <elapsedTime() << "ms,failed" << err << ":" << bodyStr; - }else if(pTicker->elapsedTime() > 500){ - DebugL << "hook " << url << " " <elapsedTime() << "ms,success:" << bodyStr; + if (!err.empty()) { + WarnL << "hook " << url << " " << pTicker->elapsedTime() << "ms,failed" << err << ":" << bodyStr; + } else if (pTicker->elapsedTime() > 500) { + DebugL << "hook " << url << " " << pTicker->elapsedTime() << "ms,success:" << bodyStr; } }); - },hook_timeoutSec); + }, hook_timeoutSec); } static ArgsType make_json(const MediaInfo &args){ diff --git a/server/WebHook.h b/server/WebHook.h old mode 100644 new mode 100755 index 0d39278e..6cde95b0 --- a/server/WebHook.h +++ b/server/WebHook.h @@ -12,13 +12,32 @@ #define ZLMEDIAKIT_WEBHOOK_H #include +#include +#include "jsoncpp/json.h" using namespace std; +using namespace Json; + +//支持json或urlencoded方式传输参数 +#define JSON_ARGS + +#ifdef JSON_ARGS +typedef Value ArgsType; +#else +typedef HttpArgs ArgsType; +#endif namespace Hook { +//web hook回复最大超时时间 extern const string kTimeoutSec; }//namespace Hook void installWebHook(); void unInstallWebHook(); - +/** + * 触发http hook请求 + * @param url 请求地址 + * @param body 请求body + * @param func 回调 + */ +void do_http_hook(const string &url, const ArgsType &body, const function &func = nullptr); #endif //ZLMEDIAKIT_WEBHOOK_H