-
Notifications
You must be signed in to change notification settings - Fork 0
/
concierge.py
186 lines (157 loc) · 7.1 KB
/
concierge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import sys, queue, uuid, argparse, subprocess, statistics, logging, os
from PyQt5 import QtNetwork, QtWebSockets
from PyQt5.QtCore import QObject, QDataStream, pyqtSignal, pyqtSlot, QCoreApplication, QTimer
import model
DEFAULTPORT = 64337
class Concierge(QObject):
""" A Server Management
A Concierge starts game servers,
* passes on their info (address, port, etc) to
* potential clients (players)
* tells the servers to shut down when no longer needed.
TODO:
[ ] Remove old code
[ ] Write additional documentation
[ ] Change newClient() to handle requests from players
looking for game servers.
[ ] Change all prints to logger messages
"""
serverAvailable = pyqtSignal(int, name='serverAvailable')
def __init__(self,
my_id = None,
port = DEFAULTPORT,
address = QtNetwork.QHostAddress.LocalHost,
num_servers = 1,
seed = -1):
super().__init__()
LOG_FORMAT = '%(levelname)s:%(module)s:%(message)s'
logging.basicConfig(level = logging.INFO, format = LOG_FORMAT)
if os.path.basename(os.getcwd()) != 'Acquire':
os.chdir('..')
logging.info('Set cwd to ' + os.getcwd())
self.server = QtWebSockets.QWebSocketServer('',QtWebSockets.QWebSocketServer.NonSecureMode)
self.port = port
self.address = address
self.readyServers = list()
self.num_servers = num_servers
self.max_servers = 1
self.serverPort = 0
self.serverPorts = dict()
self.servers_active = 0
self.servers = list() # A place to store obj references so the garbarge collector
# won't take them away
self.process_list = list()
attempts = 0
max_attempts = 10
while attempts < max_attempts and not self.server.isListening():
if self.server.listen(self.address, self.port):
self.server.newConnection.connect(self.newClient)
logging.info("Concierge listening on port {}".format(self.port))
else:
self.port += 1
if not self.server.isListening():
raise('Concierge unable to bind port')
self.game_seed = seed
self.num_games = 0
self.scores = list()
self.highscores = list()
# self.runGames()
def newClient(self):
""" Routine to handle incoming connections.
Currently, it is assumed that incoming connections are from game servers.
Later it should be changed to allow clients ot inquire about available servers.
Server connections are persistant.
When a message is recieved, processTextMessage() is signalled.
"""
logging.info('a new server connected to concierge')
client = self.server.nextPendingConnection()
client.textMessageReceived.connect(self.processTextMessage)
client.disconnected.connect(self.socketDisconnected)
self.servers.append(client) # solely to keep the garbage collector from destroying
def processTextMessage(self,message):
""" Called when a message is recieved.
Parses incoming messages, and acts on their parts.
Messages are of the form m_type;m_body
Two m_types are recognized: 'READY' and 'DONE'.
On 'READY', calls serverREADY()
On 'DONE', calls serverDone()
"""
# print("Concierge recieved message: {}".format(message))
sender= self.sender()
if len(message.split(';')) != 2:
return
m_type,m_body = message.split(';')
# print("Concierge recieved message: {}".format(m_type))
if m_type == 'READY':
self.serverPorts[sender] = m_body
self.serverReady(m_body)
elif m_type == 'DONE':
self.serverDone(m_body, sender)
def runGames(self):
""" Starts up a number of game servers
The number is defined by self.num_servers.
"""
for i in range(self.num_servers):
self.servers_active += 1
subprocess.Popen(["python", "gameServer.py", "-cp", str(self.port), "-n", '4', "-s", str(self.game_seed)])
def serverDone(self, game, server):
s, hist = eval(game)
print("\rResults of game # {}".format(self.num_games))
for player in [p for p in s['Players'] if p != 'Bank']:
print("{}: {}".format(player, model.netWorth(player, s)))
scores = [model.netWorth(player, s) for player in s['Players'] if player != "Bank"]
self.highscores.append(max(scores))
self.scores += scores
self.num_games += 1
if self.num_games < 1:
# print("\rRunning game # {}".format(self.num_games), end = '')
server.sendTextMessage("RESET")
# self.serverReady(self.serverPort)
else:
# self.of = open('results.txt', 'a')
# self.of.write("{:3d}, {:6.2f}, {:6.2f}, {:5}, {:6.2f}, {:6.2f}\n".format(self.game_seed,
# statistics.mean(self.scores),
# statistics.stdev(self.scores),
# max(self.highscores),
# statistics.mean(self.highscores),
# statistics.stdev(self.highscores)))
# self.of.close()
server.sendTextMessage("DISCONNECT")
if self.game_seed == 1000:
self.num_games = 0
self.scores = list()
self.highscores = list()
self.game_seed += 1
self.runGames()
else:
pass
# QCoreApplication.quit()
# print("Average Score was {:5.2f} with a std dev of {:5.2f}".format(
# statistics.mean(self.scores), statistics.stdev(self.scores)))
# print("Average High Score was {:5.2f} with a std dev of {:5.2f}".format(
# statistics.mean(self.highscores), statistics.stdev(self.highscores)))
def serverReady(self, port):
# print("Concierge: a server said it is ready")
for args in self.process_list:
args.append("-p")
args.append(port)
subprocess.Popen(args)
subprocess.Popen(["python", "GM.py", "-p", port, "-s", str(self.game_seed)])
self.serverAvailable.emit(int(port))
def socketDisconnected(self):
pass
if __name__ == '__main__':
app = QCoreApplication(sys.argv)
# parser = argparse.ArgumentParser()
# parser.add_argument('-cp', '--conciergePort', type = int)
# args = parser.parse_args()
c = Concierge()
c.process_list.append(["python", "randomClient.py", "-n", "Random1"])
c.process_list.append(["python", "randomClient.py", "-n", "Random2"])
c.process_list.append(["python", "randomClient.py", "-n", "Random3"])
c.process_list.append(["python", "randomClient.py", "-n", "Random4"])
# c.process_list.append(["python", "randomClient.py", "-p", port, "-n", "Random4"])
# c.process_list.append(["python", "reflexAgent.py", "-p", port, "-n", "Flex1"])
# c.process_list.append(["python", "reflexAgent2.py", "-p", port, "-n", "Flex2"])
c.runGames()
app.exec_()