mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
fix #274: http-callback support on_dvr when reap a dvr file. 2.0.89
This commit is contained in:
parent
dd2c7e0b4d
commit
dc11418c79
12 changed files with 207 additions and 7 deletions
|
@ -501,6 +501,7 @@ Supported operating systems and hardware:
|
||||||
* 2013-10-17, Created.<br/>
|
* 2013-10-17, Created.<br/>
|
||||||
|
|
||||||
## History
|
## History
|
||||||
|
* v2.0, 2015-01-03, fix [#274](https://github.com/winlinvip/simple-rtmp-server/issues/274), http-callback support on_dvr when reap a dvr file. 2.0.89
|
||||||
* v2.0, 2015-01-03, hotfix to remove the pageUrl for http callback. 2.0.88
|
* v2.0, 2015-01-03, hotfix to remove the pageUrl for http callback. 2.0.88
|
||||||
* v2.0, 2015-01-03, fix [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), dvr support custom filepath by variables. 2.0.87
|
* v2.0, 2015-01-03, fix [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), dvr support custom filepath by variables. 2.0.87
|
||||||
* v2.0, 2015-01-02, fix [#211](https://github.com/winlinvip/simple-rtmp-server/issues/211), support security allow/deny publish/play all/ip. 2.0.86
|
* v2.0, 2015-01-02, fix [#211](https://github.com/winlinvip/simple-rtmp-server/issues/211), support security allow/deny publish/play all/ip. 2.0.86
|
||||||
|
|
|
@ -296,6 +296,11 @@ vhost dvr.srs.com {
|
||||||
# 3. off, disable the time jitter algorithm, like atc.
|
# 3. off, disable the time jitter algorithm, like atc.
|
||||||
# default: full
|
# default: full
|
||||||
time_jitter full;
|
time_jitter full;
|
||||||
|
|
||||||
|
# on_dvr
|
||||||
|
# for the dvr http callback, @see http_hooks.on_dvr of vhost hooks.callback.srs.com
|
||||||
|
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#http-callback
|
||||||
|
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#http-callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +343,7 @@ vhost ingest.srs.com {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# vhost for http
|
# vhost for http server config in each vhost.
|
||||||
vhost http.srs.com {
|
vhost http.srs.com {
|
||||||
# http vhost specified config
|
# http vhost specified config
|
||||||
http {
|
http {
|
||||||
|
@ -490,6 +495,20 @@ vhost hooks.callback.srs.com {
|
||||||
# support multiple api hooks, format:
|
# support multiple api hooks, format:
|
||||||
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
||||||
on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
|
on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
|
||||||
|
# when srs reap a dvr file, call the hook,
|
||||||
|
# the request in the POST data string is a object encode by json:
|
||||||
|
# {
|
||||||
|
# "action": "on_dvr",
|
||||||
|
# "client_id": 1985,
|
||||||
|
# "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
||||||
|
# "stream": "livestream",
|
||||||
|
# "cwd": "/usr/local/srs",
|
||||||
|
# "file": "./objs/nginx/html/live/livestream.1420254068776.flv"
|
||||||
|
# }
|
||||||
|
# if valid, the hook must return HTTP code 200(Stauts OK) and response
|
||||||
|
# an int value specifies the error code(0 corresponding to success):
|
||||||
|
# 0
|
||||||
|
on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ class RESTClients(object):
|
||||||
return code
|
return code
|
||||||
|
|
||||||
'''
|
'''
|
||||||
handle the streams requests: publish/unpublish/dvr stream.
|
handle the streams requests: publish/unpublish stream.
|
||||||
'''
|
'''
|
||||||
class RESTStreams(object):
|
class RESTStreams(object):
|
||||||
exposed = True
|
exposed = True
|
||||||
|
@ -240,6 +240,74 @@ class RESTStreams(object):
|
||||||
|
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
'''
|
||||||
|
handle the dvrs requests: dvr stream.
|
||||||
|
'''
|
||||||
|
class RESTDvrs(object):
|
||||||
|
exposed = True
|
||||||
|
|
||||||
|
def GET(self):
|
||||||
|
enable_crossdomain()
|
||||||
|
|
||||||
|
dvrs = {}
|
||||||
|
return json.dumps(dvrs)
|
||||||
|
|
||||||
|
'''
|
||||||
|
for SRS hook: on_dvr
|
||||||
|
on_dvr:
|
||||||
|
when srs reap a dvr file, call the hook,
|
||||||
|
the request in the POST data string is a object encode by json:
|
||||||
|
{
|
||||||
|
"action": "on_dvr",
|
||||||
|
"client_id": 1985,
|
||||||
|
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
||||||
|
"stream": "livestream",
|
||||||
|
"cwd": "/usr/local/srs",
|
||||||
|
"file": "./objs/nginx/html/live/livestream.1420254068776.flv"
|
||||||
|
}
|
||||||
|
if valid, the hook must return HTTP code 200(Stauts OK) and response
|
||||||
|
an int value specifies the error code(0 corresponding to success):
|
||||||
|
0
|
||||||
|
'''
|
||||||
|
def POST(self):
|
||||||
|
enable_crossdomain()
|
||||||
|
|
||||||
|
# return the error code in str
|
||||||
|
code = Error.success
|
||||||
|
|
||||||
|
req = cherrypy.request.body.read()
|
||||||
|
trace("post to dvrs, req=%s"%(req))
|
||||||
|
try:
|
||||||
|
json_req = json.loads(req)
|
||||||
|
except Exception, ex:
|
||||||
|
code = Error.system_parse_json
|
||||||
|
trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
|
||||||
|
return str(code)
|
||||||
|
|
||||||
|
action = json_req["action"]
|
||||||
|
if action == "on_dvr":
|
||||||
|
code = self.__on_dvr(json_req)
|
||||||
|
else:
|
||||||
|
trace("invalid request action: %s"%(json_req["action"]))
|
||||||
|
code = Error.request_invalid_action
|
||||||
|
|
||||||
|
return str(code)
|
||||||
|
|
||||||
|
def OPTIONS(self, *args, **kwargs):
|
||||||
|
enable_crossdomain()
|
||||||
|
|
||||||
|
def __on_dvr(self, req):
|
||||||
|
code = Error.success
|
||||||
|
|
||||||
|
trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
|
||||||
|
req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"],
|
||||||
|
req["cwd"], req["file"]
|
||||||
|
))
|
||||||
|
|
||||||
|
# TODO: process the on_dvr event
|
||||||
|
|
||||||
|
return code
|
||||||
|
|
||||||
'''
|
'''
|
||||||
handle the sessions requests: client play/stop stream
|
handle the sessions requests: client play/stop stream
|
||||||
'''
|
'''
|
||||||
|
@ -1039,6 +1107,7 @@ class V1(object):
|
||||||
self.clients = RESTClients()
|
self.clients = RESTClients()
|
||||||
self.streams = RESTStreams()
|
self.streams = RESTStreams()
|
||||||
self.sessions = RESTSessions()
|
self.sessions = RESTSessions()
|
||||||
|
self.dvrs = RESTDvrs()
|
||||||
self.chats = RESTChats()
|
self.chats = RESTChats()
|
||||||
self.servers = RESTServers()
|
self.servers = RESTServers()
|
||||||
self.nodes = RESTNodes()
|
self.nodes = RESTNodes()
|
||||||
|
@ -1048,6 +1117,7 @@ class V1(object):
|
||||||
"clients": "for srs http callback, to handle the clients requests: connect/disconnect vhost/app.",
|
"clients": "for srs http callback, to handle the clients requests: connect/disconnect vhost/app.",
|
||||||
"streams": "for srs http callback, to handle the streams requests: publish/unpublish stream.",
|
"streams": "for srs http callback, to handle the streams requests: publish/unpublish stream.",
|
||||||
"sessions": "for srs http callback, to handle the sessions requests: client play/stop stream",
|
"sessions": "for srs http callback, to handle the sessions requests: client play/stop stream",
|
||||||
|
"dvrs": "for srs http callback, to handle the dvr requests: dvr stream.",
|
||||||
"chats": "for srs demo meeting, the chat streams, public chat room.",
|
"chats": "for srs demo meeting, the chat streams, public chat room.",
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"summary": "for srs cdn node",
|
"summary": "for srs cdn node",
|
||||||
|
|
|
@ -1426,6 +1426,7 @@ int SrsConfig::check_config()
|
||||||
string m = conf->at(j)->name.c_str();
|
string m = conf->at(j)->name.c_str();
|
||||||
if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
|
if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
|
||||||
&& m != "on_unpublish" && m != "on_play" && m != "on_stop"
|
&& m != "on_unpublish" && m != "on_play" && m != "on_stop"
|
||||||
|
&& m != "on_dvr"
|
||||||
) {
|
) {
|
||||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||||
srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
|
srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
|
||||||
|
@ -2335,6 +2336,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
|
||||||
return conf->get("on_stop");
|
return conf->get("on_stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
|
||||||
|
{
|
||||||
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
|
|
||||||
|
if (!conf) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf->get("on_dvr");
|
||||||
|
}
|
||||||
|
|
||||||
bool SrsConfig::get_bw_check_enabled(string vhost)
|
bool SrsConfig::get_bw_check_enabled(string vhost)
|
||||||
{
|
{
|
||||||
SrsConfDirective* conf = get_vhost(vhost);
|
SrsConfDirective* conf = get_vhost(vhost);
|
||||||
|
|
|
@ -610,6 +610,11 @@ public:
|
||||||
* @return the on_stop callback directive, the args is the url to callback.
|
* @return the on_stop callback directive, the args is the url to callback.
|
||||||
*/
|
*/
|
||||||
virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
|
virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
|
||||||
|
/**
|
||||||
|
* get the on_dvr callbacks of vhost.
|
||||||
|
* @return the on_dvr callback directive, the args is the url to callback.
|
||||||
|
*/
|
||||||
|
virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost);
|
||||||
// bwct(bandwidth check tool) section
|
// bwct(bandwidth check tool) section
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -404,6 +404,30 @@ int SrsDvrPlan::flv_close()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||||
|
SrsRequest* req = _req;
|
||||||
|
if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
|
||||||
|
// HTTP: on_dvr
|
||||||
|
SrsConfDirective* on_dvr = _srs_config->get_vhost_on_dvr(req->vhost);
|
||||||
|
if (!on_dvr) {
|
||||||
|
srs_info("ignore the empty http callback: on_dvr");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connection_id = _srs_context->get_id();
|
||||||
|
std::string ip = req->ip;
|
||||||
|
std::string cwd = _srs_config->cwd();
|
||||||
|
std::string file = segment->path;
|
||||||
|
for (int i = 0; i < (int)on_dvr->args.size(); i++) {
|
||||||
|
std::string url = on_dvr->args.at(i);
|
||||||
|
if ((ret = SrsHttpHooks::on_dvr(url, connection_id, ip, req, cwd, file)) != ERROR_SUCCESS) {
|
||||||
|
srs_error("hook client on_dvr failed. url=%s, ret=%d", url.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -379,5 +379,61 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, string cwd, string file)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsHttpUri uri;
|
||||||
|
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||||
|
srs_error("http uri parse on_dvr url failed, ignored. "
|
||||||
|
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << __SRS_JOBJECT_START
|
||||||
|
<< __SRS_JFIELD_STR("action", "on_dvr") << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT
|
||||||
|
<< __SRS_JFIELD_STR("file", file)
|
||||||
|
<< __SRS_JOBJECT_END;
|
||||||
|
std::string data = ss.str();
|
||||||
|
std::string res;
|
||||||
|
int status_code;
|
||||||
|
|
||||||
|
SrsHttpClient http;
|
||||||
|
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
|
||||||
|
srs_error("http post on_dvr uri failed, ignored. "
|
||||||
|
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||||
|
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the http status is ok.
|
||||||
|
// https://github.com/winlinvip/simple-rtmp-server/issues/158
|
||||||
|
if (status_code != SRS_CONSTS_HTTP_OK) {
|
||||||
|
ret = ERROR_HTTP_STATUS_INVLIAD;
|
||||||
|
srs_error("http hook on_dvr status failed. "
|
||||||
|
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||||
|
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||||
|
srs_warn("http hook on_dvr validate failed, ignored. "
|
||||||
|
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_trace("http hook on_dvr success. "
|
||||||
|
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||||
|
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -58,7 +58,6 @@ public:
|
||||||
* @param client_id the id of client on server.
|
* @param client_id the id of client on server.
|
||||||
* @param url the api server url, to valid the client.
|
* @param url the api server url, to valid the client.
|
||||||
* ignore if empty.
|
* ignore if empty.
|
||||||
* @return valid failed or connect to the url failed.
|
|
||||||
*/
|
*/
|
||||||
static int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req);
|
static int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req);
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +72,6 @@ public:
|
||||||
* @param client_id the id of client on server.
|
* @param client_id the id of client on server.
|
||||||
* @param url the api server url, to valid the client.
|
* @param url the api server url, to valid the client.
|
||||||
* ignore if empty.
|
* ignore if empty.
|
||||||
* @return valid failed or connect to the url failed.
|
|
||||||
*/
|
*/
|
||||||
static int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req);
|
static int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req);
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +86,6 @@ public:
|
||||||
* @param client_id the id of client on server.
|
* @param client_id the id of client on server.
|
||||||
* @param url the api server url, to valid the client.
|
* @param url the api server url, to valid the client.
|
||||||
* ignore if empty.
|
* ignore if empty.
|
||||||
* @return valid failed or connect to the url failed.
|
|
||||||
*/
|
*/
|
||||||
static int on_play(std::string url, int client_id, std::string ip, SrsRequest* req);
|
static int on_play(std::string url, int client_id, std::string ip, SrsRequest* req);
|
||||||
/**
|
/**
|
||||||
|
@ -98,6 +95,15 @@ public:
|
||||||
* ignore if empty.
|
* ignore if empty.
|
||||||
*/
|
*/
|
||||||
static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
|
static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
|
||||||
|
/**
|
||||||
|
* on_dvr hook, when reap a dvr file.
|
||||||
|
* @param client_id the id of client on server.
|
||||||
|
* @param url the api server url, to process the event.
|
||||||
|
* ignore if empty.
|
||||||
|
* @param cwd the current work directory, used to resolve the reltive file path.
|
||||||
|
* @param file the file path, can be relative or absolute path.
|
||||||
|
*/
|
||||||
|
static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -135,6 +135,9 @@ int SrsRtmpConn::do_cycle()
|
||||||
}
|
}
|
||||||
srs_verbose("rtmp connect app success");
|
srs_verbose("rtmp connect app success");
|
||||||
|
|
||||||
|
// set client ip to request.
|
||||||
|
req->ip = ip;
|
||||||
|
|
||||||
// discovery vhost, resolve the vhost from config
|
// discovery vhost, resolve the vhost from config
|
||||||
SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost);
|
SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost);
|
||||||
if (parsed_vhost) {
|
if (parsed_vhost) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// current release version
|
// current release version
|
||||||
#define VERSION_MAJOR 2
|
#define VERSION_MAJOR 2
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_REVISION 88
|
#define VERSION_REVISION 89
|
||||||
// server info.
|
// server info.
|
||||||
#define RTMP_SIG_SRS_KEY "SRS"
|
#define RTMP_SIG_SRS_KEY "SRS"
|
||||||
#define RTMP_SIG_SRS_ROLE "origin/edge server"
|
#define RTMP_SIG_SRS_ROLE "origin/edge server"
|
||||||
|
|
|
@ -91,6 +91,7 @@ SrsRequest* SrsRequest::copy()
|
||||||
{
|
{
|
||||||
SrsRequest* cp = new SrsRequest();
|
SrsRequest* cp = new SrsRequest();
|
||||||
|
|
||||||
|
cp->ip = ip;
|
||||||
cp->app = app;
|
cp->app = app;
|
||||||
cp->objectEncoding = objectEncoding;
|
cp->objectEncoding = objectEncoding;
|
||||||
cp->pageUrl = pageUrl;
|
cp->pageUrl = pageUrl;
|
||||||
|
|
|
@ -53,6 +53,9 @@ class IMergeReadHandler;
|
||||||
*/
|
*/
|
||||||
class SrsRequest
|
class SrsRequest
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
// client ip.
|
||||||
|
std::string ip;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* tcUrl: rtmp://request_vhost:port/app/stream
|
* tcUrl: rtmp://request_vhost:port/app/stream
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue