Timothy Loughlin (Locklainn Linden) schrieb:
First, I won't be around for Tues and Wed. I have to take care of some
training for grad school. This means you guys have 3 days to review this
stuff and make a decision! w00t!
Here is the design proposal for the message system refactoring. After
writing this up and looking at my branch code and Tao's, it seems what
we have in our branches is the only good solution thus far. Also, we
have essentially the same design, just with some different naming. They
perform the same functions in almost the same way.
*Similarities:
*what Tao calls EndPoint I call NetUDPClient (which is ZCAified so it
can be swapped)
what Tao calls UDPDispatcher I call MessageSystem (or UDPConnection in
my branch)
As I mentioned somewhere I am actually not sure if the way I initially
did the TCP part works that well with e.g. twisted. So maybe the network
layer at all wasn't such a good idea as it assumes that this is the
lowest layer and e.g. circuits use it.
I'd rather think that the networking layer is in the application and it
mainly passes data in and out to be handled. Also I wonder what
possibilities there are right now to exchange the NetUDPClient. It
cannot be replaced right now to use twisted. The same would be true for
the HTTPClient. (with right now I mean trunk).
So having it like discussed in the earlier mail might work better then.
Once this is refactored I would then look into HTTP and maybe build some
example twisted app which does presence or so.
*Differences:
*Tao's sending and receiving functionality is split apart. All receiving
is through the UDPDispatcher, which then dispatches to a circuit to
handle (exactly the same as Lock's). However, sending is different in
that in Tao's branch you send a message by having direct access to a
circuit. The circuit is hard-wired to a single remote host, and so you
don't pass in the destination when sending. With Lock's, every time you
send a message, you tell it which destination it will go to.
I want to note that this wasn't finished and I was far from being happy
with it. My brain was just at it's recursion depth limit ;-)
As for the address thing you are right. But I put in the endpoint you
give to the connection constructor (which is the circuit) which can be a
shared socket (or wraps it rather). But you are right that it didn't
know the address which was a problem I found hard to solve back then.
(at least so that the API is the same for all cases)
For example, here is the difference in sending and receiving (putting
the terms into Lock's terms to show the similarity and differences easily)
*
Receiving:
*Both:
MessageSystem:
receive() (also called handle() ):
size = 10000
data, address = self.udp_client.recvfrom(size)
if address not in self.circuit_list:
error
circuit = find_circuit(address)
circuit.process(data)
NOTES:
This call, receive(), can be wrapped in any way the user wants. It can
be threaded, used as a callback, non-blocking IO, whatever.
Well, it can't be a callback as you cannot pass data in you want to be
handled. In twisted you get some data from a transport and you'd need to
pass it to receive. The receivefrom is already done (or rather done in a
non-blocking fashion).
The difference between Tao's code and Lock's for receive is how a
circuit gets added to the Message System's circuit list. In Tao's, one
must manually call message_system.add_circuit(circuit). In Lock's a new
circuit is created when the user sends to a new address/port or when it
gets a message (receives) from a new address/port. The user doesn't use
connection directly, then, but they are simply used as ways to keep
track of packet acks. Note that this is the same in both as well,
because even in Tao's code the circuit delegates sending and receiving
to some udp client (called EndPoint).
I personally would prefer some wrapping like this:
Region(Circuit())
So the region knows it's connection and can instantiate it when it's
created itself (e.g. after place_avatar). This way each object knows
directly the one it's using.
The problem is of course the shared socket or some twisted code. This is
why I think that the networking layer actually needs to move up as it
seems to be the main driving force of the whole application.
*Sending:*
Tao:
message_system= MessageSystem()
conn = Connection(message_system, (address, port))
msg = Message(...)
conn.send(msg)
Lock:
message_system= MessageSystem ()
msg = Message(...)
message_system.send(msg, (address, port))
NOTES:
The differences lie in the fact that in Tao's branch you create a
connection explicitly, tie the connection with an address/port, and send
the message through the connection. In Lock's way, you send a message to
the target address/port all the time, never having access to the circuit
itself. The message system determines if the combination is new, if so,
creates a new circuit for it automatically.
*Decision:*
My vote is that we keep the design in my branch because it is mostly
finished and functional (with packet flags and all that already
working). I vote this because our designs are almost identical, with
only a naming difference. So, let's come up with the names for these
things and we will have our refactor design.
I would vote for slightly moving things from the message system to the
circuit so that you can also use it without the message system. Like
adding flags and such. This wouldn't change anything to the outside API.
For the real differences, we must decide whether or not the Message
System does the sending, or if the circuit does the sending (which
delegates to some udp client). My thoughts are that because in Tao's
branch the circuit is doing the sending and the message system doing the
receiving, we need a single udp_client, or socket at the lowest level,
and so this will be shared among the circuit and the message system
(with message system having circuits as well). We then have to pass this
socket (or EndPoint) to both the MessageSystem and the Circuit, which
makes it 1 or 3 steps more to set up sending. With Lock's design, the
EndPoint, socket, or udp_client is automatically the same for sending
and receiving.
But I am not sure it works with twisted. You need to pass something to
use for sending. In twisted you don't use sockets directly. That was the
reason for my endpoint. It's not only about single or shared socket.
So the endpoint needs to come from the application and needs to be passed.
Note that the socket issue, whether or not a single socket is used per
connection or if a single socket is used for all connections, is exactly
the same for both designs. In both designs you have to create a new
MessageSystem, or UDPDispatcher (which also needs a new EndPoint to be
created as well).
Also note that it isn't currently possible to have both designs (one
that has access to connections and one that doesn't). This is because in
my design the connections are under the hood of the message system.We
COULD, however, add this functionality to the message system, which
means having the message system be a way to create circuits:
message_system = MessageSystem()
conn1 = message_system.create_circuit(address, port)
msg = Message(...)
conn1.send(msg)
I think it is possible to give the user the possibility to not use the
message system but something else. Then we could keep most of the stuff
which is there and only would need to move things slightly.
I guess we should discuss this tomorrow :)
-- Christian
_______________________________________________
Click here to unsubscribe or manage your list subscription:
https://lists.secondlife.com/cgi-bin/mailman/listinfo/pyogp