srs/trunk/src/app/srs_app_stream_token.cpp
2025-10-17 21:55:29 -04:00

148 lines
3.9 KiB
C++

//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#include <srs_app_stream_token.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_protocol_st.hpp>
// Global instance
SrsStreamPublishTokenManager *_srs_stream_publish_tokens = NULL;
ISrsStreamPublishToken::ISrsStreamPublishToken()
{
}
ISrsStreamPublishToken::~ISrsStreamPublishToken()
{
}
SrsStreamPublishToken::SrsStreamPublishToken(const std::string &stream_url, ISrsStreamPublishTokenManager *manager)
{
stream_url_ = stream_url;
acquired_ = false;
manager_ = manager;
publisher_cid_ = SrsContextId();
}
SrsStreamPublishToken::~SrsStreamPublishToken()
{
// Automatically release the token when destroyed
if (acquired_ && manager_) {
manager_->release_token(stream_url_);
}
}
std::string SrsStreamPublishToken::stream_url()
{
return stream_url_;
}
bool SrsStreamPublishToken::is_acquired()
{
return acquired_;
}
void SrsStreamPublishToken::set_acquired(bool acquired)
{
acquired_ = acquired;
}
const SrsContextId &SrsStreamPublishToken::publisher_cid()
{
return publisher_cid_;
}
void SrsStreamPublishToken::set_publisher_cid(const SrsContextId &cid)
{
publisher_cid_ = cid;
}
ISrsStreamPublishTokenManager::ISrsStreamPublishTokenManager()
{
}
ISrsStreamPublishTokenManager::~ISrsStreamPublishTokenManager()
{
}
SrsStreamPublishTokenManager::SrsStreamPublishTokenManager()
{
mutex_ = srs_mutex_new();
}
SrsStreamPublishTokenManager::~SrsStreamPublishTokenManager()
{
// Clean up all remaining tokens. Each token's destructor automatically calls
// release_token() which removes it from tokens_ map, so we use while loop
// to avoid iterator invalidation issues.
while (!tokens_.empty()) {
SrsStreamPublishToken *token = tokens_.begin()->second;
// Token destructor will call release_token() and remove this entry from map
srs_freep(token);
}
srs_mutex_destroy(mutex_);
srs_trace("stream publish token manager destroyed");
}
srs_error_t SrsStreamPublishTokenManager::acquire_token(ISrsRequest *req, SrsStreamPublishToken *&token)
{
srs_error_t err = srs_success;
std::string stream_url = req->get_stream_url();
SrsContextId current_cid = _srs_context->get_id();
SrsLocker(&mutex_);
// Get or create token for this stream
SrsStreamPublishToken *stream_token = NULL;
std::map<std::string, SrsStreamPublishToken *>::iterator it = tokens_.find(stream_url);
if (it != tokens_.end()) {
stream_token = it->second;
} else {
stream_token = new SrsStreamPublishToken(stream_url, this);
tokens_[stream_url] = stream_token;
}
// Check if token is already acquired by another publisher
if (stream_token->is_acquired()) {
SrsContextId existing_cid = stream_token->publisher_cid();
return srs_error_new(ERROR_SYSTEM_STREAM_BUSY,
"stream %s is busy, acquired by cid=%s, current cid=%s",
stream_url.c_str(), existing_cid.c_str(), current_cid.c_str());
} else {
stream_token->set_acquired(true);
stream_token->set_publisher_cid(current_cid);
}
// Return the token from the map (caller will manage its lifetime)
token = stream_token;
return err;
}
void SrsStreamPublishTokenManager::release_token(const std::string &stream_url)
{
SrsLocker(&mutex_);
// Find and erase the token from the map
std::map<std::string, SrsStreamPublishToken *>::iterator it = tokens_.find(stream_url);
srs_assert(it != tokens_.end());
SrsStreamPublishToken *token = it->second;
token->set_acquired(false);
srs_trace("stream publish token released and deleted, url=%s", stream_url.c_str());
// Erase from map first, then delete the token
tokens_.erase(it);
}