Skip to content

Commit

Permalink
Added documentation on states.
Browse files Browse the repository at this point in the history
  • Loading branch information
svetlyak40wt committed Dec 8, 2024
1 parent 73feeeb commit 054cc96
Show file tree
Hide file tree
Showing 8 changed files with 2,251 additions and 600 deletions.
2,604 changes: 2,050 additions & 554 deletions README.md

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions docs/index.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#:defsection-copy)
(:import-from #:cl-telegram-bot-docs/changelog
#:@changelog)
(:import-from #:cl-telegram-bot-docs/states
#:@states-and-actions)
(:import-from #:docs-config
#:docs-config)
(:import-from #:40ants-doc/autodoc
Expand Down Expand Up @@ -57,8 +59,8 @@
![Quicklisp](http://quickdocs.org/badge/cl-telegram-bot.svg)
"
(@installation section)
(@quickstart section)
(@api section)
(@v2 section)
(@v1 section)
(@credits section))


Expand Down Expand Up @@ -151,4 +153,17 @@ And start communicating with him:
")


(defsection @v1 (:title "v1")
(@quickstart section)
(@api section))


(defsection @v2 (:title "v2")
(@states-and-actions section)
(@api-v2 section))


(defautodoc @api (:system :cl-telegram-bot))

(defautodoc @api-v2 (:system :cl-telegram-bot2
:ignore-packages ("cl-telegram-bot2/api")))
53 changes: 53 additions & 0 deletions docs/states.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
(uiop:define-package #:cl-telegram-bot-docs/states
(:use #:cl)
(:import-from #:40ants-doc
#:defsection)
(:import-from #:cl-telegram-bot2/state
#:state)
(:import-from #:cl-telegram-bot2/actions/send-text
#:send-text))
(in-package #:cl-telegram-bot-docs/states)


(defsection @states-and-actions (:title "States and Actions")
"
This framework makes it possible to define bot with all allowed state.
The state defines behaviour of the bot, the way it should respond to commands, updates and other events.
"
(@states section)
(@actions section))


(defsection @states (:title "States")
"
There can be more than one handler for the event. We call these handlers \"Actions\".
An action should return a NIL or a new state. In latter case, the current bot's state will be changed to the new one and handlers for `on-activation` event will be called.
State is constructed using STATE function, which accepts handlers for different kinds of events. Here is simples state which greets a user when it start the chat and then reply with the same text:
```
(defun reply-with-same-text (update)
(reply (message-text
(update-message update)))
(values))
(state (send-text \"Hello, I'm the echo bot.\")
:on-update 'reply-with-same-text)
```
The first argument to STATE function is a handler for `on-activation` event. If you don't want to react on activation, you can pass NIL instead. The SEND-TEXT function returns an action instance. This way, we tell what bot should do, we use a declarative way to describe bot's behaviour.
The :ON-UPDATE argument specifies a handler for `on-update` event. This is the most generic event which occur when bot receives an update which wasn't processed by other event handlers. For this handler we are using a custom function bound to the symbol `reply-with-same-text`. The function accepts a single argument - update object. Use generic functions from `cl-telegram-bot2/api` package to work with this update object.
The reason why we only accept a special action object or a symbol but not a lambda function is because this way we'll be able to generate schemas of all states and transitions between them. Another reason is that it will be possible to redefine fbound function and use interactive approach to changing bot's behaviour.
See other support events in STATE function documentation.
")


(defsection @actions (:title "Actions")
"
")
36 changes: 20 additions & 16 deletions examples/calc.lisp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(uiop:define-package #:cl-telegram-bot2/calc
(uiop:define-package #:cl-telegram-bot2-examples/calc
(:use #:cl)
(:import-from #:cl-telegram-bot2/state
#:state)
Expand Down Expand Up @@ -30,7 +30,7 @@
(:import-from #:40ants-logging)
(:import-from #:cl-telegram-bot2/term/back
#:back-to-id))
(in-package #:cl-telegram-bot2/calc)
(in-package #:cl-telegram-bot2-examples/calc)



Expand All @@ -52,25 +52,29 @@
(var "first-num")
(var "second-num")))


(defbot test-bot ()
()
(:initial-state
(state nil
:id "start"
:on-update (state (list
(send-text "Let's calculate!")
(ask-for-number "Enter the first number:"
:to "first-num"
:on-validation-error (send-text "Enter the number, please.")
:on-success (ask-for-number "Enter the second number:"
:to "second-num"
:on-validation-error (send-text "Enter the number, please.")
:on-success (ask-for-choice
'make-prompt-for-op-choice
'("+" "-" "*" "/")
:to "operation-name"
:on-success (list (send-text 'calc-result)
(back-to-id "start"))))))))))
:on-update
(state (list
(send-text "Let's calculate!")
(ask-for-number
"Enter the first number:"
:to "first-num"
:on-validation-error (send-text "Enter the number, please.")
:on-success (ask-for-number
"Enter the second number:"
:to "second-num"
:on-validation-error (send-text "Enter the number, please.")
:on-success (ask-for-choice
'make-prompt-for-op-choice
'("+" "-" "*" "/")
:to "operation-name"
:on-success (list (send-text 'calc-result)
(back-to-id "start"))))))))))


(defvar *bot* nil)
Expand Down
81 changes: 81 additions & 0 deletions examples/echo.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
(uiop:define-package #:cl-telegram-bot2-examples/echo
(:use #:cl)
(:import-from #:cl-telegram-bot2/state
#:state)
(:import-from #:cl-telegram-bot2/actions/send-text
#:send-text)
(:import-from #:cl-telegram-bot2/bot
#:defbot)
(:import-from #:cl-telegram-bot2/server
#:stop-polling
#:start-polling)
(:import-from #:cl-telegram-bot2/high
#:reply
#:chat-state)
(:import-from #:serapeum
#:dict
#:fmt)
(:import-from #:cl-telegram-bot2/pipeline
#:back-to-nth-parent
#:back-to
#:back)
(:import-from #:cl-telegram-bot2/api
#:update-message
#:message-text
#:message-message-id)
(:import-from #:cl-telegram-bot2/states/ask-for-number
#:ask-for-number)
(:import-from #:cl-telegram-bot2/states/base
#:var)
(:import-from #:cl-telegram-bot2/states/ask-for-choice
#:ask-for-choice)
(:import-from #:40ants-logging)
(:import-from #:cl-telegram-bot2/term/back
#:back-to-id))
(in-package #:cl-telegram-bot2-examples/echo)


(defun reply-with-same-text (update)
(reply (message-text
(update-message update)))
(values))


(defbot test-bot ()
()
(:initial-state
(state (send-text "Hello, I'm the echo bot.")
:on-update 'reply-with-same-text)))


(defvar *bot* nil)


(defun stop ()
(when *bot*
(stop-polling *bot*)
(setf *bot* nil)

(sleep 1)
(bt:all-threads)))


(defun start ()
(stop)

(40ants-logging:setup-for-repl :level :warn)

(unless *bot*
(setf *bot*
(make-test-bot (uiop:getenv "TELEGRAM_TOKEN"))))

(start-polling *bot* :debug t))


(defun clean-threads ()
"TODO: надо разобраться почему треды не подчищаются. Возможно это происходит когда случаются ошибки?"
(loop for tr in (bt:all-threads)
when (or (str:starts-with? "message-thread" (bt:thread-name tr))
(str:starts-with? "timer-wheel" (bt:thread-name tr))
(str:starts-with? "telegram-bot" (bt:thread-name tr)))
do (bt:destroy-thread tr)))
16 changes: 15 additions & 1 deletion v2/bot.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,21 @@


(defmacro defbot (name base-classes &optional slots &rest options)
"Use this macro to define a class of your Telegram bot."
"Use this macro to define a class of your Telegram bot.
Each bot has a state machine inside. The simplest bot has only one state:
```
(defbot test-bot ()
()
(:initial-state
(state (send-text \"Hello world!\"))))
```
This bot will green each who activates it.
To learn more about bot states and actions see CL-TELEGRAM-BOT-DOCS/STATES::@STATES-AND-ACTIONS section.
"
(unless (member 'bot base-classes)
(setf base-classes
(append base-classes
Expand Down
41 changes: 14 additions & 27 deletions v2/server.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,33 @@
#:make-thread
#:destroy-thread)
(:import-from #:log)
;; (:import-from #:cl-telegram-bot/update
;; #:process-updates)
;; (:import-from #:cl-telegram-bot/response
;; #:reply)
;; (:import-from #:cl-telegram-bot/bot
;; #:debug-mode
;; #:defbot)
;; (:import-from #:cl-telegram-bot/message
;; #:on-message)
;; (:import-from #:cl-telegram-bot/entities/command
;; #:update-commands
;; #:on-command)
(:import-from #:trivial-backtrace
#:print-backtrace)
(:import-from #:cl-telegram-bot2/pipeline
#:process-updates
#:continue-processing)
(:import-from #:cl-telegram-bot2/bot
#:debug-mode)
;; This package exports only essential symbols, needed
;; in 80% cases.
(:export ;; #:defbot
;; #:on-message
;; #:reply
#:start-polling
#:stop-polling
;; #:on-command
))
(:export #:start-polling
#:stop-polling))
(in-package #:cl-telegram-bot2/server)



(defvar *threads* nil)


(defun start-polling (bot &key debug
(delay-between-retries 10)
(thread-name "telegram-bot"))
(defun start-polling (bot &key
debug
(delay-between-retries 10)
(thread-name "telegram-bot"))
"Start processing new updates from the Telegram API.
Pass bot instance as the first argument and maybe some other optional arguments.
If DEBUG argument is T, then bot will ignore updates which it can't to process without errors.
Otherwise, an interactive debugger will popup."

(when (getf *threads* bot)
(error "Processing already started."))

Expand All @@ -61,14 +50,12 @@
(stop-bot ()
(stop-polling bot)))

;; (update-commands bot)

(cl-telegram-bot2/bot::start-actors bot)

(setf (getf *threads* bot)
(make-thread
(lambda ()
(handler-bind ((error #'continue-processing-if-not-debug))
(handler-bind ((serious-condition #'continue-processing-if-not-debug))
(process-updates bot)))
:name thread-name))

Expand Down
1 change: 1 addition & 0 deletions v2/spec.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#:simplified-camel-case-to-lisp)
(:import-from #:str
#:param-case)
(:import-from #:cl-telegram-bot2/deps)
(:import-from #:cl-telegram-bot2/errors
#:telegram-error)
(:import-from #:quri))
Expand Down

0 comments on commit 054cc96

Please sign in to comment.