ansys-pyensight-core 0.6.1__py3-none-any.whl → 0.6.2__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 ansys-pyensight-core might be problematic. Click here for more details.
- ansys/pyensight/core/deep_pixel_view.html +5 -5
- ansys/pyensight/core/dockerlauncher.py +80 -29
- ansys/pyensight/core/enshell_grpc.py +5 -3
- ansys/pyensight/core/launch_ensight.py +1 -4
- ansys/pyensight/core/launcher.py +44 -1
- ansys/pyensight/core/renderable.py +98 -23
- ansys/pyensight/core/session.py +24 -2
- {ansys_pyensight_core-0.6.1.dist-info → ansys_pyensight_core-0.6.2.dist-info}/METADATA +1 -1
- {ansys_pyensight_core-0.6.1.dist-info → ansys_pyensight_core-0.6.2.dist-info}/RECORD +11 -11
- {ansys_pyensight_core-0.6.1.dist-info → ansys_pyensight_core-0.6.2.dist-info}/LICENSE +0 -0
- {ansys_pyensight_core-0.6.1.dist-info → ansys_pyensight_core-0.6.2.dist-info}/WHEEL +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<link rel="stylesheet" type="text/css" href="/bootstrap.min.
|
|
4
|
+
<link rel="stylesheet" type="text/css" href="/bootstrap.min.cssOPTIONAL_QUERY"/>
|
|
5
5
|
|
|
6
|
-
<script src='/jquery-3.4.1.min.
|
|
7
|
-
<script src='/geotiff.
|
|
8
|
-
<script src='/geotiff_nexus.
|
|
9
|
-
<script src="/bootstrap.min.
|
|
6
|
+
<script src='/jquery-3.4.1.min.jsOPTIONAL_QUERY'></script>
|
|
7
|
+
<script src='/geotiff.jsOPTIONAL_QUERY'></script>
|
|
8
|
+
<script src='/geotiff_nexus.jsOPTIONAL_QUERY'></script>
|
|
9
|
+
<script src="/bootstrap.min.jsOPTIONAL_QUERY"></script>
|
|
10
10
|
|
|
11
11
|
<script>
|
|
12
12
|
function updatepick_ITEMID(e) {
|
|
@@ -16,6 +16,7 @@ Examples:
|
|
|
16
16
|
"""
|
|
17
17
|
import logging
|
|
18
18
|
import os.path
|
|
19
|
+
import re
|
|
19
20
|
import subprocess
|
|
20
21
|
import time
|
|
21
22
|
from typing import Any, Dict, Optional
|
|
@@ -160,6 +161,11 @@ class DockerLauncher(Launcher):
|
|
|
160
161
|
self._service_host_port["grpc"] = ("127.0.0.1", -1)
|
|
161
162
|
# attach to the file service if available
|
|
162
163
|
self._get_file_service()
|
|
164
|
+
# if using PIM, we have a query parameter to append to http requests
|
|
165
|
+
if self._pim_instance is not None:
|
|
166
|
+
d = {"instance_name": self._pim_instance.name}
|
|
167
|
+
self._add_query_parameters(d)
|
|
168
|
+
#
|
|
163
169
|
return
|
|
164
170
|
|
|
165
171
|
# EnShell gRPC port, EnSight gRPC port, HTTP port, WSS port
|
|
@@ -217,6 +223,31 @@ class DockerLauncher(Launcher):
|
|
|
217
223
|
except Exception:
|
|
218
224
|
raise RuntimeError(f"Can't pull Docker image: {self._image_name}")
|
|
219
225
|
|
|
226
|
+
def _get_container_env(self) -> Dict:
|
|
227
|
+
# Create the environmental variables
|
|
228
|
+
# Environment to pass into the container
|
|
229
|
+
container_env = {
|
|
230
|
+
"ENSIGHT_SECURITY_TOKEN": self._secret_key,
|
|
231
|
+
"WEBSOCKETSERVER_SECURITY_TOKEN": self._secret_key,
|
|
232
|
+
"ENSIGHT_SESSION_TEMPDIR": self._session_directory,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
# If for some reason, the ENSIGHT_ANSYS_LAUNCH is set previously,
|
|
236
|
+
# honor that value, otherwise set it to "pyensight". This allows
|
|
237
|
+
# for an environmental setup to set the value to something else
|
|
238
|
+
# (e.g. their "app").
|
|
239
|
+
if "ENSIGHT_ANSYS_LAUNCH" not in os.environ:
|
|
240
|
+
container_env["ENSIGHT_ANSYS_LAUNCH"] = "container"
|
|
241
|
+
else:
|
|
242
|
+
container_env["ENSIGHT_ANSYS_LAUNCH"] = os.environ["ENSIGHT_ANSYS_LAUNCH"]
|
|
243
|
+
|
|
244
|
+
if self._pim_instance is None:
|
|
245
|
+
container_env["ANSYSLMD_LICENSE_FILE"] = os.environ["ANSYSLMD_LICENSE_FILE"]
|
|
246
|
+
if "ENSIGHT_ANSYS_APIP_CONFIG" in os.environ:
|
|
247
|
+
container_env["ENSIGHT_ANSYS_APIP_CONFIG"] = os.environ["ENSIGHT_ANSYS_APIP_CONFIG"]
|
|
248
|
+
|
|
249
|
+
return container_env
|
|
250
|
+
|
|
220
251
|
def start(self) -> "Session":
|
|
221
252
|
"""Start EnShell by running a local Docker EnSight image.
|
|
222
253
|
|
|
@@ -245,27 +276,8 @@ class DockerLauncher(Launcher):
|
|
|
245
276
|
# initially running EnShell over the first gRPC port. Then launch EnSight
|
|
246
277
|
# and other apps.
|
|
247
278
|
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
local_env["ENSIGHT_SECURITY_TOKEN"] = self._secret_key
|
|
251
|
-
local_env["WEBSOCKETSERVER_SECURITY_TOKEN"] = self._secret_key
|
|
252
|
-
# If for some reason, the ENSIGHT_ANSYS_LAUNCH is set previously,
|
|
253
|
-
# honor that value, otherwise set it to "pyensight". This allows
|
|
254
|
-
# for an environmental setup to set the value to something else
|
|
255
|
-
# (e.g. their "app").
|
|
256
|
-
if "ENSIGHT_ANSYS_LAUNCH" not in local_env:
|
|
257
|
-
local_env["ENSIGHT_ANSYS_LAUNCH"] = "container"
|
|
258
|
-
|
|
259
|
-
# Environment to pass into the container
|
|
260
|
-
container_env = {
|
|
261
|
-
"ENSIGHT_SECURITY_TOKEN": self._secret_key,
|
|
262
|
-
"WEBSOCKETSERVER_SECURITY_TOKEN": self._secret_key,
|
|
263
|
-
"ENSIGHT_SESSION_TEMPDIR": self._session_directory,
|
|
264
|
-
"ANSYSLMD_LICENSE_FILE": os.environ["ANSYSLMD_LICENSE_FILE"],
|
|
265
|
-
"ENSIGHT_ANSYS_LAUNCH": local_env["ENSIGHT_ANSYS_LAUNCH"],
|
|
266
|
-
}
|
|
267
|
-
if "ENSIGHT_ANSYS_APIP_CONFIG" in local_env:
|
|
268
|
-
container_env["ENSIGHT_ANSYS_APIP_CONFIG"] = local_env["ENSIGHT_ANSYS_APIP_CONFIG"]
|
|
279
|
+
# get the environment to pass to the container
|
|
280
|
+
container_env = self._get_container_env()
|
|
269
281
|
|
|
270
282
|
# Ports to map between the host and the container
|
|
271
283
|
# If we're here in the code, then we're not using PIM
|
|
@@ -452,10 +464,27 @@ class DockerLauncher(Launcher):
|
|
|
452
464
|
|
|
453
465
|
use_egl = self._use_egl()
|
|
454
466
|
|
|
467
|
+
# get the environment to pass to the container
|
|
468
|
+
container_env_str = ""
|
|
469
|
+
if self._pim_instance is not None:
|
|
470
|
+
container_env = self._get_container_env()
|
|
471
|
+
for i in container_env.items():
|
|
472
|
+
container_env_str += f"{i[0]}={i[1]}\n"
|
|
473
|
+
|
|
455
474
|
# Run EnSight
|
|
456
475
|
ensight_env_vars = None
|
|
476
|
+
if container_env_str != "":
|
|
477
|
+
ensight_env_vars = container_env_str
|
|
478
|
+
|
|
457
479
|
if use_egl:
|
|
458
|
-
ensight_env_vars
|
|
480
|
+
if ensight_env_vars is None:
|
|
481
|
+
ensight_env_vars = (
|
|
482
|
+
"LD_PRELOAD=/usr/local/lib64/libGL.so.1:/usr/local/lib64/libEGL.so.1"
|
|
483
|
+
)
|
|
484
|
+
else:
|
|
485
|
+
ensight_env_vars += (
|
|
486
|
+
"LD_PRELOAD=/usr/local/lib64/libGL.so.1:/usr/local/lib64/libEGL.so.1"
|
|
487
|
+
)
|
|
459
488
|
|
|
460
489
|
ensight_args = "-batch -v 3"
|
|
461
490
|
|
|
@@ -481,23 +510,35 @@ class DockerLauncher(Launcher):
|
|
|
481
510
|
# Run websocketserver
|
|
482
511
|
wss_cmd = "cpython /ansys_inc/v" + self._ansys_version + "/CEI/nexus"
|
|
483
512
|
wss_cmd += self._ansys_version + "/nexus_launcher/websocketserver.py"
|
|
513
|
+
# websocket port - this needs to come first since we now have
|
|
514
|
+
# --add_header as a optional arg that can take an arbitrary
|
|
515
|
+
# number of optional headers.
|
|
516
|
+
wss_cmd += " " + str(self._service_host_port["ws"][1])
|
|
517
|
+
#
|
|
484
518
|
wss_cmd += " --http_directory " + self._session_directory
|
|
485
519
|
# http port
|
|
486
520
|
wss_cmd += " --http_port " + str(self._service_host_port["http"][1])
|
|
487
521
|
# vnc port
|
|
488
522
|
wss_cmd += " --client_port 1999"
|
|
489
|
-
|
|
523
|
+
# optional PIM instance header
|
|
524
|
+
if self._pim_instance is not None:
|
|
525
|
+
# Add the PIM instance header. wss needs to return this optional
|
|
526
|
+
# header in each http response. It's how the Ansys Lab proxy
|
|
527
|
+
# knows how to map back to this particular container's IP and port.
|
|
528
|
+
wss_cmd += " --add_header instance_name=" + self._pim_instance.name
|
|
529
|
+
# EnSight REST API
|
|
490
530
|
if self._enable_rest_api:
|
|
491
531
|
# grpc port
|
|
492
532
|
wss_cmd += " --grpc_port " + str(self._service_host_port["grpc_private"][1])
|
|
493
|
-
|
|
494
533
|
# EnVision sessions
|
|
495
534
|
wss_cmd += " --local_session envision 5"
|
|
496
|
-
|
|
497
|
-
|
|
535
|
+
|
|
536
|
+
wss_env_vars = None
|
|
537
|
+
if container_env_str != "":
|
|
538
|
+
wss_env_vars = container_env_str
|
|
498
539
|
|
|
499
540
|
logging.debug(f"Starting WSS: {wss_cmd}\n")
|
|
500
|
-
ret = self._enshell.start_other(wss_cmd)
|
|
541
|
+
ret = self._enshell.start_other(wss_cmd, extra_env=wss_env_vars)
|
|
501
542
|
if ret[0] != 0:
|
|
502
543
|
self.stop()
|
|
503
544
|
raise RuntimeError(f"Error starting WSS: {wss_cmd}\n")
|
|
@@ -511,11 +552,16 @@ class DockerLauncher(Launcher):
|
|
|
511
552
|
use_sos = False
|
|
512
553
|
if self._use_sos:
|
|
513
554
|
use_sos = True
|
|
555
|
+
if self._pim_instance is None:
|
|
556
|
+
ws_port = self._service_host_port["ws"][1]
|
|
557
|
+
else:
|
|
558
|
+
ws_port = self._service_host_port["http"][1]
|
|
514
559
|
session = ansys.pyensight.core.session.Session(
|
|
515
560
|
host=self._service_host_port["grpc_private"][0],
|
|
516
561
|
grpc_port=self._service_host_port["grpc_private"][1],
|
|
562
|
+
html_hostname=self._service_host_port["http"][0],
|
|
517
563
|
html_port=self._service_host_port["http"][1],
|
|
518
|
-
ws_port=
|
|
564
|
+
ws_port=ws_port,
|
|
519
565
|
install_path=None,
|
|
520
566
|
secret_key=self._secret_key,
|
|
521
567
|
timeout=self._timeout,
|
|
@@ -578,7 +624,12 @@ class DockerLauncher(Launcher):
|
|
|
578
624
|
|
|
579
625
|
def _get_host_port(self, uri: str) -> tuple:
|
|
580
626
|
parse_results = urllib3.util.parse_url(uri)
|
|
581
|
-
|
|
627
|
+
port = (
|
|
628
|
+
parse_results.port
|
|
629
|
+
if parse_results.port
|
|
630
|
+
else (443 if re.search("^https|wss$", parse_results.scheme) else None)
|
|
631
|
+
)
|
|
632
|
+
return (parse_results.host, port)
|
|
582
633
|
|
|
583
634
|
def _is_system_egl_capable(self) -> bool:
|
|
584
635
|
"""Check if the system is EGL capable.
|
|
@@ -357,10 +357,9 @@ class EnShellGRPC(object):
|
|
|
357
357
|
|
|
358
358
|
# @brief
|
|
359
359
|
#
|
|
360
|
-
|
|
361
360
|
# @param cmd The command line
|
|
362
361
|
# @return A tuple of (int, string) for (returnCode, returnString)
|
|
363
|
-
def start_other(self, cmd: str):
|
|
362
|
+
def start_other(self, cmd: str, extra_env: Optional[str] = None):
|
|
364
363
|
"""Tell EnShell to start a non-EnShell aware command.
|
|
365
364
|
|
|
366
365
|
The string will be sent to EnShell via the EnShellService::run_command()
|
|
@@ -381,7 +380,10 @@ class EnShellGRPC(object):
|
|
|
381
380
|
self.connect()
|
|
382
381
|
command_string = "start_app OTHER " + cmd
|
|
383
382
|
|
|
384
|
-
|
|
383
|
+
if extra_env is None or extra_env == "":
|
|
384
|
+
return self.run_command(command_string)
|
|
385
|
+
else:
|
|
386
|
+
return self.run_command_with_env(command_string, extra_env)
|
|
385
387
|
|
|
386
388
|
def cei_home(self):
|
|
387
389
|
"""Get the value of CEI_HOME from EnShell."""
|
ansys/pyensight/core/launcher.py
CHANGED
|
@@ -14,7 +14,7 @@ Examples:
|
|
|
14
14
|
import os.path
|
|
15
15
|
import platform
|
|
16
16
|
import socket
|
|
17
|
-
from typing import TYPE_CHECKING, List, Optional
|
|
17
|
+
from typing import TYPE_CHECKING, Dict, List, Optional
|
|
18
18
|
import warnings
|
|
19
19
|
|
|
20
20
|
import requests
|
|
@@ -82,6 +82,8 @@ class Launcher:
|
|
|
82
82
|
self._egl_env_val = True
|
|
83
83
|
else:
|
|
84
84
|
self._egl_env_val = False
|
|
85
|
+
# a dict of any optional launcher specific query parameters for URLs
|
|
86
|
+
self._query_parameters: Dict[str, str] = {}
|
|
85
87
|
|
|
86
88
|
@property
|
|
87
89
|
def session_directory(self) -> str:
|
|
@@ -266,3 +268,44 @@ class Launcher:
|
|
|
266
268
|
|
|
267
269
|
"""
|
|
268
270
|
return platform.system() == "Windows"
|
|
271
|
+
|
|
272
|
+
def _get_query_parameters(self) -> Dict[str, str]:
|
|
273
|
+
"""Return optional http query parameters as a dict.
|
|
274
|
+
It may be empty if there are None.
|
|
275
|
+
If query parameters exist, they should be added to any
|
|
276
|
+
http/https URL intended for the WSS web server.
|
|
277
|
+
This is used by things such as Ansys Lab.
|
|
278
|
+
|
|
279
|
+
Returns
|
|
280
|
+
-------
|
|
281
|
+
dict
|
|
282
|
+
query parameters that should be appended to any queries
|
|
283
|
+
"""
|
|
284
|
+
return self._query_parameters
|
|
285
|
+
|
|
286
|
+
def _add_query_parameters(self, params: Dict[str, str]) -> None:
|
|
287
|
+
"""Add query parameters supplied by params to the
|
|
288
|
+
overall dict of query parameters.
|
|
289
|
+
|
|
290
|
+
Parameters
|
|
291
|
+
----------
|
|
292
|
+
params: dict :
|
|
293
|
+
query parameters to add to overall dict
|
|
294
|
+
"""
|
|
295
|
+
for item, value in params.items():
|
|
296
|
+
self._query_parameters[item] = value
|
|
297
|
+
|
|
298
|
+
def _delete_query_parameters(self, params: List[str]) -> None:
|
|
299
|
+
"""Delete query parameters supplied by params from the
|
|
300
|
+
overall dict of query parameters.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
params: list :
|
|
305
|
+
query parameters to delete from the overall dict
|
|
306
|
+
"""
|
|
307
|
+
for item in params:
|
|
308
|
+
try:
|
|
309
|
+
del self._query_parameters[item]
|
|
310
|
+
except Exception:
|
|
311
|
+
pass
|
|
@@ -5,7 +5,7 @@ that can be displayed via HTML over the websocket server interface.
|
|
|
5
5
|
"""
|
|
6
6
|
import os
|
|
7
7
|
import shutil
|
|
8
|
-
from typing import TYPE_CHECKING, Any, List, Optional, Tuple, no_type_check
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, no_type_check
|
|
9
9
|
import uuid
|
|
10
10
|
import webbrowser
|
|
11
11
|
|
|
@@ -80,6 +80,17 @@ class Renderable:
|
|
|
80
80
|
self._aa: int = aa
|
|
81
81
|
self._fps: float = fps
|
|
82
82
|
self._num_frames: Optional[int] = num_frames
|
|
83
|
+
#
|
|
84
|
+
self._using_proxy = False
|
|
85
|
+
# if we're talking directly to WS, then use 'http' otherwise 'https' for the proxy
|
|
86
|
+
self._http_protocol = "http"
|
|
87
|
+
try:
|
|
88
|
+
if self._session.launcher._pim_instance is not None:
|
|
89
|
+
self._using_proxy = True
|
|
90
|
+
self._http_protocol = "https"
|
|
91
|
+
except Exception:
|
|
92
|
+
# the launcher may not be PIM aware; that's ok
|
|
93
|
+
pass
|
|
83
94
|
|
|
84
95
|
def __repr__(self) -> str:
|
|
85
96
|
name = self.__class__.__name__
|
|
@@ -100,6 +111,27 @@ class Renderable:
|
|
|
100
111
|
name = self.__class__.__name__
|
|
101
112
|
p.text(f"{name}( url='{self._url}' )")
|
|
102
113
|
|
|
114
|
+
def _get_query_parameters_str(self, params: Optional[Dict[str, str]] = None) -> str:
|
|
115
|
+
"""Generate any optional http query parameters.
|
|
116
|
+
Return a string formatted as a URL query to tack on to the
|
|
117
|
+
beginning part of the URL. The string may be empty if there
|
|
118
|
+
aren't any parameters. The method takes a dict
|
|
119
|
+
of parameters, possibly empty or None, and combines it with the
|
|
120
|
+
parameters from the launcher, which also may be empty.
|
|
121
|
+
"""
|
|
122
|
+
qp_dict = self._session.launcher._get_query_parameters()
|
|
123
|
+
if qp_dict is None:
|
|
124
|
+
# just in case
|
|
125
|
+
qp_dict = {}
|
|
126
|
+
if params:
|
|
127
|
+
qp_dict.update(params)
|
|
128
|
+
query_parameter_str = ""
|
|
129
|
+
symbol = "?"
|
|
130
|
+
for p in qp_dict.items():
|
|
131
|
+
query_parameter_str += f"{symbol}{p[0]}={p[1]}"
|
|
132
|
+
symbol = "&"
|
|
133
|
+
return query_parameter_str
|
|
134
|
+
|
|
103
135
|
def _generate_filename(self, suffix: str) -> Tuple[str, str]:
|
|
104
136
|
"""Create session-specific files and URLs.
|
|
105
137
|
|
|
@@ -134,6 +166,8 @@ class Renderable:
|
|
|
134
166
|
The URL to the file (through the session HTTP server) is
|
|
135
167
|
``http://{system}:{websocketserverhtmlport}/{session}_{guid}_{index}_{type}.html``.
|
|
136
168
|
|
|
169
|
+
Note that there may be optional http query parameters at the end of the URL.
|
|
170
|
+
|
|
137
171
|
After this call, ``_url`` and ``_url_remote_pathname`` reflect these names.
|
|
138
172
|
|
|
139
173
|
"""
|
|
@@ -141,8 +175,8 @@ class Renderable:
|
|
|
141
175
|
filename_index = self._filename_index
|
|
142
176
|
remote_pathname, _ = self._generate_filename(suffix)
|
|
143
177
|
simple_filename = f"{self._session.secret_key}_{self._guid}_{filename_index}{suffix}"
|
|
144
|
-
url = f"
|
|
145
|
-
self._url = url
|
|
178
|
+
url = f"{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}"
|
|
179
|
+
self._url = f"{url}/{simple_filename}{self._get_query_parameters_str()}"
|
|
146
180
|
self._url_remote_pathname = remote_pathname
|
|
147
181
|
|
|
148
182
|
def _save_remote_html_page(self, html: str) -> None:
|
|
@@ -265,7 +299,7 @@ class Renderable:
|
|
|
265
299
|
|
|
266
300
|
"""
|
|
267
301
|
for filename in self._download_names:
|
|
268
|
-
url = f"
|
|
302
|
+
url = f"{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}/{filename}{self._get_query_parameters_str()}"
|
|
269
303
|
outpath = os.path.join(dirname, filename)
|
|
270
304
|
with requests.get(url, stream=True) as r:
|
|
271
305
|
with open(outpath, "wb") as f:
|
|
@@ -302,7 +336,7 @@ class RenderableImage(Renderable):
|
|
|
302
336
|
self._session.cmd(cmd)
|
|
303
337
|
# generate HTML page with file references local to the websocket server root
|
|
304
338
|
html = '<body style="margin:0px;padding:0px;">\n'
|
|
305
|
-
html += f'<img src="/{self._png_filename}">\n'
|
|
339
|
+
html += f'<img src="/{self._png_filename}{self._get_query_parameters_str()}">\n'
|
|
306
340
|
html += "</body>\n"
|
|
307
341
|
# refresh the remote HTML
|
|
308
342
|
self._save_remote_html_page(html)
|
|
@@ -330,6 +364,9 @@ class RenderableDeepPixel(Renderable):
|
|
|
330
364
|
an iframe reference.
|
|
331
365
|
"""
|
|
332
366
|
# save the (deep) image file
|
|
367
|
+
# get the optional query parameters which may be an empty string
|
|
368
|
+
# needed for proxy servers like ansys lab
|
|
369
|
+
optional_query = self._get_query_parameters_str()
|
|
333
370
|
w, h = self._default_size(1920, 1080)
|
|
334
371
|
deep = f",num_samples={self._aa},enhanced=1"
|
|
335
372
|
cmd = f'ensight.render({w},{h}{deep}).save(r"""{self._tif_pathname}""")'
|
|
@@ -347,10 +384,12 @@ class RenderableDeepPixel(Renderable):
|
|
|
347
384
|
name += "'website', 'static', 'website', 'content', 'bootstrap.min.css')"
|
|
348
385
|
cmd += f'shutil.copy({name}, r"""{self._session.launcher.session_directory}""")\n'
|
|
349
386
|
self._session.cmd(cmd, do_eval=False)
|
|
387
|
+
url = f"{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}"
|
|
388
|
+
tiff_url = f"{url}/{self._tif_filename}{optional_query}"
|
|
350
389
|
# replace some bits in the HTML
|
|
351
|
-
tiff_url = f"http://{self._session.hostname}:{self._session.html_port}/{self._tif_filename}"
|
|
352
390
|
html = html.replace("TIFF_URL", tiff_url)
|
|
353
391
|
html = html.replace("ITEMID", self._guid)
|
|
392
|
+
html = html.replace("OPTIONAL_QUERY", optional_query)
|
|
354
393
|
# refresh the remote HTML
|
|
355
394
|
self._save_remote_html_page(html)
|
|
356
395
|
super().update()
|
|
@@ -425,7 +464,7 @@ class RenderableMP4(Renderable):
|
|
|
425
464
|
# generate HTML page with file references local to the websocket server root
|
|
426
465
|
html = '<body style="margin:0px;padding:0px;">\n'
|
|
427
466
|
html += f'<video width="{w}" height="{h}" controls>\n'
|
|
428
|
-
html += f' <source src="/{self._mp4_filename}" type="video/mp4" />\n'
|
|
467
|
+
html += f' <source src="/{self._mp4_filename}{self._get_query_parameters_str()}" type="video/mp4" />\n'
|
|
429
468
|
html += "</video>\n"
|
|
430
469
|
html += "</body>\n"
|
|
431
470
|
|
|
@@ -471,8 +510,15 @@ class RenderableWebGL(Renderable):
|
|
|
471
510
|
# Save the file
|
|
472
511
|
self._session.ensight.savegeom.save_geometric_entities(self._avz_pathname)
|
|
473
512
|
# generate HTML page with file references local to the websocket server root
|
|
474
|
-
|
|
475
|
-
|
|
513
|
+
if self._using_proxy:
|
|
514
|
+
# if using pim we get the static content from the front end and not
|
|
515
|
+
# where ensight is running, thus we use a specific URI host and not relative.
|
|
516
|
+
html = f"<script src='{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}/ansys/nexus/viewer-loader.js'></script>\n"
|
|
517
|
+
html += f"<ansys-nexus-viewer src='{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}/{self._avz_filename}"
|
|
518
|
+
html += f"{self._get_query_parameters_str()}'></ansys-nexus-viewer>\n"
|
|
519
|
+
else:
|
|
520
|
+
html = "<script src='/ansys/nexus/viewer-loader.js'></script>\n"
|
|
521
|
+
html += f"<ansys-nexus-viewer src='/{self._avz_filename}{self._get_query_parameters_str()}'></ansys-nexus-viewer>\n"
|
|
476
522
|
# refresh the remote HTML
|
|
477
523
|
self._save_remote_html_page(html)
|
|
478
524
|
super().update()
|
|
@@ -483,6 +529,11 @@ class RenderableVNC(Renderable):
|
|
|
483
529
|
|
|
484
530
|
def __init__(self, *args, **kwargs) -> None:
|
|
485
531
|
super().__init__(*args, **kwargs)
|
|
532
|
+
self._query_params = {
|
|
533
|
+
"autoconnect": "true",
|
|
534
|
+
"host": self._session.html_hostname,
|
|
535
|
+
"port": self._session.ws_port,
|
|
536
|
+
}
|
|
486
537
|
self._rendertype = "remote"
|
|
487
538
|
self.update()
|
|
488
539
|
|
|
@@ -493,9 +544,9 @@ class RenderableVNC(Renderable):
|
|
|
493
544
|
iframe reference.
|
|
494
545
|
|
|
495
546
|
"""
|
|
496
|
-
url = f"
|
|
547
|
+
url = f"{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}"
|
|
497
548
|
url += "/ansys/nexus/novnc/vnc_envision.html"
|
|
498
|
-
url +=
|
|
549
|
+
url += self._get_query_parameters_str(self._query_params)
|
|
499
550
|
self._url = url
|
|
500
551
|
super().update()
|
|
501
552
|
|
|
@@ -504,13 +555,19 @@ class RenderableVNC(Renderable):
|
|
|
504
555
|
class RenderableVNCAngular(Renderable):
|
|
505
556
|
def __init__(self, *args, **kwargs) -> None:
|
|
506
557
|
super().__init__(*args, **kwargs)
|
|
558
|
+
self._query_params = {
|
|
559
|
+
"autoconnect": "true",
|
|
560
|
+
"host": self._session.hostname,
|
|
561
|
+
"port": self._session.ws_port,
|
|
562
|
+
"secretKey": self._session.secret_key,
|
|
563
|
+
}
|
|
507
564
|
self._rendertype = "remote"
|
|
508
565
|
self.update()
|
|
509
566
|
|
|
510
567
|
def update(self):
|
|
511
|
-
url = f"
|
|
568
|
+
url = f"{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}"
|
|
512
569
|
url += "/ansys/nexus/angular/viewer_angular_pyensight.html"
|
|
513
|
-
url +=
|
|
570
|
+
url += self._get_query_parameters_str(self._query_params)
|
|
514
571
|
self._url = url
|
|
515
572
|
super().update()
|
|
516
573
|
|
|
@@ -559,17 +616,33 @@ class RenderableEVSN(Renderable):
|
|
|
559
616
|
self._session.ensight.file.save_scenario_fileslct(self._evsn_pathname)
|
|
560
617
|
|
|
561
618
|
# generate HTML page with file references local to the websocketserver root
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
619
|
+
optional_query = self._get_query_parameters_str()
|
|
620
|
+
|
|
621
|
+
html = f"<script src='/ansys/nexus/viewer-loader.js{optional_query}'></script>\n"
|
|
622
|
+
server = f"{self._http_protocol}://{self._session.html_hostname}:{self._session.html_port}"
|
|
623
|
+
|
|
624
|
+
# FIXME: This method doesn't work with Ansys Lab since the viewer seems to require
|
|
625
|
+
# a full pathname to the file being generated by EnSight on a shared file system.
|
|
626
|
+
# The following commented out line should replace the two after that, but that
|
|
627
|
+
# prevents running locally from working since it's not using the full pathname to
|
|
628
|
+
# the shared file. -MFK
|
|
629
|
+
cleanname = self._evsn_filename.replace("\\", "/")
|
|
565
630
|
attributes = f"src='{cleanname}'"
|
|
566
|
-
attributes
|
|
631
|
+
# attributes = f"src='{cleanname}{optional_query}'"
|
|
632
|
+
|
|
633
|
+
attributes += f" proxy_img='/{self._proxy_filename}{optional_query}'"
|
|
567
634
|
attributes += " aspect_ratio='proxy'"
|
|
568
635
|
attributes += " renderer='envnc'"
|
|
569
636
|
http_uri = f'"http":"{server}"'
|
|
570
|
-
ws_uri =
|
|
637
|
+
ws_uri = (
|
|
638
|
+
f'"ws":"{self._http_protocol}://{self._session.html_hostname}:{self._session.ws_port}"'
|
|
639
|
+
)
|
|
571
640
|
secrets = f'"security_token":"{self._session.secret_key}"'
|
|
572
|
-
|
|
641
|
+
if not self._using_proxy or optional_query == "":
|
|
642
|
+
attributes += f" renderer_options='{{ {http_uri}, {ws_uri}, {secrets} }}'"
|
|
643
|
+
else:
|
|
644
|
+
query_args = f'"extra_query_args":"{optional_query[1:]}"'
|
|
645
|
+
attributes += f" renderer_options='{{ {http_uri}, {ws_uri}, {secrets}, {query_args} }}'"
|
|
573
646
|
html += f"<ansys-nexus-viewer {attributes}></ansys-nexus-viewer>\n"
|
|
574
647
|
# refresh the remote HTML
|
|
575
648
|
self._save_remote_html_page(html)
|
|
@@ -622,12 +695,14 @@ class RenderableSGEO(Renderable): # pragma: no cover
|
|
|
622
695
|
# If the first update, generate the HTML
|
|
623
696
|
if self._revision == 0:
|
|
624
697
|
# generate HTML page with file references local to the websocketserver root
|
|
625
|
-
attributes =
|
|
626
|
-
|
|
698
|
+
attributes = (
|
|
699
|
+
f"src='/{self._sgeo_base_filename}/geometry.sgeo{self._get_query_parameters_str()}'"
|
|
700
|
+
)
|
|
701
|
+
attributes += f" proxy_img='/{self._sgeo_base_filename}/proxy.png{self._get_query_parameters_str()}'"
|
|
627
702
|
attributes += " aspect_ratio='proxy'"
|
|
628
703
|
attributes += " renderer='sgeo'"
|
|
629
704
|
|
|
630
|
-
html = "<script src='/ansys/nexus/viewer-loader.js'></script>\n"
|
|
705
|
+
html = f"<script src='/ansys/nexus/viewer-loader.js{self._get_query_parameters_str()}'></script>\n"
|
|
631
706
|
html += f"<ansys-nexus-viewer id='{self._guid}' {attributes}></ansys-nexus-viewer>\n"
|
|
632
707
|
html += self._periodic_script()
|
|
633
708
|
# refresh the remote HTML
|
|
@@ -662,7 +737,7 @@ class RenderableSGEO(Renderable): # pragma: no cover
|
|
|
662
737
|
html_source = os.path.join(os.path.dirname(__file__), "sgeo_poll.html")
|
|
663
738
|
with open(html_source, "r") as fp:
|
|
664
739
|
html = fp.read()
|
|
665
|
-
revision_uri = f"/{self._sgeo_base_filename}/geometry.rev"
|
|
740
|
+
revision_uri = f"/{self._sgeo_base_filename}/geometry.rev{self._get_query_parameters_str()}"
|
|
666
741
|
html = html.replace("REVURL_ITEMID", revision_uri)
|
|
667
742
|
html = html.replace("ITEMID", self._guid)
|
|
668
743
|
return html
|
ansys/pyensight/core/session.py
CHANGED
|
@@ -77,6 +77,9 @@ class Session:
|
|
|
77
77
|
The default is ``""``.
|
|
78
78
|
grpc_port : int, optional
|
|
79
79
|
Port number of the EnSight gRPC service. The default is ``12345``.
|
|
80
|
+
html_host : str, optional
|
|
81
|
+
Optional hostname for html connections if different than host
|
|
82
|
+
Used by Ansys Lab and reverse proxy servers
|
|
80
83
|
html_port : int, optional
|
|
81
84
|
Port number of the websocket server's HTTP server. The default is
|
|
82
85
|
``None``.
|
|
@@ -113,6 +116,7 @@ class Session:
|
|
|
113
116
|
install_path: Optional[str] = None,
|
|
114
117
|
secret_key: str = "",
|
|
115
118
|
grpc_port: int = 12345,
|
|
119
|
+
html_hostname: Optional[str] = None,
|
|
116
120
|
html_port: Optional[int] = None,
|
|
117
121
|
ws_port: Optional[int] = None,
|
|
118
122
|
session_directory: Optional[str] = None,
|
|
@@ -131,6 +135,11 @@ class Session:
|
|
|
131
135
|
self._hostname = host
|
|
132
136
|
self._install_path = install_path
|
|
133
137
|
self._launcher = None
|
|
138
|
+
if html_hostname == "" or html_hostname is None:
|
|
139
|
+
# if we weren't given an html host, use the hostname
|
|
140
|
+
self._html_hostname = self._hostname
|
|
141
|
+
else:
|
|
142
|
+
self._html_hostname = html_hostname
|
|
134
143
|
self._html_port = html_port
|
|
135
144
|
self._ws_port = ws_port
|
|
136
145
|
self._secret_key = secret_key
|
|
@@ -192,7 +201,8 @@ class Session:
|
|
|
192
201
|
session_dir = self.launcher.session_directory
|
|
193
202
|
s = f"Session(host='{self.hostname}', secret_key='{self.secret_key}', "
|
|
194
203
|
s += f"sos={self.sos}, rest_api={self.rest_api}, "
|
|
195
|
-
s += f"
|
|
204
|
+
s += f"html_hostname={self.html_hostname}, html_port={self.html_port}, "
|
|
205
|
+
s += f"grpc_port={self._grpc_port}, "
|
|
196
206
|
s += f"ws_port={self.ws_port}, session_directory=r'{session_dir}')"
|
|
197
207
|
return s
|
|
198
208
|
|
|
@@ -227,7 +237,14 @@ class Session:
|
|
|
227
237
|
"""
|
|
228
238
|
if not self.rest_api:
|
|
229
239
|
return
|
|
230
|
-
|
|
240
|
+
#
|
|
241
|
+
#
|
|
242
|
+
# even when using PIM and a proxy server (Ansys Lab) this connects
|
|
243
|
+
# directly from the python running in the Notebook (the front-end)
|
|
244
|
+
# to the EnSight Docker Container and not the proxy server.
|
|
245
|
+
# Thus, here we use 'http', the private hostname, and the html port
|
|
246
|
+
# (which is the same on the proxy server).
|
|
247
|
+
url = f"http://{self._hostname}:{self.html_port}/ensight/v1/session/exec"
|
|
231
248
|
time_start = time.time()
|
|
232
249
|
while time.time() - time_start < self._timeout:
|
|
233
250
|
try:
|
|
@@ -343,6 +360,11 @@ class Session:
|
|
|
343
360
|
"""Hostname of the system hosting the EnSight instance."""
|
|
344
361
|
return self._hostname
|
|
345
362
|
|
|
363
|
+
@property
|
|
364
|
+
def html_hostname(self) -> str:
|
|
365
|
+
"""Hostname of the system hosting the EnSight web server instance."""
|
|
366
|
+
return self._html_hostname
|
|
367
|
+
|
|
346
368
|
@property
|
|
347
369
|
def launcher(self) -> "Launcher":
|
|
348
370
|
"""Reference to the launcher instance if a launcher was used to instantiate the session."""
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
ansys/pyensight/core/__init__.py,sha256=ZOASvqNxSR8CGJDHQACGwjtFVvI_vmmfbpy1IAmEJhk,828
|
|
2
|
-
ansys/pyensight/core/deep_pixel_view.html,sha256=
|
|
3
|
-
ansys/pyensight/core/dockerlauncher.py,sha256=
|
|
2
|
+
ansys/pyensight/core/deep_pixel_view.html,sha256=oZmcCIS3Dqqsoj8oheYubLAH2ZVKXao3iJM2WXYBEKs,3421
|
|
3
|
+
ansys/pyensight/core/dockerlauncher.py,sha256=Bf3NsjxRhF4-rvgBv56v82EYaMYVr6k0hCYA8qwVvrc,27191
|
|
4
4
|
ansys/pyensight/core/enscontext.py,sha256=UfeFvY4ZyOcIkgKcIyhs3GohZhWl515QFhJtBxvIfpE,11803
|
|
5
|
-
ansys/pyensight/core/enshell_grpc.py,sha256=
|
|
5
|
+
ansys/pyensight/core/enshell_grpc.py,sha256=nNvJqrFG_-glM90dPAC6anFT9qXg7WohQ6CoULXgaSQ,15134
|
|
6
6
|
ansys/pyensight/core/ensight_grpc.py,sha256=yFnvxjI2cAWd0c0gcM46MEIA5Ov7DUMlufqUwwc3g9U,14343
|
|
7
7
|
ansys/pyensight/core/ensobj.py,sha256=tynUyYrpzCz2lvcse6fcmutnG6Jj111s518OlO19EqE,17354
|
|
8
|
-
ansys/pyensight/core/launch_ensight.py,sha256=
|
|
9
|
-
ansys/pyensight/core/launcher.py,sha256=
|
|
8
|
+
ansys/pyensight/core/launch_ensight.py,sha256=KqUq3dYc2j4aKMkZYu9rXXw7ODZDqFbD6kx4Vt0uJcg,5915
|
|
9
|
+
ansys/pyensight/core/launcher.py,sha256=zj-6DBp307-IJ0RTDmZOxCFVGemJu8YaagJLZFLloNw,10445
|
|
10
10
|
ansys/pyensight/core/listobj.py,sha256=vsVTeI3RY0P1n5GNOHW-iU95GCWnHlOg_E6leVMQScw,8223
|
|
11
11
|
ansys/pyensight/core/locallauncher.py,sha256=sgaPrG-7ctXZ_ytGuHeriiVmgvI0kUeX6nKVJ4OiDUs,13984
|
|
12
12
|
ansys/pyensight/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
ansys/pyensight/core/renderable.py,sha256
|
|
14
|
-
ansys/pyensight/core/session.py,sha256=
|
|
13
|
+
ansys/pyensight/core/renderable.py,sha256=z61Pum_Pa2CVoXVWOCqPngeHT_ifBS3fpqA5mZDDmnc,30777
|
|
14
|
+
ansys/pyensight/core/session.py,sha256=fI-Z_dNJz7wD_wOabF7-jd1lSq8z3KsqS70ECeAz4NY,61036
|
|
15
15
|
ansys/pyensight/core/sgeo_poll.html,sha256=1M4BIc5CZpYA3b40qzk22NcPCLhjFnWdoS2PrS6Rhn4,752
|
|
16
16
|
ansys/pyensight/core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
ansys/pyensight/core/utils/adr.py,sha256=XslZhlwcrSGzOlnhzprOv3ju_ppxxsWBjCnQL5KiNms,3570
|
|
@@ -20,7 +20,7 @@ ansys/pyensight/core/utils/parts.py,sha256=x0Zso-ef64UJ-3BmYS3dymjftaWQI21WFTsDt
|
|
|
20
20
|
ansys/pyensight/core/utils/query.py,sha256=cQXt_07ZuNAwueAIXinI3_f7G9lXass6j7G0aRJltZE,19035
|
|
21
21
|
ansys/pyensight/core/utils/support.py,sha256=gNBH_VyQ_Gdas7P28W_GZ62Tz4Gg7YK8UASUzdT-lSU,2397
|
|
22
22
|
ansys/pyensight/core/utils/views.py,sha256=vf4gSBRl6uC_LPwZdzrdMcR0dyi_PwYmRo20CPmjEBE,12209
|
|
23
|
-
ansys_pyensight_core-0.6.
|
|
24
|
-
ansys_pyensight_core-0.6.
|
|
25
|
-
ansys_pyensight_core-0.6.
|
|
26
|
-
ansys_pyensight_core-0.6.
|
|
23
|
+
ansys_pyensight_core-0.6.2.dist-info/LICENSE,sha256=qQWivZ12ETN5l3QxvTARY-QI5eoRRlyHdwLlAj0Bg5I,1089
|
|
24
|
+
ansys_pyensight_core-0.6.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
25
|
+
ansys_pyensight_core-0.6.2.dist-info/METADATA,sha256=xrpWIqcf30R_4dS1BEvbpSxWvDMTqkUxa5uf3I9wMxI,11804
|
|
26
|
+
ansys_pyensight_core-0.6.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|