func (g *RpcHandler) handleRpcRequest(cmd string, seq int, args []interface{}) (reply []interface{}) { glog.Infoln("rpc", cmd, args) if cmd == "echo" { return []interface{}{seq, "", args} } defer func() { errMsg := "" switch v := recover().(type) { case nil: // no error case string: errMsg = v case error: errMsg = v.Error() default: errMsg = fmt.Sprintf("%T: %v", v, v) } if errMsg != "" { glog.Warningln("rpc-error", cmd, args, errMsg) reply = []interface{}{seq, errMsg} } }() // FIXME: hack alert, this is special-cased to deal with the database switch cmd { case "db-get": result := database.Get(args[0].(string)) return []interface{}{seq, "", result} case "db-keys": result := database.Keys(args[0].(string)) return []interface{}{seq, "", result} case "db-put": var value interface{} if len(args) > 1 { value = args[1] } database.Put(args[0].(string), value) return nil } // if there's registered circuit for cmd, set it up and return as a stream if _, ok := flow.Registry[cmd]; ok && len(args) == 1 { c := flow.NewCircuit() c.Add("x", cmd) c.AddCircuitry("y", &streamRpcResults{seqNum: seq, replies: g}) c.Connect("x.Out", "y.In", 0) for k, v := range args[0].(map[string]interface{}) { c.Feed("x."+k, tryToConvertToTag(v)) } go func() { defer flow.DontPanic() c.Run() g.Out.Send([]interface{}{seq, false}) // end streaming }() return []interface{}{seq, true} // start streaming } panic(cmd + "?") }
//wsHandler now used ws.Config as protocol handshake now supported func wsHandler(ws *websocket.Conn) { defer flow.DontPanic() defer ws.Close() hdr := ws.Request().Header // keep track of connected clients for reload broadcasting id := hdr.Get("Sec-Websocket-Key") wsClients[id] = ws defer delete(wsClients, id) // the protocol name is used as tag to locate the proper circuit //lightbulb: We use the protocol provided by ws, rather than header, as that contains server accepted value tag := ws.Config().Protocol[0] fmt.Println("WS Protocol Selected:", tag) if tag == "" { //no specific protocol, lets opt for 'default' which just echoes (or return with no circuit!) tag = "default" } g := flow.NewCircuit() g.AddCircuitry("head", &wsHead{ws: ws}) g.Add("ws", "WebSocket-"+tag) //the client has negotiated this support g.AddCircuitry("tail", &wsTail{ws: ws}) g.Connect("head.Out", "ws.In", 0) g.Connect("ws.Out", "tail.In", 0) g.Run() }
// Set up the handlers, then start the server and start processing requests. func (w *HTTPServer) Run() { mux := http.NewServeMux() // don't use default to allow multiple instances port := getInputOrConfig(w.Port, "HTTP_PORT") //TODO:This is dependant upon mqtt func, needs moving - lightbulb pem := "" key := "" for param := range w.Param { switch param.(type) { case flow.Tag: switch param.(flow.Tag).Tag { case "certfile": f := param.(flow.Tag).Msg.(string) if _, err := os.Stat(f); err == nil { glog.Infoln("Using Certfile:", f) pem = f } case "certkey": f := param.(flow.Tag).Msg.(string) if _, err := os.Stat(f); err == nil { glog.Infoln("Using Keyfile:", f) key = f } } } } info, _ := NewHttpEndpointInfo(port, pem, key) for m := range w.Handlers { tag := m.(flow.Tag) switch v := tag.Msg.(type) { case string: h := createHandler(tag.Tag, v, info) mux.Handle(tag.Tag, &flowHandler{h, w}) case http.Handler: mux.Handle(tag.Tag, &flowHandler{v, w}) } } go func() { // will stay running until an error is returned or the app ends defer flow.DontPanic() var err error if info.uri.Scheme == "https" { err = http.ListenAndServeTLS(info.uri.Host, info.pem, info.key, mux) } else { err = http.ListenAndServe(info.uri.Host, mux) } glog.Fatal(err) glog.Infoln("http started on", info.uri.Host) }() // TODO: this is a hack to make sure the server is ready // better would be to interlock the goroutine with the listener being ready time.Sleep(50 * time.Millisecond) }
func main() { flag.Parse() // required, to set up the proper glog configuration flow.LoadConfig(defaults, *config) flow.DontPanic() // register more definitions from a JSON-formatted setup file, if specified if s := flow.Config["SETUP_FILE"]; s != "" { if err := flow.AddToRegistry(s); err != nil { panic(err) } } // if a registered circuit name is given on the command line, run it if flag.NArg() > 0 { if factory, ok := flow.Registry[flag.Arg(0)]; ok { factory().Run() return } fmt.Fprintln(os.Stderr, "Unknown command:", flag.Arg(0)) os.Exit(1) } fmt.Printf("Starting webserver for http://%s/\n", flow.Config["HTTP_PORT"]) // normal startup: save config info in database and start the webserver c := flow.NewCircuit() // database setup, save current config settings, register init gadget c.Add("db", "LevelDB") c.Feed("db.In", flow.Tag{"<clear>", "/config/"}) c.Feed("db.In", flow.Tag{"/config/appName", "JeeBus"}) c.Feed("db.In", flow.Tag{"/config/configFile", *config}) for k, v := range flow.Config { c.Feed("db.In", flow.Tag{"/config/" + k, v}) } c.Feed("db.In", flow.Tag{"<register>", "/gadget/init"}) // wait for db to finish, then dispatch to the "init" gadget, if found c.Add("wait", "Waiter") c.Add("disp", "Dispatcher") c.Connect("db.Out", "wait.Gate", 0) c.Connect("wait.Out", "disp.In", 0) c.Feed("wait.In", flow.Tag{"<dispatch>", "init"}) // webserver setup c.Add("http", "HTTPServer") c.Feed("http.Handlers", flow.Tag{"/", flow.Config["APP_DIR"]}) c.Feed("http.Handlers", flow.Tag{"/base/", flow.Config["BASE_DIR"]}) c.Feed("http.Handlers", flow.Tag{"/ws", "<websocket>"}) // start the ball rolling, keep running forever c.Add("forever", "Forever") c.Run() }
func (g *RpcHandler) handleRpcRequest(cmd string, seq int, args []interface{}) (reply []interface{}) { if cmd == "echo" { return []interface{}{seq, "", args} } defer func() { errMsg := "" switch v := recover().(type) { case nil: // no error case string: errMsg = v case error: errMsg = v.Error() default: errMsg = fmt.Sprintf("%T: %v", v, v) } if errMsg != "" { glog.Warningln("rpc-error", cmd, args, errMsg) reply = []interface{}{seq, errMsg} } }() // if there's registered circuit for cmd, set it up and return as a stream fmt.Println("RPC:", cmd, args) if _, ok := flow.Registry[cmd]; ok && len(args) == 1 { c := flow.NewCircuit() c.Add("x", cmd) c.AddCircuitry("y", &streamRpcResults{seqNum: seq, replies: g}) c.Connect("x.Out", "y.In", 0) for k, v := range args[0].(map[string]interface{}) { c.Feed("x."+k, tryToConvertToTag(v)) } go func() { defer flow.DontPanic() c.Run() g.Out.Send([]interface{}{seq, false}) // end streaming }() return []interface{}{seq, true} // start streaming } panic(cmd + "?") }
func main() { flag.Parse() // required, to set up the proper glog configuration flow.LoadConfig(defaults, *config) // register more definitions from a JSON-formatted setup file, if specified if s := flow.Config["SETUP_FILE"]; s != "" { if err := flow.AddToRegistry(s); err != nil { panic(err) } } // if a registered circuit name is given on the command line, run it if flag.NArg() > 0 { if factory, ok := flow.Registry[flag.Arg(0)]; ok { factory().Run() return } fmt.Fprintln(os.Stderr, "Unknown command:", flag.Arg(0)) os.Exit(1) } glog.Infof("Starting webserver for http://%s/\n", flow.Config["HTTP_PORT"]) // show intro page via a static webserver if the main app dir is absent fd, err := os.Open(flow.Config["APP_DIR"]) if err != nil { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(introPage)) }) panic(http.ListenAndServe(flow.Config["HTTP_PORT"], nil)) } fd.Close() // normal startup: save config info in database and start the webserver c := flow.NewCircuit() flow.DontPanic(c) // database setup, save current config settings, register init gadget c.Add("db", "LevelDB") c.Feed("db.In", flow.Tag{"<clear>", "/config/"}) c.Feed("db.In", flow.Tag{"/config/appName", "HouseMon"}) c.Feed("db.In", flow.Tag{"/config/version", VERSION}) c.Feed("db.In", flow.Tag{"/config/buildDate", BUILD_DATE}) c.Feed("db.In", flow.Tag{"/config/configFile", *config}) for k, v := range flow.Config { c.Feed("db.In", flow.Tag{"/config/" + k, v}) } c.Feed("db.In", flow.Tag{"<register>", "/gadget/init"}) // wait for db to finish, then dispatch to the "init" gadget, if found c.Add("wait", "Waiter") c.Add("disp", "Dispatcher") c.Connect("db.Out", "wait.Gate", 0) c.Connect("wait.Out", "disp.In", 0) c.Feed("wait.In", flow.Tag{"<dispatch>", "init"}) // webserver setup c.Add("http", "HTTPServer") c.Add("asink", "Sink") c.Connect("http.Out", "asink.In", 0) c.Feed("http.Handlers", flow.Tag{"DefaultMux", true}) c.Feed("http.Handlers", flow.Tag{"/", flow.Config["APP_DIR"]}) c.Feed("http.Handlers", flow.Tag{"/base/", flow.Config["BASE_DIR"]}) c.Feed("http.Handlers", flow.Tag{"/ws", "<websocket>"}) // start the ball rolling, keep running forever c.Add("forever", "Forever") c.Run() }