feat(bot): update bot configuration management by adding support for custom config paths and reticulum config directories; update bot templates to accept new parameters

This commit is contained in:
Ivan
2026-04-15 06:53:07 -05:00
parent 6ec4114854
commit af5e52a430
3 changed files with 89 additions and 7 deletions
+35
View File
@@ -17,6 +17,11 @@ class BotHandler:
def __init__(self, identity_path, config_manager=None):
self.identity_path = os.path.abspath(identity_path)
self.config_manager = config_manager
self.bot_reticulum_config_dir = os.path.abspath(
os.path.expanduser(
os.environ.get("MESHCHAT_BOT_RETICULUM_CONFIG_DIR", "~/.reticulum"),
),
)
self.bots_dir = os.path.join(self.identity_path, "bots")
os.makedirs(self.bots_dir, exist_ok=True)
self.running_bots = {}
@@ -36,6 +41,14 @@ class BotHandler:
for entry in self.bots_state:
if "storage_dir" in entry:
entry["storage_dir"] = os.path.abspath(entry["storage_dir"])
if "bot_config_dir" in entry and entry["bot_config_dir"]:
entry["bot_config_dir"] = os.path.abspath(
os.path.expanduser(entry["bot_config_dir"]),
)
if "reticulum_config_dir" in entry and entry["reticulum_config_dir"]:
entry["reticulum_config_dir"] = os.path.abspath(
os.path.expanduser(entry["reticulum_config_dir"]),
)
except FileNotFoundError:
self.bots_state = []
except Exception:
@@ -156,6 +169,8 @@ class BotHandler:
"template_id": template_id,
"name": name or f"{template_id.title()} Bot",
"storage_dir": bot_storage_dir,
"bot_config_dir": os.path.join(bot_storage_dir, "config"),
"reticulum_config_dir": self.bot_reticulum_config_dir,
"enabled": True,
"pid": None,
}
@@ -164,6 +179,10 @@ class BotHandler:
bot_storage_dir = entry["storage_dir"]
entry["template_id"] = template_id
entry["name"] = name or entry.get("name") or f"{template_id.title()} Bot"
if not entry.get("bot_config_dir"):
entry["bot_config_dir"] = os.path.join(bot_storage_dir, "config")
if not entry.get("reticulum_config_dir"):
entry["reticulum_config_dir"] = self.bot_reticulum_config_dir
entry["enabled"] = True
os.makedirs(bot_storage_dir, exist_ok=True)
@@ -177,6 +196,10 @@ class BotHandler:
entry["name"],
"--storage",
bot_storage_dir,
"--config-path",
entry["bot_config_dir"],
"--reticulum-config-dir",
entry["reticulum_config_dir"],
]
proc = subprocess.Popen(cmd, cwd=bot_storage_dir) # noqa: S603
@@ -299,6 +322,18 @@ class BotHandler:
if not storage_dir:
return None
bot_config_dir = entry.get("bot_config_dir")
if bot_config_dir:
id_path_bot_cfg = os.path.join(bot_config_dir, "identity")
if os.path.exists(id_path_bot_cfg):
return id_path_bot_cfg
reticulum_config_dir = entry.get("reticulum_config_dir")
if reticulum_config_dir:
id_path_shared = os.path.join(reticulum_config_dir, "identity")
if os.path.exists(id_path_shared):
return id_path_shared
# LXMFy stores identity in the 'config' subdirectory by default
id_path = os.path.join(storage_dir, "config", "identity")
if os.path.exists(id_path):
+24 -4
View File
@@ -20,15 +20,35 @@ def main():
parser.add_argument("--template", required=True, choices=TEMPLATE_MAP.keys())
parser.add_argument("--name", required=True)
parser.add_argument("--storage", required=True)
parser.add_argument("--config-path", default=None)
parser.add_argument(
"--reticulum-config-dir",
default=os.environ.get(
"MESHCHAT_BOT_RETICULUM_CONFIG_DIR",
os.path.expanduser("~/.reticulum"),
),
)
args = parser.parse_args()
os.makedirs(args.storage, exist_ok=True)
os.chdir(args.storage)
config_path = args.config_path
if config_path:
config_path = os.path.abspath(os.path.expanduser(config_path))
else:
config_path = os.path.join(os.path.abspath(args.storage), "config")
os.makedirs(config_path, exist_ok=True)
reticulum_config_dir = os.path.abspath(os.path.expanduser(args.reticulum_config_dir))
os.makedirs(reticulum_config_dir, exist_ok=True)
BotCls = TEMPLATE_MAP[args.template]
# LXMFy hardcodes its config directory to os.path.join(os.getcwd(), 'config').
# By chdir'ing into args.storage, we ensure 'config' and data are kept within that folder.
bot_instance = BotCls(name=args.name, storage_path=args.storage, test_mode=False)
bot_instance = BotCls(
name=args.name,
storage_path=args.storage,
test_mode=False,
config_path=config_path,
reticulum_config_dir=reticulum_config_dir,
)
# Optional immediate announce for reachability
with contextlib.suppress(Exception):
+30 -3
View File
@@ -19,7 +19,14 @@ class StoppableBot:
class EchoBotTemplate(StoppableBot):
def __init__(self, name="Echo Bot", storage_path=None, test_mode=False):
def __init__(
self,
name="Echo Bot",
storage_path=None,
test_mode=False,
config_path=None,
reticulum_config_dir=None,
):
super().__init__()
self.bot = LXMFBot(
@@ -29,6 +36,8 @@ class EchoBotTemplate(StoppableBot):
first_message_enabled=True,
test_mode=test_mode,
storage_path=storage_path,
config_path=config_path,
reticulum_config_dir=reticulum_config_dir,
)
self.setup_commands()
self.setup_message_handlers()
@@ -97,7 +106,14 @@ class EchoBotTemplate(StoppableBot):
class NoteBotTemplate(StoppableBot):
def __init__(self, name="Note Bot", storage_path=None, test_mode=False):
def __init__(
self,
name="Note Bot",
storage_path=None,
test_mode=False,
config_path=None,
reticulum_config_dir=None,
):
super().__init__()
self.bot = LXMFBot(
@@ -107,6 +123,8 @@ class NoteBotTemplate(StoppableBot):
storage_type="json",
storage_path=storage_path or "data/notes",
test_mode=test_mode,
config_path=config_path,
reticulum_config_dir=reticulum_config_dir,
)
self.setup_commands()
@@ -176,7 +194,14 @@ class NoteBotTemplate(StoppableBot):
class ReminderBotTemplate(StoppableBot):
def __init__(self, name="Reminder Bot", storage_path=None, test_mode=False):
def __init__(
self,
name="Reminder Bot",
storage_path=None,
test_mode=False,
config_path=None,
reticulum_config_dir=None,
):
super().__init__()
self.bot = LXMFBot(
@@ -186,6 +211,8 @@ class ReminderBotTemplate(StoppableBot):
storage_type="sqlite",
storage_path=storage_path or "data/reminders.db",
test_mode=test_mode,
config_path=config_path,
reticulum_config_dir=reticulum_config_dir,
)
self.setup_commands()
self.bot.scheduler.add_task(