package server import ( "fmt" "sync" "log" ) // this package creates coordinators responsible for keeping track of active clients and invoking managers type Coordinator struct { Type string // ["reactor","tui"] IncomingClients <-chan *Client *Managers Err chan error } type Managers struct { Directory map[uint32](chan<- bool) sync.Mutex } func NewCoordinator(t string,ch chan *Client, err chan error) *Coordinator { d := make(map[uint32](chan<- bool)) m := &Managers{Directory:d} c := &Coordinator{Type: t,IncomingClients: ch,Err:err} c.Managers = m return c } func FindNewManager(c *Client,ch chan bool, err chan error) { switch c.Type { case "reactor": NewReactorManager(c,ch,err) case "tui": NewTUIManager(c,ch,err) default: log.Fatal(fmt.Sprintf("ERROR %v NOT FOUND",c.Type)) } } func (c *Coordinator) Start() { // on start we need to create channel listener // on each new connection we want to check its id against our mapping go c.Listen() } func (c *Coordinator) Listen() { for { cl := <-c.IncomingClients go c.ClientHandler(cl) } } func (c *Coordinator) ClientHandler(cl *Client) { // (creates and) notifies manager of client connection c.Managers.Lock() defer c.Managers.Unlock() if m, exists := c.Managers.Directory[cl.Id]; exists { // manager in memory m <-true } else { // create channel and manager ch := make(chan bool) FindNewManager(cl, ch,c.Err) c.Managers.Directory[cl.Id] = ch // will block until manager is ready ch <-true } }