diff --git a/examples/Examples.ipynb b/examples/Examples.ipynb index ca5fcc5c5dc04af6cb345e819d5b1111923231bd..703d1c7f35725d5e480b989f714ffcd4f17b1bfb 100644 --- a/examples/Examples.ipynb +++ b/examples/Examples.ipynb @@ -1,5 +1,20 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Content\n", + "- SimpleRenderer\n", + " - Usage\n", + " - Sizing\n", + "- RemoteRenderer\n", + " - Usage\n", + " - Using Jupyter Server Proxy\n", + " - Using a custom protocol\n", + " - Usage with a pvserver and choosen port¶" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -177,7 +192,7 @@ "source": [ "### Using Jupyter Server Proxy\n", "\n", - "If you want to access your webserver using Jupyter Server Proxy, you need to set `use_jupyter_server_proxy` to True and specify the baseURL. \n", + "If you want to access your webserver using Jupyter Server Proxy, you need to set `use_jupyter_server_proxy` to True and specify the baseURL. Setting `use_jupyter_server_proxy_https` to true, allows to use the https certificates of the proxy, to use an encrypted connection between client brwoser and the jupyter Server Proxy.\n", "\n", "Example: If your notebook url is `http://localhost:8888` and you would access a process using `http://localhost:88888/proxy/8080`, the baseURL would be the part before 'proxy, `localhost:8888`." ] @@ -191,7 +206,7 @@ "outputs": [], "source": [ "proxied_renderer = RemoteRenderer(baseURL='localhost:8888', use_jupyter_server_proxy=True, \n", - " port=8080, ws='pvwebserver/ws')" + " use_jupyter_server_proxy_https=True, port=8080, ws='pvwebserver/ws')" ] }, { @@ -377,6 +392,24 @@ "source": [ "renderer.update_render()" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage with a pvserver and choosen port\n", + "This shows, how to connect to a pvserver on startup and open a specific port. Additionaly debug outpout is enabled, in case an error is searched. The pvserver adress and port can be specified. This only works with the default protocol, as the connection is established there. So in case of a custom protocol, the connection to the pvserver has to be started by the user (or in the custom protocol)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "renderer = RemoteRenderer(pvserver_host=\"localhost\", pvserver_port = 11111, baseURL=\"localhost\", ws=\"pvwebserver/ws\",\n", + " debug=True, port = 1234)" + ] } ], "metadata": { @@ -400,4 +433,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/package.json b/package.json index 63e16271019f1bd17ca33be747b2f1064f96659c..b0313dac04f3f348d229beff99eda419d4223256 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,8 @@ "@jupyter-widgets/base": "^1.1.10 || ^2", "hammerjs": "^2.0.8", "monologue.js": "^0.3.5", - "paraviewweb": "3.2.12", - "wslink": "0.1.13" + "paraviewweb": "^3.2.12", + "wslink": "^0.1.13" }, "devDependencies": { "@phosphor/application": "^1.6.0", diff --git a/pvlink/_frontend.py b/pvlink/_frontend.py index 8e391d010f2c375b86e10aaa135842deb8b58e5a..26b2c9ff7b29b39684781faa8afec3a5aae67c12 100644 --- a/pvlink/_frontend.py +++ b/pvlink/_frontend.py @@ -9,4 +9,4 @@ Information about the frontend package of the widgets. """ module_name = "pvlink" -module_version = "^0.1.0" +module_version = "0.2.1" diff --git a/pvlink/remoterenderer.py b/pvlink/remoterenderer.py index 6a6ace73f729cdab2be59ee8f9bbffc36a86e93a..22c73f3db4c4137ff5dd4c8af5bc8c3a61ba2e7a 100644 --- a/pvlink/remoterenderer.py +++ b/pvlink/remoterenderer.py @@ -20,7 +20,7 @@ import binascii import os import psutil -from ipywidgets import DOMWidget +from ipywidgets import DOMWidget, register from traitlets import Int, Unicode from ._frontend import module_name, module_version @@ -28,7 +28,7 @@ from .server import start_webserver from wslink import server server.start_webserver = start_webserver - +@register class RemoteRenderer(DOMWidget): """ A ParaViewWeb RemoteRenderer Widget which automatically starts a @@ -61,6 +61,9 @@ class RemoteRenderer(DOMWidget): whether the connection should be established using Jupyter Server Proxy. If True, the baseURL needs to be adjusted accordingly. Default = False + use_jupyter_server_proxy_https: bool + Access using wss, to Jupyter server proxy. There it will be decrypted and send as ws to socket + Default = False protocol: pv_wslink.PVServerProtocol a custom PVServerProtocol class which handles clients requests and run a default pipeline exactly once @@ -100,10 +103,11 @@ class RemoteRenderer(DOMWidget): # Placeholder to force rendering updates on change. _update = Int(0).tag(sync=True) - def __init__(self, pvserver_host=None, pvserver_port=11111, baseURL='localhost', use_jupyter_server_proxy=False, protocol=None, *args, **kwargs): + def __init__(self, pvserver_host=None, pvserver_port=11111, baseURL='localhost', use_jupyter_server_proxy=False, use_jupyter_server_proxy_https=False, protocol=None, *args, **kwargs): super().__init__(*args, **kwargs) self.baseURL = baseURL self.use_jupyter_server_proxy = use_jupyter_server_proxy + self.use_jupyter_server_proxy_https = use_jupyter_server_proxy_https self.pvserver_host = pvserver_host self.pvserver_port = pvserver_port self.protocol = protocol @@ -154,12 +158,12 @@ class RemoteRenderer(DOMWidget): if key == 'p' or key == 'port': arg_list.append(str(value)) elif value == True and (key != 'f' and key != 'force-flush'): - break + pass else: arg_list.append(value) # If no port is given, check for the next free port starting from 8080 if 'p' not in kwargs.keys() and 'port' not in kwargs.keys(): - port = self._find_next_free_port(8080) + port = _find_next_free_port(8080) arg_list.append('-p') arg_list.append(str(port)) # If no authKey is given, create a randon authentication key @@ -183,23 +187,32 @@ class RemoteRenderer(DOMWidget): self.authKey = args.authKey self.port = args.port self.sessionURL = '{wsProtocol}://{baseURL}{use_proxy}{port}/{ws_endpoint}'.format( - wsProtocol='wss' if args.sslKey and args.sslCert else 'ws', + wsProtocol='wss' if (args.sslKey and args.sslCert) or self.use_jupyter_server_proxy_https else 'ws', use_proxy='/proxy/' if self.use_jupyter_server_proxy else ':', baseURL=self.baseURL, port=args.port, ws_endpoint=args.ws ) - def _find_next_free_port(self, port): + def _find_next_free_port(start_port): """ Finds next free port starting from a given port using the psutil module. + For port numbers smaller than 1, starts search with the first registered port (1024), + returns None, if no free port can be found between start_port and the biggest port number (65535) """ - free = False - while not free: + max_port = 65535 + + if start_port < 1: + port = 1024 + else: + port = start_port + + while port <= max_port: for conn in psutil.net_connections(): if conn.status == 'LISTEN' and conn.laddr.port == port: port += 1 + break else: - free = True - return port + return port + return None def update_render(self): """Explicit call for the renderer on the javascript side to render.""" diff --git a/pvlink/simplerenderer.py b/pvlink/simplerenderer.py index ab8a6814736ee8b7029d8adae6bc6c8b3baf7d32..a1b631b4cc8e3d0fec7412e839b3c8fff76cdcac 100644 --- a/pvlink/simplerenderer.py +++ b/pvlink/simplerenderer.py @@ -11,11 +11,11 @@ This requires a VTK Web or ParaViewWeb server application, see https://kitware.github.io/paraviewweb/examples/RemoteRenderer.html#RemoteRenderer. """ -from ipywidgets import DOMWidget +from ipywidgets import DOMWidget, register from traitlets import Int, Unicode from ._frontend import module_name, module_version - +@register class SimpleRenderer(DOMWidget): """ A simple ParaViewWeb RemoteRenderer Widget. diff --git a/setup.py b/setup.py index 6234e363b71862f9ff40cdd8e102c9b854acf148..fd4d8ab6b0919768dc46995b5200166a49935145 100644 --- a/setup.py +++ b/setup.py @@ -91,9 +91,9 @@ setup_args = dict( include_package_data = True, install_requires = [ 'ipywidgets>=7.0.0', - 'psutil==5.7.0', + 'psutil>=4.0.0', 'twisted>=19.2.1', - 'wslink==0.1.13', + 'wslink>=0.1.13', ], extras_require = { 'test': [