A Blog

On tech and music

John Nguyen
career code language misc music
Introducing Graviton

I’d like to introduce Graviton in this post. Its a name I made up for my project mentioned in a previous post. There’s no real point to the name, except that it uses Electron plus Go. So I figured I’d choose a cool physics based name that starts with G.

In this post I’ll explain the basic steps in communicating between the front and back. In this case a “Hello World” should do the trick.

So there are three parts to a graviton app:

The first two parts are covered with Electron.js. And the backend is covered by Go, believe it or not.

Connecting the front-end to the glue-end is done by Electron’s internal ipc package. Its an event based system.

Let’s send a “Hello from front-end” message from our front-end. I’m a react.js guy as well, so that’s what I’ll be using.

Create a React component which has a button which calls:

ipc.send('SendHello', 'Front-end');

In the glue-end, you’ll want a handler for this event, which basically just passes this onto the backend

var client = new todoProto.Todo('localhost:3000', grpc.Credentials.createInsecure());

ipc.on('SendHello', function(event, arg) {
  client.sendHello({request: arg}, function(err, response) {
    if (err) { console.log(err); }
    event.sender.send('SendHelloResponse', response)
  });
})

The communication between the glue-end and the backend needs to be declared in a protobuf3 file. The glue-end will also handle the response which will be sent back over IPC to the front-end:

syntax = "proto3";

package Hello;

message SendHelloRequest {
  string request = 1;
}

message SendHelloResponse {
  string response = 1;
}

service Todo {
  rpc SendHello(SendHelloRequest) returns
  (SendHelloResponse);
}

Now to handle it in the backend:

type sendHelloServer struct{}

// AddTodoService implements pb.AddTodoServer
func (s sendHelloServer) SendHello(ctx context.Context, in *pb.SendHelloRequest) (*pb.SendHelloResponse, error) {
	return &pb.SendHelloResponse{Response: "Hello" + in.Request}, nil
}

func main() {
  port := os.Getenv("PORT")
	host := os.Getenv("HOST")

	if len(port) == 0 {
		port = "3000"
	}

	if len(host) == 0 {
		host = "localhost"
	}

	lis, err := net.Listen("tcp", host+":"+port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterSendHelloServer(s, &sendHelloServer{})
	s.Serve(lis)
}

The response from the Go backend is now sent to your node.js glue-end which will forward it to the front-end. Now handle the response over in your front-end:

ipc.on('SendHelloResponse', (arg) => {
  console.log(arg);
});

You will see “Hello Front-end” in your Electron’s console everytime you click the button! Amazing!

I imagine you’re thinking something like:

Goddamn that was a LOT of effort for a Hello World

Sure it was. But now you have a cool framework for your Go app! You are Hello World-ing across three different layers! Its a self contained, cross platform, multi-language, HTTP2 streaming enabled microservice!

The connection between the presentation layer and the backend is handled in Protobuf/gRPC format. Communication is very efficient compared to JSON, uses HTTP/2 and supports streaming, duplex communication and other cool things that I have only begun to explore.

I would like to imagine that with all this setup you have a scalable system with which you can create cool apps like PopcornTime, Atom and others, except now you can do it with Go.

And that’s pretty damn cool.