소스 검색

fix(nodes): clean up orphaned client_inbounds on node inbound removal

When a remote node disconnects or one of its inbounds vanishes from the
traffic snapshot, setRemoteTrafficLocked deleted the central inbound row
but left the client_inbounds join rows behind. Affected clients ended up
linked to hundreds of phantom inbounds, and editing one then failed with
"record not found" / "Load Old Data Error" because Update aborted on the
first GetInbound miss.

- Detach client_inbounds rows when deleting a vanished node inbound
- Prune stale links during client Update instead of aborting the save
- Drop orphaned client_inbounds rows on startup to heal existing DBs

Closes #4636
MHSanaei 19 시간 전
부모
커밋
169068d8fb
3개의 변경된 파일26개의 추가작업 그리고 0개의 파일을 삭제
  1. 15 0
      database/db.go
  2. 8 0
      web/service/client.go
  3. 3 0
      web/service/inbound.go

+ 15 - 0
database/db.go

@@ -83,6 +83,21 @@ func initModels() error {
 			return err
 		}
 	}
+	if err := pruneOrphanedClientInbounds(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func pruneOrphanedClientInbounds() error {
+	res := db.Exec("DELETE FROM client_inbounds WHERE inbound_id NOT IN (SELECT id FROM inbounds)")
+	if res.Error != nil {
+		log.Printf("Error pruning orphaned client_inbounds rows: %v", res.Error)
+		return res.Error
+	}
+	if res.RowsAffected > 0 {
+		log.Printf("Pruned %d orphaned client_inbounds row(s)", res.RowsAffected)
+	}
 	return nil
 }
 

+ 8 - 0
web/service/client.go

@@ -629,6 +629,14 @@ func (s *ClientService) Update(inboundSvc *InboundService, id int, updated model
 	for _, ibId := range inboundIds {
 		inbound, getErr := inboundSvc.GetInbound(ibId)
 		if getErr != nil {
+			if errors.Is(getErr, gorm.ErrRecordNotFound) {
+				if err := database.GetDB().
+					Where("client_id = ? AND inbound_id = ?", id, ibId).
+					Delete(&model.ClientInbound{}).Error; err != nil {
+					return needRestart, err
+				}
+				continue
+			}
 			return needRestart, getErr
 		}
 		oldKey := clientKeyForProtocol(inbound.Protocol, existing)

+ 3 - 0
web/service/inbound.go

@@ -1432,6 +1432,9 @@ func (s *InboundService) setRemoteTrafficLocked(nodeID int, snap *runtime.Traffi
 			Delete(&xray.ClientTraffic{}).Error; err != nil {
 			return false, err
 		}
+		if err := s.clientService.DetachInbound(tx, c.Id); err != nil {
+			return false, err
+		}
 		if err := tx.Where("id = ?", c.Id).
 			Delete(&model.Inbound{}).Error; err != nil {
 			return false, err