/* * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). * * Use of this source code is governed by MIT-like license that can be found in the * LICENSE file in the root of the source tree. All contributing project authors * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_WEBAPI_H #define ZLMEDIAKIT_WEBAPI_H #include #include #include "json/json.h" #include "Common/Parser.h" #include "Network/Socket.h" #include "Http/HttpSession.h" #include "Common/MultiMediaSourceMuxer.h" #if defined(ENABLE_WEBRTC) #include "webrtc/WebRtcTransport.h" #endif #include "Http/HttpCookieManager.h" // 配置文件路径 [AUTO-TRANSLATED:8a373c2f] // Configuration file path extern std::string g_ini_file; namespace mediakit { // //////////RTSP服务器配置/////////// [AUTO-TRANSLATED:950e1981] // //////////RTSP server configuration/////////// namespace Rtsp { extern const std::string kPort; } //namespace Rtsp // //////////RTMP服务器配置/////////// [AUTO-TRANSLATED:8de6f41f] // //////////RTMP server configuration/////////// namespace Rtmp { extern const std::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; extern const std::string kSecret; extern const std::string kApiDebug; } // namespace API class ApiRetException : public std::runtime_error { public: ApiRetException(const char *str = "success", int code = API::Success, mediakit::StrCaseMap headers = {}, Json::Value body = {}) : runtime_error(str) { _code = code; _headers = std::move(headers); _body = std::move(body); } int code() { return _code; } mediakit::StrCaseMap &getHeaders() { return _headers; } Json::Value &getBody() { return _body; } private: int _code; mediakit::StrCaseMap _headers; Json::Value _body; }; class AuthException : public ApiRetException { public: AuthException(const char *str, mediakit::StrCaseMap headers = {}, Json::Value body = {}) : ApiRetException(str, API::AuthFailed, std::move(headers), std::move(body)) {} }; class InvalidArgsException : public ApiRetException { public: InvalidArgsException(const char *str, mediakit::StrCaseMap headers = {}, Json::Value body = {}) : ApiRetException(str, API::InvalidArgs, std::move(headers), std::move(body)) {} }; class SuccessException : public ApiRetException { public: SuccessException(mediakit::StrCaseMap headers = {}, Json::Value body = {}) : ApiRetException("success", API::Success, std::move(headers), std::move(body)) {} }; using ApiArgsType = std::map; template std::string getValue(Args &args, const Key &key) { auto it = args.find(key); if (it == args.end()) { return ""; } return it->second; } template std::string getValue(Json::Value &args, const Key &key) { auto value = args.find(key); if (value == nullptr) { return ""; } return value->asString(); } template std::string getValue(std::string &args, const Key &key) { return ""; } template std::string getValue(const mediakit::Parser &parser, const Key &key) { auto ret = getValue(parser.getUrlArgs(), key); if (!ret.empty()) { return ret; } return getValue(parser.getHeader(), key); } template std::string getValue(mediakit::Parser &parser, const Key &key) { return getValue((const mediakit::Parser &) parser, key); } template std::string getValue(const mediakit::Parser &parser, Args &args, const Key &key) { auto ret = getValue(args, key); if (!ret.empty()) { return ret; } return getValue(parser, key); } template class HttpAllArgs { mediakit::Parser* _parser = nullptr; Args* _args = nullptr; public: const mediakit::Parser& parser; Args& args; HttpAllArgs(const mediakit::Parser &p, Args &a): parser(p), args(a) {} HttpAllArgs(const HttpAllArgs &that): _parser(new mediakit::Parser(that.parser)), _args(new Args(that.args)), parser(*_parser), args(*_args) {} ~HttpAllArgs() { if (_parser) { delete _parser; } if (_args) { delete _args; } } template toolkit::variant operator[](const Key &key) const { return (toolkit::variant)getValue(parser, args, key); } const Args& getArgs() const { return args; } const mediakit::Parser &getParser() const { return parser; } }; using ArgsMap = HttpAllArgs; using ArgsJson = HttpAllArgs; using ArgsString = HttpAllArgs; #define API_ARGS_MAP toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const ArgsMap &allArgs, Json::Value &val #define API_ARGS_MAP_ASYNC API_ARGS_MAP, const mediakit::HttpSession::HttpResponseInvoker &invoker #define API_ARGS_JSON toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const ArgsJson &allArgs, Json::Value &val #define API_ARGS_JSON_ASYNC API_ARGS_JSON, const mediakit::HttpSession::HttpResponseInvoker &invoker #define API_ARGS_STRING toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const ArgsString &allArgs, Json::Value &val #define API_ARGS_STRING_ASYNC API_ARGS_STRING, const mediakit::HttpSession::HttpResponseInvoker &invoker #define API_ARGS_VALUE sender, headerOut, allArgs, val // 注册http请求参数是map类型的http api [AUTO-TRANSLATED:8a273897] // Register http request parameters as map type http api void api_regist(const std::string &api_path, const std::function &func); // 注册http请求参数是map类型,但是可以异步回复的的http api [AUTO-TRANSLATED:9da5d5f5] // Register http request parameters as map type, but can be replied asynchronously http api void api_regist(const std::string &api_path, const std::function &func); // 注册http请求参数是Json::Value类型的http api(可以支持多级嵌套的json参数对象) [AUTO-TRANSLATED:c4794456] // Register http request parameters as Json::Value type http api (can support multi-level nested json parameter objects) void api_regist(const std::string &api_path, const std::function &func); // 注册http请求参数是Json::Value类型,但是可以异步回复的的http api [AUTO-TRANSLATED:742e57fd] // Register http request parameters as Json::Value type, but can be replied asynchronously http api void api_regist(const std::string &api_path, const std::function &func); // 注册http请求参数是http原始请求信息的http api [AUTO-TRANSLATED:72d3fe93] // Register http request parameters as http original request information http api void api_regist(const std::string &api_path, const std::function &func); // 注册http请求参数是http原始请求信息的异步回复的http api [AUTO-TRANSLATED:49feefa8] // Register http request parameters as http original request information asynchronous reply http api void api_regist(const std::string &api_path, const std::function &func); template bool checkArgs(Args &args, const Key &key) { return !args[key].empty(); } template bool checkArgs(Args &args, const Key &key, const KeyTypes &...keys) { return checkArgs(args, key) && checkArgs(args, keys...); } // 检查http url中或body中或http header参数是否为空的宏 [AUTO-TRANSLATED:9de001a4] // Check whether the http url, body or http header parameters are empty #define CHECK_ARGS(...) \ if(!checkArgs(allArgs,##__VA_ARGS__)){ \ throw InvalidArgsException("Required parameter missed: " #__VA_ARGS__); \ } // 检查http参数中是否附带secret密钥的宏,127.0.0.1的ip不检查密钥 [AUTO-TRANSLATED:7546956c] // Check whether the http parameters contain the secret key, the ip of 127.0.0.1 does not check the key // 同时检测是否在ip白名单内 [AUTO-TRANSLATED:d12f963d] // Check whether it is in the ip whitelist at the same time template void check_secret(toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val); #define CHECK_SECRET() check_secret(sender, headerOut, allArgs, val) void installWebApi(); void unInstallWebApi(); #if defined(ENABLE_RTPPROXY) uint16_t openRtpServer(uint16_t local_port, const mediakit::MediaTuple &tuple, int tcp_mode, const std::string &local_ip, bool re_use_port, uint32_t ssrc, int only_track, bool multiplex=false); #endif Json::Value makeMediaSourceJson(mediakit::MediaSource &media); ApiArgsType getAllArgs(const mediakit::Parser &parser); void getStatisticJson(const std::function &cb); void addStreamProxy(const mediakit::MediaTuple &tuple, const std::string &url, int retry_count, bool force, const mediakit::ProtocolOption &option, float timeout_sec, const toolkit::mINI &args, const std::function &cb); void updateStreamProxy(const mediakit::MediaTuple &tuple, const std::string &url, const toolkit::mINI &args); template class ServiceController { public: using Pointer = std::shared_ptr; std::unordered_map _map; mutable std::recursive_mutex _mtx; void clear() { decltype(_map) copy; { std::lock_guard lck(_mtx); copy.swap(_map); } } size_t erase(const std::string &key) { Pointer erase_ptr; { std::lock_guard lck(_mtx); auto itr = _map.find(key); if (itr != _map.end()) { erase_ptr = std::move(itr->second); _map.erase(itr); return 1; } } return 0; } size_t size() { std::lock_guard lck(_mtx); return _map.size(); } Pointer find(const std::string &key) const { std::lock_guard lck(_mtx); auto it = _map.find(key); if (it == _map.end()) { return nullptr; } return it->second; } void for_each(const std::function &cb, const std::string &key = {}) { std::lock_guard lck(_mtx); if (key.empty()) { auto it = _map.begin(); while (it != _map.end()) { cb(it->first, it->second); ++it; } } else { auto it = _map.find(key); if (it == _map.end()) { throw std::invalid_argument("key not found: " + key); } cb(key, it->second); } } template Pointer make(const std::string &key, _Args&& ...__args) { // assert(!find(key)); auto server = std::make_shared(std::forward<_Args>(__args)...); std::lock_guard lck(_mtx); auto it = _map.emplace(key, server); assert(it.second); return server; } template Pointer makeWithAction(const std::string &key, std::function action, _Args&& ...__args) { // assert(!find(key)); auto server = std::make_shared(std::forward<_Args>(__args)...); action(server); std::lock_guard lck(_mtx); auto it = _map.emplace(key, server); assert(it.second); return server; } template Pointer emplace(const std::string &key, _Args&& ...__args) { // assert(!find(key)); auto server = std::static_pointer_cast(std::forward<_Args>(__args)...); std::lock_guard lck(_mtx); auto it = _map.emplace(key, server); assert(it.second); return server; } }; #if defined(ENABLE_WEBRTC) template class WebRtcArgsImp : public mediakit::WebRtcArgs { public: WebRtcArgsImp(const HttpAllArgs &args, std::string session_id) : _args(args) , _session_id(std::move(session_id)) {} ~WebRtcArgsImp() override = default; toolkit::variant operator[](const std::string &key) const override { if (key == "url") { return getUrl(); } return _args[key]; } private: std::string getUrl() const { auto &allArgs = _args; CHECK_ARGS("app", "stream"); return StrPrinter << RTC_SCHEMA << "://" << (_args["Host"].empty() ? DEFAULT_VHOST : _args["Host"].data()) << "/" << _args["app"] << "/" << _args["stream"] << "?" << _args.getParser().params() + "&session=" + _session_id; } private: HttpAllArgs _args; std::string _session_id; }; #endif #endif //ZLMEDIAKIT_WEBAPI_H