func main() { flag.Parse() wl, err := whiplash.New(*whipconf, true) if err != nil { log.Fatalf("error reading configuration file: %v\n", err) } sigchan := whiplash.AppSetup("whiplash-client", "0.1.0", pclient.Pkgname, pclient.Version) defer whiplash.AppCleanup("whiplash-client") // need a pclient configuration to talk to the aggregator with pcconf = &pclient.Config{ Addr: wl.Aggregator.BindAddr + ":" + wl.Aggregator.BindPort, Timeout: wl.Client.Timeout, } // decide what notification interval to use rand.Seed(time.Now().UnixNano()) intv = rand.Intn(len(intvs)) log.Printf("using interval set: %q\n", intvs[intv]) // create tickers and launch monitor funcs pingticker := time.NewTicker(time.Second * intvs[intv]["ping"]) statticker := time.NewTicker(time.Second * intvs[intv]["stat"]) go pingSvcs(wl.Svcs, pingticker.C) go statSvcs(wl.Svcs, statticker.C) // mainloop keepalive := true for keepalive { select { case <-sigchan: // we've trapped a signal from the OS. tell our Asock to // shut down, but don't exit the eventloop because we want // to handle the Msgs which will be incoming. log.Println("OS signal received; shutting down") keepalive = false } // there's no default case in the select, as that would cause // it to be nonblocking. and that would cause main() to exit // immediately. } }
func main() { // parse flags flag.Parse() // read the whiplash configuration wl, err := whiplash.New(*whipconf, false) if err != nil { log.Fatalf("error reading configuration file: %v\n", err) } // and do application initialization sigchan := whiplash.AppSetup("whiplash-aggregator", "0.1.1", petrel.Pkgname, petrel.Version) defer whiplash.AppCleanup("whiplash-aggregator") // setup the client petrel instance. first set the msglvl, then // instantiate the petrel. phconf := &petrel.Config{ Sockname: wl.Aggregator.BindAddr + ":" + wl.Aggregator.BindPort, Msglvl: msglvl[wl.Aggregator.MsgLvl], Timeout: wl.Aggregator.Timeout, } cph, err := petrel.NewTCP(phconf) if err != nil { log.Fatal(err) } // and add command handlers to the petrel instance handlers := map[string]petrel.DispatchFunc{ "ping": pingHandler, "stat": statHandler, } for name, handler := range handlers { err = cph.AddFunc(name, "nosplit", handler) if err != nil { log.Fatal(err) } } log.Println("client petrel instantiated") // now setup the query petrel instance phconf = &petrel.Config{ Sockname: wl.Aggregator.BindAddr + ":" + wl.Aggregator.QueryPort, Msglvl: msglvl[wl.Aggregator.MsgLvl], Timeout: wl.Aggregator.QTimeout, } qph, err := petrel.NewTCP(phconf) if err != nil { log.Fatal(err) } // add command handlers to the query petrel instance handlers = map[string]petrel.DispatchFunc{ "echo": qhEcho, } for name, handler := range handlers { err = qph.AddFunc(name, "split", handler) if err != nil { log.Fatal(err) } } log.Println("query petrel instantiated") // create a channel for the client petrel Msgr handler msgchan := make(chan error, 1) // and one for the query Msgr handler querychan := make(chan error, 1) // and launch them go msgHandler(cph, msgchan) go msgHandler(qph, querychan) log.Println("aggregator now listening") // this is the mainloop of the application. keepalive := true for keepalive { select { case msg := <-msgchan: // we've been handed a Msg over msgchan, which means that // our Handler has shut itself down for some reason. if this // were a more robust server, we would modularize Handler // creation and this eventloop, so that should we trap a // 599 we could spawn a new Handler and launch it in this // one's place. but we're just gonna exit this loop, // causing main() to terminate, and with it the server // instance. log.Println("Handler has shut down. Last Msg received was:") log.Println(msg) keepalive = false break case msg := <-querychan: // the query handler has died. it should be safe to // restart. log.Println("Query handler has shut down. Last Msg received was:") log.Println(msg) log.Println("Restarting query petrel...") // TODO what it says ^^there case <-sigchan: // we've trapped a signal from the OS. tell our Petrel to // shut down, but don't exit the eventloop because we want // to handle the Msgs which will be incoming. log.Println("OS signal received; shutting down") cph.Quit() } // there's no default case in the select, as that would cause // it to be nonblocking. and that would cause main() to exit // immediately. } }
func main() { flag.Parse() args = flag.Args() // read whiplash config. genconf should be FALSE in the // whiplash.New call for a wlq instance: we don't expect to hacve // ceph services around on a machine running a query. wl, err := whiplash.New(whipconf, false) if err != nil { quit(fmt.Errorf("can't read configuration file: %s\n", err)) } // validate user input err = validateInput() if err != nil { quit(err) } // handle non-networked commands switch args[0] { case "help": showHelp() quit(nil) case "version": showVersion() quit(nil) } // set up configuration and create aclient instance pcconf := &pclient.Config{ Addr: wl.Aggregator.BindAddr + ":" + wl.Aggregator.QueryPort, Timeout: 100, } c, err := pclient.NewTCP(pcconf) if err != nil { quit(fmt.Errorf("can't connect to aggregator: %s", err)) } defer c.Close() // stitch together the non-option arguments into our request req := strings.Join(flag.Args(), " ") // and dispatch it to the server! respj, err := c.Dispatch([]byte(req)) if err != nil { quit(fmt.Errorf("sending request to aggregator failed: %s", err)) } // vivify response and handle errors resp := new(whiplash.QueryResponse) err = json.Unmarshal(respj, &resp) if err != nil { quit(fmt.Errorf("failure unmarshaling json\nerror: %s\njson: %s", err, string(respj))) } if resp.Code >= 400 { quit(fmt.Errorf("there was a problem with the request:\n%s", string(respj))) } // if -j has been specified, print the raw response data and exit if dumpjson { fmt.Println(string(resp.Data)) os.Exit(0) } // else, we have to hand off to a pretty-printing routine // TODO write a pretty-printing routine }