Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ice-dev] ParaView Web Visualizer shared sessions

Yes, we can have multiple open at once in Eclipse, though the server will pop open a new window for each additional file, so perhaps each one is its own ParaView session internally?


How can I check the http and ws endpoints to make sure they are active?


I've attached the server file.


Robert


From: Sebastien Jourdain <sebastien.jourdain@xxxxxxxxxxx>
Sent: Friday, April 22, 2016 5:17 PM
To: Smith, Robert W.
Cc: ice-dev@xxxxxxxxxxx
Subject: Re: ParaView Web Visualizer shared sessions
 
Can you have 2 different views inside your eclipse while you have only one server?

Moreover, you need to make sure your http_server does provide the same protocols as the pv_web_visualizer.py. 
On top of that, you need to make sure you both have the http and ws endpoint active.

As I don't remember what you have in your http_pvw_server.py, could you send it to me so I can look at it?

Seb

On Fri, Apr 22, 2016 at 3:07 PM, Smith, Robert W. <smithrw@xxxxxxxx> wrote:

Sebastien,


Ah, so it was just the same path to the visualizer I was using before. I've played around with it some. With the http server running on port 9600 and the web visualizer running on port 9601:


http://localhost:9601/apps/Visualizer?sessionURL=ws://localhost:9601/ws gives me a normal Web Visualizer with nothing inside it.


http://localhost:9601/apps/Visualizer?sessionURL=ws://loca​lhost:9600/ws gives me a loading screen which never ends.


I'm also not sure how to specify which particular view from the http server I want loaded into the Web Visualizer. Say I have two files open simultaneously in different views on the http server and press the open Web Visualizer button on one of them. How do I let the Web Visualizer know to sync up with that session instead of the other one?


Robert


From: Sebastien Jourdain <sebastien.jourdain@xxxxxxxxxxx>
Sent: Friday, April 22, 2016 4:14 PM

To: Smith, Robert W.
Cc: ice-dev@xxxxxxxxxxx
Subject: Re: ParaView Web Visualizer shared sessions
 
I don't think so... But I believe you must know what page you are opening right? If not, you need to find out and just add at the end the following String. "?sessionURL=ws://localhost:{same_port}/ws" and that's it.

On Fri, Apr 22, 2016 at 2:08 PM, Smith, Robert W. <smithrw@xxxxxxxx> wrote:

So the url to use the pre-existing session would be something like http://localhost:$9600:$/www?sessionURL=ws://localhost:$9600/ws​ ?


From: Sebastien Jourdain <sebastien.jourdain@xxxxxxxxxxx>
Sent: Friday, April 22, 2016 4:04 PM

To: Smith, Robert W.
Cc: ice-dev@xxxxxxxxxxx
Subject: Re: ParaView Web Visualizer shared sessions
 
Ok looking back at your command line I believe the url you are using is http://localhost:{port}/apps/Visualizer

Which mean that when you start your own script, you need to also add the following set of args:

--content ~/www

On Fri, Apr 22, 2016 at 2:01 PM, Sebastien Jourdain <sebastien.jourdain@xxxxxxxxxxx> wrote:
I'm not sure either as I don't know what is the URL that you are opening... 

On Fri, Apr 22, 2016 at 2:01 PM, Smith, Robert W. <smithrw@xxxxxxxx> wrote:

​Sebastien,


I'm not sure what "your_enpoint_xxx" is supposed to be. Is it the view ID for the file that we already have open?


Robert


From: Sebastien Jourdain <sebastien.jourdain@xxxxxxxxxxx>
Sent: Friday, April 22, 2016 3:55 PM

To: Smith, Robert W.
Cc: ice-dev@xxxxxxxxxxx
Subject: Re: ParaView Web Visualizer shared sessions
 
Ok then,

1) To auto load the file with that pv_web_visualizer.py just add that extra argument --load-file xxx
2) To use the same session, you should use something along those lines: http://localhost:${portNumber}/${your_enpoint_xxx}?sessionURL=ws://localhost:${portNumber}/ws

Let me know if that doesn't work...

Seb

On Fri, Apr 22, 2016 at 1:49 PM, Smith, Robert W. <smithrw@xxxxxxxx> wrote:

Sebastien,


When the user establishes a connection to ParaView, we run


~/pvpython ~/http_pvw_server.py --host localhost --port (portNumber)


Then we connect to that server and use it for our embedded visualizations.


When they click the Open in Web Visualizer button, we check to see if the web visualizer is already running. If not, we run 


~/pvpython ~/pv_web_visualizer.py --content ~/www --data-dir (path to a folder in the current Eclipse workspace named ItemDB. All files for visualization will be placed in this folder.) --port (portNumber2)


Then we open an internal web browser opened to localhost:(portNumber2)/apps/Visualizer 


Thanks in advance for the help.


Robert


From: Sebastien Jourdain <sebastien.jourdain@xxxxxxxxxxx>
Sent: Friday, April 22, 2016 3:32 PM
To: Smith, Robert W.
Cc: ice-dev@xxxxxxxxxxx
Subject: Re: ParaView Web Visualizer shared sessions
 
Hi Robert,

I guess before answering, I should ask you first how do you start the python script in both of your use case (inside Ice / PVW Visualizer)?
And how do you setup the --data-dir argument?

Then from that, I can explain what actually make sense for you. Otherwise I way assume something different and get you more confused.

Seb 

On Fri, Apr 22, 2016 at 1:09 PM, Smith, Robert W. <smithrw@xxxxxxxx> wrote:

Hello ​Sebastien,


Thank you for mentioning the ability to have a shared session between the http web server and the web visualizer in ParaView. I'd like to get a record of how to do this for the dev list, so could you please instructions on how to run them both from the same session?


Thank you,

Robert Smith







import json, re, os, inspect, sys

# Imports need to run a simple webserver
from twisted.web import server, resource, http
from twisted.web.resource import Resource
from twisted.internet import reactor
from twisted.web.static import File

# import paraview modules.
from paraview.web import wamp      as pv_wamp
from paraview.web import protocols as pv_protocols
from paraview import simple
from paraview import servermanager

# import RPC annotation
from autobahn.wamp import register as exportRpc

try:
    import argparse
except ImportError:
    # since  Python 2.6 and earlier don't have argparse, we simply provide
    # the source for the same as _argparse and we use it instead.
    import _argparse as argparse

# Module-level regex object won't have to be recompiled on each POST request
# The first regex group is the RPC call, e.g., viewport.image.render
# The second (optional) regex group is the view id. If not there, assume -1.
endpoint = 'rpc-http'
urlMatcher = re.compile(endpoint + '/([^/]+)')
#urlMatcher = re.compile(endpoint + '/([^/]+)' + '(?:/([0-9]*))?')

# =============================================================================
# Convenience method to parse out the rpc method name from the path.  In order
# to find the method name, the server expects the path to contain:
#
#    /hpcmp/rpc.method.name
#
# =============================================================================
def extractRpcMethod(path):
    m = urlMatcher.search(path)
    if m:
        return m.group(1) #, m.group(2)
    else:
        return None


# =============================================================================
# Custom visualization application session
# =============================================================================
class _BasicServer(pv_wamp.PVServerProtocol):

    @staticmethod
    def add_arguments(parser):
        parser.add_argument("--host", type=str, default='localhost', help="the interface for the web-server to listen on (default: localhost)")
        parser.add_argument("--port", default=8080, type=int, help="Which port to listen on", dest="port")
        
    @staticmethod
    def configure(args):
        pass

    def initialize(self):
        # Set the base directory to the user's home area. 
        baseDir = os.path.expanduser("~")
        
        # Bring used components
        self.registerVtkWebProtocol(pv_protocols.ParaViewWebMouseHandler())
        self.registerVtkWebProtocol(pv_protocols.ParaViewWebViewPort())
        self.registerVtkWebProtocol(pv_protocols.ParaViewWebViewPortImageDelivery())
        self.registerVtkWebProtocol(pv_protocols.ParaViewWebFileListing(baseDir,baseDir))
        #self.registerVtkWebProtocol(pv_protocols.ParaViewWebProxyManager(None,baseDir))
        self.proxyManager = pv_protocols.ParaViewWebProxyManager(None,baseDir)
        self.registerVtkWebProtocol(self.proxyManager)
        self.colorManager = pv_protocols.ParaViewWebColorManager()
        self.registerVtkWebProtocol(self.colorManager)
        self.registerVtkWebProtocol(pv_protocols.ParaViewWebTimeHandler())
        
        # The below dictionaries are keyed on global IDs obtained from
        #   GetGlobalIDAsString() methods.
        # Each entry looks like: view, proxyId, repId, animScene
        self.views = {}
        # Each entry contains a single file proxy.
        self.proxies = {}
        # Each entry contains a single representation proxy.
        self.representations = {}

    def createView(self, fullPath):
        # Find the relative path for the call to proxyManager.open(relativePath).
        # TODO
        relativePath = fullPath      
        
        # Create a new view.
        view = simple.CreateRenderView()
        viewId = int(view.GetGlobalIDAsString())
        self.views[viewId] = (view, None, None, None)
        
        # Open the file. Throw an error if the file could not be read.
        response = self.proxyManager.open(relativePath)
        try:
            proxyId = int(response['id'])
        except ValueError:
            self.disposeView(viewId)
            return { "success": False, "error": response['reason'] }
        proxy = self.proxyManager.mapIdToProxy(proxyId)
        self.proxies[proxyId] = proxy
        
        # Find the corresponding representation proxy.
        rep = simple.GetRepresentation(proxy=proxy, view=view)
        repId = int(rep.GetGlobalIDAsString())
        self.representations[repId] = rep
        
        # Create a new AnimationScene just for this view.
        # TODO
        animScene = None
        # Store the view metadata currently associated with the view's ID.
        self.views[viewId] = (view, proxyId, repId, animScene)
        # Hide all other proxies that for whatever reason are automatically added to this view.
        self._hideOtherViews(proxyId, view)
        self.activateView(viewId)
        # Return a JSON object containing the view ID, the proxy ID, and the representation ID.
        return { "viewId": viewId, "proxyId": proxyId, "repId": repId }

    def activateView(self, id):
        # TODO Add some error handling
        # Find the view.
        viewAssociations = self.views[id]
        view = viewAssociations[0]
        proxyId = viewAssociations[1]
        proxy = self.proxies[proxyId]
        # Make it the active view.
        # Render it.
        # TODO Why don't we need to hide the other proxies?
        #self._hideOtherViews(proxyId, view)
        simple.SetActiveView(view)
        simple.Show()
        simple.Render()
        return { "success": True }
    
    def refreshScalarBars(self, viewId):
        # Try to look up the view, throwing an error if the ID is not an 
        # integer or if the ID was not a valid key for the dictionary.
        try:
            view = self.views[int(viewId)][0]
        except ValueError:
            error = "Invalid view ID:", viewId
            return { "success": False, "error": error }
        except LookupError:
            error = "View with ID", viewId, "not found"
            return { "success": False, "error": error }
        # Hide all of the irrelevant scalar bars/legends.
        simple.HideUnusedScalarBars(view)
        return { "success": True }
    
    def disposeView(self, id):
        # TODO Add some error handling.
        # TODO Figure out how to actually dispose the ParaView resources.
        
        viewAssociations = self.views[id]
        
        # Dispose the view itself
        self.views[id] = None
        
        # Dispose the proxies
        proxyId = viewAssociations[1]
        if proxyId:
            proxy = self.proxies[proxyId]
            # TODO
            self.proxies[proxyId] = None
        repId = viewAssociations[2]
        if repId:
            rep = self.representations[repId]
            # TODO
            self.representations[repId] = None
        animScene = viewAssociations[3]
        # TODO

	sys.exit()
        
        return { "success": True }
    
    def _hideOtherViews(self, proxyId, view):
        proxies = servermanager.ProxyManager().GetProxiesInGroup("sources")
        for key in proxies:
            if key[1] != proxyId:
                simple.Hide(proxies[key], view)
        return

    def changeTime(self, id, action):
        # Find the AnimationScene for the specified view.
        viewAssociations = self.views[id]
        view = viewAssociations[0]
        # Return an error result if necessary.
        if not view:
            return { "time": -1, "error": "Invalid view with id {0}.".format(id) }
        animationScene = viewAssociations[3]
        currentTime = view.ViewTime
        # Update the AnimationScene depending on the action string.
        # This code comes (almost) straight from the ParaView protocols python script.
        if action == "next":
            animationScene.GoToNext()
            if currentTime == view.ViewTime:
                animationScene.GoToFirst()
        elif action == "prev":
            animationScene.GoToPrevious()
            if currentTime == view.ViewTime:
                animationScene.GoToLast()
        elif action == "first":
            animationScene.GoToFirst()
        elif action == "last":
            animationScene.GoToLast()
        else:
            return { "time": -1, "error": "Invalid action {0}.".format(action) }
        # Return a JSON object that contains a "success" boolean and a "reason" string.
        return view.ViewTime

# =============================================================================
# Simple web server endpoint handling POST requests to execute rpc methods
# =============================================================================
class HttpRpcResource(resource.Resource, object):
    def __init__(self, serverProtocol):
        super(HttpRpcResource, self).__init__()

        self.functionMap = {}

        # Build the rpc method dictionary
        protocolList = serverProtocol.getVtkWebProtocols()
        protocolList.append(serverProtocol)    # so the exit methods get "registered"
        for protocolObject in protocolList:
            test = lambda x: inspect.ismethod(x) or inspect.isfunction(x)
            for k in inspect.getmembers(protocolObject.__class__, test):
                proc = k[1]
                if "_wampuris" in proc.__dict__:
                    pat = proc.__dict__["_wampuris"][0]
                    if pat.is_endpoint():
                        uri = pat.uri()
                        # TODO Remove this line
                        print uri
                        self.functionMap[uri] = (protocolObject, proc)
        
        # Register the custom server methods.
        self.functionMap["createView"] = (None, serverProtocol.createView)
        self.functionMap["activateView"] = (None, serverProtocol.activateView)
        self.functionMap["disposeView"] = (None, serverProtocol.disposeView)
        self.functionMap["refreshScalarBars"] = (None, serverProtocol.refreshScalarBars)

    def getChild(self, path, request):
        return self

    def render_GET(self, request):
        return ""

    def render_POST(self, request):
        payload = json.loads(request.content.getvalue())
        args = payload['args']
        methodName = extractRpcMethod(request.path)
        print methodName
        obj,func = self.functionMap[methodName]
        if obj:
            results = func(obj, *args)
        else:
            results = func(*args)
        return json.dumps(results)


# =============================================================================
# Parse arguments, create protocol server, and start webserver
# =============================================================================
if __name__ == "__main__":

    # Create argument parser
    parser = argparse.ArgumentParser(description="ParaView Web Visualizer")

    # Add arguments
    _BasicServer.add_arguments(parser)
    args = parser.parse_args()
    _BasicServer.configure(args)

    # Create the application session
    serverProtocol = _BasicServer(None)

    # Start up the web server
    web_resource = resource.Resource()
    web_resource.putChild(endpoint, HttpRpcResource(serverProtocol))
    site = server.Site(web_resource)
    reactor.listenTCP(args.port, site, interface=args.host)
    reactor.run()

Back to the top