Beispiel #1
0
// -- 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)
	}
}
Beispiel #2
0
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)
	}

}
Beispiel #3
0
// -- 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())
	}
}
Beispiel #4
0
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}
		}
	}
}
Beispiel #5
0
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)
	}

}
Beispiel #6
0
// -- 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
	}
}