GopherJS Client and gRPC Server - Part 2

Implement the server

I like to start by creating a struct and write a simple definition that’ll immediately fail to compile.

package server

import (
	"github.com/johanbrandhorst/gopherjs-grpc-websocket/protos/server"
)

type Server struct{}

var _ server.MyServerServer = &Server{}

This won’t compile, because the Server struct does not implement the server.MyServerServer interface. But it’ll also tell us what we’ve got left to implement. So lets implement the server methods:

func (s Server) Simple(ctx context.Context, _ *empty.Empty) (*server.MyMessage, error) {
	return &server.MyMessage{
		Msg: "A simple message",
	}, nil
}

The Simple method gets a simple implementation, returning a simple message.

func (s Server) Unary(_ *empty.Empty, srv server.MyServer_UnaryServer) error {
	// Send 4 messages
	for i := uint32(0); i < 4; i++ {
		msg := &server.MyMessage{
			Msg: "A unary message",
			Num: i,
		}

		if err := srv.Send(msg); err != nil {
			return err
		}

		// Sleep to simulate some work
		time.Sleep(time.Second)
	}

	return nil
}

The Unary method simulates a longer running function that does some work and periodically replies with some result.

func (s Server) Bidi(srv server.MyServer_BidiServer) error {
	for i := uint32(0); ; i++ {
		// Blocks until a message is received
		msg, err := srv.Recv()
		if err != nil {
			if err == io.EOF {
				// Client closed connection
				return nil
			}

			return err
		}

		// Just echo back the message sent,
		// incrementing the counter
		msg.Num = i
		if err := srv.Send(msg); err != nil {
			return err
		}
	}
}

The Bidi method listens for any messages sent over the stream and echoes the message back, incrementing the counter each time. This is a very simple use of the gRPC bidi server, but since what we’re really interested in here is the client implementation, it’ll do.

Now that we’re done with the server, we can start looking at the client implementation.