-
Notifications
You must be signed in to change notification settings - Fork 23
Architecture
A running Yowsup app is a stack of several layers. The previous figure is a breakdown of core Yowsup Stack. A layer is a bidirectional channel that usually transforms the data passing through it before passing it to underlying or the above layer. Before analyzing the above stack, here is a few things you should get introduced to first:
This is the base class for all Yowsup layers. A layer should implement at least a send method and a receive method. The receive method is call for data coming from the layer below, and the send method is called for data coming from the layer above.
Here is an example Passthrough layer that you can place anywhere in the stack and it just passes through the data it gets from above and below:
class PassthroughLayer(YowLayer):
def send(self, data):
self.toLower(data)
def receive(self, data):
self.toUpper(data)
YowLayers also are able to send and receive events to and from other layers.
self.emitEvent(YowLayerEvent) #sends event to upper layers
self.broadcastEvent(YowLayerEvent) # sends event to lower layers
To handle events in one layer, you need to implement the onEvent method in that layer:
class PassthroughLayer(YowLayer):
def send(self, data):
self.toLower(data)
def receive(self, data):
self.toUpper(data)
def onEvent(self, yowLayerEvent):
if yowLayerEvent.getName() == "disconnect":
'''disconnect or whatever'''
return True #if you return true, the event will not propagate any further.
Now let's analyze the stack in the figure
Responsible for reading incoming data from the server, and writing data to it. It expects data from YowStanzaRegulatorLayer of type 'bytearray'
This layer buffers the data it gets from YowNetworkLayer until it get enough bytes to form a stanza. And then it passes to YowCryptLayer bytearray containing bytes representing exactly 1 stanza at a time. For data coming from YowCryptLayer it just passes them through to YowNetworkLayer without any alteration
When YowCryptLayer gets a bytearray from the YowStanzaRegulatorLayer, it decrypts it and passes the decrypted values to the upper YowCoderLayer. When it gets data from that YowCoderLayer, it encrypts it before passing it downwards to YowStanzaRegulatorLayer
Data arriving at YowCoderLayer from the bottom YowCryptLayer is decrypted data. It's now YowCoderLayer's job to map those decrypted bytes to meaningful XML stanzas, represented by a Yowsup class called ProtocolTreeNode. Therefore it passes to whatever layer placed above instaces for ProtocolTreeNode.
YowCoderLayer also expects to get from whatever layers placed on top of it an instance of ProtocolTreeNode. And then it takes care of transforming it to bytes before passing it downwards to YowCryptLayer
While general layers should just subclass YowLayer, there are also cases where a group of layers share similar functionality. In such case it was useful to extend the following more specific YowLayer subclasses:
A protocol layer in Yowsup is layer which expects ProtocolTreeNode from the layer below, and transmits an instance of ProtocolEntity to the layer above. YowProtocolLayer just adds convencience methods for any layer which follows this pattern. Therefore they should subclass YowProtocolLayer instead of YowLayer
A protocol entity is a mapping from the generic ProtocolTreeNode XML representation to a real object with attributes representing the stanza. For example TextMessageProtocolEntity provides you with methods like: 'getBody()', which directy returns the message body instance of getting your hands dirty with XML nodes traversing.
For each type of an XML stanza there should implemented an associated ProtocolEntity subclass.
A YowInterface layer layer is a layer which expects to receive an instance of ProtocolEntity from below. Subclassing InterfaceLayer will provide you with convenience methods like 'connect', 'disconnect' and others. An InterfaceLayer is what you usually need to implement to integrate Yowsup in any project.
When you subclass YowInterfaceLayer, you can then make use this decorator
@ProtocolEntityCallback("message")
def onMessage(messageProtocolEntity):
''' do stuff''''
This basically means, whenever your layer receives data (instances of ProtocolEntity), if this object's getTag() method returned "message", the onMessage method will be automatically invoked with this object passed as an argument.
So as "message" is basically the value returned by a protocolEntity.getTag(), those are the other main possible values as well:
- message (for both text and media messages)
- iq
- ib
- notification
- presence
- receipt
- ack
Please note that, for you to actually be able to send and receive specific type of data, notification for example, then the associated 'YowNotificationsProtocolLayer' must exist be in your stack.
Yowsup stack also supports a parallel layers. That is, several layers at the same level in the stack, all getting the same exact data from the layer above and below. In Yowsup, Protocol layers are placed in parallel, so the final stack becomes something similar to this:
YowAuthenticatorLayer, YowMessagesProtocolLayer, YowGroupsProtocolLayer, YowReceiptProtocolLayer, YowPresenceProtocolLayer ..etc YowCoderLayer YowCryptLayer YowStanzaRegulatorLayer YowNetworklayer
In this scenario, the list of layers at the same level:
(YowAuthenticatorLayer, YowMessagesProtocolLayer, YowGroupsProtocolLayer, YowReceiptProtocolLayer, YowPresenceProtocolLayer)
are all getting the exact data from YowCoderLayer which is an instance of ProtocolTreeNode, and transforming it into an instance of some Subclass of ProtocolEntity. Each layer is responsible for its own set of stanza types and transforming it into some ProtocolEntity. They are all also getting the same ProtocolEntity instance from the layer above and they're responsible for transoforming into a ProtocolTreeNode, the format acceptable by the YowCoderLayer below.