// Copyright 2020, 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 base import ( "errors" "io" "strings" ) var ( ErrSessionNotStarted = errors.New("lal.base: session has not been started yet") ) // IsUseClosedConnectionError 当connection处于这些情况时,就不需要再Close了 // TODO(chef): 临时放这 // TODO(chef): 目前暂时没有使用,因为connection支持多次调用Close // func IsUseClosedConnectionError(err error) bool { if err == io.EOF || (err != nil && strings.Contains(err.Error(), "use of closed network connection")) { return true } return false } type IClientSession interface { // PushSession: // Push() // Write() // Flush() // PullSession: // Pull() IClientSessionLifecycle ISessionUrlContext IObject ISessionStat } type IServerSession interface { IServerSessionLifecycle ISessionUrlContext IObject ISessionStat } // --------------------------------------------------------------------------------------------------------------------- type IClientSessionLifecycle interface { // Dispose 主动关闭session时调用 // // 注意,只有Start(具体session的Start类型函数一般命令为Push和Pull)成功后的session才能调用,否则行为未定义 // // Dispose可在任意协程内调用 // // 注意,目前Dispose允许调用多次,但是未来可能不对该表现做保证 // // Dispose后,调用Write函数将返回错误 // // @return 可以通过返回值判断调用Dispose前,session是否已经被关闭了 TODO(chef) 这个返回值没有太大意义,后面可能会删掉 // Dispose() error // WaitChan Start成功后,可使用这个channel来接收session结束的消息 // // 注意,只有Start成功后的session才能调用,否则行为未定义 // // 注意,目前WaitChan只会被通知一次,但是未来可能不对该表现做保证,业务方应该只关注第一次通知 // // TODO(chef): 是否应该严格保证:获取到关闭消息后,后续不应该再有该session的回调上来 // // @return 一般关闭有以下几种情况: // - 对端关闭,此时error为EOF // - 本端底层关闭,比如协议非法等,此时error为具体的错误值 // - 本端上层主动调用Dispose关闭,此时error为nil // WaitChan() <-chan error } type IServerSessionLifecycle interface { // RunLoop 开启session的事件循环,阻塞直到session结束 // RunLoop() error // Dispose 主动关闭session时调用 // // 如果是session通知业务方session已关闭(比如`RunLoop`函数返回错误),则不需要调用`Dispose` TODO(chef): review现状 // Dispose() error } // 调用约束:对于Client类型的Session,调用Start函数并返回成功后才能调用,否则行为未定义 type ISessionStat interface { // 周期性调用该函数,用于计算bitrate // // @param intervalSec 距离上次调用的时间间隔,单位毫秒 UpdateStat(intervalSec uint32) // 获取session状态 // // @return 注意,结构体中的`Bitrate`的值由最近一次`func UpdateStat`调用计算决定,其他值为当前最新值 GetStat() StatSession // 周期性调用该函数,判断是否有读取、写入数据 // 注意,判断的依据是,距离上次调用该函数的时间间隔内,是否有读取、写入数据 // 注意,不活跃,并一定是链路或网络有问题,也可能是业务层没有写入数据 // // @return readAlive 读取是否获取 // @return writeAlive 写入是否活跃 IsAlive() (readAlive, writeAlive bool) } // ISessionUrlContext 获取和流地址相关的信息 // // 调用约束:对于Client类型的Session,调用Start函数并返回成功后才能调用,否则行为未定义 // type ISessionUrlContext interface { Url() string AppName() string StreamName() string RawQuery() string } type IObject interface { // 对象的全局唯一标识 UniqueKey() string } // TODO chef: rtmp.ClientSession修改为BaseClientSession更好些