platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func appMarksDel(target string, cgroup string) error {
|
||||
target = strings.ToLower(strings.TrimSpace(target))
|
||||
if target != "vpn" && target != "direct" {
|
||||
return fmt.Errorf("invalid target")
|
||||
}
|
||||
cgroup = strings.TrimSpace(cgroup)
|
||||
if cgroup == "" {
|
||||
return fmt.Errorf("empty cgroup")
|
||||
}
|
||||
|
||||
appMarksMu.Lock()
|
||||
defer appMarksMu.Unlock()
|
||||
|
||||
st := loadAppMarksState()
|
||||
changed := pruneExpiredAppMarksLocked(&st, time.Now().UTC())
|
||||
|
||||
var id uint64
|
||||
var cgAbs string
|
||||
|
||||
if isAllDigits(cgroup) {
|
||||
v, err := strconv.ParseUint(cgroup, 10, 64)
|
||||
if err == nil {
|
||||
id = v
|
||||
}
|
||||
} else {
|
||||
rel := normalizeCgroupRelOnly(cgroup)
|
||||
if rel != "" {
|
||||
cgAbs = "/" + rel
|
||||
// Try to resolve inode id if directory still exists.
|
||||
if inode, err := cgroupDirInode(rel); err == nil {
|
||||
id = inode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to state lookup by cgroup string.
|
||||
idx := -1
|
||||
for i, it := range st.Items {
|
||||
if strings.ToLower(strings.TrimSpace(it.Target)) != target {
|
||||
continue
|
||||
}
|
||||
if id != 0 && it.ID == id {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
if id == 0 && cgAbs != "" && strings.TrimSpace(it.Cgroup) == cgAbs {
|
||||
id = it.ID
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if id != 0 {
|
||||
_ = nftDeleteAppMarkRule(target, id)
|
||||
}
|
||||
if idx >= 0 {
|
||||
st.Items = append(st.Items[:idx], st.Items[idx+1:]...)
|
||||
changed = true
|
||||
}
|
||||
|
||||
if changed {
|
||||
return saveAppMarksState(st)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user