source: trunk/src/testing/ui/sageGateBase.py @ 4

Revision 4, 27.7 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1############################################################################
2#
3# SAGE UI - A Graphical User Interface for SAGE
4# Copyright (C) 2005 Electronic Visualization Laboratory,
5# University of Illinois at Chicago
6#
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions are met:
11#
12#  * Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14#  * Redistributions in binary form must reproduce the above
15#    copyright notice, this list of conditions and the following disclaimer
16#    in the documentation and/or other materials provided with the distribution.
17#  * Neither the name of the University of Illinois at Chicago nor
18#    the names of its contributors may be used to endorse or promote
19#    products derived from this software without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32#
33# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
34#
35# Author: Ratko Jagodic
36#       
37############################################################################
38
39
40
41
42"""
43        SAGE UI --> SAGE
44        ---------------------------     
45        Register                        1000
46        Execute                         1001
47        Shutdown                        1002
48        Move                            1003
49        Resize                          1004
50        Start Performance               1005
51        Stop Performance                1006
52        BackColor                       1007
53        Bring to Front                  1010
54        App Properties Change           1011
55        App Frame Rate Change           1012
56        Stream Request                  1014
57        Rotate Window                   1018
58        SAGE Shutdown                   1100
59        Add Object                      1200
60        Move Object                     1201
61        Remove Object                   1202
62        Object Message                  1203
63        Show Object                     1204
64        Hide Object                     1205
65       
66
67        SAGE ----> SAGE UI
68        --------------------------
69        Status                          40000
70        App Info                        40001 APPID L R T B SAIL-ID
71        Performance                     40002
72        App Shutdown                    40003
73        Display Info                    40004
74        Z Order Change                  40005
75        App Exec Config                 40006
76        Display Connections             40007
77        Overlay Object Info             40018
78       
79
80        STORE INFORMATION
81"""
82
83
84from threading import Thread, RLock
85import socket, sys, string, os.path, xmlrpclib, time
86import traceback as tb
87from globals import *
88
89
90### GLOBALS ###
91
92TIMEOUT_INTERVAL = 0.5
93BLANK = ' '
94HEADER_ITEM_LEN = 8
95APP_LAUNCHER_PORT = 19010  #the default port, usually retrieved from the sage server though
96SAGE_SERVER_PORT = 8009  #the xmlrpc port of the sage server
97
98
99
100class AppLauncher:
101
102    def __init__(self, launcherId, name, ip, port, appList):
103        self.port = port
104        self.appList = appList
105        self.ip = ip
106        self.launcherId = launcherId
107        self.name = name
108        self.connected = False
109
110
111    def connect(self):
112        if not self.connected:
113            socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
114            self.server = xmlrpclib.ServerProxy("http://" + self.ip + ":" + str(self.port))
115            try:
116                self.server.test() #just use this as a way of testing whether the server is running or not
117                self.connected = True
118            except socket.error:
119                return False
120            except:
121                tb.print_exc()
122                return False
123        return True
124
125
126    def getId(self):
127        return self.launcherId
128
129    def getIP(self):
130        return self.ip
131
132    def getAppList(self):
133        return self.appList
134
135    def setAppList(self, appList):
136        self.appList = appList
137
138    def getPort(self):
139        return self.port
140
141    def getName(self):
142        return self.name
143   
144    def getServerHandle(self):
145        self.connect()
146        return self.server
147
148
149
150
151
152
153####################################################################
154#
155# DESCRIPTION: This is the base class for communication with SAGE.
156#              You need to inherit from this class and override
157#              the "onMessage" method. You can use the registerCallbackFunction
158#              and the hashCallbackFunction to store your callbacks
159#              and then retrieve them from your overridden onMessage.
160#
161# DATE: Aug, 2007
162#
163####################################################################
164
165class SageGateBase:
166       
167    def __init__(self, sageServerHost="sage.sl.startap.net", useAppLauncher=False, forceAppLauncher=None, onDisconnect=None, verbose=False):
168        self.hashCallbackFunction = {}
169        self.threadkilled = False
170        self.connected = False
171        self.sageHost = None
172        self.sagePort = 20001
173        self.forceAppLauncher = forceAppLauncher         # use this appLauncher if specified
174        self.useAppLauncher = useAppLauncher   # should we use the appLauncher at all?
175        self.onDisconnect = onDisconnect       # call this function if disconnected
176        self.verbose = verbose                 # print the output?
177        self.sageServerHost = sageServerHost           # where the sage server is running
178        self.launchers={}                      # a hash of appLaunchers currently running
179
180        # used for printing out informative messages (on sending and receiving)
181        self.hashOutgoingMessages = {} 
182        self.hashOutgoingMessages[1000] = "Register UI"
183        self.hashOutgoingMessages[1001] = "App Start"
184        self.hashOutgoingMessages[1002] = "App Shutdown"
185        self.hashOutgoingMessages[1003] = "Move"
186        self.hashOutgoingMessages[1004] = "Resize"
187        self.hashOutgoingMessages[1005] = "Request Performance"
188        self.hashOutgoingMessages[1006] = "Stop Performance"
189        self.hashOutgoingMessages[1007] = "Background Color"
190        self.hashOutgoingMessages[1010] = "Bring To Front"
191        self.hashOutgoingMessages[1011] = "App Properties Change"
192        self.hashOutgoingMessages[1012] = "App Frame Rate Change"
193        self.hashOutgoingMessages[1014] = "Stream Request"
194        self.hashOutgoingMessages[1018] = "Rotate Window"
195        self.hashOutgoingMessages[1200] = "Add Object"
196        self.hashOutgoingMessages[1201] = "Move Object"
197        self.hashOutgoingMessages[1202] = "Remove Object"
198        self.hashOutgoingMessages[1203] = "Object Message"
199        self.hashOutgoingMessages[1100] = "Shutdown"
200
201        self.hashIncomingMessages = {}
202        self.hashIncomingMessages[40000] = "SAGE Status Message"
203        self.hashIncomingMessages[40001] = "App Info Return"
204        self.hashIncomingMessages[40002] = "Performance Info"
205        self.hashIncomingMessages[40003] = "App Shutdown"
206        self.hashIncomingMessages[40004] = "Display Info"
207        self.hashIncomingMessages[40005] = "Z Change"
208        self.hashIncomingMessages[40006] = "App Exec Config"
209        self.hashIncomingMessages[40007] = "Display Connections"
210        self.hashIncomingMessages[40018] = "Overlay Object Info"
211
212
213
214    def makemsg(self,dst,code,appcode,size,data):
215        # assemble the message into a string
216        msg = '%8s\0%8s\0%8s\0%s\0' %(dst,code,appcode,data)
217        size = len(msg) + 9
218        msg = '%8s\0%s' %(size,msg)
219
220        # print the output if requested
221        if self.verbose and int(code) < 1200:  # dont print the draw object messages cause there are many of them
222            print "\n\tSEND:  " + self.hashOutgoingMessages[int(code)]
223            print "\t       [" + data + "]\n\n"
224           
225        return msg     
226
227
228    def connectToAppLauncher(self, host=socket.gethostname()):
229        socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
230        if self.forceAppLauncher:    # overriding with the one from the command line
231            self.appLauncher = xmlrpclib.ServerProxy("http://"+self.forceAppLauncher)
232        else:                         # try to find the appropriate app launcher
233            self.appLauncher = self.__getMyAppLauncher(host)
234            if type(self.appLauncher) is type(None):  # in case we couldn't find one, just assume it's running
235                self.appLauncher = xmlrpclib.ServerProxy("http://" + host + ":" + str(APP_LAUNCHER_PORT))
236
237        # now test the connection
238        try:
239            self.appLauncher.listMethods() #just use this as a way of testing whether the server is running or not
240        except socket.error:
241            return False
242        except:
243            pass
244        return True
245
246
247    def getPort(self):
248        return self.sagePort
249
250    def getHost(self):
251        return self.sageHost
252
253
254    ################################################################## 
255    #  Connect To Sage
256    ################################################################## 
257    def connectToSage(self,host=socket.gethostname(),port=20001):
258        ''' returns 1 if succeeded, 0 if no connection to SAGE and -1 if no connection to appLauncher'''
259        if self.connected == True: return 0
260
261        ## create socket
262        self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
263        if self.sock is None: return 0
264
265
266        #### RJ 2005-01-21
267        # without this, this thread will never exit because sock.recv is blocking and it will wait until
268        # something comes in. What happens is, "while" checks if threadkilled is false, it is so it goes
269        # in here and blocks until something is received. In the meantime, we want to quit so we set
270        # threadkilled to True but since we are blocked by sock.recv, we wont be able to get to the "while" again
271        self.sock.settimeout(TIMEOUT_INTERVAL)
272       
273
274        if host: self.sageHost = host
275        if port > 0: self.sagePort = port
276        ## connect
277        try:
278            self.sock.connect((host,port))
279        except socket.error:
280            print 'can\'t connect to SAGE', self.sageHost,self.sagePort
281            return 0
282
283        ##### FOR Thread
284        self.threadkilled = False
285        self.senderLock = RLock()
286        self.t = Thread(target=self.receiverThread,args=())
287        self.t.start()
288        self.connected = True
289
290        # start the overlay sender thread
291        self.overlayMsgLock = RLock()
292        self.overlayMsgQueue = []   # combined overlay messages (list of string messages)
293        self.overlayMsgFreq = 50    # send messages roughly 50 times a sec
294        self.overlaySender = Thread(target=self.overlaySenderThread)
295        self.overlaySenderKilled = False
296        self.overlaySender.start()
297
298        # now connecting to the appLauncher running on the
299        # same machine as SAGE we are connecting to
300        if self.useAppLauncher and not self.connectToAppLauncher(host):
301            print "\n===> Can't connect to the appLauncher"
302            return -1
303        else:
304            print 'connected to SAGE',self.sageHost,self.sagePort
305            return 1
306
307
308
309        ### attempts to find the appLauncher that's running on the same machine as myHost
310        ### (by comparing IP addresses of the sage machine and reported appLaunchers)
311    def __getMyAppLauncher(self, myHost):
312        self.updateLauncherList()  #get a new fresh list of appLaunchers
313       
314        def sameByIP(first, second):
315            try:
316                first = socket.gethostbyname(first)[0]
317                second = socket.gethostbyname(second)[0]
318                if first == second:
319                    return True
320                else:
321                    return False
322            except:
323                return False
324
325        # loop through all the known launchers and try to find the one that matches myHost
326        for launcher in self.launchers.itervalues():
327            try:
328                if myHost == launcher.getIP():
329                    return launcher.getServerHandle()  #returns the server object that we can call functions on
330                elif sameByIP(myHost, launcher.getIP):
331                    return launcher.getServerHandle()
332                else:
333                    return None
334            except:
335                return None
336               
337   
338   
339    ### connects to the sage server and retrieves the list of all app launchers running
340    def updateLauncherList(self):
341        sageServer = xmlrpclib.ServerProxy("http://"+self.sageServerHost+":"+str(SAGE_SERVER_PORT))
342        try:
343            # a hash comes back (key=launcherId, value=appList - that's another hash of appNames and configs)
344            launcherHash = sageServer.GetRegisteredLaunchers()
345        except socket.error:
346            print "no connection to the sage server... can't get the list of appLaunchers"
347        except:
348            tb.print_exc()
349        else:
350            self.launchers={}
351            for launcherString, appList in launcherHash.iteritems():
352                (name, launcherId) = launcherString.split(":",1)
353                (ip, port) = launcherId.split(":",1)
354                self.launchers[launcherId] = AppLauncher(launcherId, name, ip, port, appList)
355               
356        return self.launchers
357
358
359    ### returns a hash of all the appLaunchers currently running
360    def getLaunchers(self):
361        return self.updateLauncherList()
362   
363
364    # get the applist from the applauncher first and call the appropriate function
365    def getAppList(self):
366        appList = {}
367        try:
368            appList = self.appLauncher.getAppList()
369            self.hashCallbackFunction[ 40000 ]( appList )
370        except socket.error:
371            self.hashCallbackFunction[ 40000 ]( appList ) #return appList  #the server is not running
372        except:
373            tb.print_exc()
374            return False
375
376
377    def isConnected(self):
378        return self.connected
379       
380
381    def disconnectFromSage(self, isSocketError=False):
382        """ isSocketError should be True when we didn't close
383            the connection intentionally but rather the connection
384            broke for some reason. In that case the onDisconnect
385            callback is called.
386        """
387        if self.connected == False: return 0
388
389        self.threadkilled = True
390        self.overlaySenderKilled = True
391        self.connected = False         
392        #self.t.join()
393        self.sock.close()
394        del self.sock
395        print 'disconnected from SAGE',self.sageHost,self.sagePort
396
397        if isSocketError and self.onDisconnect:
398            self.onDisconnect()
399       
400        return 1
401
402
403    def sendmsg(self, data, code, sailId=''):
404        if not self.connected:
405            return 0
406
407        self.senderLock.acquire()
408
409        msg = self.makemsg(sailId,code,'',len(data),data)
410        totalcount = 0
411        try:
412            totalcount = self.sock.send(msg)
413        except socket.error:
414            print 'SageGateBase: socket error on send'
415            totalcount = 0
416            self.disconnectFromSage( isSocketError=True )
417        except Exception:
418            tb.print_exc()
419            totalcount = 0
420
421        self.senderLock.release()
422        return totalcount
423
424
425    ################################################################## 
426    # Register
427    ################################################################## 
428    # 1000 none
429    # 40004 display info format
430    ################################################################## 
431    def registerSage(self):
432        if not self.connected:
433            return 0
434        return self.sendmsg('', 1000)
435
436
437    ################################################################## 
438    # Execute
439    ################################################################## 
440    # 1001 app-name 100 100 (app-name(?))
441    # 40001 app-inst-ID left right top bottom sail-ID
442    ################################################################## 
443    def executeApp(self, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
444        if self.connected == False: return 0
445        if not appName: return 0
446
447        if not sageIP:  sageIP = self.sageHost
448        if not sagePort: sagePort = self.sagePort+1
449       
450        # try running the app (return -1 if failed for whatever reason)
451        try:
452            res = self.appLauncher.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
453        except:
454            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
455            return -1
456        else:
457            return res
458
459
460    def executeRemoteApp(self, launcherId, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
461        if self.connected == False: return 0
462        if not appName: return 0
463
464        if not sageIP:  sageIP = self.sageHost
465        if not sagePort: sagePort = self.sagePort+1
466
467        # try running the app (return -1 if failed for whatever reason)
468        if launcherId in self.launchers:
469            server = self.launchers[launcherId].getServerHandle()
470            try:
471                res = server.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
472            except:
473                print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
474                return -1
475            else:
476                return res
477        else:
478            print "Launcher not found: ", launcherId
479            return -1
480
481
482       
483    ################################################################## 
484    # Shutdown
485    ################################################################## 
486    # 1002 app-instance
487    # 40003 app-Inst-ID (?)
488    ################################################################## 
489    def shutdownApp(self,windowId):
490        if self.connected == False: return 0
491
492        data = str(windowId)
493        return self.sendmsg(data, 1002)
494
495
496    ################################################################## 
497    # Forceful Shutdown
498    ################################################################## 
499    def forceShutdownApp(self, portNum):
500        if self.connected == False: return 0
501
502        # the portNum is basically the windowId in the appLauncher context
503        return self.appLauncher.stopApp(portNum)   
504
505
506    ################################################################## 
507    # Move
508    ################################################################## 
509    # 1003 app-instance dist-X,dist-Y
510    ################################################################## 
511    def moveWindow(self,windowId,distX,distY):
512        if self.connected == False: return 0
513
514        #make sure all the coordinates are ints
515        distX = int(distX)
516        distY = int(distY)
517
518        data = str(windowId) + BLANK + str(distX) + BLANK + str(distY)
519        return self.sendmsg(data, 1003)
520       
521
522    ##############################################################
523    # Resize
524    # 1004 app-instance lef,right,top,bottom
525    ##################################################################
526    def resizeWindow(self,windowId,left=0,right=0,bottom=0,top=0):
527        if self.connected == False: return 0
528        #if not windowId: return 0
529
530        #make sure all the coordinates are ints
531        left = int(left)
532        right = int(right)
533        bottom = int(bottom)
534        top = int(top)
535
536        data = str(windowId) + BLANK + str(left) + BLANK + str(right) + BLANK + str(bottom) + BLANK + str(top)
537        return self.sendmsg(data, 1004)
538       
539
540    ###########################################################
541    # Performance Information
542    ###########################################################
543    # 1005 app-instance sending-rate
544    # 1006 app-instance         
545    ###########################################################
546    def startPerformance(self,windowId,sendingrate=2):
547        if self.connected == False: return 0
548
549        data = "%d %d" % (windowId, sendingrate )
550        return self.sendmsg(data, 1005)
551       
552
553    def stopPerformance(self,windowId):
554        if self.connected == False: return 0
555
556        data = str(windowId) # convert the data to string format
557        return self.sendmsg(data, 1006)
558       
559
560
561    ####################################       
562    # Background Color
563    # 1007 red,green blue       
564    ##################################################################
565    def setBgColor(self,(red,green,blue)=(1,1,1)):
566        if self.connected == False: return 0
567
568        data = str(red) + BLANK + str(green) + BLANK + str(blue)
569        return self.sendmsg(data, 1007)
570       
571
572    ####################################       
573    # bring the application window to the top (front)
574    # 1010 app-inst-ID
575    ##################################################################
576    def bringToFront(self, windowId):
577        if self.connected == False: return 0
578
579        data = str(windowId)
580        return self.sendmsg(data, 1010)
581       
582
583
584    ####################################       
585    # Change App Properties
586    # 1011 windowId, fsmIP, fsmPort, appConfigNum       
587    ##################################################################
588    def changeAppProperties(self,windowId, newTitle, newTitleColor=(-1,-1,-1), newBorderColor=(-1,-1,-1)):
589        if self.connected == False: return 0
590
591        data = str(windowId) + BLANK + str(newTitle)
592        data = data + BLANK + str(newTitleColor[0]) + BLANK + str(newTitleColor[1]) + BLANK + str(newTitleColor[2])
593        data = data + BLANK + str(newBorderColor[0]) + BLANK + str(newBorderColor[1]) + BLANK + str(newBorderColor[2])
594        return self.sendmsg(data, 1011)
595       
596
597    ####################################       
598    # Change App Frame Rate
599    # 1010 windowId, fsmIP, fsmPort, appConfigNum       
600    ##################################################################
601    def changeAppFrameRate(self,windowId, newFrameRate):
602        if self.connected == False: return 0
603
604        data = str(windowId) + BLANK + str(newFrameRate)
605        return self.sendmsg(data, 1012)
606       
607
608
609    ####################################       
610    # Stream Request
611    # 1014 windowId, fsmIP, fsmPort
612    ##################################################################
613    def streamApp(self,windowId, fsmIP, fsmPort):
614        if self.connected == False: return 0
615
616        data = str(windowId) + BLANK + str(fsmIP) + BLANK + str(fsmPort)
617        return self.sendmsg(data, 1014)
618       
619
620
621    ####################################       
622    # Rotate Window
623    # 1018 windowId, degree
624    ##################################################################
625    def rotateWindow(self, windowId, degree):
626        if self.connected == False: return 0
627
628        data = str(windowId) + BLANK + str(degree)
629        return self.sendmsg(data, 1018)
630
631
632
633    ####################################       
634    # Overlay Messages
635    # 1200 - 1205
636    ##################################################################
637    def addOverlay(self, overlayType, x, y, w, h, isGlobal, drawOrder):
638        data = '%s %s %s %s %s %s %s' % (overlayType, x, y, w, h, int(isGlobal), drawOrder)
639        return self.sendmsg(data, 1200)
640
641
642    def moveOverlay(self, id, dx, dy):
643        """ relative movement """
644        data = '%s %s %s' % (id, dx, dy)
645        return self.sendmsg(data, 1201)
646   
647
648    def showOverlay(self, id, doShow):
649        data = '%s %s' % (id, str(int(doShow)))
650        return self.sendmsg(data, 1204)
651
652
653    def sendOverlayMessage(self, id, *data):
654        """ this actually puts the messages in a queue
655            which are then sent at fixed intervals """
656
657        # first assemble the data into a string
658        msg = '%s' % (id)
659        for d in data:   
660            msg += " "+str(d)
661
662        self.overlayMsgLock.acquire()
663        self.overlayMsgQueue.append(msg)
664        self.overlayMsgLock.release()
665
666
667    def __sendMultipleOverlayMessages(self, msg):  # a bunch of messages combined into one
668        return self.sendmsg(msg, 1203)
669
670
671    def removeOverlay(self, id):
672        data = '%s' % (id)
673        return self.sendmsg(data, 1202)
674       
675
676    ####################################       
677    # SAGE App events
678    # 31000 - 31007
679    ##################################################################
680
681    def sendAppEvent(self, eventId, sailId, *data):
682        # first assemble the data into a string
683        msg = ''
684        for d in data:   
685            msg += " "+str(d)
686        self.sendmsg(msg, 31000+eventId, sailId)
687
688
689    ####################################       
690    # SAGE shutdown
691    # 1100      <none>
692    ##################################################################
693    def shutdownSAGE(self):
694        if self.connected == False: return 0
695        return self.sendmsg('', 1100)
696
697
698
699    ##############
700    #  Overlay Sender Thread
701    #    - Sends combined overlay messages at fixed intervals
702    ##################################################################
703    def overlaySenderThread(self):
704        while not self.overlaySenderKilled and doRun():
705            self.overlayMsgLock.acquire()
706
707            # iterate through the msg queue and assemble the messages into a string
708            msg = ""
709            for m in self.overlayMsgQueue:
710                msg += m + "\n"            # separate messages with \n
711            self.overlayMsgQueue = []      # clear the queue
712            self.overlayMsgLock.release()
713
714            # send the message if there is something to send
715            msg = msg.strip()
716            if msg != "":
717                self.__sendMultipleOverlayMessages(msg)
718               
719            # sleep for a certain time
720            time.sleep(1.0/self.overlayMsgFreq)
721
722        print "Overlay message sender thread closed"
723       
724
725    ##############
726    #  Receiver Thread
727    #    - receives messages from SAGE in a thread
728    ##################################################################
729    def receiverThread(self):
730
731        while self.threadkilled == False and doRun():   #doesn't work as expected without the sock.settimeout (look below)
732
733            #############################
734            try:
735
736                code = ""
737                incomingMsg = ""
738                msgSize = ""
739
740                # first make sure you read the whole 8 bytes for the size
741                while len(msgSize) < HEADER_ITEM_LEN:
742                    msgSize = self.sock.recv(HEADER_ITEM_LEN)
743                    if len( msgSize ) == 0:
744                        self.threadkilled = True
745                        self.overlaySenderKilled = True
746                        self.disconnectFromSage( isSocketError=True )
747                        break
748
749                if self.threadkilled: break
750               
751                # this is the number of bytes that the total message contains
752                msgSize = msgSize.replace('\x00', '')
753                sizeLeft = int(msgSize) - HEADER_ITEM_LEN    # we already read the size so read the rest of the bytes
754
755                # read the rest of the message
756                while len( incomingMsg ) < sizeLeft:
757                    incomingMsg = incomingMsg + self.sock.recv( sizeLeft - len(incomingMsg) )
758
759                # extract the tokens from the message
760                if len( incomingMsg ) > 0:
761                    incomingMsg = incomingMsg.replace('\x00', ' ')
762                    dst = incomingMsg[ 1:9 ].strip()
763                    code = int(incomingMsg[ 10:18 ].strip())
764                    appCode = incomingMsg[ 19:27 ].strip()
765                    data = incomingMsg[ 28: ].strip()
766
767                    # print the message out (except performance info since there are many of them)
768                    if self.verbose and code in self.hashIncomingMessages and code != 40002:
769                        print "\n\tRECEIVED:  " + self.hashIncomingMessages[code]
770                        lines = data.split('\n')
771                        if len(lines) < 2:
772                            print "\t\t   [" + lines[0] + "]\n\n"
773                        else:
774                            for i in range(0, len(lines)):
775                                if i == 0:
776                                    print "\t\t   [" + lines[i]
777                                elif i == len(lines)-1:
778                                    print "\t\t    " + lines[i] + "]\n\n"
779                                else:
780                                    print "\t\t    " + lines[i]
781
782
783            except socket.timeout:
784                continue
785            except socket.error:
786                #print 'SageGateBase: socket error on receive'
787                #self.disconnectFromSage( isSocketError=True )
788                continue
789            #except:
790            #   print 'exception: ', sys.exc_info()[0], sys.exc_info()[1]
791            #   break
792            ############################
793
794            if self.threadkilled:
795                break
796
797            # finally, do something with this message (ie call the subclass' message handler)
798            self.onMessage( code, data )
799
800        print "SageGate receiver thread closed"
801       
802
803    def cleanBuffer( self, stBuffer ):
804        """ converts all non-printable characters from the buffer to white spaces
805            (so that they can be removed using string.strip() function)
806        """
807        stNewBuffer = ""
808
809        for ch in stBuffer:
810            if ( ch in string.printable ):
811                stNewBuffer = stNewBuffer + ch
812            else:
813                stNewBuffer = stNewBuffer + " "
814
815        return stNewBuffer
816
817
818
819    def onMessage(self, code, data):
820        """ this is the function that gets called after a message arrives successfully
821            it must be overridden by the subclass
822        """
823        raise NotImplementedError
824
825
826    def registerCallbackFunction( self, msgID, function ):
827        self.hashCallbackFunction[ msgID ] = function
828
829
830
831
832
833       
834
835
Note: See TracBrowser for help on using the repository browser.