argussight 0.1.0__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.
Files changed (35) hide show
  1. argussight-0.1.0/LICENSE +21 -0
  2. argussight-0.1.0/PKG-INFO +151 -0
  3. argussight-0.1.0/README.md +119 -0
  4. argussight-0.1.0/argussight/__init__.py +0 -0
  5. argussight-0.1.0/argussight/__main__.py +0 -0
  6. argussight-0.1.0/argussight/core/config.py +20 -0
  7. argussight-0.1.0/argussight/core/configurations/config.yaml +40 -0
  8. argussight-0.1.0/argussight/core/configurations/processes/savers/stream_buffer.yaml +15 -0
  9. argussight-0.1.0/argussight/core/configurations/processes/savers/video_recorder.yaml +22 -0
  10. argussight-0.1.0/argussight/core/configurations/processes/savers/video_saver.yaml +16 -0
  11. argussight-0.1.0/argussight/core/configurations/processes/streamer/flow_detection.yaml +21 -0
  12. argussight-0.1.0/argussight/core/configurations/processes/streamer/optical_flow_detection.yaml +16 -0
  13. argussight-0.1.0/argussight/core/configurations/processes/streamer/streamer.yaml +3 -0
  14. argussight-0.1.0/argussight/core/configurations/processes/vprocess.yaml +3 -0
  15. argussight-0.1.0/argussight/core/helper_functions.py +35 -0
  16. argussight-0.1.0/argussight/core/manager.py +71 -0
  17. argussight-0.1.0/argussight/core/spawner.py +321 -0
  18. argussight-0.1.0/argussight/core/video_processes/savers/stream_buffer.py +32 -0
  19. argussight-0.1.0/argussight/core/video_processes/savers/video_recorder.py +122 -0
  20. argussight-0.1.0/argussight/core/video_processes/savers/video_saver.py +164 -0
  21. argussight-0.1.0/argussight/core/video_processes/streamer/flow_detection.py +185 -0
  22. argussight-0.1.0/argussight/core/video_processes/streamer/optical_flow_detection.py +136 -0
  23. argussight-0.1.0/argussight/core/video_processes/streamer/streamer.py +87 -0
  24. argussight-0.1.0/argussight/core/video_processes/vprocess.py +245 -0
  25. argussight-0.1.0/argussight/grpc/__init__.py +0 -0
  26. argussight-0.1.0/argussight/grpc/argus_service.proto +78 -0
  27. argussight-0.1.0/argussight/grpc/argus_service_pb2.py +74 -0
  28. argussight-0.1.0/argussight/grpc/argus_service_pb2_grpc.py +341 -0
  29. argussight-0.1.0/argussight/grpc/helper_functions.py +55 -0
  30. argussight-0.1.0/argussight/grpc/server.py +112 -0
  31. argussight-0.1.0/argussight/grpc/test_client.py +63 -0
  32. argussight-0.1.0/argussight/grpc/test_concurrent_requests.py +48 -0
  33. argussight-0.1.0/argussight/main.py +62 -0
  34. argussight-0.1.0/argussight/streamsproxy.py +62 -0
  35. argussight-0.1.0/pyproject.toml +41 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 European Synchrotron Radiation Facility
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.1
2
+ Name: argussight
3
+ Version: 0.1.0
4
+ Summary: An addition to MXCuBEWeb enabling simultaneous video streaming and distributed computer vision tasks.
5
+ Home-page: https://github.com/mxcube/argussight
6
+ License: MIT
7
+ Keywords: MXCuBEWeb,video streaming,computer vision,multistream,process management
8
+ Author: Yan Walesch
9
+ Author-email: <yan.walesch@esrf.fr
10
+ Requires-Python: >=3.10,<3.12
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Requires-Dist: Flask (>=3.0.3,<4.0.0)
16
+ Requires-Dist: grpcio (>=1.38.0,<2.0.0)
17
+ Requires-Dist: grpcio-tools (>=1.38.0,<2.0.0)
18
+ Requires-Dist: mxcube-video-streamer (>=1.6.0)
19
+ Requires-Dist: numpy (>=1.26.0,<2.0.0)
20
+ Requires-Dist: opencv-python (==4.10.0.84)
21
+ Requires-Dist: pillow (>=9.4.0,<=10.4.0)
22
+ Requires-Dist: pydantic (>=2.8.2,<2.9.0)
23
+ Requires-Dist: python-levenshtein (>=0.25.1,<0.26.0)
24
+ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
25
+ Requires-Dist: redis (==4.6.0)
26
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
27
+ Requires-Dist: websocket-client (>=1.8.0,<2.0.0)
28
+ Project-URL: Documentation, https://mxcube.github.io/argussight/
29
+ Project-URL: Repository, https://github.com/mxcube/argussight
30
+ Description-Content-Type: text/markdown
31
+
32
+ # Argussight
33
+
34
+ `Argussight` is a versatile video processing tool designed to manage and run multiple streaming processes using one or several input sources. It primarily works with FFmpeg streams, ensuring high compatibility and performance for video processing tasks.
35
+
36
+ Originally developed as an extension of the [video-streamer](https://github.com/mxcube/video-streamer) project by the [MXCuBE](https://github.com/mxcube) organization, `Argussight` can also operate as a standalone application. Its flexible design allows it to be reconfigured for integration with other components, making it adaptable to various use cases.
37
+
38
+ ## Advantages of using Argussight
39
+
40
+ - **Enhanced User Experience**: Multiple streams could be displayed at once from the same source, providing a comprehensive view from different angles and/or sources.
41
+
42
+ - **Facilitates Usage of Computer Vision Algorithms**: Developers can make use of different computer vision algorithms, directly on the images and do not need to handle the complexity of handling video-loading or streaming.
43
+
44
+ - **On-the-Fly Configuration**: The system can dynamically adjust streams, such as changing parameters for video anlaysis, change position of region of interest or simply switching between views according to user preferences, withou needing to restart or reconfigure the entire process.
45
+
46
+ ## Design Overview
47
+
48
+ `Argussight` is built around four key components, each playing a vital role in its functionality.
49
+
50
+ - `Spawner`: The core of `Argussight`, responsible for controlling, spawning and terminating video processes.
51
+
52
+ - `GRPC Server`: Thightly connected to the `Spawner`, it handles the communication with a client application.
53
+
54
+ - `Video processes`: Processes that are each running a specific video-related task, like generating or modifying camera streams.
55
+
56
+ - `Stream-Layer`: An abstraction layer positioned between **streaming** processes and external systems. This layer simplifies access to the streams while enhancing security through port abstraction.
57
+
58
+ ![Argussight Overview](./assets/Overview.svg)
59
+
60
+ ## Documentation 📚
61
+
62
+ Check out the full [documentation](https://mxcube.github.io/argussight/) to explore everything, this project has to offer! Including:
63
+
64
+ - Information about all natively integrated video-related processes
65
+ - A detailed explanation about the project's core functionalities
66
+ - A comprehensive guide on how to start and run the project
67
+ - A developers guide
68
+ - and more!
69
+
70
+ ## Installation
71
+
72
+ First you need to clone the repository.
73
+
74
+ ```
75
+ git clone https://github.com/mxcube/argussight.git
76
+
77
+ # Navigate to the newly created directory
78
+ cd argussight
79
+ ```
80
+
81
+ Optionally, you can create a [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html) environment for this project
82
+
83
+ ```
84
+ conda env create -f conda-envrionment.yml
85
+ ```
86
+
87
+ If you chose not to, you need to have `ffmpeg` installed on your system, you can do so via your corresponding package manager.
88
+ On Debian-based Linux distributions (Ubuntu, Debian, Pop!_OS, ...) for example you can install it like this
89
+
90
+ ```
91
+ sudo apt-get install ffmpeg
92
+ ```
93
+
94
+ Now install the remaining dependencies using `pip`
95
+
96
+ ```
97
+ # for Development
98
+ pip install -e .
99
+
100
+ # for Usage
101
+ pip install .
102
+ ```
103
+
104
+ or `poetry`
105
+
106
+ ```
107
+ poetry install
108
+ ```
109
+
110
+ ## Usage
111
+
112
+ > ### ⚠️ Attention ⚠️
113
+ > If you want to use the `Recorder` class (enabled per default), please be aware that it creates a temporary folder in the location, you start the server at.
114
+ > In the configurations folder, you can change the name of said folder, please make sure that no other folder in your current location has the same name, as it will otherwise **delete** the contents of that folder (default is `temp`).
115
+ > - To rename the temporary folder, go to `argussight/core/configurations/processes/savers/video_recorder.yaml` and change the value of `temp_folder`.
116
+ > - To disable the `Recorder` class, go to `argussight/core/configurations/config.yaml` and remove the process named `Recorder`
117
+
118
+ ### Start the Server
119
+
120
+ Once you installed all the dependencies, you can run the `argussight` server by using
121
+
122
+ ```
123
+ argussight
124
+ ```
125
+
126
+ command in a terminal window.
127
+
128
+ ### Start communication with the GRPC Server
129
+
130
+ To communicate with the grpc server, you need to establish a connection with the channel. By default the server is running on port 50051 (changeable in the `argussight/grpc/server.py` file). The code example below shows how to start a connection and get a response for the `GetProcessesRequest`:
131
+
132
+ ```
133
+ import grpc
134
+ import argussight.grpc.argus_service_pb2 as pb2
135
+ import argussight.grpc.argus_service_pb2_grpc as pb2_grpc
136
+
137
+ channel = grpc.insecure_channel("localhost:50051")
138
+ stub = pb2_grpc.SpawnerServiceStub(channel)
139
+
140
+ # try to reach the server
141
+ try:
142
+ response = stub.GetProcesses(pb2.GetProcessesRequest())
143
+ except Exception as e:
144
+ # handle exception here
145
+ print(e)
146
+ ```
147
+
148
+ ### Access your streams
149
+
150
+ To access your streams, you first need a running streaming process. To create one, you need to make a process that inherits the `Streamer` class. Please refer to the [documentation](https://mxcube.github.io/argussight/devs/vprocess/#streamer) on how to do that. If your class inherits `Streamer` and is correctly configured in the `config.yaml` file, the `Argussight` class will take care of adding every instance of your class to the `Abstraction-Layer`. To access the streams from outside, you can then create a websocket connection to `ws://localhost:7000/ws/${name}`, where `localhost:7000` is the default location of the `Abstraction-Layer` (configurable in `config.yaml`), and `name` is the unique name of your process instance.
151
+
@@ -0,0 +1,119 @@
1
+ # Argussight
2
+
3
+ `Argussight` is a versatile video processing tool designed to manage and run multiple streaming processes using one or several input sources. It primarily works with FFmpeg streams, ensuring high compatibility and performance for video processing tasks.
4
+
5
+ Originally developed as an extension of the [video-streamer](https://github.com/mxcube/video-streamer) project by the [MXCuBE](https://github.com/mxcube) organization, `Argussight` can also operate as a standalone application. Its flexible design allows it to be reconfigured for integration with other components, making it adaptable to various use cases.
6
+
7
+ ## Advantages of using Argussight
8
+
9
+ - **Enhanced User Experience**: Multiple streams could be displayed at once from the same source, providing a comprehensive view from different angles and/or sources.
10
+
11
+ - **Facilitates Usage of Computer Vision Algorithms**: Developers can make use of different computer vision algorithms, directly on the images and do not need to handle the complexity of handling video-loading or streaming.
12
+
13
+ - **On-the-Fly Configuration**: The system can dynamically adjust streams, such as changing parameters for video anlaysis, change position of region of interest or simply switching between views according to user preferences, withou needing to restart or reconfigure the entire process.
14
+
15
+ ## Design Overview
16
+
17
+ `Argussight` is built around four key components, each playing a vital role in its functionality.
18
+
19
+ - `Spawner`: The core of `Argussight`, responsible for controlling, spawning and terminating video processes.
20
+
21
+ - `GRPC Server`: Thightly connected to the `Spawner`, it handles the communication with a client application.
22
+
23
+ - `Video processes`: Processes that are each running a specific video-related task, like generating or modifying camera streams.
24
+
25
+ - `Stream-Layer`: An abstraction layer positioned between **streaming** processes and external systems. This layer simplifies access to the streams while enhancing security through port abstraction.
26
+
27
+ ![Argussight Overview](./assets/Overview.svg)
28
+
29
+ ## Documentation 📚
30
+
31
+ Check out the full [documentation](https://mxcube.github.io/argussight/) to explore everything, this project has to offer! Including:
32
+
33
+ - Information about all natively integrated video-related processes
34
+ - A detailed explanation about the project's core functionalities
35
+ - A comprehensive guide on how to start and run the project
36
+ - A developers guide
37
+ - and more!
38
+
39
+ ## Installation
40
+
41
+ First you need to clone the repository.
42
+
43
+ ```
44
+ git clone https://github.com/mxcube/argussight.git
45
+
46
+ # Navigate to the newly created directory
47
+ cd argussight
48
+ ```
49
+
50
+ Optionally, you can create a [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html) environment for this project
51
+
52
+ ```
53
+ conda env create -f conda-envrionment.yml
54
+ ```
55
+
56
+ If you chose not to, you need to have `ffmpeg` installed on your system, you can do so via your corresponding package manager.
57
+ On Debian-based Linux distributions (Ubuntu, Debian, Pop!_OS, ...) for example you can install it like this
58
+
59
+ ```
60
+ sudo apt-get install ffmpeg
61
+ ```
62
+
63
+ Now install the remaining dependencies using `pip`
64
+
65
+ ```
66
+ # for Development
67
+ pip install -e .
68
+
69
+ # for Usage
70
+ pip install .
71
+ ```
72
+
73
+ or `poetry`
74
+
75
+ ```
76
+ poetry install
77
+ ```
78
+
79
+ ## Usage
80
+
81
+ > ### ⚠️ Attention ⚠️
82
+ > If you want to use the `Recorder` class (enabled per default), please be aware that it creates a temporary folder in the location, you start the server at.
83
+ > In the configurations folder, you can change the name of said folder, please make sure that no other folder in your current location has the same name, as it will otherwise **delete** the contents of that folder (default is `temp`).
84
+ > - To rename the temporary folder, go to `argussight/core/configurations/processes/savers/video_recorder.yaml` and change the value of `temp_folder`.
85
+ > - To disable the `Recorder` class, go to `argussight/core/configurations/config.yaml` and remove the process named `Recorder`
86
+
87
+ ### Start the Server
88
+
89
+ Once you installed all the dependencies, you can run the `argussight` server by using
90
+
91
+ ```
92
+ argussight
93
+ ```
94
+
95
+ command in a terminal window.
96
+
97
+ ### Start communication with the GRPC Server
98
+
99
+ To communicate with the grpc server, you need to establish a connection with the channel. By default the server is running on port 50051 (changeable in the `argussight/grpc/server.py` file). The code example below shows how to start a connection and get a response for the `GetProcessesRequest`:
100
+
101
+ ```
102
+ import grpc
103
+ import argussight.grpc.argus_service_pb2 as pb2
104
+ import argussight.grpc.argus_service_pb2_grpc as pb2_grpc
105
+
106
+ channel = grpc.insecure_channel("localhost:50051")
107
+ stub = pb2_grpc.SpawnerServiceStub(channel)
108
+
109
+ # try to reach the server
110
+ try:
111
+ response = stub.GetProcesses(pb2.GetProcessesRequest())
112
+ except Exception as e:
113
+ # handle exception here
114
+ print(e)
115
+ ```
116
+
117
+ ### Access your streams
118
+
119
+ To access your streams, you first need a running streaming process. To create one, you need to make a process that inherits the `Streamer` class. Please refer to the [documentation](https://mxcube.github.io/argussight/devs/vprocess/#streamer) on how to do that. If your class inherits `Streamer` and is correctly configured in the `config.yaml` file, the `Argussight` class will take care of adding every instance of your class to the `Abstraction-Layer`. To access the streams from outside, you can then create a websocket connection to `ws://localhost:7000/ws/${name}`, where `localhost:7000` is the default location of the `Abstraction-Layer` (configurable in `config.yaml`), and `name` is the unique name of your process instance.
File without changes
File without changes
@@ -0,0 +1,20 @@
1
+ from typing import Union
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class RedisConfiguration(BaseModel):
7
+ host: str = Field("localhost", description="redis host")
8
+ port: int = Field(6379, description="redis port")
9
+ channel: str = Field(
10
+ "video-streamer", description="redis-channel to publish stream"
11
+ )
12
+
13
+
14
+ class CollectorConfiguration(BaseModel):
15
+ redis: RedisConfiguration
16
+
17
+
18
+ def get_config_from_dict(config_data: dict) -> Union[CollectorConfiguration, None]:
19
+ data = CollectorConfiguration(**config_data)
20
+ return data
@@ -0,0 +1,40 @@
1
+ ---
2
+
3
+ # This indicates the path to the files of the process classes
4
+ modules_path: argussight.core.video_processes
5
+
6
+ # List of available processes and their file locations from modules_path
7
+ # If accessible=true then process can be started via grpc call
8
+ worker_classes:
9
+ test:
10
+ location: vprocess.Test
11
+ accessible: true
12
+ flow_detection:
13
+ location: streamer.optical_flow_detection.OpticalFlowDetection
14
+ accessible: true
15
+ stream_buffer:
16
+ location: savers.stream_buffer.StreamBuffer
17
+ accessible: false
18
+ video_recorder:
19
+ location: savers.video_recorder.Recorder
20
+ accessible: false
21
+
22
+ # This indicates the processes that are started by argussight,
23
+ # if killed due to no response, they are restarted automatically
24
+ processes:
25
+ - name: "Saver"
26
+ type: stream_buffer
27
+ - name: "Recorder"
28
+ type: video_recorder
29
+
30
+ # This indicates the maximal waiting time (s),
31
+ # the spawner waits on responds from processes, before killing them
32
+ wait_time: 5
33
+
34
+ # This is the port for the rerouting of the streams
35
+ streams_layer_port: 7000
36
+
37
+ # Argussight is configured to run streams on different ports
38
+ # It will check for free ports, whenever a new streaming process starts
39
+ # The value below indicates at which port the search for a free port begins,
40
+ streams_starting_port: 9000
@@ -0,0 +1,15 @@
1
+ ---
2
+
3
+ parameters:
4
+ max_queue_len:
5
+ value: 200
6
+ exposed: false
7
+ main_save_folder:
8
+ value: "logs/"
9
+ exposed: false
10
+ save_format:
11
+ value: "both"
12
+ exposed: true
13
+ personnal_folder:
14
+ value: "test"
15
+ exposed: true
@@ -0,0 +1,22 @@
1
+ ---
2
+
3
+ parameters:
4
+ main_save_folder:
5
+ value: "logs/recordings"
6
+ exposed: false
7
+ # pay attention to the setting of the temp folder, as the folder will
8
+ # be cleared when the recorder is initialised,
9
+ # IMPORTANT: do NOT use an existing folder!!!
10
+ temp_folder:
11
+ value: "temp"
12
+ exposed: false
13
+ save_format:
14
+ value: "both"
15
+ exposed: true
16
+ personnal_folder:
17
+ value: "test"
18
+ exposed: true
19
+ max_recording_time:
20
+ # unit: seconds, 0 means not set
21
+ value: 0
22
+ exposed: false
@@ -0,0 +1,16 @@
1
+ ---
2
+
3
+ parameters:
4
+ main_save_folder:
5
+ value: "logs/"
6
+ exposed: false
7
+ save_format:
8
+ value: "both"
9
+ exposed: true
10
+ personnal_folder:
11
+ value: "test"
12
+ exposed: true
13
+ max_recording_time:
14
+ # unit: seconds, 0 means not set
15
+ value: 0
16
+ exposed: false
@@ -0,0 +1,21 @@
1
+ ---
2
+
3
+ parameters:
4
+ feature_params:
5
+ value:
6
+ maxCorners: 5
7
+ qualityLevel: 0.7
8
+ minDistance: 50
9
+ blockSize: 7
10
+ exposed: false
11
+
12
+ lk_params:
13
+ value:
14
+ winSize: [15, 15]
15
+ maxLevel: 2
16
+ criteria: [3, 10, 0.03]
17
+ exposed: false
18
+
19
+ roi:
20
+ value: [550, 450, 200, 500]
21
+ exposed: true
@@ -0,0 +1,16 @@
1
+ ---
2
+
3
+ parameters:
4
+ flow_params:
5
+ value:
6
+ pyr_scale: 0.5
7
+ levels: 3
8
+ winsize: 15
9
+ iterations: 3
10
+ poly_n: 5
11
+ poly_sigma: 1.1
12
+ flags: 0
13
+ exposed: false
14
+ roi:
15
+ value: [550, 450, 200, 500]
16
+ exposed: true
@@ -0,0 +1,35 @@
1
+ import socket
2
+ from typing import Union
3
+
4
+ import Levenshtein
5
+
6
+
7
+ def find_close_key(d: dict, key: str, max_distance: int = 3) -> Union[str, None]:
8
+ """Return first key in dict whose Levenshtein distance to key is <= max_distance"""
9
+ min_distance = float("inf")
10
+ closest_key = None
11
+
12
+ for dict_key in d:
13
+ distance = Levenshtein.distance(key, dict_key)
14
+ if distance < min_distance:
15
+ min_distance = distance
16
+ closest_key = dict_key
17
+
18
+ if min_distance <= max_distance:
19
+ return closest_key
20
+
21
+ return None
22
+
23
+
24
+ def is_port_free(port):
25
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
26
+ s.settimeout(1) # Optional: set a short timeout for connection attempt
27
+ result = s.connect_ex(("localhost", port))
28
+ return result != 0 # If result is non-zero, port is free
29
+
30
+
31
+ def find_free_port(start_port=9000):
32
+ port = start_port
33
+ while not is_port_free(port):
34
+ port += 1
35
+ return port
@@ -0,0 +1,71 @@
1
+ import queue
2
+ from datetime import datetime
3
+ from multiprocessing import Queue
4
+ from threading import Event
5
+
6
+ from argussight.core.video_processes.vprocess import ProcessError
7
+
8
+
9
+ class Manager:
10
+ def __init__(
11
+ self,
12
+ command_queue: Queue,
13
+ response_queue: Queue,
14
+ finished_event: Event,
15
+ failed_event: Event,
16
+ ) -> None:
17
+ self._commands_list = queue.Queue(
18
+ maxsize=20
19
+ ) # commands that are waiting to be processed by Manager
20
+ self._command_queue = (
21
+ command_queue # commands that are sent to process for being processed
22
+ )
23
+ self._response_queue = response_queue
24
+ self._finished_event = finished_event
25
+ self._failed_event = failed_event
26
+
27
+ def receive_command(
28
+ self,
29
+ command: str,
30
+ wait_time: int,
31
+ processed_event: Event,
32
+ result_queue: queue.Queue,
33
+ args,
34
+ ) -> None:
35
+ if self._commands_list.full():
36
+ raise ProcessError(
37
+ f"Cannot execute command {command}: too many commands in waiting list"
38
+ )
39
+ self._commands_list.put(
40
+ {
41
+ "command": command,
42
+ "max_wait_time": wait_time,
43
+ "time_stamp": datetime.now(),
44
+ "args": args,
45
+ "processed_event": processed_event,
46
+ "result_queue": result_queue,
47
+ }
48
+ )
49
+
50
+ def handle_commands(self) -> None:
51
+ while not self._commands_list.empty():
52
+ command = self._commands_list.get()
53
+
54
+ # Check if command is alive
55
+ if (datetime.now() - command["time_stamp"]).total_seconds() > command[
56
+ "max_wait_time"
57
+ ]:
58
+ continue
59
+
60
+ self._command_queue.put((command["command"], command["args"]))
61
+ command["processed_event"].set()
62
+
63
+ try:
64
+ result = self._response_queue.get(timeout=command["max_wait_time"])
65
+ command["result_queue"].put(result)
66
+
67
+ except queue.Empty:
68
+ self._failed_event.set()
69
+ break
70
+
71
+ self._finished_event.set()