mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-03-18 03:50:54 +08:00
on_play鉴权回调到python层
This commit is contained in:
@@ -4,18 +4,23 @@ import mk_loader
|
||||
def on_start():
|
||||
mk_logger.log_info("on_start")
|
||||
|
||||
|
||||
def on_exit():
|
||||
mk_logger.log_info("on_exit")
|
||||
|
||||
|
||||
def on_publish(type: str, info, invoker, sender) -> bool:
|
||||
mk_logger.log_info(f"on_publish: {type}")
|
||||
def on_publish(type: str, args: dict, invoker, sender: dict) -> bool:
|
||||
mk_logger.log_info(f"on_publish, args: {type}, args: {args}, sender: {sender}")
|
||||
# opt 控制转协议,请参考配置文件[protocol]下字段
|
||||
opt = {
|
||||
"enable_rtmp": "1"
|
||||
}
|
||||
# 响应推流鉴权结果
|
||||
mk_loader.mk_publish_auth_invoker_do(invoker, "", opt);
|
||||
mk_loader.publish_auth_invoker_do(invoker, "", opt);
|
||||
# 返回True代表此事件被python拦截
|
||||
return True
|
||||
|
||||
def on_play(args: dict, invoker, sender: dict) -> bool:
|
||||
mk_logger.log_info(f"on_play, args: {args}, sender: {sender}")
|
||||
# 响应播放鉴权结果
|
||||
mk_loader.auth_invoker_do(invoker, "");
|
||||
# 返回True代表此事件被python拦截
|
||||
return True
|
||||
|
||||
@@ -345,7 +345,7 @@ static inline string getPusherKey(const string &schema, const string &vhost, con
|
||||
return schema + "/" + vhost + "/" + app + "/" + stream + "/" + MD5(dst_url).hexdigest();
|
||||
}
|
||||
|
||||
static void fillSockInfo(Value& val, SockInfo* info) {
|
||||
void fillSockInfo(Value& val, SockInfo* info) {
|
||||
val["peer_ip"] = info->get_peer_ip();
|
||||
val["peer_port"] = info->get_peer_port();
|
||||
val["local_port"] = info->get_local_port();
|
||||
|
||||
@@ -230,7 +230,7 @@ void do_http_hook(const string &url, const ArgsType &body, const function<void(c
|
||||
|
||||
void dumpMediaTuple(const MediaTuple &tuple, Json::Value& item);
|
||||
|
||||
static ArgsType make_json(const MediaInfo &args) {
|
||||
ArgsType make_json(const MediaInfo &args) {
|
||||
ArgsType body;
|
||||
body["schema"] = args.schema;
|
||||
if(!args.protocol.empty()){
|
||||
@@ -397,6 +397,11 @@ void installWebHook() {
|
||||
});
|
||||
|
||||
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastMediaPlayed, [](BroadcastMediaPlayedArgs) {
|
||||
#if defined(ENABLE_PYTHON)
|
||||
if (PythonInvoker::Instance().on_play(args, invoker, sender)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GET_CONFIG(string, hook_play, Hook::kOnPlay);
|
||||
if (!hook_enable || hook_play.empty()) {
|
||||
invoker("");
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#if defined(ENABLE_PYTHON)
|
||||
|
||||
#include "pyinvoker.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include "WebHook.h"
|
||||
|
||||
using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
template <typename T>
|
||||
auto to_python(const T &obj) -> typename std::enable_if<std::is_copy_constructible<T>::value, py::capsule>::type {
|
||||
typename std::enable_if<std::is_copy_constructible<T>::value, py::capsule>::type to_python(const T &obj) {
|
||||
static auto name_str = toolkit::demangle(typeid(T).name());
|
||||
auto p = new toolkit::Any(std::make_shared<T>(obj));
|
||||
return py::capsule(p, name_str.data(), [](PyObject *capsule) {
|
||||
@@ -22,7 +24,7 @@ auto to_python(const T &obj) -> typename std::enable_if<std::is_copy_constructib
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto to_python(const T &obj) -> typename std::enable_if<!std::is_copy_constructible<T>::value, py::capsule>::type {
|
||||
typename std::enable_if<!std::is_copy_constructible<T>::value, py::capsule>::type to_python(const T &obj) {
|
||||
static auto name_str = toolkit::demangle(typeid(T).name());
|
||||
auto p = new toolkit::Any(std::shared_ptr<T>(const_cast<T *>(&obj), [](T *) {}));
|
||||
return py::capsule(p, name_str.data(), [](PyObject *capsule) {
|
||||
@@ -32,6 +34,39 @@ auto to_python(const T &obj) -> typename std::enable_if<!std::is_copy_constructi
|
||||
});
|
||||
}
|
||||
|
||||
extern ArgsType make_json(const MediaInfo &args);
|
||||
extern void fillSockInfo(Json::Value & val, SockInfo* info);
|
||||
|
||||
static py::dict jsonToPython(const Json::Value &obj) {
|
||||
py::dict ret;
|
||||
if (obj.isObject()) {
|
||||
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
||||
if (it->isNull()) {
|
||||
// 忽略null,修复wvp传null覆盖Protocol配置的问题
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
auto str = (*it).asString();
|
||||
ret[it.name().data()] = std::move(str);
|
||||
} catch (std::exception &) {
|
||||
WarnL << "Json is not convertible to string, key: " << it.name() << ", value: " << (*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
py::dict to_python(const MediaInfo &args) {
|
||||
auto json = make_json(args);
|
||||
return jsonToPython(json);
|
||||
}
|
||||
|
||||
py::dict to_python(const SockInfo &info) {
|
||||
Json::Value json;
|
||||
fillSockInfo(json, const_cast<SockInfo *>(&info));
|
||||
return jsonToPython(json);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T &to_native(const py::capsule &cap) {
|
||||
static auto name_str = toolkit::demangle(typeid(T).name());
|
||||
@@ -56,7 +91,7 @@ PYBIND11_EMBEDDED_MODULE(mk_loader, m) {
|
||||
py::gil_scoped_release release;
|
||||
LoggerWrapper::printLog(::toolkit::getLogger(), lev, file, func, line, content);
|
||||
});
|
||||
m.def("mk_publish_auth_invoker_do", [](const py::capsule &cap, const std::string &err, const py::dict &opt) {
|
||||
m.def("publish_auth_invoker_do", [](const py::capsule &cap, const std::string &err, const py::dict &opt) {
|
||||
ProtocolOption option;
|
||||
option.load(to_native(opt));
|
||||
// 执行c++代码时释放gil锁
|
||||
@@ -64,6 +99,12 @@ PYBIND11_EMBEDDED_MODULE(mk_loader, m) {
|
||||
auto &invoker = to_native<Broadcast::PublishAuthInvoker>(cap);
|
||||
invoker(err, option);
|
||||
});
|
||||
m.def("auth_invoker_do", [](const py::capsule &cap, const std::string &err) {
|
||||
// 执行c++代码时释放gil锁
|
||||
py::gil_scoped_release release;
|
||||
auto &invoker = to_native<Broadcast::AuthInvoker>(cap);
|
||||
invoker(err);
|
||||
});
|
||||
}
|
||||
|
||||
namespace mediakit {
|
||||
@@ -137,6 +178,9 @@ void PythonInvoker::load(const std::string &module_name) {
|
||||
if (hasattr(_module, "on_publish")) {
|
||||
_on_publish = _module.attr("on_publish");
|
||||
}
|
||||
if (hasattr(_module, "on_play")) {
|
||||
_on_play = _module.attr("on_play");
|
||||
}
|
||||
} catch (py::error_already_set &e) {
|
||||
PrintE("Python exception:%s", e.what());
|
||||
}
|
||||
@@ -150,6 +194,14 @@ bool PythonInvoker::on_publish(BroadcastMediaPublishArgs) {
|
||||
return _on_publish(getOriginTypeString(type), to_python(args), to_python(invoker), to_python(sender)).cast<bool>();
|
||||
}
|
||||
|
||||
bool PythonInvoker::on_play(BroadcastMediaPlayedArgs) {
|
||||
py::gil_scoped_acquire gil; // 确保在 Python 调用期间持有 GIL
|
||||
if (!_on_play) {
|
||||
return false;
|
||||
}
|
||||
return _on_play(to_python(args), to_python(invoker), to_python(sender)).cast<bool>();
|
||||
}
|
||||
|
||||
} // namespace mediakit
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
|
||||
void load(const std::string &module_name);
|
||||
bool on_publish(BroadcastMediaPublishArgs);
|
||||
bool on_play(BroadcastMediaPlayedArgs);
|
||||
|
||||
private:
|
||||
PythonInvoker();
|
||||
@@ -38,6 +39,8 @@ private:
|
||||
py::object _on_exit;
|
||||
// 推流鉴权
|
||||
py::object _on_publish;
|
||||
// 播放鉴权
|
||||
py::object _on_play;
|
||||
};
|
||||
|
||||
} // namespace mediakit
|
||||
|
||||
Reference in New Issue
Block a user