platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
146
selective-vpn-api/app/transport_singbox_profiles_mutate.go
Normal file
146
selective-vpn-api/app/transport_singbox_profiles_mutate.go
Normal file
@@ -0,0 +1,146 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user