Fix bugs with FifoPlayer and Networking
[progcomp2013.git] / qchess / src / network.py
1 import socket
2 import select
3
4 network_timeout_start = -1.0 # Timeout in seconds to wait for the start of a message
5 network_timeout_delay = 1.0 # Maximum time between two characters being received
6
7 class NetworkPlayer(Player):
8         def __init__(self, colour, network, player):
9                 Player.__init__(self, "@network:"+str(network.address), colour) 
10                 self.player = player
11                 self.network = network
12                 
13         def __str__(self):
14                 return "NetworkPlayer<"+str(self.colour)+","+str(self.player)+">"
15                 
16         def select(self):
17                 #debug(str(self) + " select called")
18                 if self.player != None:
19                         s = self.player.select()
20                         self.send_message(str(s[0]) + " " + str(s[1]))
21                 else:
22                         s = map(int, self.get_response().split(" "))
23                         for p in game.players:
24                                 if p != self and isinstance(p, NetworkPlayer) and p.player == None:
25                                         p.network.send_message(str(s[0]) + " " + str(s[1]))
26                 if s == [-1,-1]:
27                         game.final_result = "network terminate"
28                         game.stop()
29                 return s
30         
31         def send_message(self, message):
32                 #debug(str(self) + " send_message(\""+str(message)+"\") called")
33                 self.network.send_message(message)
34                 
35         def get_response(self):
36                 #debug(str(self) + " get_response() called")
37                 s = self.network.get_response()
38                 #debug(str(self) + " get_response() returns \""+str(s)+"\"")
39                 return s
40                         
41                         
42         def get_move(self):
43                 #debug(str(self) + " get_move called")
44                 if self.player != None:
45                         s = self.player.get_move()
46                         self.send_message(str(s[0]) + " " + str(s[1]))
47                 else:
48                         s = map(int, self.get_response().split(" "))
49                         for p in game.players:
50                                 if p != self and isinstance(p, NetworkPlayer) and p.player == None:
51                                         p.network.send_message(str(s[0]) + " " + str(s[1]))
52                                         
53                 if s == [-1,-1]:
54                         game.final_result = "network terminate"
55                         game.stop()
56                 return s
57         
58         def update(self, result):
59                 #debug(str(self) + " update(\""+str(result)+"\") called")
60                 if self.network.server == True:
61                         if self.player == None:
62                                 self.send_message(result)
63                 elif self.player != None:
64                         result = self.get_response()
65                         if result == "-1 -1":
66                                 game.final_result = "network terminate"
67                                 game.stop()
68                                 return "-1 -1"
69                         self.board.update(result, deselect=False)
70                 
71                 
72                 
73                 if self.player != None:
74                         result = self.player.update(result)
75                         
76                 return result
77                 
78                 
79         
80         def base_player(self):
81                 if self.player == None:
82                         return self
83                 else:
84                         return self.player.base_player()
85                 
86         def quit(self, result):
87                 try:
88                         self.send_message("-1 -1")
89                 except:
90                         pass
91
92 class Network():
93         def __init__(self, address = (None,4562)):
94                 self.socket = socket.socket()
95                 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
96                 #self.socket.setblocking(0)
97                 self.address = address
98                 self.server = (address[0] == None)
99                 
100                 
101                 self.connected = False
102                         
103         def connect(self):      
104                 #debug(str(self) + "Tries to connect")
105                 self.connected = True
106                 if self.address[0] == None:
107                         self.host = "0.0.0.0" #socket.gethostname() # Breaks things???
108                         self.socket.bind((self.host, self.address[1]))
109                         self.socket.listen(5)   
110
111                         self.src, self.actual_address = self.socket.accept()
112                         
113                         self.src.send("ok\n")
114                         s = self.get_response()
115                         if s == "QUIT":
116                                 self.src.close()
117                                 return
118                         elif s != "ok":
119                                 self.src.close()
120                                 self.__init__(colour, (self.address[0], int(s)), baseplayer)
121                                 return
122                         
123                 else:
124                         time.sleep(0.3)
125                         self.socket.connect(self.address)
126                         self.src = self.socket
127                         self.src.send("ok\n")
128                         s = self.get_response()
129                         if s == "QUIT":
130                                 self.src.close()
131                                 return
132                         elif s != "ok":
133                                 self.src.close()
134                                 self.__init__(colour, (self.address[0], int(s)), baseplayer)
135                                 return
136                         
137
138                 
139         def __str__(self):
140                 return "@network:"+str(self.address)
141
142         def get_response(self):
143                 
144                 # Timeout the start of the message (first character)
145                 if network_timeout_start > 0.0:
146                         ready = select.select([self.src], [], [], network_timeout_start)[0]
147                 else:
148                         ready = [self.src]
149                 if self.src in ready:
150                         s = self.src.recv(1)
151                 else:
152                         raise Exception("NET_UNRESPONSIVE")
153
154
155                 debug("Network get_response s = " + str(s))
156
157                 while s[len(s)-1] != '\n':
158                         # Timeout on each character in the message
159                         if network_timeout_delay > 0.0:
160                                 ready = select.select([self.src], [], [], network_timeout_delay)[0]
161                         else:
162                                 ready = [self.src]
163                         if self.src in ready:
164                                 s += self.src.recv(1) 
165                         else:
166                                 raise Exception("NET_UNRESPONSIVE")
167
168                 
169                 return s.strip(" \r\n")
170
171         def send_message(self,s):
172                 if network_timeout_start > 0.0:
173                         ready = select.select([], [self.src], [], network_timeout_start)[1]
174                 else:
175                         ready = [self.src]
176
177                 if self.src in ready:
178                         self.src.send(s + "\n")
179                 else:
180                         raise Exception("NET_UNRESPONSIVE")
181                 
182                 
183
184         def close(self):
185                 self.src.shutdown()
186                 self.src.close()

UCC git Repository :: git.ucc.asn.au