source: remote_control/puzzlebox_brainstorms_client.py @ 57

Last change on this file since 57 was 48, checked in by sc, 11 years ago

client:

  • Switched to JSON from Pickle for message encodings
  • Fixed but with command line client not respecting custom server host/port settings

configuration.ini:

  • thinkgear server settings added

configuration.py

  • thinkgear server settings added

server:

  • Switched to JSON from Pickle for message encodings

client_thinkgear:

File size: 7.7 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Client
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10#
11# Last Update: 2010.06.16
12#
13#####################################################################
14
15import os, sys
16#import cPickle as pickle
17import simplejson as json
18
19from twisted.internet import reactor, protocol, defer
20
21import puzzlebox_brainstorms_configuration as configuration
22#import puzzlebox_logger
23
24#####################################################################
25# Globals
26#####################################################################
27
28DEBUG = 1
29
30SERVER_HOST = configuration.SERVER_HOST
31SERVER_PORT = configuration.SERVER_PORT
32
33MAX_CONNECTION_ATTEMPTS = configuration.MAX_CONNECTION_ATTEMPTS
34NO_REPLY_WAIT = configuration.NO_REPLY_WAIT
35
36#####################################################################
37# Classes
38#####################################################################
39
40class puzzlebox_brainstorms_client:
41       
42        def __init__(self, log, \
43                          server_host, \
44                          server_port, \
45                          max_connection_attempts = MAX_CONNECTION_ATTEMPTS):
46               
47                self.log = log
48                self.server_host = server_host
49                self.server_port = server_port
50                self.max_connection_attempts = max_connection_attempts
51       
52       
53        ##################################################################
54       
55        def send_command(self, \
56                         command, \
57                         max_connection_attempts=MAX_CONNECTION_ATTEMPTS):
58               
59                factory = puzzlebox_brainstorms_client_send_command_factory(self.log, \
60                                                       command, \
61                                                       self.server_host, \
62                                                       self.server_port, \
63                                                       max_connection_attempts, \
64                                                       self.DEBUG)
65               
66                reactor.connectTCP(self.server_host, self.server_port, factory)
67               
68                return factory.replyDefer
69
70
71#####################################################################
72# Client Protocol class
73#####################################################################
74
75class puzzlebox_brainstorms_client_send_command_protocol(protocol.Protocol):
76       
77        def __init__(self):
78               
79                self.DEBUG = DEBUG
80                self.data_chunk = ""
81       
82       
83        ##################################################################
84       
85        def connectionMade(self):
86               
87                #data = pickle.dumps(self.factory.command)
88                data = json.dumps(self.factory.command)
89                self.transport.write(data)
90               
91                self.factory.noReply = reactor.callLater(NO_REPLY_WAIT, self.noReply)
92       
93       
94        ##################################################################
95       
96        def noReply(self):
97               
98                try:
99                        self.factory.replyDefer.callback('NO_REPLY')
100                except:
101                        if self.DEBUG:
102                                print "noReply failed to call callback"
103                        #self.factory.log.error("noReply failed to call callback")
104               
105                self.transport.loseConnection()
106       
107       
108        ##################################################################
109       
110        def dataReceived(self, data):
111               
112                try:
113                        self.factory.noReply.cancel()
114                except:
115                        if self.DEBUG:
116                                print "dataReceived after noReply triggered (or cancelled)"
117                        #self.factory.log.error("dataReceived after noReply triggered (or cancelled)")
118               
119                self.data_chunk += data
120               
121                try:
122                        #reply = pickle.loads(self.data_chunk)
123                        reply = json.loads(self.data_chunk)
124                except Exception, e:
125                        if self.DEBUG:
126                                print "Partial data received (or error: %s)." % e
127                        #self.factory.log.error("Partial data received (or error: %s)." % e)
128                else:
129                        self.data_chunk = ""
130                       
131                        try:
132                                self.factory.replyDefer.callback(reply)
133                        except:
134                                if self.DEBUG:
135                                        print "dataReceived failed to call callback"
136                                #self.factory.log.error("dataReceived failed to call callback")
137                                pass
138                       
139                        self.transport.loseConnection()
140
141
142#####################################################################
143# Client Factory class
144#####################################################################
145
146class puzzlebox_brainstorms_client_send_command_factory(protocol.ClientFactory):
147       
148        def __init__(self, log, \
149                     command, \
150                     server_host=SERVER_HOST, \
151                     server_port=SERVER_PORT, \
152                     max_connection_attempts=MAX_CONNECTION_ATTEMPTS, \
153                     DEBUG=DEBUG):
154               
155                self.log = log
156                self.DEBUG = DEBUG
157                self.server_host = server_host
158                self.server_port = server_port
159                self.command = command
160               
161                self.max_connection_attempts = max_connection_attempts
162                self.connection_attempt = 1
163               
164                self.protocol = \
165                   puzzlebox_brainstorms_client_send_command_protocol
166               
167                self.replyDefer = defer.Deferred()
168       
169       
170        ##################################################################
171       
172        def clientConnectionFailed(self, connector, reason):
173               
174                if self.DEBUG:
175                        print "Client failed to connect to remote component at %s:%i" % \
176                           (self.server_host, self.server_port)
177               
178                reply = 'FAILED_TO_CONNECT'
179               
180                self.connection_attempt = self.connection_attempt + 1
181               
182                if ((self.max_connection_attempts == None) or \
183                         (self.connection_attempt <= self.max_connection_attempts)):
184                       
185                        # If connection failed retry after one second
186                        reactor.callLater(1, connector.connect)
187               
188                else:
189                        if self.DEBUG:
190                                print "Maximum connection retries reached, aborting"
191                       
192                       
193                        self.replyDefer.callback(reply)
194       
195       
196        ##################################################################
197       
198        def clientConnectionLost(self, connector, reason):
199               
200                # Losing Connection is expected after data exchange is complete
201                try:
202                        self.replyDefer.callback(reason)
203                except:
204                        pass
205
206
207#####################################################################
208# Command line class
209#####################################################################
210
211class puzzlebox_brainstorms_client_command_line(puzzlebox_brainstorms_client):
212       
213        def __init__(self, log, \
214                          command_parameters, \
215                          server_host=SERVER_HOST, \
216                          server_port=SERVER_PORT, \
217                          DEBUG=DEBUG):
218               
219                self.log = log
220                self.DEBUG=DEBUG
221               
222                self.command_parameters = command_parameters
223                self.server_host = server_host
224                self.server_port = server_port
225                self.max_connection_attempts = MAX_CONNECTION_ATTEMPTS
226       
227       
228        ##################################################################
229       
230        def execute_command_line(self):
231               
232                (command) = self.parse_command_line(self.command_parameters)
233               
234                d = self.send_command(command)
235                d.addCallback(self.print_response_and_stop)
236       
237       
238        ##################################################################
239       
240        def print_response_and_stop(self, response):
241               
242                if self.DEBUG:
243                        print "---> [Client] Server Response:",
244                        print response
245               
246                try:
247                        reactor.stop()
248                except:
249                        print "ERROR: Can't stop reactor that isn't running."
250       
251       
252        ##################################################################
253       
254        def parse_command_line(self, command_parameters):
255               
256                try:
257                        command = command_parameters[0]
258                except:
259                        command = None
260               
261               
262                return(command)
263
264
265#####################################################################
266# Main
267#####################################################################
268
269if __name__ == '__main__':
270       
271        #log = puzzlebox_logger.puzzlebox_logger(logfile='client')
272        log = None
273       
274        command_parameters = sys.argv[1:]
275       
276        #log.info("Command parameters: %s" % command_parameters)
277       
278        client = puzzlebox_brainstorms_client_command_line(log, \
279                                                           command_parameters, \
280                                                           server_host=SERVER_HOST, \
281                                                           server_port=SERVER_PORT, \
282                                                           DEBUG=DEBUG)
283       
284        reactor.callWhenRunning(client.execute_command_line)
285        reactor.run()
286
Note: See TracBrowser for help on using the repository browser.