Advertisement
911programming

flask_app.py for 'monobot' project (2)

Apr 26th, 2019
757
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.66 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. #
  3. #  flask_app.py
  4. #
  5. #
  6.  
  7. import os, os.path
  8. import re
  9. import click
  10. import telepot
  11. import urllib.parse
  12. from pprint import pprint
  13.  
  14. # see https://pastebin.com/DnRQD648
  15. from jet.expando import Expando, expando_update, bind_expando_method
  16.  
  17.  
  18. # Set the proper value
  19. #~ SERVER_TYPE = 'REMOTE'
  20. SERVER_TYPE = 'LOCAL' # for flask server on your computer
  21.  
  22. from flask import Flask, request, g
  23.  
  24. app = Flask(__name__)
  25. app.config.from_object('config')
  26.  
  27.  
  28. def set_telepot_socks_proxy(proxy_url, username=None, password=None):
  29.     from urllib3.contrib.socks import SOCKSProxyManager
  30.     from telepot.api import _default_pool_params, _onetime_pool_params
  31.     telepot.api._onetime_pool_spec = (SOCKSProxyManager, dict(proxy_url=proxy_url, username=username, password=password, **_onetime_pool_params))
  32.     telepot.api._pools['default'] = SOCKSProxyManager(proxy_url, username=username, password=password, **_default_pool_params)
  33.  
  34.  
  35. def set_telepot_http_proxy(proxy_url) :
  36.     import urllib3
  37.     telepot.api._pools = {
  38.         'default': urllib3.ProxyManager(proxy_url=proxy_url, num_pools=3, maxsize=10, retries=False, timeout=30),
  39.     }
  40.  
  41.     telepot.api._onetime_pool_spec = (urllib3.ProxyManager, dict(proxy_url=proxy_url, num_pools=1, maxsize=1, retries=False, timeout=30))
  42.  
  43.  
  44. if SERVER_TYPE == 'LOCAL' :
  45.     # running a local flask server
  46.     proxy_url = app.config['PROXY_URL']
  47.  
  48.     if proxy_url and proxy_url.startswith('socks') :
  49.         set_telepot_socks_proxy(proxy_url)
  50.  
  51.     elif proxy_url and  proxy_url.startswith('http') :
  52.         set_telepot_http_proxy(proxy_url)
  53.  
  54. else :
  55.     # running a remote flask server on PythonAnywhere
  56.     proxy_url = "http://proxy.server:3128"
  57.     set_telepot_http_proxy(proxy_url)
  58.  
  59.  
  60.  
  61. # create one time proenv data-ware :
  62. host_url = app.config['HOST_URL']
  63. home = os.path.expanduser('~')
  64. project = app.config['PROJECT']
  65. var_path = os.path.join(home, 'var', project)
  66. session_path = os.path.join(var_path, 'sessions')
  67.  
  68. proenv = Expando(
  69.     app_path        = app.config['APT_PATH'],
  70.     home            = home,
  71.     project         = project,
  72.     var_path        = var_path,
  73.     session_path    = session_path,
  74.  
  75.     config          = app.config
  76. )
  77.  
  78. os.makedirs(var_path, exist_ok=True)
  79. os.makedirs(session_path, exist_ok=True)
  80.  
  81. # create one-time (monobot) bot_info :
  82. bot_info = Expando(
  83.     id            = app.config['BOT_ID'],
  84.     name          = app.config['BOT_NAME'],
  85.     username      = app.config['BOT_USERNAME'],
  86.     webhook_route = app.config['WEBHOOK_ROUTE'],
  87.     webhook_url   = urllib.parse.urljoin(app.config['HOST_URL'], app.config['WEBHOOK_ROUTE']),
  88.     bot           = telepot.Bot(app.config['BOT_TOKEN'])
  89. )
  90.  
  91.  
  92. if SERVER_TYPE == 'REMOTE' :
  93.     bot_info.bot.setWebhook(bot_info.webhook_url, max_connections=1)
  94.  
  95. def get_sender_info_summary(msg, ignore_lang=True) :
  96.     parts = []
  97.  
  98.     if 'from' in msg :
  99.         sender = msg['from']
  100.         parts.append('{}:'.format(sender['id']))
  101.  
  102.         if 'first_name' in sender and sender['first_name'] is not None :
  103.             parts.append(sender['first_name'])
  104.  
  105.         if 'last_name' in sender and sender['last_name'] is not None :
  106.             parts.append(sender['last_name'])
  107.  
  108.         if 'username' in sender and sender['username'] is not None :
  109.             parts.append('(@{})'.format(sender['username']))
  110.  
  111.         if 'is_bot' in sender and sender['is_bot'] :
  112.             parts.append('[BOT]')
  113.  
  114.         if not ignore_lang and 'language_code' in sender and sender['language_code'] is not None :
  115.             parts.append('<{}>'.format(sender['language_code']))
  116.  
  117.  
  118.     return ' '.join(parts)
  119.  
  120.  
  121. def get_chat_info_summary(msg, ignore_adm=True) :
  122.     parts = []
  123.  
  124.     if 'chat' in msg :
  125.         chat = msg['chat']
  126.         parts.append('{}:'.format(chat['id']))
  127.  
  128.         if 'first_name' in chat and chat['first_name'] is not None :
  129.             parts.append(chat['first_name'])
  130.  
  131.         if 'last_name' in chat and chat['last_name'] is not None :
  132.             parts.append(chat['last_name'])
  133.  
  134.         if 'username' in chat and chat['username'] is not None :
  135.             parts.append('(@{})'.format(chat['username']))
  136.  
  137.  
  138.         if 'title' in chat and chat['title'] is not None :
  139.             parts.append(chat['title'])
  140.  
  141.         if 'type' in chat and chat['type'] is not None :
  142.             parts.append('[{}]'.format(chat['type']))
  143.  
  144.         if not ignore_adm and 'all_members_are_administrators' in chat and chat['all_members_are_administrators'] :
  145.             parts.append('[ALL:ADMIN]')
  146.  
  147.     return ' '.join(parts)
  148.  
  149.  
  150. command_mention_re = re.compile(r'^/([\w]+)@([\w]+)\s*(.*)')
  151. command_re = re.compile(r'^/([\w]+)\s*(.*)')
  152. space_split_re = re.compile(r'\s+')
  153.  
  154. def split_message_text(text) :
  155.     body_parts = text.split('\n', maxsplit=1)
  156.     cmd_line = body_parts[0]
  157.     tail = None if len(body_parts) == 1 else body_parts[1].strip()
  158.  
  159.     command     = None
  160.     bot_mention = None
  161.     line        = None
  162.  
  163.     omat = command_mention_re.match(text)
  164.     if omat :
  165.         command = omat.group(1).upper()
  166.         bot_mention = omat.group(2).lower()
  167.         line = omat.group(3).strip() or None
  168.  
  169.     else :
  170.         omat = command_re.match(text)
  171.         if omat :
  172.             command = omat.group(1).upper()
  173.             line = omat.group(2).strip() or None
  174.  
  175.         else :
  176.             line = text.strip() or None
  177.  
  178.  
  179.     args = (line and space_split_re.split(line)) or []
  180.  
  181.     return Expando(command=command, bot_mention=bot_mention, line=line, args=args, tail=tail)
  182.  
  183.  
  184.  
  185. def act_start(command, message, extras) :
  186.     bot = extras.bot_info.bot
  187.     chat_id = extras.provars.chat_id
  188.     text = f'Hello! I am {extras.bot_info.name}. Nice to meet you.'
  189.     bot.sendMessage(chat_id, text)
  190.  
  191.  
  192. def act_hello(command, message, extras) :
  193.     bot = extras.bot_info.bot
  194.     chat_id = extras.provars.chat_id
  195.     text = f'Hello! Good to see you again! 🌺'
  196.     bot.sendMessage(chat_id, text)
  197.  
  198.  
  199. def act_bad_command(command, message, extras) :
  200.     bot = extras.bot_info.bot
  201.     chat_id = extras.provars.chat_id
  202.     text = f'🚫 Unknown command: {command}'
  203.     bot.sendMessage(chat_id, text)
  204.  
  205.  
  206. def act_no_command(command, message, extras) :
  207.     bot = extras.bot_info.bot
  208.     chat_id = extras.provars.chat_id
  209.     text = f'🚫 No command in message!'
  210.     bot.sendMessage(chat_id, text)
  211.  
  212.  
  213. commands = {
  214.     'START' : act_start,
  215.     'HELLO' : act_hello,
  216. }
  217.  
  218.  
  219. def handle_chat(message, extras) :
  220.     flavor = telepot.flavor(message)
  221.     assert flavor == 'chat'
  222.     content_type, chat_type, chat_id = telepot.glance(message, flavor=flavor)
  223.     sender_id = message['from']['id']
  224.     expando_update(extras.provars, content_type=content_type, chat_type=chat_type, chat_id=chat_id, sender_id=sender_id)
  225.     extras.provars.sender_info = get_sender_info_summary(message)
  226.     extras.provars.chat_info = get_chat_info_summary(message)
  227.  
  228.     if content_type == 'text' :
  229.         command_expo = split_message_text(message['text'])
  230.         expando_update(extras.provars, command_expo)
  231.  
  232.         # useful in local server:
  233.         # pprint(extras.provars.__dict__)
  234.  
  235.         # Trivial method to process the command : dictionary look up:
  236.         command = extras.provars.command
  237.  
  238.         if not command :
  239.             act_no_command(command, message, extras)
  240.  
  241.         elif command in commands :
  242.             commands[command](command, message, extras)
  243.  
  244.         else :
  245.             act_bad_command(command, message, extras)
  246.  
  247.     else :
  248.         text = '{} says : You sent me a "{}" message.'.format(extras.bot_info.name, content_type)
  249.         bot = extras.bot_info.bot
  250.         bot.sendMessage(chat_id, text)
  251.  
  252.  
  253.  
  254. @app.route(bot_info.webhook_route, methods=['POST'])
  255. def route_bot_hook() :
  256.     g.proenv = proenv
  257.     g.bot_info = bot_info
  258.     g.provars = Expando() # TODO: create provars based on current request context
  259.     g.session = Expando() # TODO: create based on current user-bot pair
  260.  
  261.     update = request.get_json()
  262.     if 'message' in update:
  263.         # it's a chat message
  264.         message = update['message']
  265.         pprint(message)
  266.         handle_chat(message, g)
  267.  
  268.     return 'OK'
  269.  
  270. # useful command-line commands if webhook URL is not known at the time that flask starts
  271.  
  272. @app.cli.command(with_appcontext=True)
  273. @click.option('-u', '--url', prompt='URL?')
  274. def set_webhook(url) :
  275.     '''Set WEBHOOK for bot.'''
  276.     base_url = url
  277.     url = urllib.parse.urljoin(base_url, app.config['WEBHOOK_ROUTE'])
  278.     bot = bot_info.bot
  279.     res = bot.setWebhook(url, max_connections=1)
  280.     pprint(res)
  281.  
  282.  
  283. @app.cli.command(with_appcontext=False)
  284. def del_webhook() :
  285.     '''Delete WEBHOOK for bot.'''
  286.     bot = bot_info.bot
  287.     res = bot.deleteWebhook()
  288.     pprint(res)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement