// 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的容器 // 管理流标识(appName,streamName)与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作为流唯一标识(比如rtmp,httpflv,httpts) // 有的协议不需要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) }