mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-02-15 04:40:52 +08:00
合并pr:#1025
This commit is contained in:
@@ -90,7 +90,7 @@ static HttpApi toApi(const function<void(API_ARGS_MAP_ASYNC)> &cb) {
|
||||
|
||||
//参数解析成map
|
||||
auto args = getAllArgs(parser);
|
||||
cb(sender, parser.getHeader(), headerOut, args, val, invoker);
|
||||
cb(sender, headerOut, HttpAllArgs<decltype(args)>(parser, args), val, invoker);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -107,26 +107,24 @@ static HttpApi toApi(const function<void(API_ARGS_JSON_ASYNC)> &cb) {
|
||||
HttpSession::KeyValue headerOut;
|
||||
headerOut["Content-Type"] = string("application/json; charset=") + charSet;
|
||||
|
||||
Json::Value out;
|
||||
out["code"] = API::Success;
|
||||
Json::Value val;
|
||||
val["code"] = API::Success;
|
||||
|
||||
if (parser["Content-Type"].find("application/json") == string::npos) {
|
||||
throw InvalidArgsException("该接口只支持json格式的请求");
|
||||
}
|
||||
//参数解析成json对象然后处理
|
||||
Json::Value in;
|
||||
Json::Value args;
|
||||
Json::Reader reader;
|
||||
reader.parse(parser.Content(), in);
|
||||
reader.parse(parser.Content(), args);
|
||||
|
||||
//参数解析成map
|
||||
auto urlArgs = getAllArgs(parser);
|
||||
cb(sender, parser.getHeader(), headerOut, in, urlArgs, out, invoker);
|
||||
cb(sender, headerOut, HttpAllArgs<decltype(args)>(parser, args), val, invoker);
|
||||
};
|
||||
}
|
||||
|
||||
static HttpApi toApi(const function<void(API_ARGS_JSON)> &cb) {
|
||||
return toApi([cb](API_ARGS_JSON_ASYNC) {
|
||||
cb(API_ARGS_JSON_VALUE);
|
||||
cb(API_ARGS_VALUE);
|
||||
invoker(200, headerOut, val.toStyledString());
|
||||
});
|
||||
}
|
||||
@@ -140,7 +138,7 @@ static HttpApi toApi(const function<void(API_ARGS_STRING_ASYNC)> &cb) {
|
||||
Json::Value val;
|
||||
val["code"] = API::Success;
|
||||
|
||||
cb(sender, parser.getHeader(), headerOut, parser, val, invoker);
|
||||
cb(sender, headerOut, HttpAllArgs<string>(parser, (string &)parser.Content()), val, invoker);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -230,19 +228,18 @@ static inline void addHttpListener(){
|
||||
size = body->remainSize();
|
||||
}
|
||||
|
||||
const std::string& content = parser.Content();
|
||||
if (size && size < 4 * 1024) {
|
||||
string contentOut = body->readData(size)->toString();
|
||||
DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
|
||||
<< "# content:\r\n" << (content.size() > 4 * 1024 ? content.substr(0, 4 * 1024) : content) << "\r\n"
|
||||
<< "# response:\r\n"
|
||||
<< contentOut << "\r\n";
|
||||
<< "# content:\r\n" << parser.Content() << "\r\n"
|
||||
<< "# response:\r\n"
|
||||
<< contentOut << "\r\n";
|
||||
invoker(code, headerOut, contentOut);
|
||||
} else {
|
||||
DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
|
||||
<< "# content:\r\n" << (content.size() > 4 * 1024 ? content.substr(0, 4 * 1024) : content) << "\r\n"
|
||||
<< "# response size:"
|
||||
<< size << "\r\n";
|
||||
<< "# content:\r\n" << parser.Content() << "\r\n"
|
||||
<< "# response size:"
|
||||
<< size << "\r\n";
|
||||
invoker(code, headerOut, body);
|
||||
}
|
||||
};
|
||||
@@ -279,8 +276,8 @@ static recursive_mutex s_ffmpegMapMtx;
|
||||
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
//rtp服务器列表
|
||||
/*static*/ unordered_map<string, RtpServer::Ptr> s_rtpServerMap;
|
||||
/*static*/ recursive_mutex s_rtpServerMapMtx;
|
||||
static unordered_map<string, RtpServer::Ptr> s_rtpServerMap;
|
||||
static recursive_mutex s_rtpServerMapMtx;
|
||||
#endif
|
||||
|
||||
static inline string getProxyKey(const string &vhost, const string &app, const string &stream) {
|
||||
@@ -412,7 +409,7 @@ void installWebApi() {
|
||||
CHECK_SECRET();
|
||||
auto &ini = mINI::Instance();
|
||||
int changed = API::Success;
|
||||
for (auto &pr : allArgs) {
|
||||
for (auto &pr : allArgs.getArgs()) {
|
||||
if (ini.find(pr.first) == ini.end()) {
|
||||
#if 1
|
||||
//没有这个key
|
||||
@@ -564,7 +561,7 @@ void installWebApi() {
|
||||
CHECK_SECRET();
|
||||
Value jsession;
|
||||
uint16_t local_port = allArgs["local_port"].as<uint16_t>();
|
||||
string &peer_ip = allArgs["peer_ip"];
|
||||
string peer_ip = allArgs["peer_ip"];
|
||||
|
||||
SessionMap::Instance().for_each_session([&](const string &id,const Session::Ptr &session){
|
||||
if(local_port != 0 && local_port != session->get_local_port()){
|
||||
@@ -602,7 +599,7 @@ void installWebApi() {
|
||||
api_regist("/index/api/kick_sessions",[](API_ARGS_MAP){
|
||||
CHECK_SECRET();
|
||||
uint16_t local_port = allArgs["local_port"].as<uint16_t>();
|
||||
string &peer_ip = allArgs["peer_ip"];
|
||||
string peer_ip = allArgs["peer_ip"];
|
||||
size_t count_hit = 0;
|
||||
|
||||
list<Session::Ptr> session_list;
|
||||
@@ -859,7 +856,7 @@ void installWebApi() {
|
||||
//测试url http://127.0.0.1/index/api/downloadBin
|
||||
api_regist("/index/api/downloadBin",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
invoker.responseFile(headerIn,StrCaseMap(),exePath());
|
||||
invoker.responseFile(allArgs.getParser().getHeader(),StrCaseMap(),exePath());
|
||||
});
|
||||
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
@@ -935,56 +932,21 @@ void installWebApi() {
|
||||
api_regist("/index/api/startSendRtp",[](API_ARGS_MAP_ASYNC){
|
||||
CHECK_SECRET();
|
||||
CHECK_ARGS("vhost", "app", "stream", "ssrc", "dst_url", "dst_port", "is_udp");
|
||||
bool isAsync = false;
|
||||
if (checkArgs(allArgs, "is_async"))
|
||||
isAsync = allArgs["is_async"];
|
||||
if (isAsync)
|
||||
{
|
||||
MediaInfo info = {};
|
||||
info._vhost = allArgs["vhost"];
|
||||
info._app = allArgs["app"];
|
||||
info._streamid = allArgs["stream"];
|
||||
info._schema = RTSP_SCHEMA;
|
||||
auto session = static_cast<TcpSession*>(&sender);
|
||||
auto session_ptr = session->shared_from_this();
|
||||
|
||||
MediaSource::findAsync(info, session_ptr, [=](const MediaSource::Ptr& src_in) mutable {
|
||||
if (!src_in) {
|
||||
val["code"] = API::OtherFailed;
|
||||
val["msg"] = "该媒体流不存在";
|
||||
invoker(200, headerOut, val.toStyledString());
|
||||
return;
|
||||
}
|
||||
auto src = dynamic_pointer_cast<RtspMediaSource>(src_in);
|
||||
//src_port为空时,则随机本地端口
|
||||
src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException& ex) mutable {
|
||||
if (ex) {
|
||||
val["code"] = API::OtherFailed;
|
||||
val["msg"] = ex.what();
|
||||
}
|
||||
val["local_port"] = local_port;
|
||||
invoker(200, headerOut, val.toStyledString());
|
||||
});
|
||||
});
|
||||
auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]);
|
||||
if (!src) {
|
||||
throw ApiRetException("该媒体流不存在", API::OtherFailed);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]);
|
||||
if (!src) {
|
||||
throw ApiRetException("该媒体流不存在", API::OtherFailed);
|
||||
|
||||
//src_port为空时,则随机本地端口
|
||||
src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException &ex) mutable{
|
||||
if (ex) {
|
||||
val["code"] = API::OtherFailed;
|
||||
val["msg"] = ex.what();
|
||||
}
|
||||
|
||||
//src_port为空时,则随机本地端口
|
||||
src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException& ex) mutable {
|
||||
if (ex) {
|
||||
val["code"] = API::OtherFailed;
|
||||
val["msg"] = ex.what();
|
||||
}
|
||||
val["local_port"] = local_port;
|
||||
invoker(200, headerOut, val.toStyledString());
|
||||
});
|
||||
}
|
||||
|
||||
val["local_port"] = local_port;
|
||||
invoker(200, headerOut, val.toStyledString());
|
||||
});
|
||||
});
|
||||
|
||||
api_regist("/index/api/stopSendRtp",[](API_ARGS_MAP){
|
||||
@@ -1149,7 +1111,7 @@ void installWebApi() {
|
||||
|
||||
//截图存在,且未过期,那么返回之
|
||||
res_old_snap = true;
|
||||
responseSnap(path, headerIn, invoker);
|
||||
responseSnap(path, allArgs.getParser().getHeader(), invoker);
|
||||
//中断遍历
|
||||
return false;
|
||||
});
|
||||
@@ -1171,7 +1133,7 @@ void installWebApi() {
|
||||
|
||||
//启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件
|
||||
auto new_snap_tmp = new_snap + ".tmp";
|
||||
FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, headerIn, new_snap, new_snap_tmp](bool success) {
|
||||
FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success) {
|
||||
if (!success) {
|
||||
//生成截图失败,可能残留空文件
|
||||
File::delete_file(new_snap_tmp.data());
|
||||
@@ -1180,7 +1142,7 @@ void installWebApi() {
|
||||
File::delete_file(new_snap.data());
|
||||
rename(new_snap_tmp.data(), new_snap.data());
|
||||
}
|
||||
responseSnap(new_snap, headerIn, invoker);
|
||||
responseSnap(new_snap, allArgs.getParser().getHeader(), invoker);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1217,9 +1179,9 @@ void installWebApi() {
|
||||
api_regist("/index/api/webrtc",[](API_ARGS_STRING_ASYNC){
|
||||
CHECK_ARGS("app", "stream");
|
||||
|
||||
auto offer_sdp = allArgs.Content();
|
||||
auto type = allArgs.getUrlArgs()["type"];
|
||||
MediaInfo info(StrPrinter << "rtc://" << headerIn["Host"] << "/" << allArgs.getUrlArgs()["app"] << "/" << allArgs.getUrlArgs()["stream"] << "?" << allArgs.Params());
|
||||
auto offer_sdp = allArgs.getArgs();
|
||||
auto type = allArgs["type"];
|
||||
MediaInfo info(StrPrinter << "rtc://" << allArgs["Host"] << "/" << allArgs["app"] << "/" << allArgs["stream"] << "?" << allArgs.getParser().Params());
|
||||
|
||||
//设置返回类型
|
||||
headerOut["Content-Type"] = HttpFileManager::getContentType(".json");
|
||||
|
||||
131
server/WebApi.h
131
server/WebApi.h
@@ -79,16 +79,117 @@ public:
|
||||
~SuccessException() = default;
|
||||
};
|
||||
|
||||
using ApiArgsType = map<string, variant, StrCaseCompare>;
|
||||
using ApiArgsType = map<string, string, StrCaseCompare>;
|
||||
|
||||
#define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, ApiArgsType &allArgs, Json::Value &val
|
||||
template<typename Args, typename First>
|
||||
string getValue(Args &args, const First &first) {
|
||||
return args[first];
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
string getValue(Json::Value &args, const First &first) {
|
||||
return args[first].asString();
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
string getValue(string &args, const First &first) {
|
||||
return "";
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
string getValue(const Parser &parser, const First &first) {
|
||||
auto ret = parser.getUrlArgs()[first];
|
||||
if (!ret.empty()) {
|
||||
return ret;
|
||||
}
|
||||
return parser.getHeader()[first];
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
string getValue(Parser &parser, const First &first) {
|
||||
return getValue((const Parser &) parser, first);
|
||||
}
|
||||
|
||||
template<typename Args, typename First>
|
||||
string getValue(const Parser &parser, Args &args, const First &first) {
|
||||
auto ret = getValue(args, first);
|
||||
if (!ret.empty()) {
|
||||
return ret;
|
||||
}
|
||||
return getValue(parser, first);
|
||||
}
|
||||
|
||||
template<typename Args>
|
||||
class HttpAllArgs {
|
||||
public:
|
||||
HttpAllArgs(const Parser &parser, Args &args) {
|
||||
_get_args = [&args]() {
|
||||
return (void *) &args;
|
||||
};
|
||||
_get_parser = [&parser]() -> const Parser & {
|
||||
return parser;
|
||||
};
|
||||
_get_value = [](HttpAllArgs &that, const string &key) {
|
||||
return getValue(that.getParser(), that.getArgs(), key);
|
||||
};
|
||||
_clone = [&](HttpAllArgs &that) {
|
||||
that._get_args = [args]() {
|
||||
return (void *) &args;
|
||||
};
|
||||
that._get_parser = [parser]() -> const Parser & {
|
||||
return parser;
|
||||
};
|
||||
that._get_value = [](HttpAllArgs &that, const string &key) {
|
||||
return getValue(that.getParser(), that.getArgs(), key);
|
||||
};
|
||||
that._cache_able = true;
|
||||
};
|
||||
}
|
||||
|
||||
HttpAllArgs(const HttpAllArgs &that) {
|
||||
if (that._cache_able) {
|
||||
_get_args = that._get_args;
|
||||
_get_parser = that._get_parser;
|
||||
_get_value = that._get_value;
|
||||
} else {
|
||||
that._clone(*this);
|
||||
}
|
||||
}
|
||||
|
||||
~HttpAllArgs() = default;
|
||||
|
||||
template<typename Key>
|
||||
variant operator[](const Key &key) const {
|
||||
return (variant)_get_value(*(HttpAllArgs*)this, key);
|
||||
}
|
||||
|
||||
const Parser &getParser() const {
|
||||
return _get_parser();
|
||||
}
|
||||
|
||||
Args &getArgs() {
|
||||
return *((Args *) _get_args());
|
||||
}
|
||||
|
||||
const Args &getArgs() const {
|
||||
return *((Args *) _get_args());
|
||||
}
|
||||
|
||||
private:
|
||||
bool _cache_able = false;
|
||||
function<void *() > _get_args;
|
||||
function<const Parser &() > _get_parser;
|
||||
function<string(HttpAllArgs &that, const string &key)> _get_value;
|
||||
function<void(HttpAllArgs &that) > _clone;
|
||||
};
|
||||
|
||||
#define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerOut, const HttpAllArgs<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 &bodyArgs, ApiArgsType &allArgs, Json::Value &val
|
||||
#define API_ARGS_JSON SockInfo &sender, HttpSession::KeyValue &headerOut, const HttpAllArgs<Json::Value> &allArgs, Json::Value &val
|
||||
#define API_ARGS_JSON_ASYNC API_ARGS_JSON, const HttpSession::HttpResponseInvoker &invoker
|
||||
#define API_ARGS_STRING SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, const Parser &allArgs, Json::Value &val
|
||||
#define API_ARGS_STRING SockInfo &sender, HttpSession::KeyValue &headerOut, const HttpAllArgs<string> &allArgs, Json::Value &val
|
||||
#define API_ARGS_STRING_ASYNC API_ARGS_STRING, const HttpSession::HttpResponseInvoker &invoker
|
||||
#define API_ARGS_VALUE sender, headerIn, headerOut, allArgs, val
|
||||
#define API_ARGS_JSON_VALUE sender, headerIn, headerOut, bodyArgs, allArgs, val
|
||||
#define API_ARGS_VALUE sender, headerOut, allArgs, val
|
||||
|
||||
//注册http请求参数是map<string, variant, StrCaseCompare>类型的http api
|
||||
void api_regist(const string &api_path, const function<void(API_ARGS_MAP)> &func);
|
||||
@@ -106,26 +207,16 @@ void api_regist(const string &api_path, const function<void(API_ARGS_STRING)> &f
|
||||
void api_regist(const string &api_path, const function<void(API_ARGS_STRING_ASYNC)> &func);
|
||||
|
||||
template<typename Args, typename First>
|
||||
bool checkArgs(Args &&args, First &&first) {
|
||||
bool checkArgs(Args &args, const First &first) {
|
||||
return !args[first].empty();
|
||||
}
|
||||
|
||||
template<typename Args, typename First, typename ...KeyTypes>
|
||||
bool checkArgs(Args &&args, First &&first, KeyTypes &&...keys) {
|
||||
return !args[first].empty() && checkArgs(std::forward<Args>(args), std::forward<KeyTypes>(keys)...);
|
||||
bool checkArgs(Args &args, const First &first, const KeyTypes &...keys) {
|
||||
return checkArgs(args, first) && checkArgs(args, keys...);
|
||||
}
|
||||
|
||||
template<typename First>
|
||||
bool checkArgs(const Parser &args, First &&first) {
|
||||
return !args.getUrlArgs()[first].empty();
|
||||
}
|
||||
|
||||
template<typename First, typename ...KeyTypes>
|
||||
bool checkArgs(const Parser &args, First &&first, KeyTypes &&...keys) {
|
||||
return !args.getUrlArgs()[first].empty() && checkArgs(args, std::forward<KeyTypes>(keys)...);
|
||||
}
|
||||
|
||||
//检查http参数是否为空的宏
|
||||
//检查http url中或body中或http header参数是否为空的宏
|
||||
#define CHECK_ARGS(...) \
|
||||
if(!checkArgs(allArgs,##__VA_ARGS__)){ \
|
||||
throw InvalidArgsException("缺少必要参数:" #__VA_ARGS__); \
|
||||
|
||||
Reference in New Issue
Block a user