cherry 笔记三(启动)

devtools/2024/10/20 9:47:12/

cherry启动很简单  app创建完  直接startup()就好了

func main() {app := cherry.Configure("./examples/config/profile-chat.json","chat-master",false,cherry.Cluster,)app.SetSerializer(cserializer.NewJSON())app.Startup()
}

Configure()--->NewApp()-->NewAppNode()  

app := &Application{INode:       node,serializer:  cserializer.NewProtobuf(),isFrontend:  isFrontend,nodeMode:    mode,startTime:   ctime.Now(),running:     0,dieChan:     make(chan bool),actorSystem: cactor.New(),}

默认的 serializer 是Protobuf()的

在Startup()之前除了可以SetSerializer() 还可以干其他很多事情 比如以下。。。

app.Register(cherryCron.New())
app.Register(data.New())
app.Register(db.New())httpServer := cherryGin.NewHttp("web_1", app.Address())
httpServer.Use(cherryGin.Cors(), cherryGin.MaxConnect(2))
httpServer.Register(new(Test1Controller))
app.Register(httpServer)func (p *AppBuilder) Register(component ...cfacade.IComponent) {p.components = append(p.components, component...)
}

这些register的component,也是暂存在AppBuilder的components中 

    // 创建pomelo网络数据包解析器,它同时也是一个actoragentActor := pomelo.NewActor("user")// 添加websocket连接器, 根据业务需要可添加多类型的connectoragentActor.AddConnector(cconnector.NewWS(":34590"))// 创建Agent时,关联onClose函数agentActor.SetOnNewAgent(func(newAgent *pomelo.Agent) {newAgent.AddOnClose(func(agent *pomelo.Agent) {session := agent.Session()if !session.IsBind() {return}// 发送玩家断开连接的消息给room actorreq := &protocol.Int64{Value: session.Uid,}agentActor.Call(".room", "exit", req)clog.Debugf("[sid = %s,uid = %d] session disconnected.",session.Sid,session.Uid,)})})// 设置数据路由函数agentActor.SetOnDataRoute(onDataRoute)// 设置网络包解析器app.SetNetParser(agentActor)

上边是设置NetParser的示例。。。。。。

app.AddActors(&ActorLog{})func (p *AppBuilder) AddActors(actors ...cfacade.IActorHandler) {p.actorSystem.Add(actors...)
}

上边是添加一些actors,这些actor都放在actorSystem中维护

设置一些东西之后,最后一步就是Startup()了

func (p *AppBuilder) Startup() {app := p.Applicationif app.NodeMode() == Cluster {cluster := ccluster.New()app.SetCluster(cluster)app.Register(cluster)discovery := cdiscovery.New()app.SetDiscovery(discovery)app.Register(discovery)}// Register custom componentsapp.Register(p.components...)// startupapp.Startup()
}

如果是Cluster模式,那么会自动注册 cluster、discovery这2个component

然后把 之前Register 暂存在AppBuilder的components里边的component(像httpServer这些)也注册到Application的components

由此可见,暂存到AppBuilder.components里边的component 最终都会汇总到Application.components 里边去。。。

最后调用app.Startup()

func (a *Application) Startup() {defer func() {if r := recover(); r != nil {clog.Error(r)}}()if a.Running() {clog.Error("Application has running.")return}defer func() {clog.Flush()}()// register actor systema.Register(a.actorSystem)// add connector componentif a.netParser != nil {for _, connector := range a.netParser.Connectors() {a.Register(connector)}}clog.Info("-------------------------------------------------")clog.Infof("[nodeId      = %s] application is starting...", a.NodeId())clog.Infof("[nodeType    = %s]", a.NodeType())clog.Infof("[pid         = %d]", os.Getpid())clog.Infof("[startTime   = %s]", a.StartTime())clog.Infof("[profilePath = %s]", cprofile.Path())clog.Infof("[profileName = %s]", cprofile.Name())clog.Infof("[env         = %s]", cprofile.Env())clog.Infof("[debug       = %v]", cprofile.Debug())clog.Infof("[printLevel  = %s]", cprofile.PrintLevel())clog.Infof("[logLevel    = %s]", clog.DefaultLogger.LogLevel)clog.Infof("[stackLevel  = %s]", clog.DefaultLogger.StackLevel)clog.Infof("[writeFile   = %v]", clog.DefaultLogger.EnableWriteFile)clog.Infof("[serializer  = %s]", a.serializer.Name())clog.Info("-------------------------------------------------")// component listfor _, c := range a.components {c.Set(a)clog.Infof("[component = %s] is added.", c.Name())}clog.Info("-------------------------------------------------")// execute Init()for _, c := range a.components {clog.Infof("[component = %s] -> OnInit().", c.Name())c.Init()}clog.Info("-------------------------------------------------")// execute OnAfterInit()for _, c := range a.components {clog.Infof("[component = %s] -> OnAfterInit().", c.Name())c.OnAfterInit()}// load net packet parserif a.isFrontend {if a.netParser == nil {clog.Panic("net packet parser is nil.")}a.netParser.Load(a)}clog.Info("-------------------------------------------------")spendTime := a.startTime.DiffInMillisecond(ctime.Now())clog.Infof("[spend time = %dms] application is running.", spendTime)clog.Info("-------------------------------------------------")// set application is runningatomic.AddInt32(&a.running, 1)sg := make(chan os.Signal, 1)signal.Notify(sg, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)select {case <-a.dieChan:clog.Info("invoke shutdown().")case s := <-sg:clog.Infof("receive shutdown signal = %v.", s)}// stop statusatomic.StoreInt32(&a.running, 0)clog.Info("------- application will shutdown -------")if a.onShutdownFn != nil {for _, f := range a.onShutdownFn {cutils.Try(func() {f()}, func(errString string) {clog.Warnf("[onShutdownFn] error = %s", errString)})}}//all components in reverse orderfor i := len(a.components) - 1; i >= 0; i-- {cutils.Try(func() {clog.Infof("[component = %s] -> OnBeforeStop().", a.components[i].Name())a.components[i].OnBeforeStop()}, func(errString string) {clog.Warnf("[component = %s] -> OnBeforeStop(). error = %s", a.components[i].Name(), errString)})}for i := len(a.components) - 1; i >= 0; i-- {cutils.Try(func() {clog.Infof("[component = %s] -> OnStop().", a.components[i].Name())a.components[i].OnStop()}, func(errString string) {clog.Warnf("[component = %s] -> OnStop(). error = %s", a.components[i].Name(), errString)})}clog.Info("------- application has been shutdown... -------")
}

维护着所有actor的 actorSystem 也是一个component  会Register到Application.components

netParser管理的所有Connector 都是compenent  会Register到Application.components

func (a *Application) Register(components ...cfacade.IComponent) {if a.Running() {return}for _, c := range components {if c == nil || c.Name() == "" {clog.Errorf("[component = %T] name is nil", c)return}result := a.Find(c.Name())if result != nil {clog.Errorf("[component name = %s] is duplicate.", c.Name())return}a.components = append(a.components, c)}
}

所有Register的component 都是暂存在 Application.components

逐步遍历components 执行 c.Set(a)  c.Init()  c.OnAfterInit() 

来看看component 接口和 基类 都长什么样? 

type (IComponent interface {Name() stringApp() IApplicationIComponentLifecycle}IComponentLifecycle interface {Set(app IApplication)Init()OnAfterInit()OnBeforeStop()OnStop()}
)// Component base component
type Component struct {app IApplication
}func (*Component) Name() string {return ""
}func (p *Component) App() IApplication {return p.app
}func (p *Component) Set(app IApplication) {p.app = app
}func (*Component) Init() {
}func (*Component) OnAfterInit() {
}func (*Component) OnBeforeStop() {
}func (*Component) OnStop() {
}

紧接着 如果当前application isFrontend是true的话,就对netParser 执行 Load()操作

func (p *actor) Load(app cfacade.IApplication) {if len(p.connectors) < 1 {panic("connectors is nil. Please call the AddConnector(...) method add IConnector.")}cmd.init(app)//  Create agent actorif _, err := app.ActorSystem().CreateActor(p.agentActorID, p); err != nil {clog.Panicf("Create agent actor fail. err = %+v", err)}for _, connector := range p.connectors {connector.OnConnect(p.defaultOnConnectFunc)go connector.Start() // start connector!}
}

init()这个里边会去初始化 一些常用的数据 比如说心跳、DataDic、序列化的名称、握手数据、心跳数据、握手回调、握手确认回调、心跳回调、收到数据包的回调。。。。这部分逻辑 跟pitaya是一样的

紧接着就是启动连接器,以便客户端来连接,类似pitaya的Acceptor 和Twisted的ClientFactory

OnConnect 是设置 当有客户端来连接时的回调函数。。。框架统一由defaultOnConnectFunc

func (p *actor) defaultOnConnectFunc(conn net.Conn) {session := &cproto.Session{Sid:       nuid.Next(),AgentPath: p.Path().String(),Data:      map[string]string{},}agent := NewAgent(p.App(), conn, session)if p.onNewAgentFunc != nil {p.onNewAgentFunc(&agent)}BindSID(&agent)agent.Run()
}

创建session,然后创建agent,onNewAgentFunc 是应用层 对于有连接过来了 设置的回调,比如聊天示例中,要设置这个连接关闭时 触发的api。。。

agentActor.SetOnNewAgent(func(newAgent *pomelo.Agent) {newAgent.AddOnClose(func(agent *pomelo.Agent) {session := agent.Session()if !session.IsBind() {return}// 发送玩家断开连接的消息给room actorreq := &protocol.Int64{Value: session.Uid,}agentActor.Call(".room", "exit", req)clog.Debugf("[sid = %s,uid = %d] session disconnected.",session.Sid,session.Uid,)})})

BindSID 主要是建立关联。。。 

sidAgentMap = make(map[cfacade.SID]*Agent)
func BindSID(agent *Agent) {lock.Lock()defer lock.Unlock()sidAgentMap[agent.SID()] = agent
}

agent.Run()就是 启动2个协程 分别读写 

func (a *Agent) Run() {go a.writeChan()go a.readChan()
}


http://www.ppmy.cn/devtools/55814.html

相关文章

RockChip Android12 System之MultipleUsers

一:概述 System中的MultipleUsers不同于其他Preference采用system_dashboard_fragment.xml文件进行加载,而是采用自身独立的xml文件user_settings.xml加载。 二:Multiple Users 1、Activity packages/apps/Settings/AndroidManifest.xml <activityandroid:name="S…

6月19日(周三)A股行情总结:A股震荡收跌,恒生科技指数大涨3%,10年期国债期货转涨续创新高

内容提要 车路云概念延续昨日涨势&#xff0c;华铭智能20CM 3连板。贵金属及PEEK材料概念全日走强&#xff1b;港股有色金属及能源股走强&#xff0c;紫金矿业涨超3%&#xff0c;中石油涨超3%。国债期货午后全线转涨&#xff0c;10年期主力合约涨0.05%报104.925元&#xff0c;…

使用不同环境的配置文件active profile

在 IntelliJ IDEA 的 Run/Debug Configurations 中&#xff0c;Active profiles 选项通常用于与 Spring Boot 应用程序相关的配置。这是 Spring Boot 特有的一个用来管理不同环境配置的特性&#xff0c;通常用来在开发&#xff08;dev&#xff09;、测试&#xff08;test&#…

【vuejs】 $on、$once、$off、$emit 事件监听方法详解以及项目实战

1. Vue实例方法概述 1.1 vm.$on vm.$on是Vue实例用来监听自定义事件的方法。它允许开发者在Vue实例上注册事件监听器&#xff0c;当事件被触发时&#xff0c;指定的回调函数会被执行。 事件监听&#xff1a;vm.$on允许开发者绑定一个或多个事件到Vue实例上&#xff0c;并且可…

5个wordpress成品站主题

Sora索啦高端制造业wordpress主题 红色高端制造业wordpress主题&#xff0c;适合外贸企业出海建独立站的wordpress模板。 https://www.jianzhanpress.com/?p5885 Polar钋啦wordpress外贸主题 制造业wordpress网站模板&#xff0c;适合生产制造企业官方网站使用的wordpress外…

Nginx缓存之代理缓存配置

Nginx 的缓存功能是集成在代理模块中的&#xff0c;当启用缓存功能时&#xff0c;Nginx 将请求返回的响应数据持久化在服务器磁盘中&#xff0c;响应数据缓存的相关元数据、有效期及缓存内容等信息将被存储在定义的共享内存中。当收到客户端请求时&#xff0c;Nginx 会在共享内…

redis的序列化问题

报错 io.netty.handler.codec.DecoderException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of org.springframework.http.ReadOnlyHttpHeaders (no Creators, like default constructor, exist): no default constructor f…

Docker: 使用容器化数据库

使用容器化数据库 使用本地容器化数据库提供了灵活性和简易的设置,使您能够在不需要传统数据库安装开销的情况下,紧密模拟生产环境。Docker 简化了这一过程,只需几条命令就可以在隔离的容器中部署、管理和扩展数据库。 在本指南中,您将学习如何: 运行本地容器化数据库访…