Skip to content

Instantly share code, notes, and snippets.

@friemen
Last active August 29, 2015 14:07
Show Gist options
  • Save friemen/193117e93a3d6ced6654 to your computer and use it in GitHub Desktop.
Save friemen/193117e93a3d6ced6654 to your computer and use it in GitHub Desktop.
Web Service Integration based on core.async
(ns servint.core
(:require [org.httpkit.server :as server]
[org.httpkit.client :as client]
[clojure.core.async :as async :refer [go >! <!]]
[compojure.core :refer [defroutes GET]]
[compojure.route :as route]
[compojure.handler :as handler]))
;; A complete webapp that demonstrates how to asynchronously
;; query web services
(defn http-get
"Requests content from url in a non-blocking fashion, returning the
result on the specified channel."
[ch url]
(client/get url #(async/put! ch %))
ch)
(defn collect-results
"Starts an async process that waits on the specified channel ch for
a maximum of max results, or until millis milliseconds have passed
by. Returns the process channel that will emit the collected results
in one vector."
[ch max millis]
(let [t-ch (async/timeout millis)]
(async/go-loop [results []]
;; loop and select via alts! from the channel ch or timeout
(let [[result source-ch] (async/alts! [ch t-ch])]
(if (= source-ch t-ch)
results ; this was a timeout
(let [results (conj results result)] ; regular result, append it
(if (= max (count results))
results ; maximum reached, return
(recur results)))))))) ; recur again at go-loop
(defn get-contents
"Requests contents for the given seq of urls and returns channel that
will contain all responses in one vector."
[urls]
(let [ch (async/chan)]
(doseq [url urls]
(http-get ch url)) ; do an async request for each url, the result will go to ch
(collect-results ch (count urls) 200))) ; get the results from the channel ch
(defn main-page
[]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello Web World!"})
(def urls ["http://fssnip.net/20"
"https://api.discogs.com/database/search?q=nirvana"])
(defn collect-page
[]
{:status 200
:body (str (count (async/<!! (get-contents urls))))})
;; define the routing of requests
(defroutes app
(GET "/" []
(main-page))
(GET "/collect" []
(collect-page))
(route/not-found "Unknown resource."))
;; ---------------------------------------------------------------------------
;; Setup HTTP server start! and stop!
(defonce http-server (atom nil))
(defn stop!
"Stop server if running."
[]
(when @http-server
(@http-server :timeout 100)
(reset! http-server nil)
:stopped))
(defn start!
"Start a new server."
[]
(reset! http-server (server/run-server (handler/site #'app) {:port 8080}))
:started)
(defn -main [&args]
(start!))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment