matlab-proxy 0.18.2__py3-none-any.whl → 0.20.0__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.
Potentially problematic release.
This version of matlab-proxy might be problematic. Click here for more details.
- matlab_proxy/app.py +73 -55
- matlab_proxy/app_state.py +370 -155
- matlab_proxy/constants.py +3 -0
- matlab_proxy/gui/asset-manifest.json +6 -6
- matlab_proxy/gui/index.html +1 -1
- matlab_proxy/gui/static/css/{main.47712126.css → main.da9c4eb8.css} +2 -2
- matlab_proxy/gui/static/css/main.da9c4eb8.css.map +1 -0
- matlab_proxy/gui/static/js/{main.5b5ca2f2.js → main.9c68c75c.js} +3 -3
- matlab_proxy/gui/static/js/main.9c68c75c.js.map +1 -0
- matlab_proxy/matlab/startup.m +0 -20
- matlab_proxy/settings.py +16 -1
- matlab_proxy/util/__init__.py +101 -1
- matlab_proxy/util/event_loop.py +28 -10
- matlab_proxy/util/mwi/embedded_connector/__init__.py +1 -1
- matlab_proxy/util/mwi/embedded_connector/helpers.py +9 -0
- matlab_proxy/util/mwi/embedded_connector/request.py +51 -21
- matlab_proxy/util/mwi/environment_variables.py +5 -0
- matlab_proxy/util/mwi/exceptions.py +16 -1
- matlab_proxy/util/mwi/logger.py +22 -2
- matlab_proxy/util/mwi/validators.py +33 -0
- matlab_proxy/util/windows.py +4 -1
- {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.20.0.dist-info}/METADATA +15 -15
- {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.20.0.dist-info}/RECORD +34 -34
- {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.20.0.dist-info}/WHEEL +1 -1
- tests/unit/test_app.py +45 -22
- tests/unit/test_app_state.py +404 -111
- tests/unit/test_constants.py +1 -0
- tests/unit/util/mwi/test_logger.py +38 -4
- tests/unit/util/mwi/test_validators.py +30 -1
- tests/unit/util/test_util.py +83 -0
- matlab_proxy/gui/static/css/main.47712126.css.map +0 -1
- matlab_proxy/gui/static/js/main.5b5ca2f2.js.map +0 -1
- /matlab_proxy/gui/static/js/{main.5b5ca2f2.js.LICENSE.txt → main.9c68c75c.js.LICENSE.txt} +0 -0
- {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.20.0.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.20.0.dist-info}/entry_points.txt +0 -0
- {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.20.0.dist-info}/top_level.txt +0 -0
matlab_proxy/app.py
CHANGED
|
@@ -94,9 +94,7 @@ def marshal_error(error):
|
|
|
94
94
|
return {"message": error.__str__, "logs": "", "type": error.__class__.__name__}
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
app, loadUrl=None, client_id=None, is_active_client=None
|
|
99
|
-
):
|
|
97
|
+
def create_status_response(app, loadUrl=None, client_id=None, is_active_client=None):
|
|
100
98
|
"""Send a generic status response about the state of server, MATLAB, MATLAB Licensing and the client session status.
|
|
101
99
|
|
|
102
100
|
Args:
|
|
@@ -111,7 +109,8 @@ async def create_status_response(
|
|
|
111
109
|
state = app["state"]
|
|
112
110
|
status = {
|
|
113
111
|
"matlab": {
|
|
114
|
-
"status":
|
|
112
|
+
"status": state.get_matlab_state(),
|
|
113
|
+
"busyStatus": state.matlab_busy_state,
|
|
115
114
|
"version": state.settings["matlab_version"],
|
|
116
115
|
},
|
|
117
116
|
"licensing": marshal_licensing_info(state.licensing),
|
|
@@ -139,14 +138,31 @@ async def clear_client_id(req):
|
|
|
139
138
|
Returns:
|
|
140
139
|
Response: an empty response in JSON format
|
|
141
140
|
"""
|
|
142
|
-
# Sleep for one second prior to clearing the client id to ensure that any remaining get_status responses are fully processed first.
|
|
143
|
-
await asyncio.sleep(1)
|
|
144
141
|
state = req.app["state"]
|
|
145
142
|
state.active_client = None
|
|
143
|
+
logger.debug("Client Id was cleaned!!!")
|
|
146
144
|
# This response is of no relevance to the front-end as the client has already exited
|
|
147
145
|
return web.json_response({})
|
|
148
146
|
|
|
149
147
|
|
|
148
|
+
def reset_timer_decorator(endpoint):
|
|
149
|
+
"""This decorator resets the IDLE timer if MWI_IDLE_TIMEOUT environment variable is supplied.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
endpoint (callable): An asynchronous function which is a request handler.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
async def reset_timer(req):
|
|
156
|
+
state = req.app["state"]
|
|
157
|
+
|
|
158
|
+
if state.is_idle_timeout_enabled:
|
|
159
|
+
await state.reset_timer()
|
|
160
|
+
|
|
161
|
+
return await endpoint(req)
|
|
162
|
+
|
|
163
|
+
return reset_timer
|
|
164
|
+
|
|
165
|
+
|
|
150
166
|
@token_auth.authenticate_access_decorator
|
|
151
167
|
async def get_auth_token(req):
|
|
152
168
|
"""API endpoint to return the auth token
|
|
@@ -192,15 +208,19 @@ async def get_env_config(req):
|
|
|
192
208
|
|
|
193
209
|
config["matlab"] = {
|
|
194
210
|
"version": state.settings["matlab_version"],
|
|
195
|
-
"
|
|
211
|
+
"supportedVersions": constants.SUPPORTED_MATLAB_VERSIONS,
|
|
196
212
|
}
|
|
197
213
|
|
|
214
|
+
# Send timeout duration for the idle timer as part of the response
|
|
215
|
+
config["idleTimeoutDuration"] = state.settings["mwi_idle_timeout"]
|
|
216
|
+
|
|
198
217
|
return web.json_response(config)
|
|
199
218
|
|
|
200
219
|
|
|
201
220
|
# @token_auth.authenticate_access_decorator
|
|
202
221
|
# Explicitly disabling authentication for this end-point,
|
|
203
222
|
# because the front end requires this endpoint to be available at all times.
|
|
223
|
+
@reset_timer_decorator
|
|
204
224
|
async def get_status(req):
|
|
205
225
|
"""API Endpoint to get the generic status of the server, MATLAB and MATLAB Licensing.
|
|
206
226
|
|
|
@@ -220,7 +240,7 @@ async def get_status(req):
|
|
|
220
240
|
is_desktop, client_id, transfer_session
|
|
221
241
|
)
|
|
222
242
|
|
|
223
|
-
return
|
|
243
|
+
return create_status_response(
|
|
224
244
|
req.app, client_id=generated_client_id, is_active_client=is_active_client
|
|
225
245
|
)
|
|
226
246
|
|
|
@@ -269,7 +289,7 @@ async def start_matlab(req):
|
|
|
269
289
|
# Start MATLAB
|
|
270
290
|
await state.start_matlab(restart_matlab=True)
|
|
271
291
|
|
|
272
|
-
return
|
|
292
|
+
return create_status_response(req.app)
|
|
273
293
|
|
|
274
294
|
|
|
275
295
|
@token_auth.authenticate_access_decorator
|
|
@@ -286,7 +306,7 @@ async def stop_matlab(req):
|
|
|
286
306
|
|
|
287
307
|
await state.stop_matlab()
|
|
288
308
|
|
|
289
|
-
return
|
|
309
|
+
return create_status_response(req.app)
|
|
290
310
|
|
|
291
311
|
|
|
292
312
|
@token_auth.authenticate_access_decorator
|
|
@@ -337,7 +357,7 @@ async def set_licensing_info(req):
|
|
|
337
357
|
# This is true for a user who has only one license associated with their account
|
|
338
358
|
await __start_matlab_if_licensed(state)
|
|
339
359
|
|
|
340
|
-
return
|
|
360
|
+
return create_status_response(req.app)
|
|
341
361
|
|
|
342
362
|
|
|
343
363
|
@token_auth.authenticate_access_decorator
|
|
@@ -361,7 +381,7 @@ async def update_entitlement(req):
|
|
|
361
381
|
await state.update_user_selected_entitlement_info(entitlement_id)
|
|
362
382
|
await __start_matlab_if_licensed(state)
|
|
363
383
|
|
|
364
|
-
return
|
|
384
|
+
return create_status_response(req.app)
|
|
365
385
|
|
|
366
386
|
|
|
367
387
|
async def __start_matlab_if_licensed(state):
|
|
@@ -397,35 +417,36 @@ async def licensing_info_delete(req):
|
|
|
397
417
|
# Persist config information
|
|
398
418
|
state.persist_config_data()
|
|
399
419
|
|
|
400
|
-
return
|
|
420
|
+
return create_status_response(req.app)
|
|
401
421
|
|
|
402
422
|
|
|
403
423
|
@token_auth.authenticate_access_decorator
|
|
404
|
-
async def
|
|
405
|
-
"""API Endpoint to
|
|
424
|
+
async def shutdown_integration_delete(req):
|
|
425
|
+
"""API Endpoint to shutdown the Integration
|
|
406
426
|
|
|
407
427
|
Args:
|
|
408
428
|
req (HTTPRequest): HTTPRequest Object
|
|
409
429
|
"""
|
|
410
|
-
logger.debug("Terminating the integration...")
|
|
411
430
|
state = req.app["state"]
|
|
412
431
|
|
|
432
|
+
logger.info(f"Going ahead with shutdown of {state.settings['integration_name']}...")
|
|
433
|
+
|
|
413
434
|
# Send response manually because this has to happen before the application exits
|
|
414
|
-
res =
|
|
435
|
+
res = create_status_response(req.app, "../")
|
|
415
436
|
await res.prepare(req)
|
|
416
437
|
await res.write_eof()
|
|
417
438
|
|
|
418
|
-
|
|
419
|
-
# End termination with 0 exit code to indicate intentional termination
|
|
439
|
+
# Gracefully shutdown the server
|
|
420
440
|
await req.app.shutdown()
|
|
421
441
|
await req.app.cleanup()
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
442
|
+
|
|
443
|
+
loop = util.get_event_loop()
|
|
444
|
+
# Run the current batch of coroutines in the event loop and then exit.
|
|
445
|
+
# This completes the loop.run_forever() blocking call and subsequent code
|
|
446
|
+
# in create_and_start_app() resumes execution.
|
|
447
|
+
loop.stop()
|
|
448
|
+
|
|
449
|
+
return res
|
|
429
450
|
|
|
430
451
|
|
|
431
452
|
# @token_auth.authenticate_access_decorator
|
|
@@ -562,7 +583,7 @@ async def matlab_view(req):
|
|
|
562
583
|
async with aiohttp.ClientSession(
|
|
563
584
|
trust_env=True,
|
|
564
585
|
cookies=req.cookies,
|
|
565
|
-
connector=aiohttp.TCPConnector(
|
|
586
|
+
connector=aiohttp.TCPConnector(ssl=False),
|
|
566
587
|
) as client_session:
|
|
567
588
|
try:
|
|
568
589
|
async with client_session.ws_connect(
|
|
@@ -628,7 +649,7 @@ async def matlab_view(req):
|
|
|
628
649
|
timeout = aiohttp.ClientTimeout(total=None)
|
|
629
650
|
async with aiohttp.ClientSession(
|
|
630
651
|
trust_env=True,
|
|
631
|
-
connector=aiohttp.TCPConnector(
|
|
652
|
+
connector=aiohttp.TCPConnector(ssl=False),
|
|
632
653
|
timeout=timeout,
|
|
633
654
|
) as client_session:
|
|
634
655
|
try:
|
|
@@ -754,7 +775,7 @@ async def matlab_starter(app):
|
|
|
754
775
|
state = app["state"]
|
|
755
776
|
|
|
756
777
|
try:
|
|
757
|
-
if state.is_licensed() and
|
|
778
|
+
if state.is_licensed() and state.get_matlab_state() == "down":
|
|
758
779
|
await state.start_matlab()
|
|
759
780
|
except asyncio.CancelledError:
|
|
760
781
|
# Ensure MATLAB is terminated
|
|
@@ -785,19 +806,9 @@ async def cleanup_background_tasks(app):
|
|
|
785
806
|
|
|
786
807
|
await state.stop_matlab(force_quit=True)
|
|
787
808
|
|
|
788
|
-
#
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
if state.task_detect_client_status:
|
|
792
|
-
tasks["detect_client_status"] = state.task_detect_client_status
|
|
793
|
-
for task_name, task in tasks.items():
|
|
794
|
-
if not task.cancelled():
|
|
795
|
-
logger.debug(f"Cancelling MWI task: {task_name} : {task} ")
|
|
796
|
-
task.cancel()
|
|
797
|
-
try:
|
|
798
|
-
await task
|
|
799
|
-
except asyncio.CancelledError:
|
|
800
|
-
pass
|
|
809
|
+
# Cleanup server tasks
|
|
810
|
+
server_tasks = state.server_tasks
|
|
811
|
+
await util.cancel_tasks(server_tasks)
|
|
801
812
|
|
|
802
813
|
|
|
803
814
|
def configure_and_start(app):
|
|
@@ -893,7 +904,7 @@ def create_app(config_name=matlab_proxy.get_default_config_name()):
|
|
|
893
904
|
"DELETE", f"{base_url}/set_licensing_info", licensing_info_delete
|
|
894
905
|
)
|
|
895
906
|
app.router.add_route(
|
|
896
|
-
"DELETE", f"{base_url}/
|
|
907
|
+
"DELETE", f"{base_url}/shutdown_integration", shutdown_integration_delete
|
|
897
908
|
)
|
|
898
909
|
app.router.add_route("*", f"{base_url}/", root_redirect)
|
|
899
910
|
app.router.add_route("*", f"{base_url}", root_redirect)
|
|
@@ -925,6 +936,11 @@ def configure_no_proxy_in_env():
|
|
|
925
936
|
|
|
926
937
|
|
|
927
938
|
def create_and_start_app(config_name):
|
|
939
|
+
"""Creates and start the web server. Will block until the server is interrupted or is shut down
|
|
940
|
+
|
|
941
|
+
Args:
|
|
942
|
+
config_name (str): Name of the configuration to use with matlab-proxy.
|
|
943
|
+
"""
|
|
928
944
|
configure_no_proxy_in_env()
|
|
929
945
|
|
|
930
946
|
# Create, configure and start the app.
|
|
@@ -936,23 +952,25 @@ def create_and_start_app(config_name):
|
|
|
936
952
|
# Add signal handlers for the current python process
|
|
937
953
|
loop = util.add_signal_handlers(loop)
|
|
938
954
|
try:
|
|
955
|
+
# Further execution is stopped here until an interrupt is raised
|
|
939
956
|
loop.run_forever()
|
|
957
|
+
|
|
940
958
|
except SystemExit:
|
|
941
959
|
pass
|
|
942
960
|
|
|
943
|
-
|
|
944
|
-
"""Shuts down the app in the event of a signal interrupt."""
|
|
945
|
-
logger.info("Shutting down MATLAB proxy-app")
|
|
946
|
-
|
|
947
|
-
await app.shutdown()
|
|
948
|
-
await app.cleanup()
|
|
949
|
-
|
|
950
|
-
# Shutdown any running tasks.
|
|
951
|
-
await util.cancel_tasks(asyncio.all_tasks())
|
|
952
|
-
|
|
961
|
+
# After handling the interrupt, proceed with shutting down the server gracefully.
|
|
953
962
|
try:
|
|
954
|
-
|
|
955
|
-
|
|
963
|
+
running_tasks = asyncio.all_tasks(loop)
|
|
964
|
+
loop.run_until_complete(
|
|
965
|
+
asyncio.gather(
|
|
966
|
+
app.shutdown(),
|
|
967
|
+
app.cleanup(),
|
|
968
|
+
util.cancel_tasks(running_tasks),
|
|
969
|
+
return_exceptions=False,
|
|
970
|
+
)
|
|
971
|
+
)
|
|
972
|
+
|
|
973
|
+
except Exception:
|
|
956
974
|
pass
|
|
957
975
|
|
|
958
976
|
logger.info("Finished shutting down. Thank you for using the MATLAB proxy.")
|