2023-05-03 20:03:22 +02:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2023-09-03 12:13:18 +02:00
|
|
|
"bufio"
|
2023-05-03 20:03:22 +02:00
|
|
|
"encoding/gob"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
2023-05-04 01:01:22 +02:00
|
|
|
"net"
|
2023-05-03 20:03:22 +02:00
|
|
|
"os"
|
2023-09-03 12:13:18 +02:00
|
|
|
"regexp"
|
2023-09-24 16:01:56 +02:00
|
|
|
|
|
|
|
"gopkg.in/yaml.v3"
|
2023-05-03 20:03:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-09-24 16:01:56 +02:00
|
|
|
Show = 0
|
2023-05-03 20:03:22 +02:00
|
|
|
Flush = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
type Request struct {
|
|
|
|
Request int
|
|
|
|
Pattern string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Response struct {
|
2023-10-04 12:00:00 +02:00
|
|
|
Err error
|
|
|
|
ClientStatus ClientStatus
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
|
|
|
|
2023-05-04 01:01:22 +02:00
|
|
|
func SendAndRetrieve(data Request) Response {
|
2023-09-03 12:13:18 +02:00
|
|
|
conn, err := net.Dial("unix", *SocketPath)
|
2023-05-03 20:03:22 +02:00
|
|
|
if err != nil {
|
2023-05-04 01:01:22 +02:00
|
|
|
log.Fatalln("Error opening connection top daemon:", err)
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
2023-09-24 16:01:56 +02:00
|
|
|
defer conn.Close()
|
2023-05-04 01:01:22 +02:00
|
|
|
|
|
|
|
err = gob.NewEncoder(conn).Encode(data)
|
2023-05-03 20:03:22 +02:00
|
|
|
if err != nil {
|
2023-05-04 01:01:22 +02:00
|
|
|
log.Fatalln("Can't send message:", err)
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
|
|
|
|
2023-05-04 01:01:22 +02:00
|
|
|
var response Response
|
|
|
|
err = gob.NewDecoder(conn).Decode(&response)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Invalid answer from daemon:", err)
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
2023-05-04 01:01:22 +02:00
|
|
|
return response
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
|
|
|
|
2023-09-24 16:01:56 +02:00
|
|
|
type PatternStatus struct {
|
2023-10-04 12:00:00 +02:00
|
|
|
Matches int `yaml:"matches"`
|
|
|
|
Actions map[string][]string `yaml:"actions"`
|
2023-09-24 16:01:56 +02:00
|
|
|
}
|
|
|
|
type MapPatternStatus map[string]*PatternStatus
|
2023-10-04 12:00:00 +02:00
|
|
|
type MapPatternStatusFlush MapPatternStatus
|
|
|
|
|
2023-09-24 16:01:56 +02:00
|
|
|
type ClientStatus map[string]map[string]MapPatternStatus
|
2023-10-04 12:00:00 +02:00
|
|
|
type ClientStatusFlush ClientStatus
|
2023-09-24 16:01:56 +02:00
|
|
|
|
|
|
|
// This block is made to hide pending_actions when empty
|
|
|
|
// and matches_since_last_trigger when zero
|
|
|
|
type FullPatternStatus PatternStatus
|
|
|
|
type MatchesStatus struct {
|
2023-10-04 12:00:00 +02:00
|
|
|
Matches int `yaml:"matches"`
|
2023-09-24 16:01:56 +02:00
|
|
|
}
|
|
|
|
type ActionsStatus struct {
|
2023-10-04 12:00:00 +02:00
|
|
|
Actions map[string][]string `yaml:"actions"`
|
2023-09-24 16:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (mps MapPatternStatus) MarshalYAML() (interface{}, error) {
|
|
|
|
ret := make(map[string]interface{})
|
|
|
|
for k, v := range mps {
|
|
|
|
if v.Matches == 0 {
|
|
|
|
if len(v.Actions) != 0 {
|
|
|
|
ret[k] = ActionsStatus{v.Actions}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if len(v.Actions) != 0 {
|
|
|
|
ret[k] = v
|
|
|
|
} else {
|
|
|
|
ret[k] = MatchesStatus{v.Matches}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
2023-10-04 12:00:00 +02:00
|
|
|
func (mps MapPatternStatusFlush) MarshalYAML() (interface{}, error) {
|
|
|
|
var ret interface{}
|
|
|
|
for _, v := range mps {
|
|
|
|
if v.Matches == 0 {
|
|
|
|
if len(v.Actions) != 0 {
|
|
|
|
ret = ActionsStatus{v.Actions}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if len(v.Actions) != 0 {
|
|
|
|
ret = v
|
|
|
|
} else {
|
|
|
|
ret = MatchesStatus{v.Matches}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (csf ClientStatusFlush) MarshalYAML() (interface{}, error) {
|
|
|
|
ret := make(map[string]map[string]MapPatternStatusFlush)
|
|
|
|
for k, v := range csf {
|
|
|
|
ret[k] = make(map[string]MapPatternStatusFlush)
|
|
|
|
for kk, vv := range v {
|
|
|
|
ret[k][kk] = MapPatternStatusFlush(vv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
2023-09-24 16:01:56 +02:00
|
|
|
// end block
|
|
|
|
|
2023-05-03 20:03:22 +02:00
|
|
|
func usage(err string) {
|
|
|
|
fmt.Println("Usage: reactionc")
|
|
|
|
fmt.Println("Usage: reactionc flush <PATTERN>")
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
|
2023-09-24 16:01:56 +02:00
|
|
|
func ClientShow(streamfilter string) {
|
|
|
|
response := SendAndRetrieve(Request{Show, streamfilter})
|
2023-09-03 12:13:18 +02:00
|
|
|
if response.Err != nil {
|
|
|
|
log.Fatalln("Received error from daemon:", response.Err)
|
|
|
|
os.Exit(1)
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
2023-09-24 16:01:56 +02:00
|
|
|
text, err := yaml.Marshal(response.ClientStatus)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed to convert daemon binary response to text format:", err)
|
|
|
|
}
|
|
|
|
fmt.Println(string(text))
|
2023-09-03 12:13:18 +02:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ClientFlush(pattern, streamfilter string) {
|
|
|
|
response := SendAndRetrieve(Request{Flush, pattern})
|
|
|
|
if response.Err != nil {
|
|
|
|
log.Fatalln("Received error from daemon:", response.Err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2023-10-04 12:00:00 +02:00
|
|
|
text, err := yaml.Marshal(ClientStatusFlush(response.ClientStatus))
|
2023-10-01 12:00:00 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalln("Failed to convert daemon binary response to text format:", err)
|
|
|
|
}
|
|
|
|
fmt.Println(string(text))
|
2023-09-03 12:13:18 +02:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Match(reg *regexp.Regexp, line string) {
|
|
|
|
if reg.MatchString(line) {
|
|
|
|
fmt.Printf("\033[32mmatching\033[0m: %v\n", line)
|
|
|
|
} else {
|
|
|
|
fmt.Printf("\033[31mno match\033[0m: %v\n", line)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func MatchStdin(reg *regexp.Regexp) {
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
for scanner.Scan() {
|
|
|
|
Match(reg, scanner.Text())
|
2023-05-03 20:03:22 +02:00
|
|
|
}
|
|
|
|
}
|