1313
1414
1515class Server :
16- def __init__ (self , app ):
16+ def __init__ (
17+ self , app , host = "0.0.0.0" , port = 5000 , log = None , debug = False , zeroconf = True
18+ ):
1719 self .app = app
1820 # Find LabThing attached to app
1921 self .labthing = current_labthing (app )
2022
21- def run (
22- self ,
23- host = "0.0.0.0" ,
24- port = 5000 ,
25- log = None ,
26- debug = False ,
27- stop_timeout = 1 ,
28- zeroconf = True ,
29- ):
30- # Type checks
31- port = int (port )
32- host = str (host )
23+ # Server properties
24+ self .host = host
25+ self .port = port
26+ self .log = log
27+ self .debug = debug
28+ self .zeroconf = zeroconf
3329
34- # Unmodified version of app
35- app_to_run = self .app
30+ # Servers
31+ self .wsgi_server = None
32+ self .zeroconf_server = None
33+ self .service_info = None
3634
37- # Handle zeroconf
38- zeroconf_server = None
39- if zeroconf and self .labthing :
40- service_info = ServiceInfo (
35+ # Events
36+ self .started_event = gevent .event .Event ()
37+
38+ def register_zeroconf (self ):
39+ if self .labthing :
40+ self .service_info = ServiceInfo (
4141 "_labthings._tcp.local." ,
42- f"{ self .labthing .title } ._labthings._tcp.local." ,
43- port = port ,
42+ f"{ self .labthing .safe_title } ._labthings._tcp.local." ,
43+ port = self . port ,
4444 properties = {
4545 "path" : self .labthing .url_prefix ,
4646 "title" : self .labthing .title ,
@@ -55,43 +55,96 @@ def run(
5555 ]
5656 ),
5757 )
58- zeroconf_server = Zeroconf (ip_version = IPVersion .V4Only )
59- zeroconf_server .register_service (service_info )
58+ self .zeroconf_server = Zeroconf (ip_version = IPVersion .V4Only )
59+ self .zeroconf_server .register_service (self .service_info )
60+
61+ def stop (self , timeout = 1 ):
62+ # Unregister zeroconf service
63+ if self .zeroconf_server :
64+ self .zeroconf_server .unregister_service (self .service_info )
65+ self .zeroconf_server .close ()
66+ self .zeroconf_server = None
67+ # Stop WSGI server with timeout
68+ if self .wsgi_server :
69+ self .wsgi_server .stop (timeout = timeout )
70+ self .wsgi_server = None
71+ # Clear started event
72+ if self .started_event .is_set ():
73+ self .started_event .clear ()
74+
75+ def start (self ):
76+ # Unmodified version of app
77+ app_to_run = self .app
78+
79+ # Handle zeroconf
80+ if self .zeroconf :
81+ self .register_zeroconf ()
6082
6183 # Handle logging
62- if not log :
63- log = logging .getLogger ()
84+ if not self . log :
85+ self . log = logging .getLogger ()
6486
6587 # Handle debug mode
66- if debug :
67- log .setLevel (logging .DEBUG )
88+ if self . debug :
89+ self . log .setLevel (logging .DEBUG )
6890 app_to_run = DebuggedApplication (self .app )
6991 logging .getLogger ("zeroconf" ).setLevel (logging .DEBUG )
7092
7193 # Slightly more useful logger output
72- friendlyhost = "localhost" if host == "0.0.0.0" else host
94+ friendlyhost = "localhost" if self . host == "0.0.0.0" else self . host
7395 print ("Starting LabThings WSGI Server" )
74- print (f"Debug mode: { debug } " )
75- print (f"Running on http://{ friendlyhost } :{ port } (Press CTRL+C to quit)" )
96+ print (f"Debug mode: { self . debug } " )
97+ print (f"Running on http://{ friendlyhost } :{ self . port } (Press CTRL+C to quit)" )
7698
7799 # Create WSGIServer
78- wsgi_server = gevent .pywsgi .WSGIServer (
79- (host , port ), app_to_run , handler_class = WebSocketHandler , log = log
100+ self .wsgi_server = gevent .pywsgi .WSGIServer (
101+ (self .host , self .port ),
102+ app_to_run ,
103+ handler_class = WebSocketHandler ,
104+ log = self .log ,
80105 )
81106
82- def stop ():
83- # Unregister zeroconf service
84- if zeroconf_server :
85- zeroconf_server .unregister_service (service_info )
86- zeroconf_server .close ()
87- # Stop WSGI server with timeout
88- wsgi_server .stop (timeout = stop_timeout )
89-
90107 # Serve
91- signal .signal (signal .SIGTERM , stop )
108+ signal .signal (signal .SIGTERM , self . stop )
92109
110+ # Set started event
111+ self .started_event .set ()
93112 try :
94- wsgi_server .serve_forever ()
95- except (KeyboardInterrupt , SystemExit ):
96- logging .warning ("Terminating by KeyboardInterrupt or SystemExit" )
97- stop ()
113+ self .wsgi_server .serve_forever ()
114+ # Ignore the exit lines in coverage
115+ # as I can't find a way to test a KeyboardInterrupt...
116+ except (KeyboardInterrupt , SystemExit ): # pragma: no cover
117+ logging .warning (
118+ "Terminating by KeyboardInterrupt or SystemExit"
119+ ) # pragma: no cover
120+ self .stop () # pragma: no cover
121+
122+ def run (
123+ self , host = None , port = None , log = None , debug = None , zeroconf = None ,
124+ ):
125+ """Starts the server allowing for runtime parameters. Designed to immitate
126+ the old Flask app.run style of starting an app
127+
128+ Args:
129+ host (string, optional): Host IP address. Defaults to None.
130+ port (int, optional): Host port. Defaults to None.
131+ log (optional): Logger to log to. Defaults to None.
132+ debug (bool, optional): Enable server debug mode. Defaults to None.
133+ zeroconf (bool, optional): Enable the zeroconf server. Defaults to None.
134+ """
135+ if port is not None :
136+ self .port = int (port )
137+
138+ if host is not None :
139+ self .host = str (host )
140+
141+ if log is not None :
142+ self .log = log
143+
144+ if debug is not None :
145+ self .debug = debug
146+
147+ if zeroconf is not None :
148+ self .zeroconf = zeroconf
149+
150+ self .start ()
0 commit comments