| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 | package mainimport (	"log"	"math/rand"	"net/http"	"sync"	// "github.com/improbable-eng/grpc-web/go/grpcweb"	_ "net/http/pprof"	pb "git.capella.pro/thepaint/protos"	"google.golang.org/protobuf/proto"	"encoding/base64"	"encoding/json"	"github.com/gorilla/websocket"	"github.com/pion/webrtc/v3"	"github.com/sirupsen/logrus")var upgrader = websocket.Upgrader{	CheckOrigin: func(r *http.Request) bool { return true },}func main() {	http.HandleFunc("/ws", websocketHandler)	logrus.Fatal(http.ListenAndServe(":8081", nil))}func Getp(ii int, jj int) []*pb.MonitorPoint {	points := []*pb.MonitorPoint{}	for i := ii * 32; i < 32*(1+ii); i++ {		for j := jj * 32; j < 32*(1+jj); 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,				},			})		}	}	return points}func Encode(obj interface{}) string {	b, err := json.Marshal(obj)	if err != nil {		panic(err)	}	return base64.StdEncoding.EncodeToString(b)}// Handle incoming websocketsfunc websocketHandler(w http.ResponseWriter, r *http.Request) {	// Upgrade HTTP request to Websocket	unsafeConn, err := upgrader.Upgrade(w, r, nil)	if err != nil {		log.Print("upgrade:", err)		return	}	c := &threadSafeWriter{unsafeConn, sync.Mutex{}}	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 {		logrus.Error(err)	}	// Create DataChannel.	f := false	sendChannel, err := pc.CreateDataChannel("data", &webrtc.DataChannelInit{		Ordered: &f,	})	if err != nil {		logrus.Error(err)	}	sendChannel.OnClose(func() {		logrus.Println("sendChannel has closed")	})	sendChannel.OnOpen(func() {		logrus.Println("sendChannel has opened")	})	sendChannel.OnMessage(func(msg webrtc.DataChannelMessage) {		data := &pb.WebRTCRequest{}		err := proto.Unmarshal(msg.Data, data)		if err != nil {			logrus.WithField("data", data).Error(err)			return		}		logrus.WithField("data", data).Info("req")		if data.GetRequestData() != nil {			for i := 0; i < 8; i++ {				for j := 0; j < 8; j++ {					data := &pb.MonitorReply{						Points: Getp(i, j),					}					md, err := proto.Marshal(data)					if err != nil {						logrus.Error(err)						continue					}					logrus.Info(len(md))					sendChannel.Send(md)					// err = sendChannel.Send(md)					// if err != nil {					// 	logrus.Error(err)					// 	continue					// }				}			}		}	})	// Create a video track	videoTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion")	if err != nil {		panic(err)	}	_, err = pc.AddTrack(videoTrack)	if err != nil {		panic(err)	}	// Create offer	offer, err := pc.CreateOffer(nil)	if err != nil {		logrus.Error(err)	}	if err := pc.SetLocalDescription(offer); err != nil {		logrus.Error(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		}		data := &pb.RTCData{			Event: string(pc.LocalDescription().Type.String()),			Data:  string(pc.LocalDescription().SDP),		}		logrus.WithField("data", data).Info("data to client")		md, _ := proto.Marshal(data)		w, _ := unsafeConn.NextWriter(websocket.BinaryMessage)		w.Write(md)		w.Close()	})	for {		_, raw, err := c.ReadMessage()		data := &pb.RTCData{}		if err != nil {			logrus.Error(err)			return		} else if err := proto.Unmarshal(raw, data); err != nil {			logrus.WithField("data", string(raw)).Error(err)			return		}		logrus.WithField("data", data).Info("data from client")		switch data.Event {		case "candidate":			candidate := webrtc.ICECandidateInit{}			if err := json.Unmarshal([]byte(data.Data), &candidate); err != nil {				logrus.Error(err)				return			}			if err := pc.AddICECandidate(candidate); err != nil {				logrus.Error(err)				return			}		case "answer":			answer := webrtc.SessionDescription{				Type: webrtc.NewSDPType(data.Event),				SDP:  data.Data,			}			if err := pc.SetRemoteDescription(answer); err != nil {				logrus.Error(err)				return			}		}	}}type threadSafeWriter struct {	*websocket.Conn	sync.Mutex}func (t *threadSafeWriter) WriteJSON(v interface{}) error {	t.Lock()	defer t.Unlock()	return t.Conn.WriteJSON(v)}
 |