Example #1
0
def main():
    service = CurrencyReciever(address='0.0.0.0', port=80)

    with entrypoint(service) as loop:
        log.info('Loop created')
        loop.create_task(currency('https://api.ratesapi.io/api/latest'))
        loop.run_forever()
Example #2
0
def enqueue_inbound_mms_event(event, rxid):
    # expected format: dictionary with the following keys
    #    gateway: the gateway that this message needs to be sent thru
    #    message: our own message ID
    #    peer_ref: provider's original message id (X-Mms-Message-Id)
    #    status: canonical status id
    #    description: verbose description of the status
    #    applies_to: phone number(s) this status applies to; missing means applies to all
    ev = bottle.request.json
    log.info(">>>> ordered {} event for incoming MMS {}: {}".format(
        event, rxid, ev))
    if \
        ev.get('gateway') is None or \
        ev.get('message') is None or \
        ev.get('peer_ref') is None or \
        ev.get('status') is None or \
        (event != "ack" and ev.get('event_for') is None) or \
        (event != "ack" and ev.get('applies_to') is None) \
    :
        return json_error(400, "Bad Request", "Missing required parameter")

    nums = list(ev.get('applies_to', ""))

    q_ev = rq.Queue("QEV-" + ev['gateway'], connection=rdbq)
    q_ev.enqueue_call(func='models.gateway.send_event_for_inbound_mms',
                      args=(
                          ev['message'],
                          event,
                          ev['peer_ref'],
                          ev['status'],
                          ev['description'],
                          ev.get('event_for'),
                          list(ev.get('applies_to', "")),
                      ),
                      meta={'retries': MAX_GW_RETRIES})
Example #3
0
async def currency_get(request):
    """Handler for GET request

    :param request: incoming request
    :return: exchange rates in json format
    """
    log.info(request)
    return web.json_response(rate)
Example #4
0
def cb_post(url, jdata):
    log.info(">>>> [callback] POSTing to {}: {}".format(url, jdata))
    rq = requests.post(url,
                       headers={'User-Agent': USER_AGENT},
                       json=json.loads(jdata))
    if rq.status_code >= 400:
        log.warning(
            ">>>> [callback] POSTing to {} failed with status {}: {}".format(
                url, rq.status_code, rq.text))
Example #5
0
    async def create_application(self):
        app = aiohttp.web.Application()

        app.add_routes([
            aiohttp.web.get('/', currency_get)
        ])
        log.info(f'Service has started')

        return app
Example #6
0
 def nq(self, gateway):
     self.gateway = gateway or DEFAULT_GATEWAY
     q_tx = rq.Queue("QTX-" + self.gateway, connection=rdbq)
     q_tx.enqueue_call(func='models.gateway.send_mms',
                       args=(self.id, ),
                       job_id=self.id,
                       meta={'retries': MAX_GW_RETRIES},
                       ttl=30)
     log.info("[] message {} queued for transmission on {}".format(
         self.id, self.gateway))
     self.set_state([], "SCHEDULED")
Example #7
0
def dispatch(content, sender, receivers, source=None):

    log.info(">>>> {} inbound on MM4 interface - From: {}, To: {}, length: {}"
        .format(source or "", sender, receivers, len(content))
    )
    log.debug(">>>> content: {}{}"
        .format(content[:4096], ("..." if len(content) > 4096 else ""))
    )
    if len(content) > 4096:
        log.debug(">>>> ...{}".format(content[-256:]))

    # get a gateway that can handle the message; preference is to search 
    # by receiver address first, by sending host next, and by sender address last
    gw = \
        cfg['receivers'].get(email.utils.parseaddr(receivers[0])[1]) or \
        cfg['peers'].get(source[0]) if source is not None else None or \
        cfg['senders'].get(email.utils.parseaddr(sender)[1])
    if gw is None:
        log.warning(">>>> no gateway to process this email")
        return "555 MAIL FROM/RCPT TO parameters not recognized"

    mm4rx_id = str(uuid.uuid4()).replace("-", "")
    
    # move content as file to be processed
    fn = repo(TMP_MMS_DIR, mm4rx_id + ".mm4")
    if cfg['general'].get('smtp_host'):
        with open(fn, "wb") as fh:
            fh.write(content)

    # post a task for the gateway parser
    q_rx = rq.Queue("QRX-" + gw, connection=rdbq)
    q_rx.enqueue_call(
        func='models.gateway.inbound', args=( mm4rx_id + ".mm4", ),
        job_id=mm4rx_id,
        meta={ 'retries': MAX_GW_RETRIES },
        ttl=30
    )
    log.info(">>>> message {}, queued for processing by gateway {}".format(mm4rx_id, gw))

    return None
Example #8
0
def mm7_inbound(gw):
    log.info("[{}] request received, {} bytes".format(
        gw, bottle.request.headers['Content-Length']))
    raw_content = bottle.request.body.read().decode()
    log.debug("[{}] request headers: {}".format(gw, [
        "{}: {}".format(h, bottle.request.headers.get(h))
        for h in bottle.request.headers.keys()
    ]))
    log.debug("[{}] >>>> raw content: {}...".format(gw, raw_content[:4096]))
    if len(raw_content) > 4096:
        log.debug("[{}] >>>> ... {}".format(gw, raw_content[-256:]))

    bottle.response.content_type = "text/xml"
    mime_headers = "Mime-Version: 1.0\nContent-Type: " + bottle.request.headers[
        'Content-Type']

    # try parsing lightly, to determine what queue to place this in
    m = email.message_from_string(mime_headers + "\n\n" + raw_content)
    try:
        if m.is_multipart():
            parts = m.get_payload()
            log.debug("[{}] handling as multipart, {} parts".format(
                gw, len(parts)))
            env_content = parts[0].get_payload(decode=True).decode()
            log.debug("[{}] SOAP envelope: {}".format(gw, env_content))
            env = ET.fromstring(env_content)
        else:
            log.debug("[{}] handling as single part".format(gw))
            env = ET.fromstring(m.get_payload(decode=True))
    except ET.ParseError as e:
        log.warning("[{}] Failed to xml-parse the SOAP envelope: {}".format(
            gw, e))
        return bottle.HTTPResponse(
            status=400, body="Failed to xml-parse the SOAP envelope")

    # get the transaction tag, treat it as unique ID of the incoming message
    env_ns = "{" + MM7_NAMESPACE['env'] + "}"
    transaction_id = None
    t_header = env.find("./" + env_ns + "Header") or []
    for t in t_header:
        if t.tag.endswith("TransactionID"):
            transaction_id = t.text.strip()
            mm7_ns = t.tag.replace("TransactionID", "")
            break
    if transaction_id is None:
        s = "SOAP envelope of received request invalid, at least missing a transaction ID"
        log.warning("[{}] {}".format(gw, s))
        return bottle.HTTPResponse(status=400, body=s)

    # try to identify the message type
    mo_meta = \
        env.find("./" + env_ns + "Body/" + mm7_ns + "DeliverReq") or \
        env.find("./" + env_ns + "Body/" + mm7_ns + "SubmitReq")
    if mo_meta:
        # create a shallow message to send back to the MMSC
        rx = MMSMessage()
        rx.last_tran_id = transaction_id
        rx.direction = 1
        log.debug("[{}] {} Incoming message {} is an MO".format(
            gw, rx.id, transaction_id))
        rx.save()
        rx.template.save()
        # save raw content
        fn = repo(TMP_MMS_DIR, rx.id + ".mm7")
        log.debug("[{}] {} saving media as {}".format(gw, rx.id,
                                                      transaction_id, fn))
        with open(fn, "w") as fh:
            fh.write(parts[1].as_string())
        # schedule message for processing
        q_rx = rq.Queue("QRX-" + gw, connection=rdbq)
        q_rx.enqueue_call(func='models.gateway.inbound',
                          args=(
                              rx.id + ".mm7",
                              ET.tostring(mo_meta),
                          ),
                          job_id=rx.id,
                          meta={'retries': MAX_GW_RETRIES},
                          ttl=30)
        # send MM7 response
        return models.gateway.MM7Gateway.build_response(
            "DeliverRsp", transaction_id, rx.id, '1000')

    m_meta = \
        env.find("./" + env_ns + "Body/" + mm7_ns + "DeliveryReportReq") or \
        env.find("./" + env_ns + "Body/" + mm7_ns + "ReadReplyReq")
    if m_meta:
        m_type = m_meta.tag.replace(mm7_ns, "")
        m_reply_type = "DeliveryReportRsp" if m_meta.tag.replace(
            mm7_ns, "") else "ReadReplyRsp"
        log.debug("[{}] Incoming message is a {}".format(gw, m_type))
        provider_msg_id = m_meta.findtext("./" + mm7_ns + "MessageID", "")
        if provider_msg_id is None:
            log.warning("[{}] No MessageID tag found in the {}".format(
                gw, m_meta))
            return models.gateway.MM7Gateway.build_response(
                m_reply_type, transaction_id, "", '4004')
        # find MT message
        txid = rdb.get('mmsxref-' + provider_msg_id)
        if txid is None:
            log.info(
                "[{}] Couldnt find reference to original message for MessageID {}"
                .format(gw, provider_msg_id))
            return models.gateway.MM7Gateway.build_response(
                m_reply_type, transaction_id, provider_msg_id, '2005')
        tx = MMSMessage(txid)
        if tx.id is None:
            log.info(
                "[{}] {} Couldnt find original message record for MessageID {}"
                .format(gw, provider_msg_id))
            return models.gateway.MM7Gateway.build_response(
                m_reply_type, transaction_id, provider_msg_id, '2005')
        # schedule DR for processing
        q_rx = rq.Queue("QRX-" + gw, connection=rdbq)
        q_rx.enqueue_call(func='models.gateway.inbound',
                          args=(
                              "",
                              ET.tostring(m_meta),
                          ),
                          job_id=transaction_id,
                          meta={'retries': MAX_GW_RETRIES},
                          ttl=30)
        # send MM7 response
        return models.gateway.MM7Gateway.build_response(
            m_reply_type, transaction_id, provider_msg_id, '1000')

    # handling for other MM7 requests (cancel, replace, etc) go here

    log.warning("[{}] Unknown or unhandled message type".format(gw))
    return bottle.HTTPResponse(status=400,
                               body="Unknown or unhandled message type")