Skip to content

Commit 70ba699

Browse files
committed
added poll option in connect(). receive() now returns None when connection is terminated
1 parent ca39989 commit 70ba699

File tree

1 file changed

+41
-24
lines changed

1 file changed

+41
-24
lines changed

scratch.py

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,37 @@ class Scratch:
1717
def __init__(self, host='localhost'):
1818
self.host= host
1919
self.port = 42001
20-
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
21-
self.connect()
20+
self.connect(poll=True)
2221
self.connected = 1
23-
def connect(self):
24-
try:
25-
self.connection.connect((self.host, self.port))
26-
except socket.error as (err, message):
27-
if err == errno.ECONNREFUSED:
28-
raise ScratchConnectionRefused('Connection refused, try enabling remote sensor connections')
29-
elif err == errno.EISCONN:
22+
23+
def connect(self, poll=False):
24+
"""
25+
Creates a connection to the Scratch environment. If poll is True, blocks until
26+
Scratch is running, and listening for connections on port 42001, else connect()
27+
raises appropiate exceptions.
28+
"""
29+
while True:
30+
try:
31+
# create the socket here not in __init__() to avoid errno 22 invalid argument
32+
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
33+
self.connection.connect((self.host, self.port))
34+
except socket.error as (err, message):
35+
if err == errno.EISCONN:
3036
raise ScratchConnectionEstablished('Already connected to Scratch')
37+
elif poll == True:
38+
continue
39+
elif err == errno.ECONNREFUSED:
40+
raise ScratchConnectionRefused('Connection refused, try enabling remote sensor connections')
3141
else:
3242
print(err, message)
3343
raise ScratchConnectionError(message)
44+
break
3445
self.connected = 1
46+
3547
def disconnect(self):
3648
self.connection.close()
3749
self.connected = 0
50+
3851
def send(self, message):
3952
#credit to chalkmarrow from scratch.mit.edu
4053
n = len(message)
@@ -50,6 +63,7 @@ def send(self, message):
5063
raise ScratchConnectionError(message)
5164
else:
5265
raise ScratchConnectionError('Not connected to Scratch')
66+
5367
def sensorupdate(self, data):
5468
"""Takes a dictionary and writes a message using the keys as sensors, and the values as the update values"""
5569
if not isinstance(data, dict):
@@ -58,6 +72,7 @@ def sensorupdate(self, data):
5872
for key in data.keys():
5973
message = message+' "'+key+'" '+data[key]
6074
self.send(message)
75+
6176
def broadcast(self, data):
6277
"""Takes a list of message strings and writes a broadcast message to scratch"""
6378
if not isinstance(data, list):
@@ -66,8 +81,10 @@ def broadcast(self, data):
6681
for mess in data:
6782
message = message+' "'+mess+'"'
6883
self.send(message)
84+
6985
def parse_message(self, message):
7086
#TODO: parse sensorupdates with quotes in sensor names and values
87+
# make more readable
7188
if message:
7289
sensorupdate_re = 'sensor-update[ ](((?:\").[^\"]*(?:\"))[ ](?:\"|)(.[^\"]*)(?:\"|)[ ])+'
7390
broadcast_re = 'broadcast[ ]\".[^"]*\"'
@@ -87,7 +104,8 @@ def parse_message(self, message):
87104
if sensorupdates[i][-1] != '\"':
88105
j = i
89106
multisense = ''
90-
#now loop through each word in list and find the word that ends with " which is the end of the variable name
107+
#now loop through each word in list and find the word
108+
#that ends with " which is the end of the variable name
91109
while j < len(sensorupdates):
92110
multisense = multisense+' '+sensorupdates[j]
93111
if sensorupdates[j][-1] == '\"':
@@ -114,32 +132,31 @@ def parse_message(self, message):
114132
return dict([('sensor-update', sensors), ('broadcast', broadcast)])
115133
else:
116134
return None
135+
117136
def receive(self, noparse=0):
118137
""" Receives data from Scratch
119138
Arguments:
120-
Optional:
121-
noparse -- 0 to pass message through a parser and return the message as a data structure
122-
1 to not parse message, but format as a string
123-
2 to not parse message and not format as a string (returns raw message)
139+
noparse: 0 to pass message through a parser and return the message as a data structure
140+
1 to not parse message, but format as a string
141+
2 to not parse message and not format as a string (returns raw message)
124142
"""
125-
126-
try:
127-
mess = self.connection.recv(1024)
128-
except socket.error as (errno, message):
129-
if errno == 107 or 9:
130-
raise ScratchConnectionError(errno, 'A connection must first be made to Scratch with Scratch.connect()')
131-
else:
132-
raise ScratchConnectionError(errno, message)
143+
try:
144+
mess = self.connection.recv(1024)
145+
except socket.error as (errno, message):
146+
raise ScratchConnectionError(errno, message)
147+
if not mess:
148+
return None
133149
if noparse == 0:
134150
return self.parse_message(repr(mess))
135-
if noparse == 1:
151+
if noparse == 1:
136152
return repr(mess)
137153
elif noparse == 2:
138-
return mess
154+
return mess
139155
else:
140156
return self.parse_message(repr(mess))
141157

142158
if __name__ == "__main__":
159+
#runs and prints out raw messages received from Scratch
143160
try:
144161
s = Scratch()
145162
except ScratchConnectionError, e:

0 commit comments

Comments
 (0)