croc/internal/session/session.go

120 lines
3.0 KiB
Go

package session
import (
"io"
"os"
"github.com/pion/webrtc/v2"
"github.com/schollz/croc/v5/pkg/stats"
"github.com/schollz/croc/v5/pkg/utils"
)
// CompletionHandler to be called when transfer is done
type CompletionHandler func()
// Session contains common elements to perform send/receive
type Session struct {
Done chan struct{}
NetworkStats *stats.Stats
sdpInput io.Reader
sdpOutput io.Writer
peerConnection *webrtc.PeerConnection
onCompletion CompletionHandler
}
// New creates a new Session
func New(sdpInput io.Reader, sdpOutput io.Writer) Session {
if sdpInput == nil {
sdpInput = os.Stdin
}
if sdpOutput == nil {
sdpOutput = os.Stdout
}
return Session{
sdpInput: sdpInput,
sdpOutput: sdpOutput,
Done: make(chan struct{}),
NetworkStats: stats.New(),
}
}
// CreateConnection prepares a WebRTC connection
func (s *Session) CreateConnection(onConnectionStateChange func(connectionState webrtc.ICEConnectionState)) error {
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
}
// Create a new RTCPeerConnection
peerConnection, err := webrtc.NewPeerConnection(config)
if err != nil {
return err
}
s.peerConnection = peerConnection
peerConnection.OnICEConnectionStateChange(onConnectionStateChange)
return nil
}
// SetSDP sets the SDP
func (s *Session) SetSDP(encoded string) error {
var sdp webrtc.SessionDescription
err := utils.Decode(encoded, &sdp)
if err != nil {
return err
}
return s.peerConnection.SetRemoteDescription(sdp)
}
// CreateDataChannel that will be used to send data
func (s *Session) CreateDataChannel(c *webrtc.DataChannelInit) (*webrtc.DataChannel, error) {
return s.peerConnection.CreateDataChannel("data", c)
}
// OnDataChannel sets an OnDataChannel handler
func (s *Session) OnDataChannel(handler func(d *webrtc.DataChannel)) {
s.peerConnection.OnDataChannel(handler)
}
// CreateAnswer set the local description and print the answer SDP
func (s *Session) CreateAnswer() (string, error) {
// Create an answer
answer, err := s.peerConnection.CreateAnswer(nil)
if err != nil {
return "", err
}
return s.createSessionDescription(answer)
}
// CreateOffer set the local description and print the offer SDP
func (s *Session) CreateOffer() (string, error) {
// Create an offer
answer, err := s.peerConnection.CreateOffer(nil)
if err != nil {
return "", err
}
return s.createSessionDescription(answer)
}
// createSessionDescription set the local description and print the SDP
func (s *Session) createSessionDescription(desc webrtc.SessionDescription) (string, error) {
// Sets the LocalDescription, and starts our UDP listeners
if err := s.peerConnection.SetLocalDescription(desc); err != nil {
return "", err
}
desc.SDP = utils.StripSDP(desc.SDP)
// Output the SDP in base64 so we can paste it in browser
return utils.Encode(desc)
}
// OnCompletion is called when session ends
func (s *Session) OnCompletion() {
if s.onCompletion != nil {
s.onCompletion()
}
}