Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Declarative framework version + Automatic API spec parser #24

Open
wants to merge 17 commits into
base: clos-everywhere
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
.*.~undo-tree~
.DS_Store
*.fasl
.env
1 change: 1 addition & 0 deletions .local.el
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(with-temp-file "/proc/self/comm" (insert "emacs tel-bot"))
1 change: 1 addition & 0 deletions cl-telegram-bot2-deps.asd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
q
16 changes: 16 additions & 0 deletions cl-telegram-bot2-examples.asd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#-asdf3.1 (error "cl-telegram-bot requires ASDF 3.1 because for lower versions pathname does not work for package-inferred systems.")
(defsystem "cl-telegram-bot2-examples"
:description "Telegram Bot API, based on sovietspaceship's work but mostly rewritten."
:author "Alexander Artemenko <[email protected]>"
:license "MIT"
:homepage "https://40ants.com/cl-telegram-bot/"
:source-control (:git "https://github.com/40ants/cl-telegram-bot")
:bug-tracker "https://github.com/40ants/cl-telegram-bot/issues"
:class :40ants-asdf-system
:defsystem-depends-on ("40ants-asdf-system")
:pathname "examples"
:depends-on ("cl-telegram-bot2-examples/calc"
"cl-telegram-bot2-examples/commands"
"cl-telegram-bot2-examples/gallery"
"cl-telegram-bot2-examples/payments")
:in-order-to ((test-op (test-op "cl-telegram-bot2-tests"))))
32 changes: 32 additions & 0 deletions cl-telegram-bot2.asd
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#-asdf3.1 (error "cl-telegram-bot requires ASDF 3.1 because for lower versions pathname does not work for package-inferred systems.")
(defsystem "cl-telegram-bot2"
:description "Telegram Bot API, based on sovietspaceship's work but mostly rewritten."
:author "Alexander Artemenko <[email protected]>"
:license "MIT"
:homepage "https://40ants.com/cl-telegram-bot/"
:source-control (:git "https://github.com/40ants/cl-telegram-bot")
:bug-tracker "https://github.com/40ants/cl-telegram-bot/issues"
:class :40ants-asdf-system
:defsystem-depends-on ("40ants-asdf-system")
:pathname "v2"
:depends-on ("cl-telegram-bot2/api"
"cl-telegram-bot2/pipeline"
"cl-telegram-bot2/server")
:in-order-to ((test-op (test-op "cl-telegram-bot2-tests"))))


(defsystem "cl-telegram-bot2/deps"
:description "Utility system to load non-package-inferred systems using package-inferred imports."
:author "Alexander Artemenko <[email protected]>"
:license "MIT"
:homepage "https://40ants.com/cl-telegram-bot/"
:source-control (:git "https://github.com/40ants/cl-telegram-bot")
:bug-tracker "https://github.com/40ants/cl-telegram-bot/issues"
:depends-on ("njson/jzon"))


(asdf:register-system-packages "log4cl" '("LOG"))
(asdf:register-system-packages "utilities.print-items" '("PRINT-ITEMS"))
(asdf:register-system-packages "dexador" '("DEX"))
(asdf:register-system-packages "sento" '("SENTO.ACTOR-SYSTEM"
"SENTO.ACTOR"))
106 changes: 106 additions & 0 deletions examples/calc.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
(uiop:define-package #:cl-telegram-bot2/calc
(: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
#: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/calc)



(defun calc-result ()
(let* ((num1 (var "first-num"))
(num2 (var "second-num"))
(op-name (var "operation-name"))
(op (gethash op-name
(dict "+" #'+
"-" #'-
"*" #'*
"/" #'/))))
(format nil "Result is: ~A"
(funcall op num1
num2))))

(defun make-prompt-for-op-choice ()
(fmt "Select an operation to apply to ~A and ~A:"
(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"))))))))))


(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)))
113 changes: 113 additions & 0 deletions examples/commands.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
(uiop:define-package #:cl-telegram-bot2-examples/commands
(:use #:cl)
(: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
#:fmt)
(:import-from #:cl-telegram-bot2/pipeline
#:back-to
#:back)
(:import-from #:cl-telegram-bot2/api
#:message-message-id)
(:import-from #:cl-telegram-bot2/state-with-commands
#:global-command
#:command
#:state-with-commands-mixin)
(:import-from #:cl-telegram-bot2/generics
#:on-result
#:on-state-activation
#:process)
(:import-from #:cl-telegram-bot2/state
#:state)
(:import-from #:cl-telegram-bot2/term/back
#:back-to-id)
(:import-from #:cl-telegram-bot2/actions/send-text
#:send-text)
(:import-from #:str
#:trim))
(in-package #:cl-telegram-bot2-examples/commands)


(defun on-help-command (arg update)
(declare (ignore arg update))
(reply "This bot has two states.

At the initial state only two commands are available:

/next - switches bot into the second state.
/help - shows this text.

The second state changes /next command to the /back and provides
additional command /reverse, which will reverse any given text.")
;; It is important to return nothing if we want switch
;; bot to a new state from this handler
(values))


(defun on-reverse-command (arg update)
(declare (ignore update))
(let ((trimmed (trim arg)))
(cond
((or (null trimmed)
(string= trimmed ""))
(reply "This command requires an argument."))
(t
(reply (reverse arg)))))
;; It is important to return nothing if we want switch
;; bot to a new state from this handler
(values))


(defbot test-bot ()
()
(:initial-state
(state (send-text "Initial state. Give /next command to go to the second state.")
:id "initial"
:on-result (send-text "Welcome back! Give /next command to go to the second state.")
:on-update (send-text "Give /next command to go to the second state.")
:commands (list
(command "/next"
(state (send-text "Second state. Give /back command to go to the initial state.")
:on-update (send-text "Give /back command to go to the initial state.")
:commands (list
(command "/back" (back-to-id "initial")
:description "Switch to the prev state")
(command "/reverse" 'on-reverse-command
:description "Switch to the prev state")))
:description "Switch to the next state")
(global-command "/help" 'on-help-command
:description "Show information about bot's commands.")))))


(defvar *bot* nil)


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


(defun start ()
(stop)

(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)))
Loading
Loading