130 lines
4.2 KiB
Go
130 lines
4.2 KiB
Go
package rules
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// UnmarshalRule unmarshals a rule from JSON based on its structure
|
|
func UnmarshalRule(data []byte) (Rule, error) {
|
|
// Unmarshal to map to check for key presence
|
|
var ruleMap map[string]any
|
|
if err := json.Unmarshal(data, &ruleMap); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal rule: %w", err)
|
|
}
|
|
|
|
// Determine rule type based on presence of keys
|
|
if _, hasAnd := ruleMap["and"]; hasAnd {
|
|
// AND rule - need to handle Rules field separately since it's an interface
|
|
andRulesRaw, ok := ruleMap["and"].([]any)
|
|
if !ok {
|
|
return nil, fmt.Errorf("and rule: children must be an array")
|
|
}
|
|
andRule := AndRule{
|
|
Rules: make([]Rule, len(andRulesRaw)),
|
|
}
|
|
// Recursively unmarshal child rules
|
|
for i, childRaw := range andRulesRaw {
|
|
childBytes, err := json.Marshal(childRaw)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal child rule %d: %w", i, err)
|
|
}
|
|
childRule, err := UnmarshalRule(childBytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal child rule %d: %w", i, err)
|
|
}
|
|
andRule.Rules[i] = childRule
|
|
}
|
|
// Unmarshal archivers separately (JSON key is still "extractors" for backward compatibility)
|
|
if extractorsRaw, ok := ruleMap["extractors"]; ok {
|
|
extractorsBytes, err := json.Marshal(extractorsRaw)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal archivers: %w", err)
|
|
}
|
|
if err := json.Unmarshal(extractorsBytes, &andRule.Archivers); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal archivers: %w", err)
|
|
}
|
|
}
|
|
return &andRule, nil
|
|
}
|
|
|
|
if _, hasOr := ruleMap["or"]; hasOr {
|
|
// OR rule - need to handle Rules field separately since it's an interface
|
|
orRulesRaw, ok := ruleMap["or"].([]any)
|
|
if !ok {
|
|
return nil, fmt.Errorf("or rule: children must be an array")
|
|
}
|
|
orRule := OrRule{
|
|
Rules: make([]Rule, len(orRulesRaw)),
|
|
}
|
|
// Recursively unmarshal child rules
|
|
for i, childRaw := range orRulesRaw {
|
|
childBytes, err := json.Marshal(childRaw)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal child rule %d: %w", i, err)
|
|
}
|
|
childRule, err := UnmarshalRule(childBytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal child rule %d: %w", i, err)
|
|
}
|
|
orRule.Rules[i] = childRule
|
|
}
|
|
// Unmarshal archivers separately (JSON key is still "extractors" for backward compatibility)
|
|
if extractorsRaw, ok := ruleMap["extractors"]; ok {
|
|
extractorsBytes, err := json.Marshal(extractorsRaw)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal archivers: %w", err)
|
|
}
|
|
if err := json.Unmarshal(extractorsBytes, &orRule.Archivers); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal archivers: %w", err)
|
|
}
|
|
}
|
|
return &orRule, nil
|
|
}
|
|
|
|
if _, hasMimetype := ruleMap["mimetype"]; hasMimetype {
|
|
// Mimetype rule
|
|
var mimetypeRule MimetypeRule
|
|
if err := json.Unmarshal(data, &mimetypeRule); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal mimetype rule: %w", err)
|
|
}
|
|
return &mimetypeRule, nil
|
|
}
|
|
|
|
if _, hasHostname := ruleMap["hostname"]; hasHostname {
|
|
// Hostname rule
|
|
var hostnameRule HostnameRule
|
|
if err := json.Unmarshal(data, &hostnameRule); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal hostname rule: %w", err)
|
|
}
|
|
return &hostnameRule, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("unable to determine rule type: must have one of 'and', 'or', 'mimetype', or 'hostname' field")
|
|
}
|
|
|
|
// UnmarshalRuleConfig unmarshals a RuleConfig from JSON
|
|
func UnmarshalRuleConfig(data []byte) (*RuleConfig, error) {
|
|
var config struct {
|
|
Rules []json.RawMessage `json:"rules"`
|
|
DefaultExtractors []ArchiverConfig `json:"default_extractors,omitempty"` // JSON key kept for backward compatibility
|
|
}
|
|
|
|
if err := json.Unmarshal(data, &config); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal rule config: %w", err)
|
|
}
|
|
|
|
rules := make([]Rule, len(config.Rules))
|
|
for i, ruleData := range config.Rules {
|
|
rule, err := UnmarshalRule(ruleData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal rule %d: %w", i, err)
|
|
}
|
|
rules[i] = rule
|
|
}
|
|
|
|
return &RuleConfig{
|
|
Rules: rules,
|
|
DefaultArchivers: config.DefaultExtractors,
|
|
}, nil
|
|
}
|