Source code for rpyc.core.service

"""Services are the heart of RPyC: each side of the connection exposes a *service*,which define the capabilities available to the other side.Note that the services by both parties need not be symmetric, e.g., one side mayexposed *service A*, while the other may expose *service B*. As long as the twocan interoperate, you're good to go."""fromfunctoolsimportpartialfromrpyc.libimporthybridmethodfromrpyc.lib.compatimportexecute,is_py_3kfromrpyc.core.protocolimportConnection

[docs]@classmethoddefget_service_aliases(cls):"""returns a list of the aliases of this service"""ifcls.ALIASES:returntuple(str(n).upper()fornincls.ALIASES)name=cls.__name__.upper()ifname.endswith("SERVICE"):name=name[:-7]return(name,)

[docs]@classmethoddefget_service_name(cls):"""returns the canonical name of the service (which is its first alias)"""returncls.get_service_aliases()[0]

exposed_get_service_aliases=get_service_aliasesexposed_get_service_name=get_service_name@hybridmethoddef_connect(self,channel,config={}):"""Setup a connection via the given channel."""ifisinstance(self,type):# autovivify if accessed as class methodself=self()# Note that we are here passing in `self` as root object for backward# compatibility and convenience. You could pass in a different root if# you wanted:conn=self._protocol(self,channel,config)self.on_connect(conn)returnconn

[docs]classVoidService(Service):"""void service - an do-nothing service"""__slots__=()

[docs]classModuleNamespace(object):"""used by the :class:`SlaveService` to implement the magical 'module namespace'"""__slots__=["__getmodule","__cache","__weakref__"]def__init__(self,getmodule):self.__getmodule=getmoduleself.__cache={}def__contains__(self,name):try:self[name]exceptImportError:returnFalseelse:returnTruedef__getitem__(self,name):iftype(name)istuple:name=".".join(name)ifnamenotinself.__cache:self.__cache[name]=self.__getmodule(name)returnself.__cache[name]def__getattr__(self,name):returnself[name]

classSlave(object):__slots__=["_conn","namespace"]def__init__(self):self._conn=Noneself.namespace={}defexecute(self,text):"""execute arbitrary code (using ``exec``)"""execute(text,self.namespace)defeval(self,text):"""evaluate arbitrary code (using ``eval``)"""returneval(text,self.namespace)defgetmodule(self,name):"""imports an arbitrary module"""return__import__(name,None,None,"*")defgetconn(self):"""returns the local connection instance to the other side"""returnself._conn

[docs]classSlaveService(Slave,Service):"""The SlaveService allows the other side to perform arbitrary imports and execution arbitrary code on the server. This is provided for compatibility with the classic RPyC (2.6) modus operandi. This service is very useful in local, secure networks, but it exposes a **major security risk** otherwise."""__slots__=()

[docs]classFakeSlaveService(VoidService):"""VoidService that can be used for connecting to peers that operate a :class:`MasterService`, :class:`ClassicService`, or the old ``SlaveService`` (pre v3.5) without exposing any functionality to them."""__slots__=()exposed_namespace=Noneexposed_execute=Noneexposed_eval=Noneexposed_getmodule=Noneexposed_getconn=None

[docs]classMasterService(Service):"""Peer for a new-style (>=v3.5) :class:`SlaveService`. Use this service if you want to connect to a ``SlaveService`` without exposing any functionality to them."""__slots__=()

[docs]classClassicService(MasterService,SlaveService):"""Full duplex master/slave service, i.e. both parties have full control over the other. Must be used by both parties."""__slots__=()

[docs]classClassicClient(MasterService,FakeSlaveService):"""MasterService that can be used for connecting to peers that operate a :class:`MasterService`, :class:`ClassicService` without exposing any functionality to them."""__slots__=()