func (ctl *Controller) Run(config *Configuration) { // Save the configuration ctl.config = config // init the model model := newClientModel(config, ctl) ctl.model = model var state mvc.State = model // init web ui var webView *web.WebView if config.InspectAddr != "disabled" { webView = web.NewWebView(ctl, config.InspectAddr) ctl.addView(webView) } // init term ui var termView *term.TermView if config.LogTo != "stdout" { termView = term.NewTermView(ctl) ctl.addView(termView) } for _, protocol := range model.GetProtocols() { switch p := protocol.(type) { case *proto.Http: if termView != nil { ctl.addView(termView.NewHttpView(p)) } if webView != nil { ctl.addView(webView.NewHttpView(p)) } default: } } if !config.SkipAutoUpdate { ctl.Go(func() { autoUpdate(state, config.AuthToken) }) } ctl.Go(ctl.model.Run) updates := ctl.updates.Reg() defer ctl.updates.UnReg(updates) done := make(chan int) for { select { case obj := <-ctl.cmds: switch cmd := obj.(type) { case cmdQuit: msg := cmd.message go func() { ctl.doShutdown() fmt.Println(msg) done <- 1 }() case cmdPlayRequest: ctl.Go(func() { ctl.model.PlayRequest(cmd.tunnel, cmd.payload) }) } case obj := <-updates: state = obj.(mvc.State) case ctl.state <- state: case <-done: return } } }
func Main() { // parse options opts := parseArgs() // set up logging log.LogTo(opts.logto) // set up auth token if opts.authtoken == "" { opts.authtoken = LoadAuthToken() } // init client state s := &State{ status: "connecting", // unique client id id: util.RandIdOrPanic(8), // command-line options opts: opts, // metrics metrics: NewClientMetrics(), } switch opts.protocol { case "http": s.protocol = proto.NewHttp() case "tcp": s.protocol = proto.NewTcp() } // init ui ctl := ui.NewController() if opts.webport != -1 { web.NewWebView(ctl, s, opts.webport) } if opts.logto != "stdout" { term.New(ctl, s) } go reconnectingControl(s, ctl) go autoUpdate(s, ctl, opts.authtoken) quitMessage := "" ctl.Wait.Add(1) go func() { defer ctl.Wait.Done() for { select { case obj := <-ctl.Cmds: switch cmd := obj.(type) { case ui.CmdQuit: quitMessage = cmd.Message ctl.DoShutdown() return case ui.CmdRequest: go func() { var localConn conn.Conn localConn, err := conn.Dial(s.opts.localaddr, "prv", nil) if err != nil { log.Warn("Failed to open private leg %s: %v", s.opts.localaddr, err) return } //defer localConn.Close() localConn = s.protocol.WrapConn(localConn) localConn.Write(cmd.Payload) ioutil.ReadAll(localConn) }() } } } }() ctl.Wait.Wait() fmt.Println(quitMessage) }