Skip to content
This repository has been archived by the owner on Jul 24, 2019. It is now read-only.

Commit

Permalink
Snitching bencode from party-repl
Browse files Browse the repository at this point in the history
  • Loading branch information
PEZ committed Dec 19, 2018
1 parent 06c53da commit 8167c77
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 26 deletions.
19 changes: 16 additions & 3 deletions packages/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"paredit.js": "^0.3.4",
"parinfer": "^3.12.0",
"bencoder": "^0.0.5",
"bencode": "^2.0.0",
"buffer": "^5.2.1"
}
}
3 changes: 2 additions & 1 deletion shadow-cljs.edn
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{:dependencies [[pez/cljfmt "0.0.3-SNAPSHOT"]
#_[zprint "0.4.11"]
[cider/cider-nrepl "0.18.0"]]
[cider/cider-nrepl "0.19.0-SNAPSHOT"]
[binaryage/oops "0.6.4"]]

:source-paths ["src" "test"]

Expand Down
30 changes: 8 additions & 22 deletions src/calva/repl/nrepl.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
(:require
["net" :as net]
["bencoder" :as bencoder]
[clojure-party-repl.bencode :as bencode]
["buffer" :as buf]
[clojure.string :as str]
[calva.js-utils :refer [cljify jsify]]))
Expand Down Expand Up @@ -61,32 +62,17 @@
:msg msg
:results []})
(.on conn "data" (fn [chunk]
(when-let [decoded-messages (let [empty-buffer (buf/Buffer.from "")
buffer (buf/Buffer.concat (jsify [empty-buffer chunk]))]
(when (= 0 (.-length buffer))
(js/console.warn "EMPTY BUFFER"))
(not-empty (decode [buffer])))]
(when-let [decoded-messages (bencode/decode chunk)]
(dorun (map (fn [decoded]
(let [d-id (:id decoded)
cb (get-in @*results [d-id :callback])
results (get-in @*results [d-id :results])]
(swap! *results assoc-in [d-id :results] (conj results decoded))
(when (some #{"done"} (:status decoded))
(let [results (get-in @*results [d-id :results])]
(println (pr-str "*results cb" @*results))
(swap! *results dissoc d-id)
(cb (jsify results))))))
#_(when (some #{"done"} (:status decoded)))
(let [results (get-in @*results [d-id :results])]
(println (pr-str "*results cb" @*results))
(swap! *results dissoc d-id)
(cb (jsify results)))))
decoded-messages))
(println (pr-str "*results pending" @*results)))))
(.write conn (bencoder/encode (jsify (assoc msg :id id))) "binary")))


(comment
(def messages (atom {}))
(let [dm '({:id "a74d6afa-925b-4801-9ab1-7d5879e07802", :new-session "357076d7-fdbb-4d42-8ad2-4284c4980885", :session "d59020f4-2220-477b-9b29-96cbbf653005", :status ["done"]})]
(map (fn [decoded]
(let [d-id (:id decoded)
cb (get-in @messages [d-id :callback])
results (get-in @messages [d-id :results])]
(swap! messages assoc-in [d-id :results] (conj results decoded))))
dm)))
(.write conn (bencode/encode (jsify (assoc msg :id id))))))
100 changes: 100 additions & 0 deletions src/clojure_party_repl/bencode.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
(ns clojure-party-repl.bencode
(:require #_[cljs.nodejs :as node]
[oops.core :refer [oget oset!]]
["bencode" :as bencode]))

#_(def bencode (node/require "bencode"))

(defn reset-decode-data []
(oset! (.-decode bencode) "data" nil)
(oset! (.-decode bencode) "encoding" nil)
(oset! (.-decode bencode) "position" 0))

(defn ^:private decode-next
"Returns a decoded data when it succeeds to decode. Returns nil when there's
no more data to be decoded or when there's only partial data."
[]
(let [previous-position (.-position (.-decode bencode))]
(try
(.next (.-decode bencode))
(catch js/Error e
(when (> (.-position (.-decode bencode))
(.-length (.-data (.-decode bencode))))
(oset! (.-decode bencode) "position" previous-position))
(js/console.log "Caught " e)))))

(defn ^:private decode-all
"Returns a vector of decoded data that was possible to decode as far as
it could."
[]
(loop [all-data []]
(if-let [decoded-data (decode-next)]
(do
(recur (conj all-data decoded-data)))
all-data)))

(defn ^:private concat-data-and-decode
"Returns a vector of decoded-data after concatinating the new data onto the
previous data."
[data]
(js/console.log "Concat and decode...")
(let [new-data (.concat js/Buffer (js/Array. (.-data (.-decode bencode)) (js/Buffer. data)))]
(oset! (.-decode bencode) "data" new-data)
(decode-all)))

(defn decoded-all? []
(js/console.log "Decoded All?: " (when (.-data (.-decode bencode))
(.-length (.-data (.-decode bencode))))
(when (.-data (.-decode bencode))
(.-position (.-decode bencode))))
(or (nil? (.-data (.-decode bencode)))
(= (.-length (.-data (.-decode bencode)))
(.-position (.-decode bencode)))))

(defn get-decode-data []
{:data (oget (.-decode bencode) "data")
:position (oget (.-decode bencode) "position")
:encoding (oget (.-decode bencode) "encoding")})

(defn apply-decode-data
"Sets the given decode data as the bencode state if the data has not been
fully decoded."
[{:keys [data position encoding]}]
(js/console.log "Applying decode data...")
(when (and data position (not= (.-length data) position))
(oset! (.-decode bencode) "data" data)
(oset! (.-decode bencode) "position" position)
(oset! (.-decode bencode) "encoding" encoding)
(js/console.log "Applied data: " (.-length (.-data (.-decode bencode))) (.-position (.-decode bencode)))))

(defn decode
"Returns a vector of decoded data in case the encoded data includes multiple
data chunks. It needs to be in a try-catch block because it can throw when
the given data is empty, partial data, or invalid data.
'decode' object holds two states: the data to be decoded and the position to
start decoding next. The position gets updated when decode.next() succeeds.
Because of these states, we need to handle two different cases:
1. bencode.decode() is called the first time or when all the previous data
has been decoded (meaning the position is at the last index), so we can
override the previous data and just call bencode.decode() again.
2. The previous data is only partially decoded, so the new data needs
to be concatinated onto the previous data before decoding."
[data]
(if (decoded-all?)
(try
(do
(apply-decode-data {:data data
:position 0
:encoding "utf8"})
(decode-all))
(catch js/Error e
(js/console.log "Caught Error during decoding: " e)))
(concat-data-and-decode data)))

(defn encode
"Encodes the given data using bencode."
[data]
(try
(.encode bencode data "binary")
(catch js/Error e
(js/console.log "Failed encoding because of " e))))

0 comments on commit 8167c77

Please sign in to comment.