package client import ( "encoding/json" "fmt" "io" "kon/auth" "kon/banner" "kon/client/state" "kon/config" "kon/constants" "kon/pon/paths/status" "kon/utils" "net/http" "net/url" "sort" "time" "github.com/fatih/color" ) func Status() { for host := range config.Config.Hosts { state.State.Mutex.Lock() state.State.Machines[host] = state.Machine{ State: state.Working, JobStart: time.Now(), } state.State.Mutex.Unlock() go StatusThread(host) } DisplayState() } func StatusThread(host string) { base, err := url.Parse("http://" + config.Config.Hosts[host] + constants.HostEndpoint) utils.CheckError(err) base.Path += "status" params := url.Values{} params.Add("token", auth.CreateToken()) base.RawQuery = params.Encode() resp, err := http.Get(base.String()) if utils.JobFailed(err, host) { return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if utils.JobFailed(err, host) { return } var status status.Status err = json.Unmarshal(body, &status) if utils.JobFailed(err, host) { return } state.State.Mutex.Lock() state.State.Machines[host] = state.Machine{ State: state.Completed, JobStart: state.State.Machines[host].JobStart, JobEnd: time.Now(), Message: fmt.Sprintf("[RAM: %0.2f%%] [Uptime: %s]", float64(status.MemUsed)/float64(status.MemTotal)*100.0, time.Duration(float64(status.Uptime)*float64(time.Second))), } state.State.Mutex.Unlock() } func Command(command string) { for host := range config.Config.Hosts { state.State.Mutex.Lock() state.State.Machines[host] = state.Machine{ State: state.Working, JobStart: time.Now(), } state.State.Mutex.Unlock() go CommandThread(host, command) } DisplayState() } func CommandThread(host string, command string) { base, err := url.Parse("http://" + config.Config.Hosts[host] + constants.HostEndpoint) utils.CheckError(err) base.Path += "command" params := url.Values{} params.Add("token", auth.CreateToken()) params.Add("command", command) base.RawQuery = params.Encode() client := http.Client{ Timeout: config.Config.CommandTimeout, } resp, err := client.Get(base.String()) if utils.JobFailed(err, host) { return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if utils.JobFailed(err, host) { return } state.State.Mutex.Lock() state.State.Machines[host] = state.Machine{ State: state.Completed, JobStart: state.State.Machines[host].JobStart, JobEnd: time.Now(), Message: string(body), } state.State.Mutex.Unlock() } func DisplayState() { finished := false for !finished { finished = true currentString := banner.FormatBanner() + "\n\n" state.State.Mutex.RLock() keys := make([]string, 0, len(state.State.Machines)) for key := range state.State.Machines { keys = append(keys, key) } sort.Strings(keys) for _, host := range keys { line := "" switch state.State.Machines[host].State { case state.Working: finished = false d := color.New(color.FgHiYellow, color.Bold) line = d.Sprintf(" - [✸] %-15s %15s\n", host, time.Since(state.State.Machines[host].JobStart)) case state.Error: d := color.New(color.FgHiRed, color.Bold) line = d.Sprintf(" - [✗] %-15s %15s %s\n", host, state.State.Machines[host].JobEnd.Sub(state.State.Machines[host].JobStart), state.State.Machines[host].Message) case state.Completed: d := color.New(color.FgHiGreen, color.Bold) line = d.Sprintf(" - [✔] %-15s %15s %s\n", host, state.State.Machines[host].JobEnd.Sub(state.State.Machines[host].JobStart), state.State.Machines[host].Message) } currentString += line } state.State.Mutex.RUnlock() print("\033[H\033[2J") println(currentString) } println("") }