OpenGeodeWeb-Back 6.15.1__tar.gz → 6.15.2__tar.gz
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-6.15.1 → opengeodeweb_back-6.15.2}/PKG-INFO +1 -1
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/pyproject.toml +1 -1
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/PKG-INFO +1 -1
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/SOURCES.txt +1 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/app.py +53 -12
- opengeodeweb_back-6.15.2/tests/test_events.py +51 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/LICENSE +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/README.md +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/requirements.txt +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/setup.cfg +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/dependency_links.txt +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/entry_points.txt +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/requires.txt +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/top_level.txt +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/__init__.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/app_config.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_functions.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/__init__.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_brep.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_cross_section.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_edged_curve2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_edged_curve3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_graph.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_grid2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_grid3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_horizon_stack3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_hybrid_solid3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_implicit_cross_section.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_implicit_structural_model.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_light_regular_grid2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_light_regular_grid3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_mesh.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_model.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_object.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_point_set2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_point_set3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_polygonal_surface2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_polygonal_surface3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_polyhedral_solid3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_raster_image2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_raster_image3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_regular_grid2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_regular_grid3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_section.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_solid_mesh3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_structural_model.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_surface_mesh2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_surface_mesh3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_tetrahedral_solid3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_triangulated_surface2d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_triangulated_surface3d.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_objects/geode_vertex_set.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/py.typed +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/__init__.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/blueprint_routes.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/__init__.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/blueprint_create.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/__init__.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/edged_curve.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/edged_curve.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/point_set.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/point_set.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/polygonal_surface.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/create/schemas/polygonal_surface.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/__init__.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/allowed_files.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/allowed_files.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/allowed_objects.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/allowed_objects.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/cell_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/cell_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/edge_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/edge_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/export_project.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/export_project.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/geode_objects_and_output_extensions.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/geographic_coordinate_systems.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/geographic_coordinate_systems.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/import_project.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/import_project.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/kill.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/kill.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/missing_files.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/missing_files.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_edge_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_edge_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_polygon_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_polygon_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_polyhedron_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_polyhedron_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_vertex_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/model_component_vertex_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/ping.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/ping.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/polyhedron_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/polyhedron_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/save_viewable_file.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/save_viewable_file.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/texture_coordinates.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/texture_coordinates.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/upload_file.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/upload_file.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/validate.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/validate.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/test_utils.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/typed_route.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/utils_functions.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/tests/test_create_routes.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/tests/test_geode_functions.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/tests/test_routes.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/tests/test_typed_routes.py +0 -0
- {opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/tests/test_utils_functions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OpenGeodeWeb-Back
|
|
3
|
-
Version: 6.15.
|
|
3
|
+
Version: 6.15.2
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "OpenGeodeWeb-Back"
|
|
7
|
-
version = "6.15.
|
|
7
|
+
version = "6.15.2"
|
|
8
8
|
dynamic = ["dependencies"]
|
|
9
9
|
authors = [{ name = "Geode-solutions", email = "team-web@geode-solutions.com" }]
|
|
10
10
|
description = "OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem"
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OpenGeodeWeb-Back
|
|
3
|
-
Version: 6.15.
|
|
3
|
+
Version: 6.15.2
|
|
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
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/SOURCES.txt
RENAMED
|
@@ -110,6 +110,7 @@ src/opengeodeweb_back/routes/schemas/validate.py
|
|
|
110
110
|
src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json
|
|
111
111
|
src/opengeodeweb_back/routes/schemas/vertex_attribute_names.py
|
|
112
112
|
tests/test_create_routes.py
|
|
113
|
+
tests/test_events.py
|
|
113
114
|
tests/test_geode_functions.py
|
|
114
115
|
tests/test_routes.py
|
|
115
116
|
tests/test_typed_routes.py
|
|
@@ -6,6 +6,7 @@ import argparse
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import queue
|
|
9
|
+
import threading
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
from typing import TYPE_CHECKING, Any
|
|
11
12
|
|
|
@@ -25,6 +26,9 @@ if TYPE_CHECKING:
|
|
|
25
26
|
|
|
26
27
|
logger = logging.getLogger(__name__)
|
|
27
28
|
|
|
29
|
+
# Below nginx's default 60 s proxy_read_timeout, which closes idle streams
|
|
30
|
+
EVENTS_KEEP_ALIVE_SECONDS = 15
|
|
31
|
+
|
|
28
32
|
|
|
29
33
|
def _register_request_hooks(app: flask.Flask) -> None:
|
|
30
34
|
@app.before_request
|
|
@@ -41,25 +45,60 @@ def _register_request_hooks(app: flask.Flask) -> None:
|
|
|
41
45
|
utils_functions.teardown_request(flask.current_app, exception)
|
|
42
46
|
|
|
43
47
|
|
|
48
|
+
type _Event = tuple[str, dict[str, Any]]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# One queue per connected stream: with a single shared queue, a stream left over from a
|
|
52
|
+
# Dropped connection would take events meant for the others.
|
|
53
|
+
class _EventListeners:
|
|
54
|
+
def __init__(self) -> None:
|
|
55
|
+
self._queues: set[queue.Queue[_Event]] = set()
|
|
56
|
+
self._lock = threading.Lock()
|
|
57
|
+
|
|
58
|
+
def publish(self, event: str, data: dict[str, Any]) -> None:
|
|
59
|
+
with self._lock:
|
|
60
|
+
for listener in self._queues:
|
|
61
|
+
listener.put((event, data))
|
|
62
|
+
|
|
63
|
+
def stream(self, keep_alive_seconds: float) -> flask.Response:
|
|
64
|
+
listener: queue.Queue[_Event] = queue.Queue()
|
|
65
|
+
with self._lock:
|
|
66
|
+
self._queues.add(listener)
|
|
67
|
+
|
|
68
|
+
def unregister() -> None:
|
|
69
|
+
with self._lock:
|
|
70
|
+
self._queues.discard(listener)
|
|
71
|
+
|
|
72
|
+
response = flask.Response(
|
|
73
|
+
_stream_events(listener, keep_alive_seconds), mimetype="text/event-stream"
|
|
74
|
+
)
|
|
75
|
+
response.call_on_close(unregister)
|
|
76
|
+
return response
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _stream_events(listener: queue.Queue[_Event], keep_alive_seconds: float) -> Generator[str]:
|
|
80
|
+
while True:
|
|
81
|
+
try:
|
|
82
|
+
event, data = listener.get(timeout=keep_alive_seconds)
|
|
83
|
+
except queue.Empty:
|
|
84
|
+
# Comment line, ignored by EventSource: keeps proxies from closing the idle
|
|
85
|
+
# Stream and lets a dropped connection be detected
|
|
86
|
+
yield ": keep-alive\n\n"
|
|
87
|
+
continue
|
|
88
|
+
yield f"event: {event}\ndata: {json.dumps(data)}\n\n"
|
|
89
|
+
|
|
90
|
+
|
|
44
91
|
def _register_event_stream(app: flask.Flask) -> None:
|
|
45
92
|
def wants_event_stream() -> bool:
|
|
46
93
|
accept = flask.request.headers.get("Accept", "")
|
|
47
94
|
return "text/event-stream" in accept
|
|
48
95
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def publish_event(event: str, data: dict[str, Any]) -> None:
|
|
52
|
-
_event_queue.put((event, data))
|
|
53
|
-
|
|
54
|
-
def stream_events() -> Generator[str]:
|
|
55
|
-
while True:
|
|
56
|
-
event, data = _event_queue.get()
|
|
57
|
-
yield f"event: {event}\ndata: {json.dumps(data)}\n\n"
|
|
96
|
+
listeners = _EventListeners()
|
|
58
97
|
|
|
59
98
|
@app.after_request
|
|
60
99
|
def after_request(response: flask.Response) -> flask.Response:
|
|
61
100
|
endpoint = flask.request.endpoint.replace(".", "/") if flask.request.endpoint else None
|
|
62
|
-
if endpoint
|
|
101
|
+
if endpoint is None or endpoint == "events":
|
|
63
102
|
return response
|
|
64
103
|
|
|
65
104
|
if wants_event_stream():
|
|
@@ -68,12 +107,14 @@ def _register_event_stream(app: flask.Flask) -> None:
|
|
|
68
107
|
payload = response.get_json()
|
|
69
108
|
except ValueError:
|
|
70
109
|
payload = {"status": response.status_code}
|
|
71
|
-
|
|
110
|
+
listeners.publish(endpoint, payload)
|
|
72
111
|
return response
|
|
73
112
|
|
|
74
113
|
@app.route("/events")
|
|
75
114
|
def events() -> flask.Response:
|
|
76
|
-
return
|
|
115
|
+
return listeners.stream(
|
|
116
|
+
flask.current_app.config.get("EVENTS_KEEP_ALIVE_SECONDS", EVENTS_KEEP_ALIVE_SECONDS)
|
|
117
|
+
)
|
|
77
118
|
|
|
78
119
|
|
|
79
120
|
def _register_error_handlers(app: flask.Flask) -> None:
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
# Standard library imports
|
|
4
|
+
import queue
|
|
5
|
+
import threading
|
|
6
|
+
import time
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from flask.testing import FlaskClient
|
|
11
|
+
|
|
12
|
+
CHUNK_TIMEOUT_SECONDS = 2.0
|
|
13
|
+
LISTENERS_CONNECT_SECONDS = 0.5
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Opens a new event stream and reads its first chunk in a daemon thread: the test client
|
|
17
|
+
# Already reads that chunk inside client.get, which blocks until something is published.
|
|
18
|
+
def _read_next_chunk(client: FlaskClient) -> queue.Queue[bytes]:
|
|
19
|
+
result: queue.Queue[bytes] = queue.Queue()
|
|
20
|
+
|
|
21
|
+
def read() -> None:
|
|
22
|
+
result.put(next(client.get("/events").iter_encoded()))
|
|
23
|
+
|
|
24
|
+
threading.Thread(target=read, daemon=True).start()
|
|
25
|
+
return result
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _chunk(result: queue.Queue[bytes]) -> str | None:
|
|
29
|
+
try:
|
|
30
|
+
return result.get(timeout=CHUNK_TIMEOUT_SECONDS).decode()
|
|
31
|
+
except queue.Empty:
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_every_listener_receives_each_event(client: FlaskClient) -> None:
|
|
36
|
+
# A listener left over from a dropped connection must not take events meant for the others
|
|
37
|
+
first = _read_next_chunk(client)
|
|
38
|
+
second = _read_next_chunk(client)
|
|
39
|
+
time.sleep(LISTENERS_CONNECT_SECONDS)
|
|
40
|
+
client.get("/health", headers={"Accept": "text/event-stream"})
|
|
41
|
+
assert _chunk(first) == "event: health\ndata: {}\n\n"
|
|
42
|
+
assert _chunk(second) == "event: health\ndata: {}\n\n"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_idle_stream_sends_keep_alive(client: FlaskClient) -> None:
|
|
46
|
+
app = client.application
|
|
47
|
+
app.config["EVENTS_KEEP_ALIVE_SECONDS"] = 0.1
|
|
48
|
+
try:
|
|
49
|
+
assert _chunk(_read_next_chunk(client)) == ": keep-alive\n\n"
|
|
50
|
+
finally:
|
|
51
|
+
app.config.pop("EVENTS_KEEP_ALIVE_SECONDS")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/requires.txt
RENAMED
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/OpenGeodeWeb_Back.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/geode_functions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/kill.json
RENAMED
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/kill.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/ping.json
RENAMED
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/routes/schemas/ping.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opengeodeweb_back-6.15.1 → opengeodeweb_back-6.15.2}/src/opengeodeweb_back/utils_functions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|