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
}
Пример #2
0
// 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 := &centralrpc.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
}