Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Stacks and Layers
A running Yowsup app is a stack of several layers. The previous figure is a breakdown of the core Yowsup stack. A layer is a bidirectional channel that transforms the data passing through it before passing it to underlying or the above layer. Before analyzing the above stack, here are 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 called for data coming from the layer below, and the
send method is called for data coming from the layer above.
Here is an example pass-through 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 (receiving) incoming data from the server, and writing (sending) data to it.
When sending, it expects data from
YowStanzaRegulatorLayer of type
When receiving, this layer buffers the data it gets from
YowNetworkLayer until it has enough bytes to form a stanza and then it passes to
YowCryptLayer bytearray containing bytes representing exactly 1 stanza at a time.
When sending, data coming from
YowCryptLayer are just passed through to
YowNetworkLayer without any alterations.
YowCryptLayer gets a bytearray from the
YowStanzaRegulatorLayer and decrypts it and passes the decrypted values to the upper
When sending, it gets data from that
YowCoderLayer and encrypts it before passing it downwards to
When receiving, data arriving at
YowCoderLayer is decrypted data. It is now
YowCoderLayer's job to map those decrypted data to meaningful XML stanzas, represented by a
Yowsup class called
ProtocolTreeNode. It then passes these
ProtocolTreeNode instances to whatever layer placed above it.
YowCoderLayer also expects to get from whatever layers placed on top of it an instance of
ProtocolTreeNode. It then takes care of transforming it to bytes before passing it downwards to
Special Layer types:
While general layers should just subclass
YowLayer, there are also cases where a group of layers share similar functionality. In such cases it is useful to extend the following more specific
A protocol layer in Yowsup that expects
ProtocolTreeNode from the layer below, and transmits an instance of
ProtocolEntity to the layer above.
YowProtocolLayer adds convencience methods for any layer which follows this pattern. Therefore they should subclass
YowProtocolLayer instead of
A protocol entity is a mapping from the generic
ProtocolTreeNode XML representation to a real object with attributes representing the stanza.
TextMessageProtocolEntity provides you with methods like
getBody that directly returns the message body instance for getting your hands dirty with XML nodes traversing.
For each type of an XML stanza there should be implemented an associated
YowInterfaceLayer layer is a layer that expects to receive an instance of
ProtocolEntity from below. Subclassing
YowInterfaceLayer will provide you with convenience methods like
disconnect, and others. A
YowInterfaceLayer 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)
Please note that, for you to actually be able to send and receive specific type of data -- notification for example -- the associated
YowNotificationsProtocolLayer must exist in your stack.
Yowsup stack also supports 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 --
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 transforming into a
ProtocolTreeNode, the format accepted by the