An asynchronous Clojure client for the Zulip API.
[org.clojars.studerl/clojure-zulip "0.2.0"]
You'll usually want to define one connection for each Zulip bot you're controlling and pass that to every call you make. The connection
function only returns an options dict and does not immediately open any connections to Zulip.
(require '[clojure-zulip.core :as zulip])
(def conn (zulip/connection {:username "my username" :api-key "my key"}))
Every API command returns a core.async
channel to which the HTTP response will be published. For each request, a new future is created to make the request, publish the response to the channel, and then terminate. Connection pooling is currently not implemented, so if you are making a ton of concurrent requests, you may need to create a pool yourself.
A sync*
wrapper macro is also provided to make any request synchronous.
(def channel (zulip/subscriptions conn))
(async/<!! channel)
=> {:msg "", :result "success", :subscriptions []}
(zulip/sync* (zulip/subscriptions conn))
=> {:msg "", :result "success", :subscriptions []}
Functions are provided for the commands listed on the Zulip endpoints page as well as some undocumented commands such as those used for managing subscriptions.
A common pattern in bot design is to subscribe to a list of streams and then respond to any messages received on those streams or through private messages. The subscribe-events
function is provided to make this easier.
(def queue-id (:queue_id (zulip/sync* (zulip/register conn))))
(def events-channel (first (zulip/subscribe-events conn queue-id))
(loop [] (println (async/<!! events-channel)) (recur))) ;; any messages are published to this channel
The following implements a bot that replies to messages of the form "!echo message" with "message".
(ns echo-bot.core
(:require [clojure-zulip.core :as zulip]
[clojure.string :as str]
[clojure.core.async :as async]))
(def conn (zulip/connection
{:username "echo-bot@zulip.com"
:api-key "secret api key"
:base-url "https://chat.zulip.com/api/v1"}))
(defn handle-event
"Check whether event contains a message starting with '!echo' if yes,
reply (either in private or on stream) with the rest of the message."
[conn event]
(let [message (:message event)
{stream :display_recipient
message-type :type
sender :sender_email
:keys [:subject :content]} message]
;; the message is for us if it begins with `!echo`
(if (and content (str/starts-with? content "!echo "))
;; if so, remove leading `!echo`
(let [reply (subs content 6)]
;; Reply to private message in private
(if (= message-type "private")
(zulip/send-private-message conn sender reply)
;; otherwise post to stream
(zulip/send-stream-message conn stream subject reply))))))
(defn mk-handler-channel
"Create channel that calls `handle-event` on input with `conn`"
[conn]
(let [c (async/chan)]
(async/go-loop []
(handle-event conn (async/<! c))
(recur))
c))
;; Connect event input to handler channel
(let [register-response (zulip/sync* (zulip/register conn))
event-channel kill-channel (zulip/subscribe-events conn register-response)
handler-channel (mk-handler-channel conn)]
(async/pipe event-channel handler-channel))
Copyright © 2013 Travis Thieman
Distributed under the Eclipse Public License version 1.0.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close