chore: remove mobile wrappers and harden go-backend service control

This commit is contained in:
sagit
2026-02-08 01:59:45 +00:00
parent 15cf25f74b
commit d720b9e00c
59 changed files with 141 additions and 2095 deletions
@@ -238,6 +238,7 @@ func (h *Handler) resolveUserTunnelAndLimiter(userID, tunnelID int64) (int64, *i
FROM user_tunnel ut
LEFT JOIN speed_limit sl ON sl.id = ut.speed_id
WHERE ut.user_id = ? AND ut.tunnel_id = ?
ORDER BY ut.id ASC
LIMIT 1
`, userID, tunnelID)
var userTunnelID int64
@@ -256,6 +257,32 @@ func (h *Handler) resolveUserTunnelAndLimiter(userID, tunnelID int64) (int64, *i
return userTunnelID, &v, nil
}
func (h *Handler) listUserTunnelIDs(userID, tunnelID int64) ([]int64, error) {
rows, err := h.repo.DB().Query(`
SELECT id
FROM user_tunnel
WHERE user_id = ? AND tunnel_id = ?
ORDER BY id ASC
`, userID, tunnelID)
if err != nil {
return nil, err
}
defer rows.Close()
out := make([]int64, 0)
for rows.Next() {
var id int64
if err := rows.Scan(&id); err != nil {
return nil, err
}
out = append(out, id)
}
if err := rows.Err(); err != nil {
return nil, err
}
return out, nil
}
func (h *Handler) syncForwardServices(forward *forwardRecord, method string, allowFallbackAdd bool) error {
if h == nil || forward == nil {
return errors.New("invalid forward sync context")
@@ -311,20 +338,62 @@ func (h *Handler) controlForwardServices(forward *forwardRecord, commandType str
if err != nil {
return err
}
base := buildForwardServiceBase(forward.ID, forward.UserID, userTunnelID)
payload := map[string]interface{}{
"services": buildForwardControlServiceNames(base, commandType),
userTunnelIDs, err := h.listUserTunnelIDs(forward.UserID, forward.TunnelID)
if err != nil {
return err
}
bases := buildForwardServiceBaseCandidates(forward.ID, forward.UserID, userTunnelID, userTunnelIDs)
seen := map[int64]struct{}{}
for _, fp := range ports {
if _, ok := seen[fp.NodeID]; ok {
continue
}
seen[fp.NodeID] = struct{}{}
_, err := h.sendNodeCommand(fp.NodeID, commandType, payload, false, tolerateNotFound)
if err != nil {
return err
var lastNotFoundErr error
nodeHandled := false
for _, base := range bases {
payload := map[string]interface{}{
"services": buildForwardControlServiceNames(base, commandType),
}
_, err := h.sendNodeCommand(fp.NodeID, commandType, payload, false, false)
if err == nil {
nodeHandled = true
break
}
if !isNotFoundError(err) {
return err
}
lastNotFoundErr = err
if shouldTryLegacySingleService(commandType) {
legacyPayload := map[string]interface{}{
"services": []string{base},
}
_, legacyErr := h.sendNodeCommand(fp.NodeID, commandType, legacyPayload, false, false)
if legacyErr == nil {
nodeHandled = true
break
}
if !isNotFoundError(legacyErr) {
return legacyErr
}
lastNotFoundErr = legacyErr
}
}
if nodeHandled {
continue
}
if tolerateNotFound {
continue
}
if lastNotFoundErr != nil {
return lastNotFoundErr
}
return errors.New("service control failed")
}
return nil
}
@@ -852,6 +921,31 @@ func buildForwardServiceBase(forwardID, userID, userTunnelID int64) string {
return fmt.Sprintf("%d_%d_%d", forwardID, userID, userTunnelID)
}
func buildForwardServiceBaseCandidates(forwardID, userID, preferredUserTunnelID int64, userTunnelIDs []int64) []string {
orderedIDs := make([]int64, 0, len(userTunnelIDs)+2)
seen := make(map[int64]struct{}, len(userTunnelIDs)+2)
appendID := func(id int64) {
if _, ok := seen[id]; ok {
return
}
seen[id] = struct{}{}
orderedIDs = append(orderedIDs, id)
}
appendID(preferredUserTunnelID)
for _, id := range userTunnelIDs {
appendID(id)
}
appendID(0)
bases := make([]string, 0, len(orderedIDs))
for _, id := range orderedIDs {
bases = append(bases, buildForwardServiceBase(forwardID, userID, id))
}
return bases
}
func buildForwardControlServiceNames(base, commandType string) []string {
names := []string{base + "_tcp", base + "_udp"}
if strings.EqualFold(strings.TrimSpace(commandType), "DeleteService") {
@@ -860,6 +954,19 @@ func buildForwardControlServiceNames(base, commandType string) []string {
return names
}
func shouldTryLegacySingleService(commandType string) bool {
cmd := strings.ToLower(strings.TrimSpace(commandType))
return cmd == "pauseservice" || cmd == "resumeservice"
}
func isNotFoundError(err error) bool {
if err == nil {
return false
}
msg := strings.ToLower(strings.TrimSpace(err.Error()))
return strings.Contains(msg, "not found") || strings.Contains(msg, "不存在")
}
func buildForwardServiceConfigs(baseName string, forward *forwardRecord, tunnel *tunnelRecord, node *nodeRecord, port int, limiter *int) []map[string]interface{} {
protocols := []string{"tcp", "udp"}
services := make([]map[string]interface{}, 0, 2)
@@ -25,3 +25,31 @@ func TestBuildForwardControlServiceNamesDelete(t *testing.T) {
t.Fatalf("expected %v, got %v", want, got)
}
}
func TestBuildForwardServiceBaseCandidates(t *testing.T) {
got := buildForwardServiceBaseCandidates(12, 34, 56, []int64{56, 78, 90})
want := []string{"12_34_56", "12_34_78", "12_34_90", "12_34_0"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("expected %v, got %v", want, got)
}
}
func TestBuildForwardServiceBaseCandidatesWithZeroPreferred(t *testing.T) {
got := buildForwardServiceBaseCandidates(12, 34, 0, []int64{78, 0, 90})
want := []string{"12_34_0", "12_34_78", "12_34_90"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("expected %v, got %v", want, got)
}
}
func TestShouldTryLegacySingleService(t *testing.T) {
if !shouldTryLegacySingleService("PauseService") {
t.Fatalf("PauseService should require legacy fallback")
}
if !shouldTryLegacySingleService("resumeService") {
t.Fatalf("ResumeService should require legacy fallback")
}
if shouldTryLegacySingleService("DeleteService") {
t.Fatalf("DeleteService should not require legacy fallback")
}
}