mirror of
https://github.com/harshabose/client.git
synced 2025-09-26 19:31:20 +08:00
131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"cloud.google.com/go/firestore"
|
|
"firebase.google.com/go"
|
|
"google.golang.org/api/option"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/pion/webrtc/v4"
|
|
)
|
|
|
|
type AnswerSignal struct {
|
|
peerConnection *PeerConnection
|
|
app *firebase.App
|
|
client *firestore.Client
|
|
docRef *firestore.DocumentRef
|
|
ctx context.Context
|
|
}
|
|
|
|
func CreateFirebaseAnswerSignal(ctx context.Context, peerConnection *PeerConnection) *AnswerSignal {
|
|
var (
|
|
configuration option.ClientOption
|
|
app *firebase.App
|
|
client *firestore.Client
|
|
err error
|
|
)
|
|
|
|
if configuration, err = GetFirebaseConfiguration(); err != nil {
|
|
panic(err)
|
|
}
|
|
if app, err = firebase.NewApp(ctx, nil, configuration); err != nil {
|
|
panic(err)
|
|
}
|
|
if client, err = app.Firestore(ctx); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return &AnswerSignal{
|
|
app: app,
|
|
client: client,
|
|
peerConnection: peerConnection,
|
|
ctx: ctx,
|
|
}
|
|
}
|
|
|
|
func (signal *AnswerSignal) Connect(category, connectionLabel string) error {
|
|
signal.docRef = signal.client.Collection(category).Doc(connectionLabel)
|
|
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
var data map[string]interface{}
|
|
loop:
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
snapshot, err := signal.docRef.Get(signal.ctx)
|
|
if err != nil || snapshot == nil {
|
|
if status.Code(err) == codes.NotFound {
|
|
continue loop
|
|
}
|
|
}
|
|
data = snapshot.Data()
|
|
|
|
if currentStatus, exists := data[FieldStatus]; !exists || currentStatus != FieldStatusPending {
|
|
continue loop
|
|
}
|
|
|
|
break loop
|
|
}
|
|
}
|
|
fmt.Println("Found Offer. Creating answer...")
|
|
|
|
return signal.answer(data[FieldOffer].(map[string]interface{}))
|
|
}
|
|
|
|
func (signal *AnswerSignal) answer(offer map[string]interface{}) error {
|
|
sdp, ok := offer[FieldSDP].(string)
|
|
if !ok {
|
|
return fmt.Errorf("invalid SDP format in offer")
|
|
}
|
|
|
|
if err := signal.peerConnection.peerConnection.SetRemoteDescription(webrtc.SessionDescription{
|
|
Type: webrtc.SDPTypeOffer,
|
|
SDP: sdp,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
answer, err := signal.peerConnection.peerConnection.CreateAnswer(nil)
|
|
if err != nil {
|
|
return fmt.Errorf("error while creating answer: %w", err)
|
|
}
|
|
|
|
if err := signal.peerConnection.peerConnection.SetLocalDescription(answer); err != nil {
|
|
return fmt.Errorf("error while setting local sdp: %w", err)
|
|
}
|
|
|
|
timer := time.NewTicker(30 * time.Second)
|
|
defer timer.Stop()
|
|
|
|
select {
|
|
case <-webrtc.GatheringCompletePromise(signal.peerConnection.peerConnection):
|
|
fmt.Println("ICE Gathering complete")
|
|
case <-timer.C:
|
|
return errors.New("failed to gather ICE candidates within 30 seconds")
|
|
}
|
|
|
|
if _, err = signal.docRef.Set(signal.ctx, map[string]interface{}{
|
|
FieldAnswer: map[string]interface{}{
|
|
FieldSDP: signal.peerConnection.peerConnection.LocalDescription().SDP,
|
|
FieldUpdatedAt: firestore.ServerTimestamp,
|
|
},
|
|
FieldStatus: FieldStatusConnected,
|
|
}, firestore.MergeAll); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (signal *AnswerSignal) Close() error {
|
|
return signal.client.Close()
|
|
}
|