mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-09-27 09:52:06 +08:00
feat: add auto update admin.zip
This commit is contained in:
9
api.go
9
api.go
@@ -181,6 +181,9 @@ func (s *Server) StreamInfo(ctx context.Context, req *pb.StreamSnapRequest) (res
|
||||
func (s *Server) TaskTree(context.Context, *emptypb.Empty) (res *pb.TaskTreeResponse, err error) {
|
||||
var fillData func(m task.ITask) *pb.TaskTreeData
|
||||
fillData = func(m task.ITask) (res *pb.TaskTreeData) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
t := m.GetTask()
|
||||
res = &pb.TaskTreeData{
|
||||
Id: m.GetTaskID(),
|
||||
@@ -197,7 +200,11 @@ func (s *Server) TaskTree(context.Context, *emptypb.Empty) (res *pb.TaskTreeResp
|
||||
res.Blocked = fillData(blockedTask)
|
||||
}
|
||||
for t := range job.RangeSubTask {
|
||||
res.Children = append(res.Children, fillData(t))
|
||||
child := fillData(t)
|
||||
if child == nil {
|
||||
continue
|
||||
}
|
||||
res.Children = append(res.Children, child)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
158
doc_CN/stream_alias_tech.md
Normal file
158
doc_CN/stream_alias_tech.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Monibuca 流别名功能技术实现文档
|
||||
|
||||
## 1. 功能概述
|
||||
|
||||
流别名(Stream Alias)是 Monibuca 中的一个重要功能,它允许为已存在的流创建一个或多个别名,使得同一个流可以通过不同的路径被访问。这个功能在以下场景特别有用:
|
||||
|
||||
- 为长路径的流创建简短别名
|
||||
- 动态修改流的访问路径
|
||||
- 实现流的重定向功能
|
||||
|
||||
## 2. 核心数据结构
|
||||
|
||||
### 2.1 AliasStream 结构
|
||||
|
||||
```go
|
||||
type AliasStream struct {
|
||||
*Publisher // 继承自 Publisher
|
||||
AutoRemove bool // 是否自动移除
|
||||
StreamPath string // 原始流路径
|
||||
Alias string // 别名路径
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 StreamAlias 消息结构
|
||||
|
||||
```protobuf
|
||||
message StreamAlias {
|
||||
string streamPath = 1; // 原始流路径
|
||||
string alias = 2; // 别名
|
||||
bool autoRemove = 3; // 是否自动移除
|
||||
uint32 status = 4; // 状态
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 核心功能实现
|
||||
|
||||
### 3.1 别名创建和修改
|
||||
|
||||
当调用 `SetStreamAlias` API 创建或修改别名时,系统会:
|
||||
|
||||
1. 验证并解析目标流路径
|
||||
2. 检查目标流是否存在
|
||||
3. 处理以下场景:
|
||||
- 修改现有别名:更新自动移除标志和流路径
|
||||
- 创建新别名:初始化新的 AliasStream 结构
|
||||
4. 处理订阅者转移或唤醒等待的订阅者
|
||||
|
||||
### 3.2 Publisher 启动时的别名处理
|
||||
|
||||
当一个 Publisher 启动时,系统会:
|
||||
|
||||
1. 检查是否存在指向该 Publisher 的别名
|
||||
2. 对于每个匹配的别名:
|
||||
- 如果别名的 Publisher 为空,设置为新的 Publisher
|
||||
- 如果别名已有 Publisher,转移订阅者到新的 Publisher
|
||||
3. 唤醒所有等待该流的订阅者
|
||||
|
||||
### 3.3 Publisher 销毁时的别名处理
|
||||
|
||||
Publisher 销毁时的处理流程:
|
||||
|
||||
1. 检查是否因被踢出而停止
|
||||
2. 从 Streams 中移除 Publisher
|
||||
3. 遍历所有别名,对于指向该 Publisher 的别名:
|
||||
- 如果设置了自动移除,则删除该别名
|
||||
- 否则保留别名结构
|
||||
4. 处理相关订阅者
|
||||
|
||||
### 3.4 订阅者处理机制
|
||||
|
||||
当新的订阅请求到来时:
|
||||
|
||||
1. 检查是否存在匹配的别名
|
||||
2. 如果存在别名:
|
||||
- 别名对应的 Publisher 存在:添加订阅者
|
||||
- Publisher 不存在:触发 OnSubscribe 事件
|
||||
3. 如果不存在别名:
|
||||
- 检查是否有匹配的正则表达式别名
|
||||
- 检查原始流是否存在
|
||||
- 根据情况添加订阅者或加入等待列表
|
||||
|
||||
## 4. API 接口
|
||||
|
||||
### 4.1 设置别名
|
||||
|
||||
```http
|
||||
POST /api/stream/alias
|
||||
```
|
||||
|
||||
请求体:
|
||||
```json
|
||||
{
|
||||
"streamPath": "原始流路径",
|
||||
"alias": "别名路径",
|
||||
"autoRemove": false
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 获取别名列表
|
||||
|
||||
```http
|
||||
GET /api/stream/alias
|
||||
```
|
||||
|
||||
响应体:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "",
|
||||
"data": [
|
||||
{
|
||||
"streamPath": "原始流路径",
|
||||
"alias": "别名路径",
|
||||
"autoRemove": false,
|
||||
"status": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态说明
|
||||
|
||||
别名状态(status)说明:
|
||||
- 0:初始状态
|
||||
- 1:别名已关联 Publisher
|
||||
- 2:存在同名的原始流
|
||||
|
||||
## 6. 最佳实践
|
||||
|
||||
1. 使用自动移除(autoRemove)
|
||||
- 当需要临时重定向流时,建议启用自动移除
|
||||
- 这样在原始流结束时,别名会自动清理
|
||||
|
||||
2. 别名命名建议
|
||||
- 使用简短且有意义的别名
|
||||
- 避免使用特殊字符
|
||||
- 建议使用规范的路径格式
|
||||
|
||||
3. 性能考虑
|
||||
- 别名机制采用高效的内存映射
|
||||
- 订阅者转移时保持连接状态
|
||||
- 支持动态修改,无需重启服务
|
||||
|
||||
## 7. 注意事项
|
||||
|
||||
1. 别名冲突处理
|
||||
- 当创建的别名与现有流路径冲突时,系统会进行适当处理
|
||||
- 建议在创建别名前检查是否存在冲突
|
||||
|
||||
2. 订阅者行为
|
||||
- 别名修改时,现有订阅者会被转移到新的流
|
||||
- 确保客户端能够处理流重定向
|
||||
|
||||
3. 资源管理
|
||||
- 及时清理不需要的别名
|
||||
- 合理使用自动移除功能
|
||||
- 监控别名状态,避免资源泄露
|
||||
```
|
206
doc_CN/stream_alias_usage.md
Normal file
206
doc_CN/stream_alias_usage.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Monibuca 流别名功能使用指南
|
||||
|
||||
## 1. 功能简介
|
||||
|
||||
流别名是 Monibuca 提供的一个强大功能,它允许您为同一个流创建多个不同的访问路径。这个功能不仅可以简化流的访问方式,更重要的是能够实现无缝的流内容切换,特别适合直播过程中插入广告等场景。
|
||||
|
||||
## 2. 基本使用方法
|
||||
|
||||
### 2.1 创建别名
|
||||
|
||||
通过 HTTP API 创建别名:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"streamPath": "live/original",
|
||||
"alias": "live/simple",
|
||||
"autoRemove": false
|
||||
}'
|
||||
```
|
||||
|
||||
### 2.2 查看当前别名列表
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/stream/alias
|
||||
```
|
||||
|
||||
### 2.3 删除别名
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"alias": "live/simple"
|
||||
}'
|
||||
```
|
||||
|
||||
## 3. 实战案例:直播广告插入
|
||||
|
||||
### 3.1 场景描述
|
||||
|
||||
在直播过程中,经常需要在适当的时机插入广告。使用流别名功能,我们可以实现:
|
||||
- 无缝切换between直播内容和广告
|
||||
- 保持观众的持续观看体验
|
||||
- 灵活控制广告的插入时机
|
||||
- 支持多个广告源的轮换播放
|
||||
|
||||
### 3.2 实现步骤
|
||||
|
||||
1. **准备工作**
|
||||
```bash
|
||||
# 假设主直播流的路径为:live/main
|
||||
# 广告流的路径为:ads/ad1
|
||||
```
|
||||
|
||||
2. **创建主直播的别名**
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"streamPath": "live/main",
|
||||
"alias": "live/show",
|
||||
"autoRemove": false
|
||||
}'
|
||||
```
|
||||
|
||||
3. **需要插入广告时**
|
||||
```bash
|
||||
# 将别名指向广告流
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"streamPath": "ads/ad1",
|
||||
"alias": "live/show",
|
||||
"autoRemove": false
|
||||
}'
|
||||
```
|
||||
|
||||
4. **广告播放结束后**
|
||||
```bash
|
||||
# 将别名重新指向主直播流
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"streamPath": "live/main",
|
||||
"alias": "live/show",
|
||||
"autoRemove": false
|
||||
}'
|
||||
```
|
||||
|
||||
### 3.3 效果说明
|
||||
|
||||
1. **对观众端的影响**
|
||||
- 观众始终访问 `live/show` 这个固定地址
|
||||
- 切换过程对观众无感知
|
||||
- 不会出现黑屏或卡顿
|
||||
- 无需刷新播放器
|
||||
|
||||
2. **对直播系统的影响**
|
||||
- 主播端推流不受影响
|
||||
- 支持多路广告源预加载
|
||||
- 可以实现精确的时间控制
|
||||
- 系统资源占用小
|
||||
|
||||
## 4. 进阶使用技巧
|
||||
|
||||
### 4.1 广告轮播方案
|
||||
|
||||
```bash
|
||||
# 创建多个广告流的别名
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"streamPath": "ads/ad1",
|
||||
"alias": "ads/current",
|
||||
"autoRemove": true
|
||||
}'
|
||||
|
||||
# 通过脚本定时切换不同的广告
|
||||
for ad in ad1 ad2 ad3; do
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"streamPath\": \"ads/$ad\",
|
||||
\"alias\": \"ads/current\",
|
||||
\"autoRemove\": true
|
||||
}"
|
||||
sleep 30 # 每个广告播放30秒
|
||||
done
|
||||
```
|
||||
|
||||
### 4.2 使用自动移除功能
|
||||
|
||||
当广告流结束时自动切回主流:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/stream/alias \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"streamPath": "ads/ad1",
|
||||
"alias": "live/show",
|
||||
"autoRemove": true
|
||||
}'
|
||||
```
|
||||
|
||||
### 4.3 条件触发广告
|
||||
|
||||
结合 Monibuca 的其他功能,可以实现:
|
||||
- 观众数量达到阈值时插入广告
|
||||
- 直播时长达到特定值时插入广告
|
||||
- 根据直播内容标签触发相关广告
|
||||
|
||||
## 5. 最佳实践建议
|
||||
|
||||
1. **广告内容预加载**
|
||||
- 提前准备好广告流
|
||||
- 确保广告源的稳定性
|
||||
- 使用缓存机制提高切换速度
|
||||
|
||||
2. **合理的切换策略**
|
||||
- 避免频繁切换影响用户体验
|
||||
- 选择适当的切换时机
|
||||
- 保持广告时长的合理控制
|
||||
|
||||
3. **监控和统计**
|
||||
- 记录广告播放情况
|
||||
- 监控切换过程是否平滑
|
||||
- 统计观众观看数据
|
||||
|
||||
4. **容错处理**
|
||||
- 广告流异常时快速切回主流
|
||||
- 设置合理的超时时间
|
||||
- 做好日志记录
|
||||
|
||||
## 6. 常见问题解答
|
||||
|
||||
1. **Q: 切换时观众会感知到卡顿吗?**
|
||||
A: 不会。流别名的切换是服务器端的操作,对客户端播放器完全透明。
|
||||
|
||||
2. **Q: 如何确保广告按预期时间播放?**
|
||||
A: 可以通过脚本控制切换时间,并配合自动移除功能来确保准确性。
|
||||
|
||||
3. **Q: 支持多少个并发的别名?**
|
||||
A: 理论上没有限制,但建议根据服务器资源合理使用。
|
||||
|
||||
4. **Q: 如何处理广告流异常的情况?**
|
||||
A: 建议使用自动移除功能,并配合监控系统及时发现和处理异常。
|
||||
|
||||
## 7. 注意事项
|
||||
|
||||
1. **资源管理**
|
||||
- 及时清理不再使用的别名
|
||||
- 避免创建过多无用的别名
|
||||
- 定期检查别名状态
|
||||
|
||||
2. **性能考虑**
|
||||
- 控制并发别名数量
|
||||
- 合理设置缓存策略
|
||||
- 监控服务器资源使用情况
|
||||
|
||||
3. **用户体验**
|
||||
- 控制广告频率和时长
|
||||
- 确保切换的流畅性
|
||||
- 考虑不同网络环境的用户
|
||||
```
|
26
server.go
26
server.go
@@ -145,6 +145,9 @@ func exit() {
|
||||
}
|
||||
|
||||
var zipReader *zip.ReadCloser
|
||||
var adminZipLastModTime time.Time
|
||||
var lastCheckTime time.Time
|
||||
var checkInterval = time.Second * 3 // 检查间隔为3秒
|
||||
|
||||
func init() {
|
||||
Servers.Init()
|
||||
@@ -152,7 +155,18 @@ func init() {
|
||||
time.AfterFunc(3*time.Second, exit)
|
||||
})
|
||||
Servers.OnDispose(exit)
|
||||
zipReader, _ = zip.OpenReader("admin.zip")
|
||||
loadAdminZip()
|
||||
}
|
||||
|
||||
func loadAdminZip() {
|
||||
if zipReader != nil {
|
||||
zipReader.Close()
|
||||
zipReader = nil
|
||||
}
|
||||
if info, err := os.Stat("admin.zip"); err == nil {
|
||||
adminZipLastModTime = info.ModTime()
|
||||
zipReader, _ = zip.OpenReader("admin.zip")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) GetKey() uint32 {
|
||||
@@ -408,6 +422,16 @@ func (s *Server) OnSubscribe(streamPath string, args url.Values) {
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// 检查 admin.zip 是否需要重新加载
|
||||
now := time.Now()
|
||||
if now.Sub(lastCheckTime) > checkInterval {
|
||||
if info, err := os.Stat("admin.zip"); err == nil && info.ModTime() != adminZipLastModTime {
|
||||
s.Info("admin.zip changed, reloading...")
|
||||
loadAdminZip()
|
||||
}
|
||||
lastCheckTime = now
|
||||
}
|
||||
|
||||
if zipReader != nil {
|
||||
http.ServeFileFS(w, r, zipReader, strings.TrimPrefix(r.URL.Path, "/admin"))
|
||||
return
|
||||
|
Reference in New Issue
Block a user