srs/trunk/src/app/srs_app_http_hooks.hpp
Winlin 1b6f97bd2d
Refine source lock to fix race condition in source managers. v7.0.61 (#4449)
This PR fixes a critical race condition in SRS source managers where
multiple coroutines could create duplicate sources for the same stream.

- **Atomic source creation**: Source lookup, creation, and pool
insertion now happen atomically within lock scope
- **Consistent interface**: Standardize on `ISrsRequest*` interface
throughout codebase
- **Handler simplification**: Remove `ISrsLiveSourceHandler*` parameter,
obtain from global server instance

---------

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
2025-08-23 07:36:41 -06:00

178 lines
9.5 KiB
C++

//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#ifndef SRS_APP_HTTP_HOOKS_HPP
#define SRS_APP_HTTP_HOOKS_HPP
#include <srs_core.hpp>
#include <string>
#include <vector>
class SrsHttpUri;
class SrsStSocket;
class ISrsRequest;
class SrsHttpParser;
class SrsHttpClient;
// HTTP hooks interface for SRS server event callbacks.
//
// This interface defines the contract for handling various server events
// through HTTP callback APIs. Implementations can send HTTP requests to
// external services to notify them of events like client connections,
// stream publishing/playing, DVR recording, HLS segment generation, etc.
//
// All hook methods that return srs_error_t are used for validation and
// can reject the operation by returning an error. Methods that return void
// are notification-only and cannot prevent the operation.
class ISrsHttpHooks
{
public:
ISrsHttpHooks();
virtual ~ISrsHttpHooks();
public:
// Stream start publishing validation hook.
// Called when a client (encoder) attempts to start publishing a stream.
// This hook can be used to authorize stream publishing or apply publishing policies.
// @param url The HTTP callback URL for publish validation. If empty, hook is ignored.
// @param req The publish request information including stream details.
// @return srs_success if publishing is allowed, error otherwise to reject publishing.
virtual srs_error_t on_publish(std::string url, ISrsRequest *req) = 0;
// Stream stop publishing notification hook.
// Called when a client (encoder) stops publishing a stream.
// This is a notification-only hook that cannot prevent the unpublishing.
// @param url The HTTP callback URL for unpublish notification. If empty, hook is ignored.
// @param req The unpublish request information.
virtual void on_unpublish(std::string url, ISrsRequest *req) = 0;
// Stream start playing validation hook.
// Called when a client attempts to start playing/subscribing to a stream.
// This hook can be used to authorize stream access or apply viewing policies.
// @param url The HTTP callback URL for play validation. If empty, hook is ignored.
// @param req The play request information including stream details.
// @return srs_success if playing is allowed, error otherwise to reject playing.
virtual srs_error_t on_play(std::string url, ISrsRequest *req) = 0;
// Stream stop playing notification hook.
// Called when a client stops playing/subscribing to a stream.
// This is a notification-only hook that cannot prevent the stop operation.
// @param url The HTTP callback URL for stop notification. If empty, hook is ignored.
// @param req The stop request information.
virtual void on_stop(std::string url, ISrsRequest *req) = 0;
public:
// DVR file completion notification hook.
// Called when a DVR recording file is completed and ready for processing.
// This hook can be used to trigger post-processing, upload, or notification workflows.
// Note: This is an asynchronous callback, so the connection context may differ.
// @param cid The source connection context ID for tracking the original stream.
// @param url The HTTP callback URL for DVR notification. If empty, hook is ignored.
// @param req The original stream request information.
// @param file The completed DVR file path (can be relative or absolute).
// @return srs_success if processing succeeds, error otherwise (logged but doesn't affect DVR).
virtual srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file) = 0;
public:
// HLS segment completion notification hook.
// Called when an HLS segment (.ts file) is generated and the playlist is updated.
// This hook can be used for CDN synchronization, analytics, or custom HLS workflows.
// Note: This is an asynchronous callback, so the connection context may differ.
// @param cid The source connection context ID for tracking the original stream.
// @param url The HTTP callback URL for HLS notification. If empty, hook is ignored.
// @param req The original stream request information.
// @param file The generated TS segment file path (can be relative or absolute).
// @param ts_url The TS segment URL as it appears in the M3U8 playlist.
// @param m3u8 The M3U8 playlist file path (can be relative or absolute).
// @param m3u8_url The M3U8 playlist URL for HTTP access.
// @param sn The sequence number of the TS segment in the HLS playlist.
// @param duration The segment duration in microseconds (srs_utime_t).
// @return srs_success if processing succeeds, error otherwise (logged but doesn't affect HLS).
virtual srs_error_t on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url,
std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration) = 0;
// HLS segment notification hook with custom URL template.
// Called when an HLS segment is generated, allowing custom URL template processing.
// The callback URL can contain variables like [ts_url] that will be replaced.
// Note: This is an asynchronous callback, so the connection context may differ.
// @param cid The source connection context ID for tracking the original stream.
// @param url The HTTP callback URL template for HLS notification. If empty, hook is ignored.
// @param req The original stream request information.
// @param ts_url The TS segment URL to replace [ts_url] variable in the callback URL.
// @param nb_notify Maximum bytes to read from the notification server response.
// @return srs_success if processing succeeds, error otherwise (logged but doesn't affect HLS).
virtual srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify) = 0;
public:
// Origin cluster co-worker discovery hook.
// Called to discover available co-worker servers in an origin cluster setup.
// This enables dynamic load balancing and failover in clustered deployments.
// @param url The HTTP callback URL for co-worker discovery. If empty, hook is ignored.
// @param host Output parameter to receive the discovered co-worker host/IP.
// @param port Output parameter to receive the discovered co-worker port.
// @return srs_success if co-worker is discovered, error otherwise.
virtual srs_error_t discover_co_workers(std::string url, std::string &host, int &port) = 0;
public:
// Stream forwarding backend discovery hook.
// Called when a published stream needs to be forwarded to backend servers.
// This hook can dynamically determine which RTMP URLs to forward the stream to.
// @param url The HTTP callback URL for backend discovery. If empty, hook is ignored.
// @param req The publish request information.
// @param rtmp_urls Output parameter to receive the list of RTMP URLs for forwarding.
// @return srs_success if backends are discovered, error otherwise.
virtual srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls) = 0;
// Deprecated hooks.
public:
// Client connection validation hook.
// Called when a client attempts to connect to the SRS server.
// This hook can be used to authenticate or authorize client connections.
// @param url The HTTP callback URL for client validation. If empty, hook is ignored.
// @param req The client request information including IP, vhost, app, stream, etc.
// @return srs_success if connection is allowed, error otherwise to reject connection.
virtual srs_error_t on_connect(std::string url, ISrsRequest *req) = 0;
// Client disconnection notification hook.
// Called when a client disconnects from the SRS server.
// This is a notification-only hook that cannot prevent the disconnection.
// @param url The HTTP callback URL for disconnect notification. If empty, hook is ignored.
// @param req The client request information.
// @param send_bytes Total bytes sent to the client during the session.
// @param recv_bytes Total bytes received from the client during the session.
virtual void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes) = 0;
};
class SrsHttpHooks : public ISrsHttpHooks
{
public:
SrsHttpHooks();
virtual ~SrsHttpHooks();
public:
srs_error_t on_connect(std::string url, ISrsRequest *req);
void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes);
srs_error_t on_publish(std::string url, ISrsRequest *req);
void on_unpublish(std::string url, ISrsRequest *req);
srs_error_t on_play(std::string url, ISrsRequest *req);
void on_stop(std::string url, ISrsRequest *req);
srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file);
srs_error_t on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url,
std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration);
srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify);
srs_error_t discover_co_workers(std::string url, std::string &host, int &port);
srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls);
private:
srs_error_t do_post(SrsHttpClient *hc, std::string url, std::string req, int &code, std::string &res);
};
// Global HTTP hooks instance
extern ISrsHttpHooks *_srs_hooks;
#endif