Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revived the example with a new structure and docs #5

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/_bin
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2020 Twitch Interactive, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may not
# use this file except in compliance with the License. A copy of the License is
# located at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# or in the "license" file accompanying this file. This file is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

FROM golang:latest AS build
WORKDIR /go/src/github.com/twitchtv/twirp-example
COPY . .
RUN make build

FROM alpine
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=build /go/bin/twirp-example /app/
EXPOSE 8000
ENTRYPOINT ["./twirp-example"]
30 changes: 0 additions & 30 deletions Gopkg.lock

This file was deleted.

11 changes: 0 additions & 11 deletions Gopkg.toml

This file was deleted.

56 changes: 56 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright 2020 Twitch Interactive, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may not
# use this file except in compliance with the License. A copy of the License is
# located at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# or in the "license" file accompanying this file. This file is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

M = $(shell printf "\033[34;1m▶\033[0m")

export GOBIN = $(CURDIR)/_bin
export PROTOPATH = $(GOPATH)/src
export BINDIR := $(GOBIN)
export PATH := $(GOBIN):$(PATH)

protoc_gen_go := $(GOBIN)/protoc-gen-go
protoc_gen_go_src := vendor/github.com/golang/protobuf/protoc-gen-go

protoc_gen_twirp := $(GOBIN)/protoc-gen-twirp
protoc_gen_twirp_src := vendor/github.com/twitchtv/twirp/protoc-gen-twirp

build: $(info $(M) Building project...)
@ CGO_ENABLED=0 go build -o /go/bin/twirp-example ./cmd/server/*.go
.PHONY: build

gen-twirp: $(protoc_gen_go) $(protoc_gen_twirp)
$(info $(M) Generating twirp files...)
@protoc --proto_path=$(GOBIN):. --twirp_out=. --go_out=. ./rpc/haberdasher/service.proto
.PHONY: gen-twirp

$(protoc_gen_go): $(protoc_gen_go_src)
@go install ./$^

$(protoc_gen_twirp): $(protoc_gen_twirp_src)
@go install ./$^

server:
$(info $(M) Starting Development server...)
go run ./cmd/server/main.go

client:
$(info $(M) Starting Client...)
go run ./cmd/client/main.go

docker-image:
$(info $(M) Building app image...)
docker build -t example .

docker-container: docker-image
$(info $(M) Running docker application container...)
docker run -p 8080:8080 example:latest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using $(info ...) is neat, but I would remove any "advanced" features from this Makefile. Let's try to keep just the minimal to run the twirp example. Instead of that, we could add a comment.

40 changes: 29 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,66 @@ Twirp at its [website](https://twitchtv.github.io/twirp/docs/intro.html) or
## Try it out

First, download this repo with the Go tool:

```
go get github.com/twitchtv/twirp-example/...
cd $GOPATH/src/github.com/twitchtv/twirp-example
```

Next, try building the client and server binaries:
```
go build ./cmd/client
go build ./cmd/server
```
Make sure that your machine has `Make` installed.

Next, try running the server and then client:

In one console window:

And run them. In one terminal session:
```
./server
make server
```

And in another:
And then run the client in another window:

```
./client
make client
```

In the client, you should see something like this:

```
-> % ./client
size:12 color:"red" name:"baseball cap"
```

In the server, something like this:

```% ./server
received req svc="Haberdasher" method="MakeHat"
response sent svc="Haberdasher" method="MakeHat" time="109.01µs"
```

If you edit the `service.proto` file and want to regenerate the updated twirp files:

```
make gen-twirp
```

If you want to make a docker image and then serve the container locally:

```
make docker-image && make docker-container
```

## Code structure

The protobuf definition for the service lives in
`rpc/haberdasher/haberdasher.proto`. The `rpc` directory name is a good way to
`rpc/haberdasher/service.proto`. The `rpc` directory name is a good way to
signal where your service definitions reside.

The generated Twirp and Go protobuf code is in the same directory. This makes it
easy to import for both internal and external users - internally, we need to
import it to have the right types for our implmentation of the service
interface, and externally it needs to be available so clients can import it.

The implementation of the server is in `internal/haberdasherserver`. Putting it
The implementation of the server is in `internal/server`. Putting it
in `internal` means that it can't be imported from outside this repository,
which is nice because we don't have to think about API stability nearly as much.

Expand All @@ -61,8 +76,11 @@ requests. This is a good demo of how you can use hooks to extend Twirp's basic
functionality - you can use hooks to add instrumentation or even for
authentication.

`tools/` store the codegen packages that are used to generate the twirp go code. It is stored in such a way that go modules could recognise them and we could create the tools binaries using Makefile.

Finally, `cmd/server` and `cmd/client` wrap things together into executable main
packages.

## License

This library is licensed under the Apache 2.0 License.
4 changes: 2 additions & 2 deletions cmd/client/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 Twitch Interactive, Inc. All Rights Reserved.
// Copyright 2020 Twitch Interactive, Inc. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2021 already 🎉

//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
// use this file except in compliance with the License. A copy of the License is
Expand Down Expand Up @@ -26,7 +26,7 @@ import (
func main() {
// Create a client capable of talking to a Haberdasher server running on
// localhost. This is a generated function call.
client := haberdasher.NewHaberdasherJSONClient("http://localhost:8080", &http.Client{})
client := haberdasher.NewHaberdasherProtobufClient("http://localhost:8080", &http.Client{})

var (
hat *haberdasher.Hat
Expand Down
5 changes: 2 additions & 3 deletions cmd/server/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# twirp example server #
# twirp example server

This binary is an example twirp server. It's meant mostly to be read
and to be used in conjunction with the neighboring client binary.
This is an example twirp server.

When a request is made, the server will log the statsd messages it
would have sent, so you'll see stuff like this:
Expand Down
50 changes: 45 additions & 5 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 Twitch Interactive, Inc. All Rights Reserved.
// Copyright 2020 Twitch Interactive, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
// use this file except in compliance with the License. A copy of the License is
Expand All @@ -14,18 +14,58 @@
package main

import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"

"github.com/twitchtv/twirp-example/internal/haberdasherserver"
"github.com/twitchtv/twirp-example/internal/hooks"
"github.com/twitchtv/twirp-example/internal/server"
"github.com/twitchtv/twirp-example/rpc/haberdasher"
)

func main() {
hook := hooks.LoggingHooks(os.Stderr)
service := haberdasherserver.New()
server := haberdasher.NewHaberdasherServer(service, hook)
log.Fatal(http.ListenAndServe(":8080", server))
twirpServer := server.NewHaberdasherServer()

twirpHandler := haberdasher.NewHaberdasherServer(twirpServer, hook)
mux := http.NewServeMux()
mux.Handle(haberdasher.HaberdasherPathPrefix, twirpHandler)

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, int64(10<<20)) // 10 MiB max per request
mux.ServeHTTP(w, r)
})

// This port can be in a config file at some point
port := 8080
appServer := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: handler,
}

shutdownCh := make(chan bool)
go func() {
shutdownSIGch := make(chan os.Signal, 1)
signal.Notify(shutdownSIGch, syscall.SIGINT, syscall.SIGTERM)

<-shutdownSIGch

log.Println("Received shutdown signal request")
if err := appServer.Shutdown(context.Background()); err != nil {
log.Fatalf("Failed to shutdown server: %s", err.Error())
}
close(shutdownCh)
}()

log.Printf("Starting example twirp service on port %d \n", port)
if err := appServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Failed to listen and serve: %s", err.Error())
}

<-shutdownCh
log.Println("Server successfully shutdown")
}
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/twitchtv/twirp-example

go 1.15

require (
github.com/golang/protobuf v1.4.3
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/twitchtv/twirp v7.1.1+incompatible
google.golang.org/protobuf v1.25.0
)
Loading