From 4b5a1fdc1be09bbc817cb47f4bd378325cd0d71f Mon Sep 17 00:00:00 2001 From: "locklainn.linden" Date: Thu, 31 Jul 2008 20:58:51 +0000 Subject: [PATCH] added an llsd builder and more stubs for the message system, now only to implement it --- pyogp/lib/base/message/circuitdata.py | 4 +- pyogp/lib/base/message/interfaces.py | 61 ++++++++++++++++++ pyogp/lib/base/message/llsd_sender.py | 1 + .../lib/base/message/message_llsd_builder.py | 60 +++++++++++++++++ pyogp/lib/base/message/message_system.py | 32 ++++++++++ pyogp/lib/base/message/net.py | 13 +++- pyogp/lib/base/tests/test_llsd_builder.py | 64 +++++++++++++++++++ 7 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 pyogp/lib/base/message/interfaces.py create mode 100644 pyogp/lib/base/message/llsd_sender.py create mode 100644 pyogp/lib/base/message/message_llsd_builder.py create mode 100644 pyogp/lib/base/tests/test_llsd_builder.py diff --git a/pyogp/lib/base/message/circuitdata.py b/pyogp/lib/base/message/circuitdata.py index d22cb15..075416b 100644 --- a/pyogp/lib/base/message/circuitdata.py +++ b/pyogp/lib/base/message/circuitdata.py @@ -14,10 +14,10 @@ class Circuit(object): """ Some statistics things we may need: bytes/packets in, bytes/packets out, unacked packet count/bytes, acked packet count/bytes""" - def __init__(self, host, circuit_code, secure_session_id): + def __init__(self, host, circuit_code, remote_session_id): self.host = host self.circuit_code = circuit_code - self.secure_session_id = secure_session_id + self.session_id = remote_session_id self.is_alive = True self.is_blocked = False self.allow_timeout = True diff --git a/pyogp/lib/base/message/interfaces.py b/pyogp/lib/base/message/interfaces.py new file mode 100644 index 0000000..917e9d6 --- /dev/null +++ b/pyogp/lib/base/message/interfaces.py @@ -0,0 +1,61 @@ +from zope.interface import Interface, Attribute + +class IMessageData(Interface): + """base interface for data that can be serialized to be sent over + a network, or deserialized from networked received data. """ + name = Attribute("""name of the message""") + size = Attribute("""size of the message""") + block_map = Attribute("""map of the blocks for the message""") + + def add_block(block): + """ adds a given block to the message """ + def get_block(block_name): + """ gets one of the message's blocks """ + + def add_data(block_name, var_name, data, data_size): + """ adds data to one of the message's blocks """ + +class IMessageBuilder(Interface): + """base interface for a message builder""" + current_msg = Attribute("""the message built/being built""") + + def build_message(): + """ returns the message and its size in serialized form. """ + + def new_message(message_name): + """ creates a new message that will be used to build into. """ + + def next_block(block_name): + """ sets the next block of the current message that we will be + adding data to. """ + #NOTE: might be helpful to have a way to have this method mixed + #with the add_data method. It IS Python btw. + + def add_data(var_name, data, data_type): + """ adds data to the current block of message being built """ + +class IMessageReader(Interface): + """base interface for a message builder""" + current_msg = Attribute("""message read/being read""") + + def validate_message(message_buffer, buffer_size): + """ makes sure the message is a valid message that can be read """ + + def read_message(message_buffer): + """ reads the message and parses its data """ + + def get_data(block_name, var_name, data_type, block_number = 0): + """ gets data from a block in the message """ + + def clear_message(): + """ clears the message being read """ + +""" +Due to the fact that LLSD can be sent multiple different ways, we have can +have different types of senders for an LLSD message. We can send to +eventqueue, http, or to capabilities. There should then be something that +maps destination (host) to a sender type. Sending an llsd message is then +delgated to the sender, rather than sent directly by the messaging system. +""" +class HTTPSender(Interface): + pass diff --git a/pyogp/lib/base/message/llsd_sender.py b/pyogp/lib/base/message/llsd_sender.py new file mode 100644 index 0000000..f90d588 --- /dev/null +++ b/pyogp/lib/base/message/llsd_sender.py @@ -0,0 +1 @@ +#implentations of the HTTPSender diff --git a/pyogp/lib/base/message/message_llsd_builder.py b/pyogp/lib/base/message/message_llsd_builder.py new file mode 100644 index 0000000..53ebbc2 --- /dev/null +++ b/pyogp/lib/base/message/message_llsd_builder.py @@ -0,0 +1,60 @@ +#third party +from zope.interface import implements + +#local +from pyogp.lib.base.message.interfaces import IMessageBuilder +from pyogp.lib.base.message.message_template import MsgData, MsgBlockData, \ + MsgVariableData + +class LLSDMessageBuilder(object): + implements(IMessageBuilder) + + def __init__(self): + self.current_template = None + self.current_msg = None + self.current_block = None + + self.cur_msg_name = '' + self.cur_block_name = '' + + def build_message(self): + """ this does not serialize it for this type of builder. The message + will be put in standard Python form and will need to be formatted + based on who the target is (xml? something else?) """ + msg = {} + for block in self.current_msg.block_map: + #message can have multiple of the same block names, so + #message actually holds a block list + block_list = self.current_msg.block_map[block] + + for block_data in block_list: + #set up the block list + if block_data.name not in msg: + msg[block_data.name] = [] + #each block in the block list is a map + block = {} + msg[block_data.name].append(block) + + #go through the variables for the data + for variable in block_data.variable_map.values(): + #the variable holds the key-value pairs of data + #for the block + block[variable.name] = variable.data + + return msg, len(msg) + + def new_message(self, message_name): + self.current_msg = MsgData(message_name) + self.cur_msg_name = message_name + + def next_block(self, block_name): + block = MsgBlockData(block_name) + self.current_msg.add_block(block) + self.current_block = block + self.cur_block_name = block_name + + def add_data(self, var_name, data, data_type): + var = MsgVariableData(var_name, data_type) + self.current_block.add_variable(var) + #size doesn't matter for llsd, formatter will take care of it + self.current_block.add_data(var_name, data, -1) diff --git a/pyogp/lib/base/message/message_system.py b/pyogp/lib/base/message/message_system.py index 5020dcc..bddd470 100644 --- a/pyogp/lib/base/message/message_system.py +++ b/pyogp/lib/base/message/message_system.py @@ -1,6 +1,13 @@ from zope.component import getGlobalSiteManager gsm = getGlobalSiteManager() +from pyogp.lib.base.data import msg_tmpl +from pyogp.lib.base.message.message_llsd_builder import LLSDMessageBuilder +from pyogp.lib.base.message.message_template_parser import MessageTemplateParser +from pyogp.lib.base.message.message_template_builder import MessageTemplateBuilder +from pyogp.lib.base.message.message_template_reader import MessageTemplateReader +from pyogp.lib.base.message.message_template_dict import TemplateDictionary + class MessageSystem(object): def __init__(): self.builder = None @@ -8,6 +15,19 @@ class MessageSystem(object): self.circuit_info = None self.socket = None + self.llsd_builder = LLSDMessageBuilder() + #self.llsd_reader = LLSDMessageReader() + + template_dict = self.load_template(msg_tmpl) + self.template_builder = MessageTemplateBuilder(template_dict) + self.template_reader = MessageTemplateReader(template_dict) + + def load_template(self, template_file): + #use the parser to load the message_template.msg message templates + parser = MessageTemplateParser(msg_tmpl) + template_list = parser.message_templates + return TemplateDictionary(self.template_list) + def receive_check(self): #determine if we have any messages that can be received through UDP #also, check and decode the message we have received @@ -31,11 +51,23 @@ class MessageSystem(object): #acks are just the packet_id that we are acking pass + def send_message_circuit(self, circuit): + """ allows someone to send a message only knowing the circuit """ + #send_message(map_circuit_to_host(circuit)) + pass + + def send_message_llsd(self, host, name, message): + """ sends an llsd message without going through builder """ + pass + def send_message(self, host): """ Sends the message that is currently built to the desired host """ #build it if it isn't built #make sure host is OK (ip and address aren't null) + + + #IF UDP/template message #use circuit manager to get the circuit to send on #if the packet is reliable, add it to the circuit manager's list of diff --git a/pyogp/lib/base/message/net.py b/pyogp/lib/base/message/net.py index b8dc1c3..7dd5e9b 100644 --- a/pyogp/lib/base/message/net.py +++ b/pyogp/lib/base/message/net.py @@ -1,5 +1,6 @@ +import socket - +#maybe put this isnt' a class #returns true if packet was sent successfully def send_packet(socket, send_buffer, size, ip_addr, port): @@ -8,3 +9,13 @@ def send_packet(socket, send_buffer, size, ip_addr, port): #returns message and size, or None if error def receive_packet(socket): pass + +def start_udp_connection(port): + """ Starts a udp connection, returning socket and port. """ + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + #error check - make sure sock is good + + #will probably be other setup for this + return sock + + diff --git a/pyogp/lib/base/tests/test_llsd_builder.py b/pyogp/lib/base/tests/test_llsd_builder.py new file mode 100644 index 0000000..a7fcf5c --- /dev/null +++ b/pyogp/lib/base/tests/test_llsd_builder.py @@ -0,0 +1,64 @@ +#standard libraries +import unittest, doctest + +#third party +from indra.base import llsd + +#local libraries +from pyogp.lib.base.message.message_llsd_builder import LLSDMessageBuilder +from pyogp.lib.base.message.message_types import MsgType + +class TestLLSDBuilder(unittest.TestCase): + + def tearDown(self): + pass + + def setUp(self): + pass + + def test_builder(self): + builder = LLSDMessageBuilder() + builder.new_message('TestMessage') + + builder.next_block('TestBlock1') + builder.add_data('Test1', 0x00000001, MsgType.MVT_U32) + + builder.next_block('TestBlock1') + builder.add_data('Test2', 0x00000001, MsgType.MVT_U32) + + builder.next_block('NeighborBlock') + builder.add_data('Test0', 0x00000001, MsgType.MVT_U32) + builder.add_data('Test1', 0x00000001, MsgType.MVT_U32) + builder.add_data('Test2', 0x00000001, MsgType.MVT_U32) + + builder.next_block('NeighborBlock') + builder.add_data('Test1', 0x00000001, MsgType.MVT_U32) + builder.add_data('Test1', 0x00000001, MsgType.MVT_U32) + builder.add_data('Test1', 0x00000001, MsgType.MVT_U32) + + builder.next_block('NeighborBlock') + builder.add_data('Test2', 0x00000001, MsgType.MVT_U32) + builder.add_data('Test2', 0x00000001, MsgType.MVT_U32) + builder.add_data('Test2', 0x00000001, MsgType.MVT_U32) + + builder.next_block('TestBlock2') + builder.add_data('Test1', 0x00000001, MsgType.MVT_U32) + + msg, size = builder.build_message() + + try: + assert len(msg['NeighborBlock']) == 3, "Multiple blocks not" + \ + " correct" + except: + assert False, "Message not set up properly" + + try: + msg = llsd.format_xml(msg) + except: + assert False, "Message not built correctly so it can be formatted" + +def test_suite(): + from unittest import TestSuite, makeSuite + suite = TestSuite() + suite.addTest(makeSuite(TestLLSDBuilder)) + return suite