Files
rulekit/internal/parser/singbox_srs.go
NeoMody 9907e8010f Phase 1: model, parsers, parse/list CLI commands
- 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
2026-04-01 10:00:21 +08:00

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
}