summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2016-11-17 17:19:53 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2016-11-17 17:19:53 -0400
commitfa8c9a2aac266a910d1f3c093e3d790a12d8ec88 (patch)
treed3b621ce936cde637110a50ceeecc09e76e0bf59
parent0014f1abfbb0544c2bcc9f55a38aeb8c4b0576c1 (diff)
devblog
-rw-r--r--doc/devblog/day_426__grab_bag.mdwn12
-rw-r--r--doc/devblog/day_427__free_p2p.mdwn51
2 files changed, 57 insertions, 6 deletions
diff --git a/doc/devblog/day_426__grab_bag.mdwn b/doc/devblog/day_426__grab_bag.mdwn
index 4a3bf908b..36e32077e 100644
--- a/doc/devblog/day_426__grab_bag.mdwn
+++ b/doc/devblog/day_426__grab_bag.mdwn
@@ -45,19 +45,19 @@ authentication. Which is a whole nother ball of complexity. So, I'm leaning
instead to using a simple custom protocol something like:
> AUTH $localuuid $token
- < AUTH-OK $remoteuuid
+ < AUTH-SUCCESS $remoteuuid
> SENDPACK $length
> $gitdata
< RECVPACK $length
< $gitdata
> GET $pos $key
- < SENDING $length
+ < DATA $length
< $bytes
- > GET-OK
+ > SUCCESS
> PUT $key
- < SEND $pos
- > SENDING $length
+ < PUT-FROM $pos
+ > DATA $length
> $bytes
- < PUT-OK
+ < SUCCESS
Today's work was sponsored by Riku Voipio.
diff --git a/doc/devblog/day_427__free_p2p.mdwn b/doc/devblog/day_427__free_p2p.mdwn
new file mode 100644
index 000000000..7c727587b
--- /dev/null
+++ b/doc/devblog/day_427__free_p2p.mdwn
@@ -0,0 +1,51 @@
+For a Haskell programmer, and day where a big thing is implemented
+without the least scrap of code that touches the IO monad is a good day.
+And this was a good day for me!
+
+Implemented the p2p protocol for tor hidden services. Its needs are somewhat
+similar to the external special remote protocol, but the two protocols are
+not fully overlapping with one-another. Rather than try to unify them, and
+so complicate both cases, I prefer to reuse as much code as possible between
+separate protocol implementations. The generating and parsing of messages
+is largely shared between them. I let the new p2p protocol otherwise
+develop in its own direction.
+
+But, I *do* want to make this p2p protocol reusable for other types of p2p
+networks than tor hidden services. This was an opportunity to use the Free
+monad, which I'd never used before. It worked out great, letting me write
+monadic code to handle requests and responses in the protocol, that reads
+the content of files and resumes transfers and so on, all independent
+of any concrete implementation.
+
+The whole implementation of the protocol only needed 74 lines of monadic code.
+It helped that I was able to factor out functions like this one, that is used
+both for handling a download, and by the remote when an upload is sent to it:
+
+ receiveContent :: Key -> Offset -> Len -> Proto Bool
+ receiveContent key offset len = do
+ content <- receiveBytes len
+ ok <- writeKeyFile key offset content
+ sendMessage $ if ok then SUCCESS else FAILURE
+ return ok
+
+To get transcripts of the protocol in action, the Free monad can be evaluated
+purely, providing the other side of the conversation:
+
+ ghci> putStrLn $ protoDump $ runPure (put (fromJust $ file2key "WORM--foo")) [PUT_FROM (Offset 10), SUCCESS]
+ > PUT WORM--foo
+ < PUT-FROM 10
+ > DATA 90
+ > bytes
+ < SUCCESS
+ result: True
+
+ ghci> putStrLn $ protoDump $ runPure (serve (toUUID "myuuid")) [GET (Offset 0) (fromJust $ file2key "WORM--foo")]
+ < GET 0 WORM--foo
+ > PROTO-ERROR must AUTH first
+ result: ()
+
+Am very happy with all this pure code and that I'm finally using Free monads.
+Next I need to get down the the dirty business of wiring this up to
+actual IO actions, and an actual network connection.
+
+Today's work was sponsored by Jake Vosloo on Patreon.