Files
free-turn-proxy/cmd/client/main.go
T
2026-08-16 23:13:01 +03:00

110 lines
2.6 KiB
Go

package main
import (
"context"
"errors"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/samosvalishe/free-turn-proxy/internal/clientid"
"github.com/samosvalishe/free-turn-proxy/internal/config"
"github.com/samosvalishe/free-turn-proxy/internal/logx"
"github.com/samosvalishe/free-turn-proxy/internal/provider/vk"
"github.com/samosvalishe/free-turn-proxy/internal/proxy/udprelay"
"github.com/samosvalishe/free-turn-proxy/internal/session"
"github.com/samosvalishe/free-turn-proxy/internal/sub"
"github.com/samosvalishe/free-turn-proxy/internal/wire/rtpopus"
)
// version is populated at build time via -ldflags "-X main.version=...".
var version = "dev"
func main() {
args := os.Args[1:]
// Резолв подписки до парсинга даёт обязательный peer для валидации.
if subURL := config.PeekSubURL(args); subURL != "" {
s, ferr := sub.Fetch(context.Background(), subURL)
if ferr != nil {
log.Fatalf("failed to fetch subscription: %v", ferr)
}
if len(s.Nodes) == 0 || s.Nodes[0].URI == nil {
log.Fatalf("no nodes found in subscription")
}
args = append(args, s.Nodes[0].URI.String())
}
cfg, err := config.ParseClient(args, os.Stderr)
if err != nil {
if errors.Is(err, flag.ErrHelp) {
os.Exit(0)
}
log.Fatalf("%v", err)
}
if cfg.Obf.GenKey {
key, gerr := rtpopus.GenKeyHex()
if gerr != nil {
log.Fatalf("gen-obf-key: %v", gerr)
}
fmt.Println(key)
return
}
logger := logx.New(cfg.Log.Debug)
logger.Infof("Free Turn Proxy client version=%s", version)
idPaths := clientid.DefaultPaths()
id, persisted, err := clientid.Resolve(cfg.ClientID, idPaths)
if err != nil {
logger.Errorf("%v", err)
os.Exit(1)
}
if !persisted {
logger.Warnf("client ID не сохранён ни по одному пути (%v) - будет новым при следующем запуске", idPaths)
}
cfg.ClientID = id
logger.Infof("Client ID: %s", cfg.ClientID)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
go func() {
<-signalChan
logger.Infof("Terminating...")
cancel()
select {
case <-signalChan:
case <-time.After(5 * time.Second):
}
logger.Errorf("Exit...")
cancel()
os.Exit(1)
}()
sess, err := session.New(cfg, session.Deps{
Logger: logger,
Solver: vk.DefaultManualSolver,
})
if err != nil {
logger.Errorf("%v", err)
os.Exit(1)
}
if err := sess.Run(ctx); err != nil {
if errors.Is(err, udprelay.ErrFatal) {
logger.Errorf("fatal: %v", err)
} else {
logger.Errorf("%v", err)
}
os.Exit(1)
}
}