@@ -28,16 +28,29 @@ class Service:
2828 >>> )
2929
3030 For the class implementing the methods of a specific varlink interface
31- a decorator is used:
31+ the ``@service.interface()`` decorator is used. The argument is a varlink
32+ interface name, **not** a Python class. The decorator loads the file
33+ ``{name}.varlink`` from the ``interface_dir`` given to the Service constructor.
34+ For example, ``@service.interface('com.redhat.system.accounts')`` loads
35+ ``com.redhat.system.accounts.varlink`` from ``interface_dir``:
3236
3337 >>> @service.interface('com.redhat.system.accounts')
3438 >>> class Accounts:
35- >>> pass
39+ >>> def GetAccounts(self):
40+ >>> return {"accounts": []}
3641
37- The varlink file corresponding to this interface is loaded from the 'interface_dir'
38- specified in the constructor of the Service. It has to end in '.varlink'.
42+ The methods defined on the decorated class directly implement the varlink
43+ interface methods. Each method receives the varlink call parameters as
44+ keyword arguments and must return a dict matching the method's return type.
3945
40- Use a :class:`RequestHandler` with your Service object and run a :class:`Server` with it.
46+ To wire a Service to a network server, create a :class:`RequestHandler` subclass
47+ and set its ``service`` class variable to your Service instance:
48+
49+ >>> class ServiceRequestHandler(varlink.RequestHandler):
50+ >>> service = service
51+ >>>
52+ >>> server = varlink.ThreadingServer("unix:@example", ServiceRequestHandler)
53+ >>> server.serve_forever()
4154
4255 If you want to use your own server with the Service object, split the incoming stream
4356 for every null byte and feed it to the :meth:`Service.handle` method.
@@ -275,6 +288,22 @@ def _set_interface(self, filename, interface_class):
275288 return interface_class
276289
277290 def interface (self , filename ):
291+ """Decorator that registers a class as the handler for a varlink interface.
292+
293+ :param filename: A varlink interface name (e.g. ``'com.example.service'``).
294+ The file ``{filename}.varlink`` is loaded from the ``interface_dir`` given
295+ to the Service constructor. This must be an interface name or a file path,
296+ **not** a Python class or type.
297+
298+ Example::
299+
300+ @service.interface('com.example.service')
301+ class Example:
302+ def Echo(self, message):
303+ return {"message": message}
304+
305+ """
306+
278307 def decorator (interface_class ):
279308 self ._add_interface (filename , interface_class ())
280309 return interface_class
@@ -325,8 +354,17 @@ def get_listen_fd() -> Union[int, None]:
325354class RequestHandler (StreamRequestHandler ):
326355 """Varlink request handler
327356
328- To use as an argument for the VarlinkServer constructor.
329- Instantiate your own class and set the class variable service to your global :class:`Service` object.
357+ Subclass this and set the ``service`` class variable to your :class:`Service` instance.
358+ Then pass your subclass to a :class:`Server` (or :class:`ThreadingServer`) constructor::
359+
360+ class ServiceRequestHandler(varlink.RequestHandler):
361+ service = service # required class variable
362+
363+ server = varlink.ThreadingServer(address, ServiceRequestHandler)
364+ server.serve_forever()
365+
366+ The ``service`` class variable is **required**; without it, incoming requests cannot
367+ be dispatched.
330368 """
331369
332370 service : Optional [Service ] = None
@@ -541,10 +579,10 @@ def __exit__(self, *args):
541579
542580
543581class ThreadingServer (ThreadingMixIn , Server ):
544- pass
582+ """Multi-threaded varlink server that handles each connection in a new thread."""
545583
546584
547585if hasattr (os , "fork" ):
548586
549587 class ForkingServer (ForkingMixIn , Server ):
550- pass
588+ """Multi-process varlink server that forks for each connection (Unix/Linux only)."""
0 commit comments