from collections import Iterable from simpy import Store from .buffer import Buffer from .core import TickProcess def NodeFactory(router, **kwargs): def factory(network, nid): return Node(network, nid, router=router, **kwargs) return factory class Node(TickProcess): '''''' def __init__(self, network, nid, buffer_size=None, tick_time=1, router=None): '''''' super().__init__(tick_time) self.env = network.env self.network = network self.id = nid self.bandwidth = float('inf') self.buffer = Buffer(self.env, capacity=buffer_size) if router is None: router = routers['direct'] self.router = router(self) self.start(self.env) self.transfer_queue = Store(self.env) def route_packets(self): packets_to_delete = [] for packet in self.buffer: # remove expired packets from buffer if packet.expired(self.env.now): packets_to_delete.append(packet) continue # ask the router what to do targets, reason, delete = self.router(packet) # check if there are targets to send to if targets is None: continue # allow for targets to be iterable or single item if not isinstance(targets, Iterable): targets = [targets] # add the packet to the transfer queue self.transfer_queue.put((packet, targets, reason)) #self.send(targets, packet, reason) # if the router requested deletion from the buffer do it if delete: packets_to_delete.append(packet) for packet in packets_to_delete: self.buffer.remove(packet) def process(self, **kwargs): '''''' while True: packet, targets, reason = yield self.transfer_queue.get() # simulate transfer delay of packet delay = packet.size / self.bandwidth yield self.env.timeout(delay) success = [] # simulates broadcast for target in targets: # try sending packet if self.network.send_link(self, target, packet): success.append(target) self.router.on_send_success(target, packet) else: self.router.on_send_failure(target, packet) packet.send(self, success, reason=reason) def recv(self, packet): if packet.destination == self: packet.recv() else: self.buffer.add(packet) @property def community(self): return self.network.community[self] def connected_to(self, other): return self.network[self][other]['state'] @property def links(self): ''' Returns a list of connected links. ''' return { met: data for met, data in self.network[self].items() if self.connected_to(met) } def __repr__(self): return 'Node(id={})'.format(self.id)