1"""Proxy classes and functions."""
2
3# Copyright (C) PyZMQ Developers
4# Distributed under the terms of the Modified BSD License.
5
6import zmq
7from zmq.devices.basedevice import Device, ThreadDevice, ProcessDevice
8
9
10class ProxyBase(object):
11    """Base class for overriding methods."""
12
13    def __init__(self, in_type, out_type, mon_type=zmq.PUB):
14
15        Device.__init__(self, in_type=in_type, out_type=out_type)
16        self.mon_type = mon_type
17        self._mon_binds = []
18        self._mon_connects = []
19        self._mon_sockopts = []
20
21    def bind_mon(self, addr):
22        """Enqueue ZMQ address for binding on mon_socket.
23
24        See zmq.Socket.bind for details.
25        """
26        self._mon_binds.append(addr)
27
28    def bind_mon_to_random_port(self, addr, *args, **kwargs):
29        """Enqueue a random port on the given interface for binding on
30        mon_socket.
31
32        See zmq.Socket.bind_to_random_port for details.
33
34        .. versionadded:: 18.0
35        """
36        port = self._reserve_random_port(addr, *args, **kwargs)
37
38        self.bind_mon('%s:%i' % (addr, port))
39
40        return port
41
42    def connect_mon(self, addr):
43        """Enqueue ZMQ address for connecting on mon_socket.
44
45        See zmq.Socket.connect for details.
46        """
47        self._mon_connects.append(addr)
48
49    def setsockopt_mon(self, opt, value):
50        """Enqueue setsockopt(opt, value) for mon_socket
51
52        See zmq.Socket.setsockopt for details.
53        """
54        self._mon_sockopts.append((opt, value))
55
56    def _setup_sockets(self):
57        ins, outs = Device._setup_sockets(self)
58        ctx = self._context
59        mons = ctx.socket(self.mon_type)
60
61        # set sockopts (must be done first, in case of zmq.IDENTITY)
62        for opt, value in self._mon_sockopts:
63            mons.setsockopt(opt, value)
64
65        for iface in self._mon_binds:
66            mons.bind(iface)
67
68        for iface in self._mon_connects:
69            mons.connect(iface)
70
71        return ins, outs, mons
72
73    def run_device(self):
74        ins, outs, mons = self._setup_sockets()
75        zmq.proxy(ins, outs, mons)
76
77
78class Proxy(ProxyBase, Device):
79    """Threadsafe Proxy object.
80
81    See zmq.devices.Device for most of the spec. This subclass adds a
82    <method>_mon version of each <method>_{in|out} method, for configuring the
83    monitor socket.
84
85    A Proxy is a 3-socket ZMQ Device that functions just like a
86    QUEUE, except each message is also sent out on the monitor socket.
87
88    A PUB socket is the most logical choice for the mon_socket, but it is not required.
89    """
90
91    pass
92
93
94class ThreadProxy(ProxyBase, ThreadDevice):
95    """Proxy in a Thread. See Proxy for more."""
96
97    pass
98
99
100class ProcessProxy(ProxyBase, ProcessDevice):
101    """Proxy in a Process. See Proxy for more."""
102
103    pass
104
105
106__all__ = [
107    'Proxy',
108    'ThreadProxy',
109    'ProcessProxy',
110]
111