1616from __future__ import print_function
1717
1818from collections import Mapping
19- import errno
2019import inspect
20+ import os
2121import re
2222import signal
23- import select
2423import sys
24+ import threading
2525import traceback
2626
2727if sys .version_info < (3 ,):
@@ -62,13 +62,11 @@ def __init__(self, library, host='127.0.0.1', port=8270, port_file=None,
6262 :param allow_stop: Allow/disallow stopping the server using
6363 ``Stop Remote Server`` keyword.
6464 """
65- self ._server = StoppableXMLRPCServer (host , int (port ))
65+ self ._server = StoppableXMLRPCServer (host , int (port ), port_file )
6666 self ._library = RemoteLibraryFactory (library )
6767 self ._allow_stop = allow_stop
6868 self ._register_functions (self ._server )
69- self ._register_signal_handlers ()
70- self ._announce_start (port_file )
71- self ._server .start ()
69+ self ._server .serve ()
7270
7371 @property
7472 def server_address (self ):
@@ -81,29 +79,13 @@ def _register_functions(self, server):
8179 server .register_function (self .get_keyword_documentation )
8280 server .register_function (self .stop_remote_server )
8381
84- def _register_signal_handlers (self ):
85- def stop_with_signal (signum , frame ):
86- self ._allow_stop = True
87- self .stop_remote_server ()
88- for name in 'SIGINT' , 'SIGTERM' , 'SIGHUP' :
89- if hasattr (signal , name ):
90- signal .signal (getattr (signal , name ), stop_with_signal )
91-
92- def _announce_start (self , port_file = None ):
93- host , port = self .server_address
94- self ._log ('Robot Framework remote server at %s:%s starting.'
95- % (host , port ))
96- if port_file :
97- with open (port_file , 'w' ) as pf :
98- pf .write (str (port ))
99-
10082 def stop_remote_server (self ):
101- prefix = 'Robot Framework remote server at %s:%s ' % self .server_address
10283 if self ._allow_stop :
103- self ._log (prefix + 'stopping.' )
104- self ._server .stop ()
84+ self ._server .stop_serve ()
10585 return True
106- self ._log (prefix + 'does not allow stopping.' , 'WARN' )
86+ # TODO: Log to __stdout__? WARN?
87+ print ('Robot Framework remote server at %s:%s does not allow stopping.'
88+ % self .server_address )
10789 return False
10890
10991 def _log (self , msg , level = None ):
@@ -140,24 +122,59 @@ def get_keyword_documentation(self, name):
140122class StoppableXMLRPCServer (SimpleXMLRPCServer ):
141123 allow_reuse_address = True
142124
143- def __init__ (self , host , port ):
144- SimpleXMLRPCServer .__init__ (self , (host , port ), logRequests = False )
145- self ._shutdown = False
125+ def __init__ (self , host , port , port_file = None ):
126+ SimpleXMLRPCServer .__init__ (self , (host , port ), logRequests = False ,
127+ bind_and_activate = False )
128+ self ._port_file = port_file
129+ self ._thread = None
130+ self ._stop_server = threading .Event ()
131+
132+ def start (self , log = False ):
133+ self .server_bind ()
134+ self .server_activate ()
135+ self ._thread = threading .Thread (target = self .serve_forever )
136+ self ._thread .start ()
137+ self ._announce_start (log , self ._port_file )
138+
139+ def _announce_start (self , log_start , port_file ):
140+ # TODO: starting -> started
141+ if log_start :
142+ print ('Robot Framework remote server at %s:%s starting.'
143+ % self .server_address )
144+ if port_file :
145+ with open (port_file , 'w' ) as pf :
146+ pf .write (str (self .server_address [1 ]))
147+
148+ def stop (self , log = False ):
149+ self .shutdown ()
150+ self .server_close ()
151+ self ._thread .join ()
152+ self ._announce_end (log , self ._port_file )
153+
154+ def _announce_end (self , log_end , port_file ):
155+ # TODO: stopping -> stopped
156+ if log_end :
157+ print ('Robot Framework remote server at %s:%s stopping.'
158+ % self .server_address )
159+ if port_file and os .path .exists (port_file ):
160+ os .remove (port_file ) # TODO: Document that port file is removed
161+
162+ def serve (self , log = True ):
163+ self ._stop_server .clear ()
164+ self ._register_signal_handlers () # TODO: use as context manager!
165+ self .start (log )
166+ while not self ._stop_server .is_set ():
167+ self ._stop_server .wait (1 )
168+ self .stop (log )
146169
147- def start (self ):
148- if hasattr (self , 'timeout' ):
149- self .timeout = 0.5
150- elif sys .platform .startswith ('java' ):
151- self .socket .settimeout (0.5 )
152- while not self ._shutdown :
153- try :
154- self .handle_request ()
155- except (OSError , select .error ) as err :
156- if err .args [0 ] != errno .EINTR :
157- raise
170+ def _register_signal_handlers (self ):
171+ for name in 'SIGINT' , 'SIGTERM' , 'SIGHUP' :
172+ if hasattr (signal , name ):
173+ signal .signal (getattr (signal , name ),
174+ lambda signum , frame : self .stop_serve ())
158175
159- def stop (self ):
160- self ._shutdown = True
176+ def stop_serve (self ):
177+ self ._stop_server . set ()
161178
162179
163180def RemoteLibraryFactory (library ):
0 commit comments