202 lines
5.6 KiB
Go
202 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
)
|
|
|
|
func init() {
|
|
logger := slog.New(&Handler{os.Stderr, slog.LevelInfo})
|
|
slog.SetDefault(logger)
|
|
}
|
|
|
|
func main() {
|
|
renderUI()
|
|
}
|
|
|
|
func renderUI() {
|
|
// SQL-files list
|
|
files, _ := filepath.Glob(filepath.Join(SQL_FILES_DIR, "*.sql"))
|
|
for i := range files {
|
|
files[i] = filepath.Base(files[i])
|
|
}
|
|
|
|
// Servers file list
|
|
configs, _ := filepath.Glob("*.ini")
|
|
|
|
configFileDropDown := tview.NewDropDown().
|
|
SetOptions(configs, nil).
|
|
SetLabel("Файл настроек серверов").
|
|
SetCurrentOption(0)
|
|
sqlFileDropDown := tview.NewDropDown().
|
|
SetOptions(files, nil).
|
|
SetLabel("Файл SQL-скрипта").
|
|
SetCurrentOption(0)
|
|
encodingDropDown := tview.NewDropDown().
|
|
SetOptions([]string{string(EncodingWin1251), string(EncodingUtf8)}, nil).
|
|
SetLabel("Кодировка CSV-файла")
|
|
encodingDropDown.SetDisabled(true)
|
|
encodingDropDown.SetCurrentOption(0)
|
|
|
|
formatDropDown := tview.NewDropDown().
|
|
SetOptions([]string{string(ExportFormatExcel), string(ExportFormatCsv)}, func(text string, index int) {
|
|
if text == string(ExportFormatCsv) {
|
|
encodingDropDown.SetDisabled(false)
|
|
return
|
|
}
|
|
|
|
encodingDropDown.SetDisabled(true)
|
|
}).
|
|
SetLabel("Формат выгрузки").SetCurrentOption(0)
|
|
|
|
form := tview.NewForm().
|
|
AddFormItem(configFileDropDown).
|
|
AddFormItem(sqlFileDropDown).
|
|
AddFormItem(formatDropDown).
|
|
AddFormItem(encodingDropDown)
|
|
form.SetTitle("Параметры").SetBorder(true)
|
|
|
|
app := tview.NewApplication()
|
|
grid := tview.NewGrid().SetRows(-1, 1).
|
|
AddItem(form, 0, 0, 1, 1, 0, 0, true).
|
|
AddItem(tview.NewButton("Запуск").SetSelectedFunc(func() {
|
|
_, scriptFilePath := sqlFileDropDown.GetCurrentOption()
|
|
_, exportFileFormatStr := formatDropDown.GetCurrentOption()
|
|
_, configFilePath := configFileDropDown.GetCurrentOption()
|
|
_, encodingStr := encodingDropDown.GetCurrentOption()
|
|
|
|
job := &Job{
|
|
configFilePath: configFilePath,
|
|
scriptFilePath: filepath.Join(SQL_FILES_DIR, scriptFilePath),
|
|
exportFileFormat: ExportFormat(exportFileFormatStr),
|
|
encoding: Encoding(encodingStr)}
|
|
|
|
err := job.init()
|
|
if err != nil {
|
|
showError(app, err)
|
|
return
|
|
}
|
|
|
|
renderProgressUI(app, job)
|
|
}), 1, 0, 1, 1, 0, 0, false)
|
|
grid.SetBorderPadding(0, 1, 1, 1)
|
|
|
|
form.SetTitle("Параметры выгрузки").SetTitleAlign(tview.AlignLeft)
|
|
if err := app.SetRoot(grid, true).EnableMouse(true).Run(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func renderProgressUI(app *tview.Application, job *Job) {
|
|
statusTextViews := make([]*tview.TextView, 0)
|
|
maxServerNameLen := 0
|
|
for i := range job.servers {
|
|
if len(job.servers[i].Name) > maxServerNameLen {
|
|
maxServerNameLen = len([]rune(job.servers[i].Name)) + 2
|
|
}
|
|
}
|
|
rows := make([]int, len(job.servers)+3)
|
|
for i := range rows {
|
|
rows[i] = 1
|
|
}
|
|
|
|
grid := tview.NewGrid().SetRows(rows...).SetColumns(1, maxServerNameLen+2)
|
|
for i, server := range job.servers {
|
|
grid.AddItem(tview.NewTextView().SetTextAlign(tview.AlignLeft).SetText(server.Name), i+1, 1, 1, 1, 0, 0, false)
|
|
|
|
p := tview.NewTextView().SetTextAlign(tview.AlignLeft).SetText("...")
|
|
statusTextViews = append(statusTextViews, p)
|
|
grid.AddItem(p, i+1, 2, 1, 1, 0, 0, false)
|
|
}
|
|
|
|
grid.AddItem(tview.NewTextView().SetTextAlign(tview.AlignLeft).SetText(strings.Repeat("-", maxServerNameLen)), len(job.servers)+1, 1, 1, 1, 0, 0, false)
|
|
grid.AddItem(tview.NewTextView().SetTextAlign(tview.AlignLeft), len(job.servers)+1, 2, 1, 1, 0, 0, false)
|
|
|
|
statusTextView := tview.NewTextView()
|
|
grid.AddItem(statusTextView, len(job.servers)+2, 2, 1, 1, 0, 0, false)
|
|
|
|
// Last empty line
|
|
grid.AddItem(tview.NewTextView(), len(job.servers)+3, 1, 1, 1, 0, 0, false)
|
|
grid.AddItem(tview.NewTextView(), len(job.servers)+3, 2, 1, 1, 0, 0, false)
|
|
|
|
go func() {
|
|
oneMoreUpdate := false
|
|
for !job.isFinished || oneMoreUpdate {
|
|
if !oneMoreUpdate {
|
|
time.Sleep(time.Second)
|
|
}
|
|
|
|
for i, server := range job.servers {
|
|
s := []string{server.Status}
|
|
if server.Error != nil {
|
|
s = append(s, server.Error.Error())
|
|
}
|
|
statusTextViews[i].SetText(strings.Join(s, ": "))
|
|
|
|
if server.Error != nil {
|
|
statusTextViews[i].SetTextColor(tcell.ColorRed)
|
|
} else if strings.HasPrefix(server.Status, "ЗАВЕРШЕНО: ") {
|
|
statusTextViews[i].SetTextColor(tcell.ColorGreen)
|
|
}
|
|
}
|
|
|
|
statusTextView.SetText(job.status)
|
|
if strings.HasPrefix(job.status, "ЗАВЕРШЕНО") {
|
|
statusTextView.SetTextColor(tcell.ColorGreen)
|
|
}
|
|
|
|
app.ForceDraw()
|
|
if job.isFinished {
|
|
if !oneMoreUpdate {
|
|
oneMoreUpdate = true
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
// TODO:
|
|
/*finishButton := tview.NewButton("OK").SetSelectedFunc(func() { app.Stop() }).SetBackgroundColor(tcell.ColorDarkGreen)
|
|
grid.AddItem(finishButton, len(job.servers)+2, 1, 1, 1, 0, 0, false)
|
|
app.ForceDraw().SetFocus(finishButton)*/
|
|
showMessage(app, "Выгрузка завершена.")
|
|
}()
|
|
|
|
go func() {
|
|
err := job.launch()
|
|
if err != nil {
|
|
showError(app, err)
|
|
}
|
|
}()
|
|
|
|
if err := app.SetRoot(grid, true).SetFocus(grid).Run(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func showError(app *tview.Application, err error) {
|
|
modal := tview.NewModal().
|
|
SetText(err.Error()).
|
|
AddButtons([]string{"OK"}).
|
|
SetBackgroundColor(tcell.ColorRed).
|
|
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
|
os.Exit(1)
|
|
})
|
|
app.SetRoot(modal, true).SetFocus(modal)
|
|
}
|
|
|
|
func showMessage(app *tview.Application, text string) {
|
|
modal := tview.NewModal().
|
|
SetText(text).
|
|
AddButtons([]string{"OK"}).
|
|
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
|
os.Exit(0)
|
|
})
|
|
app.SetRoot(modal, true).SetFocus(modal).ForceDraw()
|
|
}
|