diff --git a/confguration.go b/confguration.go new file mode 100644 index 0000000..b4486d1 --- /dev/null +++ b/confguration.go @@ -0,0 +1,108 @@ +package main + +import ( + "bufio" + "io/ioutil" + "log" + "os" + "strconv" + "strings" +) + +// Configuration holds a list of process names to be tracked and a listen address. +type Configuration struct { + ListenAddress string + IndentedOutput bool + Processes []string +} + +// LoadConfiguration loads configuration from a file. +func LoadConfiguration(path string) (conf *Configuration, err error) { + conf = &Configuration{} + + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + s := bufio.NewScanner(file) + s.Split(bufio.ScanLines) + + for s.Scan() { + kv := strings.Split(s.Text(), " = ") + switch kv[0] { + case "listen_address": + conf.ListenAddress = kv[1] + case "indented_output": + v, err := strconv.ParseBool(kv[1]) + if err != nil { + log.Printf("WARN: could not parse \"indented_output\", valid values are true or false. Defaulted to false.\n") + } + conf.IndentedOutput = v + case "processes": + if kv[1] != "" { + conf.Processes = strings.Split(kv[1], " ") + } else { + log.Printf("WARN: \"processes\" list is empty.\n") + conf.Processes = []string{} + } + } + } + + return conf, nil +} + +// StoreConfiguration writes Configuration into a file. +func (conf *Configuration) StoreConfiguration(path string) (err error) { + var config strings.Builder + + config.WriteString("listen_address = ") + config.WriteString(conf.ListenAddress) + config.WriteByte('\n') + config.WriteString("indented_output = ") + config.WriteString(strconv.FormatBool(conf.IndentedOutput)) + config.WriteByte('\n') + config.WriteString("processes = ") + config.WriteString(strings.Join(conf.Processes, " ")) + + if err := ioutil.WriteFile(path, []byte(config.String()), 0644); err != nil { + return err + } + + return nil +} + +// AddProcessToList appends a new given process into a configuration file. +func (conf *Configuration) AddProcessToList(process string, configPath string) error { + for _, v := range conf.Processes { + if v == process { + return ErrIsOnList + } + } + + conf.Processes = append(conf.Processes, process) + if err := conf.StoreConfiguration(configPath); err != nil { + return err + } + + return nil +} + +// RemoveProcessFromList removes a given process from a configuration file. +func (conf *Configuration) RemoveProcessFromList(process string, configPath string) error { + for k, v := range conf.Processes { + if v == process { + newlist := make([]string, len(conf.Processes)-1) + newlist = append(conf.Processes[:k], conf.Processes[k+1:]...) + conf.Processes = newlist + if err := conf.StoreConfiguration(configPath); err != nil { + return err + } + + return nil + } + } + + return ErrNotFound +} diff --git a/prog/errors.go b/errors.go similarity index 95% rename from prog/errors.go rename to errors.go index 3e32c8d..50bc8c4 100644 --- a/prog/errors.go +++ b/errors.go @@ -1,4 +1,4 @@ -package prog +package main import "errors" diff --git a/main.go b/main.go index c5977b7..a06cb17 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "flag" "fmt" - . "httpprocwatchd/prog" "log" "os" "os/signal" @@ -36,8 +35,9 @@ func main() { log.SetFlags(0) - flag.StringVar(&oConfigPath, "config", "config.json", "path to configuration file") - flag.StringVar(&oConfigPath, "c", "config.json", "path to configuration file (shorthand)") + flag.StringVar(&oConfigPath, "config", "config.conf", "path to configuration file") + flag.StringVar(&oConfigPath, "c", "config.conf", "path to configuration file (shorthand)") + flag.BoolVar(&oShowVersion, "version", false, "show version") flag.BoolVar(&oShowVersion, "v", false, "show version (shorthand)") @@ -68,14 +68,14 @@ func main() { } if oAddProcess != "" { - err := AddProcessToList(oAddProcess, conf, oConfigPath) + err := conf.AddProcessToList(oAddProcess, oConfigPath) if err != nil { log.Fatalf("Cannot add process: %s\n", err) } } if oRemoveProcess != "" { - err := RemoveProcessFromList(oRemoveProcess, conf, oConfigPath) + err := conf.RemoveProcessFromList(oRemoveProcess, oConfigPath) if err != nil { log.Fatalf("Cannot remove process: %s\n", err) } diff --git a/prog/processlist.go b/processlist.go similarity index 98% rename from prog/processlist.go rename to processlist.go index 14b2e6b..31f719a 100644 --- a/prog/processlist.go +++ b/processlist.go @@ -1,4 +1,4 @@ -package prog +package main import ( "encoding/xml" diff --git a/prog/confguration.go b/prog/confguration.go deleted file mode 100644 index a22434b..0000000 --- a/prog/confguration.go +++ /dev/null @@ -1,77 +0,0 @@ -package prog - -import ( - "encoding/json" - "io/ioutil" -) - -// Configuration holds a list of process names to be tracked and a listen address. -type Configuration struct { - ListenAddress string `json:"listen_address"` - Processes []string `json:"processes"` -} - -// LoadConfiguration loads configuration from a JSON file. -func LoadConfiguration(path string) (conf *Configuration, err error) { - conf = &Configuration{} - - file, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(file, conf); err != nil { - return nil, err - } - - return conf, nil -} - -// StoreConfiguration writes Configuration into a JSON file. -func StoreConfiguration(path string, conf *Configuration) (err error) { - config, err := json.Marshal(*conf) - if err != nil { - return err - } - - err = ioutil.WriteFile(path, config, 0644) - if err != nil { - return err - } - - return nil -} - -// AddProcessToList appends a new given process into a configuration file. -func AddProcessToList(process string, conf *Configuration, configPath string) error { - for _, v := range conf.Processes { - if v == process { - return ErrIsOnList - } - } - - conf.Processes = append(conf.Processes, process) - if err := StoreConfiguration(configPath, conf); err != nil { - return err - } - - return nil -} - -// RemoveProcessFromList removes a given process from a configuration file. -func RemoveProcessFromList(process string, conf *Configuration, configPath string) error { - for k, v := range conf.Processes { - if v == process { - newlist := make([]string, len(conf.Processes)-1) - newlist = append(conf.Processes[:k], conf.Processes[k+1:]...) - conf.Processes = newlist - if err := StoreConfiguration(configPath, conf); err != nil { - return err - } - - return nil - } - } - - return ErrNotFound -} diff --git a/prog/server.go b/server.go similarity index 83% rename from prog/server.go rename to server.go index 134673f..2d8fe8e 100644 --- a/prog/server.go +++ b/server.go @@ -1,4 +1,4 @@ -package prog +package main import ( "context" @@ -11,7 +11,7 @@ import ( func CreateAndStartHTTPServer(conf *Configuration) *http.Server { router := http.NewServeMux() - router.HandleFunc("/processes", AreProcessesUp(&conf.Processes)) + router.HandleFunc("/processes", AreProcessesUp(&conf.Processes, conf.IndentedOutput)) srv := &http.Server{ Addr: conf.ListenAddress, @@ -42,7 +42,7 @@ func ShutdownHTTPServer(srv *http.Server) { // AreProcessesUp handles a GET /processes request and sends back status of given // processes. -func AreProcessesUp(processes *[]string) func(http.ResponseWriter, *http.Request) { +func AreProcessesUp(processes *[]string, indented bool) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { proclist := NewProcessList() @@ -55,12 +55,16 @@ func AreProcessesUp(processes *[]string) func(http.ResponseWriter, *http.Request if hdr := r.Header.Get("Accept"); hdr == "application/xml" { w.Header().Add("Content-Type", "application/xml") enc := xml.NewEncoder(w) - enc.Indent("", "\t") + if indented { + enc.Indent("", "\t") + } enc.Encode(proclist) } else { w.Header().Add("Content-Type", "application/json") enc := json.NewEncoder(w) - enc.SetIndent("", "\t") + if indented { + enc.SetIndent("", "\t") + } enc.Encode(proclist) } } else { diff --git a/prog/util.go b/util.go similarity index 85% rename from prog/util.go rename to util.go index 3c41b26..b3dca68 100644 --- a/prog/util.go +++ b/util.go @@ -1,9 +1,10 @@ -package prog +package main import ( "io/ioutil" "os" "strconv" + "strings" ) func GetProcessPIDs(name string) ([]int, error) { @@ -22,7 +23,7 @@ func GetProcessPIDs(name string) ([]int, error) { return nil, err } - if name == string(f[:len(f)-1]) { + if strings.Contains(string(f[:len(f)-1]), name) { pids = append(pids, pid) } }