-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Architecture
A running Yowsup app is a stack of several layers. A layer is a bidirectional channel that transforms the data passing through it before passing it to underlying or the above layer. Here are a few things you should get introduced to:
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 bytearray
.
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.
When sending, 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 YowNoiseLayer
.
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 YowLayer
subclasses:
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 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
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 ProtocolEntity
subclass.
A YowInterfaceLayer
layer is a layer that expects to receive an instance of ProtocolEntity
from below. Subclassing YowInterfaceLayer
will provide you with convenience methods like connect
, 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)
- 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 -- 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,
YowNoiseLayer,
YowNoiseSegmentsLayer,
YowNetworklayer
In this scenario, the list of layers at the same level -- YowAuthenticatorLayer
, YowMessagesProtocolLayer
, YowGroupsProtocolLayer
, YowReceiptProtocolLayer
, and 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 YowCoderLayer
below.