I was speaking with Christine (who is my partner, for more context) today about issues I faced with setting up a simple app with Goblins that uses ocapn and the new Prelay netlayer. I would like to more widely distribute some feedback on things that I think would improve the interface for users of Goblins.
Ceremony
There is too much “ceremony” when using ocapn. It’s good that there are a lot of layers under the hood, but there should be an easy way to establish a connection and register objects.
I was working on a simple prelay echo peer today and in order to create a listener I have to:
- (Vat management and construction of userland objects omitted)
- Call
fetch-and-spawn-prelay-netlayer
with the ‘setup sturdyref’ generated by the prelay utility. - Await the promise to receive a prelay netlayer
- Spawn a mycapn instance
- Register the listener object with mycapn, and pass
'prelay
as the tag even though it’s the only registered netlayer type- Note that this slipped me up at first as I was expecting this to be
'tcp-tls
because I saw the prelay as a light wrapper rather than a fully named netlayer.
- Note that this slipped me up at first as I was expecting this to be
One more abstraction layer
I think having one more level of abstraction available would be helpful for the typical case.
mycapn-registry
A capability we could call a “Registry” could wrap a mycapn instance and represent the capability to register or enliven refs with the selected netlayer only. This is the common case where mycapn is needed. Users who are messing with multiple netlayers at once can go to the existing interface to get more fine-grained control, but I suspect most cases holding onto this registry object is enough.
Hypothetical API
prelay-sref->mycapn-registry <sref> [#:netlayer] [#:mycapn]
- takes a prelay sturdyref and returns a promise that resolves to a registry, wrapping a new or provided netlayer and mycapn instancemake-mycapn-registry <netlayer-type> [#:netlayer] [#:mycapn]
- Creates a fresh registry (wrapping a new or existing netlayer and mycapn instance) for the given netlayer.^registry
methods:'register
- Registers and returns the ID.'enliven
- Forwards to the internal mycapn instance’s enliven method.
Current code
(define (^listener bcom)
(lambda (text) (format #t "~a\n" text)))
(define (listen setup-sref)
(with-vat echo-vat
(on (fetch-and-spawn-prelay-netlayer setup-sref)
(lambda (netlayer)
(define mycapn (spawn-mycapn netlayer))
(define listener (spawn ^listener))
(define listener-id ($ mycapn 'register listener 'prelay))
(format #t "Listener registered at ~s\n" (ocapn-id->string listener-id))))))
(define (say setup-sref listener-sref text)
(with-vat echo-vat
(on (fetch-and-spawn-prelay-netlayer setup-sref)
(lambda (netlayer)
(on (<- (<- (spawn-mycapn netlayer) 'enliven listener-sref) text)
(lambda (_)
(format #t "sent message ~s.\n" text)))))))
Hypothetical code
(define (^listener bcom)
(lambda (text) (format #t "~a\n" text)))
(define (listen setup-sref)
(with-vat echo-vat
(on (prelay-sref->mycapn-registry setup-sref)
(lambda (registry)
(define listener (spawn ^listener))
(define listener-id ($ registry 'register listener))
(format #t "Listening at ~a\n" (ocapn-id->string listener-id)))))
(define (say setup-sref listener-sref text)
(with-vat echo-vat
(on prelay-sref->mycapn-registry setup-sref)
(lambda (registry)
(on (<- (<- registry 'enliven listener-sref) text)
(lambda (_)
(format #t "sent message ~s.\n" text)))))))
Hopefully this is clear to folks who are familiar with this API. I’d love to hear feedback on this idea. Yeah, it’s pretty simple ultimately, but I think having a good API for users will make it easier to ease into the concept.