package virtbuf // mostly just functions related to making STDOUT // more readable by us humans // also function shortcuts the do fixed limited formatting (it's like COBOL) // so reporting tables of the status of what droplets and hypervisors // are in text columns and rows that can be easily read in a terminal import ( "errors" "fmt" "net/http" "strings" "time" "google.golang.org/protobuf/types/known/timestamppb" "go.wit.com/log" ) func oldGetDurationStamp(t time.Time) string { // Get the current time currentTime := time.Now() // Calculate the duration between t current time duration := currentTime.Sub(t) return FormatDuration(duration) } // This isn't for the marketing department // so this isn't going to use 'MiB' and 'GiB' func HumanFormatBytes(b int64) string { if b < 2000 { return fmt.Sprintf("%d B", b) } kb := int(b / 1024) if kb < 2000 { return fmt.Sprintf("%d KB", kb) } mb := int(b / (1024 * 1024)) if mb < 2000 { return fmt.Sprintf("%d MB", mb) } gb := int(b / (1024 * 1024 * 1024)) if gb < 2000 { return fmt.Sprintf("%d GB", gb) } tb := int(b / (1024 * 1024 * 1024 * 1024)) return fmt.Sprintf("%d TB", tb) } func FormatDuration(d time.Duration) string { result := "" // check if it's more than a year years := int(d.Hours()) / (24 * 365) if years > 0 { result += fmt.Sprintf("%dy", years) return result } // check if it's more than a day days := int(d.Hours()) / 24 if days > 0 { result += fmt.Sprintf("%dd", days) return result } // check if it's more than an hour hours := int(d.Hours()) % 24 if hours > 0 { result += fmt.Sprintf("%dh", hours) return result } // check if it's more than a minute minutes := int(d.Minutes()) % 60 if minutes > 0 { result += fmt.Sprintf("%dm", minutes) return result } // check if it's more than a second seconds := int(d.Seconds()) % 60 if seconds > 0 { result += fmt.Sprintf("%ds", seconds) return result } // report in milliseconds ms := int(d.Milliseconds()) if ms > 100 { // todo: print .3s, etc ? return fmt.Sprintf("%1.2fs", seconds/1000) } if ms > 0 { result += fmt.Sprintf("%dms", ms) } // totally not necessary but wth var t time.Duration t = time.Duration(ms) * time.Millisecond nanos := d - t result += fmt.Sprintf("%dnanos", nanos) return result } func (d *Droplet) SprintHeader() string { if d.Current == nil { d.Current = new(Current) } header := fmt.Sprintf("%-3.3s %-9.9s %-20.20s", d.Current.State, d.Current.Hypervisor, d.Hostname) switch d.Current.State { case DropletState_ON: var dur string if d.Current.OnSince != nil { dur = "" } else { t := time.Since(d.Current.OnSince.AsTime()) // time since 'OFF' dur = FormatDuration(t) } header += fmt.Sprintf(" (on :%3s)", dur) case DropletState_OFF: var dur string if d.Current.OffSince != nil { dur = "" } else { t := time.Since(d.Current.OffSince.AsTime()) // time since 'OFF' dur = FormatDuration(t) } header += fmt.Sprintf(" (off:%3s)", dur) default: header += fmt.Sprintf(" (?? :%3s)", "") } return header } func (d *Droplet) SprintDumpHeader() string { var macs []string for _, n := range d.Networks { macs = append(macs, n.Mac) } header := fmt.Sprintf("%-4.4s%20s %-8s", d.Current.State, strings.Join(macs, " "), d.Current.Hypervisor) if d.Current == nil { return header } if d.Current.OnSince == nil { d.Current.OnSince = timestamppb.New(time.Now()) } t := time.Since(d.Current.OnSince.AsTime()) // time since 'ON' dur := FormatDuration(t) switch d.Current.State { case DropletState_ON: header += fmt.Sprintf(" (on :%3s)", dur) case DropletState_OFF: header += fmt.Sprintf(" (off:%3s)", dur) default: header += fmt.Sprintf(" (?? :%3s)", dur) } return header } func (d *Droplet) DumpDroplet(w http.ResponseWriter, r *http.Request) (string, error) { if d == nil { reason := "DumpDroplet() got d == nil" log.Warn(reason) fmt.Fprintln(w, reason) return "", errors.New(reason) } t := d.FormatTEXT() log.Info(t) fmt.Fprintln(w, t) return t, nil } func (c *Cluster) DumpDroplet(w http.ResponseWriter, r *http.Request) (string, error) { hostname := r.URL.Query().Get("hostname") d := c.FindDropletByName(hostname) if d == nil { result := "can not find droplet hostname=" + hostname log.Info(result) fmt.Fprintln(w, result) return result, errors.New(result) } return d.DumpDroplet(w, r) }