Files
elmprodvpn/selective-vpn-api/app/transport_singbox_profiles_flow_rollback_exec.go

125 lines
3.5 KiB
Go

package app
import (
"net/http"
transportcfgpkg "selective-vpn-api/app/transportcfg"
"strings"
)
func executeTransportSingBoxProfileRollbackLocked(
id string,
body SingBoxProfileRollbackRequest,
restart bool,
) (int, SingBoxProfileRollbackResponse) {
st := loadSingBoxProfilesState()
idx := findSingBoxProfileIndex(st.Items, id)
if idx < 0 {
return http.StatusNotFound, SingBoxProfileRollbackResponse{
OK: false,
Code: singBoxProfileCodeNotFound,
Message: "not found",
}
}
cur := st.Items[idx]
if body.BaseRevision > 0 && body.BaseRevision != cur.ProfileRevision {
return http.StatusConflict, SingBoxProfileRollbackResponse{
OK: false,
Code: singBoxProfileCodeRevisionMismatch,
Message: "base_revision mismatch",
ProfileID: cur.ID,
ProfileRevision: cur.ProfileRevision,
}
}
records, err := loadSingBoxHistoryRecords(cur.ID, 0)
if err != nil {
return http.StatusInternalServerError, SingBoxProfileRollbackResponse{
OK: false,
Code: singBoxProfileCodeRollbackFailed,
Message: "read history failed: " + err.Error(),
ProfileID: cur.ID,
ProfileRevision: cur.ProfileRevision,
}
}
cand, ok := selectSingBoxRollbackCandidate(records, strings.TrimSpace(body.HistoryID))
if !ok {
return http.StatusOK, SingBoxProfileRollbackResponse{
OK: false,
Code: singBoxProfileCodeHistoryMissing,
Message: "rollback snapshot not found",
ProfileID: cur.ID,
ProfileRevision: cur.ProfileRevision,
}
}
clientID := strings.TrimSpace(body.ClientID)
if clientID == "" {
clientID = strings.TrimSpace(cand.ClientID)
}
configPath := strings.TrimSpace(body.ConfigPath)
if configPath == "" {
configPath = strings.TrimSpace(cand.ConfigPath)
}
client, code, msg := resolveSingBoxApplyClient(clientID, "")
if !body.SkipRuntime {
if client == nil {
return http.StatusOK, SingBoxProfileRollbackResponse{
OK: false,
Code: code,
Message: msg,
ProfileID: cur.ID,
ProfileRevision: cur.ProfileRevision,
HistoryID: cand.ID,
}
}
if configPath == "" {
configPath = transportSingBoxConfigPath(*client)
}
}
if configPath == "" {
configPath = defaultSingBoxAppliedConfigPath(cur.ID)
}
prevData, prevExists, err := decodeHistoryPrevConfig(cand)
if err != nil {
return http.StatusInternalServerError, SingBoxProfileRollbackResponse{
OK: false,
Code: singBoxProfileCodeRollbackFailed,
Message: "decode rollback snapshot failed: " + err.Error(),
ProfileID: cur.ID,
ProfileRevision: cur.ProfileRevision,
HistoryID: cand.ID,
ClientID: clientID,
ConfigPath: configPath,
}
}
currentData, currentExists, _ := transportcfgpkg.ReadFileOptional(configPath)
if err := transportcfgpkg.RestoreFileOptional(configPath, prevData, prevExists); err != nil {
return http.StatusInternalServerError, SingBoxProfileRollbackResponse{
OK: false,
Code: singBoxProfileCodeRollbackFailed,
Message: "restore config failed: " + err.Error(),
ProfileID: cur.ID,
ProfileRevision: cur.ProfileRevision,
HistoryID: cand.ID,
ClientID: clientID,
ConfigPath: configPath,
}
}
return executeTransportSingBoxProfileRollbackRestoredLocked(
st,
idx,
cur,
body,
cand,
clientID,
configPath,
client,
currentData,
currentExists,
restart,
)
}