Pass along ConfigParsers instead of file names
This commit is contained in:
parent
2f7502723b
commit
86472afb3f
4 changed files with 109 additions and 27 deletions
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
## Next version
|
## Next version
|
||||||
|
|
||||||
|
- change how config files are passed along
|
||||||
|
- change module system to support config file changes
|
||||||
|
|
||||||
# 1.0.0 (2019-04-13)
|
# 1.0.0 (2019-04-13)
|
||||||
|
|
||||||
- add fancy argument parsing
|
- add fancy argument parsing
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
from typing import Callable
|
from typing import Callable, Dict
|
||||||
|
|
||||||
from .bot import *
|
from .bot import *
|
||||||
from .client import *
|
from .client import *
|
||||||
|
|
@ -48,12 +49,33 @@ def enable_logging(name: str = "yaboli", level: int = logging.INFO) -> None:
|
||||||
logger.addHandler(handler)
|
logger.addHandler(handler)
|
||||||
|
|
||||||
def run(
|
def run(
|
||||||
client: Callable[[str], Client],
|
bot_constructor: BotConstructor,
|
||||||
config_file: str = "bot.conf"
|
config_file: str = "bot.conf",
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# Load the config file
|
||||||
|
config = configparser.ConfigParser(allow_no_value=True)
|
||||||
|
config.read(config_file)
|
||||||
|
|
||||||
async def _run() -> None:
|
async def _run() -> None:
|
||||||
while True:
|
while True:
|
||||||
client_ = client(config_file)
|
bot = bot_constructor(config, config_file)
|
||||||
await client_.run()
|
await bot.run()
|
||||||
|
|
||||||
|
asyncio.run(_run())
|
||||||
|
|
||||||
|
def run_modulebot(
|
||||||
|
modulebot_constructor: ModuleBotConstructor,
|
||||||
|
module_constructors: Dict[str, ModuleConstructor],
|
||||||
|
config_file: str = "bot.conf",
|
||||||
|
) -> None:
|
||||||
|
# Load the config file
|
||||||
|
config = configparser.ConfigParser(allow_no_value=True)
|
||||||
|
config.read(config_file)
|
||||||
|
|
||||||
|
async def _run() -> None:
|
||||||
|
while True:
|
||||||
|
modulebot = modulebot_constructor(config, config_file,
|
||||||
|
module_constructors)
|
||||||
|
await modulebot.run()
|
||||||
|
|
||||||
asyncio.run(_run())
|
asyncio.run(_run())
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import configparser
|
import configparser
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Optional
|
from typing import Callable, List, Optional
|
||||||
|
|
||||||
from .client import Client
|
from .client import Client
|
||||||
from .command import *
|
from .command import *
|
||||||
|
|
@ -11,7 +11,7 @@ from .util import *
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
__all__ = ["Bot"]
|
__all__ = ["Bot", "BotConstructor"]
|
||||||
|
|
||||||
class Bot(Client):
|
class Bot(Client):
|
||||||
ALIASES: List[str] = []
|
ALIASES: List[str] = []
|
||||||
|
|
@ -25,12 +25,13 @@ class Bot(Client):
|
||||||
GENERAL_SECTION = "general"
|
GENERAL_SECTION = "general"
|
||||||
ROOMS_SECTION = "rooms"
|
ROOMS_SECTION = "rooms"
|
||||||
|
|
||||||
def __init__(self, config_file: str) -> None:
|
def __init__(self,
|
||||||
|
config: configparser.ConfigParser,
|
||||||
|
config_file: str,
|
||||||
|
) -> None:
|
||||||
|
self.config = config
|
||||||
self.config_file = config_file
|
self.config_file = config_file
|
||||||
|
|
||||||
self.config = configparser.ConfigParser(allow_no_value=True)
|
|
||||||
self.config.read(self.config_file)
|
|
||||||
|
|
||||||
nick = self.config[self.GENERAL_SECTION].get("nick")
|
nick = self.config[self.GENERAL_SECTION].get("nick")
|
||||||
if nick is None:
|
if nick is None:
|
||||||
logger.warn(("'nick' not set in config file. Defaulting to empty"
|
logger.warn(("'nick' not set in config file. Defaulting to empty"
|
||||||
|
|
@ -188,3 +189,5 @@ class Bot(Client):
|
||||||
logger.info(f"Restarted in &{room.name} by {message.sender.atmention}")
|
logger.info(f"Restarted in &{room.name} by {message.sender.atmention}")
|
||||||
await message.reply(self.RESTART_REPLY)
|
await message.reply(self.RESTART_REPLY)
|
||||||
await self.stop()
|
await self.stop()
|
||||||
|
|
||||||
|
BotConstructor = Callable[[configparser.ConfigParser, str], Bot]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, List, Optional
|
from typing import Callable, Dict, List, Optional
|
||||||
|
|
||||||
from .bot import Bot
|
from .bot import Bot
|
||||||
from .command import *
|
from .command import *
|
||||||
|
|
@ -10,49 +11,77 @@ from .util import *
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
__all__ = ["Module", "ModuleBot"]
|
__all__ = ["Module", "ModuleConstructor", "ModuleBot", "ModuleBotConstructor"]
|
||||||
|
|
||||||
class Module(Bot):
|
class Module(Bot):
|
||||||
DESCRIPTION: Optional[str] = None
|
DESCRIPTION: Optional[str] = None
|
||||||
|
|
||||||
def __init__(self, config_file: str, standalone: bool) -> None:
|
def __init__(self,
|
||||||
super().__init__(config_file)
|
config: configparser.ConfigParser,
|
||||||
|
config_file: str,
|
||||||
|
standalone: bool = True,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(config, config_file)
|
||||||
|
|
||||||
self.standalone = standalone
|
self.standalone = standalone
|
||||||
|
|
||||||
|
ModuleConstructor = Callable[[configparser.ConfigParser, str, bool], Module]
|
||||||
|
|
||||||
class ModuleBot(Bot):
|
class ModuleBot(Bot):
|
||||||
HELP_PRE: Optional[List[str]] = [
|
HELP_PRE: Optional[List[str]] = [
|
||||||
"This bot contains the following modules:"
|
"This bot contains the following modules:"
|
||||||
]
|
]
|
||||||
HELP_POST: Optional[List[str]] = [
|
HELP_POST: Optional[List[str]] = [
|
||||||
""
|
"",
|
||||||
"Use \"!help {atmention} <module>\" to get more information on a"
|
"For module-specific help, try \"!help {atmention} <module>\".",
|
||||||
" specific module."
|
|
||||||
]
|
]
|
||||||
MODULE_HELP_LIMIT = 5
|
MODULE_HELP_LIMIT = 5
|
||||||
|
|
||||||
def __init__(self, config_file: str) -> None:
|
MODULES_SECTION = "modules"
|
||||||
super().__init__(config_file)
|
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
config: configparser.ConfigParser,
|
||||||
|
config_file: str,
|
||||||
|
module_constructors: Dict[str, ModuleConstructor],
|
||||||
|
) -> None:
|
||||||
|
super().__init__(config, config_file)
|
||||||
|
|
||||||
|
self.module_constructors = module_constructors
|
||||||
self.modules: Dict[str, Module] = {}
|
self.modules: Dict[str, Module] = {}
|
||||||
|
|
||||||
self.register_botrulez(help_=False)
|
# Load initial modules
|
||||||
self.register_general("help", self.cmd_help_general, args=False)
|
for module_name in self.config[self.MODULES_SECTION]:
|
||||||
self.register_specific("help", self.cmd_help_specific, args=True)
|
module_constructor = self.module_constructors.get(module_name)
|
||||||
|
if module_constructor is None:
|
||||||
|
logger.warn(f"Module {module_name} not found")
|
||||||
|
continue
|
||||||
|
# standalone is set to False
|
||||||
|
module = module_constructor(self.config, self.config_file, False)
|
||||||
|
self.load_module(module_name, module)
|
||||||
|
|
||||||
def register_module(self, name: str, module: Module) -> None:
|
def load_module(self, name: str, module: Module) -> None:
|
||||||
if name in self.modules:
|
if name in self.modules:
|
||||||
logger.warn(f"Module {name!r} is already registered, overwriting...")
|
logger.warn(f"Module {name!r} is already registered, overwriting...")
|
||||||
self.modules[name] = module
|
self.modules[name] = module
|
||||||
|
|
||||||
|
def unload_module(self, name: str) -> None:
|
||||||
|
if name in self.modules:
|
||||||
|
del self.modules[name]
|
||||||
|
|
||||||
|
# Better help messages
|
||||||
|
|
||||||
def compile_module_overview(self) -> List[str]:
|
def compile_module_overview(self) -> List[str]:
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
if self.HELP_PRE is not None:
|
if self.HELP_PRE is not None:
|
||||||
lines.extend(self.HELP_PRE)
|
lines.extend(self.HELP_PRE)
|
||||||
|
|
||||||
|
any_modules = False
|
||||||
|
|
||||||
modules_without_desc: List[str] = []
|
modules_without_desc: List[str] = []
|
||||||
for module_name in sorted(self.modules):
|
for module_name in sorted(self.modules):
|
||||||
|
any_modules = True
|
||||||
|
|
||||||
module = self.modules[module_name]
|
module = self.modules[module_name]
|
||||||
|
|
||||||
if module.DESCRIPTION is None:
|
if module.DESCRIPTION is None:
|
||||||
|
|
@ -62,7 +91,10 @@ class ModuleBot(Bot):
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
|
|
||||||
if modules_without_desc:
|
if modules_without_desc:
|
||||||
lines.append(", ".join(modules_without_desc))
|
lines.append("\t" + ", ".join(modules_without_desc))
|
||||||
|
|
||||||
|
if not any_modules:
|
||||||
|
lines.append("No modules loaded.")
|
||||||
|
|
||||||
if self.HELP_POST is not None:
|
if self.HELP_POST is not None:
|
||||||
lines.extend(self.HELP_POST)
|
lines.extend(self.HELP_POST)
|
||||||
|
|
@ -79,8 +111,7 @@ class ModuleBot(Bot):
|
||||||
|
|
||||||
return module.HELP_SPECIFIC
|
return module.HELP_SPECIFIC
|
||||||
|
|
||||||
# Overwriting the botrulez help function
|
async def cmd_modules_help(self,
|
||||||
async def cmd_help_specific(self,
|
|
||||||
room: Room,
|
room: Room,
|
||||||
message: LiveMessage,
|
message: LiveMessage,
|
||||||
args: SpecificArgumentData
|
args: SpecificArgumentData
|
||||||
|
|
@ -100,6 +131,12 @@ class ModuleBot(Bot):
|
||||||
|
|
||||||
# Sending along all kinds of events
|
# Sending along all kinds of events
|
||||||
|
|
||||||
|
async def on_connected(self, room: Room) -> None:
|
||||||
|
await super().on_connected(room)
|
||||||
|
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module.on_connected(room)
|
||||||
|
|
||||||
async def on_snapshot(self, room: Room, messages: List[LiveMessage]) -> None:
|
async def on_snapshot(self, room: Room, messages: List[LiveMessage]) -> None:
|
||||||
await super().on_snapshot(room, messages)
|
await super().on_snapshot(room, messages)
|
||||||
|
|
||||||
|
|
@ -141,6 +178,18 @@ class ModuleBot(Bot):
|
||||||
for module in self.modules.values():
|
for module in self.modules.values():
|
||||||
await module.on_edit(room, message)
|
await module.on_edit(room, message)
|
||||||
|
|
||||||
|
async def on_login(self, room: Room, account_id: str) -> None:
|
||||||
|
await super().on_login(room, account_id)
|
||||||
|
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module.on_login(room, account_id)
|
||||||
|
|
||||||
|
async def on_logout(self, room: Room) -> None:
|
||||||
|
await super().on_logout(room)
|
||||||
|
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module.on_logout(room)
|
||||||
|
|
||||||
async def on_pm(self,
|
async def on_pm(self,
|
||||||
room: Room,
|
room: Room,
|
||||||
from_id: str,
|
from_id: str,
|
||||||
|
|
@ -158,3 +207,8 @@ class ModuleBot(Bot):
|
||||||
|
|
||||||
for module in self.modules.values():
|
for module in self.modules.values():
|
||||||
await module.on_disconnect(room, reason)
|
await module.on_disconnect(room, reason)
|
||||||
|
|
||||||
|
ModuleBotConstructor = Callable[
|
||||||
|
[configparser.ConfigParser, str, Dict[str, ModuleConstructor]],
|
||||||
|
Bot
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue