mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-13 02:26:36 +08:00
[优化] Phase2
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"openflare/model"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TunnelInput struct {
|
||||
Name string `json:"name"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type TunnelView struct {
|
||||
ID uint `json:"id"`
|
||||
TunnelID string `json:"tunnel_id"`
|
||||
Name string `json:"name"`
|
||||
TunnelToken string `json:"tunnel_token"`
|
||||
Status string `json:"status"`
|
||||
ClientVersion string `json:"client_version"`
|
||||
FrpVersion string `json:"frp_version"`
|
||||
LastSeenAt time.Time `json:"last_seen_at"`
|
||||
LastError string `json:"last_error"`
|
||||
CurrentVersion string `json:"current_version"`
|
||||
CurrentChecksum string `json:"current_checksum"`
|
||||
ConnectedRelays []string `json:"connected_relays"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func ListTunnels() ([]*TunnelView, error) {
|
||||
tunnels, err := model.ListTunnels()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views := make([]*TunnelView, 0, len(tunnels))
|
||||
for _, tunnel := range tunnels {
|
||||
views = append(views, buildTunnelView(tunnel))
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
func GetTunnel(id uint) (*TunnelView, error) {
|
||||
tunnel, err := model.GetTunnelByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildTunnelView(tunnel), nil
|
||||
}
|
||||
|
||||
func CreateTunnel(input TunnelInput) (*TunnelView, error) {
|
||||
name := strings.TrimSpace(input.Name)
|
||||
if name == "" {
|
||||
return nil, errors.New("Tunnel 名称不能为空")
|
||||
}
|
||||
tunnelID, err := newTunnelID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tunnelToken, err := newRandomToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tunnel := &model.Tunnel{
|
||||
TunnelID: tunnelID,
|
||||
Name: name,
|
||||
TunnelToken: tunnelToken,
|
||||
Status: "offline",
|
||||
Remark: strings.TrimSpace(input.Remark),
|
||||
}
|
||||
if err := tunnel.Insert(); err != nil {
|
||||
if model.IsUniqueConstraintError(err) {
|
||||
return nil, errors.New("Tunnel 标识生成冲突,请重试")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
slog.Info("tunnel created", "name", tunnel.Name, "tunnel_id", tunnel.TunnelID)
|
||||
return buildTunnelView(tunnel), nil
|
||||
}
|
||||
|
||||
func UpdateTunnel(id uint, input TunnelInput) (*TunnelView, error) {
|
||||
tunnel, err := model.GetTunnelByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := strings.TrimSpace(input.Name)
|
||||
if name == "" {
|
||||
return nil, errors.New("Tunnel 名称不能为空")
|
||||
}
|
||||
tunnel.Name = name
|
||||
tunnel.Remark = strings.TrimSpace(input.Remark)
|
||||
if err := tunnel.Update(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
slog.Info("tunnel updated", "name", tunnel.Name, "tunnel_id", tunnel.TunnelID)
|
||||
return buildTunnelView(tunnel), nil
|
||||
}
|
||||
|
||||
func DeleteTunnel(id uint) error {
|
||||
tunnel, err := model.GetTunnelByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("tunnel deleted", "name", tunnel.Name, "tunnel_id", tunnel.TunnelID)
|
||||
return tunnel.Delete()
|
||||
}
|
||||
|
||||
func RotateTunnelToken(id uint) (*TunnelView, error) {
|
||||
tunnel, err := model.GetTunnelByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newToken, err := newRandomToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tunnel.TunnelToken = newToken
|
||||
if err := tunnel.Update(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
slog.Info("tunnel token rotated", "tunnel_id", tunnel.TunnelID)
|
||||
return buildTunnelView(tunnel), nil
|
||||
}
|
||||
|
||||
func AuthenticateTunnelToken(token string) (*model.Tunnel, error) {
|
||||
token = strings.TrimSpace(token)
|
||||
if token == "" {
|
||||
return nil, errors.New("缺少 Tunnel Token")
|
||||
}
|
||||
tunnel, err := model.GetTunnelByTunnelToken(token)
|
||||
if err != nil {
|
||||
return nil, errors.New("Tunnel Token 无效")
|
||||
}
|
||||
return tunnel, nil
|
||||
}
|
||||
|
||||
func buildTunnelView(tunnel *model.Tunnel) *TunnelView {
|
||||
if tunnel == nil {
|
||||
return nil
|
||||
}
|
||||
relays := decodeTunnelConnectedRelays(tunnel.ConnectedRelays)
|
||||
return &TunnelView{
|
||||
ID: tunnel.ID,
|
||||
TunnelID: tunnel.TunnelID,
|
||||
Name: tunnel.Name,
|
||||
TunnelToken: tunnel.TunnelToken,
|
||||
Status: tunnel.Status,
|
||||
ClientVersion: tunnel.ClientVersion,
|
||||
FrpVersion: tunnel.FrpVersion,
|
||||
LastSeenAt: tunnel.LastSeenAt,
|
||||
LastError: tunnel.LastError,
|
||||
CurrentVersion: tunnel.CurrentVersion,
|
||||
CurrentChecksum: tunnel.CurrentChecksum,
|
||||
ConnectedRelays: relays,
|
||||
Remark: tunnel.Remark,
|
||||
CreatedAt: tunnel.CreatedAt,
|
||||
UpdatedAt: tunnel.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func decodeTunnelConnectedRelays(raw string) []string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" || raw == "[]" {
|
||||
return make([]string, 0)
|
||||
}
|
||||
var relays []string
|
||||
if err := json.Unmarshal([]byte(raw), &relays); err != nil {
|
||||
return make([]string, 0)
|
||||
}
|
||||
return relays
|
||||
}
|
||||
|
||||
func newTunnelID() (string, error) {
|
||||
token, err := newRandomToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "tun-" + token, nil
|
||||
}
|
||||
Reference in New Issue
Block a user