// -- utils func makeHandler(fn func(http.ResponseWriter, *http.Request, util.JsMap, *util.HekaLogger)) http.HandlerFunc { config := util.MzGetConfig("config.ini") // Convert the token_key from base64 (if present) if k, ok := config["token_key"]; ok { key, _ := base64.URLEncoding.DecodeString(k.(string)) config["token_key"] = key } return func(resp http.ResponseWriter, req *http.Request) { fn(resp, req, config, logger) } }
func main() { flag.Parse() // Configuration config := util.MzGetConfig(*configFile) config["VERSION"] = VERSION runtime.GOMAXPROCS(runtime.NumCPU()) logger := util.NewHekaLogger(config) store := storage.New(config, logger) handlers := moztradamus.NewHandler(config, store, logger) // Signal handler sigChan := make(chan os.Signal) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGHUP, SIGUSR1) // Rest Config errChan := make(chan error) host := util.MzGet(config, "host", "localhost") port := util.MzGet(config, "port", "8080") var RESTMux *http.ServeMux = http.DefaultServeMux var verRoot = strings.SplitN(VERSION, ".", 2)[0] RESTMux.HandleFunc(fmt.Sprintf("/%s/ping/", verRoot), handlers.PingHandler) RESTMux.HandleFunc(fmt.Sprintf("/%s/poll/", verRoot), handlers.PollHandler) RESTMux.HandleFunc("/status/", handlers.StatusHandler) logger.Info("main", "startup...", nil) go func() { errChan <- http.ListenAndServe(host+":"+port, nil) }() select { case err := <-errChan: if err != nil { panic("ListenAndServe: " + err.Error()) } case <-sigChan: logger.Info("main", "Shutting down...", nil) } }
// -- main func main() { var configFile string flag.StringVar(&configFile, "config", "config.ini", "Configuration File") flag.Parse() log.Printf("Using config %s", configFile) config := util.MzGetConfig(configFile) // Convert the token_key from base64 (if present) if k, ok := config["token_key"]; ok { key, _ := base64.URLEncoding.DecodeString(k.(string)) config["token_key"] = key } logger = util.NewHekaLogger(config) simplepush.Clients = make(map[string]*simplepush.Client) // Initialize the common server. simplepush.InitServer(config, logger) // Register the handlers // each websocket gets it's own handler. http.HandleFunc("/update/", makeHandler(simplepush.UpdateHandler)) http.HandleFunc("/status/", makeHandler(simplepush.StatusHandler)) http.Handle("/", websocket.Handler(simplepush.PushSocketHandler)) // Config the server host := util.MzGet(config, "host", "localhost") port := util.MzGet(config, "port", "8080") // Hoist the main sail logger.Info("main", fmt.Sprintf("listening on %s:%s", host, port), nil) err := http.ListenAndServe(fmt.Sprintf("%s:%s", host, port), nil) if err != nil { panic("ListenAndServe: " + err.Error()) } }
func PushSocketHandler(ws *websocket.Conn) { timer := time.Now() // can we pass this in somehow? config := util.MzGetConfig("config.ini") // Convert the token_key from base64 (if present) if k, ok := config["token_key"]; ok { key, _ := base64.URLEncoding.DecodeString(k.(string)) config["token_key"] = key } logger := util.NewHekaLogger(config) store := storage.New(config, logger) sock := PushWS{Uaid: "", Socket: ws, Scmd: make(chan PushCommand), Ccmd: make(chan PushCommand), Store: store, Logger: logger, Born: timer} sock.Logger.Info("main", "New socket connection detected", nil) defer func(log *util.HekaLogger) { if r := recover(); r != nil { log.Error("main", r.(error).Error(), nil) } }(sock.Logger) go NewWorker(config).Run(sock) for { select { case serv_cmd := <-sock.Scmd: result, args := HandleServerCommand(serv_cmd, &sock) sock.Logger.Debug("main", fmt.Sprintf("Returning Result %s", result), nil) sock.Scmd <- PushCommand{result, args} } } }
func main() { flags.ParseArgs(&opts, os.Args) // Configuration // defaults don't appear to work. if opts.ConfigFile == "" { opts.ConfigFile = "config.ini" } config := util.MzGetConfig(opts.ConfigFile) config["VERSION"] = VERSION if util.MzGetFlag(config, "aws.get_hostname") { if hostname, err := util.GetAWSPublicHostname(); err == nil { config["ws_hostname"] = hostname } } //TODO: Build out the partner cert pool if need be. // certpoo if opts.Profile != "" { log.Printf("Creating profile %s...\n", opts.Profile) f, err := os.Create(opts.Profile) if err != nil { log.Fatal("Profile creation failed:\n%s\n", err.Error()) return } defer func() { log.Printf("Closing profile...\n") pprof.StopCPUProfile() }() pprof.StartCPUProfile(f) } if opts.MemProfile != "" { defer func() { profFile, err := os.Create(opts.MemProfile) if err != nil { log.Fatal("Memory Profile creation failed:\n%s\n", err.Error()) return } pprof.WriteHeapProfile(profFile) profFile.Close() }() } runtime.GOMAXPROCS(runtime.NumCPU()) logger := util.NewHekaLogger(config) store, err := storage.Open(config, logger) if err != nil { logger.Error("main", "FAIL", nil) return } handlers := wmf.NewHandler(config, logger, store) // Signal handler sigChan := make(chan os.Signal) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGHUP, SIGUSR1) // Rest Config errChan := make(chan error) host := util.MzGet(config, "host", "localhost") port := util.MzGet(config, "port", "8080") var RESTMux *http.ServeMux = http.DefaultServeMux var WSMux *http.ServeMux = http.DefaultServeMux var verRoot = strings.SplitN(VERSION, ".", 2)[0] // REST calls // Device calls. RESTMux.HandleFunc(fmt.Sprintf("/%s/register/", verRoot), handlers.Register) RESTMux.HandleFunc(fmt.Sprintf("/%s/cmd/", verRoot), handlers.Cmd) // Web UI calls RESTMux.HandleFunc(fmt.Sprintf("/%s/queue/", verRoot), handlers.Queue) RESTMux.HandleFunc(fmt.Sprintf("/%s/state/", verRoot), handlers.State) RESTMux.HandleFunc("/static/", handlers.Static) RESTMux.HandleFunc("/metrics/", handlers.Metrics) // Operations call RESTMux.HandleFunc("/status/", handlers.Status) WSMux.Handle(fmt.Sprintf("/%s/ws/", verRoot), websocket.Handler(handlers.WSSocketHandler)) // Handle root calls as webUI RESTMux.HandleFunc("/", handlers.Index) logger.Info("main", "startup...", util.Fields{"host": host, "port": port}) go func() { errChan <- http.ListenAndServe(host+":"+port, nil) }() select { case err := <-errChan: if err != nil { panic("ListenAndServe: " + err.Error()) } case <-sigChan: logger.Info("main", "Shutting down...", nil) } }
// -- main func main() { var certFile string var keyFile string flag.Parse() config := util.MzGetConfig(*configFile) // The config file requires some customization and normalization config = simplepush.FixConfig(config) config["VERSION"] = VERSION runtime.GOMAXPROCS(runtime.NumCPU()) // Report what the app believes the current host to be, and what version. log.Printf("CurrentHost: %s, Version: %s", config["shard.current_host"], VERSION) // Metrics reporting if mprefix, ok := config["metrics.prefix"]; ok { simplepush.MetricsPrefix(mprefix.(string)) } if mstatsd, ok := config["metrics.statsd_target"]; ok { err := simplepush.MetricsStatsdTarget(mstatsd.(string)) if err != nil { log.Fatal("Couldn't create statsd client: ", err) } } // Only create profiles if requested. To view the application profiles, // see http://blog.golang.org/profiling-go-programs if *profile != "" { log.Printf("Creating profile...") f, err := os.Create(*profile) if err != nil { log.Fatal(err) } defer func() { log.Printf("Closing profile...") pprof.StopCPUProfile() }() pprof.StartCPUProfile(f) } if *memProfile != "" { defer func() { profFile, err := os.Create(*memProfile) if err != nil { log.Fatalln(err) } pprof.WriteHeapProfile(profFile) profFile.Close() }() } // Logging can be CPU intensive (note: variable reflection is VERY // CPU intensive. Avoid things like log.Printf("%v", someStruct) ) // If logging is specified as a command line flag, it overrides the // value specified in the config file. This allows short term logging // for operations. if *logging > 0 { config["logger.enable"] = "1" config["logger.filter"] = strconv.FormatInt(int64(*logging), 10) } if v, ok := config["logger.enable"]; ok { if v, _ := strconv.ParseBool(v.(string)); v { logger = util.NewHekaLogger(config) logger.Info("main", "Enabling full logger", nil) } } // Routing allows stand-alone instances to send updates between themselves. // Websock does not allow for native redirects in some browsers. Routing // allows websocket connections and updates to be handled by any server, // with the approriate notification sent. // // Note: While this is fairly primative, it works. There are more efficient // models and systems that could be used for this (e.g. 0mq, rabbit, etc.) // however those also add additional complexity to the server system. // Since this is mostly point-to-point (we know the host location to send // to), there wasn't much justification to add that complexity. // Obviously, this can and will change over time. route = &router.Router{ Port: util.MzGet(config, "shard.port", "3000"), Logger: logger, } defer func() { if route != nil { route.CloseAll() } }() // Currently, we're opting for a memcache "storage" mechanism, however // and key/value store would suffice. (bonus points if the records are // self expiring.) store = storage.New(config, logger) // Initialize the common server. simplepush.InitServer(config, logger) handlers := simplepush.NewHandler(config, logger, store, route) // Config the server var wsport string var wshost string var WSMux *http.ServeMux = http.DefaultServeMux var RESTMux *http.ServeMux = http.DefaultServeMux host := util.MzGet(config, "host", "localhost") port := util.MzGet(config, "port", "8080") // Register the handlers // each websocket gets it's own handler. if util.MzGet(config, "wsport", port) != port { wsport = util.MzGet(config, "wsport", port) wshost = util.MzGet(config, "wshost", host) WSMux = http.NewServeMux() } RESTMux.HandleFunc("/update/", handlers.UpdateHandler) RESTMux.HandleFunc("/status/", handlers.StatusHandler) RESTMux.HandleFunc("/realstatus/", handlers.RealStatusHandler) RESTMux.HandleFunc("/metrics/", handlers.MetricsHandler) WSMux.Handle("/", websocket.Handler(handlers.PushSocketHandler)) // Hoist the main sail. if logger != nil { logger.Info("main", fmt.Sprintf("listening on %s:%s", host, port), nil) } // Get the (optional) SSL certs if name, ok := config["ssl.certfile"]; ok { certFile = name.(string) } if name, ok := config["ssl.keyfile"]; ok { keyFile = name.(string) } wscertFile := util.MzGet(config, "ssl.ws.certfile", certFile) wskeyFile := util.MzGet(config, "ssl.ws.keyfile", keyFile) // wait for sigint sigChan := make(chan os.Signal) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGHUP, SIGUSR1) errChan := make(chan error) // Weigh the anchor! go func() { addr := host + ":" + port if len(certFile) > 0 && len(keyFile) > 0 { if logger != nil { logger.Info("main", "Using TLS", nil) } errChan <- http.ListenAndServeTLS(addr, certFile, keyFile, nil) } else { errChan <- http.ListenAndServe(addr, nil) } }() // Oh, we have a different context for WebSockets. Weigh that anchor too! if WSMux != RESTMux { if logger != nil { logger.Info("main", "Starting separate context for WS", nil) logger.Info("main", fmt.Sprintf("ws listen on %s:%s", wshost, wsport), nil) } go func() { wsaddr := wshost + ":" + wsport if len(wscertFile) > 0 && len(wskeyFile) > 0 { errChan <- http.ListenAndServeTLS(wsaddr, wscertFile, wskeyFile, WSMux) } else { errChan <- http.ListenAndServe(wsaddr, WSMux) } }() } // And we're underway! go route.HandleUpdates(updater) select { case err := <-errChan: if err != nil { panic("ListenAndServe: " + err.Error()) } case <-sigChan: if logger != nil { logger.Info("main", "Recieved signal, shutting down.", nil) } route.CloseAll() route = nil } }