1
0

Code was restructurised again. Moved out back to root dir.

Ditched JSON configuration file. Replaced with simple key = value format. Added indented_output option to format output with indent.
This commit is contained in:
Alexander Andreev 2022-01-02 21:30:56 +04:00
parent b1c3066d4c
commit c7fe073623
Signed by: Arav
GPG Key ID: 1327FE8A374CC86F
7 changed files with 127 additions and 91 deletions

108
confguration.go Normal file
View File

@ -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
}

View File

@ -1,4 +1,4 @@
package prog package main
import "errors" import "errors"

10
main.go
View File

@ -3,7 +3,6 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
. "httpprocwatchd/prog"
"log" "log"
"os" "os"
"os/signal" "os/signal"
@ -36,8 +35,9 @@ func main() {
log.SetFlags(0) log.SetFlags(0)
flag.StringVar(&oConfigPath, "config", "config.json", "path to configuration file") flag.StringVar(&oConfigPath, "config", "config.conf", "path to configuration file")
flag.StringVar(&oConfigPath, "c", "config.json", "path to configuration file (shorthand)") flag.StringVar(&oConfigPath, "c", "config.conf", "path to configuration file (shorthand)")
flag.BoolVar(&oShowVersion, "version", false, "show version") flag.BoolVar(&oShowVersion, "version", false, "show version")
flag.BoolVar(&oShowVersion, "v", false, "show version (shorthand)") flag.BoolVar(&oShowVersion, "v", false, "show version (shorthand)")
@ -68,14 +68,14 @@ func main() {
} }
if oAddProcess != "" { if oAddProcess != "" {
err := AddProcessToList(oAddProcess, conf, oConfigPath) err := conf.AddProcessToList(oAddProcess, oConfigPath)
if err != nil { if err != nil {
log.Fatalf("Cannot add process: %s\n", err) log.Fatalf("Cannot add process: %s\n", err)
} }
} }
if oRemoveProcess != "" { if oRemoveProcess != "" {
err := RemoveProcessFromList(oRemoveProcess, conf, oConfigPath) err := conf.RemoveProcessFromList(oRemoveProcess, oConfigPath)
if err != nil { if err != nil {
log.Fatalf("Cannot remove process: %s\n", err) log.Fatalf("Cannot remove process: %s\n", err)
} }

View File

@ -1,4 +1,4 @@
package prog package main
import ( import (
"encoding/xml" "encoding/xml"

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package prog package main
import ( import (
"context" "context"
@ -11,7 +11,7 @@ import (
func CreateAndStartHTTPServer(conf *Configuration) *http.Server { func CreateAndStartHTTPServer(conf *Configuration) *http.Server {
router := http.NewServeMux() router := http.NewServeMux()
router.HandleFunc("/processes", AreProcessesUp(&conf.Processes)) router.HandleFunc("/processes", AreProcessesUp(&conf.Processes, conf.IndentedOutput))
srv := &http.Server{ srv := &http.Server{
Addr: conf.ListenAddress, Addr: conf.ListenAddress,
@ -42,7 +42,7 @@ func ShutdownHTTPServer(srv *http.Server) {
// AreProcessesUp handles a GET /processes request and sends back status of given // AreProcessesUp handles a GET /processes request and sends back status of given
// processes. // 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) { return func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet { if r.Method == http.MethodGet {
proclist := NewProcessList() proclist := NewProcessList()
@ -55,12 +55,16 @@ func AreProcessesUp(processes *[]string) func(http.ResponseWriter, *http.Request
if hdr := r.Header.Get("Accept"); hdr == "application/xml" { if hdr := r.Header.Get("Accept"); hdr == "application/xml" {
w.Header().Add("Content-Type", "application/xml") w.Header().Add("Content-Type", "application/xml")
enc := xml.NewEncoder(w) enc := xml.NewEncoder(w)
enc.Indent("", "\t") if indented {
enc.Indent("", "\t")
}
enc.Encode(proclist) enc.Encode(proclist)
} else { } else {
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
enc.SetIndent("", "\t") if indented {
enc.SetIndent("", "\t")
}
enc.Encode(proclist) enc.Encode(proclist)
} }
} else { } else {

View File

@ -1,9 +1,10 @@
package prog package main
import ( import (
"io/ioutil" "io/ioutil"
"os" "os"
"strconv" "strconv"
"strings"
) )
func GetProcessPIDs(name string) ([]int, error) { func GetProcessPIDs(name string) ([]int, error) {
@ -22,7 +23,7 @@ func GetProcessPIDs(name string) ([]int, error) {
return nil, err return nil, err
} }
if name == string(f[:len(f)-1]) { if strings.Contains(string(f[:len(f)-1]), name) {
pids = append(pids, pid) pids = append(pids, pid)
} }
} }