Cap'n Proto Hello World Go Server

Cap'n Proto: https://capnproto.org/ go-capnp: https://github.com/capnproto/go-capnp

This is just a place for me to learn some go and stand up a server that I can send a string to and get one back.

Getting the Server Running

I wrote this up because I'm new to Go and struggled to follow the existing docs a bit. This should get you going from scratch. You can of course just clone down this repo, but if you want to know the work/steps that went into it, read on!

  1. Create a go.mod file in a server dir with these contents

    // server/go.mod
    module server
    
    go 1.19
    
    require capnproto.org/go/capnp/v3 v3.0.0-alpha.28

    and run go mod tidy (you could also run go mod init server and then add the require on the last line followed by go mod tidy)

  2. Create a .capnp file at the top-level dir (for client and server to share) and use the capnp compiler to put the generated go code into the server/hello_world dir

    capnp compile -I$GOPATH/src/capnproto.org/go/capnp/std -ogo:./server/hello_world hello_world.capnp --verbose
    

    This can be a tricky step, you've got to install capnp executable (follow instructions on capnproto.org) and point to an install of go-capnp (they have instructions for this, you can clone it or you can use go to install in the GOPATH like I did). Then you specify the generator go and the output dir ./server/hello_world.

    The result should be a hello_world.capnp.go file under server/hello_world.

  3. Implement methods in hello_world.go and add that to server/hello_world. See file in source for full details, but the gist is:

    • Use the same package as what was generated by go-capnp (hello_world)
    • Make a struct that does not match any existing struct names that can implement the server interface. This is easy if you just leave out the underscores type GreeterServer struct{} instead of type Greeter_Server struct{}
    • Add a method to it to implement the interface func (GreeterServer) Greet(ctx context.Context, call Greeter_greet) error
    • See docs on creating messages: https://github.com/capnproto/go-capnp/blob/main/docs/Working-with-Capn-Proto-Types.md
  4. Make a main package with the TCP server in it at main/main.go like the one in this repo. There are a lot of details in there, much of it is in the docs but some I had to piece together myself and I don't know if it's great, being a newcomer and all: https://github.com/capnproto/go-capnp/blob/main/docs/Remote-Procedure-Calls-using-Interfaces.md

Getting the Client Running

I happen to want to use Python as my client, so I'll include that here for completeness though you are welcome to implement whatever client you like. The python client does not require code generation, it dynamically creates methods/types (though you can generate a stubs file to help with type hinting).

  1. The python lib / docs are here: https://github.com/capnproto/pycapnp/ for getting installed and started.

  2. I just have a bare-bones client.py here. The tricky bit is handling the go import in our .capnp file. You have two options a. Update hello_world.capnp to have relative reference to go.capnp (this is the top comment in hello_world.capnp) b. Call capnp.load in the client with an imports arg which adds the location of go.capnp to the search paths (this is used now)

    Both require you help python find go.capnp which is annoying but just how things work.