Created
October 8, 2014 22:21
-
-
Save muraiki/11831288662a0c07b7d4 to your computer and use it in GitHub Desktop.
ajax-to-websocket
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns ajax-to-websocket.core | |
(:require [org.httpkit.server :as server] | |
[org.httpkit.client :as client] | |
[clojure.data.json :as json] | |
[clojure.data :as data] | |
[clojure.core.async :refer [chan <! >! go timeout onto-chan]])) | |
(defn channel-closed | |
"called when websocket channel is closed" | |
[status] | |
(println "channel closed: " status)) | |
(defn parse-url | |
"gets the url from the json sent by the client" | |
[data] | |
(:url (json/read-str data :key-fn keyword))) | |
(defn make-req | |
"grabs the url the client requested. returns name and body json response as map" | |
[url-map] | |
(let [url (:url url-map) | |
res @(client/get url {:as :text})] | |
{:name (:name url-map), | |
:body (json/read-str (:body res) :key-fn keyword)})) | |
(defn is-diff? [a-diff] | |
"given the output vector from data/diff, return if different in any way" | |
(if (and (nil? (first a-diff)) | |
(nil? (second a-diff))) | |
false | |
true)) | |
(defn send-message | |
"Sends a message to the websocket channel, converting it to json" | |
[websocket message] | |
(server/send! websocket (json/write-str message))) | |
(defn send-message-if-diff | |
"Sends a message to the websocket channel if the new data is different from the most recent state" | |
[websocket json-res last-state] | |
(let [url-name (keyword (:name json-res)) | |
res (:body json-res)] | |
(when (is-diff? (data/diff res (url-name @last-state))) | |
(swap! last-state assoc-in [url-name] res) | |
(send-message websocket | |
{:name (:name json-res), | |
:res (:body json-res)})))) | |
(defn socket-handler | |
"main websocket handler" | |
[request] | |
(server/with-channel request channel | |
(server/on-close channel channel-closed) | |
(server/on-receive channel | |
(fn [data] | |
(let [url-maps (json/read-str data :key-fn keyword) | |
poll-channel (chan) | |
last-state (atom {})] | |
(go (while (server/open? channel) | |
(send-message-if-diff channel (<! poll-channel) last-state))) | |
; parallel map, polling the requested urls | |
; sending results to poll-channel one at a time | |
(go (while (server/open? channel) | |
(onto-chan poll-channel (doall (pmap make-req url-maps))) | |
(<! (timeout 10000))))))))) | |
(defn -main [& args] | |
"start the server" | |
(server/run-server socket-handler {:port 8080})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
</head> | |
<body> | |
<script> | |
var socket = new WebSocket("ws://localhost:8080/ws"); | |
socket.onopen = function (event) { | |
var toSend = [ | |
{ | |
name: "jsontest", | |
url: "http://ip.jsontest.com/" | |
} | |
]; | |
socket.send(JSON.stringify(toSend)); | |
console.log("sent"); | |
}; | |
socket.onmessage = function (event) { | |
var res = JSON.parse(event.data); | |
console.log(res); | |
var newDiv = document.createElement("div"); | |
var newContent = document.createTextNode(res.ip); | |
newDiv.appendChild(newContent); | |
document.body.appendChild(newDiv); | |
} | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defproject ajax-to-websocket "0.1.0-SNAPSHOT" | |
:description "Server that helps translate a json api that relies on ajax polling to websockets" | |
:url "http://example.com/FIXME" | |
:license {:name "Eclipse Public License" | |
:url "http://www.eclipse.org/legal/epl-v10.html"} | |
:dependencies [[org.clojure/clojure "1.6.0"] | |
[org.clojure/core.async "0.1.346.0-17112a-alpha"] | |
[org.clojure/data.json "0.2.5"] | |
[http-kit "2.1.16"]] | |
:main ^:skip-aot ajax-to-websocket.core | |
:target-path "target/%s" | |
:profiles {:uberjar {:aot :all}}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's the error: