123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- r"""
- This module implements the core RPC and publish APIs. Developers can extend
- LinkProtocol to provide additional RPC callbacks for their web-applications. Then extend
- ServerProtocol to hook all the needed LinkProtocols together.
- """
- import logging
- from . import register as exportRpc
- from . import schedule_callback
- # =============================================================================
- #
- # Base class for objects that can accept RPC calls or publish over wslink
- #
- # =============================================================================
- class LinkProtocol(object):
- """
- Subclass this to communicate with wslink clients. LinkProtocol
- objects provide rpc and pub/sub actions.
- """
- def __init__(self):
- # need a no-op in case they are called before connect.
- self.publish = lambda x, y: None
- self.addAttachment = lambda x: None
- self.coreServer = None
- def init(self, publish, addAttachment, stopServer):
- self.publish = publish
- self.addAttachment = addAttachment
- self.stopServer = stopServer
- def getSharedObject(self, key):
- if self.coreServer:
- return self.coreServer.getSharedObject(key)
- return None
- def onConnect(self, request, client_id):
- """Called when a new websocket connection is established.
- request is the HTTP request header, and client_id an opaque string that
- identifies the connection. The default implementation is a noop. A
- subclass may redefine it.
- """
- pass
- def onClose(self, client_id):
- """Called when a websocket connection is closed."""
- pass
- # =============================================================================
- #
- # Base class for wslink ServerProtocol objects
- #
- # =============================================================================
- class ServerProtocol(object):
- """
- Defines the core server protocol for wslink. Gathers a list of LinkProtocol
- objects that provide rpc and publish functionality.
- """
- def __init__(self):
- self.linkProtocols = []
- self.secret = None
- self.initialize()
- def init(self, publish, addAttachment, stopServer):
- self.publish = publish
- self.addAttachment = addAttachment
- self.stopServer = stopServer
- def initialize(self):
- """
- Let sub classes define what they need to do to properly initialize
- themselves.
- """
- pass
- def setSharedObject(self, key, shared):
- if not hasattr(self, "sharedObjects"):
- self.sharedObjects = {}
- if shared == None and key in self.sharedObjects:
- del self.sharedObjects[key]
- else:
- self.sharedObjects[key] = shared
- def getSharedObject(self, key):
- if key in self.sharedObjects:
- return self.sharedObjects[key]
- else:
- return None
- def registerLinkProtocol(self, protocol):
- assert isinstance(protocol, LinkProtocol)
- protocol.coreServer = self
- self.linkProtocols.append(protocol)
- # Note: this can only be used _before_ a connection is made -
- # otherwise the WslinkWebSocketServerProtocol will already have stored references to
- # the RPC methods in the protocol.
- def unregisterLinkProtocol(self, protocol):
- assert isinstance(protocol, LinkProtocol)
- protocol.coreServer = None
- try:
- self.linkProtocols.remove(protocol)
- except ValueError as e:
- logging.error("Link protocol missing from registered list.")
- def getLinkProtocols(self):
- return self.linkProtocols
- def updateSecret(self, newSecret):
- self.secret = newSecret
- def onConnect(self, request, client_id):
- """Called when a new websocket connection is established.
- request is the HTTP request header, and client_id an opaque string that
- identifies the connection. The default implementation is a noop. A
- subclass may redefine it.
- """
- pass
- def onClose(self, client_id):
- """Called when a websocket connection is closed."""
- pass
- @exportRpc("application.exit")
- def exit(self):
- """RPC callback to exit"""
- self.stopServer()
- @exportRpc("application.exit.later")
- def exitLater(self, secondsLater=60):
- """RPC callback to exit after a short delay"""
- print(f"schedule exit for {secondsLater} seconds from now")
- schedule_callback(secondsLater, self.stopServer)
|