Coder Social home page Coder Social logo

grpc-websocket-proxy's Introduction

grpc-websocket-proxy

GoDoc

Wrap your grpc-gateway mux with this helper to expose streaming endpoints over websockets.

On the wire this uses newline-delimited json encoding of the messages.

Usage:

	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	if err := echoserver.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *grpcAddr, opts); err != nil {
		return err
	}
-	http.ListenAndServe(*httpAddr, mux)
+	http.ListenAndServe(*httpAddr, wsproxy.WebsocketProxy(mux))

wsproxy

import "github.com/tmc/grpc-websocket-proxy/wsproxy"

Package wsproxy implements a websocket proxy for grpc-gateway backed services

Usage

var (
	MethodOverrideParam = "method"
	TokenCookieName     = "token"
)

func WebsocketProxy

func WebsocketProxy(h http.Handler) http.HandlerFunc

WebsocketProxy attempts to expose the underlying handler as a bidi websocket stream with newline-delimited JSON as the content encoding.

The HTTP Authorization header is either populated from the Sec-Websocket-Protocol field or by a cookie. The cookie name is specified by the TokenCookieName value.

example:

Sec-Websocket-Protocol: Bearer, foobar

is converted to:

Authorization: Bearer foobar

Method can be overwritten with the MethodOverrideParam get parameter in the requested URL

grpc-websocket-proxy's People

Contributors

alvarowolfx avatar brocaar avatar htang42 avatar jfhamlin avatar le-qi avatar shahruk10 avatar tmc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grpc-websocket-proxy's Issues

How to enable debug logging

I use etcd 3.3.15 which has this module compiled in.
I set --debug=true option to enable debug messages, but I don't see messages from this module in log file.
So, how can I enable it?

Doesn't work with grpc-gateway/v2/runtime

Doesn't work with grpc-gateway/v2/runtime

I was unable to start with v2. Is there an example of the work?

The connection attempt ends

{
   "code": 12,
   "message": "Method Not Allowed",
   "details": []
}	

Probably a mistake in example

Probably the example service should be.

service EchoService {
  rpc Echo(stream EchoRequest) returns (stream EchoResponse) {
    option (google.api.http) = {get: "/echo"};
  }
  rpc Stream(Empty) returns (stream EchoResponse) {
    option (google.api.http) = {get: "/stream"};
  }
  rpc Heartbeats(stream Empty) returns (stream Heartbeat) {
    option (google.api.http) = {post: "/heartbeats"};
  }
}

Because now both Echo and Stream methods points to the same /echo location. Also the echo should probably be get not post based on what i have tested with JS example.

I could have make a PR, but I don't know which versions you use to generate.

srv.Context().Done() is not fired when WebSocket client disconnects?

I'm running into an issue, and I hope you can help me. I'm using your library to stream events published to a Redis server to a WebSocket client (browser).

func (a *DeviceAPI) StreamEventLogs(req *pb.StreamDeviceEventLogsRequest, srv pb.DeviceService_StreamEventLogsServer) error {
	var devEUI lorawan.EUI64

	// For debugging to see when the request has been cancelled
	go func() {
		fmt.Println("cancelled!", <-srv.Context().Done())
	}()

	if err := devEUI.UnmarshalText([]byte(req.DevEui)); err != nil {
		return grpc.Errorf(codes.InvalidArgument, "devEUI: %s", err)
	}

	if err := a.validator.Validate(srv.Context(),
		auth.ValidateNodeAccess(devEUI, auth.Read)); err != nil {
		return grpc.Errorf(codes.Unauthenticated, "authentication failed: %s", err)
	}

	eventLogChan := make(chan eventlog.EventLog)
	go func() {
		err := eventlog.GetEventLogForDevice(srv.Context(), devEUI, eventLogChan)
		if err != nil {
			log.WithError(err).Error("get event-log for device error")
		}
		close(eventLogChan)
	}()

	for el := range eventLogChan {
		b, err := json.Marshal(el.Payload)
		if err != nil {
			return grpc.Errorf(codes.Internal, "marshal json error: %s", err)
		}

		resp := pb.StreamDeviceEventLogsResponse{
			Type:        el.Type,
			PayloadJson: string(b),
		}

		err = srv.Send(&resp)
		if err != nil {
			log.WithError(err).Error("error sending event-log response")
		}
	}

	return nil
}

In short, eventlog.GetEventLogForDevice is executed within a Go routine and blocks until the given context (srv.Context()) is cancelled. This function publishes to eventLogChan. When it completes (with or without error), it closes eventLogChan.

Below there is a loop which reads from eventLogChan and writes this to srv.


What I noticed is that when my WebSocket client disconnects, srv.Context().Done() does not fire. So the following code does not print:

	go func() {
		fmt.Println("cancelled!", <-srv.Context().Done())
	}()

Only when srv.Send() is called (e.g. there is a new event to send to the WebSocket client), srv.Context().Done() fires (which will cancel GetEventLogForDevice).

Is this an issue with grpc-websocket-proxy (e.g. the WebSocket disconnect event is not correctly captured), or should I have implemented my code in a different way?

Import logrus as lowercase

go: github.com/tmc/grpc-websocket-proxy/examples/cmd/wsechoserver imports
	github.com/Sirupsen/logrus: github.com/Sirupsen/[email protected]: parsing go.mod:
	module declares its path as: github.com/sirupsen/logrus
	        but was required as: github.com/Sirupsen/logrus

How to send bytes data from client side?

Hi!

I'm trying to send an array byte as a client stream.
When I tried to send the data, the grpc got EOF and never got data from the client side.
In the client side, I'm using Uint8Array as a byte array.(grapc-gateway converts bytes to Uint8Array in javascript)
I'm new to WebSocket, was I missing something?

If you need more detail I will create a minimal reproduction code.

.proto message definition is

message HealthCheckRequest {
    string health = 1;
    bytes buf = 2;
}

client-side is like this.

const byteMessage = new TextEncoder().encode("test message"); // create bytes(Uint8Array) for request
ws.send(JSON.stringify({ health: 'abc', buf: byteMessage})); // this code not working(got EOF)
ws.send(JSON.stringify({ health: 'abc'}));  // without `buf` property work correctly. And I could get data on the server side.

and the server side is like this.

func (s *Server) HealthCheckBiDiStream(stream pb.TranslatorService_HealthCheckBiDiStreamServer) error {
	cnt := 0
	for {
		_, err := stream.Recv()
		if err != nil && err != io.EOF {
			log.Fatal(err)
			return err
		}
		if err == io.EOF {
			return nil
		}

		stream.Send(&pb.HealthCheckResponse{
			Health: fmt.Sprintf("OK %d", cnt),
		})

		if err != nil {
			log.Fatal(err)
			return err
		}
		cnt += 1

	}

}

Add a client example

Either using gopherjs or pure JS, just to illustrate how the MethodOverrideParam interacts with the grpc-gateway exposed gRPC methods. Probably an example of authentication too would be nice.

Passing authentication from browser JS websocket

Hey there, I see there are some docs about passing authorization using the Sec-Websocket-Protocol header. While this is a clever workaround, it doesn't appear as though it'll actually work for websockets started from the browser. From the MDN article on websockets, only registered IANA subprotocols can be passed. Attempting to pass Bearer, 123 results in

VM3291:1 Uncaught DOMException: Failed to construct 'WebSocket': The subprotocol 'Bearer, 123' is invalid.

Was this implemented with browser compatibility in mind? Or was the idea that cookies would be the only browser-friendly authorization method?

Allow client-side streaming communication

Thanks for the work on this proxy! I'm wondering if there is any example of client-side streaming implemented with this proxy. So far, I was able to send all the client-streaming messages to the server perfectly. However, grpc-gateway's generated code expects some EOF before moving on to CloseAndRecv(), so I currently cannot get the server to return the message response.

I'm wondering if there is any examples of triggering the EOF to allow client-side (not bidi) streaming with the server, or if this package would require modification to make this work.

Unable to read from socket

For the WebSocket example GET on /echo I am unable to read anything from the socket, only able to write back. Reading simply returns an error EOF, when trying to RecvMsg in the gRPC server.

Downgrade logs to Debug level

When deploying this with a grpc-gateway and grpc server it quickly becomes a bit verbose to log every websocket interaction. It would be nicer to have the logs set to debug level.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.