From 191a27fd142af7a14ca6ad1abcd293f09e63f6ad Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Mon, 13 Oct 2025 05:21:41 +0300 Subject: Move serializing stuff from bot/impl to a new file --- README.md | 2 ++ src/bot/impl.lisp | 61 ++------------------------------------------ src/enum.lisp | 2 +- src/main.lisp | 3 ++- src/serializing.lisp | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ src/tg/type-macros.lisp | 2 +- 6 files changed, 76 insertions(+), 62 deletions(-) create mode 100644 src/serializing.lisp diff --git a/README.md b/README.md index 2420d5d..daa9788 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ When running in a debuggy environment, consider (log:config :debug) ``` +When connecting via remote SWANK, you might want to run `(log:config :sane2)`. + # Licensing European Union Public Licence, version 1.2. diff --git a/src/bot/impl.lisp b/src/bot/impl.lisp index 652e2f7..93e63f5 100644 --- a/src/bot/impl.lisp +++ b/src/bot/impl.lisp @@ -6,67 +6,16 @@ (:import-from :cl+ssl) (:import-from :dex) (:import-from :log) + (:import-from :ukkoclot/serializing :fixup-args :parse-value) (:import-from :ukkoclot/strings :lisp->snake-case) (:local-nicknames (:jzon :com.inuoe.jzon)) (:export - :bot :bot-p :make-bot :fixup-value :do-call :parse-value + :bot :bot-p :make-bot :do-call :bot-config :bot-db :bot-base-uri :bot-power-on :bot-username% :bot-id%)) (in-package :ukkoclot/bot/impl) -(defgeneric parse-value (type json) - (:documentation "Parse value of TYPE from the parsed JSON") - (:method (type json) - (log:error "I don't know how to parse simple type ~A!" type) - (error "I don't know how to parse simple type ~A!" type)) - (:method ((type (eql 'boolean)) json) - (check-type json boolean) - json) - (:method ((type (eql 'integer)) json) - (check-type json integer) - json) - (:method ((type (eql 'null)) json) - (check-type json null) - json) - (:method ((type (eql 'string)) json) - (check-type json string) - json)) - -(defun try-parse-value (type json) - (handler-case (values t (parse-value type json)) - (error () (values nil nil)))) - -(defmethod parse-value ((type cons) json) - (cond ((and (eq (car type) 'array) - (null (cddr type))) - (when json - (let ((element-type (cadr type))) - (iter (for element in-vector json) - (collect (parse-value element-type element) result-type vector))))) - ((eq (car type) 'or) - (iter (for el-type in (cdr type)) - (multiple-value-bind (success res) (try-parse-value el-type json) - (when success - (return res))) - (finally - (error "Failed to parse ~S as ~A!" json type)))) - (t - (error "I don't know how to parse complex type ~A!" type)))) - -(defgeneric fixup-value (value) - (:documentation "Fixup top-level VALUE before passing it onto telegram") - (:method (value) - (jzon:stringify value :pretty *print-pretty*)) - (:method ((value null)) - value) - (:method ((value number)) - value) - (:method ((value pathname)) - value) - (:method ((value string)) - value)) - (defstruct (bot (:constructor make-bot%)) (config (error "No value given for config") :read-only t) (db (error "No value given for DB") :read-only t) @@ -81,12 +30,6 @@ (config-bot-token config) "/"))) (make-bot% :config config :db db :base-uri base-uri))) -(defun fixup-args (args) - (iter (for (key . value) in args) - (collect - (cons (string-downcase (lisp->snake-case (symbol-name key))) - (fixup-value value))))) - (defun req (uri method content) (let ((retrier (dex:retry-request 5 :interval 1))) (handler-case (dex:request uri :method method :content content) diff --git a/src/enum.lisp b/src/enum.lisp index e3ceb6b..8943a90 100644 --- a/src/enum.lisp +++ b/src/enum.lisp @@ -2,7 +2,7 @@ ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs (defpackage :ukkoclot/enum (:use :c2cl :iterate) - (:import-from :ukkoclot/bot/impl :fixup-value :parse-value) + (:import-from :ukkoclot/serializing :fixup-value :parse-value) (:import-from :string-case :string-case) (:local-nicknames (:jzon :com.inuoe.jzon)) diff --git a/src/main.lisp b/src/main.lisp index a113ab0..d418b78 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -6,8 +6,9 @@ (:import-from :anaphora :acond :awhen :it) (:import-from :log) (:import-from :swank) - (:import-from :ukkoclot/bot :make-bot :bot-power-on :fixup-value) + (:import-from :ukkoclot/bot :make-bot :bot-power-on) (:import-from :ukkoclot/db :with-db) + (:import-from :ukkoclot/serializing :fixup-value) (:import-from :ukkoclot/strings :escape-xml :is-tg-whitespace-str :starts-with :starts-with-ignore-case) (:local-nicknames (:jzon :com.inuoe.jzon)) diff --git a/src/serializing.lisp b/src/serializing.lisp new file mode 100644 index 0000000..7fafb3a --- /dev/null +++ b/src/serializing.lisp @@ -0,0 +1,68 @@ +;; SPDX-License-Identifier: EUPL-1.2 +;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs +(defpackage :ukkoclot/serializing + (:use :c2cl :iterate) + (:import-from :log) + (:import-from :ukkoclot/strings :lisp->snake-case) + (:local-nicknames + (:jzon :com.inuoe.jzon)) + (:export :fixup-args :fixup-value :parse-value :try-parse-value)) +(in-package :ukkoclot/serializing) + +(defun fixup-args (args) + (iter (for (key . value) in args) + (collect + (cons (string-downcase (lisp->snake-case (symbol-name key))) + (fixup-value value))))) + +(defgeneric fixup-value (value) + (:documentation "Fixup outgoing *top-level* `value' before passing it to telegram.") + (:method (value) + (jzon:stringify value :pretty *print-pretty*)) + (:method ((value null)) + value) + (:method ((value number)) + value) + (:method ((value pathname)) + value) + (:method ((value string)) + value)) + +(defgeneric parse-value (type json) + (:documentation "Parse incoming value of `type' from the parsed `json'.") + (:method (type json) + (log:error "I don't know how to parse simple type ~A!" type) + (error "I don't know how to parse simple type ~A!" type)) + (:method ((type (eql 'boolean)) json) + (check-type json boolean) + json) + (:method ((type (eql 'integer)) json) + (check-type json integer) + json) + (:method ((type (eql 'null)) json) + (check-type json null) + json) + (:method ((type (eql 'string)) json) + (check-type json string) + json)) + +(defmethod parse-value ((type cons) json) + (cond ((and (eq (car type) 'array) + (null (cddr type))) + (when json + (let ((element-type (cadr type))) + (iter (for element in-vector json) + (collect (parse-value element-type element) result-type vector))))) + ((eq (car type) 'or) + (iter (for el-type in (cdr type)) + (multiple-value-bind (success res) (try-parse-value el-type json) + (when success + (return res))) + (finally + (error "Failed to parse ~S as ~A!" json type)))) + (t + (error "I don't know how to parse complex type ~A!" type)))) + +(defun try-parse-value (type json) + (handler-case (values t (parse-value type json)) + (error () (values nil nil)))) diff --git a/src/tg/type-macros.lisp b/src/tg/type-macros.lisp index 7380a6d..552c908 100644 --- a/src/tg/type-macros.lisp +++ b/src/tg/type-macros.lisp @@ -2,7 +2,7 @@ ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs (defpackage :ukkoclot/tg/type-macros (:use :c2cl :iterate) - (:import-from :ukkoclot/bot/impl :parse-value) + (:import-from :ukkoclot/serializing :parse-value) (:import-from :ukkoclot/hash-tables :gethash-lazy) (:import-from :ukkoclot/strings :lisp->snake-case) (:local-nicknames -- cgit v1.2.3