- Core model: Rule, RuleSet, MergedRuleSet types with normalization - 5 parsers: Clash YAML, Clash list, Clash text, sing-box JSON, sing-box SRS - CLI: parse (display rules from any format), list (show all sources) - Supports blackmatrix7, lm-firefly, acl4ssr, loyalsoldier, sagernet, metacubex
51 lines
1.1 KiB
Go
51 lines
1.1 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"rulekit/internal/model"
|
|
"strings"
|
|
)
|
|
|
|
type SingboxSRSParser struct {
|
|
SingBoxBin string // defaults to "sing-box"
|
|
}
|
|
|
|
func (p *SingboxSRSParser) CanParse(filePath string) bool {
|
|
return strings.ToLower(filepath.Ext(filePath)) == ".srs"
|
|
}
|
|
|
|
func (p *SingboxSRSParser) Parse(filePath string) (*model.RuleSet, error) {
|
|
bin := p.SingBoxBin
|
|
if bin == "" {
|
|
bin = "sing-box"
|
|
}
|
|
|
|
cmd := exec.Command(bin, "rule-set", "decompile", filePath)
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
return nil, fmt.Errorf("sing-box decompile %s: %s", filePath, string(exitErr.Stderr))
|
|
}
|
|
return nil, fmt.Errorf("sing-box decompile %s: %w", filePath, err)
|
|
}
|
|
|
|
if len(out) == 0 {
|
|
// Empty output, return empty ruleset
|
|
return &model.RuleSet{
|
|
Name: nameFromPath(filePath),
|
|
Source: sourceFromPath(filePath),
|
|
Format: "singbox-srs",
|
|
FilePath: filePath,
|
|
}, nil
|
|
}
|
|
|
|
rs, err := parseSingboxJSON(out, filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse decompiled JSON from %s: %w", filePath, err)
|
|
}
|
|
rs.Format = "singbox-srs"
|
|
return rs, nil
|
|
}
|