pull in additional changes from 2.0 branch.
[monitor.git] / monitor / Rpyc / NetProxy.py
diff --git a/monitor/Rpyc/NetProxy.py b/monitor/Rpyc/NetProxy.py
new file mode 100644 (file)
index 0000000..96ed53e
--- /dev/null
@@ -0,0 +1,119 @@
+from Lib import ImmDict\r
+\r
+\r
+def fully_dynamic_metaclass(name, bases, dict):\r
+    """\r
+    a meta class that enables special methods to be accessed like regular names \r
+    (via __getattr__), like it used to be in old-style classes.\r
+    """\r
+\r
+    special_methods = [\r
+        "__hash__", "__len__", "__iter__", "next", "__reversed__",\r
+        "__add__", "__iadd__", "__radd__", "__sub__", "__isub__", "__rsub__", "__mul__",\r
+        "__imul__", "__rmul__", "__div__", "__idiv__", "__rdiv__", "__truediv__", \r
+        "__itruediv__", "__rtruediv__",  "__floordiv__", "__ifloordiv__", "__rfloorfiv__", \r
+        "__pow__", "__ipow__", "__rpow__", "__lshift__", "__ilshift__", "__rlshift__",\r
+        "__rshift__", "__irshift__", "__rrshift__", "__and__", "__iand__", "__rand__",\r
+        "__or__", "__ior__", "__ror__", "__xor__", "__ixor__", "__rxor__", "__mod__", \r
+        "__imod__", "__rmod__", "__divmod__", "__idivmod__", "__rdivmod__", "__pos__", \r
+        "__neg__", "__int__", "__float__", "__long__", "__oct__", "__hex__", "__coerce__",\r
+        "__eq__", "__ne__", "__le__", "__ge__", "__lt__", "__gt__", "__cmp__",\r
+    ]\r
+    \r
+    # i added '__class__' to the special attributes, but it broke some things \r
+    # (like dir), so we'll have to live without it\r
+    special_attributes = ["__doc__", "__module__"] \r
+\r
+    def make_method(name):\r
+        def caller(self, *a, **k):\r
+            return self.__getattr__(name)(*a, **k)\r
+        return caller\r
+\r
+    def make_property(name):\r
+        def getter(self):\r
+            return self.__getattr__(name)\r
+        def setter(self, value):\r
+            self.__setattr__(name, value)\r
+        def deller(self):\r
+            self.__delattr__(name)\r
+        return property(getter, setter, deller)\r
+\r
+    classdict = {}\r
+    for sn in special_methods:\r
+        classdict[sn] = make_method(sn)\r
+    classdict.update(dict)\r
+    for sa in special_attributes:\r
+        classdict[sa] = make_property(sa)\r
+    return type(name, bases, classdict)\r
+\r
+class NetProxy(object):\r
+    """NetProxy - convey local operations to the remote object. this is an abstract class"""\r
+    __metaclass__ = fully_dynamic_metaclass\r
+    \r
+    def __init__(self, conn, oid):\r
+        self.__dict__["____conn"] = conn\r
+        self.__dict__["____oid"] = oid\r
+\r
+    def __request__(self, handler, *args):\r
+        raise NotImplementedError()\r
+\r
+    def __call__(self, *args, **kwargs):\r
+        return self.__request__("handle_call", args, ImmDict(kwargs))\r
+\r
+    def __delattr__(self, *args):\r
+        return self.__request__("handle_delattr", *args)\r
+    def __getattr__(self, *args):\r
+        return self.__request__("handle_getattr", *args)\r
+    def __setattr__(self, *args):\r
+        return self.__request__("handle_setattr", *args)\r
+    \r
+    def __delitem__(self, *args):\r
+        return self.__request__("handle_delitem", *args)\r
+    def __getitem__(self, *args):\r
+        return self.__request__("handle_getitem", *args)\r
+    def __setitem__(self, *args):\r
+        return self.__request__("handle_setitem", *args)\r
+    \r
+    # special cases\r
+    def __repr__(self, *args):\r
+        return self.__request__("handle_repr", *args)\r
+    def __str__(self, *args):\r
+        return self.__request__("handle_str", *args)\r
+    def __nonzero__(self, *args):\r
+        return self.__request__("handle_bool", *args)\r
+\r
+class NetProxyWrapper(NetProxy):\r
+    """a netproxy that wraps an inner netproxy"""\r
+    __doc__ = NetProxy.__doc__\r
+\r
+    def __init__(self, proxy):\r
+        NetProxy.__init__(self, proxy.__dict__["____conn"], proxy.__dict__["____oid"])\r
+        # we must keep the original proxy alive\r
+        self.__dict__["____original_proxy"] = proxy \r
+\r
+def _dummy_callback(*args, **kw):\r
+    pass\r
+\r
+class SyncNetProxy(NetProxy):\r
+    """the default, synchronous netproxy"""\r
+    __doc__ = NetProxy.__doc__\r
+\r
+    def __init__(self, conn, oid):\r
+        NetProxy.__init__(self, conn, oid)\r
+        self.__dict__["____conn"].sync_request("handle_incref", self.__dict__["____oid"])\r
+\r
+    def __del__(self):\r
+        try:\r
+            # decref'ing is done asynchronously, because we dont need to wait for the remote \r
+            # object to die. moreover, we dont care if it fails, because that would mean the \r
+            # connection is broken, so the remote object is already dead\r
+            self.__dict__["____conn"].async_request(_dummy_callback, "handle_decref", self.__dict__["____oid"])\r
+        except:\r
+            pass\r
+    \r
+    def __request__(self, handler, *args):\r
+        return self.__dict__["____conn"].sync_request(handler, self.__dict__["____oid"], *args)\r
+\r
+\r
+\r
+\r