OpenGeodeWeb-Back 4.3.1rc1__py3-none-any.whl → 5.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {OpenGeodeWeb_Back-4.3.1rc1.dist-info → OpenGeodeWeb_Back-5.0.0rc1.dist-info}/METADATA +18 -17
- {OpenGeodeWeb_Back-4.3.1rc1.dist-info → OpenGeodeWeb_Back-5.0.0rc1.dist-info}/RECORD +10 -7
- {OpenGeodeWeb_Back-4.3.1rc1.dist-info → OpenGeodeWeb_Back-5.0.0rc1.dist-info}/WHEEL +1 -1
- opengeodeweb_back/app_config.py +33 -0
- opengeodeweb_back/geode_functions.py +4 -115
- opengeodeweb_back/routes/blueprint_routes.py +39 -13
- opengeodeweb_back/routes/schemas/ping.json +10 -0
- opengeodeweb_back/utils_functions.py +131 -0
- {OpenGeodeWeb_Back-4.3.1rc1.dist-info → OpenGeodeWeb_Back-5.0.0rc1.dist-info}/LICENSE +0 -0
- {OpenGeodeWeb_Back-4.3.1rc1.dist-info → OpenGeodeWeb_Back-5.0.0rc1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: OpenGeodeWeb-Back
|
3
|
-
Version:
|
3
|
+
Version: 5.0.0rc1
|
4
4
|
Summary: OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem
|
5
5
|
Author-email: Geode-solutions <team-web@geode-solutions.com>
|
6
6
|
Project-URL: Homepage, https://github.com/Geode-solutions/OpenGeodeWeb-Back
|
@@ -12,31 +12,32 @@ Requires-Python: >=3.8
|
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
License-File: LICENSE
|
14
14
|
Requires-Dist: asgiref ==3.8.1
|
15
|
-
Requires-Dist: attrs ==
|
15
|
+
Requires-Dist: attrs ==24.2.0
|
16
16
|
Requires-Dist: blinker ==1.8.2
|
17
17
|
Requires-Dist: click ==8.1.7
|
18
18
|
Requires-Dist: flask[async] ==3.0.3
|
19
19
|
Requires-Dist: flask-cors ==4.0.1
|
20
|
-
Requires-Dist: geode-background ==
|
21
|
-
Requires-Dist: geode-common ==
|
22
|
-
Requires-Dist: geode-conversion ==
|
23
|
-
Requires-Dist: geode-explicit ==
|
24
|
-
Requires-Dist: geode-implicit ==
|
25
|
-
Requires-Dist: geode-numerics ==
|
26
|
-
Requires-Dist: geode-simplex ==
|
27
|
-
Requires-Dist: geode-viewables ==
|
20
|
+
Requires-Dist: geode-background ==8.1.1
|
21
|
+
Requires-Dist: geode-common ==32.0.8
|
22
|
+
Requires-Dist: geode-conversion ==6.0.3
|
23
|
+
Requires-Dist: geode-explicit ==6.0.1
|
24
|
+
Requires-Dist: geode-implicit ==3.1.1
|
25
|
+
Requires-Dist: geode-numerics ==5.0.2
|
26
|
+
Requires-Dist: geode-simplex ==8.2.1
|
27
|
+
Requires-Dist: geode-viewables ==3.0.0
|
28
28
|
Requires-Dist: itsdangerous ==2.2.0
|
29
29
|
Requires-Dist: jinja2 ==3.1.4
|
30
|
-
Requires-Dist: jsonschema ==4.
|
30
|
+
Requires-Dist: jsonschema ==4.23.0
|
31
31
|
Requires-Dist: jsonschema-specifications ==2023.12.1
|
32
32
|
Requires-Dist: markupsafe ==2.1.5
|
33
|
-
Requires-Dist: opengeode-core ==
|
34
|
-
Requires-Dist: opengeode-geosciences ==
|
35
|
-
Requires-Dist: opengeode-geosciencesio ==
|
36
|
-
Requires-Dist: opengeode-inspector ==
|
37
|
-
Requires-Dist: opengeode-io ==
|
33
|
+
Requires-Dist: opengeode-core ==15.2.1
|
34
|
+
Requires-Dist: opengeode-geosciences ==8.0.0
|
35
|
+
Requires-Dist: opengeode-geosciencesio ==5.0.1
|
36
|
+
Requires-Dist: opengeode-inspector ==6.0.0
|
37
|
+
Requires-Dist: opengeode-io ==7.0.1
|
38
38
|
Requires-Dist: referencing ==0.35.1
|
39
|
-
Requires-Dist: rpds-py ==0.
|
39
|
+
Requires-Dist: rpds-py ==0.20.0
|
40
|
+
Requires-Dist: typing-extensions ==4.12.2
|
40
41
|
Requires-Dist: werkzeug ==3.0.3
|
41
42
|
|
42
43
|
<h1 align="center">OpenGeodeWeb-Back<sup><i>by Geode-solutions</i></sup></h1>
|
@@ -1,17 +1,20 @@
|
|
1
1
|
opengeodeweb_back/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
opengeodeweb_back/
|
2
|
+
opengeodeweb_back/app_config.py,sha256=bgn31kmMUhn6PwqpENPPQfsRsuXqnYgqMaV0_OoenDw,721
|
3
|
+
opengeodeweb_back/geode_functions.py,sha256=m1icB_E9SctF6LFoUDLxE0WseDy6wc1qNV6KeuBeEGo,8716
|
3
4
|
opengeodeweb_back/geode_objects.py,sha256=8UMBmghw6aoJ4YdgzaRYdMInhPz_e7zfisP7xFIQyJo,20290
|
4
|
-
opengeodeweb_back/
|
5
|
+
opengeodeweb_back/utils_functions.py,sha256=GTZllcyQT-DBfYXecxurRYa-CpBcOgpMvXqQvqNItZg,3920
|
6
|
+
opengeodeweb_back/routes/blueprint_routes.py,sha256=X_VF8pfxxci8Ek37uLjIDJTh9ItNiufd52hoBfbi9q8,8596
|
5
7
|
opengeodeweb_back/routes/schemas/allowed_files.json,sha256=pRsGf39LiJpl3zEGLg4IqvRtm7iUx3Wq4Tb4tSFXGV0,234
|
6
8
|
opengeodeweb_back/routes/schemas/allowed_objects.json,sha256=8JLtAI46eXeiJuiryS2geRVv0J1rGkFb87pRwtBZSZw,296
|
7
9
|
opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.json,sha256=0t4YhdKxDlzcLh85JU85z6Pn5h8wlXVt3Zi4ZhXXmTQ,308
|
8
10
|
opengeodeweb_back/routes/schemas/geographic_coordinate_systems.json,sha256=86QEBxAJXdMHulj2SyrxvAAwvyUq3mpKSazwASukeoM,242
|
9
11
|
opengeodeweb_back/routes/schemas/inspect_file.json,sha256=7jmmLD2oZ2dxn5-2HqS6fU92eGM3FWBQdj3CjyYmGOA,285
|
10
12
|
opengeodeweb_back/routes/schemas/missing_files.json,sha256=tJVdSM3CqYFZRC6eNW6Q3JG3RtoaZDxaZtbfx6djbX0,286
|
13
|
+
opengeodeweb_back/routes/schemas/ping.json,sha256=MhI5jtrjMsAsfIKEzdY8p1HyV9xv4O3hYfESWw6tkyE,162
|
11
14
|
opengeodeweb_back/routes/schemas/save_viewable_file.json,sha256=7BXO8vsQrmqyEQ2uycm2Ift_EY7a0KocvnGEjYrQFcQ,368
|
12
15
|
opengeodeweb_back/routes/schemas/upload_file.json,sha256=sE6bxz3mJbSZlGmrnR_hZmcx0dvZGn3Wpnn6szRPxXQ,186
|
13
|
-
OpenGeodeWeb_Back-
|
14
|
-
OpenGeodeWeb_Back-
|
15
|
-
OpenGeodeWeb_Back-
|
16
|
-
OpenGeodeWeb_Back-
|
17
|
-
OpenGeodeWeb_Back-
|
16
|
+
OpenGeodeWeb_Back-5.0.0rc1.dist-info/LICENSE,sha256=LoTB-aqQvzTGxoTRXNnhNV0LKiqdk2bQv6MB34l8zkI,1079
|
17
|
+
OpenGeodeWeb_Back-5.0.0rc1.dist-info/METADATA,sha256=zkHX_RPdw9ANRvsb_dtnunaY87p5dYuv5aass3V1uac,3083
|
18
|
+
OpenGeodeWeb_Back-5.0.0rc1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
19
|
+
OpenGeodeWeb_Back-5.0.0rc1.dist-info/top_level.txt,sha256=tN1FZeLIVBrdja2-pbmhg5-tK-JILmmT9OeIBnhlUrQ,18
|
20
|
+
OpenGeodeWeb_Back-5.0.0rc1.dist-info/RECORD,,
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Standard library imports
|
2
|
+
import os
|
3
|
+
import time
|
4
|
+
|
5
|
+
# Third party imports
|
6
|
+
# Local application imports
|
7
|
+
|
8
|
+
|
9
|
+
class Config(object):
|
10
|
+
FLASK_DEBUG = os.environ.get("FLASK_DEBUG", default=False)
|
11
|
+
DEFAULT_PORT = "5000"
|
12
|
+
CORS_HEADERS = "Content-Type"
|
13
|
+
UPLOAD_FOLDER = "./uploads"
|
14
|
+
DESKTOP_APP = False
|
15
|
+
REQUEST_COUNTER = 0
|
16
|
+
LAST_REQUEST_TIME = time.time()
|
17
|
+
LAST_PING_TIME = time.time()
|
18
|
+
|
19
|
+
|
20
|
+
class ProdConfig(Config):
|
21
|
+
SSL = None
|
22
|
+
ORIGINS = ""
|
23
|
+
MINUTES_BEFORE_TIMEOUT = "1"
|
24
|
+
SECONDS_BETWEEN_SHUTDOWNS = "10"
|
25
|
+
DATA_FOLDER_PATH = "/data/"
|
26
|
+
|
27
|
+
|
28
|
+
class DevConfig(Config):
|
29
|
+
SSL = None
|
30
|
+
ORIGINS = "*"
|
31
|
+
MINUTES_BEFORE_TIMEOUT = "1"
|
32
|
+
SECONDS_BETWEEN_SHUTDOWNS = "10"
|
33
|
+
DATA_FOLDER_PATH = "./data/"
|
@@ -1,20 +1,14 @@
|
|
1
1
|
# Standard library imports
|
2
2
|
import os
|
3
|
-
import time
|
4
|
-
import threading
|
5
|
-
import uuid
|
6
|
-
import zipfile
|
7
3
|
|
8
4
|
# Third party imports
|
9
5
|
import flask
|
10
6
|
import opengeode_geosciences as og_gs
|
11
7
|
import opengeode as og
|
12
|
-
import pkg_resources
|
13
|
-
from jsonschema import validate
|
14
|
-
from jsonschema.exceptions import ValidationError
|
15
8
|
|
16
9
|
# Local application imports
|
17
10
|
from .geode_objects import geode_objects_dict
|
11
|
+
from . import utils_functions
|
18
12
|
|
19
13
|
|
20
14
|
def geode_object_value(geode_object: str):
|
@@ -147,7 +141,9 @@ def list_geode_objects(
|
|
147
141
|
key: str = None,
|
148
142
|
):
|
149
143
|
return_dict = {}
|
150
|
-
file_extension = extension_from_filename(
|
144
|
+
file_extension = utils_functions.extension_from_filename(
|
145
|
+
os.path.basename(file_absolute_path)
|
146
|
+
)
|
151
147
|
geode_objects_filtered_list = filter_geode_objects(key)
|
152
148
|
|
153
149
|
for geode_object in geode_objects_filtered_list:
|
@@ -200,75 +196,6 @@ def get_inspector_children(obj):
|
|
200
196
|
return new_object
|
201
197
|
|
202
198
|
|
203
|
-
def versions(list_packages: list):
|
204
|
-
list_with_versions = []
|
205
|
-
for package in list_packages:
|
206
|
-
list_with_versions.append(
|
207
|
-
{
|
208
|
-
"package": package,
|
209
|
-
"version": pkg_resources.get_distribution(package).version,
|
210
|
-
}
|
211
|
-
)
|
212
|
-
return list_with_versions
|
213
|
-
|
214
|
-
|
215
|
-
def create_lock_file(
|
216
|
-
folder_absolute_path,
|
217
|
-
):
|
218
|
-
if not os.path.exists(folder_absolute_path):
|
219
|
-
os.mkdir(folder_absolute_path)
|
220
|
-
id = uuid.uuid4()
|
221
|
-
file_absolute_path = f"{folder_absolute_path}/{str(id)}.txt"
|
222
|
-
f = open(file_absolute_path, "a")
|
223
|
-
f.close()
|
224
|
-
flask.g.UUID = id
|
225
|
-
|
226
|
-
|
227
|
-
def create_time_file(folder_absolute_path):
|
228
|
-
if not os.path.exists(folder_absolute_path):
|
229
|
-
os.mkdir(folder_absolute_path)
|
230
|
-
file_path = f"{folder_absolute_path}/time.txt"
|
231
|
-
if not os.path.isfile(file_path):
|
232
|
-
f = open(file_path, "w")
|
233
|
-
f.close()
|
234
|
-
|
235
|
-
f = open(folder_absolute_path + "/time.txt", "w")
|
236
|
-
f.write(str(time.time()))
|
237
|
-
f.close()
|
238
|
-
|
239
|
-
|
240
|
-
def remove_lock_file(folder_absolute_path):
|
241
|
-
id = flask.g.UUID
|
242
|
-
os.remove(f"{folder_absolute_path}/{str(id)}.txt")
|
243
|
-
|
244
|
-
|
245
|
-
def set_interval(func, sec):
|
246
|
-
def func_wrapper():
|
247
|
-
set_interval(func, sec)
|
248
|
-
func()
|
249
|
-
|
250
|
-
t = threading.Timer(sec, func_wrapper)
|
251
|
-
t.daemon = True
|
252
|
-
t.start()
|
253
|
-
return t
|
254
|
-
|
255
|
-
|
256
|
-
def extension_from_filename(filename):
|
257
|
-
return os.path.splitext(filename)[1][1:]
|
258
|
-
|
259
|
-
|
260
|
-
def validate_request(request, schema):
|
261
|
-
json_data = request.get_json(force=True, silent=True)
|
262
|
-
|
263
|
-
if json_data is None:
|
264
|
-
json_data = {}
|
265
|
-
|
266
|
-
try:
|
267
|
-
validate(instance=json_data, schema=schema)
|
268
|
-
except ValidationError as e:
|
269
|
-
flask.abort(400, f"Validation error: {e.message}")
|
270
|
-
|
271
|
-
|
272
199
|
def geographic_coordinate_systems(geode_object: str):
|
273
200
|
if is_3D(geode_object):
|
274
201
|
return og_gs.GeographicCoordinateSystem3D.geographic_coordinate_systems()
|
@@ -329,41 +256,3 @@ def create_coordinate_system(
|
|
329
256
|
create_crs(
|
330
257
|
geode_object, data, name, input_coordiante_system, output_coordiante_system
|
331
258
|
)
|
332
|
-
|
333
|
-
|
334
|
-
def send_file(upload_folder, saved_files, new_file_name):
|
335
|
-
if len(saved_files) == 1:
|
336
|
-
mimetype = "application/octet-binary"
|
337
|
-
else:
|
338
|
-
mimetype = "application/zip"
|
339
|
-
new_file_name = os.path.splitext(new_file_name)[0] + ".zip"
|
340
|
-
with zipfile.ZipFile(os.path.join(upload_folder, new_file_name), "w") as zipObj:
|
341
|
-
for saved_file_path in saved_files:
|
342
|
-
zipObj.write(
|
343
|
-
saved_file_path,
|
344
|
-
os.path.basename(saved_file_path),
|
345
|
-
)
|
346
|
-
|
347
|
-
response = flask.send_from_directory(
|
348
|
-
directory=upload_folder,
|
349
|
-
path=new_file_name,
|
350
|
-
as_attachment=True,
|
351
|
-
mimetype=mimetype,
|
352
|
-
)
|
353
|
-
response.headers["new-file-name"] = new_file_name
|
354
|
-
response.headers["Access-Control-Expose-Headers"] = "new-file-name"
|
355
|
-
|
356
|
-
return response
|
357
|
-
|
358
|
-
|
359
|
-
def handle_exception(e):
|
360
|
-
response = e.get_response()
|
361
|
-
response.data = flask.json.dumps(
|
362
|
-
{
|
363
|
-
"code": e.code,
|
364
|
-
"name": e.name,
|
365
|
-
"description": e.description,
|
366
|
-
}
|
367
|
-
)
|
368
|
-
response.content_type = "application/json"
|
369
|
-
return response
|
@@ -1,17 +1,28 @@
|
|
1
1
|
# Standard library imports
|
2
2
|
import json
|
3
3
|
import os
|
4
|
+
import time
|
4
5
|
|
5
6
|
# Third party imports
|
6
7
|
import flask
|
7
|
-
import
|
8
|
-
from .. import geode_functions
|
8
|
+
from .. import geode_functions, utils_functions
|
9
9
|
import werkzeug
|
10
10
|
import uuid
|
11
11
|
|
12
|
-
|
13
12
|
routes = flask.Blueprint("routes", __name__)
|
14
|
-
|
13
|
+
|
14
|
+
|
15
|
+
@routes.before_request
|
16
|
+
def before_request():
|
17
|
+
if "ping" not in flask.request.path:
|
18
|
+
utils_functions.increment_request_counter(flask.current_app)
|
19
|
+
|
20
|
+
|
21
|
+
@routes.teardown_request
|
22
|
+
def teardown_request(exception):
|
23
|
+
if "ping" not in flask.request.path:
|
24
|
+
utils_functions.decrement_request_counter(flask.current_app)
|
25
|
+
utils_functions.update_last_request_time(flask.current_app)
|
15
26
|
|
16
27
|
|
17
28
|
schemas = os.path.join(os.path.dirname(__file__), "schemas")
|
@@ -28,7 +39,7 @@ with open(
|
|
28
39
|
methods=allowed_files_json["methods"],
|
29
40
|
)
|
30
41
|
def allowed_files():
|
31
|
-
|
42
|
+
utils_functions.validate_request(flask.request, allowed_files_json)
|
32
43
|
extensions = geode_functions.list_input_extensions(
|
33
44
|
flask.request.json["supported_feature"]
|
34
45
|
)
|
@@ -75,7 +86,7 @@ def allowed_objects():
|
|
75
86
|
return flask.make_response({}, 200)
|
76
87
|
|
77
88
|
UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
|
78
|
-
|
89
|
+
utils_functions.validate_request(flask.request, allowed_objects_json)
|
79
90
|
file_absolute_path = os.path.join(UPLOAD_FOLDER, flask.request.json["filename"])
|
80
91
|
allowed_objects = geode_functions.list_geode_objects(
|
81
92
|
file_absolute_path, flask.request.json["supported_feature"]
|
@@ -96,7 +107,7 @@ with open(
|
|
96
107
|
)
|
97
108
|
def missing_files():
|
98
109
|
UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
|
99
|
-
|
110
|
+
utils_functions.validate_request(flask.request, missing_files_json)
|
100
111
|
|
101
112
|
missing_files = geode_functions.missing_files(
|
102
113
|
flask.request.json["input_geode_object"],
|
@@ -134,13 +145,11 @@ with open(
|
|
134
145
|
methods=geographic_coordinate_systems_json["methods"],
|
135
146
|
)
|
136
147
|
def crs_converter_geographic_coordinate_systems():
|
137
|
-
|
148
|
+
utils_functions.validate_request(flask.request, geographic_coordinate_systems_json)
|
138
149
|
infos = geode_functions.geographic_coordinate_systems(
|
139
150
|
flask.request.json["input_geode_object"]
|
140
151
|
)
|
141
152
|
crs_list = []
|
142
|
-
print(infos)
|
143
|
-
print(flask.request.json["input_geode_object"])
|
144
153
|
for info in infos:
|
145
154
|
crs = {}
|
146
155
|
crs["name"] = info.name
|
@@ -164,7 +173,7 @@ with open(
|
|
164
173
|
)
|
165
174
|
def inspect_file():
|
166
175
|
UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
|
167
|
-
|
176
|
+
utils_functions.validate_request(flask.request, inspect_file_json)
|
168
177
|
|
169
178
|
secure_filename = werkzeug.utils.secure_filename(flask.request.json["filename"])
|
170
179
|
file_path = os.path.abspath(os.path.join(UPLOAD_FOLDER, secure_filename))
|
@@ -189,7 +198,7 @@ with open(
|
|
189
198
|
)
|
190
199
|
def geode_objects_and_output_extensions():
|
191
200
|
UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
|
192
|
-
|
201
|
+
utils_functions.validate_request(
|
193
202
|
flask.request, geode_objects_and_output_extensions_json
|
194
203
|
)
|
195
204
|
data = geode_functions.load(
|
@@ -221,7 +230,7 @@ with open(
|
|
221
230
|
def save_viewable_file():
|
222
231
|
UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
|
223
232
|
DATA_FOLDER_PATH = flask.current_app.config["DATA_FOLDER_PATH"]
|
224
|
-
|
233
|
+
utils_functions.validate_request(flask.request, save_viewable_file_json)
|
225
234
|
|
226
235
|
secure_filename = werkzeug.utils.secure_filename(flask.request.json["filename"])
|
227
236
|
file_path = os.path.abspath(os.path.join(UPLOAD_FOLDER, secure_filename))
|
@@ -260,3 +269,20 @@ def save_viewable_file():
|
|
260
269
|
},
|
261
270
|
200,
|
262
271
|
)
|
272
|
+
|
273
|
+
|
274
|
+
with open(
|
275
|
+
os.path.join(schemas, "ping.json"),
|
276
|
+
"r",
|
277
|
+
) as file:
|
278
|
+
ping_json = json.load(file)
|
279
|
+
|
280
|
+
|
281
|
+
@routes.route(
|
282
|
+
ping_json["route"],
|
283
|
+
methods=ping_json["methods"],
|
284
|
+
)
|
285
|
+
def ping():
|
286
|
+
utils_functions.validate_request(flask.request, ping_json)
|
287
|
+
flask.current_app.config.update(LAST_PING_TIME=time.time())
|
288
|
+
return flask.make_response({"message": "Flask server is running"}, 200)
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# Standard library imports
|
2
|
+
import os
|
3
|
+
import threading
|
4
|
+
import time
|
5
|
+
import zipfile
|
6
|
+
|
7
|
+
# Third party imports
|
8
|
+
import flask
|
9
|
+
from jsonschema import validate
|
10
|
+
from jsonschema.exceptions import ValidationError
|
11
|
+
import pkg_resources
|
12
|
+
|
13
|
+
# Local application imports
|
14
|
+
|
15
|
+
|
16
|
+
def increment_request_counter(current_app):
|
17
|
+
if "REQUEST_COUNTER" in current_app.config:
|
18
|
+
REQUEST_COUNTER = int(current_app.config.get("REQUEST_COUNTER"))
|
19
|
+
REQUEST_COUNTER += 1
|
20
|
+
current_app.config.update(REQUEST_COUNTER=REQUEST_COUNTER)
|
21
|
+
|
22
|
+
|
23
|
+
def decrement_request_counter(current_app):
|
24
|
+
if "REQUEST_COUNTER" in current_app.config:
|
25
|
+
REQUEST_COUNTER = int(current_app.config.get("REQUEST_COUNTER"))
|
26
|
+
REQUEST_COUNTER -= 1
|
27
|
+
current_app.config.update(REQUEST_COUNTER=REQUEST_COUNTER)
|
28
|
+
|
29
|
+
|
30
|
+
def update_last_request_time(current_app):
|
31
|
+
if "LAST_REQUEST_TIME" in current_app.config:
|
32
|
+
LAST_REQUEST_TIME = time.time()
|
33
|
+
current_app.config.update(LAST_REQUEST_TIME=LAST_REQUEST_TIME)
|
34
|
+
|
35
|
+
|
36
|
+
def kill_task(current_app):
|
37
|
+
DESKTOP_APP = bool(current_app.config.get("DESKTOP_APP"))
|
38
|
+
REQUEST_COUNTER = int(current_app.config.get("REQUEST_COUNTER"))
|
39
|
+
LAST_PING_TIME = float(current_app.config.get("LAST_PING_TIME"))
|
40
|
+
LAST_REQUEST_TIME = float(current_app.config.get("LAST_REQUEST_TIME"))
|
41
|
+
MINUTES_BEFORE_TIMEOUT = float(current_app.config.get("MINUTES_BEFORE_TIMEOUT"))
|
42
|
+
current_time = time.time()
|
43
|
+
minutes_since_last_request = (current_time - LAST_REQUEST_TIME) / 60
|
44
|
+
minutes_since_last_ping = (current_time - LAST_PING_TIME) / 60
|
45
|
+
|
46
|
+
if (
|
47
|
+
(
|
48
|
+
(minutes_since_last_request > MINUTES_BEFORE_TIMEOUT)
|
49
|
+
and (DESKTOP_APP == False)
|
50
|
+
)
|
51
|
+
or (minutes_since_last_ping > MINUTES_BEFORE_TIMEOUT)
|
52
|
+
) and (REQUEST_COUNTER == 0):
|
53
|
+
print("Server timed out due to inactivity, shutting down...", flush=True)
|
54
|
+
os._exit(0)
|
55
|
+
|
56
|
+
|
57
|
+
def versions(list_packages: list):
|
58
|
+
list_with_versions = []
|
59
|
+
for package in list_packages:
|
60
|
+
list_with_versions.append(
|
61
|
+
{
|
62
|
+
"package": package,
|
63
|
+
"version": pkg_resources.get_distribution(package).version,
|
64
|
+
}
|
65
|
+
)
|
66
|
+
return list_with_versions
|
67
|
+
|
68
|
+
|
69
|
+
def validate_request(request, schema):
|
70
|
+
json_data = request.get_json(force=True, silent=True)
|
71
|
+
|
72
|
+
if json_data is None:
|
73
|
+
json_data = {}
|
74
|
+
|
75
|
+
try:
|
76
|
+
validate(instance=json_data, schema=schema)
|
77
|
+
except ValidationError as e:
|
78
|
+
flask.abort(400, f"Validation error: {e.message}")
|
79
|
+
|
80
|
+
|
81
|
+
def set_interval(func, sec, args=None):
|
82
|
+
def func_wrapper():
|
83
|
+
set_interval(func, sec, args)
|
84
|
+
func(args)
|
85
|
+
|
86
|
+
t = threading.Timer(sec, func_wrapper)
|
87
|
+
t.daemon = True
|
88
|
+
t.start()
|
89
|
+
return t
|
90
|
+
|
91
|
+
|
92
|
+
def extension_from_filename(filename):
|
93
|
+
return os.path.splitext(filename)[1][1:]
|
94
|
+
|
95
|
+
|
96
|
+
def send_file(upload_folder, saved_files, new_file_name):
|
97
|
+
if len(saved_files) == 1:
|
98
|
+
mimetype = "application/octet-binary"
|
99
|
+
else:
|
100
|
+
mimetype = "application/zip"
|
101
|
+
new_file_name = os.path.splitext(new_file_name)[0] + ".zip"
|
102
|
+
with zipfile.ZipFile(os.path.join(upload_folder, new_file_name), "w") as zipObj:
|
103
|
+
for saved_file_path in saved_files:
|
104
|
+
zipObj.write(
|
105
|
+
saved_file_path,
|
106
|
+
os.path.basename(saved_file_path),
|
107
|
+
)
|
108
|
+
|
109
|
+
response = flask.send_from_directory(
|
110
|
+
directory=upload_folder,
|
111
|
+
path=new_file_name,
|
112
|
+
as_attachment=True,
|
113
|
+
mimetype=mimetype,
|
114
|
+
)
|
115
|
+
response.headers["new-file-name"] = new_file_name
|
116
|
+
response.headers["Access-Control-Expose-Headers"] = "new-file-name"
|
117
|
+
|
118
|
+
return response
|
119
|
+
|
120
|
+
|
121
|
+
def handle_exception(e):
|
122
|
+
response = e.get_response()
|
123
|
+
response.data = flask.json.dumps(
|
124
|
+
{
|
125
|
+
"code": e.code,
|
126
|
+
"name": e.name,
|
127
|
+
"description": e.description,
|
128
|
+
}
|
129
|
+
)
|
130
|
+
response.content_type = "application/json"
|
131
|
+
return response
|
File without changes
|
File without changes
|