from Pyro5.api import expose, Daemon fmt = '%Y-%m-%d %H:%M:%S %Z%z' @expose class Server(object): def echo(self, date): print("ECHO:") print(" [raw] ", repr(date)) if hasattr(date, "isoformat"): print(" [iso] ", date.isoformat()) return date def pytz(self): tz_nl = pytz.timezone("Europe/Amsterdam") return tz_nl.localize(datetime.datetime.now()) def dateutil(self): tz_nl = dateutil.tz.gettz("Europe/Amsterdam") return datetime.datetime.now(tz_nl) def pendulum(self): tz_nl = pendulum.now("Europe/Amsterdam") return tz_nl # main program Daemon.serveSimple({Server: "example.timezones"}, ns=False)
self.number = number self.callback = callback print("Worker %d created" % self.number) @expose @oneway def work(self, amount): print("Worker %d busy..." % self.number) time.sleep(amount) print("Worker %d done. Informing callback client." % self.number) self._pyroDaemon.unregister(self) self.callback._pyroClaimOwnership( ) # because this method may run in a different thread every time it's called self.callback.done(self.number) # invoke the callback object class CallbackServer(object): def __init__(self): self.number = 0 @expose def addworker(self, callback): self.number += 1 print("server: adding worker %d" % self.number) worker = Worker(self.number, callback) self._pyroDaemon.register(worker) # make it a Pyro object return worker Daemon.serveSimple({CallbackServer: "example.callback"})
from Pyro5.api import Daemon import excep Daemon.serveSimple({excep.TestClass: "example.exceptions"}, ns=True, verbose=True)
import logging from Pyro5.api import expose, Daemon import Pyro5.config logging.basicConfig(level=logging.DEBUG) logging.getLogger("Pyro5").setLevel(logging.DEBUG) Pyro5.config.COMMTIMEOUT = 5.0 Pyro5.config.POLLTIMEOUT = 5.0 # only used for multiplexing server class TestDisconnect(object): @expose def echo(self, arg): print("echo: ", arg) return arg Daemon.serveSimple({TestDisconnect: "example.disconnect"}, ns=False)
from Pyro5.api import expose, Daemon, config @expose class CalcServer(object): def add(self, num1, num2): print("calling add: %d, %d" % (num1, num2)) return num1 + num2 config.COMMTIMEOUT = 0.5 # the server should time out easily now Daemon.serveSimple({CalcServer: "example.autoretry"})
# for 'Thingy' we register both serialization and deserialization hooks SerializerBase.register_dict_to_class("waheeee-custom-thingy", thingy_dict_to_class) SerializerBase.register_class_to_dict(mycustomclasses.Thingy, thingy_class_to_dict) # for 'OtherThingy' we only register a deserialization hook (and for serialization depend on serpent's default behavior) SerializerBase.register_dict_to_class("mycustomclasses.OtherThingy", otherthingy_dict_to_class) # regular Pyro server stuff @expose class Server(object): def method(self, arg): print("\nmethod called, arg=", arg) response = mycustomclasses.Thingy(999) return response def othermethod(self, arg): print("\nothermethod called, arg=", arg) response = mycustomclasses.OtherThingy(999) return response Daemon.serveSimple( { Server: "example.customclasses" }, ns=False)
self.collection.discard(self) @expose @behavior(instance_mode="single") class Service(object): def __init__(self): self.resources = set() # the allocated resources def allocate(self, name): resource = Resource(name, self.resources) self.resources.add(resource) current_context.track_resource(resource) print("service: allocated resource", name, " for client", current_context.client_sock_addr) def free(self, name): resources = {r for r in self.resources if r.name == name} self.resources -= resources for r in resources: r.close() current_context.untrack_resource(r) def list(self): return [r.name for r in self.resources] with CustomDaemon() as daemon: Daemon.serveSimple({ Service: "service" }, ns=False, daemon=daemon)
@behavior(instance_mode="session") @expose class SessionboundDatabase(object): """ This pyro object will work fine when used from multiple proxies at the same time because you'll get a new instance for every new session (proxy connection) """ def __init__(self): # get the user-token from the USER annotation user_annotation = current_context.annotations["USER"] user = bytes(user_annotation).decode("utf-8") self.connection = database.connect(user) print("[%s] new instance and connection for user: %s" % (self.__class__.__name__, user)) def store(self, key, value): self.connection.store(key, value) def retrieve(self, key): return self.connection.retrieve(key) def ping(self): return "hi" Daemon.serveSimple({ SingletonDatabase: "example.usersession.singletondb", SessionboundDatabase: "example.usersession.sessiondb" })
import time from Pyro5.api import expose, Daemon @expose class Thingy(object): def multiply(self, a, b): return a * b def add(self, a, b): return a + b def divide(self, a, b): return a // b def error(self): return 1 // 0 def delay(self, seconds): time.sleep(seconds) return seconds def printmessage(self, message): print(message) return 0 Daemon.serveSimple({Thingy: "example.batched"}, ns=False)
for (n, c) in self.channels[channel]: if n == nick: self.channels[channel].remove((n, c)) break self.publish(channel, 'SERVER', '** ' + nick + ' left **') if len(self.channels[channel]) < 1: del self.channels[channel] print('REMOVED CHANNEL %s' % channel) self.nicks.remove(nick) print("%s LEFT %s" % (nick, channel)) def publish(self, channel, nick, msg): if channel not in self.channels: print('IGNORED UNKNOWN CHANNEL %s' % channel) return for (n, c) in self.channels[channel][:]: # use a copy of the list c._pyroClaimOwnership() try: c.message(nick, msg) # oneway call except Pyro5.errors.ConnectionClosedError: # connection dropped, remove the listener if it's still there # check for existence because other thread may have killed it already if (n, c) in self.channels[channel]: self.channels[channel].remove((n, c)) print('Removed dead listener %s %s' % (n, c)) Daemon.serveSimple({ ChatBox: "example.chatbox.server" })
from Pyro5.api import expose, behavior, Daemon @expose @behavior(instance_mode="single") class Warehouse(object): def __init__(self): self.contents = ["chair", "bike", "flashlight", "laptop", "couch"] def list_contents(self): return self.contents def take(self, name, item): self.contents.remove(item) print("{0} took the {1}.".format(name, item)) def store(self, name, item): self.contents.append(item) print("{0} stored the {1}.".format(name, item)) Daemon.serveSimple({Warehouse: "example.warehouse"}, ns=False)
from collections import defaultdict from Pyro5.api import behavior, expose, Daemon # note: the dispatcher doesn't know anything about the CustomData class from the customdata module! @behavior(instance_mode="single") class Dispatcher(object): def __init__(self): self.listeners = defaultdict(list) @expose def register(self, topic, listener): self.listeners[topic].append(listener) print("New listener for topic {} registered: {}".format( topic, listener._pyroUri)) @expose def process_blob(self, blob): print("Dispatching blob with name:", blob.info) listeners = self.listeners.get(blob.info, []) for listener in listeners: listener._pyroClaimOwnership( ) # because this process_blob call may run in a different thread every time it is invoked listener.process_blob(blob) Daemon.serveSimple({Dispatcher: "example.blobdispatcher"})
from Pyro5.api import expose, Daemon from thingy import Thingy @expose class Factory(object): def createSomething(self, number): # create a new item thing = Thingy(number) # connect it to the Pyro daemon to make it a Pyro object self._pyroDaemon.register(thing) # Return it. Pyro's autoproxy feature turns it into a proxy automatically. # If that feature is disabled, the object itself (a copy) is returned, # and the client won't be able to interact with the actual Pyro object here. return thing Daemon.serveSimple({Factory: "example.autoproxy"}, ns=False)
self.resultqueue = queue.Queue() def putWork(self, item): self.workqueue.put(item) def getWork(self, timeout=5): try: return self.workqueue.get(block=True, timeout=timeout) except queue.Empty: raise ValueError("no items in queue") def putResult(self, item): self.resultqueue.put(item) def getResult(self, timeout=5): try: return self.resultqueue.get(block=True, timeout=timeout) except queue.Empty: raise ValueError("no result available") def workQueueSize(self): return self.workqueue.qsize() def resultQueueSize(self): return self.resultqueue.qsize() # main program Daemon.serveSimple({DispatcherQueue: "example.distributed.dispatcher"})
return self.callcount # the number of completed calls def getconfig(self): return Pyro5.config.as_dict() def delay(self): threadname = threading.current_thread().getName() print("delay called in thread %s" % threadname) time.sleep(1) self.callcount += 1 return threadname @oneway def onewaydelay(self): threadname = threading.current_thread().getName() print("onewaydelay called in thread %s" % threadname) time.sleep(1) self.callcount += 1 # main program Pyro5.config.SERVERTYPE = "undefined" servertype = input("Servertype threaded or multiplex (t/m)?") if servertype == "t": Pyro5.config.SERVERTYPE = "thread" else: Pyro5.config.SERVERTYPE = "multiplex" Daemon.serveSimple({Server: "example.servertypes"})
class SessionInstance(object): @expose def msg(self, message): print("[%s] %s.msg: %s" % (id(self), self.__class__.__name__, message)) return id(self), self.correlation_id @classmethod def create_instance(cls): obj = cls() obj.correlation_id = current_context.correlation_id return obj @behavior(instance_mode="percall") class PercallInstance(object): @expose def msg(self, message): print("[%s] %s.msg: %s" % (id(self), self.__class__.__name__, message)) return id(self) if __name__ == "__main__": # please make sure a name server is running somewhere first. Daemon.serveSimple( { SingleInstance: "instance.single", SessionInstance: "instance.session", PercallInstance: "instance.percall" }, verbose=True)
def payCart(self, cart, name=None): receipt = [] if name: receipt.append("Receipt for %s." % name) receipt.append("Receipt Date: " + time.asctime()) total = 0.0 for item in cart.getContents(): price = self.inventory[item] total += price receipt.append("%13s %.2f" % (item, price)) receipt.append("") receipt.append("%13s %.2f" % ("total:", total)) cart.empty() return "\n".join(receipt) def leave(self, name): print("Customer %s leaves." % name) cart = self.customersInStore[name] print(" their shopping cart contains: %s" % cart.getContents()) if cart.getContents(): print(" it is not empty, they are trying to shoplift!") raise Exception("attempt to steal a full cart prevented") # delete the cart and unregister it with pyro del self.customersInStore[name] self._pyroDaemon.unregister(cart) # main program Daemon.serveSimple({Shop: "example.shop"})
import time import threading from Pyro5.api import expose, oneway, behavior, Daemon @expose @behavior("single") class Server(object): def __init__(self): self.counter = 0 @oneway def increment_oneway(self): print("oneway call executing in thread", threading.get_ident()) time.sleep(0.5) self.counter += 1 def increment(self): time.sleep(0.5) self.counter += 1 def getcount(self): return self.counter print("main thread:", threading.get_ident()) Daemon.serveSimple({Server: "example.oneway2"})
@expose class Streamer(object): def list(self): return [1, 2, 3, 4, 5, 6, 7, 8, 9] def iterator(self): return iter([1, 2, 3, 4, 5, 6, 7, 8, 9]) def generator(self): i = 1 while i < 10: yield i i += 1 def slow_generator(self): i = 1 while i < 10: time.sleep(0.5) yield i i += 1 def fibonacci(self): a, b = 0, 1 while True: yield a a, b = b, a + b Daemon.serveSimple({Streamer: "example.streamer"}, ns=False)
from Pyro5.api import behavior, expose, locate_ns, Daemon import Pyro5.config from diffiehellman import DiffieHellman Pyro5.config.SERVERTYPE = "multiplex" ns = locate_ns() @behavior(instance_mode="session") class KeyExchange(object): def __init__(self): print("New KeyExchange, initializing Diffie-Hellman") self.dh = DiffieHellman(group=14) @expose def exchange_key(self, other_public_key): print("received a public key, calculating shared secret...") self.dh.make_shared_secret_and_key(other_public_key) print("shared secret key = ", self.dh.key) return self.dh.public_key Daemon.serveSimple({KeyExchange: "example.dh.keyexchange"}, ns=True)
with futures.ThreadPoolExecutor() as pool: roundrobin_counters = cycle(all_counters.values()) tasks = [] for chunk in grouper(200, lines): tasks.append(pool.submit(self.count_chunk, next(roundrobin_counters), chunk)) # gather the results print("Collecting %d results (counted in parallel)..." % len(tasks)) totals = Counter() for task in futures.as_completed(tasks): try: totals.update(task.result()) except Pyro5.errors.CommunicationError as x: raise Pyro5.errors.PyroError("Something went wrong in the server when collecting the responses: "+str(x)) return totals if __name__ == "__main__": print("Spinning up 5 word counters, and 1 dispatcher.") config.SERVERTYPE = "thread" Daemon.serveSimple( { WordCounter(): "example.dc2.wordcount.1", WordCounter(): "example.dc2.wordcount.2", WordCounter(): "example.dc2.wordcount.3", WordCounter(): "example.dc2.wordcount.4", WordCounter(): "example.dc2.wordcount.5", Dispatcher: "example.dc2.dispatcher" }, verbose=False )
import Pyro5.config # Pyro5.config.COMMTIMEOUT=2 class Testclass(object): @expose def transfer(self, data): if Pyro5.config.SERIALIZER == "serpent" and type(data) is dict: data = serpent.tobytes(data) # in case of serpent encoded bytes print("received %d bytes" % len(data)) return len(data) @expose def download_chunks(self, size): print("client requests a 'streaming' download of %d bytes" % size) data = bytearray(size) i = 0 chunksize = 200000 print(" using chunks of size", chunksize) while i < size: yield data[i:i + chunksize] i += chunksize Daemon.serveSimple({Testclass: "example.hugetransfer"}, host=Pyro5.socketutil.get_ip_address("localhost", workaround127=True), ns=False, verbose=True)
self.sub = {"name": "value"} self.value = 42 self._value = 123 self.__value = 999 def __dunder__(self): return "yep" def __len__(self): return 200 def getValue(self): return self.value @property def prop_value(self): return self.value @prop_value.setter def prop_value(self, value): self.value = value @property def prop_sub(self): return self.sub Daemon.serveSimple({ Thingy: "example.attributes" }, ns=False)