This URL has Read-Only access.

Statistics
| Branch: | Tag: | Revision:

root / txosc / async.py @ 9167485b

History | View | Annotate | Download (5.2 kB)

1 9167485b Alexandre Quessy
#!/usr/bin/env python
2 9167485b Alexandre Quessy
# -*- test-case-name: txosc.test.test_async -*-
3 9167485b Alexandre Quessy
# Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse
4 9167485b Alexandre Quessy
# See LICENSE for details.
5 9167485b Alexandre Quessy
6 9167485b Alexandre Quessy
"""
7 9167485b Alexandre Quessy
Asynchronous implementation of OSC for Twisted
8 9167485b Alexandre Quessy
"""
9 9167485b Alexandre Quessy
import struct
10 9167485b Alexandre Quessy
11 9167485b Alexandre Quessy
from twisted.internet import defer, protocol
12 9167485b Alexandre Quessy
from twisted.application.internet import MulticastServer
13 9167485b Alexandre Quessy
from txosc.osc import *
14 9167485b Alexandre Quessy
from txosc.osc import _elementFromBinary
15 9167485b Alexandre Quessy
16 9167485b Alexandre Quessy
#
17 9167485b Alexandre Quessy
# Stream based client/server protocols
18 9167485b Alexandre Quessy
#
19 9167485b Alexandre Quessy
20 9167485b Alexandre Quessy
class StreamBasedProtocol(protocol.Protocol):
21 9167485b Alexandre Quessy
    """
22 9167485b Alexandre Quessy
    OSC over TCP sending and receiving protocol.
23 9167485b Alexandre Quessy
    """
24 9167485b Alexandre Quessy
25 9167485b Alexandre Quessy
    def connectionMade(self):
26 9167485b Alexandre Quessy
        self.factory.connectedProtocol = self
27 9167485b Alexandre Quessy
        if hasattr(self.factory, 'deferred'):
28 9167485b Alexandre Quessy
            self.factory.deferred.callback(True)
29 9167485b Alexandre Quessy
        self._buffer = ""
30 9167485b Alexandre Quessy
        self._pkgLen = None
31 9167485b Alexandre Quessy
32 9167485b Alexandre Quessy
33 9167485b Alexandre Quessy
    def dataReceived(self, data):
34 9167485b Alexandre Quessy
        """
35 9167485b Alexandre Quessy
        Called whenever data is received.
36 9167485b Alexandre Quessy

37 9167485b Alexandre Quessy
        In a stream-based protocol such as TCP, the stream should
38 9167485b Alexandre Quessy
        begin with an int32 giving the size of the first packet,
39 9167485b Alexandre Quessy
        followed by the contents of the first packet, followed by the
40 9167485b Alexandre Quessy
        size of the second packet, etc.
41 9167485b Alexandre Quessy

42 9167485b Alexandre Quessy
        @type data: L{str}
43 9167485b Alexandre Quessy
        """
44 9167485b Alexandre Quessy
        self._buffer += data
45 9167485b Alexandre Quessy
        if len(self._buffer) < 4:
46 9167485b Alexandre Quessy
            return
47 9167485b Alexandre Quessy
        if self._pkgLen is None:
48 9167485b Alexandre Quessy
            self._pkgLen = struct.unpack(">i", self._buffer[:4])[0]
49 9167485b Alexandre Quessy
        if len(self._buffer) < self._pkgLen + 4:
50 9167485b Alexandre Quessy
            print "waiting for %d more bytes" % (self._pkgLen + 4 - len(self._buffer))
51 9167485b Alexandre Quessy
            return
52 9167485b Alexandre Quessy
        payload = self._buffer[4:4 + self._pkgLen]
53 9167485b Alexandre Quessy
        self._buffer = self._buffer[4 + self._pkgLen:]
54 9167485b Alexandre Quessy
        self._pkgLen = None
55 9167485b Alexandre Quessy
56 9167485b Alexandre Quessy
        if payload:
57 9167485b Alexandre Quessy
            element = _elementFromBinary(payload)
58 9167485b Alexandre Quessy
            self.factory.gotElement(element)
59 9167485b Alexandre Quessy
60 9167485b Alexandre Quessy
        if len(self._buffer):
61 9167485b Alexandre Quessy
            self.dataReceived("")
62 9167485b Alexandre Quessy
63 9167485b Alexandre Quessy
64 9167485b Alexandre Quessy
    def send(self, element):
65 9167485b Alexandre Quessy
        """
66 9167485b Alexandre Quessy
        Send an OSC element over the TCP wire.
67 9167485b Alexandre Quessy
        @param element: L{txosc.osc.Message} or L{txosc.osc.Bundle}
68 9167485b Alexandre Quessy
        """
69 9167485b Alexandre Quessy
        binary = element.toBinary()
70 9167485b Alexandre Quessy
        self.transport.write(struct.pack(">i", len(binary)) + binary)
71 9167485b Alexandre Quessy
        #TODO: return a Deferred
72 9167485b Alexandre Quessy
73 9167485b Alexandre Quessy
74 9167485b Alexandre Quessy
75 9167485b Alexandre Quessy
class StreamBasedFactory(object):
76 9167485b Alexandre Quessy
    """
77 9167485b Alexandre Quessy
    Factory object for the sending and receiving of elements in a
78 9167485b Alexandre Quessy
    stream-based protocol (e.g. TCP, serial).
79 9167485b Alexandre Quessy

80 9167485b Alexandre Quessy
    @ivar receiver:  A L{Receiver} object which is used to dispatch
81 9167485b Alexandre Quessy
        incoming messages to.
82 9167485b Alexandre Quessy
    @ivar connectedProtocol: An instance of L{StreamBasedProtocol}
83 9167485b Alexandre Quessy
        representing the current connection.
84 9167485b Alexandre Quessy
    """
85 9167485b Alexandre Quessy
    receiver = None
86 9167485b Alexandre Quessy
    connectedProtocol = None
87 9167485b Alexandre Quessy
88 9167485b Alexandre Quessy
    def __init__(self, receiver=None):
89 9167485b Alexandre Quessy
        if receiver:
90 9167485b Alexandre Quessy
            self.receiver = receiver
91 9167485b Alexandre Quessy
92 9167485b Alexandre Quessy
93 9167485b Alexandre Quessy
    def send(self, element):
94 9167485b Alexandre Quessy
        self.connectedProtocol.send(element)
95 9167485b Alexandre Quessy
96 9167485b Alexandre Quessy
97 9167485b Alexandre Quessy
    def gotElement(self, element):
98 9167485b Alexandre Quessy
        if self.receiver:
99 9167485b Alexandre Quessy
            self.receiver.dispatch(element, self)
100 9167485b Alexandre Quessy
        else:
101 9167485b Alexandre Quessy
            raise OscError("Element received, but no Receiver in place: " + str(element))
102 9167485b Alexandre Quessy
103 9167485b Alexandre Quessy
    def __str__(self):
104 9167485b Alexandre Quessy
        return str(self.connectedProtocol.transport.client)
105 9167485b Alexandre Quessy
106 9167485b Alexandre Quessy
107 9167485b Alexandre Quessy
class ClientFactory(protocol.ClientFactory, StreamBasedFactory):
108 9167485b Alexandre Quessy
    """
109 9167485b Alexandre Quessy
    TCP client factory
110 9167485b Alexandre Quessy
    """
111 9167485b Alexandre Quessy
    protocol = StreamBasedProtocol
112 9167485b Alexandre Quessy
113 9167485b Alexandre Quessy
    def __init__(self, receiver=None):
114 9167485b Alexandre Quessy
        StreamBasedFactory.__init__(self, receiver)
115 9167485b Alexandre Quessy
        self.deferred = defer.Deferred()
116 9167485b Alexandre Quessy
117 9167485b Alexandre Quessy
118 9167485b Alexandre Quessy
class ServerFactory(protocol.ServerFactory, StreamBasedFactory):
119 9167485b Alexandre Quessy
    """
120 9167485b Alexandre Quessy
    TCP server factory
121 9167485b Alexandre Quessy
    """
122 9167485b Alexandre Quessy
    protocol = StreamBasedProtocol
123 9167485b Alexandre Quessy
124 9167485b Alexandre Quessy
125 9167485b Alexandre Quessy
#
126 9167485b Alexandre Quessy
# Datagram client/server protocols
127 9167485b Alexandre Quessy
#
128 9167485b Alexandre Quessy
129 9167485b Alexandre Quessy
class DatagramServerProtocol(protocol.DatagramProtocol):
130 9167485b Alexandre Quessy
    """
131 9167485b Alexandre Quessy
    The UDP OSC server protocol.
132 9167485b Alexandre Quessy

133 9167485b Alexandre Quessy
    @ivar receiver: The L{Receiver} instance to dispatch received
134 9167485b Alexandre Quessy
        elements to.
135 9167485b Alexandre Quessy
    """
136 9167485b Alexandre Quessy
137 9167485b Alexandre Quessy
    def __init__(self, receiver):
138 9167485b Alexandre Quessy
        """
139 9167485b Alexandre Quessy
        @param receiver: L{Receiver} instance.
140 9167485b Alexandre Quessy
        """
141 9167485b Alexandre Quessy
        self.receiver = receiver
142 9167485b Alexandre Quessy
143 9167485b Alexandre Quessy
    def datagramReceived(self, data, (host, port)):
144 9167485b Alexandre Quessy
        element = _elementFromBinary(data)
145 9167485b Alexandre Quessy
        self.receiver.dispatch(element, (host, port))
146 9167485b Alexandre Quessy
147 9167485b Alexandre Quessy
class MulticastDatagramServerProtocol(DatagramServerProtocol):
148 9167485b Alexandre Quessy
    """
149 9167485b Alexandre Quessy
    UDP OSC server protocol that can listen to multicast.
150 9167485b Alexandre Quessy
    
151 9167485b Alexandre Quessy
    Here is an example on how to use it:
152 9167485b Alexandre Quessy
    
153 9167485b Alexandre Quessy
      reactor.listenMulticast(8005, MulticastServerUDP(receiver, "224.0.0.1"), listenMultiple=True)
154 9167485b Alexandre Quessy
    
155 9167485b Alexandre Quessy
    This way, many listeners can listen on the same port, same host, to the same multicast group. (in this case, the 224.0.0.1 multicast group)
156 9167485b Alexandre Quessy
    """
157 9167485b Alexandre Quessy
    def __init__(self, receiver, multicast_addr="224.0.0.1"):
158 9167485b Alexandre Quessy
        """
159 9167485b Alexandre Quessy
        @param multicast_addr: IP address of the multicast group.
160 9167485b Alexandre Quessy
        @param receiver: L{txosc.dispatch.Receiver} instance.
161 9167485b Alexandre Quessy
        @type multicast_addr: str
162 9167485b Alexandre Quessy
        @type receiver: L{txosc.dispatch.Receiver}
163 9167485b Alexandre Quessy
        """
164 9167485b Alexandre Quessy
        self.multicast_addr = multicast_addr
165 9167485b Alexandre Quessy
        DatagramServerProtocol.__init__(self, receiver)
166 9167485b Alexandre Quessy
        
167 9167485b Alexandre Quessy
    def startProtocol(self):
168 9167485b Alexandre Quessy
        """
169 9167485b Alexandre Quessy
        Join a specific multicast group, which is the IP we will respond to
170 9167485b Alexandre Quessy
        """
171 9167485b Alexandre Quessy
        self.transport.joinGroup(self.multicast_addr)
172 9167485b Alexandre Quessy
173 9167485b Alexandre Quessy
class DatagramClientProtocol(protocol.DatagramProtocol):
174 9167485b Alexandre Quessy
    """
175 9167485b Alexandre Quessy
    The UDP OSC client protocol.
176 9167485b Alexandre Quessy
    """
177 9167485b Alexandre Quessy
178 9167485b Alexandre Quessy
    def send(self, element, (host, port)):
179 9167485b Alexandre Quessy
        """
180 9167485b Alexandre Quessy
        Send a L{txosc.osc.Message} or L{txosc.osc.Bundle} to the address specified.
181 9167485b Alexandre Quessy
        @type element: L{txosc.osc.Message}
182 9167485b Alexandre Quessy
        """
183 9167485b Alexandre Quessy
        data = element.toBinary()
184 9167485b Alexandre Quessy
        self.transport.write(data, (host, port))
185 9167485b Alexandre Quessy