package localserver // import ( // context "context" // "encoding/json" // "fmt" // "io" // sync "sync" // "github.com/pion/webrtc/v3" // ) // type WebrtcFsManager struct { // stream SignalingService_LinkClient // DatachannelManager DataChannelManager // LocalSD map[string]*webrtc.SessionDescription // RTCPeerConnections map[string]*webrtc.PeerConnection // DataChannels map[string]*webrtc.DataChannel // PendingCandidates map[string][]*webrtc.ICECandidate // CandidateChannel chan *IncomingCandidate // CandidateMux *sync.RWMutex // RTCPeerConnectionMapMux *sync.RWMutex // DataChannelMapMux *sync.RWMutex // LocalSDMapMux *sync.RWMutex // } // func NewWebrtcFsManager(dataChannelManager DataChannelManager) (webrtcFsManager *WebrtcFsManager, err error) { // webrtcFsManager = &WebrtcFsManager{ // DatachannelManager: dataChannelManager, // DataChannels: make(map[string]*webrtc.DataChannel), // PendingCandidates: make(map[string][]*webrtc.ICECandidate), // LocalSD: make(map[string]*webrtc.SessionDescription), // RTCPeerConnections: make(map[string]*webrtc.PeerConnection), // RTCPeerConnectionMapMux: &sync.RWMutex{}, // LocalSDMapMux: &sync.RWMutex{}, // CandidateMux: &sync.RWMutex{}, // DataChannelMapMux: &sync.RWMutex{}, // } // return // } // func (wf *WebrtcFsManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) { // bs, err := json.Marshal(payload) // if err != nil { // return // } // err = wf.stream.Send(&SignalingMessage{ // Type: messageType, // From: from, // To: to, // Payload: bs, // }) // return // } // func (wf *WebrtcFsManager) CreateOffer(ctx context.Context, target string, from string, cb OnICECandidateFunc) (err error) { // peerConnection, err := wf.createPeerConnection(target, from, webrtc.SDPTypeOffer, cb) // if err != nil { // return // } // rawOffer, err := peerConnection.CreateOffer(nil) // if err != nil { // return // } // if err = peerConnection.SetLocalDescription(rawOffer); err != nil { // return // } // wf.RTCPeerConnectionMapMux.Lock() // // logger.Println("adding for target", target) // wf.RTCPeerConnections[target] = peerConnection // wf.RTCPeerConnectionMapMux.Unlock() // err = wf.sendSignalingMessage(string(WEBRTC_OFFER_FS), "lolo_local_serv", target, map[string]any{ // "to": target, // "from": "lolo_local_serv", // "sdp": rawOffer.SDP, // }) // return // } // func (wf *WebrtcFsManager) HandleOffer(ctx context.Context, req map[string]string, cb OnICECandidateFunc) (err error) { // done, errCh := make(chan struct{}), make(chan error) // go func() { // peerConnection, err := wf.createPeerConnection(req[FROM], req[TO], webrtc.SDPTypeAnswer, cb) // if err != nil { // errCh <- err // return // } // wf.RTCPeerConnectionMapMux.Lock() // wf.RTCPeerConnections[req[FROM]] = peerConnection // wf.RTCPeerConnectionMapMux.Unlock() // offer := webrtc.SessionDescription{ // Type: webrtc.SDPTypeOffer, // SDP: req[SDP], // } // if err = peerConnection.SetRemoteDescription(offer); err != nil { // errCh <- err // return // } // rawAnswer, err := peerConnection.CreateAnswer(nil) // if err != nil { // errCh <- err // return // } // wf.LocalSDMapMux.Lock() // wf.LocalSD[req[FROM]] = &rawAnswer // wf.LocalSDMapMux.Unlock() // // if err = wf.stream.Send(&Request{ // // Type: string(WEBRTC_ANSWER_FS), // // From: "lolo_local_serv", // // Token: "none", // // Payload: map[string]string{ // // "to": req[FROM], // // "from": "lolo_local_serv", // // "sdp": rawAnswer.SDP, // // }, // // }); err != nil { // // errCh <- err // // return // // } // done <- struct{}{} // }() // select { // case <-done: // return // case err = <-errCh: // return // case <-ctx.Done(): // err = ctx.Err() // return // } // } // func (wf *WebrtcFsManager) HandleAnswer(ctx context.Context, req map[string]string) (err error) { // wf.RTCPeerConnectionMapMux.RLock() // defer wf.RTCPeerConnectionMapMux.RUnlock() // defer func() { // if r := recover(); err != nil { // // logger.Printf("recover from panic : %v\n", r) // } // }() // if _, ok := wf.RTCPeerConnections[req[FROM]]; !ok { // err = fmt.Errorf("no corresponding peer connection for id : %s", req[FROM]) // return // } // peerConnnection := wf.RTCPeerConnections[req[FROM]] // if err = peerConnnection.SetRemoteDescription(webrtc.SessionDescription{ // Type: webrtc.SDPTypeAnswer, // SDP: req[SDP], // }); err != nil { // return // } // // if err = wf.stream.Send(&Request{ // // Type: string(WEBRTC_COUNTER_OFFER_FS), // // From: "lolo_local_serv", // // Token: "none", // // Payload: map[string]string{ // // "from": "lolo_local_serv", // // "to": req[FROM], // // }, // // }); err != nil { // // return // // } // wf.CandidateMux.RLock() // for range wf.PendingCandidates[req[FROM]] { // // logger.Println("sending candidate to", req[FROM]) // // if err = wf.stream.Send(&Request{ // // Type: string(WEBRTC_CANDIDATE_FS), // // From: "lolo_local_serv", // // Token: "none", // // Payload: map[string]string{ // // "from": "lolo_local_serv", // // "to": req[FROM], // // "candidate": candidate.ToJSON().Candidate, // // "sdpMid": *candidate.ToJSON().SDPMid, // // "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)), // // }, // // }); err != nil { // // return // // } // } // wf.CandidateMux.RUnlock() // wf.CandidateMux.Lock() // delete(wf.PendingCandidates, req[FROM]) // wf.CandidateMux.Unlock() // wf.LocalSDMapMux.Lock() // delete(wf.LocalSD, req[FROM]) // wf.LocalSDMapMux.Unlock() // return // } // func (wf *WebrtcFsManager) HandleCounterOffer(ctx context.Context, req map[string]string) (err error) { // wf.RTCPeerConnectionMapMux.RLock() // if _, ok := wf.RTCPeerConnections[req[FROM]]; !ok { // err = fmt.Errorf("no field corresponding peer connection for id %s", req[FROM]) // return // } // connection := wf.RTCPeerConnections[req[FROM]] // wf.RTCPeerConnectionMapMux.RUnlock() // wf.LocalSDMapMux.RLock() // if err = connection.SetLocalDescription(*wf.LocalSD[req[FROM]]); err != nil { // return // } // wf.LocalSDMapMux.RUnlock() // wf.CandidateMux.RLock() // for range wf.PendingCandidates[req[FROM]] { // // // logger.Println("sending candidate to", req[FROM]) // // if err = wf.stream.Send(&Request{ // // Type: string(WEBRTC_CANDIDATE_FS), // // From: "lolo_local_serv", // // Token: "none", // // Payload: map[string]string{ // // "from": "lolo_local_serv", // // "to": req[FROM], // // "candidate": candidate.ToJSON().Candidate, // // "sdpMid": *candidate.ToJSON().SDPMid, // // "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)), // // }, // // }); err != nil { // // return // // } // } // wf.CandidateMux.RUnlock() // return // } // func (wf *WebrtcFsManager) createPeerConnection(target string, from string, peerType webrtc.SDPType, cb OnICECandidateFunc) (peerConnection *webrtc.PeerConnection, err error) { // defer func() { // if r := recover(); err != nil { // // logger.Printf("recover from panic : %v\n", r) // } // }() // s := webrtc.SettingEngine{} // s.DetachDataChannels() // api := webrtc.NewAPI(webrtc.WithSettingEngine(s)) // config := webrtc.Configuration{ // ICEServers: []webrtc.ICEServer{ // { // URLs: []string{"stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302?transport=tcp"}, // }, // }, // SDPSemantics: webrtc.SDPSemanticsUnifiedPlan, // } // peerConnection, err = api.NewPeerConnection(config) // if err != nil { // return // } // if peerType == webrtc.SDPTypeOffer { // maxRetransmits := uint16(100) // channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{ // MaxRetransmits: &maxRetransmits, // }) // if err != nil { // return nil, err // } // channel.OnOpen(func() { // // logger.Println("channel opened") // if chanErr := channel.SendText("yooo man this is open"); chanErr != nil { // // logger.Println(chanErr) // } // }) // channel.OnMessage(func(msg webrtc.DataChannelMessage) { // // logger.Printf("new message %s\n", string(msg.Data)) // done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{ // From: target, // Type: "test", // Payload: &DatachannelMessagePayload{}, // }, channel) // select { // case <-done: // //// logger.Println("done with success") // case e := <-errCh: // // logger.Println(e) // // logger.Println("this is impossible") // } // }) // wf.DataChannelMapMux.Lock() // wf.DataChannels[target] = channel // wf.DataChannelMapMux.Unlock() // } // peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) { // // logger.Printf("ICE connection state has changed %s\n", is.String()) // if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed { // // logger.Println(is) // } // }) // peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) { // dc.OnOpen(func() { // // logger.Printf("got a new open datachannel %s\n", dc.Label()) // dataChann, err := dc.Detach() // if err != nil { // // logger.Println(err) // return // } // for { // var x []byte = make([]byte, 2<<15) // n, _, err := dataChann.ReadDataChannel(x) // if err != nil { // // logger.Println(err) // if err == io.EOF { // return // } // continue // } // go func(msg []byte) { // var dataChannelMessage DatachannelMessage // if unmarshalErr := json.Unmarshal(msg, &dataChannelMessage); unmarshalErr != nil { // // logger.Println(unmarshalErr) // return // } // done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{ // From: dataChannelMessage.From, // Type: dataChannelMessage.Type, // Payload: dataChannelMessage.Payload, // }, dc) // select { // case <-done: // //// logger.Println("done with success") // case e := <-errCh: // // logger.Println(e) // // logger.Println("this is impossible") // } // }(x[:n]) // } // }) // // dc.OnMessage(func(msg webrtc.DataChannelMessage) { // // var dataChannelMessage DatachannelMessage // // if unmarshalErr := json.Unmarshal(msg.Data, &dataChannelMessage); unmarshalErr != nil { // // // logger.Println(unmarshalErr) // // return // // } // // done, errCh := wf.DatachannelManager.HandleMessage(&DatachannelMessage{ // // From: dataChannelMessage.From, // // Type: dataChannelMessage.Type, // // Payload: dataChannelMessage.Payload, // // }, dc) // // select { // // case <-done: // // //// logger.Println("done with success") // // case e := <-errCh: // // // logger.Println(e) // // // logger.Println("this is impossible") // // } // // }) // }) // peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) { // if i == nil { // return // } // wf.CandidateMux.Lock() // defer wf.CandidateMux.Unlock() // desc := peerConnection.RemoteDescription() // if desc == nil { // wf.PendingCandidates[target] = append(wf.PendingCandidates[target], i) // } else { // // logger.Println(i) // if iceCandidateErr := cb(target, i); iceCandidateErr != nil { // // logger.Println(iceCandidateErr) // } // } // }) // peerConnection.OnNegotiationNeeded(func() { // if peerConnection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && peerConnection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer { // wf.RTCPeerConnectionMapMux.Lock() // defer wf.RTCPeerConnectionMapMux.Unlock() // for _, connection := range wf.RTCPeerConnections { // if connection.SignalingState() != webrtc.SignalingStateHaveLocalOffer && connection.SignalingState() != webrtc.SignalingStateHaveRemoteOffer { // localSd, err := connection.CreateOffer(nil) // if err != nil { // // logger.Println(err) // return // } // if err = connection.SetLocalDescription(localSd); err != nil { // // logger.Println(err) // return // } // // if err = wf.stream.Send(&Request{ // // Type: string(WEBRTC_RENNEGOTIATION_OFFER_FS), // // From: "lolo_local_serv", // // Token: "", // // Payload: map[string]string{ // // "to": id, // // "sdp": localSd.SDP, // // }, // // }); err != nil { // // // logger.Println(err) // // return // // } // } // } // } // }) // return // } // func (wf *WebrtcFsManager) HandleRennegotiationOffer(from string, dst string, sdp string) (err error) { // wf.RTCPeerConnectionMapMux.Lock() // defer wf.RTCPeerConnectionMapMux.Unlock() // if _, ok := wf.RTCPeerConnections[from]; !ok { // err = fmt.Errorf("no corresponding peer connection for id %s", from) // return // } // if wf.RTCPeerConnections[from].SignalingState() != webrtc.SignalingStateStable { // err = fmt.Errorf("rennego called in wrong state") // return // } // if err = wf.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil { // return // } // localSd, err := wf.RTCPeerConnections[from].CreateAnswer(nil) // if err != nil { // return // } // if err = wf.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil { // return // } // // if err = wf.stream.Send(&Request{ // // Type: string(WEBRTC_RENNEGOTIATION_ANSWER_FS), // // From: "lolo_local_serv", // // Token: "", // // Payload: map[string]string{ // // "to": from, // // "sdp": localSd.SDP, // // }, // // }); err != nil { // // // logger.Println(err) // // return // // } // return // } // func (wf *WebrtcFsManager) HandleRennegotiationAnswer(from string, dst string, sdp string) (err error) { // wf.RTCPeerConnectionMapMux.Lock() // defer wf.RTCPeerConnectionMapMux.Unlock() // if _, ok := wf.RTCPeerConnections[from]; !ok { // err = fmt.Errorf("no corresponding peer connection for id %s", from) // return // } // err = wf.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer}) // return // } // func (wf *WebrtcFsManager) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) { // wf.RTCPeerConnectionMapMux.Lock() // defer wf.RTCPeerConnectionMapMux.Unlock() // err = wf.RTCPeerConnections[from].AddICECandidate(*candidate) // return // }