125 lines
3.5 KiB
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,
|
|
)
|
|
}
|