// Why realMain? See https://groups.google.com/forum/#!topic/golang-nuts/_Twwb5ULStM
// So that defer will run propoerly
func realMain() (exitStatus int) {

	// initialize ncurses
	stdscr, colors, resetScreen := initializeNcurses()

	// clean up the screen before we die
	defer func() {
		if err := recover(); err != nil {
			resetScreen()
			fmt.Fprintf(os.Stderr, "exiting from error: %s \n", err)
			ERROR.Println("exiting from error: ", err)
			exitStatus = 1
			os.Exit(1)
		}
	}()

	// draw the stuff on the screen
	msgWin, workerCountWin, durWin, reqSecWin, barsWin, scaleWin, maxWin := drawDisplay(stdscr)

	// create our various channels
	infoMsgsCh := make(chan ncursesMsg)
	exitCh := make(chan int)
	changeNumRequestersCh := make(chan interface{})
	changeNumRequestersListenerCh := make(chan interface{})
	reqMadeOnSecCh := make(chan interface{})
	reqMadeOnSecListenerCh := make(chan interface{})
	reqMadeOnSecSlaveListenerCh := make(chan interface{})
	failsOnSecCh := make(chan int)
	durationCh := make(chan int64)
	durationDisplayCh := make(chan string)
	reqSecDisplayCh := make(chan string)
	bytesPerSecCh := make(chan bytesPerSecMsg)
	bytesPerSecDisplayCh := make(chan string)
	barsToDrawCh := make(chan currentBars)

	// start all the worker goroutines
	go windowRunloop(infoMsgsCh, exitCh, changeNumRequestersCh, msgWin)
	go barsController(reqMadeOnSecListenerCh, failsOnSecCh, barsToDrawCh, reqSecDisplayCh)
	go requesterController(infoMsgsCh, changeNumRequestersListenerCh, reqMadeOnSecCh, failsOnSecCh, durationCh, bytesPerSecCh, *testUrl, *introduceRandomFails)
	go durationWinController(durationCh, durationDisplayCh)
	go bytesPerSecController(bytesPerSecCh, bytesPerSecDisplayCh)

	numRequestersBcaster := bcast.MakeNew(changeNumRequestersCh, INFO)
	numRequestersBcaster.Join(changeNumRequestersListenerCh)

	reqMadeOnSecBcaster := bcast.MakeNew(reqMadeOnSecCh, INFO)
	reqMadeOnSecBcaster.Join(reqMadeOnSecListenerCh)

	if *listen > 0 {
		port := *listen
		// we don't want to join until we start the listener
		joinUp := func() {
			reqMadeOnSecBcaster.Join(reqMadeOnSecSlaveListenerCh)
		}
		go slave.ListenForMaster(port, changeNumRequestersCh, reqMadeOnSecSlaveListenerCh, joinUp, INFO)
	} else if len(slaveList) > 0 {
		connectToSlaves(slaveList, numRequestersBcaster, reqMadeOnSecCh)
	}

	currentScale := int64(1)

	// This is the main loop controlling the ncurses display. Since ncurses
	// wasn't designed with concurrency in mind, only one goroutine should
	// write to a window, so I'm putting all the window writing in here.
main:
	for {
		select {
		case msg := <-infoMsgsCh:
			updateMsgWin(msg, msgWin, workerCountWin)
		case msg := <-durationDisplayCh:
			// that %7s should really be determined from durWidth
			durWin.MovePrint(1, 1, fmt.Sprintf("%11s", msg))
			durWin.NoutRefresh()
		case msg := <-reqSecDisplayCh:
			reqSecWin.MovePrint(1, 1, fmt.Sprintf("%14s", msg))
			reqSecWin.NoutRefresh()
		case msg := <-barsToDrawCh:
			currentScale = calculateScale(msg.max)
			// 25 is the number of rows in the window, s/b dynamic or defined elsewhere
			maxWin.MovePrint(1, 1, fmt.Sprintf("%5d", msg.max))
			maxWin.NoutRefresh()
			scaleWin.MovePrint(1, 1, fmt.Sprintf("%5d", currentScale))
			scaleWin.NoutRefresh()
			updateBarsWin(msg, barsWin, *colors, currentScale)
		case msg := <-bytesPerSecDisplayCh:
			//msgAsFloat64, err := strconv.ParseFloat(msg, 64)
			//if err != nil {
			//    panic(fmt.Sprintf("converting %s failed: %v", msg, err))
			//}
			//if msgAsFloat64 > 0 {
			if msg != "      0.00" {
				INFO.Println("bytes/sec for each second: ", msg)
			}
		case exitStatus = <-exitCh:
			break main
		}

		gc.Update()
	}

	msgWin.Delete()
	gc.End()
	INFO.Println("exiting with status ", exitStatus)
	return exitStatus
}
func drawDisplay(
	stdscr *gc.Window,
) (
	msgWin *gc.Window,
	workerCountWin *gc.Window,
	durWin *gc.Window,
	reqSecWin *gc.Window,
	barsWin *gc.Window,
	scaleWin *gc.Window,
	maxWin *gc.Window,
) {

	// print startup message
	stdscr.Print("Press 'q' to exit")
	stdscr.NoutRefresh()

	// Create message window
	// and enable the use of the
	// keypad on it so the arrow keys are available
	msgHeight, msgWidth := 5, 40
	msgY, msgX := 1, 0
	msgWin = createWindow(msgHeight, msgWidth, msgY, msgX)
	msgWin.Keypad(true)
	msgWin.Box(0, 0)
	msgWin.NoutRefresh()

	// Create the counter window, showing how many goroutines are active
	ctrHeight, ctrWidth := 3, 7
	ctrY := 2
	ctrX := msgWidth + 1
	stdscr.MovePrint(1, ctrX+1, "thrds")
	stdscr.NoutRefresh()
	workerCountWin = createWindow(ctrHeight, ctrWidth, ctrY, ctrX)
	workerCountWin.Box(0, 0)
	workerCountWin.NoutRefresh()

	// Create the avg duration window, showing 5 second moving average
	durHeight, durWidth := 4, 14
	durY := 2
	durX := ctrX + ctrWidth + 1
	stdscr.MovePrint(1, durX+1, "duration ms")
	stdscr.NoutRefresh()
	durWin = createWindow(durHeight, durWidth, durY, durX)
	durWin.Box(0, 0)
	durWin.NoutRefresh()

	// Create the requests/sec window,
	reqSecHeight, reqSecWidth := 3, 16
	reqSecY := 2
	reqSecX := durX + durWidth + 1
	stdscr.MovePrint(1, reqSecX+1, "req/s 1/5/60")
	stdscr.NoutRefresh()
	reqSecWin = createWindow(reqSecHeight, reqSecWidth, reqSecY, reqSecX)
	reqSecWin.Box(0, 0)
	reqSecWin.NoutRefresh()

	// Create the bars window, showing the moving display of bars
	secondsPerMinute := 60
	barsWidth := secondsPerMinute + 3 // we wrap after a minute
	barsHeight := 25                  // need to size this dynamically, TBD
	barsY := msgHeight + 1
	barsX := 9 // leave space for scale window
	barsWin = createWindow(barsHeight, barsWidth, barsY, barsX)
	barsWin.Box(0, 0)
	barsWin.NoutRefresh()

	// Max window, showing the max seen over the last 60 seconds
	maxWidth := 7
	maxHeight := 3
	maxY := barsY + barsHeight - 8
	maxX := 1
	stdscr.MovePrint(maxY, 1, "max:")
	stdscr.NoutRefresh()
	maxY += 1
	maxWin = createWindow(maxHeight, maxWidth, maxY, maxX)
	maxWin.Box(0, 0)
	maxWin.NoutRefresh()

	// Scale window, showing our current scaling factor for the bars display
	scaleWidth := 7
	scaleHeight := 3
	scaleY := barsY + barsHeight - 4
	scaleX := 1
	stdscr.MovePrint(scaleY, 1, "scale:")
	stdscr.NoutRefresh()
	scaleY += 1
	scaleWin = createWindow(scaleHeight, scaleWidth, scaleY, scaleX)
	scaleWin.Box(0, 0)
	scaleWin.MovePrint(1, 1, fmt.Sprintf("%5s", "1"))
	scaleWin.NoutRefresh()

	// Update will flush only the characters which have changed between the
	// physical screen and the virtual screen, minimizing the number of
	// characters which must be sent
	gc.Update()

	return
}
Beispiel #3
0
func main() {
	stdscr, _ := gc.Init()
	defer gc.End()

	yMAX, xMAX := stdscr.MaxYX()
	yMAX = yMAX - 5
	xMAX = xMAX - 5

	gc.StartColor()
	gc.Raw(true)
	gc.Echo(false)
	gc.Cursor(0)
	stdscr.Keypad(true)
	//gc.InitPair(1, gc.C_RED, gc.C_BLACK)
	//gc.InitPair(2, gc.C_CYAN, gc.C_BLACK)

	// build the menu items
	menu_items := []string{
		" P  - 152.111.192.51",
		" W  - 152.111.192.52",
		" E  - 152.111.192.53",
		" R  - 152.111.192.54",
		" T  - 152.111.192.55",
		"Exit"}
	items := make([]*gc.MenuItem, len(menu_items))
	for i, val := range menu_items {
		items[i], _ = gc.NewItem(val, "")
		defer items[i].Free()
	}

	// create the menu
	menu, _ := gc.NewMenu(items)
	defer menu.Free()

	menuwin, _ := gc.NewWindow(yMAX, xMAX, 1, 1)
	menuwin.Keypad(true)

	menu.SetWindow(menuwin)
	//dwin := menuwin.Derived(6, 38, 3, 1)

	//menu.SubWindow(dwin)
	menu.Option(gc.O_SHOWDESC, true)
	menu.Format(5, 2)
	menu.Mark("*")

	// MovePrint centered menu title
	title := "My Menu"
	menuwin.Box(0, 0)
	menuwin.ColorOn(1)
	menuwin.MovePrint(1, (WIDTH/2)-(len(title)/2), title)
	menuwin.ColorOff(1)
	menuwin.MoveAddChar(2, 0, gc.ACS_LTEE)

	//menuwin.HLine(4, 1, gc.ACS_HLINE, WIDTH-2)
	//  menuwin.HLine(12, 10, gc.ACS_HLINE, WIDTH-2)

	//menuwin.MoveAddChar(2, WIDTH-1, gc.ACS_RTEE)

	y, _ := stdscr.MaxYX()
	stdscr.ColorOn(2)
	stdscr.MovePrint(y-3, 1,
		"Use up/down arrows or page up/down to navigate. 'q' to exit")
	stdscr.ColorOff(2)
	stdscr.Refresh()

	menu.Post()
	defer menu.UnPost()
	menuwin.Refresh()

	for {
		gc.Update()

		ch := menuwin.GetChar()

		if ch == 'p' {

			cmd2 := exec.Command("clear")
			cmd2.Stdout = os.Stdout
			cmd2.Stdin = os.Stdin
			//cmd2.Stderr = os.Stderr
			cmd2.Run()

			cmd := exec.Command("ssh", "[email protected]")
			cmd.Stdout = os.Stdout
			cmd.Stdin = os.Stdin
			cmd.Stderr = os.Stderr

			cmd.Run()
			return

		} else if ch == 'q' {
			return
		} else if ch == 27 {
			return
		} else {
			menu.Driver(gc.DriverActions[ch])
		}
	}
}