-
-
Save anonymous/b76aa36a4a627c038142 to your computer and use it in GitHub Desktop.
comnet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# -*- coding: utf-8 -*- | |
import socket | |
import time | |
import sys | |
count = range(100000) | |
letter = str(sys.argv[1]) | |
print(letter) | |
register = bytes(':{0}:control::register:{0}\r\n.\r\n'.format(letter), 'UTF-8') | |
pong = bytes(':{0}:{0}:alarm:ping\r\n.\r\n'.format(letter), 'UTF-8') | |
s = socket.socket() | |
s.connect(('127.0.0.1', 8081)) | |
s.send(register) | |
values = [] | |
for i in count: | |
time.sleep(0) | |
start = time.time() | |
s.send(pong) | |
s.recv(1024) | |
end = time.time() | |
diff = start - end | |
print(('time:', diff)) | |
values.append(diff) | |
i = 0 | |
for var in values: | |
i += var | |
average = i / len(values) #seconds | |
miliseconds = average*1000 | |
print(('average: ', miliseconds, 'ms')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import socket | |
import sys | |
letter = str(sys.argv[1]) | |
print(letter) | |
register = bytes(':{0}:control::register:{0}\r\n.\r\n'.format(letter), 'UTF-8') | |
pong = bytes(':{0}:{0}:walnut:pong\r\n.\r\n'.format(letter), 'UTF-8') | |
s = socket.socket() | |
s.connect(('127.0.0.1', 8081)) | |
s.send(register) | |
while True: | |
s.recv(1024) | |
s.send(pong) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pyuv | |
import socket | |
import local | |
import protocol | |
from message import Message | |
class Connection(pyuv.TCP): | |
"""class which represents single connection, can be useful""" | |
terminator = protocol.message_terminator | |
def __init__(self, server): | |
"""init, shall we?""" | |
self.ibuffer = "" | |
self._callback = lambda x: None | |
self._error_callback = lambda: None | |
super(Connection, self).__init__(server.loop) | |
def setCallback(self, callback=None): | |
""" sets the connection callback on incoming message""" | |
if callback is not None: | |
self._callback = callback | |
else: | |
self._callback = lambda x: None | |
def setErrorCallback(self, callback=None): | |
""" sets the connection callback on incoming message""" | |
if callback is not None: | |
self._error_callback = callback | |
else: | |
self._error_callback = lambda: None | |
def startup(self): | |
""" stars read incoming data""" | |
self.start_read(self.on_read) | |
def on_read(self, client, data, error): | |
""" everytime the reading starts!""" | |
if data is None: | |
self._error_callback() | |
return | |
data = data.decode("UTF-8") | |
searched = self.ibuffer[:-len(self.terminator)] + data | |
while True: | |
splitted = searched.split(self.terminator, 1) | |
if len(splitted) == 2: | |
self.ibuffer += splitted[0] | |
#print(("comnet","recv" ,self.ibuffer)) | |
self._callback(self.ibuffer) | |
self.ibuffer = "" | |
searched = data = splitted[1] | |
else: | |
self.ibuffer += data | |
break | |
def displace(self, message): | |
""" displaces the message""" | |
#print(("comnet", "send", str(message))) | |
self.write(bytes(str(message) + self.terminator, "UTF-8")) | |
class Server(pyuv.TCP): | |
"""basic class for handling comnets server""" | |
def __init__(self, addr, manager, loop): | |
""" we innit it, don't we? also adding host and port is not bad""" | |
super(Server, self).__init__(loop) | |
self.manager = manager | |
self.ip, self.port = addr | |
self.bind(addr) | |
self.shakers = [] | |
self.conteiners = {} | |
self.listen(self.handle_accept) | |
def dial_connection(self, ip): | |
""" creates new connection and returns it""" | |
connection = Connection(self) | |
addr = (ip, self.port) | |
def after_dial(tcp_handle, error): | |
self.create_handshaker(tcp_handle) | |
connection.connect(addr, after_dial) | |
def handle_accept(self, server, error): | |
"""method to accept new connection""" | |
connection = Connection(self) | |
self.accept(connection) | |
self.create_handshaker(connection) | |
def create_handshaker(self, connection): | |
shaker = Handshaker(connection, | |
self.handshake_done, | |
self.handshake_error) | |
self.shakers.append(shaker) | |
def handshake_error(self, shaker): | |
shaker.stop_read() | |
self.shakers.remove(shaker) | |
def handshake_done(self, shaker): | |
""" after handshake is done, extracts connection and name from | |
Handshaker, removes it and creates Communicator object """ | |
print(("comnet", "handshaker", "handshaking done, moving connection" | |
"to Communicator object")) | |
self.shakers.remove(shaker) | |
connection = shaker.connection | |
name = shaker.name | |
try: | |
conteiner = self.conteiners[name] | |
except KeyError: | |
conteiner = self.manager.create_conteiner() | |
self.conteiners[name] = conteiner | |
com = Communicator(connection) | |
conteiner.add_communicator(com) | |
class Point(): | |
""" Class to manage connections to different points by the context """ | |
def __init__(self, server, manager): | |
""" we need object with actual connection""" | |
self.server = server | |
self.conteiners = server.conteiners | |
self.manager = manager | |
def displace(self, message): | |
self.conteiners[message.target_point].displace(message) | |
def on_read(self, conteiner, message): | |
if message.target_point == protocol.point_name: | |
self.manager.displace_to_localhost(message) | |
else: | |
self.displace(message) | |
def remove_conteiner(self, conteiner): | |
for name, con in self.conteiners.items(): | |
if con == conteiner: | |
todel = name | |
del self.conteiners[todel] | |
class Conteiner(): | |
def __init__(self, point): | |
self.communicators = [] | |
self.point = point | |
def add_communicator(self, com): | |
self.communicators.append(com) | |
com.setCallback(self.on_read) | |
com.setErrorCallback(self.on_error) | |
def displace(self, message): | |
self.communicators[0].displace(message) | |
def on_error(self, com): | |
self.communicators.remove(com) | |
if len(self.communicators) == 0: | |
self.point.remove_conteiner(self) | |
def on_read(self, message): | |
self.point.on_read(self, message) | |
class Handshaker(): | |
""" executes handshaking process on given connection """ | |
def __init__(self, connection, callback, error_callback): | |
""" needs the connection on which handshaking should be done and | |
callback to call after its done: | |
callback(handshaker)""" | |
self.connection = connection | |
self.error_callback = error_callback | |
self.callback = callback | |
self.protocol = protocol.Handshaker(self) | |
self.tasks = self.protocol.tasks[::-1] | |
connection.setCallback(self.recv) | |
self.make_shake() | |
self.connection.startup() | |
def make_shake(self): | |
if len(self.tasks) == 0: | |
self.callback(self) | |
return | |
name, send, recv = self.tasks.pop() | |
self.connection.displace(name + ":" + send()) | |
self.wait_for = name, recv | |
def recv(self, data): | |
l = data.split(":", 1) | |
name, recv = self.wait_for | |
if len(l) < 2: | |
self.connection.displace("error: bad syntax") | |
return | |
if l[0] not in ("error", name): | |
self.connection.displace("error: bad item") | |
return | |
if l[0] == "error": | |
self.error_callback(self) | |
elif l[0] == name: | |
try: | |
recv(l[1]) | |
except protocol.protocolError as err: | |
mes = "error:{0}:{1}".format(err.string_name, str(err)) | |
self.connection.displace(mes) | |
self.error_callback(self) | |
else: | |
self.make_shake() | |
else: | |
print("shit happend") | |
class Communicator(): | |
def __init__(self, con): | |
self.connection = con | |
self._callback = lambda x: None | |
self._error_callback = lambda: None | |
self.connection.setCallback(self.on_read) | |
self.connection.setErrorCallback(self.on_error) | |
def displace(self, message): | |
self.connection.displace(message) | |
def on_read(self, string): | |
message = Message(protocol.decode_message(string), self) | |
self._callback(message) | |
def on_error(self): | |
self._error_callback(self) | |
def setErrorCallback(self, callback=None): | |
""" sets the connection callback on incoming message""" | |
if callback is not None: | |
self._error_callback = callback | |
else: | |
self._error_callback = lambda: None | |
def setCallback(self, callback=None): | |
""" sets the connection callback on incoming message""" | |
if callback is not None: | |
self._callback = callback | |
else: | |
self._callback = lambda x: None | |
class Manager(): | |
""" class used to manage the comnet server""" | |
def __init__(self, addr, local_addr, broadcast_addr, loop): | |
""" init shoudln't we?'""" | |
self.server = Server(addr, self, loop) | |
self.point = Point(self.server, self) | |
self.broadcaster = Broadcaster(broadcast_addr, loop, self) | |
self.local = local.Manager(local_addr, self, loop) | |
def dial_connection(self, ip, name): | |
""" dials connection to specified adress and name""" | |
self.server.dial_connection(ip) | |
def allow_connect(self, name): | |
""" allows specified point to connect via broadcaster""" | |
self.broadcaster.allow_connect(name) | |
def displace_to_comnet(self, message): | |
""" sends message to comnet""" | |
self.point.displace(message) | |
def displace_to_localhost(self, message): | |
self.local.displace_to_localhost(message) | |
def create_conteiner(self): | |
return Conteiner(self.point) | |
class Broadcaster: | |
""" this is little bit tricky, I couldn't find a way to force pyuv bindigs | |
to crate broadcaster ... maybe it is possible, but I coudln't find a | |
way to do it, so here is version where I use nonblocking standart socket | |
combined with libuv's Timer object to create "async" behavior, the | |
delay before this class is able to detect incoming broadcasting | |
shoudln't be so much deal anyway and for outgoing it's the same, on the | |
other hand for effectivity there will be two timers for that purpose, | |
one for incoming and one for outgoing""" | |
def __init__(self, addr, loop, manager): | |
"""we need the loop and adress on which we should work""" | |
self.ip, self.port = addr | |
self.manager = manager | |
self.ignored = [] | |
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) | |
self.socket.setblocking(0) | |
self.socket.bind(addr) | |
self.outgoing_timer = pyuv.Timer(loop) | |
self.outgoing_timer.start(self.outgoing, 1, 1) | |
self.incoming_timer = pyuv.Timer(loop) | |
self.incoming_timer.start(self.incoming, 1, 1) | |
def outgoing(self, timer_handle): | |
""" method designed to broadcast the point informations""" | |
items = ("comnet", socket.gethostname()) | |
mes = ":".join(items) | |
self.socket.sendto(bytes(mes, "UTF-8"), ('<broadcast>', self.port)) | |
def incoming(self, timer_handle): | |
""" receives incoming broadcasts""" | |
try: | |
mes, addr = self.socket.recvfrom(8192) | |
ip, port = addr | |
items = mes.decode("UTF-8").split(":", 1) | |
if len(items) == 2 and items[0] == "comnet": | |
if items[1] not in self.ignored: | |
self.manager.dial_connection(ip, items[1]) | |
self.ignored.append(items[1]) | |
except socket.error: | |
# TODO: check if it's only error when recvfrom is empty | |
pass | |
def allow_connect(self, name): | |
""" allows connection of name""" | |
self.ignored.remove(name) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 *-* | |
import pyuv | |
import control | |
from message import Message, Error_message, Empty_error_message | |
import protocol | |
""" | |
message syntax: | |
<source point>:<source channel>:<target channel>:<target point>:<message> | |
""" | |
class rightsError(Exception): | |
"""class used to when problem with rights""" | |
class noRegisteredError(Exception): | |
"""used when channel is notRegistered""" | |
class alreadyRegisteredError(Exception): | |
"""used when channel is already registered""" | |
class messageLengthError(Exception): | |
"""used when incoming message is too long""" | |
class channelLockedError(Exception): | |
"""used when channel is locked""" | |
class Connection(pyuv.TCP): | |
"""class which represents single connection, can be useful""" | |
maxMessageLength = 16384 | |
terminator = protocol.message_terminator | |
def __init__(self, server, manager): | |
"""init, shall we?""" | |
super(Connection, self).__init__(server.loop) | |
self.ibuffer = "" | |
self.manager = manager | |
def on_read(self, client, data, error): | |
""" everytime the reading starts!""" | |
if data is None: | |
self.manager.remove_connection(self) | |
return | |
data = data.decode("UTF-8") | |
searched = self.ibuffer[:-len(self.terminator)] + data | |
while True: | |
splitted = searched.split(self.terminator, 1) | |
if len(splitted) == 2: | |
self.ibuffer += splitted[0] | |
self.found_terminator() | |
searched = data = splitted[1] | |
else: | |
self.ibuffer += data | |
break | |
def displace(self, message): | |
"""little moddification to standart push""" | |
#print(("local", "sends", str(message))) | |
self.write(bytes(str(message) + self.terminator, "UTF-8")) | |
def check_max_length(self, string): | |
"""checks maximal length of one message""" | |
if len(string) > self.maxMessageLength: | |
string = ("Message is too long, please make it" | |
" shorter, max length is {0}") | |
raise messageLengthError(string.format(self.maxMessageLength)) | |
def create_message_from_string(self, string): | |
"""create message object from the string""" | |
return Message(protocol.decode_message(string), self) | |
def found_terminator(self): | |
"""found end of message""" | |
string = self.ibuffer.strip() | |
self.ibuffer = "" | |
try: | |
self.check_max_length(string) | |
except messageLengthError as error: | |
error = Empty_error_message(str(error)) | |
self.displace(error) | |
return | |
try: | |
message = self.create_message_from_string(string) | |
except protocol.messageSyntaxError as error: | |
error = Empty_error_message(str(error)) | |
self.displace(error) | |
self.manager.displace_from_local(message) | |
class Server(pyuv.TCP): | |
"""basic class for handling local connecitons server""" | |
connections = [] | |
def __init__(self, addr, manager, loop): | |
""" we innit it, don't we? also adding host and port is not bad""" | |
super(Server, self).__init__(loop) | |
self.bind(addr) | |
self.listen(self.handle_accept) | |
self.manager = manager | |
def handle_accept(self, server, error): | |
"""method to accept new connection""" | |
connection = Connection(self, self.manager) | |
self.accept(connection) | |
connection.start_read(connection.on_read) | |
self.connections.append(connection) | |
class Manager(): | |
"""class to manage the local server""" | |
def __init__(self, addr, comnet, loop): | |
"""init shoudln't we? local is object which represents local | |
connections and comnet should represent connection to the comnet'""" | |
self.channels = {} | |
self.loop = loop | |
self.comnet = comnet | |
self.server = Server(addr, self, loop) | |
self.control = control.control(self, comnet) | |
self.register('control', self.control) | |
def displace_from_local(self, message): | |
""" used to displace messages coming from clients""" | |
try: | |
self.check_source_channel_rights(message) | |
except (rightsError, noRegisteredError) as error: | |
error = Error_message(message, str(error)) | |
message.source.displace(error) | |
return | |
# let's decide the direction, comnet or localhost? | |
if message.target_point in ("", "localhost"): | |
self.displace_to_localhost(message) | |
else: | |
self.displace_to_comnet(message) | |
def displace_to_localhost(self, message): | |
"""sends message to client connection""" | |
try: | |
self.check_if_channel_exists(message.target_channel) | |
except noRegisteredError: | |
error = Error_message(message, "target_channel is not registered!") | |
message.source.displace(error) | |
return | |
try: | |
self.check_if_locked(message.target_channel) | |
except channelLockedError: | |
error = Error_message(message, "targe_channel is locked!") | |
message.source.displace(error) | |
return | |
self.channels[message.target_channel].connection.displace(message) | |
def displace_to_comnet(self, message): | |
""" sends message from local object to comnet object""" | |
message.source_point = protocol.point_name | |
self.comnet.displace_to_comnet(message) | |
def check_if_locked(self, channel): | |
"""raises channelLockedError if the channel is locked""" | |
if self.channels[channel].lock: | |
raise channelLockedError | |
def check_if_channel_exists(self, channel): | |
"""checks if the <channel> exists""" | |
try: | |
self.channels[channel] | |
except KeyError: | |
raise noRegisteredError | |
def register(self, name, connection): | |
"""registers the channel for specific connection, | |
TRUE if succeed, FALSE if taken""" | |
try: | |
self.channels[name] | |
except KeyError: | |
channel = Channel(name) | |
channel.connection = connection | |
self.channels[name] = channel | |
print("channel registered") | |
return name | |
else: | |
print("channel failed to register") | |
raise alreadyRegisteredError | |
def check_source_channel_rights(self, message): | |
"""method to check if message can be sent by connection""" | |
try: | |
connection = self.channels[message.source_channel].connection | |
if connection == message.source: | |
return message | |
else: | |
if message.target_channel == "control": | |
print("targeted channel is system 'control' channel") | |
return message | |
print("Channel is owned by different connection") | |
message = "Your source_channel is not yours!" | |
raise rightsError(message) | |
except KeyError: | |
if message.target_channel == "control": | |
print("targeted channel is system 'control' channel") | |
return message | |
print("Channel is not owned by the connection or any") | |
message = "Your source_channel is not yours and registered" | |
raise noRegisteredError(message) | |
def lock_channel(self, message, name): | |
""" locks channel, needs the source message to confirm rights""" | |
try: | |
channel = self.channels[name] | |
except KeyError: | |
raise noRegisteredError | |
return | |
if message.source == channel.connection: | |
channel.lock = True | |
else: | |
raise rightsError | |
return | |
class Channel(): | |
"""class represents channel in local comnet server""" | |
name = "" | |
connection = None | |
lock = False | |
def __init__(self, name): | |
"""init!""" | |
self.name = name |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment