A more framework-y library for use with tg-clj inspired by ring web-servers.
Installation | Getting Started | Examples | Introduction | Persistent Storage | tg-clj
Caution
tg-clj-server
and tg-clj
are considered alpha!
I'll put a warning in the changelog when a breaking change happens. This warning will be removed once I consider the API stable.
When writing a bot that's more complicated than a few :sendMessage
s, it's much
nicer (and more testable) to build it out of modular components:
(defn hello-handler [{u :update}]
{:op :sendMessage
:request {:text "Hi! 🤖"
:chat_id (get-in u [:message :chat :id])}})
(defn reply-handler [{u :update}]
(-> {:op :sendMessage
:request {:text "Message received 📨"}}
(u/reply-to u)))
(def routes
[["/hello" #'hello-handler]
[(constantly true) #'reply-handler]])
(let [client (tg/make-client {:token "<your token>"})
app (defaults/make-app routes)]
(tg-poll/run-server client app))
For the full bot see /examples/simple.clj
.
Use as a dependency in deps.edn
or bb.edn
:
io.github.akeboshiwind/tg-clj {:git/tag "v0.2.2" :git/sha "f742d7e"}
io.github.akeboshiwind/tg-clj-server {:git/tag "v0.3.0" :git/sha "8c66e84"}
To get things setup you'll need some routes:
(require '[tg-clj-server.utils :as u])
(defn poll? [request]
(get-in request [:update :message :poll]))
(def routes
[; A route is made up of:
; - A predicate that takes a request
; - Route-data which must contain a `:handler` function
[poll?
{:handler (fn [{u :update}]
; Return a map with an :op key to automatically call `tg-clj/invoke`
(-> {:op :sendMessage
:request {:text "Woah, that's a poll!"}}
; We have a handy util for replying to a message directly
(u/reply-to u)))}]
; As syntactic sugar:
; - You can supply a string command
; - A handler function
["/command"
(fn [{u :update}]
(-> {:op :sendMessage
:request {:text "Woah, that's a command!"}}
(u/reply-to u)))]])
Then you'll need to create an app
with those routes:
(require '[tg-clj-server.defaults :as defaults])
(def app
(defaults/make-app routes {; You can supply additional middleware here
:middleware []
; You can set options on provided middleware like so
; (The store is in-memory only by default)
:store/path "/path/to/store.edn"}))
defaults/make-app
provides some handy middleware like simple-router and invoke. It's not required, see examples/no_defaults.clj
Then finally you can run the server with a client:
(require '[tg-clj.core :as tg]
'[tg-clj-server.poll :as tg-poll])
(let [client (tg/make-client {:token "<your token>"})]
; Warning, This will block!
(tg-poll/run-server client app))
And that's it! Try out your new bot 🤖
For some complete bots take a look at the /examples
folder.
If you want to learn more start at the intro.
clj -M:dev
To run tests:
clj -X:dev:test
- Tag the commit
v<version>
git push --tags
- Update the README.md with the new version and git hash
- Update the CHANGELOG.md