This URL has Read-Only access.

Statistics
| Branch: | Tag: | Revision:

root / py / maugis / scenic / communication.py @ 5f9ffd67

History | View | Annotate | Download (5.7 kB)

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# 
4
# Scenic
5
# Copyright (C) 2008 Société des arts technologiques (SAT)
6
# http://www.sat.qc.ca
7
# All rights reserved.
8
#
9
# This file is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 2 of the License, or
12
# (at your option) any later version.
13
#
14
# Scenic is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with Scenic. If not, see <http://www.gnu.org/licenses/>.
21

    
22
from scenic import sig
23
from scenic import sic
24
from twisted.internet import reactor
25
from twisted.internet import defer
26

    
27
class Server(object):
28
    """
29
    TCP receiver
30
    """
31
    def __init__(self, app, negotiation_port):
32
        self.port = negotiation_port
33
        self.server_factory = sic.ServerFactory()
34
        self.server_factory.dict_received_signal.connect(self.on_dict_received)
35
        self._port_obj = None
36
        self.remote_ip = None
37
        
38
        self.received_command_signal = sig.Signal()
39
        self.received_command_signal.connect(app.on_server_receive_command)
40
 
41
    def start_listening(self):
42
        if not self.is_listening():
43
            self._port_obj = reactor.listenTCP(self.port, self.server_factory)
44
            return self.server_factory.connected_deferred
45
        else:
46
            print "Already listening", "!!!!!!!!!!"  # FIXME
47
            return defer.succeed(True) #FIXME
48
    
49
    def on_dict_received(self, server_proto, d):
50
        print "Communication: received", d
51
        msg = d
52
        addr = server_proto.get_peer_ip()
53
        self.remote_ip = addr
54
        self.received_command_signal(msg, addr)
55

    
56
    def change_port(self, new_port):
57
        """
58
        Closes the server and starts it on an other port.
59
       """
60
        self.port = new_port
61
        def _on_closed(result):
62
            return self.start_listening()
63
        
64
        deferred = self.close()
65
        deferred.addCallback(_on_closed)
66
        return deferred
67

    
68
    def get_peer_ip(self):
69
        return self.remote_ip
70

    
71
    def close(self): # TODO: important ! 
72
        if self.is_listening():
73
            def _cb(result):
74
                self._port_obj = None
75
                return result
76
            d = self._port_obj.stopListening()
77
            d.addCallback(_cb)
78
            return d
79
        else:
80
            print "no server to close"
81
            return defer.succeed(True) # FIXME!!!
82

    
83
    def is_listening(self):
84
        return self._port_obj is not None
85
        
86
        
87

    
88
class Client(object):
89
    """
90
    TCP sender
91
    """
92
    def __init__(self, connection_error_handler):
93
        self.port = None
94
        self.host = None
95
        self.sic_sender = None
96
        self.clientPort = None
97
        
98
        self.connection_error_signal = sig.Signal()
99
        self.connection_error_signal.connect(connection_error_handler) # TODO
100
        
101
    def connect(self, host, port):
102
        """
103
        Connects and sends an INVITE message
104
        @rettype: L{Deferred}
105
        """
106
        def _on_connected(proto):
107
            print "connected"
108
            self.sic_sender = proto
109
            return proto
110
        
111
        def _on_error(reason):
112
            print "could not connect"
113
            self._connected = False
114
            self.sic_sender = None
115
            err = str(reason.getErrorMessage())
116
            msg = "Could not send to remote host."
117
            self.connection_error_signal(err, msg)
118
            return reason        
119

    
120
        if not self.is_connected():
121
            self.host = host
122
            self.port = port
123
            self.client_factory = sic.ClientFactory()
124
            print 'trying to connect'
125
            print self.host, self.port
126
            self.clientPort = reactor.connectTCP(self.host, self.port, self.client_factory)
127
            self.client_factory.connected_deferred.addCallback(_on_connected).addErrback(_on_error)
128
            return self.client_factory.connected_deferred
129
        else:
130
            msg = "client already connected to some host"
131
            print msg, "!!!!!!!!!!!!!!!"
132
            #TODO: return failure?
133
            return defer.succeed(True) # FIXME
134
   
135
 
136
    def send(self, msg):
137
        """
138
        @param msg: dict
139
        @rettype: None
140
        """
141
        if self.is_connected():
142
            self.sic_sender.send_message(msg)
143
        else:
144
            msg = "Not connected, cannot send message " + msg
145
            raise AssertionError(msg)
146
    
147
    def is_connected(self):
148
        return self.sic_sender is not None
149

    
150
    def disconnect(self):
151
        """
152
        @rettype: Deferred
153
        """
154
        if self.is_connected():
155
            d = self.clientPort.transport.loseConnection() # TODO: trigger a deffered when connection lost
156
            self.port = None
157
            self.sic_sender = None
158
            return defer.succeed(True)
159
        else:
160
            msg = "Not connected."
161
            return defer.succeed(True) # FIXME
162
            
163
def connect_send_and_disconnect(host, port, mess):
164
    d = defer.Deferred()
165
    def _on_connected(sic_sender):
166
        sic_sender.send_message(mess)
167
        clientPort.transport.loseConnection()
168
        d.callback(True)
169
    def _on_error(reason):
170
        print reason
171
        d.errback(reason)
172
        return None
173
    client_factory = sic.ClientFactory()
174
    print 'trying to connect to', host, port, 'to send message', mess
175
    clientPort = reactor.connectTCP(host, port, client_factory)
176
    client_factory.connected_deferred.addCallback(_on_connected).addErrback(_on_error)
177
    return d