Skip to content

Commit

Permalink
Can pass Service as instance or class!
Browse files Browse the repository at this point in the history
This allows

- sharing the same service object among multiple clients on a server
  (as was the expectation by the user in #198)

- using an pre-initialized instance when connecting a client or hosting
  a oneshot server (partial resolution for #244)
  • Loading branch information
coldfix committed Dec 21, 2017
1 parent 9ceb3f9 commit 0290e65
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 4 deletions.
4 changes: 4 additions & 0 deletions rpyc/core/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"""
from rpyc.lib.compat import execute, is_py3k
from rpyc.core.protocol import Connection
from rpyc.utils.helpers import hybridmethod


class Service(object):
Expand Down Expand Up @@ -87,8 +88,11 @@ def get_service_name(cls):
exposed_get_service_aliases = get_service_aliases
exposed_get_service_name = get_service_name

@hybridmethod
def connect(self, channel, config={}):
"""Setup a connection via the given channel."""
if isinstance(self, type): # autovivify if accessed as class method
self = self()
conn = self._protocol(self, channel, config)
self.on_connect(conn)
return conn
Expand Down
4 changes: 2 additions & 2 deletions rpyc/utils/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def connect_channel(channel, service = VoidService, config = {}):
:returns: an RPyC connection
"""
return service().connect(channel, config)
return service.connect(channel, config)

def connect_stream(stream, service = VoidService, config = {}):
"""creates a connection over a given stream
Expand Down Expand Up @@ -182,7 +182,7 @@ def ssh_connect(remote_machine, remote_port, service = VoidService, config = {})
tun = remote_machine.tunnel(loc_port, remote_port)
stream = TunneledSocketStream.connect("localhost", loc_port)
stream.tun = tun
return service().connect(Channel(stream), config=config)
return service.connect(Channel(stream), config=config)

def discover(service_name, host = None, registrar = None, timeout = 2):
"""
Expand Down
11 changes: 11 additions & 0 deletions rpyc/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,14 @@ def stop(self):
self._thread.join()
self._conn = None


class hybridmethod(object):
"""Decorator for hybrid instance/class methods that will act like a normal
method if accessed via an instance, but act like classmethod if accessed
via the class."""
def __init__(self, func):
self.func = func
def __get__(self, obj, cls):
return self.func.__get__(cls if obj is None else obj, obj)
def __set__(self, obj, val):
raise AttributeError("Cannot overwrite method")
4 changes: 2 additions & 2 deletions rpyc/utils/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def _serve_client(self, sock, credentials):
try:
config = dict(self.protocol_config, credentials = credentials,
endpoints = (sock.getsockname(), addrinfo), logger = self.logger)
conn = self.service().connect(
conn = self.service.connect(
Channel(SocketStream(sock)),
config)
self._handle_connection(conn)
Expand Down Expand Up @@ -477,7 +477,7 @@ def _authenticate_and_build_connection(self, sock):
h, p = sock.getpeername()
config = dict(self.protocol_config, credentials=credentials, connid="%s:%d"%(h, p),
endpoints=(sock.getsockname(), (h, p)))
return self.service().connect(
return self.service.connect(
Channel(SocketStream(sock)), config)

def _accept_method(self, sock):
Expand Down

0 comments on commit 0290e65

Please sign in to comment.