/* * register creates a new client, assigns it an id and returns it */ func (reg *ClientRegistry) register(client *network.Conn) uint32 { var clientId uint32 // protect: // - increment the next available id // - client map write reg.mutex.Lock() // we have a new client, assign him an id. clientId = reg.allocId() reg.clients[clientId] = client // record the client id inside the connection, this is needed for later // retriving the clientId when we just have a connection clientData := ClientData{ Id: clientId, Name: "", Joined: false, } client.SetUserData(clientData) // Note: for now we just stupidly increment the next available id. // We will have other problems to solve before this overflows... reg.mutex.Unlock() log.WithFields(log.Fields{ "client": clientData, "addr": client.GetRawConn().RemoteAddr(), }).Info("Accepted a new client") return clientId }
func (reg *ClientRegistry) Join(join messages.Join, c *network.Conn) bool { clientData := c.GetUserData().(ClientData) log.WithFields(log.Fields{"name": join.Name, "clientData": clientData}).Info("Received JOIN from client") // client already JOINED? if clientData.Joined { reg.Leave("Joined already received", c) return false } // name length condition if len(join.Name) < 3 { reg.Leave("Name is too short", c) return false } // name already taken? nameTaken := false playerNames := make(map[uint32]string) // compute the list of joined players, populating the STAY message and // checking if name is taken as well reg.ForEach(func(cd ClientData) bool { nameTaken = cd.Name == join.Name playerNames[cd.Id] = cd.Name // stop iteration if name is taken return !nameTaken }) if nameTaken { reg.Leave("Name is already taken", c) return false } // create and send STAY to the new client stay := messages.Stay{Id: clientData.Id, Players: playerNames} err := c.AsyncSendPacket(messages.New(messages.StayId, stay), time.Second) if err != nil { // handle error in case we couldn't send the STAY message log.WithError(err).Error("Couldn't send STAY message to the new client") reg.Leave("Couldn't finish handshaking", c) return false } // fill a JOINED message joined := &messages.Joined{ Id: clientData.Id, Name: join.Name, Type: join.Type, } log.WithField("joined", joined).Info("Tell to the world this client has joined") reg.Broadcast(messages.New(messages.JoinedId, joined)) // at this point we consider the client as accepted clientData.Joined = true clientData.Name = join.Name c.SetUserData(clientData) return true }