mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-25 01:10:30 +00:00
142 lines
3.1 KiB
Go
142 lines
3.1 KiB
Go
package oomkiller
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
)
|
|
|
|
func PromoteDraft(basePath string, accept func(metadataContent []byte) bool) {
|
|
draftPath := filepath.Join(basePath, DraftDirectoryName)
|
|
info, err := os.Stat(draftPath)
|
|
if err != nil || !info.IsDir() {
|
|
return
|
|
}
|
|
lockPath := filepath.Join(draftPath, lockFileName)
|
|
lock, err := lockDraft(lockPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
os.Remove(lockPath)
|
|
unlockDraft(lock)
|
|
if !draftNotable(draftPath) {
|
|
os.RemoveAll(draftPath)
|
|
return
|
|
}
|
|
if accept != nil {
|
|
metadataContent, readErr := os.ReadFile(filepath.Join(draftPath, metadataFileName))
|
|
if readErr != nil || !accept(metadataContent) {
|
|
os.RemoveAll(draftPath)
|
|
return
|
|
}
|
|
}
|
|
promoteDirectory(draftPath, filepath.Join(basePath, ReportsDirectoryName))
|
|
}
|
|
|
|
func draftNotable(draftPath string) bool {
|
|
file, err := os.Open(filepath.Join(draftPath, eventsFileName))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
defer file.Close()
|
|
scanner := bufio.NewScanner(file)
|
|
scanner.Buffer(nil, 1<<20)
|
|
for scanner.Scan() {
|
|
var event struct {
|
|
Type string `json:"t"`
|
|
}
|
|
err = json.Unmarshal(scanner.Bytes(), &event)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
switch event.Type {
|
|
case eventTypePressure, eventTypeReset, eventTypeSnapshot:
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func promoteDirectory(draftPath string, reportsPath string) {
|
|
info, err := os.Stat(draftPath)
|
|
if err != nil || !info.IsDir() {
|
|
return
|
|
}
|
|
err = os.MkdirAll(reportsPath, 0o777)
|
|
if err != nil {
|
|
return
|
|
}
|
|
destPath, err := nextAvailableReportPath(reportsPath, info.ModTime().UTC())
|
|
if err != nil {
|
|
os.RemoveAll(draftPath)
|
|
return
|
|
}
|
|
err = os.Rename(draftPath, destPath)
|
|
if err != nil {
|
|
os.RemoveAll(draftPath)
|
|
}
|
|
}
|
|
|
|
func nextAvailableReportPath(reportsDir string, timestamp time.Time) (string, error) {
|
|
destName := timestamp.Format("2006-01-02T15-04-05")
|
|
destPath := filepath.Join(reportsDir, destName)
|
|
_, err := os.Stat(destPath)
|
|
if os.IsNotExist(err) {
|
|
return destPath, nil
|
|
}
|
|
for i := 1; i <= 1000; i++ {
|
|
suffixedPath := filepath.Join(reportsDir, destName+"-"+strconv.Itoa(i))
|
|
_, err = os.Stat(suffixedPath)
|
|
if os.IsNotExist(err) {
|
|
return suffixedPath, nil
|
|
}
|
|
}
|
|
return "", E.New("no available report path for ", destName)
|
|
}
|
|
|
|
func copyDirectory(sourcePath string, destPath string) error {
|
|
entries, err := os.ReadDir(sourcePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = os.MkdirAll(destPath, 0o777)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, entry := range entries {
|
|
if entry.IsDir() || strings.HasPrefix(entry.Name(), ".") {
|
|
continue
|
|
}
|
|
err = copyFile(filepath.Join(sourcePath, entry.Name()), filepath.Join(destPath, entry.Name()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func copyFile(sourcePath string, destPath string) error {
|
|
source, err := os.Open(sourcePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer source.Close()
|
|
dest, err := os.OpenFile(destPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.Copy(dest, source)
|
|
if err != nil {
|
|
dest.Close()
|
|
return err
|
|
}
|
|
return dest.Close()
|
|
}
|