-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinterfaces.py
233 lines (218 loc) · 8.77 KB
/
interfaces.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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# -*- coding: utf-8 -*-
import time, threading, string
from OSC import OSCClient, OSCMessage, OSCServer, getUrlStr, OSCClientError
from Queue import Queue
def runPrototype(prot):
try:
time.sleep(1)
prot.setup()
while True:
## keep it from looping faster than ~60 times per second
loopStart = time.time()
prot._checkLocalNet()
prot.loop()
loopTime = time.time()-loopStart
if (loopTime < 0.017):
time.sleep(0.017 - loopTime)
except KeyboardInterrupt:
prot._cleanUpOsc()
prot.stop()
class PrototypeInterface:
""" prototype interface:
all prototypes must implement setup() and loop() functions
self.messageQ will have all messages coming in from LocalNet
in the format (locale,type,text)
this also implements subscribeToAll() and subscribeTo(name) """
def removeNonAscii(self, s):
return "".join(i for i in s if i in string.printable)
def removeAccents(self,txt):
## hack! sanitize text
txt = txt.replace("#","")
##
txt = txt.replace("á","aa")
txt = txt.replace("é","ee")
txt = txt.replace("í","ii")
txt = txt.replace("ó","oo")
txt = txt.replace("ú","uu")
txt = txt.replace("ñ","ni")
##
txt = txt.replace("Á","aa")
txt = txt.replace("É","ee")
txt = txt.replace("Í","ii")
txt = txt.replace("Ó","oo")
txt = txt.replace("Ú","uu")
txt = txt.replace("Ñ","ni")
return txt
def _oscHandler(self, addr, tags, stuff, source):
addrTokens = addr.lstrip('/').split('/')
## list of all receivers
if ((addrTokens[0].lower() == "localnet")
and (addrTokens[1].lower() == "receivers")):
## as good, if not better than a ping
self.lastPingTime = time.time()
for rcvr in stuff[0].split(','):
self.allReceivers[rcvr] = rcvr
if(self.subscribedToAll and not self.subscribedReceivers):
self.subscribeToAll()
## actual message from AEffect Network !!
elif (addrTokens[0].lower() == "aeffectlab"):
self.messageQ.put((addrTokens[1],
addrTokens[2],
stuff[0].decode('utf-8')))
## ping
if ((addrTokens[0].lower() == "localnet")
and (addrTokens[1].lower() == "ping")):
self.lastPingTime = time.time()
def _checkLocalNet(self):
## clear receivers to force a localNet check
if(time.time()-self.lastPingTime > 45):
self.allReceivers = {}
if((not self.allReceivers)
and (time.time() - self.lastLocalNetConnectionAttempt > 10)):
self.lastLocalNetConnectionAttempt = time.time()
## request list of all receivers from localnet
msg = OSCMessage()
msg.setAddress("/LocalNet/ListReceivers")
msg.append(self.inPort)
try:
self.oscClient.connect(self.localNetAddress)
self.oscClient.sendto(msg,self.localNetAddress)
self.oscClient.connect(self.localNetAddress)
except OSCClientError:
print "no connection to %s:%s, can't request list of receivers"%(self.localNetAddress)
def __init__(self,inip,inport,outip,outport):
## administrative: names and ports
self.messageQ = Queue()
self.inIp = inip
self.inPort = inport
self.localNetAddress = (outip,outport)
self.name = self.__class__.__name__.lower()
self.allReceivers = {}
self.subscribedReceivers = {}
self.subscribedToAll = False
self.lastPingTime = time.time()
self.lastLocalNetConnectionAttempt = time.time()
## setup osc client
self.oscClient = OSCClient()
self.oscClient.connect(self.localNetAddress)
## setup osc receiver
self.oscServer = OSCServer((self.inIp, self.inPort))
self.oscServer.addMsgHandler('default', self._oscHandler)
self.oscThread = threading.Thread(target = self.oscServer.serve_forever)
self.oscThread.start()
## request list of all receivers from localnet
self._checkLocalNet()
def _cleanUpOsc(self):
## disconnect from LocalNet
for rcvr in self.subscribedReceivers.keys():
msg = OSCMessage()
msg.setAddress("/LocalNet/Remove/"+rcvr)
msg.append(self.inPort)
try:
self.oscClient.connect(self.localNetAddress)
self.oscClient.sendto(msg,self.localNetAddress)
self.oscClient.connect(self.localNetAddress)
except OSCClientError:
print "no connection to %s:%s, can't disconnect from receivers"%(self.localNetAddress)
## close osc
self.oscServer.close()
self.oscThread.join()
def subscribeToAll(self):
self.subscribedToAll = True
for rcvr in self.allReceivers.keys():
if(not rcvr.lower().startswith('osc')):
self.subscribeTo(rcvr)
def subscribeTo(self,rcvr):
msg = OSCMessage()
msg.setAddress("/LocalNet/Add/"+self.name+"/"+rcvr)
msg.append(self.inPort)
try:
self.oscClient.connect(self.localNetAddress)
self.oscClient.sendto(msg,self.localNetAddress)
self.oscClient.connect(self.localNetAddress)
except OSCClientError:
print "no connection to %s:%s, can't subscribe to %s receiver"%(self.localNetAddress, rcvr)
else:
self.subscribedReceivers[rcvr] = rcvr
def setup(self):
print "setup not implemented"
def loop(self):
print "loop not implemented"
def stop(self):
print "stop not implemented"
class MessageReceiverInterface:
"""A message receiver interface"""
# Sets up the stuff a receiver might need
def __init__(self):
self.subscriberList = []
self.name = ""
self.lastMessageTime = time.time()
def setup(self, db, osc, loc):
print "setup not implemented"
# Checks for new messages
def update(self):
print "update not implemented"
# Clean up
def stop(self):
print "stop not implemented"
# Adds a new subscriber to a receiver
def addSubscriber(self, (ip,port)):
if(not (ip,int(port)) in self.subscriberList):
self.subscriberList.append((ip,int(port)))
# Removes subscriber from receiver
def removeSubscriber(self, (ip,port)):
if((ip,int(port)) in self.subscriberList):
self.subscriberList.remove((ip,int(port)))
# Checks if it has specific subscriber
def hasSubscriber(self, (ip,port)):
return ((ip,port) in self.subscriberList)
# Prepare OSC message and send it to all subscribers
def sendToAllSubscribers(self, txt, addr=None):
if (addr is None):
addr = "/AEffectLab/"+self.location['name']+"/"+self.name
## setup osc message
msg = OSCMessage()
msg.setAddress(addr)
## Send utf-8 byte blob
msg.append(txt.encode('utf-8'), 'b')
## send to subscribers
self._sendToAllSubscribers(msg)
## update timer
self.lastMessageTime = time.time()
# Prepare OSC message to send to specific subscriber
def sendToSubscriber(self, ip,port, txt):
addr = "/AEffectLab/"+self.location['name']+"/"+self.name
## setup osc message
msg = OSCMessage()
msg.setAddress(addr)
## Send utf-8 byte blob
msg.append(txt.encode('utf-8'), 'b')
## send to subscriber
self._sendToSubscriber(msg,ip,port)
## update timer
self.lastMessageTime = time.time()
# Sends OSC msg to all subscribers
def _sendToAllSubscribers(self, oscMsg):
delQ = Queue()
for (ip,port) in self.subscriberList:
try:
self.oscClient.connect((ip, port))
self.oscClient.sendto(oscMsg, (ip, port))
self.oscClient.connect((ip, port))
except OSCClientError:
print ("no connection to "+ip+":"+str(port)
+", removing it from osc subscribers")
delQ.put((ip,port))
continue
while (not delQ.empty()):
self.removeSubscriber(delQ.get())
# Send OSC to specific subscriber
def _sendToSubscriber(self,msg,ip,port):
try:
self.oscClient.connect((ip, port))
self.oscClient.sendto(msg, (ip, port))
self.oscClient.connect((ip, port))
except OSCClientError:
print ("no connection to "+ip+":"+str(port)
+", removing it from osc subscribers")
self.removeSubscriber((ip,port))