Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The architecture of lookout and its components are described in [src-d/lookout/d
**SDK includes:**
- proto [definitions](./proto)
- pre-generated libraries code for [Golang](./pb) and [Python](./python)
- low-level helpers to workaround protobuf/gRPC caveats. Check [go documentation](https://godoc.org/gopkg.in/src-d/lookout-sdk.v0/pb)
- quickstart documentation on [how to write an analyzer](#how-to-create-a-new-analyzer)


Expand Down Expand Up @@ -97,9 +98,11 @@ Please check how to create client in [bblfsh documentation](https://docs.sourced
Caveats
========
- client: disable secure connection on dialing with `grpc.WithInsecure()`
- client/server: set [max gRPC message size](https://github.com/grpc/grpc/issues/7927)
- client: set [max gRPC message size](https://github.com/grpc/grpc/issues/7927):
- go: use `pb.DialContext` instead.
- client: turn off [gRPC fail-fast](https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md) mode
If your analyzer greedy creates a connection to DataServer before one was actually started, you might want to disable fail-fast mode. This way the RPCs are queued until the chanel ready. Here is an [example](https://github.com/src-d/lookout-gometalint-analyzer/blob/7b4b37fb3109299516fbb43017934d131784f49f/cmd/gometalint-analyzer/main.go#L66).
- go client/server: use `pb.ToGoGrpcAddress` and `pb.Listen` to support [RFC 3986 URI scheme](https://github.com/grpc/grpc-go/issues/1911)

Release Process
=================
Expand Down
15 changes: 4 additions & 11 deletions language-analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io"
"net"
"os"

"google.golang.org/grpc"
Expand All @@ -20,14 +19,13 @@ import (
type analyzer struct{}

var portToListen = 2020
var dataSrvAddr = "localhost:10301"
var dataSrvAddr, _ = pb.ToGoGrpcAddress("ipv4://localhost:10301")
var version = "alpha"
var maxMessageSize = 100 * 1024 * 1024 //100mb

func (*analyzer) NotifyReviewEvent(ctx context.Context, review *pb.ReviewEvent) (*pb.EventResponse, error) {
log.Infof("got review request %v", review)

conn, err := grpc.Dial(dataSrvAddr, grpc.WithInsecure())
conn, err := pb.DialContext(ctx, dataSrvAddr, grpc.WithInsecure())
if err != nil {
log.Errorf(err, "failed to connect to DataServer at %s", dataSrvAddr)
return nil, err
Expand Down Expand Up @@ -88,18 +86,13 @@ func (*analyzer) NotifyPushEvent(context.Context, *pb.PushEvent) (*pb.EventRespo
}

func main() {
lis, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", portToListen))
lis, err := pb.Listen(fmt.Sprintf("ipv4://0.0.0.0:%d", portToListen))
if err != nil {
log.Errorf(err, "failed to listen on port: %d", portToListen)
os.Exit(1)
}

opts := []grpc.ServerOption{
grpc.MaxRecvMsgSize(maxMessageSize),
grpc.MaxSendMsgSize(maxMessageSize),
}

grpcServer := grpc.NewServer(opts...)
grpcServer := grpc.NewServer()
pb.RegisterAnalyzerServer(grpcServer, &analyzer{})
log.Infof("starting gRPC Analyzer server at port %d", portToListen)
grpcServer.Serve(lis)
Expand Down
95 changes: 95 additions & 0 deletions pb/grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package pb

import (
"fmt"
"net"
"net/url"

context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)

// maxMessageSize overrides default grpc max. message size to send/receive to/from clients
var maxMessageSize = 100 * 1024 * 1024 // 100MB

//TODO: https://github.com/grpc/grpc-go/issues/1911

// ToNetListenerAddress converts a gRPC URL to a network+address consumable by
// net.Listen. For example:
// ipv4://127.0.0.1:8080 -> (tcp4, 127.0.0.1:8080)
func ToNetListenerAddress(target string) (network, address string, err error) {
u, err := url.Parse(target)
if err != nil {
return
}

if u.Scheme == "dns" {
err = fmt.Errorf("dns:// not supported")
return
}

if u.Scheme == "unix" {
network = "unix"
address = u.Path
return
}

address = u.Host
switch u.Scheme {
case "ipv4":
network = "tcp4"
case "ipv6":
network = "tcp6"
default:
err = fmt.Errorf("scheme not supported: %s", u.Scheme)
}

return
}

// ToGoGrpcAddress converts a standard gRPC target name to a
// one that is supported by grpc-go.
func ToGoGrpcAddress(address string) (string, error) {
n, a, err := ToNetListenerAddress(address)
if err != nil {
return "", err
}

if n == "unix" {
return fmt.Sprintf("unix:%s", a), nil
}

return a, nil
}

// Listen is equivalent to standard net.Listen, but taking gRPC URL as input.
func Listen(address string) (net.Listener, error) {
n, a, err := ToNetListenerAddress(address)
if err != nil {
return nil, err
}

return net.Listen(n, a)
}

// NewServer creates new grpc.Server with custom message size
func NewServer(opts ...grpc.ServerOption) *grpc.Server {
opts = append(opts,
grpc.MaxRecvMsgSize(maxMessageSize),
grpc.MaxSendMsgSize(maxMessageSize),
)

return grpc.NewServer(opts...)
}

// DialContext creates a client connection to the given target with custom message size
func DialContext(ctx context.Context, target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
opts = append(opts,
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(maxMessageSize),
grpc.MaxCallSendMsgSize(maxMessageSize),
),
)

return grpc.DialContext(ctx, target, opts...)
}