from flask import Flask, render_template, make_response
from flask_paginate import Pagination, get_page_parameter, get_page_args
from flask_caching import Cache
from flask import request
import pendulum
import subprocess
import base64
import os
import textwrap
import sys
base_path = "/messagebase"
app = Flask(__name__, static_url_path=base_path + "/static")
@app.template_filter("datefmt")
def format_datetime(value):
# dt = pendulum.from_timestamp(value, tz=pendulum.tz.local_timezone())
dt = pendulum.from_timestamp(value)
return dt.to_datetime_string()
# Check Configuring Flask-Caching section for more details
# cache = Cache(app, config={"CACHE_TYPE": "filesystem", "CACHE_DIR": "cache"})
cache = Cache(
app, config={"CACHE_TYPE": "redis", "CACHE_REDIS_HOST": "redis"}
)
# cache = Cache(app, config={"CACHE_TYPE": "redis", "CACHE_REDIS_HOST": "olympus"})
# import jammin
import sqlite3
dbconnect = sqlite3.connect("db/message.sqlite3")
dbc = dbconnect.cursor()
bases = {
"FSXNET-General": "fsx_gen",
"FSXNET-Ads": "fsx_ads",
"FSXNET-BBS": "fsx_bbs",
"FSXNET-BOT": "fsx_bot",
# "FSXNET-Encryption": "msgs/fsx_cry",
"FSXNET-Ham Radio": "fsx_ham",
# "FSXNET-Magicka": "msgs/fsx_mag",
"FSXNET-Magicka": "fsx_mag",
"FSXNET-Mystic": "fsx_mys",
"FSXNET-Enigma": "fsx_eng",
# "HappyNet-General": "msgs/hpy_gen",
}
def bbs_get_messages(area):
global dbc
messages = []
for row in dbc.execute(
# "SELECT message_id, to_user_name, from_user_name, subject, modified_timestamp from message WHERE area_tag=?",
"SELECT message_id, to_user_name, from_user_name, subject, modified_timestamp from message WHERE area_tag=? ORDER BY message_id;",
(area,),
):
stamp = pendulum.parse(row[4]).timestamp()
messages.append(
{
"MsgNum": row[0],
"number": row[0],
"to": row[1],
"from": row[2],
"subject": row[3],
"written": stamp,
# // written
# // received
# // processed
}
)
return messages
def bbs_message(area, msgno):
global dbc
messages = []
dbc.execute(
"SELECT message_id, to_user_name, from_user_name, subject, modified_timestamp, message from message WHERE message_id=?",
(msgno,),
)
row = dbc.fetchone()
stamp = pendulum.parse(row[4]).timestamp()
return {
"MsgNum": row[0],
"number": row[0],
"to": row[1],
"from": row[2],
"subject": row[3],
"written": stamp,
"received": stamp,
"processed": stamp,
"text": row[5], # .decode("cp437"),
"bytes": row[5].encode("cp437")
# // written
# // received
# // processed
}
# bases = {"FSX_BOT": "fsx_bot"}
# @cache.memoize(timeout=5 * 60, key_prefix="messages")
@cache.memoize(timeout=5 * 60)
def get_messages(base):
messages = bbs_get_messages(base)
messages.reverse()
return messages
@cache.memoize(timeout=60)
def get_message(base, msgno):
# message = jammin.read_message(base, msgno)
message = bbs_message(base, msgno)
return message
@app.errorhandler(404)
def not_found(e):
return render_template("404.html")
@app.route(base_path + "/list")
def list_bases():
return render_template(
"list.html", bases=bases, base_path=base_path, title="Message Areas"
)
# return 'Here would be a listing of message bases'
@app.route(base_path + "/clear")
def clear_cache():
cache.clear()
return "Cache Cleared. Back to hitting refresh!"
@app.route(base_path + "/messages/")
def display_messages(area):
if area not in bases:
return render_template(
"missing-area.html", base_path=base_path, title="Missing Area"
)
# messages = jammin.get_messages(bases[area])
messages = get_messages(bases[area])
# messages.reverse() # cached.reverse()
page = request.args.get(get_page_parameter(), type=int, default=1)
# get_page_arg defaults to page 1, per_page of 10
PER_PAGE = 50
total = len(messages)
pagination = Pagination(
page=page,
total=total,
css_framework="foundation",
record_name="messages",
per_page=PER_PAGE,
)
page, per_page, offset = get_page_args()
start = (page - 1) * PER_PAGE
end = start + PER_PAGE
# messages = messages[(page-1) * PER_PAGE:offset+PER_PAGE]
messages = messages[start:end]
return render_template(
"messages.html",
messages=messages,
area=area,
pagination=pagination,
base_path=base_path,
title="Messages for " + bases[area],
)
@cache.memoize(timeout=60)
def ansi_to_png(raw_ansi_bytes, idx):
pid = os.getppid()
ansifile = "{0}-{1}.ans".format(idx, pid)
pngfile = "{0}-{1}.png".format(idx, pid)
with open(ansifile, "wb") as fp:
fp.write(raw_ansi_bytes)
subprocess.run(["./ansilove", "-d", "-o", pngfile, ansifile])
with open(pngfile, "rb") as fp:
png = fp.read()
os.unlink(ansifile)
os.unlink(pngfile)
return png
def ansi_to_png64(raw_ansi_bytes, idx):
png = ansi_to_png(raw_ansi_bytes, idx)
return base64.b64encode(png).decode("utf-8")
@app.route(base_path + "/image//.png")
def display_ansi(area, msgno):
if area not in bases:
return "RATS", 404
message = get_message(bases[area], msgno)
if not message:
return "RATS", 404
if not "text" in message:
return "RATS", 404
# png = ansi_to_png(message["bytes"].replace(b"\r", b"\n"), msgno)
png = ansi_to_png(message["bytes"], msgno)
# png = ansi_to_png(message["bytes"].replace("\r", "\n"), msgno)
response = make_response(png)
response.headers.set("Content-Type", "image/png")
return response
#
/")
def display_message(area, msgno):
if area not in bases:
return render_template(
"missing-area.html", base_path=base_path, title="Missing Area"
)
# message = jammin.read_message(bases[area], msgno)
message = get_message(bases[area], msgno)
if not message:
return render_template(
"missing-message.html",
base_path=base_path,
area=area,
title="Missing Message",
)
messages = get_messages(bases[area])
# prevmsg and nextmsg are completely different now.
prevmsg = None
nextmsg = None
total = len(messages)
for idx, msg in enumerate(messages):
if msg["MsgNum"] == msgno:
# Ok, found what we're looking for
if idx > 0:
prevmsg = messages[idx - 1]["MsgNum"]
if idx + 1 < total:
nextmsg = messages[idx + 1]["MsgNum"]
# prevmsg = None
# nextmsg = None
# if msgno > 1:
# prevmsg = msgno - 1
# if msgno < total:
# nextmsg = msgno + 1
if "text" in message:
if "\x1b" in message["text"]:
# Ok, the message contains ANSI CODES -- Convert
message["png"] = True
# message["png"] = ansi_to_png64(
# message["bytes"].replace(b"\r", b"\n"), msgno
# )
else:
text = message["text"].replace("\r", "\n")
# Ok, latest changes aren't doing word-wrap for us, so do it here.
text = "\n".join(
[
textwrap.fill(txt, width=78, replace_whitespace=False)
for txt in text.splitlines()
]
)
message["text"] = text
# message["text"].replace("\r", "\n") #
\n")
return render_template(
"message.html",
message=message,
area=area,
msgnumber=msgno,
prevmsg=prevmsg,
nextmsg=nextmsg,
base_path=base_path,
title="Message {0}".format(msgno),
)