Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Atwood authored May 20, 2021
2 parents 2336fa6 + 45bb5e6 commit 08177b4
Show file tree
Hide file tree
Showing 3 changed files with 451 additions and 61 deletions.
47 changes: 47 additions & 0 deletions internal/activePlot.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -55,6 +56,52 @@ type ActivePlot struct {
process *os.Process
}

// getPhaseTime returns the end time of a phase. phase 0 is the start time
// of the entire plot, and phase 4 is the end time of the entire plot.
// TODO: We can change the ActivePlot structure to be PhaseTime [5]time.Time,
// but that's a protocol change.
func (ap *ActivePlot) getPhaseTime(phase int) time.Time {
switch phase {
case 0:
return ap.StartTime
case 1:
return ap.Phase1Time
case 2:
return ap.Phase2Time
case 3:
return ap.Phase3Time
case 4:
return ap.EndTime
default:
panic("request for invalid phase time")
}
}

// getCurrentPhase returns the current phase, or a negative number to indicate an error.
// TODO: We can also change this to be part of the structure, but that's also a protocol change.
func (ap *ActivePlot) getCurrentPhase() int {
parts := strings.Split(ap.Phase, "/")
if len(parts) != 2 {
return -1
} else if i, err := strconv.Atoi(parts[0]); err != nil {
return -2
} else {
return i
}
}

// getProgress returns the current progress, or a negative number to indicate an error
// TODO: We can also change this to be part of the structure, but that's also a protocol change.
func (ap *ActivePlot) getProgress() int {
if len(ap.Progress) == 0 {
return -1
} else if i, err := strconv.Atoi(ap.Progress[:len(ap.Progress)-1]); err != nil {
return -2
} else {
return i
}
}

func (ap *ActivePlot) Duration(currentTime time.Time) string {
return DurationString(currentTime.Sub(ap.StartTime))
}
Expand Down
203 changes: 142 additions & 61 deletions internal/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,23 @@ import (

"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"

"plotng/internal/widget"
)

type Client struct {
app *tview.Application
plotTable *tview.Table
activePlotsTable *widget.SortedTable
targetTable *tview.Table
tmpTable *tview.Table
lastTable *tview.Table
logTextbox *tview.TextView
hosts []string
msg map[string]*Msg
archivedTableActive bool
activeLogs map[int][]string
activeLogs map[string][]string
archivedLogs map[int][]string
logPlotId string
}

var httpClient = &http.Client{
Expand Down Expand Up @@ -58,6 +61,7 @@ func (client *Client) processLoop() {
}

func (client *Client) checkServers() {
client.activeLogs = make(map[string][]string)
for _, host := range client.hosts {
client.checkServer(host)
}
Expand All @@ -75,9 +79,6 @@ func (client *Client) getServerData(host string) (*Msg, error) {
decoder := gob.NewDecoder(resp.Body)
if err := decoder.Decode(&msg); err == nil {
msg := &msg
sort.Slice(msg.Actives, func(i, j int) bool {
return msg.Actives[i].PlotId < msg.Actives[j].PlotId
})
sort.Slice(msg.Archived, func(i, j int) bool {
return msg.Archived[i].PlotId > msg.Archived[j].PlotId
})
Expand Down Expand Up @@ -105,6 +106,10 @@ func (client *Client) checkServer(host string) {
client.drawTargetTable()
client.drawActivePlots()
client.drawArchivedPlots()
if log, ok := client.activeLogs[client.logPlotId]; ok {
client.logTextbox.SetText(strings.Join(log, ""))
client.logTextbox.ScrollToEnd()
}
})
}

Expand Down Expand Up @@ -173,10 +178,16 @@ func (client *Client) drawTargetTable() {

func (client *Client) setupUI() {
tview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault
client.plotTable = tview.NewTable()
client.plotTable.SetSelectable(true, false).SetBorder(true).SetTitleAlign(tview.AlignLeft).SetTitle("Active Plots")
client.plotTable.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse))
client.plotTable.SetSelectionChangedFunc(client.selectActivePlot).SetFixed(1, 6)
client.activePlotsTable = widget.NewSortedTable()
client.activePlotsTable.SetSelectable(true)
client.activePlotsTable.SetBorder(true)
client.activePlotsTable.SetTitleAlign(tview.AlignLeft)
client.activePlotsTable.SetTitle(" Active Plots ")
client.activePlotsTable.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse))
client.activePlotsTable.SetSelectionChangedFunc(client.selectActivePlot)
client.activePlotsTable.SetHeaders(activePlotsHeaders...)
client.activePlotsTable.SetColumnAlign(3, tview.AlignRight)
client.activePlotsTable.SetColumnAlign(4, tview.AlignRight)

client.tmpTable = tview.NewTable()
client.tmpTable.SetSelectable(true, false).SetBorder(true).SetTitleAlign(tview.AlignLeft).SetTitle("Plot Directories")
Expand Down Expand Up @@ -205,7 +216,7 @@ func (client *Client) setupUI() {

mainPanel := tview.NewFlex()
mainPanel.SetDirection(tview.FlexRow)
mainPanel.AddItem(client.plotTable, 0, 1, true)
mainPanel.AddItem(client.activePlotsTable, 0, 1, true)
mainPanel.AddItem(dirPanel, 0, 1, false)
mainPanel.AddItem(client.lastTable, 0, 1, false)
mainPanel.AddItem(client.logTextbox, 0, 1, false)
Expand All @@ -215,61 +226,124 @@ func (client *Client) setupUI() {
client.app.EnableMouse(true)
}

func (client *Client) shortenPlotId(id string) string {
func shortenPlotId(id string) string {
if len(id) < 20 {
return ""
}
return fmt.Sprintf("%s...%s", id[:10], id[len(id)-10:])
}

// Active plots

type activePlotsData struct {
host string
plotId string
status int
phase int
progress int
startTime time.Time
plotDir string
destDir string
}

var activePlotsHeaders = []string{
"Host",
"Plot ID",
"Status",
"Phase",
"Progress",
"Start Time",
"Duration",
"Plot Dir",
"Dest Dir",
}

func (apd *activePlotsData) Strings() []string {
status := "Unknown"
switch apd.status {
case PlotRunning:
status = "Running"
case PlotError:
status = "Errored"
case PlotFinished:
status = "Finished"
}
return []string{
apd.host,
shortenPlotId(apd.plotId),
status,
fmt.Sprintf("%d/4", apd.phase),
fmt.Sprintf("%d%%", apd.progress),
apd.startTime.Format("2006-01-02 15:04:05"),
DurationString(time.Now().Sub(apd.startTime)),
apd.plotDir,
apd.destDir,
}
}

func (apd *activePlotsData) LessThan(Other widget.SortableRow, column int) bool {
other := Other.(*activePlotsData)
switch column {
case 0:
return apd.host < other.host
case 1:
return apd.plotId < other.plotId
case 2:
return apd.status < other.status
case 3:
return apd.phase < other.phase
case 4:
return apd.progress < other.progress
case 5, 6:
return apd.startTime.Before(other.startTime)
case 7:
return apd.plotDir < other.plotDir
case 8:
return apd.destDir < other.destDir
default:
panic("unknown column")
}
}

func (client *Client) makeActivePlotsData(host string, p *ActivePlot) *activePlotsData {
apd := &activePlotsData{}
apd.host = host
apd.plotId = p.Id
apd.status = p.State
apd.phase = p.getCurrentPhase()
apd.progress = p.getProgress()
apd.startTime = p.getPhaseTime(0)
apd.plotDir = p.PlotDir
apd.destDir = p.TargetDir
return apd
}

func (client *Client) drawActivePlots() {
client.plotTable.Clear()
client.plotTable.SetCell(0, 0, tview.NewTableCell("Host"))
client.plotTable.SetCell(0, 1, tview.NewTableCell("Plot Id"))
client.plotTable.SetCell(0, 2, tview.NewTableCell("Status"))
client.plotTable.SetCell(0, 3, tview.NewTableCell("Phase"))
client.plotTable.SetCell(0, 4, tview.NewTableCell("Progress"))
client.plotTable.SetCell(0, 5, tview.NewTableCell("Start Time"))
client.plotTable.SetCell(0, 6, tview.NewTableCell("Duration"))
client.plotTable.SetCell(0, 7, tview.NewTableCell("Plot Dir"))
client.plotTable.SetCell(0, 8, tview.NewTableCell("Dest Dir"))

t := time.Now()
count := 0
client.activeLogs = map[int][]string{}
for _, host := range client.hosts {
msg, found := client.msg[host]
if !found {
continue
}
for _, plot := range msg.Actives {
state := "Unknown"
switch plot.State {
case PlotRunning:
state = "Running"
case PlotError:
state = "Errored"
case PlotFinished:
state = "Finished"
}
activePlotsCount := 0

client.plotTable.SetCell(count+1, 0, tview.NewTableCell(host))
client.plotTable.SetCell(count+1, 1, tview.NewTableCell(client.shortenPlotId(plot.Id)))
client.plotTable.SetCell(count+1, 2, tview.NewTableCell(state))
client.plotTable.SetCell(count+1, 3, tview.NewTableCell(plot.Phase).SetAlign(tview.AlignRight))
client.plotTable.SetCell(count+1, 4, tview.NewTableCell(plot.Progress).SetAlign(tview.AlignRight))
client.plotTable.SetCell(count+1, 5, tview.NewTableCell(plot.StartTime.Format("2006-01-02 15:04:05")))
client.plotTable.SetCell(count+1, 6, tview.NewTableCell(plot.Duration(t)))
client.plotTable.SetCell(count+1, 7, tview.NewTableCell(plot.PlotDir))
client.plotTable.SetCell(count+1, 8, tview.NewTableCell(plot.TargetDir))
client.activeLogs[count+1] = plot.Tail
count++
keysToRemove := make(map[string]struct{})
for _, key := range client.activePlotsTable.Keys() {
keysToRemove[key] = struct{}{}
}

for host, msg := range client.msg {
for _, plot := range msg.Actives {
delete(keysToRemove, plot.Id)
client.activeLogs[plot.Id] = plot.Tail
client.activePlotsTable.SetRowData(plot.Id, client.makeActivePlotsData(host, plot))
activePlotsCount++
}
}
client.plotTable.SetTitle(fmt.Sprintf(" Active Plots [%d] ", count))
client.plotTable.ScrollToBeginning()

for key, _ := range keysToRemove {
client.activePlotsTable.ClearRowData(key)
}

client.activePlotsTable.SetTitle(fmt.Sprintf(" Active Plots [%d] ", activePlotsCount))
}

////////////////////////////////////////////

func (client *Client) drawArchivedPlots() {
client.lastTable.Clear()
client.lastTable.SetCell(0, 0, tview.NewTableCell("Host"))
Expand Down Expand Up @@ -301,7 +375,7 @@ func (client *Client) drawArchivedPlots() {
}

client.lastTable.SetCell(count+1, 0, tview.NewTableCell(host))
client.lastTable.SetCell(count+1, 1, tview.NewTableCell(client.shortenPlotId(plot.Id)))
client.lastTable.SetCell(count+1, 1, tview.NewTableCell(shortenPlotId(plot.Id)))
client.lastTable.SetCell(count+1, 2, tview.NewTableCell(state))
client.lastTable.SetCell(count+1, 3, tview.NewTableCell(plot.Phase))
client.lastTable.SetCell(count+1, 4, tview.NewTableCell(plot.StartTime.Format("2006-01-02 15:04:05")))
Expand All @@ -317,18 +391,25 @@ func (client *Client) drawArchivedPlots() {
client.lastTable.ScrollToBeginning()
}

func (client *Client) selectActivePlot(row int, column int) {
s := ""
if log, found := client.activeLogs[row]; found {
for _, line := range log {
s += line
}
func (client *Client) selectActivePlot(key string) {
client.logPlotId = key
client.lastTable.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse | tcell.AttrDim))
client.activePlotsTable.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse | tcell.AttrBold))
if log, found := client.activeLogs[key]; found {
client.logTextbox.SetText(strings.Join(log, ""))
client.logTextbox.ScrollToEnd()

} else {
client.logTextbox.SetText("")
}
client.logTextbox.SetText(strings.TrimSpace(s))
}

func (client *Client) selectArchivedPlot(row int, column int) {
s := ""

client.logPlotId = ""
client.activePlotsTable.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse | tcell.AttrDim))
client.lastTable.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse | tcell.AttrBold))
if log, found := client.archivedLogs[row]; found {
for _, line := range log {
s += line
Expand Down
Loading

0 comments on commit 08177b4

Please sign in to comment.