Files
OpenFlare/openflare_relay/internal/relay/runner.go
T
2026-06-01 08:47:09 +08:00

95 lines
2.0 KiB
Go

package relay
import (
"context"
"encoding/json"
"log/slog"
"time"
"openflare-relay/internal/config"
"openflare-relay/internal/frps"
"openflare-relay/internal/heartbeat"
"openflare-relay/internal/httpclient"
"openflare-relay/internal/state"
"openflare-relay/internal/wsclient"
"openflare/service"
)
type Runner struct {
Config *config.Config
StateStore *state.Store
HeartbeatService *heartbeat.Service
FrpsManager *frps.Manager
WebSocketService *wsclient.Client
HttpClient *httpclient.Client
}
func (r *Runner) Run(ctx context.Context) error {
// Start heartbeat loop in background
go r.HeartbeatService.Run(ctx)
// WebSocket reconnection loop
for {
select {
case <-ctx.Done():
r.FrpsManager.Stop()
return ctx.Err()
default:
}
conn, err := r.WebSocketService.Connect(ctx)
if err != nil {
slog.Error("relay ws connect failed, will retry", "error", err)
r.sleepContext(ctx, 5*time.Second)
continue
}
r.handleConnection(ctx, conn)
_ = conn.Close()
slog.Info("relay ws connection closed, reconnecting...")
r.sleepContext(ctx, 2*time.Second)
}
}
func (r *Runner) handleConnection(ctx context.Context, conn *wsclient.Connection) {
for {
select {
case <-ctx.Done():
return
default:
}
msg, err := conn.Receive()
if err != nil {
slog.Error("relay ws receive failed", "error", err)
return
}
switch msg.Type {
case "ping":
_ = conn.SendPong()
case "relay_config":
payloadBytes, ok := msg.Payload.(json.RawMessage)
if !ok {
slog.Error("invalid relay_config payload type")
continue
}
var cfg service.RelayConfig
if err := json.Unmarshal(payloadBytes, &cfg); err != nil {
slog.Error("failed to unmarshal relay_config", "error", err)
continue
}
r.FrpsManager.UpdateConfig(&cfg)
default:
slog.Debug("ignored unknown ws message type", "type", msg.Type)
}
}
}
func (r *Runner) sleepContext(ctx context.Context, d time.Duration) {
select {
case <-ctx.Done():
case <-time.After(d):
}
}