Skip to content

Commit

Permalink
0.1.6
Browse files Browse the repository at this point in the history
  • Loading branch information
dspearson committed May 12, 2019
1 parent cc860d0 commit 49749c3
Show file tree
Hide file tree
Showing 9 changed files with 19 additions and 75 deletions.
12 changes: 1 addition & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,19 @@
[![Build Status](https://travis-ci.org/dspearson/phlegyas.svg?branch=master)](https://travis-ci.org/dspearson/phlegyas)

```clj
[phlegyas "0.1.6-SNAPSHOT"]
[phlegyas "0.1.6"]
```

*WARNING: DRAGONS LIE AHEAD! THIS IS WOEFULLY INCOMPLETE. USE AT YOUR OWN PERIL!*

The vast majority of the protocol-level documentation was sourced from the wonderful [Plan 9 from User Space](https://9fans.github.io/plan9port/man/man9/) project.

I have copied the test resources from [droyo's styx package](https://github.com/droyo/styx/), credit due for making it available.

Run `lein test` to verify things work as they should. Currently, 100% of the provided framedumps are successfully handled, hopefully indicating that this is fully up to spec.

"LISP programmers know the value of everything and the cost of nothing." Thus, I have not measured performance of the encode/decode in any serious manner, and the example state machine is a dumb single loop, likely unsuitable for any serious use. However, the principles of how to piece things together should be evident, and the design entirely customisable.

Note the field names in `types.clj`. The `assemble-packet` function will take a map of these and create a byte-array for you. `disassemble-packet` will do the reverse.

### Development Notes

There are still many functions that require implementation, not least the VFS layer. Consider it unstable and subject to major changes.

I have included a built-in TCP server in order to aid this development, accessible from the phlegyas.core namespace.

Jack in with Spacemacs/CIDER with `,'` and then, at the REPL, `(r)`
Expand All @@ -43,7 +37,3 @@ This should aid in the development cycle.
The example VFS layer will create a single filesystem for attaching, and some example files within, with both dynamic and static content.

When hitting inevitable issues, a simple call to `(r)` again will reset the service back to a clean state, ready to continue on your adventures.

### Example Application

I have created a [small bit of standalone code](https://github.com/dspearson/phlegyas-example) to illustrate how to use this library in your applications.
8 changes: 3 additions & 5 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
(defproject phlegyas "0.1.6-SNAPSHOT"
(defproject phlegyas "0.1.6"
:description "phlegyas: an implementation of 9P2000"
:url "https://github.com/dspearson/phlegyas"
:license {:name "ISC Licence"}
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/core.async "0.4.490"]
[primitive-math "0.1.6"]
[manifold "0.1.9-alpha3"]
[manifold "0.1.8"]
[aleph "0.4.6"]
[buddy/buddy-core "1.4.0"]
[com.taoensso/tufte "2.0.1"]
[org.clojure/core.incubator "0.1.4"]
[com.taoensso/timbre "4.10.0"]]
[org.clojure/core.incubator "0.1.4"]]
:plugins [[cider/cider-nrepl "0.21.1"]
[jonase/eastwood "0.3.5"]]
:main ^:skip-aot phlegyas.core
Expand Down
6 changes: 1 addition & 5 deletions src/phlegyas/buffers.clj
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
(ns phlegyas.buffers
(:require [phlegyas.util :refer :all]
[taoensso.timbre :as log]
[primitive-math :as math
:refer [int->uint
uint->int
:refer [uint->int
short->ushort
ushort->short
long->ulong
ulong->long
byte->ubyte
ubyte->byte]]))

(set! *warn-on-reflection* true)
Expand Down
1 change: 0 additions & 1 deletion src/phlegyas/client.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
(ns phlegyas.client
(:require [clojure.set :as sets]
[manifold.stream :as s]
[taoensso.timbre :as log]
[manifold.deferred :as d]
[clojure.string :as cs]
[aleph.tcp :as tcp]
Expand Down
5 changes: 1 addition & 4 deletions src/phlegyas/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
[clojure.core.async :as async]
[manifold.stream :as s]
[manifold.deferred :as d]
[aleph.tcp :as tcp]
[taoensso.timbre :as log])
[aleph.tcp :as tcp])
(:gen-class))

(defn server!
Expand All @@ -29,8 +28,6 @@
(consume incoming-frame-stream outgoing-frame-stream connection #'state-handler)
connection))

(log/set-level! :info)

(def srv nil)

(defn tcp-route
Expand Down
47 changes: 11 additions & 36 deletions src/phlegyas/frames.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@
[clojure.core.async :as async]
[manifold.deferred :as d]
[manifold.stream :as s]
[taoensso.timbre :as log]
[primitive-math :as math
:refer [ubyte->byte
uint->int
ushort->short
ulong->long]]))
:refer [uint->int]]))

(set! *warn-on-reflection* true)

Expand All @@ -29,18 +25,12 @@
(defn disassemble-packet
"Takes in a byte-array, and attempts to decode it. Produces a map, matching that
of the message type found in the `phlegyas.types` namespace."
[packet & [uuid]]
(log/debug uuid "disassemble-packet")
(let [start (System/nanoTime)
^java.nio.ByteBuffer frame (wrap-buffer packet)
[packet]
(let [^java.nio.ByteBuffer frame (wrap-buffer packet)
len (uint->int (frame-length frame))
frame-typ (frame-type frame)
layout (get frame-layouts frame-typ)
data (into {:frame frame-typ :transaction-id uuid} (for [typ layout] {typ ((get get-operation typ) frame)}))
end (System/nanoTime)]
(if (> (/ (- end start) 1000) 1000)
(log/debug uuid "disassemble time:" (float (/ (- end start) 1000000)) "msecs" ":" frame))
data))
layout (get frame-layouts frame-typ)]
(into {:frame frame-typ} (for [typ layout] {typ ((get get-operation typ) frame)}))))

(defn assemble
"Takes in a frame and frame type, calculates the final size of the frame
Expand All @@ -55,45 +45,30 @@
"Takes in a map representing a frame (see `frame-layouts` in the `phlegyas.types` namespace, and
intro(9P) manual), and encodes it."
[frame]
(log/trace (:transaction-id frame) "assemble-packet")
(log/trace (:transaction-id frame) frame)
(let [start (System/nanoTime)
uuid (:transaction-id frame)
ftype (:frame frame)
layout (get frame-layouts ftype)
data (-> (for [typ layout] ((get put-operation typ) (get frame typ))) flatten (assemble ftype) pack)
end (System/nanoTime)]
(if (> (/ (- end start) 1000000) 100)
(log/debug uuid "slow assemble time:" (float (/ (- end start) 1000000)) "msecs" ":" frame))
data))
(let [ftype (:frame frame)
layout (get frame-layouts ftype)]
(-> (for [typ layout] ((get put-operation typ) (get frame typ))) flatten (assemble ftype) pack)))

(defn dispatch-frame
"Cuts frames along their boundaries, returning any partially assembled packets back to
the frame loop."
[packet out uuid]
(log/trace uuid "dispatch-frame")
[packet out]
(loop [x packet]
(if (< (count x) 4)
(vec x)
(let [l (-> (subvec x 0 4) byte-array ^java.nio.ByteBuffer wrap-buffer frame-length)]
(if (< (count x) l)
(vec x)
(do
(s/put! out (-> x (subvec 0 l) byte-array (disassemble-packet uuid)))
(s/put! out (-> x (subvec 0 l) byte-array disassemble-packet))
(recur (vec (subvec x l)))))))))

(defn frame-assembler
"Spawn a thread to recursively read from an incoming stream."
[in out]
(async/thread
(loop [packet (vec @(s/take! in))]
(let [start (System/nanoTime)
uuid (uuid!)
partial (dispatch-frame packet out uuid)
end (System/nanoTime)]
(log/trace uuid "frame assembler")
(if (> (/ (- end start) 1000000) 100)
(log/debug uuid "slow dispatch-frame time:" (float (/ (- end start) 1000000)) "msecs"))
(let [partial (dispatch-frame packet out)]
(if (s/closed? in)
(s/close! out)
(recur (vec (mapcat seq [partial @(s/take! in)]))))))))
6 changes: 1 addition & 5 deletions src/phlegyas/state.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
[clojure.core.async :as async]
[clojure.core.incubator :as i]
[manifold.stream :as s]
[manifold.deferred :as d]
[taoensso.timbre :as log]))
[manifold.deferred :as d]))

;; an example state machine

Expand Down Expand Up @@ -327,11 +326,8 @@
acknowledgement of a previous action has been sent. Therefore, this can be
executed asynchronously inside a future."
[frame connection out]
(log/debug (:transaction-id frame) "in:" frame)
(conj-val (:in-flight-requests connection) (:tag frame))
(let [reply (((:frame frame) state-handlers) frame connection)]
(log/trace (:transaction-id frame) "state:" @(:state connection))
(log/debug (:transaction-id frame) "out:" reply)
(s/put! out reply)
(disj-val (:in-flight-requests connection) (:tag frame))))

Expand Down
4 changes: 0 additions & 4 deletions src/phlegyas/util.clj
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@
(let [buffer (ByteBuffer/wrap x)]
(.order buffer java.nio.ByteOrder/LITTLE_ENDIAN))))

(defn uuid!
[]
(.toString (java.util.UUID/randomUUID)))

(defn pack
"Pack a sequence into a byte array."
[coll]
Expand Down
5 changes: 1 addition & 4 deletions src/phlegyas/vfs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
[clojure.string :as string]
[clojure.set :as sets]
[primitive-math :as math
:refer [int->uint short->ushort
uint->int ushort->short
long->ulong ulong->long]]
[taoensso.timbre :as log])
:refer [uint->int ulong->long]])
(:import [java.nio.file Files LinkOption]
[java.nio.file.attribute BasicFileAttributes PosixFilePermission PosixFilePermissions PosixFileAttributes]))

Expand Down

0 comments on commit 49749c3

Please sign in to comment.