Source code for yowsup_gateway.layer

# -*- coding: utf-8 -*-
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
from yowsup.layers import EventCallback
from yowsup.layers.protocol_messages.protocolentities import \
    TextMessageProtocolEntity
import logging
from yowsup.layers.network import YowNetworkLayer
from yowsup_gateway.results import SuccessfulResult
from yowsup_gateway.exceptions import ConnectionError
from functools import wraps


logger = logging.getLogger(__name__)

[docs]def connection_required(f): @wraps(f) def decorated_function(self, *args, **kwargs): if not self.connected: raise ConnectionError("%s needs to be connected" % f.__name__) return f(self, *args, **kwargs) return decorated_function
[docs]class ExitGateway(Exception): """ Raised by GatewayLayer to exit stack loop """ pass
[docs]class GatewayLayer(YowInterfaceLayer): """ Layer to be on the top of the Yowsup Stack. :ivar bool connected: connected or not connected to whatsapp :ivar list ack_pending: list with incoming ack messages to receive :ivar list inbox: list of received messages from whatsapp :ivar list outbox: list of sent messages to whatsapp """ CALLBACK_EVENT = "org.openwhatsapp.yowsup.prop.callback" PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue" EVENT_SEND_MESSAGES = "org.openwhatsapp.yowsup.prop.queue.sendmessage" def __init__(self): super(GatewayLayer, self).__init__() self.ack_pending = [] self.connected = False self.inbox = [] self.outbox = [] def _get_event_callback(self): return self.getProp(self.CALLBACK_EVENT, None) def _send_protocol_entity(self, protocol_entity): self.outbox.append(protocol_entity) self.toLower(protocol_entity) def _receive_protocol_entity(self, protocol_entity): self.inbox.append(protocol_entity)
[docs] def check_pending_flow(self): if self.ack_pending: pending_acks = [pending_ack for pending_ack in self.ack_pending] raise ConnectionError("Pending incoming Ack messages not received \ %s" % str(pending_acks))
@ProtocolEntityCallback("success")
[docs] def on_success(self, success_protocol_entity): """ Callback when there is a successful connection to whatsapp server """ logger.info("Logged in") self.connected = True callback_event = self._get_event_callback() if callback_event: self.onEvent(callback_event)
@ProtocolEntityCallback("failure")
[docs] def on_failure(self, entity): """ Callback function when there is a failure in a connection to whatsapp server """ logger.error("Login failed, reason: %s" % entity.getReason()) self.connected = False
@ProtocolEntityCallback("ack") @connection_required
[docs] def on_ack(self, entity): """ Callback function when receiving an ack for a sent message from whatsapp """ self.inbox.append(entity) # if the id match ack_pending id, then pop the id of the message out if entity.getId() in self.ack_pending: self.ack_pending.pop(self.ack_pending.index(entity.getId())) logger.info("Message sent:" + str(entity.getId())) if not len(self.ack_pending): logger.info("Disconnect") self.disconnect()
@ProtocolEntityCallback("message") @connection_required
[docs] def on_message(self, message_protocol_entity): """ Callback function when receiving message from whatsapp server """ self._receive_protocol_entity(message_protocol_entity) self._send_protocol_entity(message_protocol_entity.ack())
@ProtocolEntityCallback("receipt") @connection_required
[docs] def on_receipt(self, receipt_protocol_entity): """ Callback function when receiving receipt message from whatsapp """ self._receive_protocol_entity(receipt_protocol_entity) self._send_protocol_entity(receipt_protocol_entity.ack())
@EventCallback(EVENT_SEND_MESSAGES) @connection_required
[docs] def on_send_messages(self, yowLayerEvent): """ Callback function when receiving event to send messages """ for message in yowLayerEvent.getArg("messages"): number, content = message if '@' in number: message_protocol_entity = \ TextMessageProtocolEntity(content, to=number) elif '-' in number: message_protocol_entity = \ TextMessageProtocolEntity(content, to="%s@g.us" % number) else: message_protocol_entity = \ TextMessageProtocolEntity(content, to="%s@s.whatsapp.net" % number) # append the id of message to ack_pending list # which the id of message will be deleted when ack is received. self.ack_pending.append(message_protocol_entity.getId()) self._send_protocol_entity(message_protocol_entity)
@EventCallback(YowNetworkLayer.EVENT_STATE_DISCONNECTED) @connection_required
[docs] def on_disconnected(self, yowLayerEvent): """ Callback function when receiving a disconnection event """ self.connected = False self.check_pending_flow() self.getStack().result = SuccessfulResult(self.inbox, self.outbox) raise ExitGateway()