package transfer const ( StatePending = "PENDING" StateAccepted = "ACCEPTED" StateP2PActive = "P2P_ACTIVE" StateRelayActive = "RELAY_ACTIVE" StateDone = "DONE" StateFailed = "FAILED" StateCancelled = "CANCELLED" ) const ( ModeP2P = "p2p" ModeRelay = "relay" ) // AutoAcceptThreshold is the file size at/under which the receiver may // silently auto-accept a transfer. brief §2: "> 100 MB 二次确认". const AutoAcceptThreshold = 100 * 1024 * 1024 // IsValidTransition reports whether a transfer may move from→to. // // Forward-only: any state can advance to a "later" state, but never go back. // We're permissive because client→server timing races are real: // - sender's /p2p can land before receiver's /accept commits → PENDING → P2P_ACTIVE // - either side may call /done before /p2p ever fired → ACCEPTED → DONE // Strict ordering would surface as 409s the user can't recover from. // // Terminal states (DONE / FAILED / CANCELLED) accept no further transitions. func IsValidTransition(from, to string) bool { switch from { case StatePending: return to == StateAccepted || to == StateP2PActive || to == StateRelayActive || to == StateCancelled || to == StateFailed case StateAccepted: return to == StateP2PActive || to == StateRelayActive || to == StateDone || to == StateCancelled || to == StateFailed case StateP2PActive: // P2P 失败自动 fallback 到 Relay (brief §2). return to == StateRelayActive || to == StateDone || to == StateFailed || to == StateCancelled case StateRelayActive: return to == StateDone || to == StateFailed || to == StateCancelled case StateDone, StateFailed, StateCancelled: return false } return false } // IsTerminal reports whether the state is final (no further transitions). func IsTerminal(state string) bool { return state == StateDone || state == StateFailed || state == StateCancelled }