I've finished my Python Bot for telegram to send HTML5 games through the chat, thanks to the help of this community! Unfortunately it seems that in order for the bot to fetch the score, I need to actually set up a HTTP server within the bot to do so. As it seems through my research, I can't seem to figure out how to create a server in python with ssl, without it being self signed (since it will give a blank page when the user clicks to play the game).
I bought a domain and it's already set up with my VPS IP adress, altough I have a ssl certificate for Apache...
Could someone help me set this up? Since sending and unsecured HTTP connection or a self-signed one will result in a blank page within the app...
Thank you very much!
Edit1: Bot Code:
import configparser, threading, requests, json, re, time, sys
from uuid import uuid4
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram import InlineQueryResultGame, ParseMode, InputTextMessageContent
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, InlineQueryHandler, CommandHandler, CallbackContext
from http.server import HTTPServer, BaseHTTPRequestHandler
def error_callback(update, context):
logger.warning('Update "%s" caused error "%s"', update, context.error)
class Global:
def __init__(self):
return
class GameHTTPRequestHandler(BaseHTTPRequestHandler):
def __init__(self, *args):
BaseHTTPRequestHandler.__init__(self, *args)
def do_GET(self):
if "#" in self.path:
self.path = self.path.split("#")[0]
if "?" in self.path:
(route, params) = self.path.split("?")
else:
route = self.path
params = ""
route = route[1:]
params = params.split("&")
if route in Global.games:
self.send_response(200)
self.end_headers()
self.wfile.write(open(route+'.html', 'rb').read())
elif route == "setScore":
params = {}
for item in self.path.split("?")[1].split("&"):
if "=" in item:
pair = item.split("=")
params[pair[0]] = pair[1]
print(params)
if "imid" in params:
Global.bot.set_game_score(params["uid"], params["score"], inline_message_id=params["imid"])
else:
Global.bot.set_game_score(params["uid"], params["score"], message_id=params["mid"], chat_id=params["cid"])
self.send_response(200)
self.end_headers()
self.wfile.write(b'Set score')
else:
self.send_response(404)
self.end_headers()
self.wfile.write(b'Invalid game!')
def start(update, context):
Global.bot.send_game(update.message.chat_id, Global.featured)
def error(update, context):
print(update, error)
def button(update, context):
print(update)
query = update.callback_query
game = query.game_short_name
uid = str(query.from_user.id)
if query.message:
mid = str(query.message.message_id)
cid = str(query.message.chat.id)
url = "http://" + Global.host + ":"+Global.port + "/" + game + "?uid="+uid+"&mid="+mid+"&cid="+cid
else:
imid = update.callback_query.inline_message_id
url = "http://" + Global.host + ":"+Global.port + "/" + game + "?uid="+uid+"&imid="+imid
print(url)
Global.bot.answer_callback_query(query.id, text=game, url=url)
def inlinequery(update, context):
query = update.inline_query.query
results = []
for game in Global.games:
if query.lower() in game.lower():
results.append(InlineQueryResultGame(id=str(uuid4()),game_short_name=game))
Global.update.inline_query.answer(results)
def main():
config = configparser.ConfigParser()
config.read('config.ini')
token = config['DEFAULT']['API_KEY']
Global.games = config['DEFAULT']['GAMES'].split(',')
Global.host = config['DEFAULT']['HOST']
Global.port = config['DEFAULT']['PORT']
Global.featured = config['DEFAULT']['FEATURED']
updater = Updater(token=token, use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler('start', start))
dp.add_handler(InlineQueryHandler(inlinequery))
dp.add_handler(CallbackQueryHandler(button))
dp.add_error_handler(error)
Global.bot = updater.bot
print("Polling telegram")
updater.start_polling()
print("Starting http server")
http = HTTPServer((Global.host, int(Global.port)), GameHTTPRequestHandler)
http.serve_forever()
if __name__ == '__main__':
main()
Code inside the HTML5 Game, related to the score:
function gameOver() {
isGameOver = true;
clearInterval(gameInterval);
const urlParams = new URLSearchParams(window.location.search);
const uid = urlParams.get('uid');
const mid = urlParams.get('mid');
const cid = urlParams.get('cid');
const imid = urlParams.get('imid');
if (imid) {
const request = new Request(`/setScore?uid=${uid}&imid=${imid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
}
else {
const request = new Request(`/setScore?uid=${uid}&mid=${mid}&cid=${cid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
}
}
Original Bot by Mark Powers
After some clarifications about the question the comments, let me try to make some comments. This is probably far from a ready-to-use solution and more some hints on what to look for.
The ultimate goal is to trigger a setGameScore
request from a HTML5 + JS webpage, while having that webpage properly SSL encrypted. That page can either be hosted independently of the bot, in which case the JS code should make the request itself (method 1 below), or is hosted via a python-based webserver within the same script as the bot (methods 2 + 3 below), in which case the goals would be to
Currently your JS code does something like
const request = new Request(`/setScore?uid=${uid}&imid=${imid}&score=${score}`);
fetch(request).then(response => console.log("set score"));
My knowledge of JS is limited, but judging by sources like this it seems like
fetch("https://api.telegram.org/botTOKEN/setGameScore?...").then(response => console.log("set score"));
should already do the trick
BaseHTTPRequestHandler
This seems to be a more general topic. E.g. I found these similar looking questions:
I.e. make the BaseHTTPRequestHandler
listen to "localhost" and have Apache/Nginx forward traffic to the correct port. Inspiration for this basically comes from here. In this case, encrypting apache/nginx with letsencrypt should be rather straightforward.