Codebase list golang-github-go-kit-kit / f9d8373b-9935-4125-b2b2-694ccabcf82b/upstream/0.12.0
Import upstream version 0.12.0 Debian Janitor 1 year, 5 months ago
309 changed file(s) with 13841 addition(s) and 11354 deletion(s). Raw diff Collapse all Expand all
0 # These are supported funding model platforms
1
2 github: [peterbourgon]
0 name: Bug report
1 description: Report a bug
2 labels: [bug]
3 body:
4 - type: textarea
5 attributes:
6 label: What did you do?
7 validations:
8 required: true
9 - type: textarea
10 attributes:
11 label: What did you expect?
12 validations:
13 required: true
14 - type: textarea
15 attributes:
16 label: What happened instead?
17 validations:
18 required: true
0 blank_issues_enabled: false
1 contact_links:
2 - name: Ask a question
3 url: https://github.com/go-kit/kit/discussions/new?category=q-a
4 about: Questions and discussions with the Go kit community
5
6 - name: Website
7 url: https://gokit.io/
8 about: Project overview, examples, frequently asked questions, etc.
9
10 - name: Reference
11 url: https://pkg.go.dev/github.com/go-kit/kit
12 about: Go kit package documentation
13
14 - name: Slack channel
15 url: https://gophers.slack.com/messages/go-kit
16 about: Real-time discussions and Q&A
0 name: Feature request
1 description: Suggest new functionality or an enhancement
2 body:
3 - type: textarea
4 attributes:
5 label: What would you like?
6 validations:
7 required: true
0 [*.yml]
1 indent_size = 2
0 name: CI
1
2 on:
3 push:
4 branches:
5 - master
6 pull_request:
7
8 jobs:
9 build:
10 name: Build
11 runs-on: ubuntu-latest
12 strategy:
13 matrix: # Support latest and one minor back
14 go: ["1.16", "1.17"]
15 env:
16 GOFLAGS: -mod=readonly
17
18 services:
19 etcd:
20 image: gcr.io/etcd-development/etcd:v3.5.0
21 ports:
22 - 2379
23 env:
24 ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
25 ETCD_ADVERTISE_CLIENT_URLS: http://0.0.0.0:2379
26 options: --health-cmd "ETCDCTL_API=3 etcdctl --endpoints http://localhost:2379 endpoint health" --health-interval 10s --health-timeout 5s --health-retries 5
27
28 consul:
29 image: consul:1.10
30 ports:
31 - 8500
32
33 zk:
34 image: zookeeper:3.5
35 ports:
36 - 2181
37
38 eureka:
39 image: springcloud/eureka
40 ports:
41 - 8761
42 env:
43 eureka.server.responseCacheUpdateIntervalMs: 1000
44
45 steps:
46 - name: Set up Go
47 uses: actions/setup-go@v2.1.3
48 with:
49 stable: "false"
50 go-version: ${{ matrix.go }}
51
52 - name: Checkout code
53 uses: actions/checkout@v2
54
55 - name: Run tests
56 env:
57 ETCD_ADDR: http://localhost:${{ job.services.etcd.ports[2379] }}
58 CONSUL_ADDR: localhost:${{ job.services.consul.ports[8500] }}
59 ZK_ADDR: localhost:${{ job.services.zk.ports[2181] }}
60 EUREKA_ADDR: http://localhost:${{ job.services.eureka.ports[8761] }}/eureka
61 run: go test -v -race -coverprofile=coverage.coverprofile -covermode=atomic -tags integration ./...
62
63 - name: Upload coverage
64 uses: codecov/codecov-action@v1
65 with:
66 token: ${{ secrets.CODECOV_TOKEN }}
67 file: coverage.coverprofile
0 examples/addsvc/addsvc
1 examples/addsvc/client/client
2 examples/apigateway/apigateway
3 examples/profilesvc/profilesvc
4 examples/stringsvc1/stringsvc1
5 examples/stringsvc2/stringsvc2
6 examples/stringsvc3/stringsvc3
70 *.coverprofile
81
92 # Compiled Object files, Static and Dynamic libs (Shared Objects)
+0
-16
.travis.yml less more
0 language: go
1
2 env:
3 - COVERALLS_TOKEN=MYSkSqcsWXd6DmP6TnSeiDhtvuL4u6ndp
4
5 before_install:
6 - go get github.com/mattn/goveralls
7 - go get github.com/modocache/gover
8
9 script:
10 - go test -race -v ./...
11 - ./coveralls.bash
12
13 go:
14 - 1.9.x
15 - tip
0 # Go kit [![Circle CI](https://circleci.com/gh/go-kit/kit.svg?style=shield)](https://circleci.com/gh/go-kit/kit) [![Travis CI](https://travis-ci.org/go-kit/kit.svg?branch=master)](https://travis-ci.org/go-kit/kit) [![GoDoc](https://godoc.org/github.com/go-kit/kit?status.svg)](https://godoc.org/github.com/go-kit/kit) [![Coverage Status](https://coveralls.io/repos/go-kit/kit/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-kit/kit?branch=master) [![Go Report Card](https://goreportcard.com/badge/go-kit/kit)](https://goreportcard.com/report/go-kit/kit) [![Sourcegraph](https://sourcegraph.com/github.com/go-kit/kit/-/badge.svg)](https://sourcegraph.com/github.com/go-kit/kit?badge)
0 # Go kit
11
2 **Go kit** is a **programming toolkit** for building microservices
3 (or elegant monoliths) in Go. We solve common problems in distributed
2 ![GitHub Workflow Status](https://github.com/go-kit/kit/workflows/CI/badge.svg)
3 [![GoDev](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/go-kit/kit?tab=doc)
4 [![codecov](https://codecov.io/gh/go-kit/kit/branch/master/graph/badge.svg)](https://codecov.io/gh/go-kit/kit)
5 [![Go Report Card](https://goreportcard.com/badge/go-kit/kit)](https://goreportcard.com/report/go-kit/kit)
6 [![Sourcegraph](https://sourcegraph.com/github.com/go-kit/kit/-/badge.svg)](https://sourcegraph.com/github.com/go-kit/kit?badge)
7
8 **Go kit** is a **programming toolkit** for building microservices
9 (or elegant monoliths) in Go. We solve common problems in distributed
410 systems and application architecture so you can focus on delivering
511 business value.
612
713 - Website: [gokit.io](https://gokit.io)
814 - Mailing list: [go-kit](https://groups.google.com/forum/#!forum/go-kit)
915 - Slack: [gophers.slack.com](https://gophers.slack.com) **#go-kit** ([invite](https://gophersinvite.herokuapp.com/))
16
17 ## Sponsors
18
19 Click on Sponsor, above, for more information on sponsorship.
1020
1121 ## Motivation
1222
4959
5060 ## Dependency management
5161
52 Go kit is a library, designed to be imported into a binary package. Vendoring
53 is currently the best way for binary package authors to ensure reliable,
54 reproducible builds. Therefore, we strongly recommend our users use vendoring
55 for all of their dependencies, including Go kit. To avoid compatibility and
56 availability issues, Go kit doesn't vendor its own dependencies, and
57 doesn't recommend use of third-party import proxies.
62 Go kit is [modules](https://github.com/golang/go/wiki/Modules) aware, and we
63 encourage users to use the standard modules tooling. But Go kit is at major
64 version 0, so it should be compatible with non-modules environments.
5865
59 There are several tools which make vendoring easier, including
60 [dep](https://github.com/golang/dep),
61 [gb](http://getgb.io),
62 [glide](https://github.com/Masterminds/glide),
63 [gvt](https://github.com/FiloSottile/gvt), and
64 [govendor](https://github.com/kardianos/govendor).
65 In addition, Go kit uses a variety of continuous integration providers
66 to find and fix compatibility problems as soon as they occur.
66 ## Code generators
67
68 There are several third-party tools that can generate Go kit code based on
69 different starting assumptions.
70
71 - [devimteam/microgen](https://github.com/devimteam/microgen)
72 - [GrantZheng/kit](https://github.com/GrantZheng/kit)
73 - [kujtimiihoxha/kit](https://github.com/kujtimiihoxha/kit) (unmaintained)
74 - [nytimes/marvin](https://github.com/nytimes/marvin)
75 - [sagikazarmark/mga](https://github.com/sagikazarmark/mga)
76 - [sagikazarmark/protoc-gen-kit](https://github.com/sagikazarmark/protoc-gen-kit)
77 - [tuneinc/truss](https://github.com/tuneinc/truss)
6778
6879 ## Related projects
6980
7283 ### Service frameworks
7384
7485 - [gizmo](https://github.com/nytimes/gizmo), a microservice toolkit from The New York Times ★
75 - [go-micro](https://github.com/myodc/go-micro), a microservices client/server library ★
86 - [go-micro](https://github.com/micro/go-micro), a distributed systems development framework ★
7687 - [gotalk](https://github.com/rsms/gotalk), async peer communication protocol & library
7788 - [Kite](https://github.com/koding/kite), a micro-service framework
7889 - [gocircuit](https://github.com/gocircuit/circuit), dynamic cloud orchestration
90101 - [mattheath/phosphor](https://github.com/mondough/phosphor), distributed system tracing
91102 - [pivotal-golang/lager](https://github.com/pivotal-golang/lager), an opinionated logging library
92103 - [rubyist/circuitbreaker](https://github.com/rubyist/circuitbreaker), circuit breaker library
93 - [Sirupsen/logrus](https://github.com/Sirupsen/logrus), structured, pluggable logging for Go ★
104 - [sirupsen/logrus](https://github.com/sirupsen/logrus), structured, pluggable logging for Go ★
94105 - [sourcegraph/appdash](https://github.com/sourcegraph/appdash), application tracing system based on Google's Dapper
95106 - [spacemonkeygo/monitor](https://github.com/spacemonkeygo/monitor), data collection, monitoring, instrumentation, and Zipkin client library
96107 - [streadway/handy](https://github.com/streadway/handy), net/http handler filters
100111 ### Web frameworks
101112
102113 - [Gorilla](http://www.gorillatoolkit.org)
103 - [Gin](https://gin-gonic.github.io/gin/)
114 - [Gin](https://gin-gonic.com/)
104115 - [Negroni](https://github.com/codegangsta/negroni)
105116 - [Goji](https://github.com/zenazn/goji)
106117 - [Martini](https://github.com/go-martini/martini)
107118 - [Beego](http://beego.me/)
108119 - [Revel](https://revel.github.io/) (considered [harmful](https://github.com/go-kit/kit/issues/350))
120 - [GoBuffalo](https://gobuffalo.io/)
109121
110122 ## Additional reading
111123
112 - [Architecting for the Cloud](http://fr.slideshare.net/stonse/architecting-for-the-cloud-using-netflixoss-codemash-workshop-29852233) — Netflix
124 - [Architecting for the Cloud](https://slideshare.net/stonse/architecting-for-the-cloud-using-netflixoss-codemash-workshop-29852233) — Netflix
113125 - [Dapper, a Large-Scale Distributed Systems Tracing Infrastructure](http://research.google.com/pubs/pub36356.html) — Google
114126 - [Your Server as a Function](http://monkey.org/~marius/funsrv.pdf) (PDF) — Twitter
115
116 ---
117
118 Development supported by [DigitalOcean](https://digitalocean.com).
+0
-17
ROADMAP.md less more
0 # Roadmap
1
2 This is a coarse-grained roadmap of Go kit development direction in the short
3 to mid-term future. It will be kept reasonably up-to-date by the project
4 maintainers. Suggest new ideas, enhancements, and features using the standard
5 [issues](https://github.com/go-kit/kit/issues) model.
6
7 ## Prioritized
8
9 1. kitgen code generation (#308, #70)
10 1. package pubsub (#298, #295)
11
12 ## Unprioritized
13
14 - package log/levels refactor (#250, #269, #252)
15 - package auth/jwt (#255)
16
0 package casbin
1
2 import (
3 "context"
4 "errors"
5
6 stdcasbin "github.com/casbin/casbin/v2"
7 "github.com/go-kit/kit/endpoint"
8 )
9
10 type contextKey string
11
12 const (
13 // CasbinModelContextKey holds the key to store the access control model
14 // in context, it can be a path to configuration file or a casbin/model
15 // Model.
16 CasbinModelContextKey contextKey = "CasbinModel"
17
18 // CasbinPolicyContextKey holds the key to store the access control policy
19 // in context, it can be a path to policy file or an implementation of
20 // casbin/persist Adapter interface.
21 CasbinPolicyContextKey contextKey = "CasbinPolicy"
22
23 // CasbinEnforcerContextKey holds the key to retrieve the active casbin
24 // Enforcer.
25 CasbinEnforcerContextKey contextKey = "CasbinEnforcer"
26 )
27
28 var (
29 // ErrModelContextMissing denotes a casbin model was not passed into
30 // the parsing of middleware's context.
31 ErrModelContextMissing = errors.New("CasbinModel is required in context")
32
33 // ErrPolicyContextMissing denotes a casbin policy was not passed into
34 // the parsing of middleware's context.
35 ErrPolicyContextMissing = errors.New("CasbinPolicy is required in context")
36
37 // ErrUnauthorized denotes the subject is not authorized to do the action
38 // intended on the given object, based on the context model and policy.
39 ErrUnauthorized = errors.New("Unauthorized Access")
40 )
41
42 // NewEnforcer checks whether the subject is authorized to do the specified
43 // action on the given object. If a valid access control model and policy
44 // is given, then the generated casbin Enforcer is stored in the context
45 // with CasbinEnforcer as the key.
46 func NewEnforcer(
47 subject string, object interface{}, action string,
48 ) endpoint.Middleware {
49 return func(next endpoint.Endpoint) endpoint.Endpoint {
50 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
51 casbinModel := ctx.Value(CasbinModelContextKey)
52 casbinPolicy := ctx.Value(CasbinPolicyContextKey)
53 enforcer, err := stdcasbin.NewEnforcer(casbinModel, casbinPolicy)
54 if err != nil {
55 return nil, err
56 }
57
58 ctx = context.WithValue(ctx, CasbinEnforcerContextKey, enforcer)
59 ok, err := enforcer.Enforce(subject, object, action)
60 if err != nil {
61 return nil, err
62 }
63 if !ok {
64 return nil, ErrUnauthorized
65 }
66
67 return next(ctx, request)
68 }
69 }
70 }
0 package casbin
1
2 import (
3 "context"
4 "testing"
5
6 stdcasbin "github.com/casbin/casbin/v2"
7 "github.com/casbin/casbin/v2/model"
8 fileadapter "github.com/casbin/casbin/v2/persist/file-adapter"
9 )
10
11 func TestStructBaseContext(t *testing.T) {
12 e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil }
13
14 m := model.NewModel()
15 m.AddDef("r", "r", "sub, obj, act")
16 m.AddDef("p", "p", "sub, obj, act")
17 m.AddDef("e", "e", "some(where (p.eft == allow))")
18 m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)")
19
20 a := fileadapter.NewAdapter("testdata/keymatch_policy.csv")
21
22 ctx := context.WithValue(context.Background(), CasbinModelContextKey, m)
23 ctx = context.WithValue(ctx, CasbinPolicyContextKey, a)
24
25 // positive case
26 middleware := NewEnforcer("alice", "/alice_data/resource1", "GET")(e)
27 ctx1, err := middleware(ctx, struct{}{})
28 if err != nil {
29 t.Fatalf("Enforcer returned error: %s", err)
30 }
31 _, ok := ctx1.(context.Context).Value(CasbinEnforcerContextKey).(*stdcasbin.Enforcer)
32 if !ok {
33 t.Fatalf("context should contains the active enforcer")
34 }
35
36 // negative case
37 middleware = NewEnforcer("alice", "/alice_data/resource2", "POST")(e)
38 _, err = middleware(ctx, struct{}{})
39 if err == nil {
40 t.Fatalf("Enforcer should return error")
41 }
42 }
43
44 func TestFileBaseContext(t *testing.T) {
45 e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil }
46 ctx := context.WithValue(context.Background(), CasbinModelContextKey, "testdata/basic_model.conf")
47 ctx = context.WithValue(ctx, CasbinPolicyContextKey, "testdata/basic_policy.csv")
48
49 // positive case
50 middleware := NewEnforcer("alice", "data1", "read")(e)
51 _, err := middleware(ctx, struct{}{})
52 if err != nil {
53 t.Fatalf("Enforcer returned error: %s", err)
54 }
55 }
0 [request_definition]
1 r = sub, obj, act
2
3 [policy_definition]
4 p = sub, obj, act
5
6 [policy_effect]
7 e = some(where (p.eft == allow))
8
9 [matchers]
10 m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
0 p, alice, data1, read
1 p, bob, data2, write
0 p, alice, /alice_data/*, GET
1 p, alice, /alice_data/resource1, POST
2
3 p, bob, /alice_data/resource2, GET
4 p, bob, /bob_data/*, POST
5
6 p, cathy, /cathy_data, (GET)|(POST)
66
77 NewParser takes a key function and an expected signing method and returns an
88 `endpoint.Middleware`. The middleware will parse a token passed into the
9 context via the `jwt.JWTTokenContextKey`. If the token is valid, any claims
9 context via the `jwt.JWTContextKey`. If the token is valid, any claims
1010 will be added to the context via the `jwt.JWTClaimsContextKey`.
1111
1212 ```go
1313 import (
14 stdjwt "github.com/dgrijalva/jwt-go"
14 stdjwt "github.com/golang-jwt/jwt/v4"
1515
1616 "github.com/go-kit/kit/auth/jwt"
1717 "github.com/go-kit/kit/endpoint"
2929
3030 NewSigner takes a JWT key ID header, the signing key, signing method, and a
3131 claims object. It returns an `endpoint.Middleware`. The middleware will build
32 the token string and add it to the context via the `jwt.JWTTokenContextKey`.
32 the token string and add it to the context via the `jwt.JWTContextKey`.
3333
3434 ```go
3535 import (
36 stdjwt "github.com/dgrijalva/jwt-go"
36 stdjwt "github.com/golang-jwt/jwt/v4"
3737
3838 "github.com/go-kit/kit/auth/jwt"
3939 "github.com/go-kit/kit/endpoint"
5454 ```
5555
5656 In order for the parser and the signer to work, the authorization headers need
57 to be passed between the request and the context. `ToHTTPContext()`,
58 `FromHTTPContext()`, `ToGRPCContext()`, and `FromGRPCContext()` are given as
57 to be passed between the request and the context. `HTTPToContext()`,
58 `ContextToHTTP()`, `GRPCToContext()`, and `ContextToGRPC()` are given as
5959 helpers to do this. These functions implement the correlating transport's
6060 RequestFunc interface and can be passed as ClientBefore or ServerBefore
6161 options.
6464
6565 ```go
6666 import (
67 stdjwt "github.com/dgrijalva/jwt-go"
67 stdjwt "github.com/golang-jwt/jwt/v4"
6868
6969 grpctransport "github.com/go-kit/kit/transport/grpc"
7070 "github.com/go-kit/kit/auth/jwt"
7676 options := []httptransport.ClientOption{}
7777 var exampleEndpoint endpoint.Endpoint
7878 {
79 exampleEndpoint = grpctransport.NewClient(..., grpctransport.ClientBefore(jwt.FromGRPCContext())).Endpoint()
79 exampleEndpoint = grpctransport.NewClient(..., grpctransport.ClientBefore(jwt.ContextToGRPC())).Endpoint()
8080 exampleEndpoint = jwt.NewSigner(
8181 "kid-header",
8282 []byte("SigningString"),
9494 "context"
9595
9696 "github.com/go-kit/kit/auth/jwt"
97 "github.com/go-kit/kit/log"
97 "github.com/go-kit/log"
9898 grpctransport "github.com/go-kit/kit/transport/grpc"
9999 )
100100
107107 endpoints.CreateUserEndpoint,
108108 DecodeGRPCCreateUserRequest,
109109 EncodeGRPCCreateUserResponse,
110 append(options, grpctransport.ServerBefore(jwt.ToGRPCContext()))...,
110 append(options, grpctransport.ServerBefore(jwt.GRPCToContext()))...,
111111 ),
112112 getUser: grpctransport.NewServer(
113113 ctx,
33 "context"
44 "errors"
55
6 jwt "github.com/dgrijalva/jwt-go"
7
86 "github.com/go-kit/kit/endpoint"
7 "github.com/golang-jwt/jwt/v4"
98 )
109
1110 type contextKey string
1211
1312 const (
14 // JWTTokenContextKey holds the key used to store a JWT Token in the
15 // context.
16 JWTTokenContextKey contextKey = "JWTToken"
13 // JWTContextKey holds the key used to store a JWT in the context.
14 JWTContextKey contextKey = "JWTToken"
15
16 // JWTTokenContextKey is an alias for JWTContextKey.
17 //
18 // Deprecated: prefer JWTContextKey.
19 JWTTokenContextKey = JWTContextKey
1720
1821 // JWTClaimsContextKey holds the key used to store the JWT Claims in the
1922 // context.
2629 ErrTokenContextMissing = errors.New("token up for parsing was not passed through the context")
2730
2831 // ErrTokenInvalid denotes a token was not able to be validated.
29 ErrTokenInvalid = errors.New("JWT Token was invalid")
32 ErrTokenInvalid = errors.New("JWT was invalid")
3033
3134 // ErrTokenExpired denotes a token's expire header (exp) has since passed.
32 ErrTokenExpired = errors.New("JWT Token is expired")
35 ErrTokenExpired = errors.New("JWT is expired")
3336
34 // ErrTokenMalformed denotes a token was not formatted as a JWT token.
35 ErrTokenMalformed = errors.New("JWT Token is malformed")
37 // ErrTokenMalformed denotes a token was not formatted as a JWT.
38 ErrTokenMalformed = errors.New("JWT is malformed")
3639
3740 // ErrTokenNotActive denotes a token's not before header (nbf) is in the
3841 // future.
4346 ErrUnexpectedSigningMethod = errors.New("unexpected signing method")
4447 )
4548
46 // NewSigner creates a new JWT token generating middleware, specifying key ID,
49 // NewSigner creates a new JWT generating middleware, specifying key ID,
4750 // signing string, signing method and the claims you would like it to contain.
4851 // Tokens are signed with a Key ID header (kid) which is useful for determining
4952 // the key to use for parsing. Particularly useful for clients.
5861 if err != nil {
5962 return nil, err
6063 }
61 ctx = context.WithValue(ctx, JWTTokenContextKey, tokenString)
64 ctx = context.WithValue(ctx, JWTContextKey, tokenString)
6265
6366 return next(ctx, request)
6467 }
8184 return &jwt.StandardClaims{}
8285 }
8386
84 // NewParser creates a new JWT token parsing middleware, specifying a
87 // NewParser creates a new JWT parsing middleware, specifying a
8588 // jwt.Keyfunc interface, the signing method and the claims type to be used. NewParser
8689 // adds the resulting claims to endpoint context or returns error on invalid token.
8790 // Particularly useful for servers.
8992 return func(next endpoint.Endpoint) endpoint.Endpoint {
9093 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
9194 // tokenString is stored in the context from the transport handlers.
92 tokenString, ok := ctx.Value(JWTTokenContextKey).(string)
95 tokenString, ok := ctx.Value(JWTContextKey).(string)
9396 if !ok {
9497 return nil, ErrTokenContextMissing
9598 }
77
88 "crypto/subtle"
99
10 jwt "github.com/dgrijalva/jwt-go"
1110 "github.com/go-kit/kit/endpoint"
11 "github.com/golang-jwt/jwt/v4"
1212 )
1313
1414 type customClaims struct {
4343 t.Fatalf("Signer returned error: %s", err)
4444 }
4545
46 token, ok := ctx.(context.Context).Value(JWTTokenContextKey).(string)
46 token, ok := ctx.(context.Context).Value(JWTContextKey).(string)
4747 if !ok {
4848 t.Fatal("Token did not exist in context")
4949 }
5050
5151 if token != expectedKey {
52 t.Fatalf("JWT tokens did not match: expecting %s got %s", expectedKey, token)
52 t.Fatalf("JWTs did not match: expecting %s got %s", expectedKey, token)
5353 }
5454 }
5555
8686 }
8787
8888 // Invalid Token is passed into the parser
89 ctx := context.WithValue(context.Background(), JWTTokenContextKey, invalidKey)
89 ctx := context.WithValue(context.Background(), JWTContextKey, invalidKey)
9090 _, err = parser(ctx, struct{}{})
9191 if err == nil {
9292 t.Error("Parser should have returned an error")
9494
9595 // Invalid Method is used in the parser
9696 badParser := NewParser(keys, invalidMethod, MapClaimsFactory)(e)
97 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
97 ctx = context.WithValue(context.Background(), JWTContextKey, signedKey)
9898 _, err = badParser(ctx, struct{}{})
9999 if err == nil {
100100 t.Error("Parser should have returned an error")
110110 }
111111
112112 badParser = NewParser(invalidKeys, method, MapClaimsFactory)(e)
113 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
113 ctx = context.WithValue(context.Background(), JWTContextKey, signedKey)
114114 _, err = badParser(ctx, struct{}{})
115115 if err == nil {
116116 t.Error("Parser should have returned an error")
117117 }
118118
119119 // Correct token is passed into the parser
120 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
120 ctx = context.WithValue(context.Background(), JWTContextKey, signedKey)
121121 ctx1, err := parser(ctx, struct{}{})
122122 if err != nil {
123123 t.Fatalf("Parser returned error: %s", err)
134134
135135 // Test for malformed token error response
136136 parser = NewParser(keys, method, StandardClaimsFactory)(e)
137 ctx = context.WithValue(context.Background(), JWTTokenContextKey, malformedKey)
137 ctx = context.WithValue(context.Background(), JWTContextKey, malformedKey)
138138 ctx1, err = parser(ctx, struct{}{})
139139 if want, have := ErrTokenMalformed, err; want != have {
140140 t.Fatalf("Expected %+v, got %+v", want, have)
147147 if err != nil {
148148 t.Fatalf("Unable to Sign Token: %+v", err)
149149 }
150 ctx = context.WithValue(context.Background(), JWTTokenContextKey, token)
150 ctx = context.WithValue(context.Background(), JWTContextKey, token)
151151 ctx1, err = parser(ctx, struct{}{})
152152 if want, have := ErrTokenExpired, err; want != have {
153153 t.Fatalf("Expected %+v, got %+v", want, have)
160160 if err != nil {
161161 t.Fatalf("Unable to Sign Token: %+v", err)
162162 }
163 ctx = context.WithValue(context.Background(), JWTTokenContextKey, token)
163 ctx = context.WithValue(context.Background(), JWTContextKey, token)
164164 ctx1, err = parser(ctx, struct{}{})
165165 if want, have := ErrTokenNotActive, err; want != have {
166166 t.Fatalf("Expected %+v, got %+v", want, have)
168168
169169 // test valid standard claims token
170170 parser = NewParser(keys, method, StandardClaimsFactory)(e)
171 ctx = context.WithValue(context.Background(), JWTTokenContextKey, standardSignedKey)
171 ctx = context.WithValue(context.Background(), JWTContextKey, standardSignedKey)
172172 ctx1, err = parser(ctx, struct{}{})
173173 if err != nil {
174174 t.Fatalf("Parser returned error: %s", err)
183183
184184 // test valid customized claims token
185185 parser = NewParser(keys, method, func() jwt.Claims { return &customClaims{} })(e)
186 ctx = context.WithValue(context.Background(), JWTTokenContextKey, customSignedKey)
186 ctx = context.WithValue(context.Background(), JWTContextKey, customSignedKey)
187187 ctx1, err = parser(ctx, struct{}{})
188188 if err != nil {
189189 t.Fatalf("Parser returned error: %s", err)
204204 var (
205205 kf = func(token *jwt.Token) (interface{}, error) { return []byte("secret"), nil }
206206 e = NewParser(kf, jwt.SigningMethodHS256, MapClaimsFactory)(endpoint.Nop)
207 key = JWTTokenContextKey
207 key = JWTContextKey
208208 val = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtpZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ28ta2l0In0.14M2VmYyApdSlV_LZ88ajjwuaLeIFplB8JpyNy0A19E"
209209 ctx = context.WithValue(context.Background(), key, val)
210210 )
2525 return ctx
2626 }
2727
28 return context.WithValue(ctx, JWTTokenContextKey, token)
28 return context.WithValue(ctx, JWTContextKey, token)
2929 }
3030 }
3131
3333 // useful for clients.
3434 func ContextToHTTP() http.RequestFunc {
3535 return func(ctx context.Context, r *stdhttp.Request) context.Context {
36 token, ok := ctx.Value(JWTTokenContextKey).(string)
36 token, ok := ctx.Value(JWTContextKey).(string)
3737 if ok {
3838 r.Header.Add("Authorization", generateAuthHeaderFromToken(token))
3939 }
5353
5454 token, ok := extractTokenFromAuthHeader(authHeader[0])
5555 if ok {
56 ctx = context.WithValue(ctx, JWTTokenContextKey, token)
56 ctx = context.WithValue(ctx, JWTContextKey, token)
5757 }
5858
5959 return ctx
6464 // useful for clients.
6565 func ContextToGRPC() grpc.ClientRequestFunc {
6666 return func(ctx context.Context, md *metadata.MD) context.Context {
67 token, ok := ctx.Value(JWTTokenContextKey).(string)
67 token, ok := ctx.Value(JWTContextKey).(string)
6868 if ok {
6969 // capital "Key" is illegal in HTTP/2.
7070 (*md)["authorization"] = []string{generateAuthHeaderFromToken(token)}
7676
7777 func extractTokenFromAuthHeader(val string) (token string, ok bool) {
7878 authHeaderParts := strings.Split(val, " ")
79 if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != bearer {
79 if len(authHeaderParts) != 2 || !strings.EqualFold(authHeaderParts[0], bearer) {
8080 return "", false
8181 }
8282
1414 // When the header doesn't exist
1515 ctx := reqFunc(context.Background(), &http.Request{})
1616
17 if ctx.Value(JWTTokenContextKey) != nil {
17 if ctx.Value(JWTContextKey) != nil {
1818 t.Error("Context shouldn't contain the encoded JWT")
1919 }
2020
2323 header.Set("Authorization", "no expected auth header format value")
2424 ctx = reqFunc(context.Background(), &http.Request{Header: header})
2525
26 if ctx.Value(JWTTokenContextKey) != nil {
26 if ctx.Value(JWTContextKey) != nil {
2727 t.Error("Context shouldn't contain the encoded JWT")
2828 }
2929
3131 header.Set("Authorization", generateAuthHeaderFromToken(signedKey))
3232 ctx = reqFunc(context.Background(), &http.Request{Header: header})
3333
34 token := ctx.Value(JWTTokenContextKey).(string)
34 token := ctx.Value(JWTContextKey).(string)
3535 if token != signedKey {
3636 t.Errorf("Context doesn't contain the expected encoded token value; expected: %s, got: %s", signedKey, token)
3737 }
4040 func TestContextToHTTP(t *testing.T) {
4141 reqFunc := ContextToHTTP()
4242
43 // No JWT Token is passed in the context
43 // No JWT is passed in the context
4444 ctx := context.Background()
4545 r := http.Request{}
4646 reqFunc(ctx, &r)
5050 t.Error("authorization key should not exist in metadata")
5151 }
5252
53 // Correct JWT Token is passed in the context
54 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
53 // Correct JWT is passed in the context
54 ctx = context.WithValue(context.Background(), JWTContextKey, signedKey)
5555 r = http.Request{Header: http.Header{}}
5656 reqFunc(ctx, &r)
5757
5959 expected := generateAuthHeaderFromToken(signedKey)
6060
6161 if token != expected {
62 t.Errorf("Authorization header does not contain the expected JWT token; expected %s, got %s", expected, token)
62 t.Errorf("Authorization header does not contain the expected JWT; expected %s, got %s", expected, token)
6363 }
6464 }
6565
6969
7070 // No Authorization header is passed
7171 ctx := reqFunc(context.Background(), md)
72 token := ctx.Value(JWTTokenContextKey)
72 token := ctx.Value(JWTContextKey)
7373 if token != nil {
74 t.Error("Context should not contain a JWT Token")
74 t.Error("Context should not contain a JWT")
7575 }
7676
7777 // Invalid Authorization header is passed
78 md["authorization"] = []string{fmt.Sprintf("%s", signedKey)}
78 md["authorization"] = []string{signedKey}
7979 ctx = reqFunc(context.Background(), md)
80 token = ctx.Value(JWTTokenContextKey)
80 token = ctx.Value(JWTContextKey)
8181 if token != nil {
82 t.Error("Context should not contain a JWT Token")
82 t.Error("Context should not contain a JWT")
8383 }
8484
8585 // Authorization header is correct
8686 md["authorization"] = []string{fmt.Sprintf("Bearer %s", signedKey)}
8787 ctx = reqFunc(context.Background(), md)
88 token, ok := ctx.Value(JWTTokenContextKey).(string)
88 token, ok := ctx.Value(JWTContextKey).(string)
8989 if !ok {
90 t.Fatal("JWT Token not passed to context correctly")
90 t.Fatal("JWT not passed to context correctly")
9191 }
9292
9393 if token != signedKey {
94 t.Errorf("JWT tokens did not match: expecting %s got %s", signedKey, token)
94 t.Errorf("JWTs did not match: expecting %s got %s", signedKey, token)
9595 }
9696 }
9797
9898 func TestContextToGRPC(t *testing.T) {
9999 reqFunc := ContextToGRPC()
100100
101 // No JWT Token is passed in the context
101 // No JWT is passed in the context
102102 ctx := context.Background()
103103 md := metadata.MD{}
104104 reqFunc(ctx, &md)
108108 t.Error("authorization key should not exist in metadata")
109109 }
110110
111 // Correct JWT Token is passed in the context
112 ctx = context.WithValue(context.Background(), JWTTokenContextKey, signedKey)
111 // Correct JWT is passed in the context
112 ctx = context.WithValue(context.Background(), JWTContextKey, signedKey)
113113 md = metadata.MD{}
114114 reqFunc(ctx, &md)
115115
116116 token, ok := md["authorization"]
117117 if !ok {
118 t.Fatal("JWT Token not passed to metadata correctly")
118 t.Fatal("JWT not passed to metadata correctly")
119119 }
120120
121121 if token[0] != generateAuthHeaderFromToken(signedKey) {
122 t.Errorf("JWT tokens did not match: expecting %s got %s", signedKey, token[0])
122 t.Errorf("JWTs did not match: expecting %s got %s", signedKey, token[0])
123123 }
124124 }
+0
-27
circle.yml less more
0 machine:
1 pre:
2 - curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0
3 - sudo rm -rf /usr/local/go
4 - curl -sSL https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz | sudo tar xz -C /usr/local
5 services:
6 - docker
7
8 dependencies:
9 pre:
10 - sudo curl -L "https://github.com/docker/compose/releases/download/1.10.0/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose
11 - sudo chmod +x /usr/local/bin/docker-compose
12 - docker-compose -f docker-compose-integration.yml up -d --force-recreate
13
14 test:
15 pre:
16 - mkdir -p /home/ubuntu/.go_workspace/src/github.com/go-kit
17 - mv /home/ubuntu/kit /home/ubuntu/.go_workspace/src/github.com/go-kit
18 - ln -s /home/ubuntu/.go_workspace/src/github.com/go-kit/kit /home/ubuntu/kit
19 - go get -t github.com/go-kit/kit/...
20 override:
21 - go test -v -race -tags integration github.com/go-kit/kit/...:
22 environment:
23 ETCD_ADDR: http://localhost:2379
24 CONSUL_ADDR: localhost:8500
25 ZK_ADDR: localhost:2181
26 EUREKA_ADDR: http://localhost:8761/eureka
0 comment: false
+0
-31
coveralls.bash less more
0 #!/usr/bin/env bash
1
2 if ! type -P gover
3 then
4 echo gover missing: go get github.com/modocache/gover
5 exit 1
6 fi
7
8 if ! type -P goveralls
9 then
10 echo goveralls missing: go get github.com/mattn/goveralls
11 exit 1
12 fi
13
14 if [[ "$COVERALLS_TOKEN" == "" ]]
15 then
16 echo COVERALLS_TOKEN not set
17 exit 1
18 fi
19
20 go list ./... | grep -v '/examples/' | cut -d'/' -f 4- | while read d
21 do
22 cd $d
23 go test -covermode count -coverprofile coverage.coverprofile
24 cd -
25 done
26
27 gover
28 goveralls -coverprofile gover.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN
29 find . -name '*.coverprofile' -delete
30
00 version: '2'
11 services:
22 etcd:
3 image: quay.io/coreos/etcd
3 image: gcr.io/etcd-development/etcd:v3.5.0
44 ports:
55 - "2379:2379"
6 command: /usr/local/bin/etcd -advertise-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 -listen-client-urls "http://0.0.0.0:2379,http://0.0.0.0:4001"
6 environment:
7 ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
8 ETCD_ADVERTISE_CLIENT_URLS: http://0.0.0.0:2379
9
710 consul:
8 image: progrium/consul
11 image: consul:1.7
912 ports:
1013 - "8500:8500"
11 command: -server -bootstrap
14
1215 zk:
13 image: zookeeper
16 image: zookeeper:3.5
1417 ports:
1518 - "2181:2181"
19
1620 eureka:
1721 image: springcloud/eureka
1822 environment:
2525 return outer(next)
2626 }
2727 }
28
29 // Failer may be implemented by Go kit response types that contain business
30 // logic error details. If Failed returns a non-nil error, the Go kit transport
31 // layer may interpret this as a business logic error, and may encode it
32 // differently than a regular, successful response.
33 //
34 // It's not necessary for your response types to implement Failer, but it may
35 // help for more sophisticated use cases. The addsvc example shows how Failer
36 // should be used by a complete application.
37 type Failer interface {
38 Failed() error
39 }
00 # Examples
11
2 For more information about these examples,
3 including a walkthrough of the stringsvc example,
4 see [gokit.io/examples](https://gokit.io/examples).
2 Examples have been relocated to a separate repository: https://github.com/go-kit/examples
+0
-17
examples/addsvc/README.md less more
0 # addsvc
1
2 addsvc is an example microservice which takes full advantage of most of Go
3 kit's features, including both service- and transport-level middlewares,
4 speaking multiple transports simultaneously, distributed tracing, and rich
5 error definitions. The server binary is available in cmd/addsvc. The client
6 binary is available in cmd/addcli.
7
8 Finally, the addtransport package provides both server and clients for each
9 supported transport. The client structs bake-in certain middlewares, in order to
10 demonstrate the _client library pattern_. But beware: client libraries are
11 generally a bad idea, because they easily lead to the
12 [distributed monolith antipattern](https://www.microservices.com/talks/dont-build-a-distributed-monolith/).
13 If you don't _know_ you need to use one in your organization, it's probably best
14 avoided: prefer moving that logic to consumers, and relying on
15 [contract testing](https://docs.pact.io/best_practices/contract_tests_not_functional_tests.html)
16 to detect incompatibilities.
+0
-198
examples/addsvc/cmd/addcli/addcli.go less more
0 package main
1
2 import (
3 "context"
4 "flag"
5 "fmt"
6 "os"
7 "strconv"
8 "text/tabwriter"
9 "time"
10
11 "google.golang.org/grpc"
12
13 "github.com/apache/thrift/lib/go/thrift"
14 lightstep "github.com/lightstep/lightstep-tracer-go"
15 stdopentracing "github.com/opentracing/opentracing-go"
16 zipkin "github.com/openzipkin/zipkin-go-opentracing"
17 "sourcegraph.com/sourcegraph/appdash"
18 appdashot "sourcegraph.com/sourcegraph/appdash/opentracing"
19
20 "github.com/go-kit/kit/log"
21
22 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
23 "github.com/go-kit/kit/examples/addsvc/pkg/addtransport"
24 addthrift "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc"
25 )
26
27 func main() {
28 // The addcli presumes no service discovery system, and expects users to
29 // provide the direct address of an addsvc. This presumption is reflected in
30 // the addcli binary and the client packages: the -transport.addr flags
31 // and various client constructors both expect host:port strings. For an
32 // example service with a client built on top of a service discovery system,
33 // see profilesvc.
34 fs := flag.NewFlagSet("addcli", flag.ExitOnError)
35 var (
36 httpAddr = fs.String("http-addr", "", "HTTP address of addsvc")
37 grpcAddr = fs.String("grpc-addr", "", "gRPC address of addsvc")
38 thriftAddr = fs.String("thrift-addr", "", "Thrift address of addsvc")
39 thriftProtocol = fs.String("thrift-protocol", "binary", "binary, compact, json, simplejson")
40 thriftBuffer = fs.Int("thrift-buffer", 0, "0 for unbuffered")
41 thriftFramed = fs.Bool("thrift-framed", false, "true to enable framing")
42 zipkinURL = fs.String("zipkin-url", "", "Enable Zipkin tracing via a collector URL e.g. http://localhost:9411/api/v1/spans")
43 lightstepToken = flag.String("lightstep-token", "", "Enable LightStep tracing via a LightStep access token")
44 appdashAddr = flag.String("appdash-addr", "", "Enable Appdash tracing via an Appdash server host:port")
45 method = fs.String("method", "sum", "sum, concat")
46 )
47 fs.Usage = usageFor(fs, os.Args[0]+" [flags] <a> <b>")
48 fs.Parse(os.Args[1:])
49 if len(fs.Args()) != 2 {
50 fs.Usage()
51 os.Exit(1)
52 }
53
54 // This is a demonstration client, which supports multiple tracers.
55 // Your clients will probably just use one tracer.
56 var tracer stdopentracing.Tracer
57 {
58 if *zipkinURL != "" {
59 collector, err := zipkin.NewHTTPCollector(*zipkinURL)
60 if err != nil {
61 fmt.Fprintln(os.Stderr, err.Error())
62 os.Exit(1)
63 }
64 defer collector.Close()
65 var (
66 debug = false
67 hostPort = "localhost:80"
68 serviceName = "addsvc"
69 )
70 recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
71 tracer, err = zipkin.NewTracer(recorder)
72 if err != nil {
73 fmt.Fprintln(os.Stderr, err.Error())
74 os.Exit(1)
75 }
76 } else if *lightstepToken != "" {
77 tracer = lightstep.NewTracer(lightstep.Options{
78 AccessToken: *lightstepToken,
79 })
80 defer lightstep.FlushLightStepTracer(tracer)
81 } else if *appdashAddr != "" {
82 tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr))
83 } else {
84 tracer = stdopentracing.GlobalTracer() // no-op
85 }
86 }
87
88 // This is a demonstration client, which supports multiple transports.
89 // Your clients will probably just define and stick with 1 transport.
90 var (
91 svc addservice.Service
92 err error
93 )
94 if *httpAddr != "" {
95 svc, err = addtransport.NewHTTPClient(*httpAddr, tracer, log.NewNopLogger())
96 } else if *grpcAddr != "" {
97 conn, err := grpc.Dial(*grpcAddr, grpc.WithInsecure(), grpc.WithTimeout(time.Second))
98 if err != nil {
99 fmt.Fprintf(os.Stderr, "error: %v", err)
100 os.Exit(1)
101 }
102 defer conn.Close()
103 svc = addtransport.NewGRPCClient(conn, tracer, log.NewNopLogger())
104 } else if *thriftAddr != "" {
105 // It's necessary to do all of this construction in the func main,
106 // because (among other reasons) we need to control the lifecycle of the
107 // Thrift transport, i.e. close it eventually.
108 var protocolFactory thrift.TProtocolFactory
109 switch *thriftProtocol {
110 case "compact":
111 protocolFactory = thrift.NewTCompactProtocolFactory()
112 case "simplejson":
113 protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
114 case "json":
115 protocolFactory = thrift.NewTJSONProtocolFactory()
116 case "binary", "":
117 protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
118 default:
119 fmt.Fprintf(os.Stderr, "error: invalid protocol %q\n", *thriftProtocol)
120 os.Exit(1)
121 }
122 var transportFactory thrift.TTransportFactory
123 if *thriftBuffer > 0 {
124 transportFactory = thrift.NewTBufferedTransportFactory(*thriftBuffer)
125 } else {
126 transportFactory = thrift.NewTTransportFactory()
127 }
128 if *thriftFramed {
129 transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
130 }
131 transportSocket, err := thrift.NewTSocket(*thriftAddr)
132 if err != nil {
133 fmt.Fprintf(os.Stderr, "error: %v\n", err)
134 os.Exit(1)
135 }
136 transport, err := transportFactory.GetTransport(transportSocket)
137 if err != nil {
138 fmt.Fprintf(os.Stderr, "error: %v\n", err)
139 os.Exit(1)
140 }
141 if err := transport.Open(); err != nil {
142 fmt.Fprintf(os.Stderr, "error: %v\n", err)
143 os.Exit(1)
144 }
145 defer transport.Close()
146 client := addthrift.NewAddServiceClientFactory(transport, protocolFactory)
147 svc = addtransport.NewThriftClient(client)
148 } else {
149 fmt.Fprintf(os.Stderr, "error: no remote address specified\n")
150 os.Exit(1)
151 }
152 if err != nil {
153 fmt.Fprintf(os.Stderr, "error: %v\n", err)
154 os.Exit(1)
155 }
156
157 switch *method {
158 case "sum":
159 a, _ := strconv.ParseInt(fs.Args()[0], 10, 64)
160 b, _ := strconv.ParseInt(fs.Args()[1], 10, 64)
161 v, err := svc.Sum(context.Background(), int(a), int(b))
162 if err != nil {
163 fmt.Fprintf(os.Stderr, "error: %v\n", err)
164 os.Exit(1)
165 }
166 fmt.Fprintf(os.Stdout, "%d + %d = %d\n", a, b, v)
167
168 case "concat":
169 a := fs.Args()[0]
170 b := fs.Args()[1]
171 v, err := svc.Concat(context.Background(), a, b)
172 if err != nil {
173 fmt.Fprintf(os.Stderr, "error: %v\n", err)
174 os.Exit(1)
175 }
176 fmt.Fprintf(os.Stdout, "%q + %q = %q\n", a, b, v)
177
178 default:
179 fmt.Fprintf(os.Stderr, "error: invalid method %q\n", method)
180 os.Exit(1)
181 }
182 }
183
184 func usageFor(fs *flag.FlagSet, short string) func() {
185 return func() {
186 fmt.Fprintf(os.Stderr, "USAGE\n")
187 fmt.Fprintf(os.Stderr, " %s\n", short)
188 fmt.Fprintf(os.Stderr, "\n")
189 fmt.Fprintf(os.Stderr, "FLAGS\n")
190 w := tabwriter.NewWriter(os.Stderr, 0, 2, 2, ' ', 0)
191 fs.VisitAll(func(f *flag.Flag) {
192 fmt.Fprintf(w, "\t-%s %s\t%s\n", f.Name, f.DefValue, f.Usage)
193 })
194 w.Flush()
195 fmt.Fprintf(os.Stderr, "\n")
196 }
197 }
+0
-279
examples/addsvc/cmd/addsvc/addsvc.go less more
0 package main
1
2 import (
3 "flag"
4 "fmt"
5 "net"
6 "net/http"
7 "os"
8 "os/signal"
9 "syscall"
10 "text/tabwriter"
11
12 "github.com/apache/thrift/lib/go/thrift"
13 lightstep "github.com/lightstep/lightstep-tracer-go"
14 "github.com/oklog/oklog/pkg/group"
15 stdopentracing "github.com/opentracing/opentracing-go"
16 zipkin "github.com/openzipkin/zipkin-go-opentracing"
17 stdprometheus "github.com/prometheus/client_golang/prometheus"
18 "github.com/prometheus/client_golang/prometheus/promhttp"
19 "google.golang.org/grpc"
20 "sourcegraph.com/sourcegraph/appdash"
21 appdashot "sourcegraph.com/sourcegraph/appdash/opentracing"
22
23 "github.com/go-kit/kit/log"
24 "github.com/go-kit/kit/metrics"
25 "github.com/go-kit/kit/metrics/prometheus"
26
27 addpb "github.com/go-kit/kit/examples/addsvc/pb"
28 "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint"
29 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
30 "github.com/go-kit/kit/examples/addsvc/pkg/addtransport"
31 addthrift "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc"
32 )
33
34 func main() {
35 // Define our flags. Your service probably won't need to bind listeners for
36 // *all* supported transports, or support both Zipkin and LightStep, and so
37 // on, but we do it here for demonstration purposes.
38 fs := flag.NewFlagSet("addsvc", flag.ExitOnError)
39 var (
40 debugAddr = fs.String("debug.addr", ":8080", "Debug and metrics listen address")
41 httpAddr = fs.String("http-addr", ":8081", "HTTP listen address")
42 grpcAddr = fs.String("grpc-addr", ":8082", "gRPC listen address")
43 thriftAddr = fs.String("thrift-addr", ":8083", "Thrift listen address")
44 thriftProtocol = fs.String("thrift-protocol", "binary", "binary, compact, json, simplejson")
45 thriftBuffer = fs.Int("thrift-buffer", 0, "0 for unbuffered")
46 thriftFramed = fs.Bool("thrift-framed", false, "true to enable framing")
47 zipkinURL = fs.String("zipkin-url", "", "Enable Zipkin tracing via a collector URL e.g. http://localhost:9411/api/v1/spans")
48 lightstepToken = flag.String("lightstep-token", "", "Enable LightStep tracing via a LightStep access token")
49 appdashAddr = flag.String("appdash-addr", "", "Enable Appdash tracing via an Appdash server host:port")
50 )
51 fs.Usage = usageFor(fs, os.Args[0]+" [flags]")
52 fs.Parse(os.Args[1:])
53
54 // Create a single logger, which we'll use and give to other components.
55 var logger log.Logger
56 {
57 logger = log.NewLogfmtLogger(os.Stderr)
58 logger = log.With(logger, "ts", log.DefaultTimestampUTC)
59 logger = log.With(logger, "caller", log.DefaultCaller)
60 }
61
62 // Determine which tracer to use. We'll pass the tracer to all the
63 // components that use it, as a dependency.
64 var tracer stdopentracing.Tracer
65 {
66 if *zipkinURL != "" {
67 logger.Log("tracer", "Zipkin", "URL", *zipkinURL)
68 collector, err := zipkin.NewHTTPCollector(*zipkinURL)
69 if err != nil {
70 logger.Log("err", err)
71 os.Exit(1)
72 }
73 defer collector.Close()
74 var (
75 debug = false
76 hostPort = "localhost:80"
77 serviceName = "addsvc"
78 )
79 recorder := zipkin.NewRecorder(collector, debug, hostPort, serviceName)
80 tracer, err = zipkin.NewTracer(recorder)
81 if err != nil {
82 logger.Log("err", err)
83 os.Exit(1)
84 }
85 } else if *lightstepToken != "" {
86 logger.Log("tracer", "LightStep") // probably don't want to print out the token :)
87 tracer = lightstep.NewTracer(lightstep.Options{
88 AccessToken: *lightstepToken,
89 })
90 defer lightstep.FlushLightStepTracer(tracer)
91 } else if *appdashAddr != "" {
92 logger.Log("tracer", "Appdash", "addr", *appdashAddr)
93 tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr))
94 } else {
95 logger.Log("tracer", "none")
96 tracer = stdopentracing.GlobalTracer() // no-op
97 }
98 }
99
100 // Create the (sparse) metrics we'll use in the service. They, too, are
101 // dependencies that we pass to components that use them.
102 var ints, chars metrics.Counter
103 {
104 // Business-level metrics.
105 ints = prometheus.NewCounterFrom(stdprometheus.CounterOpts{
106 Namespace: "example",
107 Subsystem: "addsvc",
108 Name: "integers_summed",
109 Help: "Total count of integers summed via the Sum method.",
110 }, []string{})
111 chars = prometheus.NewCounterFrom(stdprometheus.CounterOpts{
112 Namespace: "example",
113 Subsystem: "addsvc",
114 Name: "characters_concatenated",
115 Help: "Total count of characters concatenated via the Concat method.",
116 }, []string{})
117 }
118 var duration metrics.Histogram
119 {
120 // Endpoint-level metrics.
121 duration = prometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
122 Namespace: "example",
123 Subsystem: "addsvc",
124 Name: "request_duration_seconds",
125 Help: "Request duration in seconds.",
126 }, []string{"method", "success"})
127 }
128 http.DefaultServeMux.Handle("/metrics", promhttp.Handler())
129
130 // Build the layers of the service "onion" from the inside out. First, the
131 // business logic service; then, the set of endpoints that wrap the service;
132 // and finally, a series of concrete transport adapters. The adapters, like
133 // the HTTP handler or the gRPC server, are the bridge between Go kit and
134 // the interfaces that the transports expect. Note that we're not binding
135 // them to ports or anything yet; we'll do that next.
136 var (
137 service = addservice.New(logger, ints, chars)
138 endpoints = addendpoint.New(service, logger, duration, tracer)
139 httpHandler = addtransport.NewHTTPHandler(endpoints, tracer, logger)
140 grpcServer = addtransport.NewGRPCServer(endpoints, tracer, logger)
141 thriftServer = addtransport.NewThriftServer(endpoints)
142 )
143
144 // Now we're to the part of the func main where we want to start actually
145 // running things, like servers bound to listeners to receive connections.
146 //
147 // The method is the same for each component: add a new actor to the group
148 // struct, which is a combination of 2 anonymous functions: the first
149 // function actually runs the component, and the second function should
150 // interrupt the first function and cause it to return. It's in these
151 // functions that we actually bind the Go kit server/handler structs to the
152 // concrete transports and run them.
153 //
154 // Putting each component into its own block is mostly for aesthetics: it
155 // clearly demarcates the scope in which each listener/socket may be used.
156 var g group.Group
157 {
158 // The debug listener mounts the http.DefaultServeMux, and serves up
159 // stuff like the Prometheus metrics route, the Go debug and profiling
160 // routes, and so on.
161 debugListener, err := net.Listen("tcp", *debugAddr)
162 if err != nil {
163 logger.Log("transport", "debug/HTTP", "during", "Listen", "err", err)
164 os.Exit(1)
165 }
166 g.Add(func() error {
167 logger.Log("transport", "debug/HTTP", "addr", *debugAddr)
168 return http.Serve(debugListener, http.DefaultServeMux)
169 }, func(error) {
170 debugListener.Close()
171 })
172 }
173 {
174 // The HTTP listener mounts the Go kit HTTP handler we created.
175 httpListener, err := net.Listen("tcp", *httpAddr)
176 if err != nil {
177 logger.Log("transport", "HTTP", "during", "Listen", "err", err)
178 os.Exit(1)
179 }
180 g.Add(func() error {
181 logger.Log("transport", "HTTP", "addr", *httpAddr)
182 return http.Serve(httpListener, httpHandler)
183 }, func(error) {
184 httpListener.Close()
185 })
186 }
187 {
188 // The gRPC listener mounts the Go kit gRPC server we created.
189 grpcListener, err := net.Listen("tcp", *grpcAddr)
190 if err != nil {
191 logger.Log("transport", "gRPC", "during", "Listen", "err", err)
192 os.Exit(1)
193 }
194 g.Add(func() error {
195 logger.Log("transport", "gRPC", "addr", *grpcAddr)
196 baseServer := grpc.NewServer()
197 addpb.RegisterAddServer(baseServer, grpcServer)
198 return baseServer.Serve(grpcListener)
199 }, func(error) {
200 grpcListener.Close()
201 })
202 }
203 {
204 // The Thrift socket mounts the Go kit Thrift server we created earlier.
205 // There's a lot of boilerplate involved here, related to configuring
206 // the protocol and transport; blame Thrift.
207 thriftSocket, err := thrift.NewTServerSocket(*thriftAddr)
208 if err != nil {
209 logger.Log("transport", "Thrift", "during", "Listen", "err", err)
210 os.Exit(1)
211 }
212 g.Add(func() error {
213 logger.Log("transport", "Thrift", "addr", *thriftAddr)
214 var protocolFactory thrift.TProtocolFactory
215 switch *thriftProtocol {
216 case "binary":
217 protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
218 case "compact":
219 protocolFactory = thrift.NewTCompactProtocolFactory()
220 case "json":
221 protocolFactory = thrift.NewTJSONProtocolFactory()
222 case "simplejson":
223 protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
224 default:
225 return fmt.Errorf("invalid Thrift protocol %q", *thriftProtocol)
226 }
227 var transportFactory thrift.TTransportFactory
228 if *thriftBuffer > 0 {
229 transportFactory = thrift.NewTBufferedTransportFactory(*thriftBuffer)
230 } else {
231 transportFactory = thrift.NewTTransportFactory()
232 }
233 if *thriftFramed {
234 transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
235 }
236 return thrift.NewTSimpleServer4(
237 addthrift.NewAddServiceProcessor(thriftServer),
238 thriftSocket,
239 transportFactory,
240 protocolFactory,
241 ).Serve()
242 }, func(error) {
243 thriftSocket.Close()
244 })
245 }
246 {
247 // This function just sits and waits for ctrl-C.
248 cancelInterrupt := make(chan struct{})
249 g.Add(func() error {
250 c := make(chan os.Signal, 1)
251 signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
252 select {
253 case sig := <-c:
254 return fmt.Errorf("received signal %s", sig)
255 case <-cancelInterrupt:
256 return nil
257 }
258 }, func(error) {
259 close(cancelInterrupt)
260 })
261 }
262 logger.Log("exit", g.Run())
263 }
264
265 func usageFor(fs *flag.FlagSet, short string) func() {
266 return func() {
267 fmt.Fprintf(os.Stderr, "USAGE\n")
268 fmt.Fprintf(os.Stderr, " %s\n", short)
269 fmt.Fprintf(os.Stderr, "\n")
270 fmt.Fprintf(os.Stderr, "FLAGS\n")
271 w := tabwriter.NewWriter(os.Stderr, 0, 2, 2, ' ', 0)
272 fs.VisitAll(func(f *flag.Flag) {
273 fmt.Fprintf(w, "\t-%s %s\t%s\n", f.Name, f.DefValue, f.Usage)
274 })
275 w.Flush()
276 fmt.Fprintf(os.Stderr, "\n")
277 }
278 }
+0
-55
examples/addsvc/cmd/addsvc/pact_test.go less more
0 package main
1
2 import (
3 "fmt"
4 "net/http"
5 "os"
6 "strings"
7 "testing"
8
9 "github.com/pact-foundation/pact-go/dsl"
10 )
11
12 func TestPactStringsvcUppercase(t *testing.T) {
13 if os.Getenv("WRITE_PACTS") == "" {
14 t.Skip("skipping Pact contracts; set WRITE_PACTS environment variable to enable")
15 }
16
17 pact := dsl.Pact{
18 Port: 6666,
19 Consumer: "addsvc",
20 Provider: "stringsvc",
21 }
22 defer pact.Teardown()
23
24 pact.AddInteraction().
25 UponReceiving("stringsvc uppercase").
26 WithRequest(dsl.Request{
27 Headers: map[string]string{"Content-Type": "application/json; charset=utf-8"},
28 Method: "POST",
29 Path: "/uppercase",
30 Body: `{"s":"foo"}`,
31 }).
32 WillRespondWith(dsl.Response{
33 Status: 200,
34 Headers: map[string]string{"Content-Type": "application/json; charset=utf-8"},
35 Body: `{"v":"FOO"}`,
36 })
37
38 if err := pact.Verify(func() error {
39 u := fmt.Sprintf("http://localhost:%d/uppercase", pact.Server.Port)
40 req, err := http.NewRequest("POST", u, strings.NewReader(`{"s":"foo"}`))
41 if err != nil {
42 return err
43 }
44 req.Header.Set("Content-Type", "application/json; charset=utf-8")
45 if _, err = http.DefaultClient.Do(req); err != nil {
46 return err
47 }
48 return nil
49 }); err != nil {
50 t.Fatal(err)
51 }
52
53 pact.WritePact()
54 }
+0
-40
examples/addsvc/cmd/addsvc/wiring_test.go less more
0 package main
1
2 import (
3 "io/ioutil"
4 "net/http"
5 "net/http/httptest"
6 "strings"
7 "testing"
8
9 "github.com/opentracing/opentracing-go"
10
11 "github.com/go-kit/kit/log"
12 "github.com/go-kit/kit/metrics/discard"
13
14 "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint"
15 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
16 "github.com/go-kit/kit/examples/addsvc/pkg/addtransport"
17 )
18
19 func TestHTTP(t *testing.T) {
20 svc := addservice.New(log.NewNopLogger(), discard.NewCounter(), discard.NewCounter())
21 eps := addendpoint.New(svc, log.NewNopLogger(), discard.NewHistogram(), opentracing.GlobalTracer())
22 mux := addtransport.NewHTTPHandler(eps, opentracing.GlobalTracer(), log.NewNopLogger())
23 srv := httptest.NewServer(mux)
24 defer srv.Close()
25
26 for _, testcase := range []struct {
27 method, url, body, want string
28 }{
29 {"GET", srv.URL + "/concat", `{"a":"1","b":"2"}`, `{"v":"12"}`},
30 {"GET", srv.URL + "/sum", `{"a":1,"b":2}`, `{"v":3}`},
31 } {
32 req, _ := http.NewRequest(testcase.method, testcase.url, strings.NewReader(testcase.body))
33 resp, _ := http.DefaultClient.Do(req)
34 body, _ := ioutil.ReadAll(resp.Body)
35 if want, have := testcase.want, strings.TrimSpace(string(body)); want != have {
36 t.Errorf("%s %s %s: want %q, have %q", testcase.method, testcase.url, testcase.body, want, have)
37 }
38 }
39 }
+0
-270
examples/addsvc/pb/addsvc.pb.go less more
0 // Code generated by protoc-gen-go. DO NOT EDIT.
1 // source: addsvc.proto
2
3 /*
4 Package pb is a generated protocol buffer package.
5
6 It is generated from these files:
7 addsvc.proto
8
9 It has these top-level messages:
10 SumRequest
11 SumReply
12 ConcatRequest
13 ConcatReply
14 */
15 package pb
16
17 import proto "github.com/golang/protobuf/proto"
18 import fmt "fmt"
19 import math "math"
20
21 import (
22 context "golang.org/x/net/context"
23 grpc "google.golang.org/grpc"
24 )
25
26 // Reference imports to suppress errors if they are not otherwise used.
27 var _ = proto.Marshal
28 var _ = fmt.Errorf
29 var _ = math.Inf
30
31 // This is a compile-time assertion to ensure that this generated file
32 // is compatible with the proto package it is being compiled against.
33 // A compilation error at this line likely means your copy of the
34 // proto package needs to be updated.
35 const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
36
37 // The sum request contains two parameters.
38 type SumRequest struct {
39 A int64 `protobuf:"varint,1,opt,name=a" json:"a,omitempty"`
40 B int64 `protobuf:"varint,2,opt,name=b" json:"b,omitempty"`
41 }
42
43 func (m *SumRequest) Reset() { *m = SumRequest{} }
44 func (m *SumRequest) String() string { return proto.CompactTextString(m) }
45 func (*SumRequest) ProtoMessage() {}
46 func (*SumRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
47
48 func (m *SumRequest) GetA() int64 {
49 if m != nil {
50 return m.A
51 }
52 return 0
53 }
54
55 func (m *SumRequest) GetB() int64 {
56 if m != nil {
57 return m.B
58 }
59 return 0
60 }
61
62 // The sum response contains the result of the calculation.
63 type SumReply struct {
64 V int64 `protobuf:"varint,1,opt,name=v" json:"v,omitempty"`
65 Err string `protobuf:"bytes,2,opt,name=err" json:"err,omitempty"`
66 }
67
68 func (m *SumReply) Reset() { *m = SumReply{} }
69 func (m *SumReply) String() string { return proto.CompactTextString(m) }
70 func (*SumReply) ProtoMessage() {}
71 func (*SumReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
72
73 func (m *SumReply) GetV() int64 {
74 if m != nil {
75 return m.V
76 }
77 return 0
78 }
79
80 func (m *SumReply) GetErr() string {
81 if m != nil {
82 return m.Err
83 }
84 return ""
85 }
86
87 // The Concat request contains two parameters.
88 type ConcatRequest struct {
89 A string `protobuf:"bytes,1,opt,name=a" json:"a,omitempty"`
90 B string `protobuf:"bytes,2,opt,name=b" json:"b,omitempty"`
91 }
92
93 func (m *ConcatRequest) Reset() { *m = ConcatRequest{} }
94 func (m *ConcatRequest) String() string { return proto.CompactTextString(m) }
95 func (*ConcatRequest) ProtoMessage() {}
96 func (*ConcatRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
97
98 func (m *ConcatRequest) GetA() string {
99 if m != nil {
100 return m.A
101 }
102 return ""
103 }
104
105 func (m *ConcatRequest) GetB() string {
106 if m != nil {
107 return m.B
108 }
109 return ""
110 }
111
112 // The Concat response contains the result of the concatenation.
113 type ConcatReply struct {
114 V string `protobuf:"bytes,1,opt,name=v" json:"v,omitempty"`
115 Err string `protobuf:"bytes,2,opt,name=err" json:"err,omitempty"`
116 }
117
118 func (m *ConcatReply) Reset() { *m = ConcatReply{} }
119 func (m *ConcatReply) String() string { return proto.CompactTextString(m) }
120 func (*ConcatReply) ProtoMessage() {}
121 func (*ConcatReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
122
123 func (m *ConcatReply) GetV() string {
124 if m != nil {
125 return m.V
126 }
127 return ""
128 }
129
130 func (m *ConcatReply) GetErr() string {
131 if m != nil {
132 return m.Err
133 }
134 return ""
135 }
136
137 func init() {
138 proto.RegisterType((*SumRequest)(nil), "pb.SumRequest")
139 proto.RegisterType((*SumReply)(nil), "pb.SumReply")
140 proto.RegisterType((*ConcatRequest)(nil), "pb.ConcatRequest")
141 proto.RegisterType((*ConcatReply)(nil), "pb.ConcatReply")
142 }
143
144 // Reference imports to suppress errors if they are not otherwise used.
145 var _ context.Context
146 var _ grpc.ClientConn
147
148 // This is a compile-time assertion to ensure that this generated file
149 // is compatible with the grpc package it is being compiled against.
150 const _ = grpc.SupportPackageIsVersion4
151
152 // Client API for Add service
153
154 type AddClient interface {
155 // Sums two integers.
156 Sum(ctx context.Context, in *SumRequest, opts ...grpc.CallOption) (*SumReply, error)
157 // Concatenates two strings
158 Concat(ctx context.Context, in *ConcatRequest, opts ...grpc.CallOption) (*ConcatReply, error)
159 }
160
161 type addClient struct {
162 cc *grpc.ClientConn
163 }
164
165 func NewAddClient(cc *grpc.ClientConn) AddClient {
166 return &addClient{cc}
167 }
168
169 func (c *addClient) Sum(ctx context.Context, in *SumRequest, opts ...grpc.CallOption) (*SumReply, error) {
170 out := new(SumReply)
171 err := grpc.Invoke(ctx, "/pb.Add/Sum", in, out, c.cc, opts...)
172 if err != nil {
173 return nil, err
174 }
175 return out, nil
176 }
177
178 func (c *addClient) Concat(ctx context.Context, in *ConcatRequest, opts ...grpc.CallOption) (*ConcatReply, error) {
179 out := new(ConcatReply)
180 err := grpc.Invoke(ctx, "/pb.Add/Concat", in, out, c.cc, opts...)
181 if err != nil {
182 return nil, err
183 }
184 return out, nil
185 }
186
187 // Server API for Add service
188
189 type AddServer interface {
190 // Sums two integers.
191 Sum(context.Context, *SumRequest) (*SumReply, error)
192 // Concatenates two strings
193 Concat(context.Context, *ConcatRequest) (*ConcatReply, error)
194 }
195
196 func RegisterAddServer(s *grpc.Server, srv AddServer) {
197 s.RegisterService(&_Add_serviceDesc, srv)
198 }
199
200 func _Add_Sum_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
201 in := new(SumRequest)
202 if err := dec(in); err != nil {
203 return nil, err
204 }
205 if interceptor == nil {
206 return srv.(AddServer).Sum(ctx, in)
207 }
208 info := &grpc.UnaryServerInfo{
209 Server: srv,
210 FullMethod: "/pb.Add/Sum",
211 }
212 handler := func(ctx context.Context, req interface{}) (interface{}, error) {
213 return srv.(AddServer).Sum(ctx, req.(*SumRequest))
214 }
215 return interceptor(ctx, in, info, handler)
216 }
217
218 func _Add_Concat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
219 in := new(ConcatRequest)
220 if err := dec(in); err != nil {
221 return nil, err
222 }
223 if interceptor == nil {
224 return srv.(AddServer).Concat(ctx, in)
225 }
226 info := &grpc.UnaryServerInfo{
227 Server: srv,
228 FullMethod: "/pb.Add/Concat",
229 }
230 handler := func(ctx context.Context, req interface{}) (interface{}, error) {
231 return srv.(AddServer).Concat(ctx, req.(*ConcatRequest))
232 }
233 return interceptor(ctx, in, info, handler)
234 }
235
236 var _Add_serviceDesc = grpc.ServiceDesc{
237 ServiceName: "pb.Add",
238 HandlerType: (*AddServer)(nil),
239 Methods: []grpc.MethodDesc{
240 {
241 MethodName: "Sum",
242 Handler: _Add_Sum_Handler,
243 },
244 {
245 MethodName: "Concat",
246 Handler: _Add_Concat_Handler,
247 },
248 },
249 Streams: []grpc.StreamDesc{},
250 Metadata: "addsvc.proto",
251 }
252
253 func init() { proto.RegisterFile("addsvc.proto", fileDescriptor0) }
254
255 var fileDescriptor0 = []byte{
256 // 189 bytes of a gzipped FileDescriptorProto
257 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x4c, 0x49, 0x29,
258 0x2e, 0x4b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x48, 0x52, 0xd2, 0xe0, 0xe2,
259 0x0a, 0x2e, 0xcd, 0x0d, 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0xe2, 0xe1, 0x62, 0x4c, 0x94,
260 0x60, 0x54, 0x60, 0xd4, 0x60, 0x0e, 0x62, 0x4c, 0x04, 0xf1, 0x92, 0x24, 0x98, 0x20, 0xbc, 0x24,
261 0x25, 0x2d, 0x2e, 0x0e, 0xb0, 0xca, 0x82, 0x9c, 0x4a, 0x90, 0x4c, 0x19, 0x4c, 0x5d, 0x99, 0x90,
262 0x00, 0x17, 0x73, 0x6a, 0x51, 0x11, 0x58, 0x25, 0x67, 0x10, 0x88, 0xa9, 0xa4, 0xcd, 0xc5, 0xeb,
263 0x9c, 0x9f, 0x97, 0x9c, 0x58, 0x82, 0x61, 0x30, 0x27, 0x8a, 0xc1, 0x9c, 0x20, 0x83, 0x75, 0xb9,
264 0xb8, 0x61, 0x8a, 0x51, 0xcc, 0xe6, 0xc4, 0x6a, 0xb6, 0x51, 0x0c, 0x17, 0xb3, 0x63, 0x4a, 0x8a,
265 0x90, 0x2a, 0x17, 0x73, 0x70, 0x69, 0xae, 0x10, 0x9f, 0x5e, 0x41, 0x92, 0x1e, 0xc2, 0x07, 0x52,
266 0x3c, 0x70, 0x7e, 0x41, 0x4e, 0xa5, 0x12, 0x83, 0x90, 0x1e, 0x17, 0x1b, 0xc4, 0x70, 0x21, 0x41,
267 0x90, 0x0c, 0x8a, 0xab, 0xa4, 0xf8, 0x91, 0x85, 0xc0, 0xea, 0x93, 0xd8, 0xc0, 0x41, 0x63, 0x0c,
268 0x08, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x37, 0x81, 0x99, 0x2a, 0x01, 0x00, 0x00,
269 }
+0
-36
examples/addsvc/pb/addsvc.proto less more
0 syntax = "proto3";
1
2 package pb;
3
4 // The Add service definition.
5 service Add {
6 // Sums two integers.
7 rpc Sum (SumRequest) returns (SumReply) {}
8
9 // Concatenates two strings
10 rpc Concat (ConcatRequest) returns (ConcatReply) {}
11 }
12
13 // The sum request contains two parameters.
14 message SumRequest {
15 int64 a = 1;
16 int64 b = 2;
17 }
18
19 // The sum response contains the result of the calculation.
20 message SumReply {
21 int64 v = 1;
22 string err = 2;
23 }
24
25 // The Concat request contains two parameters.
26 message ConcatRequest {
27 string a = 1;
28 string b = 2;
29 }
30
31 // The Concat response contains the result of the concatenation.
32 message ConcatReply {
33 string v = 1;
34 string err = 2;
35 }
+0
-14
examples/addsvc/pb/compile.sh less more
0 #!/usr/bin/env sh
1
2 # Install proto3 from source
3 # brew install autoconf automake libtool
4 # git clone https://github.com/google/protobuf
5 # ./autogen.sh ; ./configure ; make ; make install
6 #
7 # Update protoc Go bindings via
8 # go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
9 #
10 # See also
11 # https://github.com/grpc/grpc-go/tree/master/examples
12
13 protoc addsvc.proto --go_out=plugins=grpc:.
+0
-43
examples/addsvc/pkg/addendpoint/middleware.go less more
0 package addendpoint
1
2 import (
3 "context"
4 "fmt"
5 "time"
6
7 "github.com/go-kit/kit/endpoint"
8 "github.com/go-kit/kit/log"
9 "github.com/go-kit/kit/metrics"
10 )
11
12 // InstrumentingMiddleware returns an endpoint middleware that records
13 // the duration of each invocation to the passed histogram. The middleware adds
14 // a single field: "success", which is "true" if no error is returned, and
15 // "false" otherwise.
16 func InstrumentingMiddleware(duration metrics.Histogram) endpoint.Middleware {
17 return func(next endpoint.Endpoint) endpoint.Endpoint {
18 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
19
20 defer func(begin time.Time) {
21 duration.With("success", fmt.Sprint(err == nil)).Observe(time.Since(begin).Seconds())
22 }(time.Now())
23 return next(ctx, request)
24
25 }
26 }
27 }
28
29 // LoggingMiddleware returns an endpoint middleware that logs the
30 // duration of each invocation, and the resulting error, if any.
31 func LoggingMiddleware(logger log.Logger) endpoint.Middleware {
32 return func(next endpoint.Endpoint) endpoint.Endpoint {
33 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
34
35 defer func(begin time.Time) {
36 logger.Log("transport_error", err, "took", time.Since(begin))
37 }(time.Now())
38 return next(ctx, request)
39
40 }
41 }
42 }
+0
-128
examples/addsvc/pkg/addendpoint/set.go less more
0 package addendpoint
1
2 import (
3 "context"
4
5 rl "github.com/juju/ratelimit"
6 stdopentracing "github.com/opentracing/opentracing-go"
7 "github.com/sony/gobreaker"
8
9 "github.com/go-kit/kit/circuitbreaker"
10 "github.com/go-kit/kit/endpoint"
11 "github.com/go-kit/kit/log"
12 "github.com/go-kit/kit/metrics"
13 "github.com/go-kit/kit/ratelimit"
14 "github.com/go-kit/kit/tracing/opentracing"
15
16 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
17 )
18
19 // Set collects all of the endpoints that compose an add service. It's meant to
20 // be used as a helper struct, to collect all of the endpoints into a single
21 // parameter.
22 type Set struct {
23 SumEndpoint endpoint.Endpoint
24 ConcatEndpoint endpoint.Endpoint
25 }
26
27 // New returns a Set that wraps the provided server, and wires in all of the
28 // expected endpoint middlewares via the various parameters.
29 func New(svc addservice.Service, logger log.Logger, duration metrics.Histogram, trace stdopentracing.Tracer) Set {
30 var sumEndpoint endpoint.Endpoint
31 {
32 sumEndpoint = MakeSumEndpoint(svc)
33 sumEndpoint = ratelimit.NewTokenBucketLimiter(rl.NewBucketWithRate(1, 1))(sumEndpoint)
34 sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{}))(sumEndpoint)
35 sumEndpoint = opentracing.TraceServer(trace, "Sum")(sumEndpoint)
36 sumEndpoint = LoggingMiddleware(log.With(logger, "method", "Sum"))(sumEndpoint)
37 sumEndpoint = InstrumentingMiddleware(duration.With("method", "Sum"))(sumEndpoint)
38 }
39 var concatEndpoint endpoint.Endpoint
40 {
41 concatEndpoint = MakeConcatEndpoint(svc)
42 concatEndpoint = ratelimit.NewTokenBucketLimiter(rl.NewBucketWithRate(100, 100))(concatEndpoint)
43 concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{}))(concatEndpoint)
44 concatEndpoint = opentracing.TraceServer(trace, "Concat")(concatEndpoint)
45 concatEndpoint = LoggingMiddleware(log.With(logger, "method", "Concat"))(concatEndpoint)
46 concatEndpoint = InstrumentingMiddleware(duration.With("method", "Concat"))(concatEndpoint)
47 }
48 return Set{
49 SumEndpoint: sumEndpoint,
50 ConcatEndpoint: concatEndpoint,
51 }
52 }
53
54 // Sum implements the service interface, so Set may be used as a service.
55 // This is primarily useful in the context of a client library.
56 func (s Set) Sum(ctx context.Context, a, b int) (int, error) {
57 resp, err := s.SumEndpoint(ctx, SumRequest{A: a, B: b})
58 if err != nil {
59 return 0, err
60 }
61 response := resp.(SumResponse)
62 return response.V, response.Err
63 }
64
65 // Concat implements the service interface, so Set may be used as a
66 // service. This is primarily useful in the context of a client library.
67 func (s Set) Concat(ctx context.Context, a, b string) (string, error) {
68 resp, err := s.ConcatEndpoint(ctx, ConcatRequest{A: a, B: b})
69 if err != nil {
70 return "", err
71 }
72 response := resp.(ConcatResponse)
73 return response.V, response.Err
74 }
75
76 // MakeSumEndpoint constructs a Sum endpoint wrapping the service.
77 func MakeSumEndpoint(s addservice.Service) endpoint.Endpoint {
78 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
79 req := request.(SumRequest)
80 v, err := s.Sum(ctx, req.A, req.B)
81 return SumResponse{V: v, Err: err}, nil
82 }
83 }
84
85 // MakeConcatEndpoint constructs a Concat endpoint wrapping the service.
86 func MakeConcatEndpoint(s addservice.Service) endpoint.Endpoint {
87 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
88 req := request.(ConcatRequest)
89 v, err := s.Concat(ctx, req.A, req.B)
90 return ConcatResponse{V: v, Err: err}, nil
91 }
92 }
93
94 // Failer is an interface that should be implemented by response types.
95 // Response encoders can check if responses are Failer, and if so if they've
96 // failed, and if so encode them using a separate write path based on the error.
97 type Failer interface {
98 Failed() error
99 }
100
101 // SumRequest collects the request parameters for the Sum method.
102 type SumRequest struct {
103 A, B int
104 }
105
106 // SumResponse collects the response values for the Sum method.
107 type SumResponse struct {
108 V int `json:"v"`
109 Err error `json:"-"` // should be intercepted by Failed/errorEncoder
110 }
111
112 // Failed implements Failer.
113 func (r SumResponse) Failed() error { return r.Err }
114
115 // ConcatRequest collects the request parameters for the Concat method.
116 type ConcatRequest struct {
117 A, B string
118 }
119
120 // ConcatResponse collects the response values for the Concat method.
121 type ConcatResponse struct {
122 V string `json:"v"`
123 Err error `json:"-"`
124 }
125
126 // Failed implements Failer.
127 func (r ConcatResponse) Failed() error { return r.Err }
+0
-69
examples/addsvc/pkg/addservice/middleware.go less more
0 package addservice
1
2 import (
3 "context"
4
5 "github.com/go-kit/kit/log"
6 "github.com/go-kit/kit/metrics"
7 )
8
9 // Middleware describes a service (as opposed to endpoint) middleware.
10 type Middleware func(Service) Service
11
12 // LoggingMiddleware takes a logger as a dependency
13 // and returns a ServiceMiddleware.
14 func LoggingMiddleware(logger log.Logger) Middleware {
15 return func(next Service) Service {
16 return loggingMiddleware{logger, next}
17 }
18 }
19
20 type loggingMiddleware struct {
21 logger log.Logger
22 next Service
23 }
24
25 func (mw loggingMiddleware) Sum(ctx context.Context, a, b int) (v int, err error) {
26 defer func() {
27 mw.logger.Log("method", "Sum", "a", a, "b", b, "v", v, "err", err)
28 }()
29 return mw.next.Sum(ctx, a, b)
30 }
31
32 func (mw loggingMiddleware) Concat(ctx context.Context, a, b string) (v string, err error) {
33 defer func() {
34 mw.logger.Log("method", "Concat", "a", a, "b", b, "v", v, "err", err)
35 }()
36 return mw.next.Concat(ctx, a, b)
37 }
38
39 // InstrumentingMiddleware returns a service middleware that instruments
40 // the number of integers summed and characters concatenated over the lifetime of
41 // the service.
42 func InstrumentingMiddleware(ints, chars metrics.Counter) Middleware {
43 return func(next Service) Service {
44 return instrumentingMiddleware{
45 ints: ints,
46 chars: chars,
47 next: next,
48 }
49 }
50 }
51
52 type instrumentingMiddleware struct {
53 ints metrics.Counter
54 chars metrics.Counter
55 next Service
56 }
57
58 func (mw instrumentingMiddleware) Sum(ctx context.Context, a, b int) (int, error) {
59 v, err := mw.next.Sum(ctx, a, b)
60 mw.ints.Add(float64(v))
61 return v, err
62 }
63
64 func (mw instrumentingMiddleware) Concat(ctx context.Context, a, b string) (string, error) {
65 v, err := mw.next.Concat(ctx, a, b)
66 mw.chars.Add(float64(len(v)))
67 return v, err
68 }
+0
-71
examples/addsvc/pkg/addservice/service.go less more
0 package addservice
1
2 import (
3 "context"
4 "errors"
5
6 "github.com/go-kit/kit/log"
7 "github.com/go-kit/kit/metrics"
8 )
9
10 // Service describes a service that adds things together.
11 type Service interface {
12 Sum(ctx context.Context, a, b int) (int, error)
13 Concat(ctx context.Context, a, b string) (string, error)
14 }
15
16 // New returns a basic Service with all of the expected middlewares wired in.
17 func New(logger log.Logger, ints, chars metrics.Counter) Service {
18 var svc Service
19 {
20 svc = NewBasicService()
21 svc = LoggingMiddleware(logger)(svc)
22 svc = InstrumentingMiddleware(ints, chars)(svc)
23 }
24 return svc
25 }
26
27 var (
28 // ErrTwoZeroes is an arbitrary business rule for the Add method.
29 ErrTwoZeroes = errors.New("can't sum two zeroes")
30
31 // ErrIntOverflow protects the Add method. We've decided that this error
32 // indicates a misbehaving service and should count against e.g. circuit
33 // breakers. So, we return it directly in endpoints, to illustrate the
34 // difference. In a real service, this probably wouldn't be the case.
35 ErrIntOverflow = errors.New("integer overflow")
36
37 // ErrMaxSizeExceeded protects the Concat method.
38 ErrMaxSizeExceeded = errors.New("result exceeds maximum size")
39 )
40
41 // NewBasicService returns a naïve, stateless implementation of Service.
42 func NewBasicService() Service {
43 return basicService{}
44 }
45
46 type basicService struct{}
47
48 const (
49 intMax = 1<<31 - 1
50 intMin = -(intMax + 1)
51 maxLen = 10
52 )
53
54 func (s basicService) Sum(_ context.Context, a, b int) (int, error) {
55 if a == 0 && b == 0 {
56 return 0, ErrTwoZeroes
57 }
58 if (b > 0 && a > (intMax-b)) || (b < 0 && a < (intMin-b)) {
59 return 0, ErrIntOverflow
60 }
61 return a + b, nil
62 }
63
64 // Concat implements Service.
65 func (s basicService) Concat(_ context.Context, a, b string) (string, error) {
66 if len(a)+len(b) > maxLen {
67 return "", ErrMaxSizeExceeded
68 }
69 return a + b, nil
70 }
+0
-210
examples/addsvc/pkg/addtransport/grpc.go less more
0 package addtransport
1
2 import (
3 "context"
4 "errors"
5 "time"
6
7 "google.golang.org/grpc"
8
9 jujuratelimit "github.com/juju/ratelimit"
10 stdopentracing "github.com/opentracing/opentracing-go"
11 "github.com/sony/gobreaker"
12 oldcontext "golang.org/x/net/context"
13
14 "github.com/go-kit/kit/circuitbreaker"
15 "github.com/go-kit/kit/endpoint"
16 "github.com/go-kit/kit/log"
17 "github.com/go-kit/kit/ratelimit"
18 "github.com/go-kit/kit/tracing/opentracing"
19 grpctransport "github.com/go-kit/kit/transport/grpc"
20
21 "github.com/go-kit/kit/examples/addsvc/pb"
22 "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint"
23 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
24 )
25
26 type grpcServer struct {
27 sum grpctransport.Handler
28 concat grpctransport.Handler
29 }
30
31 // NewGRPCServer makes a set of endpoints available as a gRPC AddServer.
32 func NewGRPCServer(endpoints addendpoint.Set, tracer stdopentracing.Tracer, logger log.Logger) pb.AddServer {
33 options := []grpctransport.ServerOption{
34 grpctransport.ServerErrorLogger(logger),
35 }
36 return &grpcServer{
37 sum: grpctransport.NewServer(
38 endpoints.SumEndpoint,
39 decodeGRPCSumRequest,
40 encodeGRPCSumResponse,
41 append(options, grpctransport.ServerBefore(opentracing.GRPCToContext(tracer, "Sum", logger)))...,
42 ),
43 concat: grpctransport.NewServer(
44 endpoints.ConcatEndpoint,
45 decodeGRPCConcatRequest,
46 encodeGRPCConcatResponse,
47 append(options, grpctransport.ServerBefore(opentracing.GRPCToContext(tracer, "Concat", logger)))...,
48 ),
49 }
50 }
51
52 func (s *grpcServer) Sum(ctx oldcontext.Context, req *pb.SumRequest) (*pb.SumReply, error) {
53 _, rep, err := s.sum.ServeGRPC(ctx, req)
54 if err != nil {
55 return nil, err
56 }
57 return rep.(*pb.SumReply), nil
58 }
59
60 func (s *grpcServer) Concat(ctx oldcontext.Context, req *pb.ConcatRequest) (*pb.ConcatReply, error) {
61 _, rep, err := s.concat.ServeGRPC(ctx, req)
62 if err != nil {
63 return nil, err
64 }
65 return rep.(*pb.ConcatReply), nil
66 }
67
68 // NewGRPCClient returns an AddService backed by a gRPC server at the other end
69 // of the conn. The caller is responsible for constructing the conn, and
70 // eventually closing the underlying transport. We bake-in certain middlewares,
71 // implementing the client library pattern.
72 func NewGRPCClient(conn *grpc.ClientConn, tracer stdopentracing.Tracer, logger log.Logger) addservice.Service {
73 // We construct a single ratelimiter middleware, to limit the total outgoing
74 // QPS from this client to all methods on the remote instance. We also
75 // construct per-endpoint circuitbreaker middlewares to demonstrate how
76 // that's done, although they could easily be combined into a single breaker
77 // for the entire remote instance, too.
78 limiter := ratelimit.NewTokenBucketLimiter(jujuratelimit.NewBucketWithRate(100, 100))
79
80 // Each individual endpoint is an http/transport.Client (which implements
81 // endpoint.Endpoint) that gets wrapped with various middlewares. If you
82 // made your own client library, you'd do this work there, so your server
83 // could rely on a consistent set of client behavior.
84 var sumEndpoint endpoint.Endpoint
85 {
86 sumEndpoint = grpctransport.NewClient(
87 conn,
88 "pb.Add",
89 "Sum",
90 encodeGRPCSumRequest,
91 decodeGRPCSumResponse,
92 pb.SumReply{},
93 grpctransport.ClientBefore(opentracing.ContextToGRPC(tracer, logger)),
94 ).Endpoint()
95 sumEndpoint = opentracing.TraceClient(tracer, "Sum")(sumEndpoint)
96 sumEndpoint = limiter(sumEndpoint)
97 sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{
98 Name: "Sum",
99 Timeout: 30 * time.Second,
100 }))(sumEndpoint)
101 }
102
103 // The Concat endpoint is the same thing, with slightly different
104 // middlewares to demonstrate how to specialize per-endpoint.
105 var concatEndpoint endpoint.Endpoint
106 {
107 concatEndpoint = grpctransport.NewClient(
108 conn,
109 "pb.Add",
110 "Concat",
111 encodeGRPCConcatRequest,
112 decodeGRPCConcatResponse,
113 pb.ConcatReply{},
114 grpctransport.ClientBefore(opentracing.ContextToGRPC(tracer, logger)),
115 ).Endpoint()
116 concatEndpoint = opentracing.TraceClient(tracer, "Concat")(concatEndpoint)
117 concatEndpoint = limiter(concatEndpoint)
118 concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{
119 Name: "Concat",
120 Timeout: 10 * time.Second,
121 }))(concatEndpoint)
122 }
123
124 // Returning the endpoint.Set as a service.Service relies on the
125 // endpoint.Set implementing the Service methods. That's just a simple bit
126 // of glue code.
127 return addendpoint.Set{
128 SumEndpoint: sumEndpoint,
129 ConcatEndpoint: concatEndpoint,
130 }
131 }
132
133 // decodeGRPCSumRequest is a transport/grpc.DecodeRequestFunc that converts a
134 // gRPC sum request to a user-domain sum request. Primarily useful in a server.
135 func decodeGRPCSumRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
136 req := grpcReq.(*pb.SumRequest)
137 return addendpoint.SumRequest{A: int(req.A), B: int(req.B)}, nil
138 }
139
140 // decodeGRPCConcatRequest is a transport/grpc.DecodeRequestFunc that converts a
141 // gRPC concat request to a user-domain concat request. Primarily useful in a
142 // server.
143 func decodeGRPCConcatRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
144 req := grpcReq.(*pb.ConcatRequest)
145 return addendpoint.ConcatRequest{A: req.A, B: req.B}, nil
146 }
147
148 // decodeGRPCSumResponse is a transport/grpc.DecodeResponseFunc that converts a
149 // gRPC sum reply to a user-domain sum response. Primarily useful in a client.
150 func decodeGRPCSumResponse(_ context.Context, grpcReply interface{}) (interface{}, error) {
151 reply := grpcReply.(*pb.SumReply)
152 return addendpoint.SumResponse{V: int(reply.V), Err: str2err(reply.Err)}, nil
153 }
154
155 // decodeGRPCConcatResponse is a transport/grpc.DecodeResponseFunc that converts
156 // a gRPC concat reply to a user-domain concat response. Primarily useful in a
157 // client.
158 func decodeGRPCConcatResponse(_ context.Context, grpcReply interface{}) (interface{}, error) {
159 reply := grpcReply.(*pb.ConcatReply)
160 return addendpoint.ConcatResponse{V: reply.V, Err: str2err(reply.Err)}, nil
161 }
162
163 // encodeGRPCSumResponse is a transport/grpc.EncodeResponseFunc that converts a
164 // user-domain sum response to a gRPC sum reply. Primarily useful in a server.
165 func encodeGRPCSumResponse(_ context.Context, response interface{}) (interface{}, error) {
166 resp := response.(addendpoint.SumResponse)
167 return &pb.SumReply{V: int64(resp.V), Err: err2str(resp.Err)}, nil
168 }
169
170 // encodeGRPCConcatResponse is a transport/grpc.EncodeResponseFunc that converts
171 // a user-domain concat response to a gRPC concat reply. Primarily useful in a
172 // server.
173 func encodeGRPCConcatResponse(_ context.Context, response interface{}) (interface{}, error) {
174 resp := response.(addendpoint.ConcatResponse)
175 return &pb.ConcatReply{V: resp.V, Err: err2str(resp.Err)}, nil
176 }
177
178 // encodeGRPCSumRequest is a transport/grpc.EncodeRequestFunc that converts a
179 // user-domain sum request to a gRPC sum request. Primarily useful in a client.
180 func encodeGRPCSumRequest(_ context.Context, request interface{}) (interface{}, error) {
181 req := request.(addendpoint.SumRequest)
182 return &pb.SumRequest{A: int64(req.A), B: int64(req.B)}, nil
183 }
184
185 // encodeGRPCConcatRequest is a transport/grpc.EncodeRequestFunc that converts a
186 // user-domain concat request to a gRPC concat request. Primarily useful in a
187 // client.
188 func encodeGRPCConcatRequest(_ context.Context, request interface{}) (interface{}, error) {
189 req := request.(addendpoint.ConcatRequest)
190 return &pb.ConcatRequest{A: req.A, B: req.B}, nil
191 }
192
193 // These annoying helper functions are required to translate Go error types to
194 // and from strings, which is the type we use in our IDLs to represent errors.
195 // There is special casing to treat empty strings as nil errors.
196
197 func str2err(s string) error {
198 if s == "" {
199 return nil
200 }
201 return errors.New(s)
202 }
203
204 func err2str(err error) string {
205 if err == nil {
206 return ""
207 }
208 return err.Error()
209 }
+0
-219
examples/addsvc/pkg/addtransport/http.go less more
0 package addtransport
1
2 import (
3 "bytes"
4 "context"
5 "encoding/json"
6 "errors"
7 "io/ioutil"
8 "net/http"
9 "net/url"
10 "strings"
11 "time"
12
13 jujuratelimit "github.com/juju/ratelimit"
14 stdopentracing "github.com/opentracing/opentracing-go"
15 "github.com/sony/gobreaker"
16
17 "github.com/go-kit/kit/circuitbreaker"
18 "github.com/go-kit/kit/endpoint"
19 "github.com/go-kit/kit/log"
20 "github.com/go-kit/kit/ratelimit"
21 "github.com/go-kit/kit/tracing/opentracing"
22 httptransport "github.com/go-kit/kit/transport/http"
23
24 "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint"
25 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
26 )
27
28 // NewHTTPHandler returns an HTTP handler that makes a set of endpoints
29 // available on predefined paths.
30 func NewHTTPHandler(endpoints addendpoint.Set, tracer stdopentracing.Tracer, logger log.Logger) http.Handler {
31 options := []httptransport.ServerOption{
32 httptransport.ServerErrorEncoder(errorEncoder),
33 httptransport.ServerErrorLogger(logger),
34 }
35 m := http.NewServeMux()
36 m.Handle("/sum", httptransport.NewServer(
37 endpoints.SumEndpoint,
38 decodeHTTPSumRequest,
39 encodeHTTPGenericResponse,
40 append(options, httptransport.ServerBefore(opentracing.HTTPToContext(tracer, "Sum", logger)))...,
41 ))
42 m.Handle("/concat", httptransport.NewServer(
43 endpoints.ConcatEndpoint,
44 decodeHTTPConcatRequest,
45 encodeHTTPGenericResponse,
46 append(options, httptransport.ServerBefore(opentracing.HTTPToContext(tracer, "Concat", logger)))...,
47 ))
48 return m
49 }
50
51 // NewHTTPClient returns an AddService backed by an HTTP server living at the
52 // remote instance. We expect instance to come from a service discovery system,
53 // so likely of the form "host:port". We bake-in certain middlewares,
54 // implementing the client library pattern.
55 func NewHTTPClient(instance string, tracer stdopentracing.Tracer, logger log.Logger) (addservice.Service, error) {
56 // Quickly sanitize the instance string.
57 if !strings.HasPrefix(instance, "http") {
58 instance = "http://" + instance
59 }
60 u, err := url.Parse(instance)
61 if err != nil {
62 return nil, err
63 }
64
65 // We construct a single ratelimiter middleware, to limit the total outgoing
66 // QPS from this client to all methods on the remote instance. We also
67 // construct per-endpoint circuitbreaker middlewares to demonstrate how
68 // that's done, although they could easily be combined into a single breaker
69 // for the entire remote instance, too.
70 limiter := ratelimit.NewTokenBucketLimiter(jujuratelimit.NewBucketWithRate(100, 100))
71
72 // Each individual endpoint is an http/transport.Client (which implements
73 // endpoint.Endpoint) that gets wrapped with various middlewares. If you
74 // made your own client library, you'd do this work there, so your server
75 // could rely on a consistent set of client behavior.
76 var sumEndpoint endpoint.Endpoint
77 {
78 sumEndpoint = httptransport.NewClient(
79 "POST",
80 copyURL(u, "/sum"),
81 encodeHTTPGenericRequest,
82 decodeHTTPSumResponse,
83 httptransport.ClientBefore(opentracing.ContextToHTTP(tracer, logger)),
84 ).Endpoint()
85 sumEndpoint = opentracing.TraceClient(tracer, "Sum")(sumEndpoint)
86 sumEndpoint = limiter(sumEndpoint)
87 sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{
88 Name: "Sum",
89 Timeout: 30 * time.Second,
90 }))(sumEndpoint)
91 }
92
93 // The Concat endpoint is the same thing, with slightly different
94 // middlewares to demonstrate how to specialize per-endpoint.
95 var concatEndpoint endpoint.Endpoint
96 {
97 concatEndpoint = httptransport.NewClient(
98 "POST",
99 copyURL(u, "/concat"),
100 encodeHTTPGenericRequest,
101 decodeHTTPConcatResponse,
102 httptransport.ClientBefore(opentracing.ContextToHTTP(tracer, logger)),
103 ).Endpoint()
104 concatEndpoint = opentracing.TraceClient(tracer, "Concat")(concatEndpoint)
105 concatEndpoint = limiter(concatEndpoint)
106 concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{
107 Name: "Concat",
108 Timeout: 10 * time.Second,
109 }))(concatEndpoint)
110 }
111
112 // Returning the endpoint.Set as a service.Service relies on the
113 // endpoint.Set implementing the Service methods. That's just a simple bit
114 // of glue code.
115 return addendpoint.Set{
116 SumEndpoint: sumEndpoint,
117 ConcatEndpoint: concatEndpoint,
118 }, nil
119 }
120
121 func copyURL(base *url.URL, path string) *url.URL {
122 next := *base
123 next.Path = path
124 return &next
125 }
126
127 func errorEncoder(_ context.Context, err error, w http.ResponseWriter) {
128 w.WriteHeader(err2code(err))
129 json.NewEncoder(w).Encode(errorWrapper{Error: err.Error()})
130 }
131
132 func err2code(err error) int {
133 switch err {
134 case addservice.ErrTwoZeroes, addservice.ErrMaxSizeExceeded, addservice.ErrIntOverflow:
135 return http.StatusBadRequest
136 }
137 return http.StatusInternalServerError
138 }
139
140 func errorDecoder(r *http.Response) error {
141 var w errorWrapper
142 if err := json.NewDecoder(r.Body).Decode(&w); err != nil {
143 return err
144 }
145 return errors.New(w.Error)
146 }
147
148 type errorWrapper struct {
149 Error string `json:"error"`
150 }
151
152 // decodeHTTPSumRequest is a transport/http.DecodeRequestFunc that decodes a
153 // JSON-encoded sum request from the HTTP request body. Primarily useful in a
154 // server.
155 func decodeHTTPSumRequest(_ context.Context, r *http.Request) (interface{}, error) {
156 var req addendpoint.SumRequest
157 err := json.NewDecoder(r.Body).Decode(&req)
158 return req, err
159 }
160
161 // decodeHTTPConcatRequest is a transport/http.DecodeRequestFunc that decodes a
162 // JSON-encoded concat request from the HTTP request body. Primarily useful in a
163 // server.
164 func decodeHTTPConcatRequest(_ context.Context, r *http.Request) (interface{}, error) {
165 var req addendpoint.ConcatRequest
166 err := json.NewDecoder(r.Body).Decode(&req)
167 return req, err
168 }
169
170 // decodeHTTPSumResponse is a transport/http.DecodeResponseFunc that decodes a
171 // JSON-encoded sum response from the HTTP response body. If the response has a
172 // non-200 status code, we will interpret that as an error and attempt to decode
173 // the specific error message from the response body. Primarily useful in a
174 // client.
175 func decodeHTTPSumResponse(_ context.Context, r *http.Response) (interface{}, error) {
176 if r.StatusCode != http.StatusOK {
177 return nil, errors.New(r.Status)
178 }
179 var resp addendpoint.SumResponse
180 err := json.NewDecoder(r.Body).Decode(&resp)
181 return resp, err
182 }
183
184 // decodeHTTPConcatResponse is a transport/http.DecodeResponseFunc that decodes
185 // a JSON-encoded concat response from the HTTP response body. If the response
186 // has a non-200 status code, we will interpret that as an error and attempt to
187 // decode the specific error message from the response body. Primarily useful in
188 // a client.
189 func decodeHTTPConcatResponse(_ context.Context, r *http.Response) (interface{}, error) {
190 if r.StatusCode != http.StatusOK {
191 return nil, errors.New(r.Status)
192 }
193 var resp addendpoint.ConcatResponse
194 err := json.NewDecoder(r.Body).Decode(&resp)
195 return resp, err
196 }
197
198 // encodeHTTPGenericRequest is a transport/http.EncodeRequestFunc that
199 // JSON-encodes any request to the request body. Primarily useful in a client.
200 func encodeHTTPGenericRequest(_ context.Context, r *http.Request, request interface{}) error {
201 var buf bytes.Buffer
202 if err := json.NewEncoder(&buf).Encode(request); err != nil {
203 return err
204 }
205 r.Body = ioutil.NopCloser(&buf)
206 return nil
207 }
208
209 // encodeHTTPGenericResponse is a transport/http.EncodeResponseFunc that encodes
210 // the response as JSON to the response writer. Primarily useful in a server.
211 func encodeHTTPGenericResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
212 if f, ok := response.(addendpoint.Failer); ok && f.Failed() != nil {
213 errorEncoder(ctx, f.Failed(), w)
214 return nil
215 }
216 w.Header().Set("Content-Type", "application/json; charset=utf-8")
217 return json.NewEncoder(w).Encode(response)
218 }
+0
-119
examples/addsvc/pkg/addtransport/thrift.go less more
0 package addtransport
1
2 import (
3 "context"
4 "time"
5
6 jujuratelimit "github.com/juju/ratelimit"
7 "github.com/sony/gobreaker"
8
9 "github.com/go-kit/kit/circuitbreaker"
10 "github.com/go-kit/kit/endpoint"
11 "github.com/go-kit/kit/ratelimit"
12
13 "github.com/go-kit/kit/examples/addsvc/pkg/addendpoint"
14 "github.com/go-kit/kit/examples/addsvc/pkg/addservice"
15 addthrift "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc"
16 )
17
18 type thriftServer struct {
19 ctx context.Context
20 endpoints addendpoint.Set
21 }
22
23 // NewThriftServer makes a set of endpoints available as a Thrift service.
24 func NewThriftServer(endpoints addendpoint.Set) addthrift.AddService {
25 return &thriftServer{
26 endpoints: endpoints,
27 }
28 }
29
30 func (s *thriftServer) Sum(ctx context.Context, a int64, b int64) (*addthrift.SumReply, error) {
31 request := addendpoint.SumRequest{A: int(a), B: int(b)}
32 response, err := s.endpoints.SumEndpoint(ctx, request)
33 if err != nil {
34 return nil, err
35 }
36 resp := response.(addendpoint.SumResponse)
37 return &addthrift.SumReply{Value: int64(resp.V), Err: err2str(resp.Err)}, nil
38 }
39
40 func (s *thriftServer) Concat(ctx context.Context, a string, b string) (*addthrift.ConcatReply, error) {
41 request := addendpoint.ConcatRequest{A: a, B: b}
42 response, err := s.endpoints.ConcatEndpoint(ctx, request)
43 if err != nil {
44 return nil, err
45 }
46 resp := response.(addendpoint.ConcatResponse)
47 return &addthrift.ConcatReply{Value: resp.V, Err: err2str(resp.Err)}, nil
48 }
49
50 // NewThriftClient returns an AddService backed by a Thrift server described by
51 // the provided client. The caller is responsible for constructing the client,
52 // and eventually closing the underlying transport. We bake-in certain middlewares,
53 // implementing the client library pattern.
54 func NewThriftClient(client *addthrift.AddServiceClient) addservice.Service {
55 // We construct a single ratelimiter middleware, to limit the total outgoing
56 // QPS from this client to all methods on the remote instance. We also
57 // construct per-endpoint circuitbreaker middlewares to demonstrate how
58 // that's done, although they could easily be combined into a single breaker
59 // for the entire remote instance, too.
60 limiter := ratelimit.NewTokenBucketLimiter(jujuratelimit.NewBucketWithRate(100, 100))
61
62 // Each individual endpoint is an http/transport.Client (which implements
63 // endpoint.Endpoint) that gets wrapped with various middlewares. If you
64 // could rely on a consistent set of client behavior.
65 var sumEndpoint endpoint.Endpoint
66 {
67 sumEndpoint = MakeThriftSumEndpoint(client)
68 sumEndpoint = limiter(sumEndpoint)
69 sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{
70 Name: "Sum",
71 Timeout: 30 * time.Second,
72 }))(sumEndpoint)
73 }
74
75 // The Concat endpoint is the same thing, with slightly different
76 // middlewares to demonstrate how to specialize per-endpoint.
77 var concatEndpoint endpoint.Endpoint
78 {
79 concatEndpoint = MakeThriftConcatEndpoint(client)
80 concatEndpoint = limiter(concatEndpoint)
81 concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{
82 Name: "Concat",
83 Timeout: 10 * time.Second,
84 }))(concatEndpoint)
85 }
86
87 // Returning the endpoint.Set as a service.Service relies on the
88 // endpoint.Set implementing the Service methods. That's just a simple bit
89 // of glue code.
90 return addendpoint.Set{
91 SumEndpoint: sumEndpoint,
92 ConcatEndpoint: concatEndpoint,
93 }
94 }
95
96 // MakeThriftSumEndpoint returns an endpoint that invokes the passed Thrift client.
97 // Useful only in clients, and only until a proper transport/thrift.Client exists.
98 func MakeThriftSumEndpoint(client *addthrift.AddServiceClient) endpoint.Endpoint {
99 return func(ctx context.Context, request interface{}) (interface{}, error) {
100 req := request.(addendpoint.SumRequest)
101 reply, err := client.Sum(ctx, int64(req.A), int64(req.B))
102 if err == addservice.ErrIntOverflow {
103 return nil, err // special case; see comment on ErrIntOverflow
104 }
105 return addendpoint.SumResponse{V: int(reply.Value), Err: err}, nil
106 }
107 }
108
109 // MakeThriftConcatEndpoint returns an endpoint that invokes the passed Thrift
110 // client. Useful only in clients, and only until a proper
111 // transport/thrift.Client exists.
112 func MakeThriftConcatEndpoint(client *addthrift.AddServiceClient) endpoint.Endpoint {
113 return func(ctx context.Context, request interface{}) (interface{}, error) {
114 req := request.(addendpoint.ConcatRequest)
115 reply, err := client.Concat(ctx, req.A, req.B)
116 return addendpoint.ConcatResponse{V: reply.Value, Err: err}, nil
117 }
118 }
+0
-14
examples/addsvc/thrift/addsvc.thrift less more
0 struct SumReply {
1 1: i64 value
2 2: string err
3 }
4
5 struct ConcatReply {
6 1: string value
7 2: string err
8 }
9
10 service AddService {
11 SumReply Sum(1: i64 a, 2: i64 b)
12 ConcatReply Concat(1: string a, 2: string b)
13 }
+0
-5
examples/addsvc/thrift/compile.sh less more
0 #!/usr/bin/env sh
1
2 # See also https://thrift.apache.org/tutorial/go
3
4 thrift -r --gen "go:package_prefix=github.com/go-kit/kit/examples/addsvc/thrift/gen-go/,thrift_import=github.com/apache/thrift/lib/go/thrift" addsvc.thrift
+0
-7
examples/addsvc/thrift/gen-go/addsvc/GoUnusedProtection__.go less more
0 // Autogenerated by Thrift Compiler (1.0.0-dev)
1 // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
2
3 package addsvc
4
5 var GoUnusedProtection__ int;
6
+0
-159
examples/addsvc/thrift/gen-go/addsvc/add_service-remote/add_service-remote.go less more
0 // Autogenerated by Thrift Compiler (1.0.0-dev)
1 // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
2
3 package main
4
5 import (
6 "context"
7 "flag"
8 "fmt"
9 "math"
10 "net"
11 "net/url"
12 "os"
13 "strconv"
14 "strings"
15 "github.com/apache/thrift/lib/go/thrift"
16 "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc"
17 )
18
19
20 func Usage() {
21 fmt.Fprintln(os.Stderr, "Usage of ", os.Args[0], " [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:")
22 flag.PrintDefaults()
23 fmt.Fprintln(os.Stderr, "\nFunctions:")
24 fmt.Fprintln(os.Stderr, " SumReply Sum(i64 a, i64 b)")
25 fmt.Fprintln(os.Stderr, " ConcatReply Concat(string a, string b)")
26 fmt.Fprintln(os.Stderr)
27 os.Exit(0)
28 }
29
30 func main() {
31 flag.Usage = Usage
32 var host string
33 var port int
34 var protocol string
35 var urlString string
36 var framed bool
37 var useHttp bool
38 var parsedUrl url.URL
39 var trans thrift.TTransport
40 _ = strconv.Atoi
41 _ = math.Abs
42 flag.Usage = Usage
43 flag.StringVar(&host, "h", "localhost", "Specify host and port")
44 flag.IntVar(&port, "p", 9090, "Specify port")
45 flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)")
46 flag.StringVar(&urlString, "u", "", "Specify the url")
47 flag.BoolVar(&framed, "framed", false, "Use framed transport")
48 flag.BoolVar(&useHttp, "http", false, "Use http")
49 flag.Parse()
50
51 if len(urlString) > 0 {
52 parsedUrl, err := url.Parse(urlString)
53 if err != nil {
54 fmt.Fprintln(os.Stderr, "Error parsing URL: ", err)
55 flag.Usage()
56 }
57 host = parsedUrl.Host
58 useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == "http"
59 } else if useHttp {
60 _, err := url.Parse(fmt.Sprint("http://", host, ":", port))
61 if err != nil {
62 fmt.Fprintln(os.Stderr, "Error parsing URL: ", err)
63 flag.Usage()
64 }
65 }
66
67 cmd := flag.Arg(0)
68 var err error
69 if useHttp {
70 trans, err = thrift.NewTHttpClient(parsedUrl.String())
71 } else {
72 portStr := fmt.Sprint(port)
73 if strings.Contains(host, ":") {
74 host, portStr, err = net.SplitHostPort(host)
75 if err != nil {
76 fmt.Fprintln(os.Stderr, "error with host:", err)
77 os.Exit(1)
78 }
79 }
80 trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))
81 if err != nil {
82 fmt.Fprintln(os.Stderr, "error resolving address:", err)
83 os.Exit(1)
84 }
85 if framed {
86 trans = thrift.NewTFramedTransport(trans)
87 }
88 }
89 if err != nil {
90 fmt.Fprintln(os.Stderr, "Error creating transport", err)
91 os.Exit(1)
92 }
93 defer trans.Close()
94 var protocolFactory thrift.TProtocolFactory
95 switch protocol {
96 case "compact":
97 protocolFactory = thrift.NewTCompactProtocolFactory()
98 break
99 case "simplejson":
100 protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
101 break
102 case "json":
103 protocolFactory = thrift.NewTJSONProtocolFactory()
104 break
105 case "binary", "":
106 protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
107 break
108 default:
109 fmt.Fprintln(os.Stderr, "Invalid protocol specified: ", protocol)
110 Usage()
111 os.Exit(1)
112 }
113 client := addsvc.NewAddServiceClientFactory(trans, protocolFactory)
114 if err := trans.Open(); err != nil {
115 fmt.Fprintln(os.Stderr, "Error opening socket to ", host, ":", port, " ", err)
116 os.Exit(1)
117 }
118
119 switch cmd {
120 case "Sum":
121 if flag.NArg() - 1 != 2 {
122 fmt.Fprintln(os.Stderr, "Sum requires 2 args")
123 flag.Usage()
124 }
125 argvalue0, err6 := (strconv.ParseInt(flag.Arg(1), 10, 64))
126 if err6 != nil {
127 Usage()
128 return
129 }
130 value0 := argvalue0
131 argvalue1, err7 := (strconv.ParseInt(flag.Arg(2), 10, 64))
132 if err7 != nil {
133 Usage()
134 return
135 }
136 value1 := argvalue1
137 fmt.Print(client.Sum(context.Background(), value0, value1))
138 fmt.Print("\n")
139 break
140 case "Concat":
141 if flag.NArg() - 1 != 2 {
142 fmt.Fprintln(os.Stderr, "Concat requires 2 args")
143 flag.Usage()
144 }
145 argvalue0 := flag.Arg(1)
146 value0 := argvalue0
147 argvalue1 := flag.Arg(2)
148 value1 := argvalue1
149 fmt.Print(client.Concat(context.Background(), value0, value1))
150 fmt.Print("\n")
151 break
152 case "":
153 Usage()
154 break
155 default:
156 fmt.Fprintln(os.Stderr, "Invalid function ", cmd)
157 }
158 }
+0
-24
examples/addsvc/thrift/gen-go/addsvc/addsvc-consts.go less more
0 // Autogenerated by Thrift Compiler (1.0.0-dev)
1 // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
2
3 package addsvc
4
5 import (
6 "bytes"
7 "reflect"
8 "context"
9 "fmt"
10 "github.com/apache/thrift/lib/go/thrift"
11 )
12
13 // (needed to ensure safety because of naive import list construction.)
14 var _ = thrift.ZERO
15 var _ = fmt.Printf
16 var _ = context.Background
17 var _ = reflect.DeepEqual
18 var _ = bytes.Equal
19
20
21 func init() {
22 }
23
+0
-1065
examples/addsvc/thrift/gen-go/addsvc/addsvc.go less more
0 // Autogenerated by Thrift Compiler (1.0.0-dev)
1 // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
2
3 package addsvc
4
5 import (
6 "bytes"
7 "reflect"
8 "context"
9 "fmt"
10 "github.com/apache/thrift/lib/go/thrift"
11 )
12
13 // (needed to ensure safety because of naive import list construction.)
14 var _ = thrift.ZERO
15 var _ = fmt.Printf
16 var _ = context.Background
17 var _ = reflect.DeepEqual
18 var _ = bytes.Equal
19
20 // Attributes:
21 // - Value
22 // - Err
23 type SumReply struct {
24 Value int64 `thrift:"value,1" db:"value" json:"value"`
25 Err string `thrift:"err,2" db:"err" json:"err"`
26 }
27
28 func NewSumReply() *SumReply {
29 return &SumReply{}
30 }
31
32
33 func (p *SumReply) GetValue() int64 {
34 return p.Value
35 }
36
37 func (p *SumReply) GetErr() string {
38 return p.Err
39 }
40 func (p *SumReply) Read(iprot thrift.TProtocol) error {
41 if _, err := iprot.ReadStructBegin(); err != nil {
42 return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
43 }
44
45
46 for {
47 _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
48 if err != nil {
49 return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
50 }
51 if fieldTypeId == thrift.STOP { break; }
52 switch fieldId {
53 case 1:
54 if fieldTypeId == thrift.I64 {
55 if err := p.ReadField1(iprot); err != nil {
56 return err
57 }
58 } else {
59 if err := iprot.Skip(fieldTypeId); err != nil {
60 return err
61 }
62 }
63 case 2:
64 if fieldTypeId == thrift.STRING {
65 if err := p.ReadField2(iprot); err != nil {
66 return err
67 }
68 } else {
69 if err := iprot.Skip(fieldTypeId); err != nil {
70 return err
71 }
72 }
73 default:
74 if err := iprot.Skip(fieldTypeId); err != nil {
75 return err
76 }
77 }
78 if err := iprot.ReadFieldEnd(); err != nil {
79 return err
80 }
81 }
82 if err := iprot.ReadStructEnd(); err != nil {
83 return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
84 }
85 return nil
86 }
87
88 func (p *SumReply) ReadField1(iprot thrift.TProtocol) error {
89 if v, err := iprot.ReadI64(); err != nil {
90 return thrift.PrependError("error reading field 1: ", err)
91 } else {
92 p.Value = v
93 }
94 return nil
95 }
96
97 func (p *SumReply) ReadField2(iprot thrift.TProtocol) error {
98 if v, err := iprot.ReadString(); err != nil {
99 return thrift.PrependError("error reading field 2: ", err)
100 } else {
101 p.Err = v
102 }
103 return nil
104 }
105
106 func (p *SumReply) Write(oprot thrift.TProtocol) error {
107 if err := oprot.WriteStructBegin("SumReply"); err != nil {
108 return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
109 if p != nil {
110 if err := p.writeField1(oprot); err != nil { return err }
111 if err := p.writeField2(oprot); err != nil { return err }
112 }
113 if err := oprot.WriteFieldStop(); err != nil {
114 return thrift.PrependError("write field stop error: ", err) }
115 if err := oprot.WriteStructEnd(); err != nil {
116 return thrift.PrependError("write struct stop error: ", err) }
117 return nil
118 }
119
120 func (p *SumReply) writeField1(oprot thrift.TProtocol) (err error) {
121 if err := oprot.WriteFieldBegin("value", thrift.I64, 1); err != nil {
122 return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:value: ", p), err) }
123 if err := oprot.WriteI64(int64(p.Value)); err != nil {
124 return thrift.PrependError(fmt.Sprintf("%T.value (1) field write error: ", p), err) }
125 if err := oprot.WriteFieldEnd(); err != nil {
126 return thrift.PrependError(fmt.Sprintf("%T write field end error 1:value: ", p), err) }
127 return err
128 }
129
130 func (p *SumReply) writeField2(oprot thrift.TProtocol) (err error) {
131 if err := oprot.WriteFieldBegin("err", thrift.STRING, 2); err != nil {
132 return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:err: ", p), err) }
133 if err := oprot.WriteString(string(p.Err)); err != nil {
134 return thrift.PrependError(fmt.Sprintf("%T.err (2) field write error: ", p), err) }
135 if err := oprot.WriteFieldEnd(); err != nil {
136 return thrift.PrependError(fmt.Sprintf("%T write field end error 2:err: ", p), err) }
137 return err
138 }
139
140 func (p *SumReply) String() string {
141 if p == nil {
142 return "<nil>"
143 }
144 return fmt.Sprintf("SumReply(%+v)", *p)
145 }
146
147 // Attributes:
148 // - Value
149 // - Err
150 type ConcatReply struct {
151 Value string `thrift:"value,1" db:"value" json:"value"`
152 Err string `thrift:"err,2" db:"err" json:"err"`
153 }
154
155 func NewConcatReply() *ConcatReply {
156 return &ConcatReply{}
157 }
158
159
160 func (p *ConcatReply) GetValue() string {
161 return p.Value
162 }
163
164 func (p *ConcatReply) GetErr() string {
165 return p.Err
166 }
167 func (p *ConcatReply) Read(iprot thrift.TProtocol) error {
168 if _, err := iprot.ReadStructBegin(); err != nil {
169 return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
170 }
171
172
173 for {
174 _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
175 if err != nil {
176 return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
177 }
178 if fieldTypeId == thrift.STOP { break; }
179 switch fieldId {
180 case 1:
181 if fieldTypeId == thrift.STRING {
182 if err := p.ReadField1(iprot); err != nil {
183 return err
184 }
185 } else {
186 if err := iprot.Skip(fieldTypeId); err != nil {
187 return err
188 }
189 }
190 case 2:
191 if fieldTypeId == thrift.STRING {
192 if err := p.ReadField2(iprot); err != nil {
193 return err
194 }
195 } else {
196 if err := iprot.Skip(fieldTypeId); err != nil {
197 return err
198 }
199 }
200 default:
201 if err := iprot.Skip(fieldTypeId); err != nil {
202 return err
203 }
204 }
205 if err := iprot.ReadFieldEnd(); err != nil {
206 return err
207 }
208 }
209 if err := iprot.ReadStructEnd(); err != nil {
210 return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
211 }
212 return nil
213 }
214
215 func (p *ConcatReply) ReadField1(iprot thrift.TProtocol) error {
216 if v, err := iprot.ReadString(); err != nil {
217 return thrift.PrependError("error reading field 1: ", err)
218 } else {
219 p.Value = v
220 }
221 return nil
222 }
223
224 func (p *ConcatReply) ReadField2(iprot thrift.TProtocol) error {
225 if v, err := iprot.ReadString(); err != nil {
226 return thrift.PrependError("error reading field 2: ", err)
227 } else {
228 p.Err = v
229 }
230 return nil
231 }
232
233 func (p *ConcatReply) Write(oprot thrift.TProtocol) error {
234 if err := oprot.WriteStructBegin("ConcatReply"); err != nil {
235 return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
236 if p != nil {
237 if err := p.writeField1(oprot); err != nil { return err }
238 if err := p.writeField2(oprot); err != nil { return err }
239 }
240 if err := oprot.WriteFieldStop(); err != nil {
241 return thrift.PrependError("write field stop error: ", err) }
242 if err := oprot.WriteStructEnd(); err != nil {
243 return thrift.PrependError("write struct stop error: ", err) }
244 return nil
245 }
246
247 func (p *ConcatReply) writeField1(oprot thrift.TProtocol) (err error) {
248 if err := oprot.WriteFieldBegin("value", thrift.STRING, 1); err != nil {
249 return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:value: ", p), err) }
250 if err := oprot.WriteString(string(p.Value)); err != nil {
251 return thrift.PrependError(fmt.Sprintf("%T.value (1) field write error: ", p), err) }
252 if err := oprot.WriteFieldEnd(); err != nil {
253 return thrift.PrependError(fmt.Sprintf("%T write field end error 1:value: ", p), err) }
254 return err
255 }
256
257 func (p *ConcatReply) writeField2(oprot thrift.TProtocol) (err error) {
258 if err := oprot.WriteFieldBegin("err", thrift.STRING, 2); err != nil {
259 return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:err: ", p), err) }
260 if err := oprot.WriteString(string(p.Err)); err != nil {
261 return thrift.PrependError(fmt.Sprintf("%T.err (2) field write error: ", p), err) }
262 if err := oprot.WriteFieldEnd(); err != nil {
263 return thrift.PrependError(fmt.Sprintf("%T write field end error 2:err: ", p), err) }
264 return err
265 }
266
267 func (p *ConcatReply) String() string {
268 if p == nil {
269 return "<nil>"
270 }
271 return fmt.Sprintf("ConcatReply(%+v)", *p)
272 }
273
274 type AddService interface {
275 // Parameters:
276 // - A
277 // - B
278 Sum(ctx context.Context, a int64, b int64) (r *SumReply, err error)
279 // Parameters:
280 // - A
281 // - B
282 Concat(ctx context.Context, a string, b string) (r *ConcatReply, err error)
283 }
284
285 type AddServiceClient struct {
286 Transport thrift.TTransport
287 ProtocolFactory thrift.TProtocolFactory
288 InputProtocol thrift.TProtocol
289 OutputProtocol thrift.TProtocol
290 SeqId int32
291 }
292
293 func NewAddServiceClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *AddServiceClient {
294 return &AddServiceClient{Transport: t,
295 ProtocolFactory: f,
296 InputProtocol: f.GetProtocol(t),
297 OutputProtocol: f.GetProtocol(t),
298 SeqId: 0,
299 }
300 }
301
302 func NewAddServiceClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *AddServiceClient {
303 return &AddServiceClient{Transport: t,
304 ProtocolFactory: nil,
305 InputProtocol: iprot,
306 OutputProtocol: oprot,
307 SeqId: 0,
308 }
309 }
310
311 // Parameters:
312 // - A
313 // - B
314 func (p *AddServiceClient) Sum(ctx context.Context, a int64, b int64) (r *SumReply, err error) {
315 if err = p.sendSum(a, b); err != nil { return }
316 return p.recvSum()
317 }
318
319 func (p *AddServiceClient) sendSum(a int64, b int64)(err error) {
320 oprot := p.OutputProtocol
321 if oprot == nil {
322 oprot = p.ProtocolFactory.GetProtocol(p.Transport)
323 p.OutputProtocol = oprot
324 }
325 p.SeqId++
326 if err = oprot.WriteMessageBegin("Sum", thrift.CALL, p.SeqId); err != nil {
327 return
328 }
329 args := AddServiceSumArgs{
330 A : a,
331 B : b,
332 }
333 if err = args.Write(oprot); err != nil {
334 return
335 }
336 if err = oprot.WriteMessageEnd(); err != nil {
337 return
338 }
339 return oprot.Flush()
340 }
341
342
343 func (p *AddServiceClient) recvSum() (value *SumReply, err error) {
344 iprot := p.InputProtocol
345 if iprot == nil {
346 iprot = p.ProtocolFactory.GetProtocol(p.Transport)
347 p.InputProtocol = iprot
348 }
349 method, mTypeId, seqId, err := iprot.ReadMessageBegin()
350 if err != nil {
351 return
352 }
353 if method != "Sum" {
354 err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "Sum failed: wrong method name")
355 return
356 }
357 if p.SeqId != seqId {
358 err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "Sum failed: out of sequence response")
359 return
360 }
361 if mTypeId == thrift.EXCEPTION {
362 error0 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception")
363 var error1 error
364 error1, err = error0.Read(iprot)
365 if err != nil {
366 return
367 }
368 if err = iprot.ReadMessageEnd(); err != nil {
369 return
370 }
371 err = error1
372 return
373 }
374 if mTypeId != thrift.REPLY {
375 err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "Sum failed: invalid message type")
376 return
377 }
378 result := AddServiceSumResult{}
379 if err = result.Read(iprot); err != nil {
380 return
381 }
382 if err = iprot.ReadMessageEnd(); err != nil {
383 return
384 }
385 value = result.GetSuccess()
386 return
387 }
388
389 // Parameters:
390 // - A
391 // - B
392 func (p *AddServiceClient) Concat(ctx context.Context, a string, b string) (r *ConcatReply, err error) {
393 if err = p.sendConcat(a, b); err != nil { return }
394 return p.recvConcat()
395 }
396
397 func (p *AddServiceClient) sendConcat(a string, b string)(err error) {
398 oprot := p.OutputProtocol
399 if oprot == nil {
400 oprot = p.ProtocolFactory.GetProtocol(p.Transport)
401 p.OutputProtocol = oprot
402 }
403 p.SeqId++
404 if err = oprot.WriteMessageBegin("Concat", thrift.CALL, p.SeqId); err != nil {
405 return
406 }
407 args := AddServiceConcatArgs{
408 A : a,
409 B : b,
410 }
411 if err = args.Write(oprot); err != nil {
412 return
413 }
414 if err = oprot.WriteMessageEnd(); err != nil {
415 return
416 }
417 return oprot.Flush()
418 }
419
420
421 func (p *AddServiceClient) recvConcat() (value *ConcatReply, err error) {
422 iprot := p.InputProtocol
423 if iprot == nil {
424 iprot = p.ProtocolFactory.GetProtocol(p.Transport)
425 p.InputProtocol = iprot
426 }
427 method, mTypeId, seqId, err := iprot.ReadMessageBegin()
428 if err != nil {
429 return
430 }
431 if method != "Concat" {
432 err = thrift.NewTApplicationException(thrift.WRONG_METHOD_NAME, "Concat failed: wrong method name")
433 return
434 }
435 if p.SeqId != seqId {
436 err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, "Concat failed: out of sequence response")
437 return
438 }
439 if mTypeId == thrift.EXCEPTION {
440 error2 := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "Unknown Exception")
441 var error3 error
442 error3, err = error2.Read(iprot)
443 if err != nil {
444 return
445 }
446 if err = iprot.ReadMessageEnd(); err != nil {
447 return
448 }
449 err = error3
450 return
451 }
452 if mTypeId != thrift.REPLY {
453 err = thrift.NewTApplicationException(thrift.INVALID_MESSAGE_TYPE_EXCEPTION, "Concat failed: invalid message type")
454 return
455 }
456 result := AddServiceConcatResult{}
457 if err = result.Read(iprot); err != nil {
458 return
459 }
460 if err = iprot.ReadMessageEnd(); err != nil {
461 return
462 }
463 value = result.GetSuccess()
464 return
465 }
466
467
468 type AddServiceProcessor struct {
469 processorMap map[string]thrift.TProcessorFunction
470 handler AddService
471 }
472
473 func (p *AddServiceProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
474 p.processorMap[key] = processor
475 }
476
477 func (p *AddServiceProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
478 processor, ok = p.processorMap[key]
479 return processor, ok
480 }
481
482 func (p *AddServiceProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
483 return p.processorMap
484 }
485
486 func NewAddServiceProcessor(handler AddService) *AddServiceProcessor {
487
488 self4 := &AddServiceProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}
489 self4.processorMap["Sum"] = &addServiceProcessorSum{handler:handler}
490 self4.processorMap["Concat"] = &addServiceProcessorConcat{handler:handler}
491 return self4
492 }
493
494 func (p *AddServiceProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
495 name, _, seqId, err := iprot.ReadMessageBegin()
496 if err != nil { return false, err }
497 if processor, ok := p.GetProcessorFunction(name); ok {
498 return processor.Process(ctx, seqId, iprot, oprot)
499 }
500 iprot.Skip(thrift.STRUCT)
501 iprot.ReadMessageEnd()
502 x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name)
503 oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)
504 x5.Write(oprot)
505 oprot.WriteMessageEnd()
506 oprot.Flush()
507 return false, x5
508
509 }
510
511 type addServiceProcessorSum struct {
512 handler AddService
513 }
514
515 func (p *addServiceProcessorSum) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
516 args := AddServiceSumArgs{}
517 if err = args.Read(iprot); err != nil {
518 iprot.ReadMessageEnd()
519 x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
520 oprot.WriteMessageBegin("Sum", thrift.EXCEPTION, seqId)
521 x.Write(oprot)
522 oprot.WriteMessageEnd()
523 oprot.Flush()
524 return false, err
525 }
526
527 iprot.ReadMessageEnd()
528 result := AddServiceSumResult{}
529 var retval *SumReply
530 var err2 error
531 if retval, err2 = p.handler.Sum(ctx, args.A, args.B); err2 != nil {
532 x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing Sum: " + err2.Error())
533 oprot.WriteMessageBegin("Sum", thrift.EXCEPTION, seqId)
534 x.Write(oprot)
535 oprot.WriteMessageEnd()
536 oprot.Flush()
537 return true, err2
538 } else {
539 result.Success = retval
540 }
541 if err2 = oprot.WriteMessageBegin("Sum", thrift.REPLY, seqId); err2 != nil {
542 err = err2
543 }
544 if err2 = result.Write(oprot); err == nil && err2 != nil {
545 err = err2
546 }
547 if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {
548 err = err2
549 }
550 if err2 = oprot.Flush(); err == nil && err2 != nil {
551 err = err2
552 }
553 if err != nil {
554 return
555 }
556 return true, err
557 }
558
559 type addServiceProcessorConcat struct {
560 handler AddService
561 }
562
563 func (p *addServiceProcessorConcat) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
564 args := AddServiceConcatArgs{}
565 if err = args.Read(iprot); err != nil {
566 iprot.ReadMessageEnd()
567 x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
568 oprot.WriteMessageBegin("Concat", thrift.EXCEPTION, seqId)
569 x.Write(oprot)
570 oprot.WriteMessageEnd()
571 oprot.Flush()
572 return false, err
573 }
574