Skip to content

A more framework-y library for use with tg-clj inspired by ring web-servers.

License

Notifications You must be signed in to change notification settings

Akeboshiwind/tg-clj-server

Repository files navigation

tg-clj-server

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.

Why

When writing a bot that's more complicated than a few :sendMessages, 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.

Installation

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"}

Getting Started

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.

Dev

clj -M:dev

To run tests:

clj -X:dev:test

Releasing

  1. Tag the commit v<version>
  2. git push --tags
  3. Update the README.md with the new version and git hash
  4. Update the CHANGELOG.md

About

A more framework-y library for use with tg-clj inspired by ring web-servers.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published