diff options
| -rw-r--r-- | ocicl.csv | 1 | ||||
| -rw-r--r-- | src/main.lisp | 60 | ||||
| -rw-r--r-- | src/transport.lisp | 38 |
3 files changed, 54 insertions, 45 deletions
| @@ -1,5 +1,4 @@ | |||
| 1 | alexandria, ghcr.io/ocicl/alexandria@sha256:e433c2e076ed3bcf8641b97b00192680db2201d305efac9293539dee88c7fbf7, alexandria-20240503-8514d8e/alexandria.asd | 1 | alexandria, ghcr.io/ocicl/alexandria@sha256:e433c2e076ed3bcf8641b97b00192680db2201d305efac9293539dee88c7fbf7, alexandria-20240503-8514d8e/alexandria.asd |
| 2 | anaphora, ghcr.io/ocicl/anaphora@sha256:55f1c61b7826c5451a60b4b4522e35e770504bbfa2036d8becbf21f6d654925a, anaphora-20240503-bcf0f74/anaphora.asd | ||
| 3 | babel, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel.asd | 2 | babel, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel.asd |
| 4 | babel-streams, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel-streams.asd | 3 | babel-streams, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel-streams.asd |
| 5 | babel-tests, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel-tests.asd | 4 | babel-tests, ghcr.io/ocicl/babel@sha256:9d9fcde71acc2b5c39572de4f11756a08c1d8801caa86c581b85dabaa35928b3, babel-20250905-4eaf3f2/babel-tests.asd |
diff --git a/src/main.lisp b/src/main.lisp index cd9e755..94148a7 100644 --- a/src/main.lisp +++ b/src/main.lisp | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> |
| 3 | (defpackage :ukkoclot/main | 3 | (defpackage :ukkoclot/main |
| 4 | (:nicknames :ukkoclot) | 4 | (:nicknames :ukkoclot) |
| 5 | (:use :c2cl :ukkoclot/config :ukkoclot/inline-bots :ukkoclot/tg) | 5 | (:use :c2cl :iterate :ukkoclot/config :ukkoclot/inline-bots :ukkoclot/tg) |
| 6 | (:import-from :anaphora :acond :awhen :it) | 6 | (:import-from :alexandria :when-let) |
| 7 | (:import-from :com.dieggsy.f-string :enable-f-strings) | 7 | (:import-from :com.dieggsy.f-string :enable-f-strings) |
| 8 | (:import-from :log) | 8 | (:import-from :log) |
| 9 | (:import-from :ukkoclot/db :with-db) | 9 | (:import-from :ukkoclot/db :with-db) |
| @@ -55,12 +55,12 @@ | |||
| 55 | (loop for update across updates do | 55 | (loop for update across updates do |
| 56 | (unwind-protect | 56 | (unwind-protect |
| 57 | (progn | 57 | (progn |
| 58 | (awhen (update-message update) | 58 | (when-let (msg (update-message update)) |
| 59 | (reporty (it) | 59 | (reporty (msg) |
| 60 | (on-message bot it))) | 60 | (on-message bot msg))) |
| 61 | (awhen (update-callback-query update) | 61 | (when-let (cbq (update-callback-query update)) |
| 62 | (reporty (it) | 62 | (reporty (cbq) |
| 63 | (on-callback-query bot it)))) | 63 | (on-callback-query bot cbq)))) |
| 64 | (setf gup-offset (1+ (update-update-id update))))))) | 64 | (setf gup-offset (1+ (update-update-id update))))))) |
| 65 | ;; One last getUpdates to make sure offset is stored on server | 65 | ;; One last getUpdates to make sure offset is stored on server |
| 66 | (get-updates bot :timeout 0 :limit 1 :offset gup-offset)) | 66 | (get-updates bot :timeout 0 :limit 1 :offset gup-offset)) |
| @@ -74,10 +74,10 @@ | |||
| 74 | (config-owner (bot-config bot)))) | 74 | (config-owner (bot-config bot)))) |
| 75 | (let ((bot-id (read-from-string data t nil :start 4))) | 75 | (let ((bot-id (read-from-string data t nil :start 4))) |
| 76 | (blacklist-inline-bot bot bot-id)) | 76 | (blacklist-inline-bot bot bot-id)) |
| 77 | (awhen (callback-query-message cb) | 77 | (when-let (msg (callback-query-message cb)) |
| 78 | (delete-message bot | 78 | (delete-message bot |
| 79 | :chat-id (message-chat-id it) | 79 | :chat-id (message-chat-id msg) |
| 80 | :message-id (message-id it))) | 80 | :message-id (message-id msg))) |
| 81 | (answer-callback-query bot | 81 | (answer-callback-query bot |
| 82 | :callback-query-id (callback-query-id cb) | 82 | :callback-query-id (callback-query-id cb) |
| 83 | :text "OK")) | 83 | :text "OK")) |
| @@ -87,10 +87,10 @@ | |||
| 87 | (config-owner (bot-config bot)))) | 87 | (config-owner (bot-config bot)))) |
| 88 | (let ((bot-id (read-from-string data t nil :start 4))) | 88 | (let ((bot-id (read-from-string data t nil :start 4))) |
| 89 | (whitelist-inline-bot bot bot-id)) | 89 | (whitelist-inline-bot bot bot-id)) |
| 90 | (awhen (callback-query-message cb) | 90 | (when-let (msg (callback-query-message cb)) |
| 91 | (delete-message bot | 91 | (delete-message bot |
| 92 | :chat-id (message-chat-id it) | 92 | :chat-id (message-chat-id msg) |
| 93 | :message-id (message-id it))) | 93 | :message-id (message-id msg))) |
| 94 | (answer-callback-query bot | 94 | (answer-callback-query bot |
| 95 | :callback-query-id (callback-query-id cb) | 95 | :callback-query-id (callback-query-id cb) |
| 96 | :text "OK")) | 96 | :text "OK")) |
| @@ -104,15 +104,16 @@ | |||
| 104 | 104 | ||
| 105 | (defun on-message (bot msg) | 105 | (defun on-message (bot msg) |
| 106 | (block nil | 106 | (block nil |
| 107 | (awhen (message-via-bot msg) | 107 | (when-let (inline-bot (message-via-bot msg)) |
| 108 | (unless (on-inline-bot bot msg it) | 108 | (unless (on-inline-bot bot msg inline-bot) |
| 109 | (return))) | 109 | (return))) |
| 110 | 110 | ||
| 111 | (awhen (message-text msg) | 111 | (when-let (text (message-text msg)) |
| 112 | (on-text-message bot msg it)) | 112 | (on-text-message bot msg text)) |
| 113 | 113 | ||
| 114 | (awhen (message-new-chat-members msg) | 114 | (when-let (new-chat-members (message-new-chat-members msg)) |
| 115 | (loop for new-chat-member across it do | 115 | (iter |
| 116 | (for new-chat-member in-vector new-chat-members) | ||
| 116 | (on-new-member bot msg new-chat-member))))) | 117 | (on-new-member bot msg new-chat-member))))) |
| 117 | 118 | ||
| 118 | (defun on-new-member (bot msg new-member) | 119 | (defun on-new-member (bot msg new-member) |
| @@ -145,11 +146,12 @@ | |||
| 145 | ;; warn gets removed after a month of no warns | 146 | ;; warn gets removed after a month of no warns |
| 146 | (return)) | 147 | (return)) |
| 147 | 148 | ||
| 148 | (awhen (message-entities msg) | 149 | (when-let (entities (message-entities msg)) |
| 149 | (loop for entity across it | 150 | (iter |
| 150 | when (and (equal (message-entity-type entity) bot-command) | 151 | (for entity in-vector entities) |
| 151 | (= (message-entity-offset entity) 0)) | 152 | (when (and (eql (message-entity-type entity) bot-command) |
| 152 | do (on-text-command bot msg text (message-entity-extract entity text)))) | 153 | (zerop (message-entity-offset entity))) |
| 154 | (on-text-command bot msg text (message-entity-extract entity text))))) | ||
| 153 | 155 | ||
| 154 | ;; TODO: Replace this cond with a nicer dispatch. Something like string-case? | 156 | ;; TODO: Replace this cond with a nicer dispatch. Something like string-case? |
| 155 | (cond ((equal text ":3") | 157 | (cond ((equal text ":3") |
| @@ -241,15 +243,15 @@ | |||
| 241 | (let ((simple-cmd (simplify-cmd bot cmd))) | 243 | (let ((simple-cmd (simplify-cmd bot cmd))) |
| 242 | (log:debug "text-command: ~A AKA ~A" cmd simple-cmd) | 244 | (log:debug "text-command: ~A AKA ~A" cmd simple-cmd) |
| 243 | ;; TODO: Replace this cond with a nicer dispatch. Something like string-case? | 245 | ;; TODO: Replace this cond with a nicer dispatch. Something like string-case? |
| 244 | (acond | 246 | (cond |
| 245 | ((equal simple-cmd "chatid") | 247 | ((equal simple-cmd "chatid") |
| 246 | (reply-message bot msg | 248 | (reply-message bot msg |
| 247 | #f"<code>{(message-chat-id msg)}</code>" | 249 | #f"<code>{(message-chat-id msg)}</code>" |
| 248 | :parse-mode html)) | 250 | :parse-mode html)) |
| 249 | 251 | ||
| 250 | ((and (equal simple-cmd "msginfo") | 252 | ((equal simple-cmd "msginfo") |
| 251 | (message-reply-to-message msg)) | 253 | (when-let (replied (message-reply-to-message msg)) |
| 252 | (reply-message bot it (let ((*print-pretty* t)) (fixup-value it)))) | 254 | (reply-message bot replied (let ((*print-pretty* t)) (fixup-value replied))))) |
| 253 | 255 | ||
| 254 | ((equal simple-cmd "ping") | 256 | ((equal simple-cmd "ping") |
| 255 | (let* ((start-time (get-internal-real-time)) | 257 | (let* ((start-time (get-internal-real-time)) |
diff --git a/src/transport.lisp b/src/transport.lisp index 941341a..d47db4d 100644 --- a/src/transport.lisp +++ b/src/transport.lisp | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | 1 | ;; SPDX-License-Identifier: EUPL-1.2 |
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> |
| 3 | (defpackage :ukkoclot/transport | 3 | (defpackage :ukkoclot/transport |
| 4 | (:documentation "Package dealing with HTTP calls.") | ||
| 4 | (:use :c2cl) | 5 | (:use :c2cl) |
| 5 | (:import-from :anaphora :aand :acond :it) | ||
| 6 | (:import-from :cl+ssl) | 6 | (:import-from :cl+ssl) |
| 7 | (:import-from :dex) | 7 | (:import-from :dex) |
| 8 | (:import-from :log) | 8 | (:import-from :log) |
| @@ -14,6 +14,7 @@ | |||
| 14 | (in-package :ukkoclot/transport) | 14 | (in-package :ukkoclot/transport) |
| 15 | 15 | ||
| 16 | (defun req (uri method content) | 16 | (defun req (uri method content) |
| 17 | "Wrapper function for making a request." | ||
| 17 | (let ((retrier (dex:retry-request 5 :interval 1)) | 18 | (let ((retrier (dex:retry-request 5 :interval 1)) |
| 18 | ;; This is needed to avoid hangs, | 19 | ;; This is needed to avoid hangs, |
| 19 | ;; see https://github.com/fukamachi/dexador/issues/91#issuecomment-1093472364 | 20 | ;; see https://github.com/fukamachi/dexador/issues/91#issuecomment-1093472364 |
| @@ -25,22 +26,29 @@ | |||
| 25 | (cl+ssl::ssl-error (e) (funcall retrier e))))) | 26 | (cl+ssl::ssl-error (e) (funcall retrier e))))) |
| 26 | 27 | ||
| 27 | (defun do-call% (method uri out-type args-encoded) | 28 | (defun do-call% (method uri out-type args-encoded) |
| 28 | (let ((body (req uri method args-encoded))) | 29 | "Internal function with the arguments already encoded. |
| 29 | (let ((hash (jzon:parse body))) | 30 | |
| 30 | (acond | 31 | See `do-call'." |
| 31 | ((gethash "ok" hash) (parse-value out-type (gethash "result" hash))) | 32 | (let* ((body (req uri method args-encoded)) |
| 32 | ((aand (gethash "parameters" hash) | 33 | (hash (jzon:parse body))) |
| 33 | (gethash "retry_after" it)) | 34 | (if (gethash "ok" hash) |
| 34 | (log:info "Should sleep for ~A seconds" it) | 35 | (parse-value out-type (gethash "result" hash)) |
| 35 | (sleep it) | 36 | (let* ((error-code (gethash "error_code" hash)) |
| 36 | (log:info "Good morning!") | 37 | (description (gethash "description" hash)) |
| 37 | (do-call% method uri out-type args-encoded)) | 38 | (parameters (gethash "parameters" hash)) |
| 38 | (t (error "TG error ~A: ~A ~:A" | 39 | (retry-after (when parameters (gethash "retry_after" parameters)))) |
| 39 | (gethash "error_code" hash) | 40 | (cond |
| 40 | (gethash "description" hash) | 41 | (retry-after |
| 41 | (gethash "parameters" hash))))))) | 42 | (log:info "Should sleep for ~A seconds" retry-after) |
| 43 | (sleep retry-after) | ||
| 44 | (log:info "Good morning!") | ||
| 45 | (do-call% method uri out-type args-encoded)) | ||
| 46 | (t | ||
| 47 | (error "TG error ~A: ~A ~:A" | ||
| 48 | error-code description parameters))))))) | ||
| 42 | 49 | ||
| 43 | (defun do-call (bot method path out-type args) | 50 | (defun do-call (bot method path out-type args) |
| 51 | "Perform a HTTP call." | ||
| 44 | (let ((uri (concatenate 'string (bot-base-uri bot) path)) | 52 | (let ((uri (concatenate 'string (bot-base-uri bot) path)) |
| 45 | (args-encoded (fixup-args args))) | 53 | (args-encoded (fixup-args args))) |
| 46 | (log:debug "~A .../~A ~S" method path args-encoded) | 54 | (log:debug "~A .../~A ~S" method path args-encoded) |