package main import ( "context" "flag" "fmt" "log" "math/rand" "net" "net/http" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/credentials" "google.golang.org/grpc/examples/data" // "github.com/improbable-eng/grpc-web/go/grpcweb" _ "net/http/pprof" pb "git.capella.pro/thepaint/protos" "encoding/base64" "encoding/json" "github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/pion/webrtc/v3" "github.com/sirupsen/logrus" ) var ( tls = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP") certFile = flag.String("cert_file", "", "The TLS cert file") keyFile = flag.String("key_file", "", "The TLS key file") jsonDBFile = flag.String("json_db_file", "", "A json file containing a list of features") port = flag.Int("port", 8080, "The server port") ) type server struct { pb.UnimplementedPaintClientServer // savedFeatures []*pb.Feature // read-only after initialized // // mu sync.Mutex // protects routeNotes // routeNotes map[string][]*pb.RouteNote } func main() { grpclog.V(10) flag.Parse() lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port)) if err != nil { log.Fatalf("failed to listen: %v", err) } var opts []grpc.ServerOption if *tls { if *certFile == "" { *certFile = data.Path("x509/server_cert.pem") } if *keyFile == "" { *keyFile = data.Path("x509/server_key.pem") } creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile) if err != nil { log.Fatalf("Failed to generate credentials %v", err) } opts = []grpc.ServerOption{grpc.Creds(creds)} } grpcServer := grpc.NewServer(opts...) s := newServer() pb.RegisterPaintClientServer(grpcServer, s) logrus.Printf("starting %d", *port) wrappedServer := grpcweb.WrapServer(grpcServer, grpcweb.WithOriginFunc(func(origin string) bool { return true }), grpcweb.WithWebsocketsMessageReadLimit(100000)) handler := func(resp http.ResponseWriter, req *http.Request) { logrus.Info(req) if req.ProtoMajor != 2 { wrappedServer.ServeHTTP(resp, req) } else { grpcServer.ServeHTTP(resp, req) } } httpServer := http.Server{ Addr: fmt.Sprintf(":%d", port), // Handler: CompressHandler(http.HandlerFunc(handler)), Handler: http.HandlerFunc(handler), } go func() { http.ListenAndServe(":8081", nil) }() if err := httpServer.Serve(lis); err != nil { grpclog.Fatalf("failed starting http server: %v", err) } } func (s *server) Paint(ctx context.Context, request *pb.PaintRequest) (*pb.PaintReply, error) { panic("implement me") } func (s *server) Monitor(sub *pb.MonitorSub, monitorServer pb.PaintClient_MonitorServer) error { // for k := 0; k < 4; k++ { // points := []*pb.MonitorPoint{} // for i := 64*k; i < 64*(k+1); i++ { // for j := 0; j < 256; j++ { // points = append(points, &pb.MonitorPoint{ // Point: &pb.BPoint{ // X: int32(i), // Y: int32(j), // }, // Color: &pb.BColor{ // Rgba: uint32(rand.Intn(256)) | uint32(rand.Intn(256))<<8 | uint32(rand.Intn(256))<<16 | 255<<24, // }, // }) // } // } // // monitorServer.Send(&pb.MonitorReply{ // Points: points, // // BytesPoints: b.Bytes(), // }) // } points := []*pb.MonitorPoint{} for i := 0; i < 256; i++ { for j := 0; j < 256; j++ { points = append(points, &pb.MonitorPoint{ Point: &pb.BPoint{ X: int32(i), Y: int32(j), }, Color: &pb.BColor{ Rgba: uint32(rand.Intn(256)) | uint32(rand.Intn(256))<<8 | uint32(rand.Intn(256))<<16 | 255<<24, }, }) } } monitorServer.Send(&pb.MonitorReply{ Points: points, // BytesPoints: b.Bytes(), }) return nil } // func (s *server) RequestRTC(req pb.PaintClient_RequestRTCServer) error { // offer(req) // return nil // } func newServer() *server { s := &server{} return s } func handleError(err error) { logrus.Error(err) } func (s *server) RequestRTC(stream pb.PaintClient_RequestRTCServer) error { logrus.Info("NEW GRPC") // Configure and create a new PeerConnection. config := webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ { URLs: []string{"stun:melvans.com:3478"}, Username: "b84e4232f84505e3c3967184df374f2cdaa954f1", Credential: "afc39ae0591c132292f73a87f6f3725311fbafa0", // URLs: []string{"stun:stun.l.google.com:19302"}, }, }, } pc, err := webrtc.NewPeerConnection(config) if err != nil { handleError(err) } // Create DataChannel. sendChannel, err := pc.CreateDataChannel("data", nil) if err != nil { handleError(err) } sendChannel.OnClose(func() { logrus.Println("sendChannel has closed") }) sendChannel.OnOpen(func() { logrus.Println("sendChannel has opened") }) sendChannel.OnMessage(func(msg webrtc.DataChannelMessage) { logrus.Println(string(msg.Data)) }) // Create offer offer, err := pc.CreateOffer(nil) if err != nil { handleError(err) } if err := pc.SetLocalDescription(offer); err != nil { handleError(err) } // Add handlers for setting up the connection. pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) { logrus.Println(state) }) // connectionString := make(chan bool) // Trickle ICE. Emit server candidate to client pc.OnICECandidate(func(i *webrtc.ICECandidate) { if i == nil { return } // candidateString, err := json.Marshal(i.ToJSON()) // if err != nil { // logrus.Error(err) // return // } logrus.Println(i) err = stream.Send(&pb.RTCData{ Event: string(pc.LocalDescription().Type.String()), Data: string(pc.LocalDescription().SDP), }) // connectionString <- true if err != nil { logrus.Error(err) return } }) for { msg, err := stream.Recv() if err != nil { logrus.Error(err) return err } answer := webrtc.SessionDescription{ SDP: msg.Data, Type: webrtc.NewSDPType(msg.Event), } err = pc.SetRemoteDescription(answer) if err != nil { logrus.Error(err) return err } } // // If PeerConnection is closed remove it from global list // pc.OnConnectionStateChange(func(p webrtc.PeerConnectionState) { // switch p { // case webrtc.PeerConnectionStateFailed: // if err := pc.Close(); err != nil { // log.Print(err) // } // case webrtc.PeerConnectionStateClosed: // log.Print("closed") // } // }) // offer, err := pc.CreateOffer(nil) // if err != nil { // logrus.Error(err) // } // if err = pc.SetLocalDescription(offer); err != nil { // logrus.Error(err) // } // logrus.Println(offer) // <-connectionString // answer := webrtc.SessionDescription{ // SDP: sub.Data, // Type: webrtc.SDPTypeAnswer, // } // err = pc.SetRemoteDescription(answer) // if err != nil { // logrus.Error(err) // } // return nil } func Encode(obj interface{}) string { b, err := json.Marshal(obj) if err != nil { panic(err) } return base64.StdEncoding.EncodeToString(b) } func websocketHandler(w http.ResponseWriter, r *http.Request) { }