On this page:
5.1 What Cap  TP gives you
5.2 Cap  TP Limitations
5.3 Cap  TP usage example
5.3.1 Launch a Tor daemon for Goblins
5.3.2 Two Goblins programs chatting over Cap  TP
5.4 Cap  TP API
spawn-mycapn
8.2

5 Distributed programming with CapTP

 (require goblins/ocapn/captp) package: goblins

CAUTION: CapTP support is still in early days. Please do not rely yet on this protocol being stable.

CapTP is a system for enabling distributed programming in a mutually suspicious network. It originated in the E programming language but has since appeared in Cap’N Proto, Waterken, Agoric’s SwingSet, and now Goblins.

5.1 What CapTP gives you

All of these combine into an efficient and powerful protocol that, most powerfully of all, the author of Goblins programs mostly need not think too much about. This circumvents the usual years and years of careful message structure coordination and standardization for many kinds of distributed programs, which can simply be written as normal Goblins programs rather than bespoke protocols.

5.2 CapTP Limitations

5.3 CapTP usage example

There’s still work to be done in terms of making Goblins’ CapTP "easier" to use and set up. In the meanwhile, let’s give an example showing off Goblins’ Tor Onion Services support.

5.3.1 Launch a Tor daemon for Goblins

In order for this to work, Goblins needs a Tor daemon to talk to... Goblins can set up and manage the onion services itself once it has that. So far it seems like running a single Goblins tor process "as your user" is the easiest option, and let various Goblins processes connect to that.

Here’s an example config file template... replace <user> with your actual username:

DataDirectory /home/<user>/.cache/goblins/tor/data/

SocksPort unix:/home/<user>/.cache/goblins/tor/tor-socks-sock RelaxDirModeCheck

ControlSocket unix:/home/<user>/.cache/goblins/tor/tor-control-sock RelaxDirModeCheck

Log notice file /home/<user>/.cache/goblins/tor/tor-log.txt

Put in ~/.config/goblins/tor-config.txt or something.

You’ll also want to make the relevant directories:

mkdir -p ~/.cache/goblins/tor/data

Okay, now you can launch the Tor daemon:

tor -f ~/.config/goblins/tor-config.txt

In the future we should probably make a raco launcher that does the above for users so they don’t need to read this section. :P

5.3.2 Two Goblins programs chatting over CapTP

Here’s our server, save as captp-alice.rkt:

#lang racket
 
(require goblins
         goblins/actor-lib/bootstrap
         goblins/ocapn
         goblins/ocapn/netlayer/onion
         net/url)
 
;; Machine to talk to the network on
(define-vat-run machine-run (make-vat))
(define mycapn
  (machine-run
   (spawn-mycapn (setup-onion-netlayer))))
 
;; Get the command line argument for Alice's address
(define alice-sref
  (command-line #:args (alice-sref-str)
                (string->ocapn-sturdyref alice-sref-str)))
 
;; Set up a vat for "alice"
(define-vat-run a-run (make-vat))
(a-run
 (define alice-vow (<- mycapn 'enliven alice-sref))
 (on (<- alice-vow "Alice")
     (lambda (heard-back)
       (displayln (format "Alice heard back: ~a" heard-back))
       ;; we're done
       (semaphore-post finished))))
 
;; A semaphore for us to signal once we've heard back from Alice
(define finished (make-semaphore))
(sync finished)

Traditionally Alice talks to Bob, you see. So now we need Bob.

Now save the following client code as captp-bob.rkt:

#lang racket
 
(require goblins
         goblins/actor-lib/bootstrap
         goblins/ocapn
         goblins/ocapn/netlayer/onion
         net/url)
 
;; Bob is going to be a "greeter" of sorts, so let's define what
;; that is
(define (^greeter _bcom my-name)   ; constructor args
  (lambda (your-name)              ; invocation args
    (format "Hello ~a, my name is ~a!" your-name my-name)))
 
;; Now let's make a vat for bob, and run bob in it
(define-vat-run b-run (make-vat))
(define bob (b-run (spawn ^greeter "Bob")))
 
;; First, let's set up our "machine" for the network
(define-vat-run machine-run (make-vat))
(machine-run
 (define mycapn
   (spawn-mycapn (setup-onion-netlayer)))
 
 ;; Now we need a sturdyref for Bob... let's print it out so that
 ;; we know how to connect
 (define bob-sturdyref
   ($ mycapn 'register bob 'onion))
 
 ;; And let's print out to the command line
 (displayln (format "Bob's sturdyref: ~a"
                    (url->string (ocapn-sturdyref->url bob-sturdyref)))))
 
;; And we need some way to keep things open despite the other vats
;; humming along in their own threads... this kluge does it
(sync (make-semaphore))

Okay, let’s try it out. Open up two terminals, and in the first one run:

racket captp-bob.rkt

It’ll spit out a captp "sturdyref" URI. Copy it and in a new terminal paste it as the argument to captp-alice.rkt:

racket captp-alice.rkt STURDYREF-GOES-HERE

You should see:

Bob heard back: Hello Bob, my name is Alice!

If that worked, your connection succeeded! Horray!

5.4 CapTP API

procedure

(spawn-mycapn netlayer ...)  local-refr?

  netlayer : local-refr?
Spawns a captp "machine router". Needs to be run in a vat context. Needs to be supplied netlayers in order to operate; see the Tor Onion Services example above for an example.

Returns an object representing the machine with various methods that Chris really ought to document.

Sorry, these docs are pretty sparse; we hope to make them better. Hopefully the above example helps get you started.