diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-13 07:48:40 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-13 07:48:40 +0200 |
| commit | c88dddee1953c938b47830ec13696f23770eb22d (patch) | |
| tree | 35cca5c6bab8c62bf2bc18895764ff9a0bc84741 /internal/session | |
| parent | 2a665812a0c224ef32d37b2cca681512c5b7d6c1 (diff) | |
task 400: add server session command scaffolding
Diffstat (limited to 'internal/session')
| -rw-r--r-- | internal/session/spec.go | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/internal/session/spec.go b/internal/session/spec.go new file mode 100644 index 0000000..2d1b77d --- /dev/null +++ b/internal/session/spec.go @@ -0,0 +1,124 @@ +package session + +import ( + "fmt" + "strings" + + "github.com/mimecast/dtail/internal/config" + "github.com/mimecast/dtail/internal/omode" + "github.com/mimecast/dtail/internal/regex" +) + +// Spec captures the mutable, per-connection workload a DTail client wants to run. +type Spec struct { + Mode omode.Mode `json:"mode"` + Files []string `json:"files"` + Options string `json:"options,omitempty"` + Query string `json:"query,omitempty"` + Regex string `json:"regex,omitempty"` + RegexInvert bool `json:"regex_invert,omitempty"` + Timeout int `json:"timeout,omitempty"` +} + +// NewSpec returns a session specification from client args. +func NewSpec(args config.Args) Spec { + return Spec{ + Mode: args.Mode, + Files: splitFiles(args.What), + Options: args.SerializeOptions(), + Query: strings.TrimSpace(args.QueryStr), + Regex: args.RegexStr, + RegexInvert: args.RegexInvert, + Timeout: args.Timeout, + } +} + +// Commands returns the legacy command stream for this session specification. +func (s Spec) Commands() ([]string, error) { + switch { + case s.Mode == omode.HealthClient: + return []string{"health"}, nil + case s.Query != "": + return s.queryCommands() + default: + return s.readCommands(s.Mode.String()) + } +} + +func (s Spec) queryCommands() ([]string, error) { + if s.Mode != omode.MapClient && s.Mode != omode.TailClient { + return nil, fmt.Errorf("session spec query mode requires map or tail mode, got %s", s.Mode) + } + + regexValue, err := s.serializedRegex() + if err != nil { + return nil, err + } + + commands := []string{fmt.Sprintf("map:%s %s", s.Options, s.Query)} + readMode := "cat" + if s.Mode == omode.TailClient { + readMode = "tail" + } + + for _, file := range s.Files { + if s.Timeout > 0 { + commands = append(commands, fmt.Sprintf("timeout %d %s %s %s", s.Timeout, readMode, file, regexValue)) + continue + } + commands = append(commands, fmt.Sprintf("%s:%s %s %s", readMode, s.Options, file, regexValue)) + } + + return commands, nil +} + +func (s Spec) readCommands(mode string) ([]string, error) { + switch s.Mode { + case omode.TailClient, omode.CatClient, omode.GrepClient: + default: + return nil, fmt.Errorf("unsupported session mode %s", s.Mode) + } + + regexValue, err := s.serializedRegex() + if err != nil { + return nil, err + } + + var commands []string + for _, file := range s.Files { + commands = append(commands, fmt.Sprintf("%s:%s %s %s", mode, s.Options, file, regexValue)) + } + + return commands, nil +} + +func (s Spec) serializedRegex() (string, error) { + flag := regex.Default + if s.RegexInvert { + flag = regex.Invert + } + + re, err := regex.New(s.Regex, flag) + if err != nil { + return "", err + } + + return re.Serialize() +} + +func splitFiles(what string) []string { + if strings.TrimSpace(what) == "" { + return nil + } + + rawFiles := strings.Split(what, ",") + files := make([]string, 0, len(rawFiles)) + for _, file := range rawFiles { + file = strings.TrimSpace(file) + if file == "" { + continue + } + files = append(files, file) + } + return files +} |
