Added basic implementation to gtpsocket, started to sketch out networkthread
This commit is contained in:
parent
da583678c1
commit
4f5227cd82
106
lib/gtpsocket.py
106
lib/gtpsocket.py
|
@ -1,29 +1,80 @@
|
||||||
# A class for communicating in Go Text Protocol
|
# A class for communicating in Go Text Protocol
|
||||||
#
|
#
|
||||||
# An already-connected socket should be passed in, then this class
|
# An already-connected socket should be passed in, then this class
|
||||||
# can be used to handle GTP simply
|
# can be used to handle some aspects of GTP simply
|
||||||
|
|
||||||
|
# Commands that any user of this class *must* support...
|
||||||
|
# quit
|
||||||
|
# boardsize
|
||||||
|
# clear_board
|
||||||
|
# komi
|
||||||
|
# play
|
||||||
|
# genmove
|
||||||
|
|
||||||
|
|
||||||
class GTPSocket:
|
class GTPSocket:
|
||||||
|
# By default the list only has commands we can handle internally in this class.
|
||||||
|
# Anything that uses this class should append any commands it can handle to this
|
||||||
|
# list. A common pattern would be:
|
||||||
|
#
|
||||||
|
# dispatcher = {'command1': function_1, 'command_2': function_2, 'command_3': function_3}
|
||||||
|
# gtp_socket = GTPSocket(socket)
|
||||||
|
# GTPSocket.known_cmds.extend(dispatcher.keys())
|
||||||
|
# gtp = gtp_socket.get()
|
||||||
|
# if gtp.type == 'command':
|
||||||
|
# dispatcher[gtp.command](gtp)
|
||||||
|
known_cmds = ['protocol_version', 'name', 'version', 'known_command', 'list_commands']
|
||||||
|
|
||||||
def __init__(self, socket):
|
def __init__(self, socket):
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.id = None
|
self.last_id = None
|
||||||
|
|
||||||
def get_gtp(self):
|
def get(self):
|
||||||
msg = None
|
msg = None
|
||||||
|
|
||||||
while msg is None:
|
while msg is None:
|
||||||
try:
|
try:
|
||||||
msg = self.socket.recv(1024)
|
msg = self.socket.recv(4096)
|
||||||
if not self._validate_gtp(msg):
|
if msg[0] == '?':
|
||||||
|
print "Error: GTP response: " + msg
|
||||||
|
return self._msg_to_response(msg)
|
||||||
|
elif msg[0] == '=':
|
||||||
|
return self._msg_to_response(msg)
|
||||||
|
elif not _validate_gtp(msg):
|
||||||
print 'Error: Incoming data was not a valid GTP message'
|
print 'Error: Incoming data was not a valid GTP message'
|
||||||
msg = None
|
msg = None
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
gtp = self._msg_to_gtp(msg)
|
||||||
|
|
||||||
def send_gtp(self, msg):
|
# Some gtp commands should be handled internally
|
||||||
|
if gtp.command == 'protocol_version':
|
||||||
|
self.send_response('2', gtp.id)
|
||||||
|
|
||||||
|
elif gtp.command == 'name':
|
||||||
|
self.send_response('pygo', gtp.id)
|
||||||
|
|
||||||
|
elif gtp.command == 'version':
|
||||||
|
self.send_response('', gtp.id)
|
||||||
|
|
||||||
|
elif gtp.command == 'known_command':
|
||||||
|
if gtp.arguments[0] in GTPSocket.known_cmds:
|
||||||
|
resp = 'true'
|
||||||
|
else:
|
||||||
|
resp = 'false'
|
||||||
|
self.send_response(resp, gtp.id)
|
||||||
|
|
||||||
|
elif gtp.command == 'list_commands':
|
||||||
|
self.send_response(''.join(GTPSocket.known_cmds, '\n'), gtp.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def send(self, msg):
|
||||||
try:
|
try:
|
||||||
|
msg = str(self.last_id + 1) + ' ' + msg + "\n"
|
||||||
if _validate_gtp(msg):
|
if _validate_gtp(msg):
|
||||||
|
self.last_id += 1
|
||||||
self.socket.send(msg)
|
self.socket.send(msg)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
@ -33,5 +84,46 @@ class GTPSocket:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _validate_gtp(self, gtp):
|
def send_response(self, msg, resp_id=None, is_error=False):
|
||||||
|
try:
|
||||||
|
to_send = ''
|
||||||
|
if is_error:
|
||||||
|
to_send += '?'
|
||||||
|
else:
|
||||||
|
to_send += '='
|
||||||
|
|
||||||
|
if resp_id is not None:
|
||||||
|
to_send += str(resp_id)
|
||||||
|
|
||||||
|
to_send += msg + "\n\n"
|
||||||
|
self.socket.send(to_send)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _msg_to_gtp(self, msg):
|
||||||
|
gtp = Object()
|
||||||
|
data = msg.split(' ')
|
||||||
|
gtp.type = 'message'
|
||||||
|
gtp.id = int(data[0])
|
||||||
|
gtp.command = data[1]
|
||||||
|
|
||||||
|
if len(data) > 2:
|
||||||
|
gtp.arguments = data[2:]
|
||||||
|
|
||||||
|
return gtp
|
||||||
|
|
||||||
|
|
||||||
|
def _msg_to_response(self, msg):
|
||||||
|
resp = Object()
|
||||||
|
resp.type = 'response'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# For now, we *require* our messages to have an id.
|
||||||
|
# This violates the protocol, but we'll deal with the
|
||||||
|
# more complicated case later.
|
||||||
|
def _validate_gtp(msg):
|
||||||
|
return re.match(r'\d+?\s+\w+?', msg)
|
||||||
|
|
33
lib/networkthread.py
Normal file
33
lib/networkthread.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# This class implements a thread that handles the networking connection.
|
||||||
|
# It expects a copy of the board and an open socket to the remote host, which
|
||||||
|
# it will bind to a GTPSocket.
|
||||||
|
# This is the only thread that should be calling get(), but send() could be called
|
||||||
|
# twice, so we wrap it in a mutex.
|
||||||
|
# The board is also wrapped in a mutex, even though only this thread should modify it
|
||||||
|
# if it exists.
|
||||||
|
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkThread(threading.Thread):
|
||||||
|
dispatcher = {
|
||||||
|
'quit': None,
|
||||||
|
'boardsize': None,
|
||||||
|
'clear_board': None,
|
||||||
|
'komi': None,
|
||||||
|
'play': None,
|
||||||
|
'genmove': None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, goban, socket):
|
||||||
|
self.goban = goban
|
||||||
|
self.goban_lock = threading.Lock()
|
||||||
|
self.socket = GTPSocket(socket)
|
||||||
|
self.send_lock = threading.Lock()
|
||||||
|
|
||||||
|
GTPSocket.known_cmds.extend(dispatcher.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user