matlab-proxy 0.5.3__py3-none-any.whl → 0.30.1__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.
- matlab_proxy/app.py +578 -205
- matlab_proxy/app_state.py +1061 -431
- matlab_proxy/constants.py +37 -0
- matlab_proxy/default_configuration.py +39 -4
- matlab_proxy/devel.py +18 -22
- matlab_proxy/gui/index.html +20 -1
- matlab_proxy/gui/static/css/index.BedVwcEg.css +10 -0
- matlab_proxy/gui/static/js/index.pQwV1obF.js +64 -0
- matlab_proxy/gui/static/media/MATLAB-env-blur.NupTbPv_.png +0 -0
- matlab_proxy/matlab/evaluateUserMatlabCode.m +51 -0
- matlab_proxy/matlab/startup.m +3 -28
- matlab_proxy/settings.py +543 -112
- matlab_proxy/util/__init__.py +187 -59
- matlab_proxy/util/cookie_jar.py +72 -0
- matlab_proxy/util/event_loop.py +28 -10
- matlab_proxy/util/list_servers.py +71 -26
- matlab_proxy/util/mw.py +16 -15
- matlab_proxy/util/mwi/download.py +136 -0
- matlab_proxy/util/mwi/embedded_connector/__init__.py +1 -1
- matlab_proxy/util/mwi/embedded_connector/helpers.py +12 -4
- matlab_proxy/util/mwi/embedded_connector/request.py +78 -12
- matlab_proxy/util/mwi/environment_variables.py +120 -27
- matlab_proxy/util/mwi/exceptions.py +63 -9
- matlab_proxy/util/mwi/logger.py +141 -27
- matlab_proxy/util/mwi/session_name.py +28 -0
- matlab_proxy/util/mwi/token_auth.py +264 -121
- matlab_proxy/util/mwi/validators.py +231 -88
- matlab_proxy/util/system.py +9 -0
- matlab_proxy/util/windows.py +32 -6
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info}/METADATA +94 -49
- matlab_proxy-0.30.1.dist-info/RECORD +88 -0
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info}/WHEEL +1 -2
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info}/entry_points.txt +1 -1
- matlab_proxy_manager/README.md +85 -0
- matlab_proxy_manager/__init__.py +6 -0
- matlab_proxy_manager/lib/README.md +53 -0
- matlab_proxy_manager/lib/__init__.py +1 -0
- matlab_proxy_manager/lib/api.py +419 -0
- matlab_proxy_manager/storage/README.md +54 -0
- matlab_proxy_manager/storage/__init__.py +1 -0
- matlab_proxy_manager/storage/file_repository.py +144 -0
- matlab_proxy_manager/storage/interface.py +62 -0
- matlab_proxy_manager/storage/server.py +172 -0
- matlab_proxy_manager/utils/__init__.py +1 -0
- matlab_proxy_manager/utils/auth.py +77 -0
- matlab_proxy_manager/utils/constants.py +8 -0
- matlab_proxy_manager/utils/decorators.py +37 -0
- matlab_proxy_manager/utils/environment_variables.py +51 -0
- matlab_proxy_manager/utils/exceptions.py +45 -0
- matlab_proxy_manager/utils/helpers.py +314 -0
- matlab_proxy_manager/utils/logger.py +76 -0
- matlab_proxy_manager/web/README.md +37 -0
- matlab_proxy_manager/web/__init__.py +1 -0
- matlab_proxy_manager/web/app.py +536 -0
- matlab_proxy_manager/web/monitor.py +45 -0
- matlab_proxy_manager/web/watcher.py +65 -0
- matlab_proxy/gui/asset-manifest.json +0 -23
- matlab_proxy/gui/authorization.html +0 -115
- matlab_proxy/gui/bootstrap.3.4.1.min.css +0 -6
- matlab_proxy/gui/navbar.css +0 -8
- matlab_proxy/gui/signin.css +0 -42
- matlab_proxy/gui/static/css/main.d890078a.chunk.css +0 -13
- matlab_proxy/gui/static/css/main.d890078a.chunk.css.map +0 -1
- matlab_proxy/gui/static/js/2.13be6544.chunk.js +0 -3
- matlab_proxy/gui/static/js/2.13be6544.chunk.js.LICENSE.txt +0 -59
- matlab_proxy/gui/static/js/2.13be6544.chunk.js.map +0 -1
- matlab_proxy/gui/static/js/main.c311d854.chunk.js +0 -2
- matlab_proxy/gui/static/js/main.c311d854.chunk.js.map +0 -1
- matlab_proxy/gui/static/js/runtime-main.f70e4d5f.js +0 -2
- matlab_proxy/gui/static/js/runtime-main.f70e4d5f.js.map +0 -1
- matlab_proxy/gui/static/media/arrow.0c2968b9.svg +0 -4
- matlab_proxy/gui/static/media/feedback.6e8d50eb.svg +0 -1
- matlab_proxy/gui/static/media/gripper.9defbc5e.svg +0 -1
- matlab_proxy/gui/static/media/help.15e5bfab.svg +0 -1
- matlab_proxy/gui/static/media/ico-header-contact-hover.0958c442.svg +0 -17
- matlab_proxy/gui/static/media/ico-header-contact.ae9169c8.svg +0 -17
- matlab_proxy/gui/static/media/restart.7987508a.svg +0 -1
- matlab_proxy/gui/static/media/sign-out.08356b67.svg +0 -1
- matlab_proxy/gui/static/media/start.50c4596f.svg +0 -1
- matlab_proxy/gui/static/media/stop.30c9a9ab.svg +0 -1
- matlab_proxy/gui/static/media/terminate.7ea1363e.svg +0 -1
- matlab_proxy/gui/token.html +0 -123
- matlab_proxy-0.5.3.dist-info/RECORD +0 -84
- matlab_proxy-0.5.3.dist-info/top_level.txt +0 -1
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.82b1212e.woff → glyphicons-halflings-regular.BKjkU69z.woff} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.5be1347c.eot → glyphicons-halflings-regular.BUJKDMgK.eot} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.060b2710.svg → glyphicons-halflings-regular.CSehLiBc.svg} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.4692b9ec.ttf → glyphicons-halflings-regular.DrwTMapi.ttf} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.be810be3.woff2 → glyphicons-halflings-regular.DzqM6ju8.woff2} +0 -0
- /matlab_proxy/gui/static/media/{ico-header-account-hover.89438e91.svg → ico-header-account-hover.-jQHo6Wx.svg} +0 -0
- /matlab_proxy/gui/static/media/{ico-header-account.86b10d7b.svg → ico-header-account.CJCFoo5a.svg} +0 -0
- /matlab_proxy/gui/static/media/{ico-sprite.cbdb66c0.png → ico-sprite.DXGLgzq9.png} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-eps.4d20e0ee.ttf → mathworks-eps.CGNQALa9.ttf} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-eps.df1428df.svg → mathworks-eps.DrkCtQtG.svg} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-eps.e5c41e84.woff → mathworks-eps.Ds7lQbql.woff} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-pictograms.3fc6513a.woff → mathworks-pictograms.BdqxEfBR.woff} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-pictograms.f6f087b0.svg → mathworks-pictograms.CCLweoD4.svg} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-pictograms.6e128c0e.ttf → mathworks-pictograms.DZhFdRSm.ttf} +0 -0
- /matlab_proxy/gui/static/media/{mathworks.80a3218e.svg → mathworks.C-qsbhDy.svg} +0 -0
- /matlab_proxy/gui/static/media/{mathworks.c422935b.ttf → mathworks.Ceplx86V.ttf} +0 -0
- /matlab_proxy/gui/static/media/{mathworks.37a563ef.woff → mathworks.D08X1Vp8.woff} +0 -0
- /matlab_proxy/gui/static/media/{trigger-error.3f1c4ef2.svg → trigger-error.QEdsGL-m.svg} +0 -0
- /matlab_proxy/gui/static/media/{trigger-ok.7b9c238b.svg → trigger-ok.Dzg8OIrk.svg} +0 -0
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info/licenses}/LICENSE.md +0 -0
matlab_proxy/settings.py
CHANGED
|
@@ -1,39 +1,141 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2020-2025 The MathWorks, Inc.
|
|
2
2
|
|
|
3
|
+
import datetime
|
|
3
4
|
import os
|
|
4
5
|
import shutil
|
|
5
6
|
import socket
|
|
6
7
|
import ssl
|
|
7
|
-
import sys
|
|
8
8
|
import tempfile
|
|
9
9
|
import uuid
|
|
10
10
|
import xml.etree.ElementTree as ET
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
|
+
from cryptography import x509
|
|
14
|
+
from cryptography.hazmat.primitives import hashes, serialization
|
|
15
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
16
|
+
from cryptography.x509.oid import NameOID
|
|
17
|
+
|
|
13
18
|
import matlab_proxy
|
|
14
|
-
from matlab_proxy
|
|
19
|
+
from matlab_proxy import constants
|
|
20
|
+
from matlab_proxy.constants import MWI_AUTH_TOKEN_NAME_FOR_HTTP
|
|
21
|
+
from matlab_proxy.util import mwi, system
|
|
22
|
+
from matlab_proxy.util.cookie_jar import HttpOnlyCookieJar
|
|
15
23
|
from matlab_proxy.util.mwi import environment_variables as mwi_env
|
|
16
|
-
from matlab_proxy.util.mwi import token_auth
|
|
24
|
+
from matlab_proxy.util.mwi import session_name, token_auth
|
|
25
|
+
from matlab_proxy.util.mwi.exceptions import (
|
|
26
|
+
FatalError,
|
|
27
|
+
MatlabInstallError,
|
|
28
|
+
UIVisibleFatalError,
|
|
29
|
+
)
|
|
17
30
|
|
|
18
31
|
logger = mwi.logger.get()
|
|
19
32
|
|
|
20
33
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
if
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
def get_process_startup_timeout():
|
|
35
|
+
"""Returns the timeout for a process launched by matlab-proxy as specified by MWI_PROCESS_START_TIMEOUT environment variable
|
|
36
|
+
if valid, else returns the default value.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
int: timeout for a process launched by matlab-proxy
|
|
40
|
+
"""
|
|
41
|
+
custom_startup_timeout = os.getenv(mwi_env.get_env_name_process_startup_timeout())
|
|
42
|
+
|
|
43
|
+
if custom_startup_timeout:
|
|
44
|
+
if custom_startup_timeout.isdigit():
|
|
45
|
+
logger.info(
|
|
46
|
+
f"Using custom process startup timeout {custom_startup_timeout} seconds"
|
|
47
|
+
)
|
|
48
|
+
return int(custom_startup_timeout)
|
|
49
|
+
|
|
50
|
+
else:
|
|
51
|
+
logger.warning(
|
|
52
|
+
f"The value set for {mwi_env.get_env_name_process_startup_timeout()}:{custom_startup_timeout} is not a number. Using {constants.DEFAULT_PROCESS_START_TIMEOUT} as the default value"
|
|
53
|
+
)
|
|
54
|
+
return constants.DEFAULT_PROCESS_START_TIMEOUT
|
|
55
|
+
|
|
56
|
+
logger.debug(
|
|
57
|
+
f"Using {constants.DEFAULT_PROCESS_START_TIMEOUT} seconds as the default timeout value"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return constants.DEFAULT_PROCESS_START_TIMEOUT
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_matlab_executable_and_root_path():
|
|
64
|
+
"""Returns the path from the MWI_CUSTOM_MATLAB_ROOT environment variable if valid, else returns
|
|
65
|
+
MATLAB root based on the matlab executable if found on the system path.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
pathlib.Path: pathlib.Path objects to MATLAB executable & MATLAB root.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
# Use custom matlab root path if provided.
|
|
72
|
+
custom_matlab_root_path = os.environ.get(mwi_env.get_env_name_custom_matlab_root())
|
|
73
|
+
|
|
74
|
+
if custom_matlab_root_path:
|
|
75
|
+
matlab_root_path = Path(custom_matlab_root_path)
|
|
76
|
+
|
|
77
|
+
# Terminate process if invalid Custom Path was provided!
|
|
78
|
+
matlab_root_path = mwi.validators.validate_matlab_root_path(
|
|
79
|
+
matlab_root_path, is_custom_matlab_root=True
|
|
80
|
+
)
|
|
26
81
|
|
|
82
|
+
# Generate executable path from root path
|
|
83
|
+
matlab_executable_path = matlab_root_path / "bin" / "matlab"
|
|
84
|
+
if system.is_windows():
|
|
85
|
+
matlab_executable_path = matlab_executable_path.with_suffix(".exe")
|
|
27
86
|
|
|
28
|
-
|
|
29
|
-
|
|
87
|
+
logger.info(
|
|
88
|
+
f"Using Custom MATLAB Executable: {matlab_executable_path} with Root: {matlab_root_path}"
|
|
89
|
+
)
|
|
90
|
+
return matlab_executable_path, matlab_root_path
|
|
91
|
+
|
|
92
|
+
# Custom matlab root not specified, search for MATLAB on system path
|
|
93
|
+
matlab_executable_path = shutil.which("matlab")
|
|
94
|
+
|
|
95
|
+
if matlab_executable_path:
|
|
96
|
+
matlab_root_path = Path(matlab_executable_path).resolve().parent.parent
|
|
97
|
+
logger.debug(f"MATLAB root folder: {matlab_root_path}")
|
|
98
|
+
matlab_root_path = mwi.validators.validate_matlab_root_path(
|
|
99
|
+
matlab_root_path, is_custom_matlab_root=False
|
|
100
|
+
)
|
|
101
|
+
return matlab_executable_path, matlab_root_path
|
|
102
|
+
|
|
103
|
+
# Control only gets here if custom matlab root was not set AND which matlab returned no results.
|
|
104
|
+
# Note, error messages are formatted as multi-line strings and the front end displays them as is.
|
|
105
|
+
raise MatlabInstallError(
|
|
106
|
+
"Unable to find MATLAB on the system PATH. Add MATLAB to the system PATH, and restart matlab-proxy."
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_matlab_version(matlab_root_path):
|
|
111
|
+
"""Returns MATLAB version from VersionInfo.xml file present at matlab_root_path
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
matlab_root_path (pathlib.Path): pathlib.Path to MATLAB root.
|
|
30
115
|
|
|
31
|
-
|
|
116
|
+
Returns:
|
|
117
|
+
(str | None): Returns MATLAB version from VersionInfo.xml file.
|
|
118
|
+
"""
|
|
119
|
+
if matlab_root_path is None:
|
|
32
120
|
return None
|
|
33
121
|
|
|
34
|
-
|
|
122
|
+
version_info_file_path = Path(matlab_root_path) / constants.VERSION_INFO_FILE_NAME
|
|
123
|
+
if not version_info_file_path.exists():
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
tree = ET.parse(version_info_file_path)
|
|
35
127
|
root = tree.getroot()
|
|
36
|
-
|
|
128
|
+
|
|
129
|
+
matlab_version = root.find("release").text
|
|
130
|
+
|
|
131
|
+
# If the matlab on system PATH is a wrapper script, then it would not be possible to determine MATLAB root (inturn not being able to determine MATLAB version)
|
|
132
|
+
# unless MWI_CUSTOM_MATLAB_ROOT is set. Raising only a warning as the matlab version is only required for communicating with MHLM.
|
|
133
|
+
if not matlab_version:
|
|
134
|
+
logger.warning(
|
|
135
|
+
f"Could not determine MATLAB version from MATLAB root path: {matlab_root_path}. Set {mwi_env.get_env_name_custom_matlab_root()} to a valid MATLAB root path"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return matlab_version
|
|
37
139
|
|
|
38
140
|
|
|
39
141
|
def get_ws_env_settings():
|
|
@@ -46,8 +148,22 @@ def get_ws_env_settings():
|
|
|
46
148
|
def get_mwi_config_folder(dev=False):
|
|
47
149
|
if dev:
|
|
48
150
|
return get_test_temp_dir()
|
|
151
|
+
|
|
49
152
|
else:
|
|
50
|
-
|
|
153
|
+
config_folder_path = Path.home() / ".matlab" / "MWI"
|
|
154
|
+
# In multi-host environments, Path.home() can be the same for
|
|
155
|
+
# multiple hosts and can cause issues when different hosts launch
|
|
156
|
+
# matlab-proxy on the same port.
|
|
157
|
+
# Using hostname to be part of the path of the config folder would avoid collisions.
|
|
158
|
+
hostname = socket.gethostname()
|
|
159
|
+
if hostname:
|
|
160
|
+
config_folder_path = config_folder_path / "hosts" / hostname
|
|
161
|
+
|
|
162
|
+
logger.debug(
|
|
163
|
+
f"{'Hostname could not be determined. ' if not hostname else ''}Using the folder: {config_folder_path} for storing all matlab-proxy related session information"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
return config_folder_path
|
|
51
167
|
|
|
52
168
|
|
|
53
169
|
def get_mwi_logs_root_dir(dev=False):
|
|
@@ -58,7 +174,12 @@ def get_dev_settings(config):
|
|
|
58
174
|
devel_file = Path(__file__).resolve().parent / "./devel.py"
|
|
59
175
|
mwi_config_folder = get_mwi_config_folder(dev=True)
|
|
60
176
|
ws_env, ws_env_suffix = get_ws_env_settings()
|
|
177
|
+
(
|
|
178
|
+
mwi_auth_token,
|
|
179
|
+
mwi_auth_token_hash,
|
|
180
|
+
) = token_auth.generate_mwi_auth_token_and_hash().values()
|
|
61
181
|
return {
|
|
182
|
+
"error": None,
|
|
62
183
|
"matlab_path": Path(),
|
|
63
184
|
"matlab_version": "R2020b",
|
|
64
185
|
"matlab_cmd": [
|
|
@@ -70,7 +191,7 @@ def get_dev_settings(config):
|
|
|
70
191
|
"create_xvfb_cmd": create_xvfb_cmd,
|
|
71
192
|
"base_url": os.environ.get(mwi_env.get_env_name_base_url(), ""),
|
|
72
193
|
"app_port": os.environ.get(mwi_env.get_env_name_app_port(), 8000),
|
|
73
|
-
"host_interface":
|
|
194
|
+
"host_interface": "127.0.0.1",
|
|
74
195
|
"mwapikey": str(uuid.uuid4()),
|
|
75
196
|
"matlab_protocol": "http",
|
|
76
197
|
"matlab_display": ":1",
|
|
@@ -82,14 +203,26 @@ def get_dev_settings(config):
|
|
|
82
203
|
"mwa_login": f"https://login{ws_env_suffix}.mathworks.com",
|
|
83
204
|
"mwi_custom_http_headers": mwi.custom_http_headers.get(),
|
|
84
205
|
"env_config": mwi.validators.validate_env_config(config),
|
|
206
|
+
"integration_name": "MATLAB Desktop",
|
|
85
207
|
"ssl_context": None,
|
|
86
208
|
"mwi_logs_root_dir": get_mwi_logs_root_dir(dev=True),
|
|
87
|
-
"mwi_proxy_lock_file_name": "mwi_proxy.lock",
|
|
88
209
|
"mw_context_tags": get_mw_context_tags(matlab_proxy.get_default_config_name()),
|
|
89
210
|
"mwi_server_url": None,
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
211
|
+
"mwi_is_token_auth_enabled": mwi_auth_token is not None,
|
|
212
|
+
"mwi_auth_status": False,
|
|
213
|
+
"mwi_auth_token": mwi_auth_token,
|
|
214
|
+
"mwi_auth_token_hash": mwi_auth_token_hash,
|
|
215
|
+
"mwi_auth_token_name_for_http": MWI_AUTH_TOKEN_NAME_FOR_HTTP,
|
|
216
|
+
"mwi_auth_token_name_for_env": mwi_env.get_env_name_mwi_auth_token().lower(),
|
|
217
|
+
"mwi_use_existing_license": mwi.validators.validate_use_existing_licensing(
|
|
218
|
+
os.getenv(mwi_env.get_env_name_mwi_use_existing_license(), "")
|
|
219
|
+
),
|
|
220
|
+
"warnings": [],
|
|
221
|
+
"is_xvfb_available": False,
|
|
222
|
+
"is_windowmanager_available": False,
|
|
223
|
+
"mwi_idle_timeout": None,
|
|
224
|
+
"cookie_jar": _get_cookie_jar(),
|
|
225
|
+
"browser_title": session_name.get_browser_title("R2020b"),
|
|
93
226
|
}
|
|
94
227
|
|
|
95
228
|
|
|
@@ -103,6 +236,13 @@ def get(config_name=matlab_proxy.get_default_config_name(), dev=False):
|
|
|
103
236
|
|
|
104
237
|
Returns:
|
|
105
238
|
Dict: Containing data on how to start MATLAB among other information.
|
|
239
|
+
|
|
240
|
+
Raises:
|
|
241
|
+
Initialization of settings is not exception safe.
|
|
242
|
+
Exceptions of Type UIVisibleFatalError are not propagated upwards, and are instead set in the error data member.
|
|
243
|
+
This will allow for the app to error out gracefully in the front end as well.
|
|
244
|
+
|
|
245
|
+
All other exceptions will propagate upwards and result in the app to shutdown.
|
|
106
246
|
"""
|
|
107
247
|
|
|
108
248
|
if dev:
|
|
@@ -111,7 +251,6 @@ def get(config_name=matlab_proxy.get_default_config_name(), dev=False):
|
|
|
111
251
|
# If running tests using Pytest, it will set environment variable TEST to true before running tests.
|
|
112
252
|
# Will make test env specific changes before returning the settings.
|
|
113
253
|
if mwi_env.is_testing_mode_enabled():
|
|
114
|
-
|
|
115
254
|
# Set ready_delay value to 0 for faster fake MATLAB startup.
|
|
116
255
|
ready_delay = ["--ready-delay", "0"]
|
|
117
256
|
matlab_cmd = settings["matlab_cmd"]
|
|
@@ -125,77 +264,149 @@ def get(config_name=matlab_proxy.get_default_config_name(), dev=False):
|
|
|
125
264
|
s.close()
|
|
126
265
|
|
|
127
266
|
# Set NLM Connection string. Server will start using this connection string for licensing
|
|
128
|
-
settings["nlm_conn_str"] = "
|
|
129
|
-
|
|
130
|
-
return settings
|
|
267
|
+
settings["nlm_conn_str"] = "123@nlm"
|
|
131
268
|
|
|
132
269
|
else:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
270
|
+
settings = {"error": None, "warnings": []}
|
|
271
|
+
|
|
272
|
+
# Initializing server settings separately allows us to return
|
|
273
|
+
# a minimal set of settings required to launch the server even if
|
|
274
|
+
# there is an exception thrown when creating the matlab specific settings.
|
|
275
|
+
settings.update(get_server_settings(config_name))
|
|
138
276
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
277
|
+
settings["is_xvfb_available"] = True if shutil.which("Xvfb") else False
|
|
278
|
+
settings["is_windowmanager_available"] = (
|
|
279
|
+
True if shutil.which("fluxbox") else False
|
|
142
280
|
)
|
|
143
281
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
"
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
282
|
+
# Warn user if xvfb is not available on system path.
|
|
283
|
+
if system.is_linux():
|
|
284
|
+
if not settings["is_xvfb_available"]:
|
|
285
|
+
warning = " Unable to find Xvfb on the system PATH. Xvfb enables graphical abilities like plots and figures in the MATLAB desktop.\nConsider adding Xvfb to the system PATH and restart matlab-proxy.\nFor details, see https://github.com/mathworks/matlab-proxy#requirements."
|
|
286
|
+
logger.warning(warning)
|
|
287
|
+
settings["warnings"].append(warning)
|
|
288
|
+
|
|
289
|
+
if not settings["is_windowmanager_available"]:
|
|
290
|
+
warning = " Unable to find fluxbox on the system PATH. To use Simulink Online, add Fluxbox to the system PATH and restart matlab-proxy. For details, see https://github.com/mathworks/matlab-proxy#requirements."
|
|
291
|
+
logger.warning(warning)
|
|
292
|
+
|
|
293
|
+
settings.update(get_matlab_settings())
|
|
294
|
+
|
|
295
|
+
return settings
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def get_server_settings(config_name):
|
|
299
|
+
"""Get the settings required to launch the MATLAB-PROXY web server.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
config : Dictionary as specified by the default_configuration.py file. Used to customize the app.
|
|
303
|
+
dev (bool, optional): development environment. Defaults to False.
|
|
304
|
+
|
|
305
|
+
Raises:
|
|
306
|
+
This function is not exception safe, and all exceptions will result in the termination of the app.
|
|
307
|
+
If you need to add exceptions which need to be presented in the UI, add them to get_matlab_settings
|
|
308
|
+
"""
|
|
309
|
+
(
|
|
310
|
+
mwi_auth_token,
|
|
311
|
+
mwi_auth_token_hash,
|
|
312
|
+
) = token_auth.generate_mwi_auth_token_and_hash().values()
|
|
313
|
+
mwi_config_folder = get_mwi_config_folder()
|
|
314
|
+
|
|
315
|
+
# log file validation check is already done in logger.py
|
|
316
|
+
mwi_log_file = os.getenv(mwi_env.get_env_name_log_file(), None)
|
|
317
|
+
|
|
318
|
+
env_config = mwi.validators.validate_env_config(config_name)
|
|
319
|
+
short_desc = env_config["extension_name_short_description"]
|
|
320
|
+
integration_name = (
|
|
321
|
+
short_desc
|
|
322
|
+
if env_config["extension_name"] == matlab_proxy.get_default_config_name()
|
|
323
|
+
else f"{short_desc} - MATLAB Integration"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
cookie_jar = _get_cookie_jar()
|
|
327
|
+
return {
|
|
328
|
+
"create_xvfb_cmd": create_xvfb_cmd,
|
|
329
|
+
"base_url": mwi.validators.validate_base_url(
|
|
330
|
+
os.getenv(mwi_env.get_env_name_base_url(), "")
|
|
331
|
+
),
|
|
332
|
+
# Set host interface to 0.0.0.0 to bind on all interfaces
|
|
333
|
+
"host_interface": "0.0.0.0",
|
|
334
|
+
# not_exception_safe, can_terminate_process by throwing FatalError
|
|
335
|
+
"app_port": mwi.validators.validate_app_port_is_free(
|
|
336
|
+
os.getenv(mwi_env.get_env_name_app_port())
|
|
337
|
+
),
|
|
338
|
+
"env_config": env_config,
|
|
339
|
+
"integration_name": integration_name,
|
|
340
|
+
"mwapikey": str(uuid.uuid4()),
|
|
341
|
+
"matlab_protocol": "https",
|
|
342
|
+
"matlab_config_file": mwi_config_folder / "proxy_app_config.json",
|
|
343
|
+
"mwi_custom_http_headers": mwi.custom_http_headers.get(),
|
|
344
|
+
# This directory will be used to store connector.securePort(matlab_ready_file) and its corresponding files. This will be
|
|
345
|
+
# a central place to store logs of all the running instances of MATLAB launched by matlab-proxy
|
|
346
|
+
"mwi_logs_root_dir": get_mwi_logs_root_dir(),
|
|
347
|
+
"mwi_log_file": mwi_log_file,
|
|
348
|
+
"mw_context_tags": get_mw_context_tags(config_name),
|
|
349
|
+
# The url where the matlab-proxy server is accessible at
|
|
350
|
+
"mwi_server_url": None,
|
|
351
|
+
"mwi_is_token_auth_enabled": mwi_auth_token is not None,
|
|
352
|
+
"mwi_auth_status": False,
|
|
353
|
+
"mwi_auth_token": mwi_auth_token,
|
|
354
|
+
"mwi_auth_token_hash": mwi_auth_token_hash,
|
|
355
|
+
"mwi_auth_token_name_for_http": MWI_AUTH_TOKEN_NAME_FOR_HTTP,
|
|
356
|
+
"mwi_auth_token_name_for_env": mwi_env.get_env_name_mwi_auth_token().lower(),
|
|
357
|
+
"mwi_use_existing_license": mwi.validators.validate_use_existing_licensing(
|
|
358
|
+
os.getenv(mwi_env.get_env_name_mwi_use_existing_license(), "")
|
|
359
|
+
),
|
|
360
|
+
"ssl_context": _validate_ssl_files_and_get_ssl_context(mwi_config_folder),
|
|
361
|
+
# validate_idle_timeout converts the timeout from minutes to seconds
|
|
362
|
+
"mwi_idle_timeout": mwi.validators.validate_idle_timeout(
|
|
363
|
+
os.getenv(mwi_env.get_env_name_shutdown_on_idle_timeout())
|
|
364
|
+
),
|
|
365
|
+
"cookie_jar": cookie_jar,
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def get_matlab_settings():
|
|
370
|
+
"""Returns the settings required to start MATLAB.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Dict: Containing data on how to start MATLAB among other information.
|
|
374
|
+
Raises:
|
|
375
|
+
This function is not exception safe, and all exceptions will result in the termination of the app.
|
|
376
|
+
Unless they are of type UIVisibleFatalError
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
ws_env, ws_env_suffix = get_ws_env_settings()
|
|
380
|
+
mw_licensing_urls = _get_mw_licensing_urls(ws_env_suffix)
|
|
381
|
+
nlm_conn_str = _get_nlm_conn_str()
|
|
382
|
+
has_custom_code_to_execute, code_to_execute = _get_matlab_code_to_execute()
|
|
383
|
+
err = None
|
|
384
|
+
|
|
385
|
+
try:
|
|
386
|
+
matlab_executable_path, matlab_root_path = get_matlab_executable_and_root_path()
|
|
387
|
+
|
|
388
|
+
except UIVisibleFatalError as error:
|
|
389
|
+
logger.error(f"Exception raised during initialization: {error}")
|
|
390
|
+
# Set matlab root and executable path to None as MATLAB root could not be determined
|
|
391
|
+
matlab_executable_path = matlab_root_path = None
|
|
392
|
+
err = error
|
|
393
|
+
|
|
394
|
+
matlab_version = get_matlab_version(matlab_root_path)
|
|
395
|
+
matlab_version_determined_on_startup = bool(matlab_version)
|
|
396
|
+
matlab_cmd = _get_matlab_cmd(matlab_executable_path, code_to_execute, nlm_conn_str)
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
"error": err,
|
|
400
|
+
"matlab_version": matlab_version,
|
|
401
|
+
"matlab_path": matlab_root_path,
|
|
402
|
+
"matlab_version_determined_on_startup": matlab_version_determined_on_startup,
|
|
403
|
+
"matlab_cmd": matlab_cmd,
|
|
404
|
+
"ws_env": ws_env,
|
|
405
|
+
**mw_licensing_urls,
|
|
406
|
+
"nlm_conn_str": nlm_conn_str,
|
|
407
|
+
"has_custom_code_to_execute": has_custom_code_to_execute,
|
|
408
|
+
"browser_title": session_name.get_browser_title(matlab_version),
|
|
409
|
+
}
|
|
199
410
|
|
|
200
411
|
|
|
201
412
|
def get_mw_context_tags(extension_name):
|
|
@@ -246,7 +457,7 @@ def create_xvfb_cmd():
|
|
|
246
457
|
str(dpipe[1]),
|
|
247
458
|
"-screen",
|
|
248
459
|
"0",
|
|
249
|
-
"
|
|
460
|
+
"3840x2160x24",
|
|
250
461
|
"-dpi",
|
|
251
462
|
"100",
|
|
252
463
|
# "-ac",
|
|
@@ -267,30 +478,250 @@ def get_test_temp_dir():
|
|
|
267
478
|
return test_temp_dir
|
|
268
479
|
|
|
269
480
|
|
|
270
|
-
def
|
|
271
|
-
"""Creates an SSL CONTEXT for use with the TCP Site
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
logger.
|
|
292
|
-
|
|
293
|
-
|
|
481
|
+
def _validate_ssl_files_and_get_ssl_context(mwi_config_folder):
|
|
482
|
+
"""Creates an SSL CONTEXT for use with the TCP Site.
|
|
483
|
+
The certfile string must be the path to a single file in PEM format containing the
|
|
484
|
+
certificate as well as any number of CA certificates needed to establish the certificate’s authenticity.
|
|
485
|
+
The keyfile string, if present, must point to a file containing the private key in.
|
|
486
|
+
Otherwise the private key will be taken from certfile as well.
|
|
487
|
+
"""
|
|
488
|
+
is_self_signed_certificates = False
|
|
489
|
+
env_name_enable_ssl = mwi_env.get_env_name_enable_ssl()
|
|
490
|
+
is_ssl_enabled = mwi_env._is_env_set_to_true(env_name_enable_ssl)
|
|
491
|
+
env_name_ssl_key_file = mwi_env.get_env_name_ssl_key_file()
|
|
492
|
+
env_name_ssl_cert_file = mwi_env.get_env_name_ssl_cert_file()
|
|
493
|
+
|
|
494
|
+
ssl_key_file, ssl_cert_file = (
|
|
495
|
+
os.getenv(env_name_ssl_key_file, None),
|
|
496
|
+
os.getenv(env_name_ssl_cert_file, None),
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
# Don't use SSL if the user has explicitly disabled SSL communication or not set the respective env var
|
|
500
|
+
if not is_ssl_enabled:
|
|
501
|
+
if ssl_cert_file:
|
|
502
|
+
logger.warning(
|
|
503
|
+
f"Ignoring provided SSL files, as {env_name_enable_ssl} is either unset or set to false"
|
|
504
|
+
)
|
|
505
|
+
return None
|
|
506
|
+
|
|
507
|
+
# Validate that provided SSL files are valid files
|
|
508
|
+
ssl_key_file, ssl_cert_file = mwi.validators.validate_ssl_key_and_cert_file(
|
|
509
|
+
ssl_key_file, ssl_cert_file
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
if not ssl_cert_file and not ssl_key_file:
|
|
513
|
+
logger.debug("Using auto-generated self-signed certificates")
|
|
514
|
+
|
|
515
|
+
# certs dir under the MWI_CONFIG_FOLDER will hold the self-signed certificates
|
|
516
|
+
mwi_certs_dir = mwi_config_folder / "certs"
|
|
517
|
+
mwi_certs_dir.mkdir(parents=True, exist_ok=True)
|
|
518
|
+
|
|
519
|
+
# New certs are generated for every run leading to functionally reliable system, alternative is
|
|
520
|
+
# to check for existing certs and have error handling around expired/bad certs.
|
|
521
|
+
ssl_cert_file, ssl_key_file = generate_new_self_signed_certs(mwi_certs_dir)
|
|
522
|
+
is_self_signed_certificates = True
|
|
523
|
+
try:
|
|
524
|
+
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
525
|
+
ssl_context.load_cert_chain(ssl_cert_file, ssl_key_file)
|
|
526
|
+
logger.debug("Certificate chain was correctly loaded")
|
|
527
|
+
except Exception as e:
|
|
528
|
+
logger.error(f"Unable to load certificates. Error: {e}")
|
|
529
|
+
|
|
530
|
+
# Setting to None to use http mode in the event of failing to setup self-signed certificates
|
|
294
531
|
ssl_context = None
|
|
295
532
|
|
|
533
|
+
# Raise a fatal error only in the event of an exception while loading customer-supplied ssl files
|
|
534
|
+
if not is_self_signed_certificates:
|
|
535
|
+
raise FatalError(e)
|
|
536
|
+
|
|
296
537
|
return ssl_context
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def generate_new_self_signed_certs(mwi_certs_dir):
|
|
541
|
+
"""
|
|
542
|
+
Generates a new self-signed certificate and corresponding private key, saves them as PEM files in the specified directory.
|
|
543
|
+
The certificate is valid for 365 days from the time of creation.
|
|
544
|
+
|
|
545
|
+
Parameters:
|
|
546
|
+
- mwi_certs_dir (Path): A pathlib.Path object representing the directory where the certificate and key files will be saved.
|
|
547
|
+
|
|
548
|
+
Returns:
|
|
549
|
+
- tuple: A tuple containing the file paths (as strings) to the newly created certificate and private key PEM files.
|
|
550
|
+
The first element is the path to the certificate file (cert.pem), and the second is the path to the key file (key.pem).
|
|
551
|
+
|
|
552
|
+
Raises:
|
|
553
|
+
- FileNotFoundError: If the mwi_certs_dir does not exist.
|
|
554
|
+
- Any other exception that may occur during file writing or certificate generation.
|
|
555
|
+
"""
|
|
556
|
+
cert_file = priv_key_file = None
|
|
557
|
+
try:
|
|
558
|
+
# Generate private key
|
|
559
|
+
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
|
560
|
+
|
|
561
|
+
# Self-signed certificate
|
|
562
|
+
subject = issuer = x509.Name(
|
|
563
|
+
[
|
|
564
|
+
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
|
|
565
|
+
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Massachusetts"),
|
|
566
|
+
x509.NameAttribute(NameOID.LOCALITY_NAME, "Natick"),
|
|
567
|
+
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "MathWorks Inc."),
|
|
568
|
+
x509.NameAttribute(NameOID.COMMON_NAME, "mathworks.com"),
|
|
569
|
+
]
|
|
570
|
+
)
|
|
571
|
+
cert = (
|
|
572
|
+
x509.CertificateBuilder()
|
|
573
|
+
.subject_name(subject)
|
|
574
|
+
.issuer_name(issuer)
|
|
575
|
+
.public_key(private_key.public_key())
|
|
576
|
+
.serial_number(x509.random_serial_number())
|
|
577
|
+
.not_valid_before(datetime.datetime.utcnow())
|
|
578
|
+
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
|
|
579
|
+
.sign(private_key, hashes.SHA256())
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
# Write private key to file
|
|
583
|
+
priv_key_file = mwi_certs_dir / "key.pem"
|
|
584
|
+
with open(priv_key_file, "wb") as f:
|
|
585
|
+
f.write(
|
|
586
|
+
private_key.private_bytes(
|
|
587
|
+
encoding=serialization.Encoding.PEM,
|
|
588
|
+
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
589
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
590
|
+
)
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
# Write certificate to file
|
|
594
|
+
cert_file = mwi_certs_dir / "cert.pem"
|
|
595
|
+
with open(cert_file, "wb") as f:
|
|
596
|
+
f.write(cert.public_bytes(serialization.Encoding.PEM))
|
|
597
|
+
|
|
598
|
+
except Exception as ex:
|
|
599
|
+
logger.warning(
|
|
600
|
+
f"Failed to generate self-signed certificates, proceeding with non-secure mode! Error: {ex}"
|
|
601
|
+
)
|
|
602
|
+
cert_file = priv_key_file = None
|
|
603
|
+
|
|
604
|
+
return cert_file, priv_key_file
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def _sanitize_file_path_for_matlab(filepath: str) -> str:
|
|
608
|
+
"""
|
|
609
|
+
Replace single quotes in the filepath with double single quotes to preserve the quote when used in MATLAB code.
|
|
610
|
+
"""
|
|
611
|
+
filepath_with_single_quotes_escaped = filepath.replace("'", "''")
|
|
612
|
+
return filepath_with_single_quotes_escaped
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def _get_matlab_code_to_execute():
|
|
616
|
+
"""Returns the code that needs to run on MATLAB startup.
|
|
617
|
+
Will check for user provided custom MATLAB code and execute it along with the default startup script.
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
tuple: With the first value representing whether there is custom MATLAB code to execute, and the second value representing the MATLAB code to execute.
|
|
621
|
+
"""
|
|
622
|
+
matlab_code_dir = Path(__file__).resolve().parent / "matlab"
|
|
623
|
+
matlab_startup_file = str(matlab_code_dir / "startup.m")
|
|
624
|
+
matlab_code_file = str(matlab_code_dir / "evaluateUserMatlabCode.m")
|
|
625
|
+
|
|
626
|
+
has_custom_code_to_execute = (
|
|
627
|
+
len(os.getenv(mwi_env.get_env_name_custom_matlab_code(), "").strip()) > 0
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
# Sanitize file paths to avoid MATLAB not running the script due to early breakup of character array.
|
|
631
|
+
mp_code_to_execute = f"try; run('{_sanitize_file_path_for_matlab(matlab_startup_file)}'); catch MATLABProxyInitializationError; disp(MATLABProxyInitializationError.message); end;"
|
|
632
|
+
custom_code_to_execute = f"try; run('{_sanitize_file_path_for_matlab(matlab_code_file)}'); catch MATLABCustomStartupCodeError; disp(MATLABCustomStartupCodeError.message); end;"
|
|
633
|
+
code_to_execute = (
|
|
634
|
+
mp_code_to_execute + custom_code_to_execute
|
|
635
|
+
if has_custom_code_to_execute
|
|
636
|
+
else mp_code_to_execute
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
return has_custom_code_to_execute, code_to_execute
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
def _get_nlm_conn_str():
|
|
643
|
+
"""Get the Network License Manager (NLM) connection string.
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
str: The NLM connection string provided by the MLM_LICENSE_FILE environment variable.
|
|
647
|
+
"""
|
|
648
|
+
# NLM Connection String provided by MLM_LICENSE_FILE environment variable
|
|
649
|
+
nlm_conn_str = mwi.validators.validate_mlm_license_file(
|
|
650
|
+
os.environ.get(mwi_env.get_env_name_network_license_manager())
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
return nlm_conn_str
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def _get_mw_licensing_urls(ws_env_suffix):
|
|
657
|
+
"""Get the MathWorks licensing URLs.
|
|
658
|
+
|
|
659
|
+
Args:
|
|
660
|
+
ws_env_suffix (str): The environment suffix for the licensing URLs.
|
|
661
|
+
|
|
662
|
+
Returns:
|
|
663
|
+
dict: A dictionary containing the MathWorks licensing URLs for authentication and entitlement.
|
|
664
|
+
"""
|
|
665
|
+
return {
|
|
666
|
+
"mwa_api_endpoint": f"https://login{ws_env_suffix}.mathworks.com/authenticationws/service/v4",
|
|
667
|
+
"mhlm_api_endpoint": f"https://licensing{ws_env_suffix}.mathworks.com/mls/service/v1/entitlement/list",
|
|
668
|
+
"mwa_login": f"https://login{ws_env_suffix}.mathworks.com",
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def _get_matlab_cmd(matlab_executable_path, code_to_execute, nlm_conn_str):
|
|
673
|
+
"""Construct the MATLAB command with appropriate flags and arguments.
|
|
674
|
+
|
|
675
|
+
Args:
|
|
676
|
+
matlab_executable_path (str): The path to the MATLAB executable.
|
|
677
|
+
code_to_execute (str): The MATLAB code to execute on startup.
|
|
678
|
+
nlm_conn_str (str): The Network License Manager connection string.
|
|
679
|
+
|
|
680
|
+
Returns:
|
|
681
|
+
list: A list of command-line arguments to launch MATLAB with the specified configuration.
|
|
682
|
+
"""
|
|
683
|
+
if not matlab_executable_path:
|
|
684
|
+
return None
|
|
685
|
+
|
|
686
|
+
matlab_lic_mode = ["-licmode", "file"] if nlm_conn_str else ""
|
|
687
|
+
|
|
688
|
+
if mwi_env.Experimental.get_licmode_override():
|
|
689
|
+
matlab_lic_mode = ["-licmode", mwi_env.Experimental.get_licmode_override()]
|
|
690
|
+
logger.info(f"Using MATLAB license mode arguments: {matlab_lic_mode}")
|
|
691
|
+
|
|
692
|
+
# flag to hide MATLAB Window
|
|
693
|
+
flag_to_hide_desktop = ["-nodesktop"]
|
|
694
|
+
if system.is_windows():
|
|
695
|
+
flag_to_hide_desktop.extend(["-noDisplayDesktop", "-wait", "-log"])
|
|
696
|
+
|
|
697
|
+
profile_matlab_startup = (
|
|
698
|
+
"-timing" if mwi_env.Experimental.is_matlab_startup_profiling_enabled() else ""
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
return [
|
|
702
|
+
matlab_executable_path,
|
|
703
|
+
"-nosplash",
|
|
704
|
+
*flag_to_hide_desktop,
|
|
705
|
+
"-softwareopengl",
|
|
706
|
+
*matlab_lic_mode,
|
|
707
|
+
"-externalUI",
|
|
708
|
+
profile_matlab_startup,
|
|
709
|
+
"-r",
|
|
710
|
+
code_to_execute,
|
|
711
|
+
]
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def _get_cookie_jar():
|
|
715
|
+
"""Returns an instance of HttpOnly cookie jar if MWI_USE_COOKIE_CACHE environment variable is set to True
|
|
716
|
+
|
|
717
|
+
Returns:
|
|
718
|
+
HttpOnlyCookieJar: An instance of HttpOnly cookie jar if MWI_USE_COOKIE_CACHE environment variable is set to True, otherwise None.
|
|
719
|
+
"""
|
|
720
|
+
cookie_jar = None
|
|
721
|
+
if mwi_env.Experimental.should_use_cookie_cache():
|
|
722
|
+
logger.info(
|
|
723
|
+
f"Environment variable {mwi_env.Experimental.get_env_name_use_cookie_cache()} is set. matlab-proxy server will cache cookies from MATLAB"
|
|
724
|
+
)
|
|
725
|
+
cookie_jar = HttpOnlyCookieJar()
|
|
726
|
+
|
|
727
|
+
return cookie_jar
|