;; SPDX-License-Identifier: EUPL-1.2 ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs (defpackage :ukkoclot/src/config (:documentation "Stuff for loading the configuration of the bot") (:nicknames :conf) (:use :c2cl :iterate :ukkoclot/src/rw-lock) (:export #:*config* #:config #:make-config #:config-p #:copy-config #:load-config #:print-default #:bot-name #:bot-token #:db-path #:dev-group #:owner)) (in-package :ukkoclot/src/config) (defstruct config (lock (make-rw-lock :name "config's lock") :type rw-lock :read-only t) (bot-name "Ukko's Clot" :type string) (bot-token "123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi" :type string) (db-path #P"./data.db" :type (or pathname string)) (dev-group -1001234567890 :type integer) (owner 12345678 :type integer)) (defvar *config* (make-config) "Bot's configuration") (defun bot-name (&optional (config *config*)) "Get the desired name for the bot" (with-slots (lock bot-name) config (with-read-lock (lock) bot-name))) (defun bot-token (&optional (config *config*)) "Get the API token for the bot" (with-slots (lock bot-token) config (with-read-lock (lock) bot-token))) (defun db-path (&optional (config *config*)) "Get the path to the bot's database" (with-slots (lock db-path) config (with-read-lock (lock) db-path))) (defun dev-group (&optional (config *config*)) "Get the ID of the dev/testing group" (with-slots (lock dev-group) config (with-read-lock (lock) dev-group))) (defun owner (&optional (config *config*)) "Get the ID of the bot's owner" (with-slots (lock owner) config (with-read-lock (lock) owner))) (defun load-config (filename &optional (config *config*)) "Load config from the given `filename'." (prog1 config (let ((data (with-open-file (f filename) (read f)))) (with-write-lock ((config-lock config)) (iter (for (kw-name value) on data by #'cddr) (let ((name (intern (symbol-name kw-name) :ukkoclot/src/config))) (setf (slot-value config name) value))))))) (defun serialize (config) "Serializes the config to a plist." (with-read-lock ((config-lock config)) (iter (for slot in (class-direct-slots (class-of config))) (let ((name (slot-definition-name slot))) (unless (eql name 'lock) (let ((kw-name (intern (symbol-name name) :keyword))) (appending (list kw-name (slot-value config name))))))))) (defun print-default (filename) "Prints the default config to the given `filename'." (with-open-file (f filename :direction :output :if-exists :supersede) (format f ";; lint:suppress in-package spdx-license-identifier~%") (format f ";; Copy this file to config.lisp and modify it there~%") (let ((data (serialize (make-config)))) (format f "~<(~;~@{~(~W~) ~W~^ ~_~}~;)~:>~%" data))))