func (cs *centralServer) RegisterGameServer(args *centralrpc.RegisterGameServerArgs, reply *centralrpc.RegisterGameServerReply) error { cs.gameServersLock.Lock() var id uint32 if gs, exists := cs.hostPortToGameServer[args.HostPort]; !exists { // Check if we hit the limit if len(cs.gameServers) >= cs.numGameServers { LOGE.Println("Received request to register game server when ring is FULL") reply.Status = centralrpc.Full cs.gameServersLock.Unlock() return nil } // Get a new ID id = cs.nextGameServerID cs.nextGameServerID++ // Get host:port hostport := args.HostPort // Add new server object to map gs = &gameServer{paxosrpc.Node{id, hostport}, 0} cs.gameServers[id] = gs cs.hostPortToGameServer[hostport] = gs } else { id = gs.info.ID } // Check if all the game servers in the ring have registered. If they // haven't, then reply with not ready. Otherwise, reply with OK, send back // to the unique ID, and the list of all game servers. if len(cs.gameServers) < cs.numGameServers { reply.Status = centralrpc.NotReady } else { reply.Status = centralrpc.OK reply.GameServerID = id // Check if the game servers sliced has been cached. If it hasn't, make it. if cs.gameServersSlice == nil { cs.gameServersSlice = make([]paxosrpc.Node, len(cs.gameServers)) i := 0 for _, node := range cs.gameServers { cs.gameServersSlice[i] = node.info i++ } } reply.Servers = cs.gameServersSlice } LOGV.Printf("Received registration request from %d, reply was %d\n", id, reply.Status) cs.gameServersLock.Unlock() return nil }
// NewGameServer creates an instance of a Game Server. It does not return // until it has successfully joined the cluster of game servers and started // its libpaxos service. func NewGameServer(centralServerHostPort, hostname string, port int, pattern string) (GameServer, error) { // RPC Dial to the central server to join the ring c, err := rpc.DialHTTP("tcp", centralServerHostPort) if err != nil { fmt.Println("Could not connect to central server host port via RPC") fmt.Println(err) return nil, err } // Register myself with the central server, obtaining my ID, and a // complete list of all servers in the ring. gshostport := fmt.Sprintf("%s:%d", hostname, port) args := ¢ralrpc.RegisterGameServerArgs{gshostport} var reply centralrpc.RegisterGameServerReply reply.Status = centralrpc.NotReady for reply.Status != centralrpc.OK { err = c.Call("CentralServer.RegisterGameServer", args, &reply) if err != nil { fmt.Println("Could not RPC call method CentralServer.RegisterGameServer") fmt.Println(err) return nil, err } if reply.Status == centralrpc.Full { return nil, errors.New("Could not register with central server, ring FULL") } time.Sleep(REGISTER_RETRY_INTERVAL * time.Millisecond) } // Start the libpaxos service newlibpaxos, err := libpaxos.NewLibpaxos(reply.GameServerID, gshostport, reply.Servers) if err != nil { fmt.Println("Could not start libpaxos") fmt.Println(err) return nil, err } // Websockets client related stuff clients := make(map[int]*client) addCh := make(chan *client) delCh := make(chan *client) doneCh := make(chan bool) errCh := make(chan error) // Debugging setup var vOut, eOut io.Writer if LOG_TO_FILE { now := time.Now().String() var err1, err2 error vOut, err1 = os.Create(fmt.Sprintf("%d_debug_%s.log", reply.GameServerID, now)) eOut, err2 = os.Create(fmt.Sprintf("%d_error_%s.log", reply.GameServerID, now)) if err1 != nil || err2 != nil { panic(err) } } else { vOut = os.Stdout eOut = os.Stderr } LOGV = util.NewLogger(DEBUG_LOG, "DEBUG", vOut) LOGE = util.NewLogger(ERROR_LOG, "ERROR", eOut) gs := &gameServer{ reply.GameServerID, hostname, port, gshostport, newlibpaxos, pattern, sync.Mutex{}, clients, addCh, delCh, doneCh, errCh, 0, make(chan *paxosrpc.ProposalValue, 1000), len(reply.Servers), lib2048.NewGame2048(), make(chan *util.Game2048State, 1000), make(chan *lib2048.Move, 1000), } gs.libpaxos.DecidedHandler(gs.handleDecided) LOGV.Printf("GS node %d loaded libpaxos\n", reply.GameServerID) go gs.ListenForClients() go gs.processMoves() go gs.clientTasker() go gs.clientMasterHandler() return gs, nil }