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()
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})
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)
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))
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
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")
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
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")