FireBot/threads.py

159 lines
5 KiB
Python

#!/usr/bin/python3
import bare, pylast
import config as conf
import random as r
from logs import log
from typing import Any, Callable, NoReturn
from threading import Thread
from time import sleep
from traceback import format_exc
def is_dead(thr: Thread) -> bool:
thr.join(timeout=0)
return not thr.is_alive()
def threadWrapper(data: dict) -> NoReturn:
if not data["noWrap"]:
while 1:
if data["ignoreErrors"]:
try:
data["func"](*data["args"])
except Exception:
Err = format_exc()
for line in Err.split("\n"):
log(line, "Thread", "WARN")
else:
try:
data["func"](*data["args"])
except Exception:
Err = format_exc()
for line in Err.split("\n"):
log(line, "Thread", "CRASH")
exit(1)
sleep(data["interval"])
log("Threaded loop broken", "Thread", "FATAL")
else:
data["func"](*data["args"])
exit(1)
def startThread(data: dict) -> Thread:
t = Thread(target=threadWrapper, args=(data,))
t.daemon = True
t.start()
return t
def threadManager(
threads: dict[str, dict[str, Any]],
output: bool = False,
mgr: str = "TManager",
interval: int = 60,
) -> NoReturn:
if output:
log("Begin init of thread manager", mgr)
running = {}
for name in threads:
data = threads[name]
running[name] = startThread(data)
if output:
log("All threads running, starting checkup loop", mgr)
while 1:
sleep(interval)
if output:
log("Checking threads", mgr)
for name in running:
t = running[name]
if is_dead(t):
if output:
log(f"Thread {name} has died, restarting", mgr, "WARN")
data = threads[name]
running[name] = startThread(data)
log("Thread manager loop broken", mgr, "FATAL")
exit(1)
def radio(instance: bare.bot) -> NoReturn:
lastTrack = ""
complained = False
firstMiss = False
misses = 0
missChunk = 0
missCap = -5
perChunk = 10
debug = False # instance.server == "replirc"
while 1:
try:
newTrack = instance.lastfmLink.get_user("Firepup650").get_now_playing()
if newTrack:
if complained:
complained = False
misses = 0
missChunk = 0
elif misses > missCap:
missChunk += 1
if missChunk >= perChunk:
misses -= 1
missChunk = 0
thisTrack = newTrack.__str__()
if thisTrack != lastTrack:
lastTrack = thisTrack
instance.msg("f.sp " + thisTrack, "#fp-radio")
instance.sendraw(
f"TOPIC #fp-radio :Firepup radio ({thisTrack}) - https://open.spotify.com/playlist/4ctNy3O0rOwhhXIKyLvUZM"
)
elif not complained:
missChunk = 0
if misses < 0:
misses += 1
if debug:
instance.msg(
str(
{
"misses": misses,
"missChunk": missChunk,
"misses exceed or meet limit": misses <= missCap,
}
),
"#fp-radio-debug",
)
sleep(2)
continue
instance.msg(
"Firepup seems to have stopped the music by mistake :/", "#fp-radio"
)
instance.sendraw(
"TOPIC #fp-radio :Firepup radio (Offline) - https://open.spotify.com/playlist/4ctNy3O0rOwhhXIKyLvUZM"
)
complained = True
lastTrack = "null"
except Exception:
Err = format_exc()
for line in Err.split("\n"):
instance.log(line, "WARN")
if debug:
instance.msg(
str(
{
"misses": misses,
"missChunk": missChunk,
"misses exceed or meet limit": misses <= missCap,
}
),
"#fp-radio-debug",
)
sleep(2)
instance.log("Thread while loop broken", "FATAL")
exit(1)
def ping(instance: bare.bot) -> NoReturn:
while 1:
instance.sendraw("PING :keepalive")
sleep(30)
data: dict[str, dict[str, Any]] = {
"radio": {"noWrap": True, "func": radio, "passInstance": True},
"pingMon": {"noWrap": True, "func": ping, "passInstance": True}
}