|
|
|
@ -4,6 +4,7 @@ import copy |
|
|
|
|
import json |
|
|
|
|
import pprint |
|
|
|
|
import threading |
|
|
|
|
import traceback |
|
|
|
|
|
|
|
|
|
from mastodon import Mastodon |
|
|
|
|
|
|
|
|
@ -34,10 +35,10 @@ class BotClient: |
|
|
|
|
kwargs = {}, |
|
|
|
|
daemon = True) |
|
|
|
|
|
|
|
|
|
def log_str(self, obj, infix = str()): |
|
|
|
|
def log_str(self, obj = "", infix = str()): |
|
|
|
|
return self.bot.log_str(obj, infix = "{}: {}".format(self.config["name"], infix)) |
|
|
|
|
|
|
|
|
|
def log(self, obj, infix = str()): |
|
|
|
|
def log(self, obj = "", infix = str()): |
|
|
|
|
return self.bot.log(obj, infix = "{}: {}".format(self.config["name"], infix)) |
|
|
|
|
|
|
|
|
|
def setup(self): |
|
|
|
@ -70,6 +71,7 @@ class BotClient: |
|
|
|
|
|
|
|
|
|
def start(self): |
|
|
|
|
self.poll_thread.start() |
|
|
|
|
self.on_start() |
|
|
|
|
|
|
|
|
|
def poll_loop(self): |
|
|
|
|
while True: |
|
|
|
@ -81,9 +83,9 @@ class BotClient: |
|
|
|
|
time.sleep(self.config["poll_interval"]) |
|
|
|
|
else: |
|
|
|
|
self.on_wake() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while len(statuses) > 0: |
|
|
|
|
self.on_poll_page(statuses) |
|
|
|
|
self.on_status_page(statuses) |
|
|
|
|
|
|
|
|
|
for status in sorted(statuses, |
|
|
|
|
key = lambda status: status["created_at"]): |
|
|
|
@ -93,15 +95,16 @@ class BotClient: |
|
|
|
|
with self.state_lock: |
|
|
|
|
self.state["min_status_id"] = status["id"] |
|
|
|
|
|
|
|
|
|
self.save_state() |
|
|
|
|
|
|
|
|
|
time.sleep(self.config["rate_limit"]) |
|
|
|
|
statuses = self.api.fetch_previous(statuses) |
|
|
|
|
|
|
|
|
|
except Exception as exc: |
|
|
|
|
self.save_state() |
|
|
|
|
|
|
|
|
|
except Exception as exc: |
|
|
|
|
self.on_poll_exception(exc) |
|
|
|
|
time.sleep(self.config["rate_limit"]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def load_state(self): |
|
|
|
|
with self.state_lock: |
|
|
|
|
self.state = self.on_load_state() |
|
|
|
@ -112,11 +115,14 @@ class BotClient: |
|
|
|
|
self.on_save_state(copy.deepcopy(self.state)) |
|
|
|
|
self.on_state_saved(self.state) |
|
|
|
|
|
|
|
|
|
def on_start(self): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def on_poll(self): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
def on_poll_exception(self, exc): |
|
|
|
|
pass |
|
|
|
|
self.log(traceback.format_exc()) |
|
|
|
|
|
|
|
|
|
def on_wake(self): |
|
|
|
|
pass |
|
|
|
@ -146,20 +152,25 @@ class BotClient: |
|
|
|
|
|
|
|
|
|
class Bot: |
|
|
|
|
DEFAULT_CONFIG = { |
|
|
|
|
"app_name": "Generic Bot", |
|
|
|
|
"rate_limit": 1, |
|
|
|
|
"poll_interval": 10, |
|
|
|
|
"name": "generic-bot", |
|
|
|
|
"defaults": { |
|
|
|
|
"app_name": "Generic Bot", |
|
|
|
|
"rate_limit": 1, |
|
|
|
|
"poll_interval": 10 |
|
|
|
|
}, |
|
|
|
|
"clients": { |
|
|
|
|
"mastodon.social": {}}} |
|
|
|
|
|
|
|
|
|
def __init__(self, client_type = BotClient, config = None): |
|
|
|
|
def __init__(self, client_type = BotClient, config = {}): |
|
|
|
|
self.clients = {} |
|
|
|
|
|
|
|
|
|
self.client_type = client_type |
|
|
|
|
self.config = config or self.DEFAULT_CONFIG |
|
|
|
|
|
|
|
|
|
self.config = {**self.DEFAULT_CONFIG, **config} |
|
|
|
|
self.config["defaults"] = {**self.DEFAULT_CONFIG["defaults"], **config.get("defaults", {})} |
|
|
|
|
|
|
|
|
|
def log_str(self, obj, infix = str()): |
|
|
|
|
prefix = "{}: {}".format(self.config["tag"], infix) |
|
|
|
|
prefix = "{}: {}".format(self.config["name"], infix) |
|
|
|
|
return prefix + log_obj_str(obj).replace("\n", "\n" + prefix) |
|
|
|
|
|
|
|
|
|
def log(self, *args, **kwargs): |
|
|
|
@ -172,17 +183,15 @@ class Bot: |
|
|
|
|
def on_start_clients(self, client_configs): |
|
|
|
|
clients = {} |
|
|
|
|
for client_name, client_config in client_configs.items(): |
|
|
|
|
client_config = {**{ |
|
|
|
|
"name": client_name, |
|
|
|
|
"app_name": self.config["app_name"], |
|
|
|
|
"rate_limit": self.config["rate_limit"], |
|
|
|
|
"poll_interval": self.config["poll_interval"], |
|
|
|
|
}, **client_config} |
|
|
|
|
client_config = { |
|
|
|
|
**self.config["defaults"], |
|
|
|
|
**{"name": client_name}, |
|
|
|
|
**client_config} |
|
|
|
|
client = self.on_init_client(client_name, client_config) |
|
|
|
|
client.setup() |
|
|
|
|
clients[client_config["name"]] = client |
|
|
|
|
|
|
|
|
|
start_interval = self.config["poll_interval"] / len(self.config["clients"]) |
|
|
|
|
start_interval = self.config["defaults"]["poll_interval"] / len(self.config["clients"]) |
|
|
|
|
for client in clients.values(): |
|
|
|
|
client.start() |
|
|
|
|
time.sleep(start_interval) |
|
|
|
|