matlab-proxy 0.25.1__py3-none-any.whl → 0.27.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.

Files changed (63) hide show
  1. matlab_proxy/app.py +68 -16
  2. matlab_proxy/app_state.py +8 -2
  3. matlab_proxy/constants.py +1 -0
  4. matlab_proxy/default_configuration.py +2 -2
  5. matlab_proxy/gui/index.html +1 -1
  6. matlab_proxy/gui/static/js/{index.CZgGkMCD.js → index.BcDShXfH.js} +16 -16
  7. matlab_proxy/settings.py +24 -2
  8. matlab_proxy/util/cookie_jar.py +72 -0
  9. matlab_proxy/util/list_servers.py +2 -2
  10. matlab_proxy/util/mwi/environment_variables.py +15 -0
  11. matlab_proxy/util/mwi/session_name.py +28 -0
  12. matlab_proxy/util/mwi/validators.py +2 -4
  13. {matlab_proxy-0.25.1.dist-info → matlab_proxy-0.27.0.dist-info}/METADATA +37 -23
  14. {matlab_proxy-0.25.1.dist-info → matlab_proxy-0.27.0.dist-info}/RECORD +29 -56
  15. {matlab_proxy-0.25.1.dist-info → matlab_proxy-0.27.0.dist-info}/WHEEL +1 -2
  16. matlab_proxy_manager/README.md +85 -0
  17. matlab_proxy_manager/lib/README.md +53 -0
  18. matlab_proxy_manager/lib/api.py +156 -114
  19. matlab_proxy_manager/storage/README.md +54 -0
  20. matlab_proxy_manager/storage/server.py +5 -2
  21. matlab_proxy_manager/utils/constants.py +2 -1
  22. matlab_proxy_manager/utils/environment_variables.py +6 -1
  23. matlab_proxy_manager/utils/exceptions.py +45 -0
  24. matlab_proxy_manager/utils/helpers.py +2 -2
  25. matlab_proxy_manager/utils/logger.py +4 -1
  26. matlab_proxy_manager/web/README.md +37 -0
  27. matlab_proxy_manager/web/app.py +71 -19
  28. matlab_proxy-0.25.1.dist-info/top_level.txt +0 -3
  29. tests/integration/__init__.py +0 -1
  30. tests/integration/integration_tests_with_license/__init__.py +0 -1
  31. tests/integration/integration_tests_with_license/conftest.py +0 -47
  32. tests/integration/integration_tests_with_license/test_http_end_points.py +0 -397
  33. tests/integration/integration_tests_without_license/__init__.py +0 -1
  34. tests/integration/integration_tests_without_license/conftest.py +0 -116
  35. tests/integration/integration_tests_without_license/test_matlab_is_down_if_unlicensed.py +0 -49
  36. tests/integration/utils/__init__.py +0 -1
  37. tests/integration/utils/integration_tests_utils.py +0 -352
  38. tests/integration/utils/licensing.py +0 -152
  39. tests/unit/__init__.py +0 -1
  40. tests/unit/conftest.py +0 -66
  41. tests/unit/test_app.py +0 -1200
  42. tests/unit/test_app_state.py +0 -1094
  43. tests/unit/test_constants.py +0 -7
  44. tests/unit/test_ddux.py +0 -22
  45. tests/unit/test_devel.py +0 -246
  46. tests/unit/test_non_dev_mode.py +0 -169
  47. tests/unit/test_settings.py +0 -659
  48. tests/unit/util/__init__.py +0 -3
  49. tests/unit/util/mwi/__init__.py +0 -1
  50. tests/unit/util/mwi/embedded_connector/__init__.py +0 -1
  51. tests/unit/util/mwi/embedded_connector/test_helpers.py +0 -29
  52. tests/unit/util/mwi/embedded_connector/test_request.py +0 -64
  53. tests/unit/util/mwi/test_custom_http_headers.py +0 -281
  54. tests/unit/util/mwi/test_download.py +0 -152
  55. tests/unit/util/mwi/test_logger.py +0 -82
  56. tests/unit/util/mwi/test_token_auth.py +0 -303
  57. tests/unit/util/mwi/test_validators.py +0 -364
  58. tests/unit/util/test_mw.py +0 -550
  59. tests/unit/util/test_util.py +0 -221
  60. tests/utils/__init__.py +0 -1
  61. tests/utils/logging_util.py +0 -81
  62. {matlab_proxy-0.25.1.dist-info → matlab_proxy-0.27.0.dist-info}/entry_points.txt +0 -0
  63. {matlab_proxy-0.25.1.dist-info → matlab_proxy-0.27.0.dist-info/licenses}/LICENSE.md +0 -0
matlab_proxy/app.py CHANGED
@@ -209,6 +209,8 @@ async def get_env_config(req):
209
209
  "supportedVersions": constants.SUPPORTED_MATLAB_VERSIONS,
210
210
  }
211
211
 
212
+ config["browserTitle"] = state.settings["browser_title"]
213
+
212
214
  # Send timeout duration for the idle timer as part of the response
213
215
  config["idleTimeoutDuration"] = state.settings["mwi_idle_timeout"]
214
216
 
@@ -283,6 +285,10 @@ async def start_matlab(req):
283
285
  JSONResponse: JSONResponse object containing updated information on the state of MATLAB among other information.
284
286
  """
285
287
  state = req.app["state"]
288
+ cookie_jar = req.app["settings"]["cookie_jar"]
289
+
290
+ if cookie_jar:
291
+ cookie_jar.clear()
286
292
 
287
293
  # Start MATLAB
288
294
  await state.start_matlab(restart_matlab=True)
@@ -349,7 +355,7 @@ async def set_licensing_info(req):
349
355
  raise Exception(
350
356
  'License type must be "NLM" or "MHLM" or "ExistingLicense"!'
351
357
  )
352
- except Exception as e:
358
+ except Exception:
353
359
  raise web.HTTPBadRequest(text="Error with licensing!")
354
360
 
355
361
  # This is true for a user who has only one license associated with their account
@@ -493,7 +499,7 @@ def make_static_route_table(app):
493
499
  Returns:
494
500
  Dict: Containing information about the static files and header information.
495
501
  """
496
- import importlib_resources
502
+ import importlib_resources as resources
497
503
 
498
504
  from matlab_proxy import gui
499
505
  from matlab_proxy.gui import static
@@ -505,14 +511,14 @@ def make_static_route_table(app):
505
511
 
506
512
  for mod, parent in [
507
513
  (gui.__name__, ""),
508
- (gui.static.__name__, "/static"),
509
- (gui.static.css.__name__, "/static/css"),
510
- (gui.static.js.__name__, "/static/js"),
511
- (gui.static.media.__name__, "/static/media"),
514
+ (static.__name__, "/static"),
515
+ (css.__name__, "/static/css"),
516
+ (js.__name__, "/static/js"),
517
+ (media.__name__, "/static/media"),
512
518
  ]:
513
- for entry in importlib_resources.files(mod).iterdir():
519
+ for entry in resources.files(mod).iterdir():
514
520
  name = entry.name
515
- if not importlib_resources.files(mod).joinpath(name).is_dir():
521
+ if not resources.files(mod).joinpath(name).is_dir():
516
522
  if name != "__init__.py":
517
523
  # Special case for manifest.json
518
524
  if "manifest.json" in name:
@@ -557,6 +563,9 @@ async def matlab_view(req):
557
563
  matlab_protocol = req.app["settings"]["matlab_protocol"]
558
564
  mwapikey = req.app["settings"]["mwapikey"]
559
565
  matlab_base_url = f"{matlab_protocol}://127.0.0.1:{matlab_port}"
566
+ cookie_jar = req.app["settings"]["cookie_jar"]
567
+
568
+ cookies_from_jar = cookie_jar.get_dict() if cookie_jar else None
560
569
 
561
570
  # If we are trying to send request to matlab while the matlab_port is still not assigned
562
571
  # by embedded connector, return service not available and log a message
@@ -575,17 +584,23 @@ async def matlab_view(req):
575
584
  and reqH.get(UPGRADE, "").lower() == "websocket"
576
585
  and req.method == "GET"
577
586
  ):
578
- ws_server = web.WebSocketResponse()
587
+ ws_server = web.WebSocketResponse(
588
+ max_msg_size=constants.MAX_WEBSOCKET_MESSAGE_SIZE_IN_MB, compress=True
589
+ )
579
590
  await ws_server.prepare(req)
580
591
 
581
592
  async with aiohttp.ClientSession(
593
+ cookies=(
594
+ cookies_from_jar if cookie_jar else req.cookies
595
+ ), # If cookie jar is not provided, use the cookies from the incoming request
582
596
  trust_env=True,
583
- cookies=req.cookies,
584
597
  connector=aiohttp.TCPConnector(ssl=False),
585
598
  ) as client_session:
586
599
  try:
587
600
  async with client_session.ws_connect(
588
601
  matlab_base_url + req.path_qs,
602
+ max_msg_size=constants.MAX_WEBSOCKET_MESSAGE_SIZE_IN_MB, # max websocket message size from MATLAB to browser
603
+ compress=12, # enable websocket messages compression
589
604
  ) as ws_client:
590
605
 
591
606
  async def wsforward(ws_from, ws_to):
@@ -617,16 +632,28 @@ async def matlab_view(req):
617
632
  await ws_to.close(
618
633
  code=ws_to.close_code, message=msg.extra
619
634
  )
635
+ elif mt == aiohttp.WSMsgType.ERROR:
636
+ logger.error(f"WebSocket error received: {msg}")
637
+ if "exceeds limit" in str(msg.data):
638
+ logger.error(
639
+ f"Message too large: {msg.data}. Please refresh browser tab to reconnect."
640
+ )
641
+ break
620
642
  else:
621
643
  raise ValueError(f"Unexpected message type: {msg}")
622
644
 
623
645
  await asyncio.wait(
624
646
  [
625
- asyncio.create_task(wsforward(ws_server, ws_client)),
626
- asyncio.create_task(wsforward(ws_client, ws_server)),
647
+ asyncio.create_task(
648
+ wsforward(ws_server, ws_client)
649
+ ), # browser to MATLAB
650
+ asyncio.create_task(
651
+ wsforward(ws_client, ws_server)
652
+ ), # MATLAB to browser
627
653
  ],
628
654
  return_when=asyncio.FIRST_COMPLETED,
629
655
  )
656
+
630
657
  return ws_server
631
658
 
632
659
  except Exception as err:
@@ -666,11 +693,37 @@ async def matlab_view(req):
666
693
  allow_redirects=False,
667
694
  data=req_body,
668
695
  params=None,
696
+ cookies=cookies_from_jar, # Pass cookies from cookie_jar for HTTP requests to MATLAB. This value will
697
+ # be none if cookie jar is not enabled
669
698
  ) as res:
670
699
  headers = res.headers.copy()
671
700
  body = await res.read()
672
- headers.update(req.app["settings"]["mwi_custom_http_headers"])
673
- return web.Response(headers=headers, status=res.status, body=body)
701
+
702
+ response = web.Response(
703
+ status=res.status, headers=headers, body=body
704
+ )
705
+
706
+ # Purpose of the cookie-jar in matlab-proxy is to:
707
+ # 1) Update the cookies within it when the Embedded Connector sends back Set-Cookie headers in the response.
708
+ # 2) Read these cookies from the cookie jar and insert them into subsequent requests to the Embedded Connector.
709
+
710
+ # Due to matlab-proxy's PING requests to EC, the number cookies present in the cookie-jar and their
711
+ # value will be more than the ones present on the browser side.
712
+ # Example: The JSESSIONID cookie will be present in the cookie-jar but not on the browser side.
713
+ # This inconsistency of cookies between the browser and matlab-proxy's cookie-jar is expected and okay
714
+ # as these cookies are HttpOnly cookies.
715
+
716
+ # Incase the Embedded Connector sends cookies which are not HttpOnly, then additional logic needs to be written
717
+ # to update the response with cookies from the cookie jar before it is forwarded to the browser.
718
+ if cookie_jar:
719
+ # Update the cookies in the cookie jar with the Set-Cookie headers in the response.
720
+ cookie_jar.update_from_response_headers(headers)
721
+
722
+ response.headers.update(
723
+ req.app["settings"]["mwi_custom_http_headers"]
724
+ )
725
+
726
+ return response
674
727
 
675
728
  # Handles any pending HTTP requests from the browser when the MATLAB process is terminated before responding to them.
676
729
  except (
@@ -852,7 +905,7 @@ def configure_and_start(app):
852
905
 
853
906
  logger.debug("Starting MATLAB proxy app")
854
907
  logger.debug(
855
- f' with base_url: {app["settings"]["base_url"]} and app_port:{app["settings"]["app_port"]}.'
908
+ f" with base_url: {app['settings']['base_url']} and app_port:{app['settings']['app_port']}."
856
909
  )
857
910
 
858
911
  app["state"].create_server_info_file()
@@ -987,7 +1040,6 @@ def print_version_and_exit():
987
1040
 
988
1041
  def main():
989
1042
  """Starting point of the integration. Creates the web app and runs indefinitely."""
990
-
991
1043
  if util.parse_cli_args()["version"]:
992
1044
  print_version_and_exit()
993
1045
 
matlab_proxy/app_state.py CHANGED
@@ -896,8 +896,14 @@ class AppState:
896
896
 
897
897
  mwi_server_info_file = mwi_logs_dir / "mwi_server.info"
898
898
  mwi_auth_token_str = token_auth.get_mwi_auth_token_access_str(self.settings)
899
- with open(mwi_server_info_file, "w") as fh:
900
- fh.write(self.settings["mwi_server_url"] + mwi_auth_token_str + "\n")
899
+ with open(mwi_server_info_file, "w", encoding="utf-8") as fh:
900
+ fh.write(
901
+ self.settings["mwi_server_url"]
902
+ + mwi_auth_token_str
903
+ + "\n"
904
+ + self.settings["browser_title"]
905
+ + "\n"
906
+ )
901
907
  self.mwi_server_session_files["mwi_server_info_file"] = mwi_server_info_file
902
908
  logger.debug(f"Server info stored into: {mwi_server_info_file}")
903
909
 
matlab_proxy/constants.py CHANGED
@@ -6,6 +6,7 @@ from typing import Final, List
6
6
  CONNECTOR_SECUREPORT_FILENAME: Final[str] = "connector.securePort"
7
7
  VERSION_INFO_FILE_NAME: Final[str] = "VersionInfo.xml"
8
8
  MAX_HTTP_REQUEST_SIZE: Final[int] = 500_000_000 # 500MB
9
+ MAX_WEBSOCKET_MESSAGE_SIZE_IN_MB: Final[int] = 500_000_000 # 500MB
9
10
  MATLAB_LOGS_FILE_NAME: Final[str] = "matlab_logs.txt"
10
11
  USER_CODE_OUTPUT_FILE_NAME: Final[str] = "startup_code_output.txt"
11
12
 
@@ -1,4 +1,4 @@
1
- # Copyright 2020-2024 The MathWorks, Inc.
1
+ # Copyright 2020-2025 The MathWorks, Inc.
2
2
  from enum import Enum
3
3
  from typing import List
4
4
 
@@ -45,7 +45,7 @@ def get_required_config() -> List[str]:
45
45
  list: A list of strings representing the required
46
46
  configuration keys.
47
47
  """
48
- required_keys: List[str] = [
48
+ required_keys: List[ConfigKeys] = [
49
49
  ConfigKeys.DOC_URL,
50
50
  ConfigKeys.EXT_NAME,
51
51
  ConfigKeys.EXT_NAME_DESC,
@@ -11,7 +11,7 @@
11
11
  <meta name="internal_mw_identifier" content="MWI_MATLAB_PROXY_IDENTIFIER" />
12
12
  <link rel="manifest" href="./manifest.json" />
13
13
  <title>MATLAB</title>
14
- <script type="module" crossorigin src="./static/js/index.CZgGkMCD.js"></script>
14
+ <script type="module" crossorigin src="./static/js/index.BcDShXfH.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="./static/css/index.BSVLACuY.css">
16
16
  </head>
17
17
  <body>