summaryrefslogtreecommitdiff
path: root/src/main.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.lisp')
-rw-r--r--src/main.lisp126
1 files changed, 58 insertions, 68 deletions
diff --git a/src/main.lisp b/src/main.lisp
index caef651..fa7fab0 100644
--- a/src/main.lisp
+++ b/src/main.lisp
@@ -8,10 +8,10 @@
8 (:import-from :conf) 8 (:import-from :conf)
9 (:import-from :log) 9 (:import-from :log)
10 (:import-from :serapeum :drop) 10 (:import-from :serapeum :drop)
11 (:import-from :state :*state* :make-state)
11 (:import-from :str) 12 (:import-from :str)
12 (:import-from :ukkoclot/src/db :with-db) 13 (:import-from :ukkoclot/src/db :with-db)
13 (:import-from :ukkoclot/src/serializing :fixup-value) 14 (:import-from :ukkoclot/src/serializing :fixup-value)
14 (:import-from :ukkoclot/src/state :make-bot :bot-power-on)
15 (:import-from :ukkoclot/src/strings :escape-xml :is-tg-whitespace :is-tg-whitespace-str) 15 (:import-from :ukkoclot/src/strings :escape-xml :is-tg-whitespace :is-tg-whitespace-str)
16 (:local-nicknames 16 (:local-nicknames
17 (:jzon :com.inuoe.jzon)) 17 (:jzon :com.inuoe.jzon))
@@ -26,7 +26,7 @@
26 `(cond 26 `(cond
27 (*in-prod* 27 (*in-prod*
28 (handler-case (progn ,@body) ; lint:suppress redundant-progn 28 (handler-case (progn ,@body) ; lint:suppress redundant-progn
29 (error (err) (report-error bot ,evt err)))) 29 (error (err) (report-error ,evt err))))
30 (t ,@body))) 30 (t ,@body)))
31 31
32(defun main () 32(defun main ()
@@ -43,87 +43,82 @@
43(defun main-with-config () 43(defun main-with-config ()
44 (unwind-protect 44 (unwind-protect
45 (with-db (db (conf:db-path)) 45 (with-db (db (conf:db-path))
46 (let ((bot (make-bot db))) 46 (setf *state* (make-state db))
47 ;; TODO: Catch fatal errors & report them 47 ;; TODO: Catch fatal errors & report them
48 (wrapped-main bot))) 48 (wrapped-main))
49 (log:info "We're done!"))) 49 (log:info "We're done!")))
50 50
51(defun wrapped-main (bot) 51(defun wrapped-main ()
52 (when *in-prod* 52 (when *in-prod*
53 (send-message bot :chat-id (conf:dev-group) :text "Initializing...")) 53 (send-message :chat-id (conf:dev-group) :text "Initializing..."))
54 (set-my-name bot :name (conf:bot-name)) 54 (set-my-name :name (conf:bot-name))
55 (let ((gup-offset 0)) 55 (let ((gup-offset 0))
56 (loop while (bot-power-on bot) do 56 (loop while (state:power-on) do
57 (let ((updates (get-updates bot :timeout 60 :offset gup-offset))) 57 (let ((updates (get-updates :timeout 60 :offset gup-offset)))
58 (loop for update across updates do 58 (loop for update across updates do
59 (unwind-protect 59 (unwind-protect
60 (progn 60 (progn
61 (when-let (msg (update-message update)) 61 (when-let (msg (update-message update))
62 (reporty (msg) 62 (reporty (msg)
63 (on-message bot msg))) 63 (on-message msg)))
64 (when-let (cbq (update-callback-query update)) 64 (when-let (cbq (update-callback-query update))
65 (reporty (cbq) 65 (reporty (cbq)
66 (on-callback-query bot cbq)))) 66 (on-callback-query cbq))))
67 (setf gup-offset (1+ (update-update-id update))))))) 67 (setf gup-offset (1+ (update-update-id update)))))))
68 ;; One last getUpdates to make sure offset is stored on server 68 ;; One last getUpdates to make sure offset is stored on server
69 (get-updates bot :timeout 0 :limit 1 :offset gup-offset)) 69 (get-updates :timeout 0 :limit 1 :offset gup-offset))
70 (send-message bot :chat-id (conf:dev-group) :text "Shutting down...")) 70 (send-message :chat-id (conf:dev-group) :text "Shutting down..."))
71 71
72(defun on-callback-query (bot cb) 72(defun on-callback-query (cb)
73 (let ((data (callback-query-data cb))) 73 (let ((data (callback-query-data cb)))
74 (cond ((and data 74 (cond ((and data
75 (str:starts-with-p "bbl:" data :ignore-case nil) 75 (str:starts-with-p "bbl:" data :ignore-case nil)
76 (= (user-id (callback-query-from cb)) 76 (= (user-id (callback-query-from cb))
77 (conf:owner))) 77 (conf:owner)))
78 (let ((bot-id (read-from-string data t nil :start 4))) 78 (let ((bot-id (read-from-string data t nil :start 4)))
79 (blacklist-inline-bot bot bot-id)) 79 (blacklist-inline-bot bot-id))
80 (when-let (msg (callback-query-message cb)) 80 (when-let (msg (callback-query-message cb))
81 (delete-message bot 81 (delete-message :chat-id (message-chat-id msg)
82 :chat-id (message-chat-id msg)
83 :message-id (message-id msg))) 82 :message-id (message-id msg)))
84 (answer-callback-query bot 83 (answer-callback-query :callback-query-id (callback-query-id cb)
85 :callback-query-id (callback-query-id cb)
86 :text "OK")) 84 :text "OK"))
87 ((and data 85 ((and data
88 (str:starts-with-p "bwl:" data :ignore-case nil) 86 (str:starts-with-p "bwl:" data :ignore-case nil)
89 (= (user-id (callback-query-from cb)) 87 (= (user-id (callback-query-from cb))
90 (conf:owner))) 88 (conf:owner)))
91 (let ((bot-id (read-from-string data t nil :start 4))) 89 (let ((bot-id (read-from-string data t nil :start 4)))
92 (whitelist-inline-bot bot bot-id)) 90 (whitelist-inline-bot bot-id))
93 (when-let (msg (callback-query-message cb)) 91 (when-let (msg (callback-query-message cb))
94 (delete-message bot 92 (delete-message :chat-id (message-chat-id msg)
95 :chat-id (message-chat-id msg)
96 :message-id (message-id msg))) 93 :message-id (message-id msg)))
97 (answer-callback-query bot 94 (answer-callback-query :callback-query-id (callback-query-id cb)
98 :callback-query-id (callback-query-id cb)
99 :text "OK")) 95 :text "OK"))
100 (t 96 (t
101 (log:info "Unrecognised callback query data: ~A" data) 97 (log:info "Unrecognised callback query data: ~A" data)
102 (answer-callback-query bot 98 (answer-callback-query :callback-query-id (callback-query-id cb)
103 :callback-query-id (callback-query-id cb)
104 :text "Unallowed callback query, don't press the button again" 99 :text "Unallowed callback query, don't press the button again"
105 :show-alert t))))) 100 :show-alert t)))))
106 101
107 102
108(defun on-message (bot msg) 103(defun on-message (msg)
109 (block nil 104 (block nil
110 (when-let (inline-bot (message-via-bot msg)) 105 (when-let (inline-bot (message-via-bot msg))
111 (unless (on-inline-bot bot msg inline-bot) 106 (unless (on-inline-bot msg inline-bot)
112 (return))) 107 (return)))
113 108
114 (when-let (text (message-text msg)) 109 (when-let (text (message-text msg))
115 (on-text-message bot msg text)) 110 (on-text-message msg text))
116 111
117 (when-let (new-chat-members (message-new-chat-members msg)) 112 (when-let (new-chat-members (message-new-chat-members msg))
118 (iter 113 (iter
119 (for new-chat-member in-vector new-chat-members) 114 (for new-chat-member in-vector new-chat-members)
120 (on-new-member bot msg new-chat-member))))) 115 (on-new-member msg new-chat-member)))))
121 116
122(defun on-new-member (bot msg new-member) 117(defun on-new-member (msg new-member)
123 (if (= (user-id new-member) (bot-id bot)) 118 (if (= (user-id new-member) (bot-id))
124 (reply-animation bot msg #P"blob/rule-11.mp4" 119 (reply-animation msg #P"blob/rule-11.mp4"
125 :allow-sending-without-reply t) 120 :allow-sending-without-reply t)
126 (reply-animation bot msg #P"blob/rule-10.mp4" 121 (reply-animation msg #P"blob/rule-10.mp4"
127 :text (concatenate 'string "Hello there, " 122 :text (concatenate 'string "Hello there, "
128 (user-format-name new-member) 123 (user-format-name new-member)
129 "! Be on your bestest behaviour now!!") 124 "! Be on your bestest behaviour now!!")
@@ -136,7 +131,7 @@
136 ;; TODO: 131 ;; TODO:
137 nil) 132 nil)
138 133
139(defun on-text-message (bot msg text) 134(defun on-text-message (msg text)
140 (block nil 135 (block nil
141 (when (is-bad-text text) 136 (when (is-bad-text text)
142 ;; TODO: Delete message, mute & warn user 137 ;; TODO: Delete message, mute & warn user
@@ -155,19 +150,19 @@
155 (for entity in-vector entities) 150 (for entity in-vector entities)
156 (when (and (eql (message-entity-type entity) bot-command) 151 (when (and (eql (message-entity-type entity) bot-command)
157 (zerop (message-entity-offset entity))) 152 (zerop (message-entity-offset entity)))
158 (on-text-command bot msg text (message-entity-extract entity text))))) 153 (on-text-command msg text (message-entity-extract entity text)))))
159 154
160 ;; TODO: Replace this cond with a nicer dispatch. Something like string-case? 155 ;; TODO: Replace this cond with a nicer dispatch. Something like string-case?
161 (cond ((equal text ":3") 156 (cond ((equal text ":3")
162 (reply-message bot msg ">:3")) 157 (reply-message msg ">:3"))
163 158
164 ((equal text ">:3") 159 ((equal text ">:3")
165 (reply-message bot msg "<b>&gt;:3</b>" :parse-mode html)) 160 (reply-message msg "<b>&gt;:3</b>" :parse-mode html))
166 161
167 ((str:starts-with-p "big " text) 162 ((str:starts-with-p "big " text)
168 (let ((the-text (drop 4 text))) 163 (let ((the-text (drop 4 text)))
169 (unless (is-tg-whitespace-str the-text) 164 (unless (is-tg-whitespace-str the-text)
170 (reply-message bot msg 165 (reply-message msg
171 (concatenate 'string 166 (concatenate 'string
172 "<b>" 167 "<b>"
173 (escape-xml (string-upcase the-text)) 168 (escape-xml (string-upcase the-text))
@@ -175,33 +170,31 @@
175 :parse-mode html)))) 170 :parse-mode html))))
176 171
177 ((string-equal text "dio cane") 172 ((string-equal text "dio cane")
178 (reply-message bot 173 (reply-message (or (message-reply-to-message msg) msg)
179 (or (message-reply-to-message msg) msg)
180 "porco dio")) 174 "porco dio"))
181 175
182 ((string-equal text "forgor") 176 ((string-equal text "forgor")
183 (reply-message bot msg "💀")) 177 (reply-message msg "💀"))
184 178
185 ((string-equal text "huh") 179 ((string-equal text "huh")
186 (reply-message bot msg "idgi")) 180 (reply-message msg "idgi"))
187 181
188 ((string= text "H") 182 ((string= text "H")
189 (reply-message bot msg "<code>Randomly selected reminder that h &gt; H.</code>" :parse-mode html)) 183 (reply-message msg "<code>Randomly selected reminder that h &gt; H.</code>" :parse-mode html))
190 184
191 ((string-equal text "porco dio") 185 ((string-equal text "porco dio")
192 (reply-message bot 186 (reply-message (or (message-reply-to-message msg) msg)
193 (or (message-reply-to-message msg) msg)
194 "dio cane")) 187 "dio cane"))
195 188
196 ((str:starts-with-p "say " text) 189 ((str:starts-with-p "say " text)
197 (let ((the-text (drop 4 text))) 190 (let ((the-text (drop 4 text)))
198 (unless (is-tg-whitespace-str the-text) 191 (unless (is-tg-whitespace-str the-text)
199 (reply-message bot msg the-text)))) 192 (reply-message msg the-text))))
200 193
201 ((str:starts-with-p "tiny " text) 194 ((str:starts-with-p "tiny " text)
202 (let ((the-text (drop 5 text))) 195 (let ((the-text (drop 5 text)))
203 (unless (is-tg-whitespace-str the-text) 196 (unless (is-tg-whitespace-str the-text)
204 (reply-message bot msg 197 (reply-message msg
205 (map 'string #'(lambda (ch) 198 (map 'string #'(lambda (ch)
206 (if (is-tg-whitespace ch) 199 (if (is-tg-whitespace ch)
207 ch 200 ch
@@ -209,16 +202,15 @@
209 the-text))))) 202 the-text)))))
210 203
211 ((string-equal text "uwu") 204 ((string-equal text "uwu")
212 (reply-message bot msg "OwO")) 205 (reply-message msg "OwO"))
213 206
214 ((string-equal text "waow") 207 ((string-equal text "waow")
215 (reply-message 208 (reply-message
216 bot
217 (or (message-reply-to-message msg) msg) 209 (or (message-reply-to-message msg) msg)
218 "BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED")) 210 "BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED"))
219 211
220 ((string-equal text "what") 212 ((string-equal text "what")
221 (reply-message bot msg 213 (reply-message msg
222 (with-output-to-string (s) 214 (with-output-to-string (s)
223 (if (char= (elt text 0) #\w) 215 (if (char= (elt text 0) #\w)
224 (write-char #\g s) 216 (write-char #\g s)
@@ -235,55 +227,53 @@
235 227
236 (t nil)))) 228 (t nil))))
237 229
238(defun simplify-cmd (bot cmd) 230(defun simplify-cmd (cmd)
239 (let ((at-idx (position #\@ cmd))) 231 (let ((at-idx (position #\@ cmd)))
240 (if (null at-idx) 232 (if (null at-idx)
241 (drop 1 cmd) 233 (drop 1 cmd)
242 (let ((username (drop (1+ at-idx) cmd)) 234 (let ((username (drop (1+ at-idx) cmd))
243 (my-username (bot-username bot))) 235 (my-username (bot-username)))
244 (if (equal username my-username) 236 (if (equal username my-username)
245 (subseq cmd 1 at-idx) 237 (subseq cmd 1 at-idx)
246 nil))))) 238 nil)))))
247 239
248(defun on-text-command (bot msg text cmd) 240(defun on-text-command (msg text cmd)
249 (declare (ignore text)) 241 (declare (ignore text))
250 (let ((simple-cmd (simplify-cmd bot cmd))) 242 (let ((simple-cmd (simplify-cmd cmd)))
251 (log:debug "text-command: ~A AKA ~A" cmd simple-cmd) 243 (log:debug "text-command: ~A AKA ~A" cmd simple-cmd)
252 ;; TODO: Replace this cond with a nicer dispatch. Something like string-case? 244 ;; TODO: Replace this cond with a nicer dispatch. Something like string-case?
253 (cond 245 (cond
254 ((equal simple-cmd "chatid") 246 ((equal simple-cmd "chatid")
255 (reply-message bot msg 247 (reply-message msg
256 #f"<code>{(message-chat-id msg)}</code>" 248 #f"<code>{(message-chat-id msg)}</code>"
257 :parse-mode html)) 249 :parse-mode html))
258 250
259 ((equal simple-cmd "msginfo") 251 ((equal simple-cmd "msginfo")
260 (when-let (replied (message-reply-to-message msg)) 252 (when-let (replied (message-reply-to-message msg))
261 (reply-message bot replied (let ((*print-pretty* t)) (fixup-value replied))))) 253 (reply-message replied (let ((*print-pretty* t)) (fixup-value replied)))))
262 254
263 ((equal simple-cmd "ping") 255 ((equal simple-cmd "ping")
264 (let* ((start-time (get-internal-real-time)) 256 (let* ((start-time (get-internal-real-time))
265 (reply (reply-message bot msg #f"Pong!{;~2%}Send time: ...")) 257 (reply (reply-message msg #f"Pong!{;~2%}Send time: ..."))
266 (end-time (get-internal-real-time)) 258 (end-time (get-internal-real-time))
267 (time-elapsed (* (/ (- end-time start-time) internal-time-units-per-second) 259 (time-elapsed (* (/ (- end-time start-time) internal-time-units-per-second)
268 1000))) 260 1000)))
269 (edit-message-text bot 261 (edit-message-text :chat-id (message-chat-id reply)
270 :chat-id (message-chat-id reply)
271 :message-id (message-id reply) 262 :message-id (message-id reply)
272 :text #f"Pong!{;~2%}Send time: {time-elapsed;~G}ms"))) 263 :text #f"Pong!{;~2%}Send time: {time-elapsed;~G}ms")))
273 264
274 ((and (equal simple-cmd "shutdown") 265 ((and (equal simple-cmd "shutdown")
275 (message-from msg) 266 (message-from msg)
276 (= (user-id (message-from msg)) (conf:owner))) 267 (= (user-id (message-from msg)) (conf:owner)))
277 (setf (bot-power-on bot) nil) 268 (setf (state:power-on) nil)
278 (reply-message bot msg "Initialising shutdown..." :allow-sending-without-reply t))))) 269 (reply-message msg "Initialising shutdown..." :allow-sending-without-reply t)))))
279 270
280(defun escape-xml-obj (obj) 271(defun escape-xml-obj (obj)
281 (escape-xml #f"{obj}")) 272 (escape-xml #f"{obj}"))
282 273
283(defun report-error (bot evt err) 274(defun report-error (evt err)
284 (log:error "While handling ~A: ~A" evt err) 275 (log:error "While handling ~A: ~A" evt err)
285 (let ((msg #f"<code>{(escape-xml-obj err)}</code> while handling{;~%}<pre>{(escape-xml-obj evt)}</pre>")) 276 (let ((msg #f"<code>{(escape-xml-obj err)}</code> while handling{;~%}<pre>{(escape-xml-obj evt)}</pre>"))
286 (send-message bot 277 (send-message :chat-id (conf:dev-group)
287 :chat-id (conf:dev-group) 278 :text msg
288 :text msg 279 :parse-mode html)))
289 :parse-mode html)))