= Transports

////
 talk about strings vs. bytestrings, the encoding thereof, etc when we
figure that out
////

_Transports_ are roughly analogous to Ring's adapters: they provide an
implementation of a common protocol (`nrepl.transport.Transport`)
to enable nREPL clients and servers to send and receive messages without regard
for the underlying channel or particulars of message encoding.

nREPL includes three transports, all of which are socket-based: a "tty"
transport that allows one to connect to an nREPL endpoint using e.g. `telnet`
(which therefore supports only the most simplistic interactive evaluation of
expressions), one that uses
https://wiki.theory.org/index.php/BitTorrentSpecification#Bencoding[bencode] to encode
nREPL messages over sockets, and one that uses EDN as the data exchange format.

NOTE: It's the bencode transport that is used by default by
`nrepl.server/start-server` and `nrepl.core/connect`.

https://github.com/nrepl/nrepl/wiki/Extensions[Other nREPL transports (e.g. HTTP) are available as libraries].

== Bencode Transport

This is, and will mostly likely remain, nREPL's default and primary
transport. It is pronounced B-Encode, and is a relatively simple format,
comprising of only two scalar types (byte strings and integer) and two
collection types (dictionaries and lists).

A simple nREPL message, to run the operation `eval` on the code `(+ 2 2)` would
look like this in bencode (line breaks added for clarity):

----
d
4:code
7:(+ 2 2)
2:op
4:eval
e
----

In documentation, this message would typically be expressed in EDN format:

[source,clojure]
----
{:op "eval" :code "(+ 2 2)"}
----

Given that many, if not most, nREPL clients do not use EDN as their native data
format, it's best to think of this as the format of a message once received by
nREPL. Correspondingly, responses are in the form they take just before being
sent through the transport.

nREPL's bencode encoder/decoder performs the following type conversions:

.How nrepl.bencode handles types
|=======================================
| EDN type > | Bencode type > | EDN type

| String     | String         | String
| Keyword    | String         | String
| Symbol     | String         | String
| Integer    | Integer        | Integer
| Map        | Dictionary     | Map
| Vector     | List           | Vector
| List       | List           | Vector
| Set        | List           | Vector
|=======================================

In addition, nREPL server performs a `keywordize-keys` operation on the received
map, restoring the likes of `:op` and `:code` to keywords. Thus, the use of
keywords in writing nREPL message is mainly for clarity. The following messages,
when encoded using nREPL's bencode encoder and received by nREPL, are equivalent:

[source,clojure]
----
 {:op "eval"  ...} ;; this is also the internal representation
 {:op :eval ...}
 {"op" "eval" ...}
 {"op" :eval ...}
----

There's nothing special you have to do to use the bencode transport,
as it's the default transport for `nrepl.server/start-server`.

You'll need a bencode capable client to connect to an nREPL server that transport.

TIP: nREPL's bencode implementation is available as a https://github.com/nrepl/bencode[standalone library].
Keep in mind that nREPL itself doesn't use this library, as it's committed to having 0 runtime dependencies.
The code in the library and in nREPL `nrepl.bencode` namespace is identical, though, and will be kept in sync
in the future.

== EDN Transport

NOTE: The EDN transport was introduced in nREPL 0.7.

The main difference between the bencode transport and the EDN one is that instead of bencode dictionaries and lists, and being limited to integer and byte string types, you'd be sending and receiving full EDN structures and types, including maps, vectors, lists, sets, strings, keywords and symbols. The structures of the messages is similar, only the data format changes.

This may be useful in a couple of usecases: In some clients, including ClojureScript ones, where EDN is easier to handle than bencode. Furthermore, because this transport exposes more of the richer data types in the internals of nREPL and its middleware, it may support more complex usecases.

The introduction of the EDN transport does require more specification of the message format, whereby some vagueness was allowed for by the limitatioms of bencode. For example, `:op` values are strings, and `:status` is either a keyword, or a set of keywords. This may cause some surprised, unintended consequences. Thus tweaks to the EDN message format may be possible until the transport is declared mature.

These details are reflected in the `nrepl.spec` ns, against which responses are verified during testing. This is not used by nREPL anywhere else at moment.

For example, of the (same as before) four messages

[source,clojure]
----
 {:op "eval"  ...}
 {:op :eval ...}
 {"op" "eval" ...}
 {"op" :eval ...}
----

the first one is considered canonical, though nREPL will accept the second one as well. The third and fourth one will not work.

Using the EDN transport is pretty simple. You just need to start an nREPL server with EDN transport and you're good to go:

[source,clojure]
----
(require
 '[nrepl.server :as server]
 '[nrepl.transport :as transport])

(server/start-server :port 12345 :transport-fn transport/edn)
----

You can also start an nREPL with a EDN transport using `clj`:

[source,shell]
----
$ clj -M:nrepl -m nrepl.cmdline -t nrepl.transport/edn
nREPL server started on port 63266 on host localhost - nrepl+edn://localhost:63266
----

== TTY Transport

Using the TTY transport is pretty simple. You just need to start an nREPL server with TTY transport and you're good to go:

[source,clojure]
----
(require
 '[nrepl.server :as server]
 '[nrepl.transport :as transport])

(server/start-server :port 12345 :transport-fn transport/tty :greeting-fn transport/tty-greeting)
----

NOTE: The `:greeting-fn` is responsible for printing the initial message you'll see
upon connecting.

Afterwards you can simply connect to the server with some TTY client like `telnet`, `nc` or `inf-clojure`.

[source,shell]
----
$ nc localhost 12345

;; Clojure 1.9.0
user=>
----

Starting with nREPL 0.5 you can also start an nREPL with a TTY transport using `clj`:

[source,shell]
----
$ clj -M:nrepl -m nrepl.cmdline -t nrepl.transport/tty
nREPL server started on port 63266 on host localhost - telnet://localhost:63266
----
