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

147 lines
3.7 KiB
Go

package app
import (
transportcfgpkg "selective-vpn-api/app/transportcfg"
"strings"
"time"
)
func createSingBoxProfileLocked(st *singBoxProfilesState, req SingBoxProfileCreateRequest) (SingBoxProfile, string, error) {
mode := SingBoxProfileModeTyped
if strings.TrimSpace(string(req.Mode)) != "" {
parsed, ok := normalizeSingBoxProfileMode(req.Mode)
if !ok {
return SingBoxProfile{}, singBoxProfileCodeBadMode, errSingBoxProfileMode()
}
mode = parsed
}
id := sanitizeID(req.ID)
if id == "" {
id = deriveSingBoxProfileID(req.Name, req.Protocol, st.Items)
}
if id == "" {
return SingBoxProfile{}, singBoxProfileCodeBadID, errSingBoxProfileID()
}
if findSingBoxProfileIndex(st.Items, id) >= 0 {
return SingBoxProfile{}, singBoxProfileCodeIDConflict, errSingBoxProfileExists()
}
enabled := true
if req.Enabled != nil {
enabled = *req.Enabled
}
now := time.Now().UTC().Format(time.RFC3339)
item := SingBoxProfile{
ID: id,
Name: strings.TrimSpace(req.Name),
Mode: mode,
Protocol: normalizeSingBoxProtocol(req.Protocol),
Enabled: enabled,
SchemaVersion: normalizeSingBoxSchemaVersion(req.SchemaVersion),
ProfileRevision: 1,
RenderRevision: 0,
Typed: cloneMapDeep(req.Typed),
RawConfig: cloneMapDeep(req.RawConfig),
Meta: cloneMapDeep(req.Meta),
CreatedAt: now,
UpdatedAt: now,
}
if item.Name == "" {
item.Name = id
}
secretRes, err := applySingBoxSecretsPatch(id, false, req.Secrets)
if err != nil {
return SingBoxProfile{}, singBoxProfileCodeSecretsFailed, err
}
item.HasSecrets = secretRes.HasSecrets
item.SecretsMasked = secretRes.Masked
st.Items = append(st.Items, item)
ensureSingBoxProfilesActiveID(st)
st.Revision++
return item, "", nil
}
func patchSingBoxProfile(cur SingBoxProfile, req SingBoxProfilePatchRequest) (SingBoxProfile, singBoxSecretsPatchResult, bool, string, error) {
next := cur
changed := false
now := time.Now().UTC().Format(time.RFC3339)
if req.Name != nil {
v := strings.TrimSpace(*req.Name)
if v == "" {
v = next.ID
}
if next.Name != v {
next.Name = v
changed = true
}
}
if req.Mode != nil {
mode, ok := normalizeSingBoxProfileMode(*req.Mode)
if !ok {
return cur, singBoxSecretsPatchResult{}, false, singBoxProfileCodeBadMode, errSingBoxProfileMode()
}
if next.Mode != mode {
next.Mode = mode
changed = true
}
}
if req.Protocol != nil {
v := normalizeSingBoxProtocol(*req.Protocol)
if next.Protocol != v {
next.Protocol = v
changed = true
}
}
if req.Enabled != nil && next.Enabled != *req.Enabled {
next.Enabled = *req.Enabled
changed = true
}
if req.SchemaVersion != nil {
v := normalizeSingBoxSchemaVersion(*req.SchemaVersion)
if next.SchemaVersion != v {
next.SchemaVersion = v
changed = true
}
}
if req.Typed != nil {
next.Typed = cloneMapDeep(req.Typed)
changed = true
}
if req.RawConfig != nil {
next.RawConfig = cloneMapDeep(req.RawConfig)
changed = true
}
if req.Meta != nil {
next.Meta = cloneMapDeep(req.Meta)
changed = true
}
secretRes := singBoxSecretsPatchResult{
HasSecrets: next.HasSecrets,
Masked: transportcfgpkg.CloneStringMap(next.SecretsMasked),
}
if req.ClearSecrets || req.Secrets != nil {
var err error
secretRes, err = applySingBoxSecretsPatch(next.ID, req.ClearSecrets, req.Secrets)
if err != nil {
return cur, singBoxSecretsPatchResult{}, false, singBoxProfileCodeSecretsFailed, err
}
next.HasSecrets = secretRes.HasSecrets
next.SecretsMasked = secretRes.Masked
if secretRes.Changed {
changed = true
}
}
if !changed {
return cur, secretRes, false, "", nil
}
next.ProfileRevision = cur.ProfileRevision + 1
next.UpdatedAt = now
return next, secretRes, true, "", nil
}