From bfff09e57a1ca3fa69ecd7dc45fdfbe9dd96dfe0 Mon Sep 17 00:00:00 2001 From: postmannen Date: Wed, 30 Jun 2021 07:14:04 +0200 Subject: [PATCH] restructured into single function --- stew/messageSlide.go | 455 +++++++++++++++++++++++++++++++++++++++++ stew/stew.go | 467 +------------------------------------------ 2 files changed, 460 insertions(+), 462 deletions(-) create mode 100644 stew/messageSlide.go diff --git a/stew/messageSlide.go b/stew/messageSlide.go new file mode 100644 index 0000000..3ce08bf --- /dev/null +++ b/stew/messageSlide.go @@ -0,0 +1,455 @@ +package stew + +import ( + "encoding/json" + "fmt" + "log" + "os" + "reflect" + "strconv" + "strings" + "time" + + "github.com/RaaLabs/steward" + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +func messageSlide(app *tview.Application) tview.Primitive { + type pageMessage struct { + flex *tview.Flex + msgInputForm *tview.Form + msgOutputForm *tview.TextView + logForm *tview.TextView + } + + p := pageMessage{} + app = tview.NewApplication() + + p.msgInputForm = tview.NewForm() + p.msgInputForm.SetBorder(true).SetTitle("Request values").SetTitleAlign(tview.AlignLeft) + + p.msgOutputForm = tview.NewTextView() + p.msgOutputForm.SetBorder(true).SetTitle("Message output").SetTitleAlign(tview.AlignLeft) + p.msgOutputForm.SetChangedFunc(func() { + // Will cause the log window to be redrawn as soon as + // new output are detected. + app.Draw() + }) + + p.logForm = tview.NewTextView() + p.logForm.SetBorder(true).SetTitle("Log/Status").SetTitleAlign(tview.AlignLeft) + p.logForm.SetChangedFunc(func() { + // Will cause the log window to be redrawn as soon as + // new output are detected. + app.Draw() + }) + + // Create a flex layout. + // + // First create the outer flex layout. + p.flex = tview.NewFlex().SetDirection(tview.FlexRow). + // Add the top windows with columns. + AddItem(tview.NewFlex().SetDirection(tview.FlexColumn). + AddItem(p.msgInputForm, 0, 10, false). + AddItem(p.msgOutputForm, 0, 10, false), + 0, 10, false). + // Add the bottom log window. + AddItem(tview.NewFlex(). + AddItem(p.logForm, 0, 2, false), + 0, 2, false) + + // Check that the message struct used within stew are up to date, and + // consistent with the fields used in the main Steward message file. + // If it throws an error here we need to update the msg struct type, + // or add a case for the field to except. + err := compareMsgAndMessage() + if err != nil { + log.Printf("%v\n", err) + os.Exit(1) + } + + m := msg{} + + // Loop trough all the fields of the Message struct, and create + // a an input field or dropdown selector for each field. + // If a field of the struct is not defined below, it will be + // created a "no defenition" element, so it we can easily spot + // Message fields who miss an item in the form. + // + // INFO: The reason that reflect are being used here is to have + // a simple way of detecting that we are creating form fields + // for all the fields in the struct. If we have forgot'en one + // it will create a "no case" field in the console, to easily + // detect that a struct field are missing a defenition below. + + mRefVal := reflect.ValueOf(m) + + for i := 0; i < mRefVal.NumField(); i++ { + var err error + values := []string{"1", "2"} + + fieldName := mRefVal.Type().Field(i).Name + + switch fieldName { + case "ToNode": + // Get nodes from file. + values, err = getNodeNames("nodeslist.cfg") + if err != nil { + // TODO: Handle error here, exit ? + return nil + } + + item := tview.NewDropDown() + item.SetLabelColor(tcell.ColorIndianRed) + item.SetLabel(fieldName).SetOptions(values, nil) + p.msgInputForm.AddFormItem(item) + //c.msgForm.AddDropDown(mRefVal.Type().Field(i).Name, values, 0, nil).SetItemPadding(1) + case "ID": + // This value is automatically assigned by steward. + case "Data": + value := `"bash","-c","..."` + p.msgInputForm.AddInputField(fieldName, value, 30, nil, nil) + case "Method": + var m steward.Method + ma := m.GetMethodsAvailable() + values := []string{} + for k := range ma.Methodhandlers { + values = append(values, string(k)) + } + p.msgInputForm.AddDropDown(fieldName, values, 0, nil).SetItemPadding(1) + case "ReplyMethod": + var m steward.Method + rm := m.GetReplyMethods() + values := []string{} + for _, k := range rm { + values = append(values, string(k)) + } + p.msgInputForm.AddDropDown(fieldName, values, 0, nil).SetItemPadding(1) + case "ACKTimeout": + value := 30 + p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) + case "Retries": + value := 1 + p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) + case "ReplyACKTimeout": + value := 30 + p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) + case "ReplyRetries": + value := 1 + p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) + case "MethodTimeout": + value := 120 + p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) + case "Directory": + value := "/some-dir/" + p.msgInputForm.AddInputField(fieldName, value, 30, nil, nil) + case "FileExtension": + value := ".log" + p.msgInputForm.AddInputField(fieldName, value, 30, nil, nil) + case "Operation": + // Prepare the selectedFunc that will be triggered for the operations + // when a field in the dropdown is selected. + // This selectedFunc will generate the sub fields of the selected + // operation, and will also remove any previously drawn operation + // sub fields from the current form. + values := []string{"ps", "startProc", "stopProc"} + selectedFunc := func(option string, optionIndex int) { + + // Prepare the map structure that knows what tview items the + // operation should contain. + // Then we can pick from this map later, to know what fields + // to draw, and also which fields to delete if another operation + // is selected from the dropdown. + + type formItem struct { + label string + formItem tview.FormItem + } + + operationFormItems := map[string][]formItem{} + + operationFormItems["ps"] = nil + + operationFormItems["startProc"] = func() []formItem { + formItems := []formItem{} + + // Get values values to be used for the "Method" dropdown. + var m steward.Method + ma := m.GetMethodsAvailable() + values := []string{} + for k := range ma.Methodhandlers { + values = append(values, string(k)) + } + + // Create the individual form items, and append them to the + // formItems slice to be drawn later. + { + label := "startProc Method" + item := tview.NewDropDown() + item.SetLabel(label).SetOptions(values, nil).SetLabelWidth(25) + formItems = append(formItems, formItem{label: label, formItem: item}) + } + { + label := "startProc AllowedNodes" + item := tview.NewInputField() + item.SetLabel(label).SetFieldWidth(30).SetLabelWidth(25) + formItems = append(formItems, formItem{label: label, formItem: item}) + } + + return formItems + }() + + operationFormItems["stopProc"] = func() []formItem { + formItems := []formItem{} + + // RecevingNode node `json:"receivingNode"` + // Method Method `json:"method"` + // Kind processKind `json:"kind"` + // ID int `json:"id"` + + // Get nodes from file. + values, err = getNodeNames("nodeslist.cfg") + if err != nil { + fmt.Fprintf(p.logForm, "%v: error: unable to get nodes\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) + return nil + } + + { + label := "stopProc ToNode" + item := tview.NewDropDown() + item.SetLabel(label).SetOptions(values, nil).SetLabelWidth(25) + formItems = append(formItems, formItem{label: label, formItem: item}) + + } + + // Get values values to be used for the "Method" dropdown. + var m steward.Method + ma := m.GetMethodsAvailable() + values := []string{} + for k := range ma.Methodhandlers { + values = append(values, string(k)) + } + + // Create the individual form items, and append them to the + // formItems slice. + { + label := "stopProc Method" + item := tview.NewDropDown() + item.SetLabel(label).SetOptions(values, nil).SetLabelWidth(25) + formItems = append(formItems, formItem{label: label, formItem: item}) + + } + + processKind := []string{"publisher", "subscriber"} + + { + label := "stopProc processKind" + item := tview.NewDropDown() + item.SetLabel(label).SetOptions(processKind, nil).SetLabelWidth(25) + formItems = append(formItems, formItem{label: label, formItem: item}) + + } + + { + label := "stopProc ID" + item := tview.NewInputField() + item.SetLabel(label).SetFieldWidth(30).SetLabelWidth(25) + formItems = append(formItems, formItem{label: label, formItem: item}) + } + + return formItems + }() + + itemDraw := func(label string) { + // Delete previously drawn sub operation form items. + for _, vSlice := range operationFormItems { + for _, v := range vSlice { + i := p.msgInputForm.GetFormItemIndex(v.label) + if i > -1 { + p.msgInputForm.RemoveFormItem(i) + } + } + } + + // Get and draw the form items to the form. + formItems := operationFormItems[label] + for _, v := range formItems { + p.msgInputForm.AddFormItem(v.formItem) + } + } + + switch option { + case "ps": + itemDraw("ps") + case "startProc": + itemDraw("startProc") + case "stopProc": + itemDraw("stopProc") + default: + fmt.Fprintf(p.logForm, "%v: error: missing menu item for %v\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), option) + } + } + + p.msgInputForm.AddDropDown(fieldName, values, 0, selectedFunc).SetItemPadding(1) + + default: + // Add a no definition fields to the form if a a field within the + // struct were missing an action above, so we can easily detect + // if there is missing a case action for one of the struct fields. + p.msgInputForm.AddDropDown("error: no case for: "+fieldName, values, 0, nil).SetItemPadding(1) + } + + } + + // Add Buttons below the message fields. Like Generate and Exit. + p.msgInputForm. + // Add a generate button, which when pressed will loop through all the + // message form items, and if found fill the value into a msg struct, + // and at last write it to a file. + // + // TODO: Should also add a write directly to socket here. + AddButton("generate to console", func() { + // --- + opCmdStartProc := steward.OpCmdStartProc{} + opCmdStopProc := steward.OpCmdStopProc{} + // --- + + // fh, err := os.Create("message.json") + // if err != nil { + // log.Fatalf("error: failed to create test.log file: %v\n", err) + // } + // defer fh.Close() + + p.msgOutputForm.Clear() + fh := p.msgOutputForm + + m := msg{} + // Loop trough all the form fields + for i := 0; i < p.msgInputForm.GetFormItemCount(); i++ { + fi := p.msgInputForm.GetFormItem(i) + label, value := getLabelAndValue(fi) + + switch label { + case "ToNode": + if value == "" { + fmt.Fprintf(p.logForm, "%v : error: missing ToNode \n", time.Now().Format("Mon Jan _2 15:04:05 2006")) + return + } + + m.ToNode = steward.Node(value) + case "Data": + // Split the comma separated string into a + // and remove the start and end ampersand. + sp := strings.Split(value, ",") + + var data []string + + for _, v := range sp { + // Check if format is correct, return if not. + pre := strings.HasPrefix(v, "\"") + suf := strings.HasSuffix(v, "\"") + if !pre || !suf { + fmt.Fprintf(p.logForm, "%v : error: missing or malformed format for command, should be \"cmd\",\"arg1\",\"arg2\" ...\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) + return + } + // Remove leading and ending ampersand. + v = v[1:] + v = strings.TrimSuffix(v, "\"") + + data = append(data, v) + } + + m.Data = data + case "Method": + m.Method = steward.Method(value) + case "ReplyMethod": + m.ReplyMethod = steward.Method(value) + case "ACKTimeout": + v, _ := strconv.Atoi(value) + m.ACKTimeout = v + case "Retries": + v, _ := strconv.Atoi(value) + m.Retries = v + case "ReplyACKTimeout": + v, _ := strconv.Atoi(value) + m.ReplyACKTimeout = v + case "ReplyRetries": + v, _ := strconv.Atoi(value) + m.ReplyRetries = v + case "MethodTimeout": + v, _ := strconv.Atoi(value) + m.MethodTimeout = v + case "Directory": + m.Directory = value + case "FileExtension": + m.FileExtension = value + case "Operation": + // We need to check what type of operation it is, and pick + // the correct struct type, and fill it with values + switch value { + case "ps": + //TODO + case "startProc": + m.Operation = &opCmdStartProc + case "stopProc": + m.Operation = &opCmdStopProc + default: + m.Operation = nil + } + case "startProc Method": + if value == "" { + fmt.Fprintf(p.logForm, "%v : error: missing startProc Method\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) + return + } + opCmdStartProc.Method = steward.Method(value) + case "startProc AllowedNodes": + // Split the comma separated string into a + // and remove the start and end ampersand. + sp := strings.Split(value, ",") + + var allowedNodes []steward.Node + + for _, v := range sp { + // Check if format is correct, return if not. + pre := strings.HasPrefix(v, "\"") || !strings.HasPrefix(v, ",") || !strings.HasPrefix(v, "\",") || !strings.HasPrefix(v, ",\"") + suf := strings.HasSuffix(v, "\"") + if !pre || !suf { + fmt.Fprintf(p.logForm, "%v : error: malformed format for command, should be \"cmd\",\"arg1\",\"arg2\" ...\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) + return + } + // Remove leading and ending ampersand. + v = v[1:] + v = strings.TrimSuffix(v, "\"") + + allowedNodes = append(allowedNodes, steward.Node(v)) + } + + opCmdStartProc.AllowedNodes = allowedNodes + default: + fmt.Fprintf(p.logForm, "%v : error: did not find case defenition for how to handle the \"%v\" within the switch statement\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), label) + } + } + msgs := []msg{} + msgs = append(msgs, m) + + msgsIndented, err := json.MarshalIndent(msgs, "", " ") + if err != nil { + fmt.Fprintf(p.logForm, "%v : error: jsonIndent failed: %v\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), err) + } + + _, err = fh.Write(msgsIndented) + if err != nil { + fmt.Fprintf(p.logForm, "%v : error: write to fh failed: %v\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), err) + } + }). + + // Add exit button. + AddButton("exit", func() { + app.Stop() + }) + + app.SetFocus(p.msgInputForm) + + return p.flex +} diff --git a/stew/stew.go b/stew/stew.go index c4137c2..7dcbabc 100644 --- a/stew/stew.go +++ b/stew/stew.go @@ -1,18 +1,13 @@ -package steward +package stew import ( "bufio" - "encoding/json" "flag" "fmt" - "log" "os" "reflect" "strconv" - "strings" - "time" - "github.com/gdamore/tcell/v2" "github.com/rivo/tview" "github.com/RaaLabs/steward" @@ -38,85 +33,18 @@ func NewStew() (*Stew, error) { } func (s *Stew) Start() error { - c := newPageMessage() - err := c.start() - if err != nil { - return fmt.Errorf("error: console failed: %v", err) - } + app := tview.NewApplication() - return nil -} + slide := messageSlide(app) -// --------------------------------------------------- -type pageMessage struct { - flex *tview.Flex - msgInputForm *tview.Form - msgOutputForm *tview.TextView - logForm *tview.TextView - app *tview.Application -} - -func newPageMessage() *pageMessage { - p := pageMessage{} - p.app = tview.NewApplication() - - p.msgInputForm = tview.NewForm() - p.msgInputForm.SetBorder(true).SetTitle("Request values").SetTitleAlign(tview.AlignLeft) - - p.msgOutputForm = tview.NewTextView() - p.msgOutputForm.SetBorder(true).SetTitle("Message output").SetTitleAlign(tview.AlignLeft) - p.msgOutputForm.SetChangedFunc(func() { - // Will cause the log window to be redrawn as soon as - // new output are detected. - p.app.Draw() - }) - - p.logForm = tview.NewTextView() - p.logForm.SetBorder(true).SetTitle("Log/Status").SetTitleAlign(tview.AlignLeft) - p.logForm.SetChangedFunc(func() { - // Will cause the log window to be redrawn as soon as - // new output are detected. - p.app.Draw() - }) - - // Create a flex layout. - // - // First create the outer flex layout. - p.flex = tview.NewFlex().SetDirection(tview.FlexRow). - // Add the top windows with columns. - AddItem(tview.NewFlex().SetDirection(tview.FlexColumn). - AddItem(p.msgInputForm, 0, 10, false). - AddItem(p.msgOutputForm, 0, 10, false), - 0, 10, false). - // Add the bottom log window. - AddItem(tview.NewFlex(). - AddItem(p.logForm, 0, 2, false), - 0, 2, false) - return &p -} - -// Will start the console. -func (p *pageMessage) start() error { - // Check that the message struct used within stew are up to date, and - // consistent with the fields used in the main Steward message file. - // If it throws an error here we need to update the msg struct type, - // or add a case for the field to except. - err := compareMsgAndMessage() - if err != nil { - log.Printf("%v\n", err) - os.Exit(1) - } - - p.drawMsgForm() - - if err := p.app.SetRoot(p.flex, true).SetFocus(p.msgInputForm).EnableMouse(true).Run(); err != nil { + if err := app.SetRoot(slide, true).EnableMouse(true).Run(); err != nil { panic(err) } return nil } -// Will check and compare all the fields of the main message struct +// Check and compare all the fields of the main message struct // used in Steward, and the message struct used in Stew that they are // equal. // If they are not equal an error will be returned to the user with @@ -166,391 +94,6 @@ func compareMsgAndMessage() error { return nil } -func (p *pageMessage) drawMsgForm() error { - m := msg{} - - // Loop trough all the fields of the Message struct, and create - // a an input field or dropdown selector for each field. - // If a field of the struct is not defined below, it will be - // created a "no defenition" element, so it we can easily spot - // Message fields who miss an item in the form. - // - // INFO: The reason that reflect are being used here is to have - // a simple way of detecting that we are creating form fields - // for all the fields in the struct. If we have forgot'en one - // it will create a "no case" field in the console, to easily - // detect that a struct field are missing a defenition below. - - mRefVal := reflect.ValueOf(m) - - for i := 0; i < mRefVal.NumField(); i++ { - var err error - values := []string{"1", "2"} - - fieldName := mRefVal.Type().Field(i).Name - - switch fieldName { - case "ToNode": - // Get nodes from file. - values, err = getNodeNames("nodeslist.cfg") - if err != nil { - return err - } - - item := tview.NewDropDown() - item.SetLabelColor(tcell.ColorIndianRed) - item.SetLabel(fieldName).SetOptions(values, nil) - p.msgInputForm.AddFormItem(item) - //c.msgForm.AddDropDown(mRefVal.Type().Field(i).Name, values, 0, nil).SetItemPadding(1) - case "ID": - // This value is automatically assigned by steward. - case "Data": - value := `"bash","-c","..."` - p.msgInputForm.AddInputField(fieldName, value, 30, nil, nil) - case "Method": - var m steward.Method - ma := m.GetMethodsAvailable() - values := []string{} - for k := range ma.Methodhandlers { - values = append(values, string(k)) - } - p.msgInputForm.AddDropDown(fieldName, values, 0, nil).SetItemPadding(1) - case "ReplyMethod": - var m steward.Method - rm := m.GetReplyMethods() - values := []string{} - for _, k := range rm { - values = append(values, string(k)) - } - p.msgInputForm.AddDropDown(fieldName, values, 0, nil).SetItemPadding(1) - case "ACKTimeout": - value := 30 - p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) - case "Retries": - value := 1 - p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) - case "ReplyACKTimeout": - value := 30 - p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) - case "ReplyRetries": - value := 1 - p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) - case "MethodTimeout": - value := 120 - p.msgInputForm.AddInputField(fieldName, fmt.Sprintf("%d", value), 30, validateInteger, nil) - case "Directory": - value := "/some-dir/" - p.msgInputForm.AddInputField(fieldName, value, 30, nil, nil) - case "FileExtension": - value := ".log" - p.msgInputForm.AddInputField(fieldName, value, 30, nil, nil) - case "Operation": - // Prepare the selectedFunc that will be triggered for the operations - // when a field in the dropdown is selected. - // This selectedFunc will generate the sub fields of the selected - // operation, and will also remove any previously drawn operation - // sub fields from the current form. - values := []string{"ps", "startProc", "stopProc"} - selectedFunc := func(option string, optionIndex int) { - - // Prepare the map structure that knows what tview items the - // operation should contain. - // Then we can pick from this map later, to know what fields - // to draw, and also which fields to delete if another operation - // is selected from the dropdown. - - type formItem struct { - label string - formItem tview.FormItem - } - - operationFormItems := map[string][]formItem{} - - operationFormItems["ps"] = nil - - operationFormItems["startProc"] = func() []formItem { - formItems := []formItem{} - - // Get values values to be used for the "Method" dropdown. - var m steward.Method - ma := m.GetMethodsAvailable() - values := []string{} - for k := range ma.Methodhandlers { - values = append(values, string(k)) - } - - // Create the individual form items, and append them to the - // formItems slice to be drawn later. - { - label := "startProc Method" - item := tview.NewDropDown() - item.SetLabel(label).SetOptions(values, nil).SetLabelWidth(25) - formItems = append(formItems, formItem{label: label, formItem: item}) - } - { - label := "startProc AllowedNodes" - item := tview.NewInputField() - item.SetLabel(label).SetFieldWidth(30).SetLabelWidth(25) - formItems = append(formItems, formItem{label: label, formItem: item}) - } - - return formItems - }() - - operationFormItems["stopProc"] = func() []formItem { - formItems := []formItem{} - - // RecevingNode node `json:"receivingNode"` - // Method Method `json:"method"` - // Kind processKind `json:"kind"` - // ID int `json:"id"` - - // Get nodes from file. - values, err = getNodeNames("nodeslist.cfg") - if err != nil { - fmt.Fprintf(p.logForm, "%v: error: unable to get nodes\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) - return nil - } - - { - label := "stopProc ToNode" - item := tview.NewDropDown() - item.SetLabel(label).SetOptions(values, nil).SetLabelWidth(25) - formItems = append(formItems, formItem{label: label, formItem: item}) - - } - - // Get values values to be used for the "Method" dropdown. - var m steward.Method - ma := m.GetMethodsAvailable() - values := []string{} - for k := range ma.Methodhandlers { - values = append(values, string(k)) - } - - // Create the individual form items, and append them to the - // formItems slice. - { - label := "stopProc Method" - item := tview.NewDropDown() - item.SetLabel(label).SetOptions(values, nil).SetLabelWidth(25) - formItems = append(formItems, formItem{label: label, formItem: item}) - - } - - processKind := []string{"publisher", "subscriber"} - - { - label := "stopProc processKind" - item := tview.NewDropDown() - item.SetLabel(label).SetOptions(processKind, nil).SetLabelWidth(25) - formItems = append(formItems, formItem{label: label, formItem: item}) - - } - - { - label := "stopProc ID" - item := tview.NewInputField() - item.SetLabel(label).SetFieldWidth(30).SetLabelWidth(25) - formItems = append(formItems, formItem{label: label, formItem: item}) - } - - return formItems - }() - - itemDraw := func(label string) { - // Delete previously drawn sub operation form items. - for _, vSlice := range operationFormItems { - for _, v := range vSlice { - i := p.msgInputForm.GetFormItemIndex(v.label) - if i > -1 { - p.msgInputForm.RemoveFormItem(i) - } - } - } - - // Get and draw the form items to the form. - formItems := operationFormItems[label] - for _, v := range formItems { - p.msgInputForm.AddFormItem(v.formItem) - } - } - - switch option { - case "ps": - itemDraw("ps") - case "startProc": - itemDraw("startProc") - case "stopProc": - itemDraw("stopProc") - default: - fmt.Fprintf(p.logForm, "%v: error: missing menu item for %v\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), option) - } - } - - p.msgInputForm.AddDropDown(fieldName, values, 0, selectedFunc).SetItemPadding(1) - - default: - // Add a no definition fields to the form if a a field within the - // struct were missing an action above, so we can easily detect - // if there is missing a case action for one of the struct fields. - p.msgInputForm.AddDropDown("error: no case for: "+fieldName, values, 0, nil).SetItemPadding(1) - } - - } - - // Add Buttons below the message fields. Like Generate and Exit. - p.msgInputForm. - // Add a generate button, which when pressed will loop through all the - // message form items, and if found fill the value into a msg struct, - // and at last write it to a file. - // - // TODO: Should also add a write directly to socket here. - AddButton("generate to console", func() { - // --- - opCmdStartProc := steward.OpCmdStartProc{} - opCmdStopProc := steward.OpCmdStopProc{} - // --- - - // fh, err := os.Create("message.json") - // if err != nil { - // log.Fatalf("error: failed to create test.log file: %v\n", err) - // } - // defer fh.Close() - - p.msgOutputForm.Clear() - fh := p.msgOutputForm - - m := msg{} - // Loop trough all the form fields - for i := 0; i < p.msgInputForm.GetFormItemCount(); i++ { - fi := p.msgInputForm.GetFormItem(i) - label, value := getLabelAndValue(fi) - - switch label { - case "ToNode": - if value == "" { - fmt.Fprintf(p.logForm, "%v : error: missing ToNode \n", time.Now().Format("Mon Jan _2 15:04:05 2006")) - return - } - - m.ToNode = steward.Node(value) - case "Data": - // Split the comma separated string into a - // and remove the start and end ampersand. - sp := strings.Split(value, ",") - - var data []string - - for _, v := range sp { - // Check if format is correct, return if not. - pre := strings.HasPrefix(v, "\"") - suf := strings.HasSuffix(v, "\"") - if !pre || !suf { - fmt.Fprintf(p.logForm, "%v : error: missing or malformed format for command, should be \"cmd\",\"arg1\",\"arg2\" ...\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) - return - } - // Remove leading and ending ampersand. - v = v[1:] - v = strings.TrimSuffix(v, "\"") - - data = append(data, v) - } - - m.Data = data - case "Method": - m.Method = steward.Method(value) - case "ReplyMethod": - m.ReplyMethod = steward.Method(value) - case "ACKTimeout": - v, _ := strconv.Atoi(value) - m.ACKTimeout = v - case "Retries": - v, _ := strconv.Atoi(value) - m.Retries = v - case "ReplyACKTimeout": - v, _ := strconv.Atoi(value) - m.ReplyACKTimeout = v - case "ReplyRetries": - v, _ := strconv.Atoi(value) - m.ReplyRetries = v - case "MethodTimeout": - v, _ := strconv.Atoi(value) - m.MethodTimeout = v - case "Directory": - m.Directory = value - case "FileExtension": - m.FileExtension = value - case "Operation": - // We need to check what type of operation it is, and pick - // the correct struct type, and fill it with values - switch value { - case "ps": - //TODO - case "startProc": - m.Operation = &opCmdStartProc - case "stopProc": - m.Operation = &opCmdStopProc - default: - m.Operation = nil - } - case "startProc Method": - if value == "" { - fmt.Fprintf(p.logForm, "%v : error: missing startProc Method\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) - return - } - opCmdStartProc.Method = steward.Method(value) - case "startProc AllowedNodes": - // Split the comma separated string into a - // and remove the start and end ampersand. - sp := strings.Split(value, ",") - - var allowedNodes []steward.Node - - for _, v := range sp { - // Check if format is correct, return if not. - pre := strings.HasPrefix(v, "\"") || !strings.HasPrefix(v, ",") || !strings.HasPrefix(v, "\",") || !strings.HasPrefix(v, ",\"") - suf := strings.HasSuffix(v, "\"") - if !pre || !suf { - fmt.Fprintf(p.logForm, "%v : error: malformed format for command, should be \"cmd\",\"arg1\",\"arg2\" ...\n", time.Now().Format("Mon Jan _2 15:04:05 2006")) - return - } - // Remove leading and ending ampersand. - v = v[1:] - v = strings.TrimSuffix(v, "\"") - - allowedNodes = append(allowedNodes, steward.Node(v)) - } - - opCmdStartProc.AllowedNodes = allowedNodes - default: - fmt.Fprintf(p.logForm, "%v : error: did not find case defenition for how to handle the \"%v\" within the switch statement\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), label) - } - } - msgs := []msg{} - msgs = append(msgs, m) - - msgsIndented, err := json.MarshalIndent(msgs, "", " ") - if err != nil { - fmt.Fprintf(p.logForm, "%v : error: jsonIndent failed: %v\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), err) - } - - _, err = fh.Write(msgsIndented) - if err != nil { - fmt.Fprintf(p.logForm, "%v : error: write to fh failed: %v\n", time.Now().Format("Mon Jan _2 15:04:05 2006"), err) - } - }). - - // Add exit button. - AddButton("exit", func() { - p.app.Stop() - }) - - p.app.SetFocus(p.msgInputForm) - - return nil -} - // Will return the Label And the text Value of an input or dropdown form field. func getLabelAndValue(fi tview.FormItem) (string, string) { var label string