You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/logic/group_manager.go

232 lines
7.1 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/lal
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package logic
// ---------------------------------------------------------------------------------------------------------------------
type IGroupCreator interface {
CreateGroup(appName, streamName string) *Group
}
// IGroupManager
//
// 封装管理Group的容器
// 管理流标识appNamestreamName与Group的映射关系。比如appName是否参与映射匹配
//
type IGroupManager interface {
// GetOrCreateGroup
//
// @param appName 注意,如果没有,可以为""
// @return createFlag 如果为false表示group之前就存在如果为true表示为当前新创建
//
GetOrCreateGroup(appName string, streamName string) (group *Group, createFlag bool)
// GetGroup
//
// @return 如果不存在则返回nil
//
GetGroup(appName string, streamName string) *Group
// Iterate 遍历所有 Group
//
// @param onIterateGroup 如果返回false则删除这个 Group
//
Iterate(onIterateGroup func(group *Group) bool)
Len() int
// TODO(chef): feat 没有提供删除操作,因为目前使用时,是在遍历时做删除的
}
// ---------------------------------------------------------------------------------------------------------------------
// SimpleGroupManager 忽略appName只使用streamName
//
type SimpleGroupManager struct {
groupCreator IGroupCreator
groups map[string]*Group // streamName -> Group
}
func NewSimpleGroupManager(groupCreator IGroupCreator) *SimpleGroupManager {
return &SimpleGroupManager{
groupCreator: groupCreator,
groups: make(map[string]*Group),
}
}
func (s *SimpleGroupManager) GetOrCreateGroup(appName string, streamName string) (group *Group, createFlag bool) {
g := s.GetGroup(appName, streamName)
if g == nil {
g = s.groupCreator.CreateGroup(appName, streamName)
s.groups[streamName] = g
return g, true
}
return g, false
}
func (s *SimpleGroupManager) GetGroup(appName string, streamName string) *Group {
g, ok := s.groups[streamName]
if !ok {
return nil
}
return g
}
func (s *SimpleGroupManager) Iterate(onIterateGroup func(group *Group) bool) {
for streamName, group := range s.groups {
if !onIterateGroup(group) {
delete(s.groups, streamName)
}
}
}
func (s *SimpleGroupManager) Len() int {
return len(s.groups)
}
// ---------------------------------------------------------------------------------------------------------------------
// ComplexGroupManager
//
// 注意这个模块的功能不完全目前只使用SimpleGroupManager
//
// TODO(chef):
//
// - 现有逻辑重构至当前模块中【DONE】
// - server_manger接入当前模块替换掉原来的map【DONE】
// - 重构整理使用server_manager的地方【DONE】
// - 实现appName逻辑的IGroupManager【DONE】
// - 增加单元测试【DONE】
// - 配置文件或var.go中增加选取具体IGroupManager实现的开关
// - 去除配置文件中一部分的url_pattern
// - 更新相应的文档本文件注释server_manager等中原有关于appName的注释配置文件文档流地址列表文档
// - 创建group时没有appname后面又有了可以考虑更新一下
// - ComplexGroupManager使用IGroupCreator
//
// ---------------------------------------------------------------------------------------------------------------------
//
// 背景:
// 有的协议需要结合appName和streamName作为流唯一标识比如rtmphttpflvhttpts
// 有的协议不需要appName只使用streamName作为流唯一标识比如rtsp
// 目标:
// 有appName的协议需要参考appName
// 没appName的协议需要和有appName的协议互通
// 注意:
// - 当以上两种类型的协议混用时系统使用者应避免第二种协议的streamName在第一种协议中存在相同的streamName但是appName不止一个
// 这种情况下,内部无法知道该如何对应
// - group可能由第一种协议创建也可能由第二种协议创建
//
type ComplexGroupManager struct {
groupCreator IGroupCreator
// 注意一个group只可能在一个容器中两个容器中的group加起来才是全量
onlyStreamNameGroups map[string]*Group // streamName -> Group
appNameStreamNameGroups map[string]map[string]*Group // appName -> streamName -> Group
}
func NewComplexGroupManager(groupCreator IGroupCreator) *ComplexGroupManager {
return &ComplexGroupManager{
groupCreator: groupCreator,
onlyStreamNameGroups: make(map[string]*Group),
appNameStreamNameGroups: make(map[string]map[string]*Group),
}
}
func (gm *ComplexGroupManager) GetOrCreateGroup(appName string, streamName string) (group *Group, createFlag bool) {
return gm.getGroup(appName, streamName, true)
}
func (gm *ComplexGroupManager) GetGroup(appName string, streamName string) *Group {
g, _ := gm.getGroup(appName, streamName, false)
return g
}
func (gm *ComplexGroupManager) getGroup(appName string, streamName string, shouldCreate bool) (group *Group, createFlag bool) {
var ok bool
if appName == "" {
group, ok = gm.onlyStreamNameGroups[streamName]
if ok {
return group, false
}
// 虽然没有appName也有可能在appNameStreamNameGroups中我们遍历查找
//
// 注意此时有可能不同appName的容器里都有对应这个streamName的group但是程序已没法区分系统使用者应规范流名称避免出现这种问题
//
for _, m := range gm.appNameStreamNameGroups {
group, ok = m[streamName]
if ok {
return group, false
}
}
// 两个容器都没找到
if shouldCreate {
group = gm.groupCreator.CreateGroup(appName, streamName)
gm.onlyStreamNameGroups[streamName] = group
return group, true
} else {
return nil, false
}
} else { // appName存在
// 先在对应appName中查找
m, mok := gm.appNameStreamNameGroups[appName]
if mok {
group, ok = m[streamName]
if ok {
return group, false
}
}
// 虽然有appName也有可能在onlyStreamNameGroups中我们尝试一下
group, ok = gm.onlyStreamNameGroups[streamName]
if ok {
return group, false
}
// 都没有找到
if shouldCreate {
group = gm.groupCreator.CreateGroup(appName, streamName)
if !mok {
m = make(map[string]*Group)
gm.appNameStreamNameGroups[appName] = m
}
m[streamName] = group
return group, true
} else {
return nil, false
}
}
}
func (gm *ComplexGroupManager) Iterate(onIterateGroup func(group *Group) bool) {
for streamName, group := range gm.onlyStreamNameGroups {
if !onIterateGroup(group) {
delete(gm.onlyStreamNameGroups, streamName)
}
}
for appName, m := range gm.appNameStreamNameGroups {
for streamName, group := range m {
if !onIterateGroup(group) {
delete(m, streamName)
if len(m) == 0 {
delete(gm.appNameStreamNameGroups, appName)
}
}
}
}
}
func (gm *ComplexGroupManager) Len() int {
var c int
for _, m := range gm.appNameStreamNameGroups {
c += len(m)
}
return c + len(gm.onlyStreamNameGroups)
}