gstlal
1.13.0
Toggle main menu visibility
Loading...
Searching...
No Matches
python
httpinterface.py
1
#
2
# Copyright (C) 2011,2012,2014,2016,2018 Kipp Cannon
3
#
4
# This program is free software; you can redistribute it and/or modify it
5
# under the terms of the GNU General Public License as published by the
6
# Free Software Foundation; either version 2 of the License, or (at your
7
# option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful, but
10
# WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12
# Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with this program; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
#
18
19
20
"""
21
Stuff to help add an http control and query interface to a program.
22
"""
23
24
25
#
26
# =============================================================================
27
#
28
# Preamble
29
#
30
# =============================================================================
31
#
32
33
34
import
socket
35
import
sys
36
import
threading
37
import
time
38
import
warnings
39
40
41
try
:
42
import
bottle
43
if
tuple(map(int, bottle.__version__.split(
"."
))) < (0, 13):
44
# FIXME: see
45
# https://git.ligo.org/lscsoft/gstlal/-/merge_requests/146
46
# if the required patch is added to the distro-supplied
47
# bottle before a 0.13 is released, update the version
48
# check to the correct version
49
raise
ImportError
50
except
ImportError:
51
# FIXME: remove after system-wide isntall can be relied on
52
from
.
import
bottle
53
from
.
import
servicediscovery
54
55
56
#
57
# =============================================================================
58
#
59
# HTTP Interface Helpers
60
#
61
# =============================================================================
62
#
63
64
65
class
HTTPDServer
(object):
66
def
__init__
(self, host, port, bottle_app, verbose = False):
67
self.
host
= host
68
self.
port
= port
69
self.
bottle_app
= bottle_app
70
self.
verbose
= verbose
71
72
def
__enter__(self):
73
self.
httpd
= bottle.WSGIRefServer(host = self.
host
, port = self.
port
)
74
self.
httpd_thread
= threading.Thread(target = self.
httpd
.run, args = (self.
bottle_app
,))
75
self.
httpd_thread
.daemon =
True
76
self.
httpd_thread
.start()
77
if
self.
verbose
:
78
print(
"waiting for http server to start ..."
, file=sys.stderr)
79
while
self.
httpd
.port == 0:
80
time.sleep(0.25)
81
self.
host
= self.
httpd
.host
82
self.
port
= self.
httpd
.port
83
if
self.
verbose
:
84
print(
"started http server on http://%s:%d"
% (self.
httpd
.host, self.
httpd
.port), file=sys.stderr)
85
return
self
86
87
def
__exit__(self, exc_type, exc_value, traceback):
88
if
self.
verbose
:
89
print(
"stopping http server on http://%s:%d ..."
% (self.
httpd
.host, self.
httpd
.port), file=sys.stderr)
90
try
:
91
self.
httpd
.shutdown()
92
except
Exception
as
e:
93
result =
"failed: %s"
% str(e)
94
else
:
95
result =
"done"
96
if
self.
verbose
:
97
print(result, file=sys.stderr)
98
print(
"killing http server thread ..."
, file=sys.stderr)
99
# wait 10 seconds, then give up
100
self.
httpd_thread
.join(10.0)
101
if
self.
verbose
:
102
print(
"timeout"
if
self.
httpd_thread
.is_alive()
else
"done"
, file=sys.stderr)
103
104
105
class
HTTPServers
(list):
106
"""
107
Utility to start, advertise, track and shutdown http servers on all
108
interfaces. De-advertise and shutdown the servers by deleting this
109
object. Do not allow the object to be garbage collected until you
110
wish the servers to be shutdown.
111
112
Example:
113
114
>>> # save return value in a variable to prevent garbage collection
115
>>> servers = HTTPServers(port = 12345)
116
>>> pass # blah
117
>>> pass # blah
118
>>> pass # blah
119
>>> # shutdown servers by deleting object
120
>>> del servers
121
122
If port = 0 (the default) a port will be assigned randomly.
123
bottle_app should be a Bottle instance. If bottle_app is None (the
124
default) then the current default Bottle application is used.
125
"""
126
def
__init__
(self, port = 0, bottle_app = None, service_name = "www", service_domain = None, service_properties = None, verbose = False, service_discovery = True):
127
if
bottle_app
is
None
:
128
bottle_app = bottle.default_app()
129
self.
verbose
= verbose
130
self.
service_discovery
= service_discovery
131
if
self.
service_discovery
:
132
self.
service_publisher
=
servicediscovery.Publisher
().__enter__()
133
else
:
134
warnings.warn(
"disabling service discovery, this web server won't be able to advertise the location of the services it provides."
)
135
for
(ignored, ignored, ignored, ignored, (host, port))
in
socket.getaddrinfo(
None
, port, socket.AF_INET, socket.SOCK_STREAM, 0, socket.AI_NUMERICHOST | socket.AI_PASSIVE):
136
httpd =
HTTPDServer
(host, port, bottle_app, verbose = verbose).__enter__()
137
if
verbose:
138
print(
"advertising http server \"%s\" on http://%s:%d ..."
% (service_name, httpd.host, httpd.port), file=sys.stderr)
139
if
self.
service_discovery
:
140
service = self.
service_publisher
.add_service(
141
sname = service_name,
142
sdomain = service_domain,
143
port = httpd.port,
144
properties = service_properties,
145
commit =
False
146
)
147
else
:
148
service =
None
149
if
verbose:
150
print(
"done (%s)"
% (
"."
.join((service.sname, service.sdomain))
if
service
else
""
), file=sys.stderr)
151
self.append((httpd, service))
152
if
not
self:
153
raise
ValueError(
"unable to start servers%s"
% (
" on port %d"
% port
if
port != 0
else
""
))
154
if
self.
service_discovery
:
155
self.
service_publisher
.commit()
156
157
def
__del__(self):
158
if
self.
verbose
:
159
print(
"de-advertising http server(s) ..."
, file=sys.stderr)
160
try
:
161
if
self.
service_discovery
:
162
self.
service_publisher
.__exit__(
None
,
None
,
None
)
163
except
Exception
as
e:
164
if
self.
verbose
:
165
print(
"failed: %s"
% str(e), file=sys.stderr)
166
else
:
167
if
self.
verbose
:
168
print(
"done"
, file=sys.stderr)
169
while
self:
170
try
:
171
self.pop()[0].__exit__(
None
,
None
,
None
)
172
except
Exception
as
e:
173
if
self.
verbose
:
174
print(
"failed: %s"
% str(e), file=sys.stderr)
python.httpinterface.HTTPDServer
Definition
httpinterface.py:65
python.httpinterface.HTTPDServer.bottle_app
bottle_app
Definition
httpinterface.py:69
python.httpinterface.HTTPDServer.verbose
verbose
Definition
httpinterface.py:70
python.httpinterface.HTTPDServer.host
host
Definition
httpinterface.py:67
python.httpinterface.HTTPDServer.httpd_thread
httpd_thread
Definition
httpinterface.py:74
python.httpinterface.HTTPDServer.httpd
httpd
Definition
httpinterface.py:73
python.httpinterface.HTTPDServer.port
port
Definition
httpinterface.py:68
python.httpinterface.HTTPServers
Definition
httpinterface.py:105
python.httpinterface.HTTPServers.service_publisher
service_publisher
Definition
httpinterface.py:132
python.httpinterface.HTTPServers.verbose
verbose
Definition
httpinterface.py:129
python.httpinterface.HTTPServers.service_discovery
service_discovery
Definition
httpinterface.py:130
python.servicediscovery.Publisher
Definition
servicediscovery.py:143
__init__
Generated by
1.17.0