-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nrepl: fix bencode quirks by hiding broken values behind a 'pile of poo'
- Loading branch information
Showing
5 changed files
with
99 additions
and
15 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
(ns dirac.lib.bencode-hell | ||
(:require [clojure.walk :refer [postwalk]] | ||
[clojure.edn :as edn])) | ||
|
||
; bencode transport (default for nREPL) cannot be trusted (as of [org.clojure/tools.nrepl "0.2.12"]) | ||
; the list of quirks I've discovered so far: | ||
; 1. encoding booleans throws | ||
; 2. nils are decoded as [] | ||
|
||
; We work around those by encoding broken values as strings with unicode marker (U+1F4A9) "pile of poo" prepended. | ||
; On the nREPL client side, we detect poo markers and decode strings back to clojure values. | ||
|
||
; Anyone observing dirac-related nREPL messages should immediatelly spot that something smelly is going on... | ||
|
||
; Warning! don't get your hands dirty when working with this code! | ||
|
||
(def marker "\uD83D\uDCA9") | ||
(def re-marker (re-pattern (str marker "(.*)"))) | ||
|
||
(defn broken-value? [v] | ||
(or (nil? v) | ||
(boolean? v))) | ||
|
||
(defn encode-value [v] | ||
(pr-str v)) | ||
|
||
(defn decode-value [v] | ||
(edn/read-string v)) | ||
|
||
(defn encoder [v] | ||
(if (broken-value? v) | ||
(str marker (encode-value v)) | ||
v)) | ||
|
||
(defn decoder [v] | ||
(if (string? v) | ||
(if-let [m (re-matches re-marker v)] | ||
(decode-value (second m)) | ||
v) | ||
v)) | ||
|
||
(defn encode-poo [message] | ||
(postwalk encoder message)) | ||
|
||
(defn decode-poo [message] | ||
(postwalk decoder message)) |
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
(ns dirac.nrepl.transports.bencode-workarounds | ||
(:require [clojure.tools.nrepl.transport :as nrepl-transport] | ||
[clojure.tools.logging :as log] | ||
[dirac.logging :as logging] | ||
[dirac.lib.bencode-hell :as bencode-hell] | ||
[dirac.nrepl.debug :as debug]) | ||
(:import (clojure.tools.nrepl.transport Transport))) | ||
|
||
; we have to invent our own encoding/decoding scheme for values which bencode cannot safely transfer | ||
; see dirac.lib.bencode-hell | ||
; | ||
; please note that if user is not using bencode transport but replace it with something sane, this workaround won't break it | ||
|
||
; -- transport wrapper ------------------------------------------------------------------------------------------------------ | ||
|
||
(defrecord BencodeWorkaroundsTransport [nrepl-message transport] | ||
Transport | ||
(recv [_this timeout] | ||
(let [dirty-message (nrepl-transport/recv transport timeout) | ||
clean-message (bencode-hell/decode-poo dirty-message)] | ||
clean-message)) | ||
(send [_this reply-message] | ||
(let [clean-message reply-message | ||
dirty-message (bencode-hell/encode-poo clean-message)] | ||
(nrepl-transport/send transport dirty-message)))) | ||
|
||
; -- public interface ------------------------------------------------------------------------------------------------------- | ||
|
||
(defn make-nrepl-message-with-bencode-workarounds [nrepl-message] | ||
(log/trace "make-nrepl-message-with-bencode-workarounds" (debug/pprint-nrepl-message nrepl-message)) | ||
(update nrepl-message :transport (partial ->BencodeWorkaroundsTransport nrepl-message))) |