<commit_before>package operation

import (
	"fmt"
	"log"
	"os/exec"

	json "github.com/bitly/go-simplejson"
	"github.com/kataras/go-template/html"
	"github.com/kataras/iris"
	"github.com/spf13/viper"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var db *mgo.Database

func initDB(dbURL string) {
	session, err := mgo.Dial(dbURL)
	if err != nil {
		log.Fatal(err)
	}
	db = session.DB("operation")
}

func getArgs(task *Task, frontTag, backTag string) []string {
	fabPath := viper.GetString("fabPath")
	if frontTag == "" {
		frontTag = *task.Project.Front.Branch
	}
	if backTag == "" {
		backTag = *task.Project.Backend.Branch
	}
	deploy := fmt.Sprintf("deploy:tmp_path=%s,backend_url=%s,backend_branch=%s,front_url=%s,front_branch=%s,remote_path=%s,venv_path=%s,program=%s,workers=%s,worker_class=%s,bind=%s,user_group=%s,ext=%s,path=%s,include=%s,local_user=%s,local_password=%s,config_name=%s,nginx=%v",
		*task.LocalServer.Path, *task.Project.Backend.Address, backTag, *task.Project.Front.Address, frontTag, *task.RemoteServer.Path, *task.VenvPath, *task.Gunicorn.Program, *task.Gunicorn.Workers,
		*task.Gunicorn.WorkerClass, *task.Gunicorn.Bind, *task.RemoteServer.Group, *task.Supervisor.Extension, *task.Supervisor.Path, *task.Supervisor.Include, *task.LocalServer.User, *task.LocalServer.Password, *task.ConfigName, *task.Nginx)
	cmd := []string{
		"-f", fabPath, "-u", *task.RemoteServer.User, "-p", *task.RemoteServer.Password, "-H", *task.RemoteServer.Host, deploy}
	return cmd
}

// RunCommand ...
func RunCommand(c iris.WebsocketConnection, taskID, frontTag, backTag string) *exec.Cmd {
	task := &Task{}
	coll := db.C("tasks")
	err := coll.FindId(bson.ObjectIdHex(taskID)).One(task)
	if err != nil {
		log.Fatal(err)
	}
	cmdArgs := getArgs(task, frontTag, backTag)
	fmt.Println(cmdArgs)
	// cmd := exec.Command("fab", cmdArgs...)
	// stdout, err := cmd.StdoutPipe()
	// if err != nil {
	// 	log.Fatal(err)
	// }
	// scanner := bufio.NewScanner(stdout)
	// go func() {
	// 	for scanner.Scan() {
	// 		c.EmitMessage(scanner.Bytes())
	// 	}
	// }()
	// if err := cmd.Start(); err != nil {
	// 	log.Fatal(err)
	// }
	// if err := cmd.Wait(); err != nil {
	// 	log.Fatal(err)
	// }
	// return cmd
	return nil
}

// CreateApp ...
func CreateApp() *iris.Framework {
	viper.AddConfigPath("/Users/sunyu/workspace/goprojects/src/github.com/syfun/operation")
	viper.AddConfigPath("D:/Workspace/gowork/src/github.com/syfun/operation")
	viper.AddConfigPath("/opt/operation")
	viper.SetConfigName("config")
	viper.SetConfigType("json")
	if err := viper.ReadInConfig(); err != nil {
		log.Panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	initDB(viper.GetString("mongoURL"))
	app := iris.New()
	fmt.Println("##########")
	fmt.Println("templatePath", viper.GetString("templatePath"))
	fmt.Println("fabPath", viper.GetString("fabPath"))
	app.UseTemplate(html.New()).Directory(viper.GetString("templatePath"), ".html")
	app.Static("/static", viper.GetString("staticPath"), 1)
	app.Get("/", func(c *iris.Context) {
		c.MustRender("index.html", nil)
	})
	app.Post("/api/v1/tasks", createTask)
	app.Get("/api/v1/tasks", queryTask)
	app.Put("/api/v1/tasks/:taskID", updateTask)
	app.Delete("/api/v1/tasks/:taskID", deleteTask)

	app.Config.Websocket.Endpoint = "/ws"
	app.Websocket.OnConnection(func(c iris.WebsocketConnection) {
		fmt.Println("Connected.")
		var cmd *exec.Cmd
		c.OnMessage(func(message []byte) {
			fmt.Println(string(message))
			js, _ := json.NewJson(message)
			msgType, err := js.Get("type").String()
			if err != nil {
				log.Panic(err)
			}
			if msgType == "deploy" {
				taskID, err := js.Get("taskID").String()
				if err != nil {
					log.Println(err)
				}
				frontTag, err := js.Get("frontTag").String()
				if err != nil {
					log.Println(err)
				}
				backTag, err := js.Get("backTag").String()
				if err != nil {
					log.Println(err)
				}
				cmd = RunCommand(c, taskID, frontTag, backTag)
			} else if msgType == "stop" {
				if err := cmd.Process.Kill(); err != nil {
					log.Panic(err)
				}
			}
		})
	})
	return app
}
<commit_msg>update Runcommand<commit_after>package operation

import (
	"fmt"
	"log"
	"os/exec"

	json "github.com/bitly/go-simplejson"
	"github.com/kataras/go-template/html"
	"github.com/kataras/iris"
	"github.com/spf13/viper"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"bufio"
)

var db *mgo.Database

func initDB(dbURL string) {
	session, err := mgo.Dial(dbURL)
	if err != nil {
		log.Fatal(err)
	}
	db = session.DB("operation")
}

func getArgs(task *Task, frontTag, backTag string) []string {
	fabPath := viper.GetString("fabPath")
	if frontTag == "" {
		frontTag = *task.Project.Front.Branch
	}
	if backTag == "" {
		backTag = *task.Project.Backend.Branch
	}
	deploy := fmt.Sprintf("deploy:tmp_path=%s,backend_url=%s,backend_branch=%s,front_url=%s,front_branch=%s,remote_path=%s,venv_path=%s,program=%s,workers=%s,worker_class=%s,bind=%s,user_group=%s,ext=%s,path=%s,include=%s,local_user=%s,local_password=%s,config_name=%s,nginx=%v",
		*task.LocalServer.Path, *task.Project.Backend.Address, backTag, *task.Project.Front.Address, frontTag, *task.RemoteServer.Path, *task.VenvPath, *task.Gunicorn.Program, *task.Gunicorn.Workers,
		*task.Gunicorn.WorkerClass, *task.Gunicorn.Bind, *task.RemoteServer.Group, *task.Supervisor.Extension, *task.Supervisor.Path, *task.Supervisor.Include, *task.LocalServer.User, *task.LocalServer.Password, *task.ConfigName, *task.Nginx)
	cmd := []string{
		"-f", fabPath, "-u", *task.RemoteServer.User, "-p", *task.RemoteServer.Password, "-H", *task.RemoteServer.Host, deploy}
	return cmd
}

// RunCommand ...
func RunCommand(c iris.WebsocketConnection, taskID, frontTag, backTag string) *exec.Cmd {
	task := &Task{}
	coll := db.C("tasks")
	err := coll.FindId(bson.ObjectIdHex(taskID)).One(task)
	if err != nil {
		log.Fatal(err)
	}
	cmdArgs := getArgs(task, frontTag, backTag)
	 cmd := exec.Command("fab", cmdArgs...)
	 stdout, err := cmd.StdoutPipe()
	 if err != nil {
	 	log.Fatal(err)
	 }
	 scanner := bufio.NewScanner(stdout)
	 go func() {
	 	for scanner.Scan() {
	 		c.EmitMessage(scanner.Bytes())
	 	}
	 }()
	 if err := cmd.Start(); err != nil {
	 	log.Fatal(err)
	 }
	 if err := cmd.Wait(); err != nil {
	 	log.Fatal(err)
	 }
	 return cmd
}

// CreateApp ...
func CreateApp() *iris.Framework {
	viper.AddConfigPath("/Users/sunyu/workspace/goprojects/src/github.com/syfun/operation")
	viper.AddConfigPath("D:/Workspace/gowork/src/github.com/syfun/operation")
	viper.AddConfigPath("/opt/operation")
	viper.SetConfigName("config")
	viper.SetConfigType("json")
	if err := viper.ReadInConfig(); err != nil {
		log.Panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	initDB(viper.GetString("mongoURL"))
	app := iris.New()
	fmt.Println("##########")
	fmt.Println("templatePath", viper.GetString("templatePath"))
	fmt.Println("fabPath", viper.GetString("fabPath"))
	app.UseTemplate(html.New()).Directory(viper.GetString("templatePath"), ".html")
	app.Static("/static", viper.GetString("staticPath"), 1)
	app.Get("/", func(c *iris.Context) {
		c.MustRender("index.html", nil)
	})
	app.Post("/api/v1/tasks", createTask)
	app.Get("/api/v1/tasks", queryTask)
	app.Put("/api/v1/tasks/:taskID", updateTask)
	app.Delete("/api/v1/tasks/:taskID", deleteTask)

	app.Config.Websocket.Endpoint = "/ws"
	app.Websocket.OnConnection(func(c iris.WebsocketConnection) {
		fmt.Println("Connected.")
		var cmd *exec.Cmd
		c.OnMessage(func(message []byte) {
			fmt.Println(string(message))
			js, _ := json.NewJson(message)
			msgType, err := js.Get("type").String()
			if err != nil {
				log.Panic(err)
			}
			if msgType == "deploy" {
				taskID, err := js.Get("taskID").String()
				if err != nil {
					log.Println(err)
				}
				frontTag, err := js.Get("frontTag").String()
				if err != nil {
					log.Println(err)
				}
				backTag, err := js.Get("backTag").String()
				if err != nil {
					log.Println(err)
				}
				cmd = RunCommand(c, taskID, frontTag, backTag)
			} else if msgType == "stop" {
				if err := cmd.Process.Kill(); err != nil {
					log.Panic(err)
				}
			}
		})
	})
	return app
}
<|endoftext|>


<commit_before>package tsq

import (
	"encoding/json"
	"errors"
	"mime"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"
)

type server struct {
	taskQueue *TaskQueue
	router    *mux.Router
}

func ServeQueue(baseURL string, q *TaskQueue) http.Handler {
	svr := &server{
		router:    mux.NewRouter().Path(baseURL).Subrouter(),
		taskQueue: q,
	}
	svr.registerRoutes()

	return svr.router
}

func (s *server) registerRoutes() {
	s.router.HandleFunc("/", jsonResponse(s.listServices))
	s.router.HandleFunc("/tasks/", jsonResponse(s.listDefinedTasks)).Name("tasks")
	s.router.HandleFunc("/tasks/{name}/", jsonResponse(s.submitTask)).Methods("POST").Name("submitTask")
	s.router.HandleFunc("/jobs/", jsonResponse(s.listJobs)).Name("jobs")
	s.router.HandleFunc("/jobs/{uuid}/", jsonResponse(s.getJobStatus)).Name("job")
}

type NameRef struct {
	Name string `json:"name"`
	Href string `json:"href"`
}

func (s *server) listServices(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	tasksUrl, err := s.router.Get("tasks").URL()
	if err != nil {
		return
	}
	jobsUrl, err := s.router.Get("jobs").URL()
	if err != nil {
		return
	}
	services := []NameRef{
		{"tasks", tasksUrl.String()},
		{"jobs", jobsUrl.String()},
	}
	data = services
	return
}

func (s *server) listDefinedTasks(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	tasks := make([]NameRef, 0, len(s.taskQueue.tasks))
	for key := range s.taskQueue.tasks {
		taskUrl, err := s.router.Get("submitTask").URL("name", key)
		if err != nil {
			return tasks, err
		}
		tasks = append(tasks, NameRef{key, taskUrl.String()})
	}
	data = tasks
	return
}

func (s *server) submitTask(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	name := mux.Vars(r)["name"]
	timeout, err := getTimeout(r)
	if err != nil {
		return
	}

	var arguments interface{}
	if r.Header.Get("Content-Type") != "" {
		mt, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
		if err != nil {
			return nil, err
		}
		if mt == "application/json" && r.ContentLength != 0 {
			err = json.NewDecoder(r.Body).Decode(&arguments)
			if err != nil {
				return nil, err
			}
		}
	}

	job, err := s.taskQueue.Submit(name, arguments)
	if err != nil {
		err = &httpError{404, err}
		return
	}

	if timeout > 0 {
		job, err = waitForJob(s.taskQueue, job.UUID, time.Duration(timeout)*time.Second)
		if err != nil {
			return
		}
	}

	url, err := s.router.Get("job").URL("uuid", job.UUID)
	data = WebJob{job, url.String()}
	return
}

type WebJob struct {
	*Job
	Href string `json:"href"`
}

func (s *server) listJobs(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	storedJobs, err := s.taskQueue.jobStore.GetJobs()
	if err != nil {
		return
	}
	jobs := make([]interface{}, 0, len(storedJobs))
	for _, job := range storedJobs {
		url, err := s.router.Get("job").URL("uuid", job.UUID)
		if err != nil {
			return data, err
		}
		jobs = append(jobs, WebJob{job, url.String()})
	}
	data = jobs
	return
}

func (s *server) getJobStatus(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	uuid := mux.Vars(r)["uuid"]
	job, err := s.taskQueue.GetJob(uuid)
	if err != nil {
		err = &httpError{404, err}
		return
	}

	url, err := s.router.Get("job").URL("uuid", job.UUID)
	if err != nil {
		return data, err
	}
	data = WebJob{job, url.String()}
	return
}

type httpError struct {
	Status int
	Err    error
}

func (e *httpError) Error() string {
	return "HTTP " + strconv.Itoa(e.Status) + " " + e.Err.Error()
}

type httpHandler func(http.ResponseWriter, *http.Request) (interface{}, error)

func jsonResponse(fn httpHandler) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var err error
		data, err := fn(w, r)
		if e, ok := err.(*httpError); ok {
			http.Error(w, e.Error(), e.Status)
			return
		}
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		renderJSON(w, data)
	}
}

func renderJSON(w http.ResponseWriter, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(data)
	if err != nil {
		http.Error(w, err.Error(), 500)
	}
}

func getTimeout(r *http.Request) (timeout int, err error) {
	timeoutParam := r.URL.Query().Get("jobTimeoutSeconds")
	if len(timeoutParam) == 0 {
		return
	}
	timeout, err = strconv.Atoi(timeoutParam)
	return
}

func waitForJob(taskQueue *TaskQueue, uuid string, timeout time.Duration) (job *Job, err error) {
	tick := time.Tick(500 * time.Millisecond)
	stop := time.After(timeout)

	for {
		select {
		case <-stop:
			err = &httpError{504, errors.New("Timed out waiting for job " + job.UUID)}
			return
		case <-tick:
			job, err = taskQueue.GetJob(uuid)
			if err != nil {
				return
			}
			if job.Status == JOB_SUCCESS || job.Status == JOB_FAILURE {
				return
			}
		}
	}
}
<commit_msg>Change Path to PathPrefix<commit_after>package tsq

import (
	"encoding/json"
	"errors"
	"mime"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"
)

type server struct {
	taskQueue *TaskQueue
	router    *mux.Router
}

func ServeQueue(baseURL string, q *TaskQueue) http.Handler {
	svr := &server{
		router:    mux.NewRouter().PathPrefix(baseURL).Subrouter(),
		taskQueue: q,
	}
	svr.registerRoutes()

	return svr.router
}

func (s *server) registerRoutes() {
	s.router.HandleFunc("/", jsonResponse(s.listServices))
	s.router.HandleFunc("/tasks/", jsonResponse(s.listDefinedTasks)).Name("tasks")
	s.router.HandleFunc("/tasks/{name}/", jsonResponse(s.submitTask)).Methods("POST").Name("submitTask")
	s.router.HandleFunc("/jobs/", jsonResponse(s.listJobs)).Name("jobs")
	s.router.HandleFunc("/jobs/{uuid}/", jsonResponse(s.getJobStatus)).Name("job")
}

type NameRef struct {
	Name string `json:"name"`
	Href string `json:"href"`
}

func (s *server) listServices(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	tasksUrl, err := s.router.Get("tasks").URL()
	if err != nil {
		return
	}
	jobsUrl, err := s.router.Get("jobs").URL()
	if err != nil {
		return
	}
	services := []NameRef{
		{"tasks", tasksUrl.String()},
		{"jobs", jobsUrl.String()},
	}
	data = services
	return
}

func (s *server) listDefinedTasks(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	tasks := make([]NameRef, 0, len(s.taskQueue.tasks))
	for key := range s.taskQueue.tasks {
		taskUrl, err := s.router.Get("submitTask").URL("name", key)
		if err != nil {
			return tasks, err
		}
		tasks = append(tasks, NameRef{key, taskUrl.String()})
	}
	data = tasks
	return
}

func (s *server) submitTask(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	name := mux.Vars(r)["name"]
	timeout, err := getTimeout(r)
	if err != nil {
		return
	}

	var arguments interface{}
	if r.Header.Get("Content-Type") != "" {
		mt, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
		if err != nil {
			return nil, err
		}
		if mt == "application/json" && r.ContentLength != 0 {
			err = json.NewDecoder(r.Body).Decode(&arguments)
			if err != nil {
				return nil, err
			}
		}
	}

	job, err := s.taskQueue.Submit(name, arguments)
	if err != nil {
		err = &httpError{404, err}
		return
	}

	if timeout > 0 {
		job, err = waitForJob(s.taskQueue, job.UUID, time.Duration(timeout)*time.Second)
		if err != nil {
			return
		}
	}

	url, err := s.router.Get("job").URL("uuid", job.UUID)
	data = WebJob{job, url.String()}
	return
}

type WebJob struct {
	*Job
	Href string `json:"href"`
}

func (s *server) listJobs(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	storedJobs, err := s.taskQueue.jobStore.GetJobs()
	if err != nil {
		return
	}
	jobs := make([]interface{}, 0, len(storedJobs))
	for _, job := range storedJobs {
		url, err := s.router.Get("job").URL("uuid", job.UUID)
		if err != nil {
			return data, err
		}
		jobs = append(jobs, WebJob{job, url.String()})
	}
	data = jobs
	return
}

func (s *server) getJobStatus(w http.ResponseWriter, r *http.Request) (data interface{}, err error) {
	uuid := mux.Vars(r)["uuid"]
	job, err := s.taskQueue.GetJob(uuid)
	if err != nil {
		err = &httpError{404, err}
		return
	}

	url, err := s.router.Get("job").URL("uuid", job.UUID)
	if err != nil {
		return data, err
	}
	data = WebJob{job, url.String()}
	return
}

type httpError struct {
	Status int
	Err    error
}

func (e *httpError) Error() string {
	return "HTTP " + strconv.Itoa(e.Status) + " " + e.Err.Error()
}

type httpHandler func(http.ResponseWriter, *http.Request) (interface{}, error)

func jsonResponse(fn httpHandler) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var err error
		data, err := fn(w, r)
		if e, ok := err.(*httpError); ok {
			http.Error(w, e.Error(), e.Status)
			return
		}
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		renderJSON(w, data)
	}
}

func renderJSON(w http.ResponseWriter, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	err := json.NewEncoder(w).Encode(data)
	if err != nil {
		http.Error(w, err.Error(), 500)
	}
}

func getTimeout(r *http.Request) (timeout int, err error) {
	timeoutParam := r.URL.Query().Get("jobTimeoutSeconds")
	if len(timeoutParam) == 0 {
		return
	}
	timeout, err = strconv.Atoi(timeoutParam)
	return
}

func waitForJob(taskQueue *TaskQueue, uuid string, timeout time.Duration) (job *Job, err error) {
	tick := time.Tick(500 * time.Millisecond)
	stop := time.After(timeout)

	for {
		select {
		case <-stop:
			err = &httpError{504, errors.New("Timed out waiting for job " + job.UUID)}
			return
		case <-tick:
			job, err = taskQueue.GetJob(uuid)
			if err != nil {
				return
			}
			if job.Status == JOB_SUCCESS || job.Status == JOB_FAILURE {
				return
			}
		}
	}
}
<|endoftext|>


<commit_before>// Package neptulon is a socket framework with middleware support.
package neptulon

import (
	"fmt"
	"log"
	"sync"

	"github.com/neptulon/client"
	"github.com/neptulon/cmap"
)

// Server is a Neptulon server.
type Server struct {
	debug          bool
	err            error
	errMutex       sync.RWMutex
	listener       *Listener
	middleware     []func(ctx *client.Ctx)
	conns          *cmap.CMap // conn ID -> Conn
	connHandler    func(conn *client.Conn)
	disconnHandler func(conn *client.Conn)
}

// NewTLSServer creates a Neptulon server using Transport Layer Security.
// Debug mode dumps raw TCP data to stderr (log.Println() default).
func NewTLSServer(cert, privKey, clientCACert []byte, laddr string, debug bool) (*Server, error) {
	l, err := ListenTLS(cert, privKey, clientCACert, laddr, debug)
	if err != nil {
		return nil, err
	}

	return &Server{
		debug:          debug,
		listener:       l,
		conns:          cmap.New(),
		connHandler:    func(conn *client.Conn) {},
		disconnHandler: func(conn *client.Conn) {},
	}, nil
}

// Conn registers a function to handle client connection events.
func (s *Server) Conn(handler func(conn *client.Conn)) {
	s.connHandler = handler
}

// Middleware registers middleware to handle incoming messages.
func (s *Server) Middleware(middleware ...func(ctx *client.Ctx)) {
	s.middleware = append(s.middleware, middleware...)
}

// Disconn registers a function to handle client disconnection events.
func (s *Server) Disconn(handler func(conn *client.Conn)) {
	s.disconnHandler = handler
}

// Run starts accepting connections on the internal listener and handles connections with registered middleware.
// This function blocks and never returns, unless there was an error while accepting a new connection or the listner was closed.
func (s *Server) Run() error {
	err := s.listener.Accept(s.handleConn, s.handleMsg, s.handleDisconn)
	if err != nil && s.debug {
		log.Fatalln("Listener returned an error while closing:", err)
	}

	s.errMutex.Lock()
	s.err = err
	s.errMutex.Unlock()

	return err
}

// Send sends a message throught the connection denoted by the connection ID.
func (s *Server) Send(connID string, msg []byte) error {
	if conn, ok := s.conns.GetOk(connID); ok {
		return conn.(*client.Conn).Write(msg)
	}

	return fmt.Errorf("Connection ID not found: %v", connID)
}

// Stop stops a server instance.
func (s *Server) Stop() error {
	err := s.listener.Close()

	// close all active connections discarding any read/writes that is going on currently
	// this is not a problem as we always require an ACK but it will also mean that message deliveries will be at-least-once; to-and-from the server
	s.conns.Range(func(conn interface{}) {
		conn.(*client.Conn).Close()
	})

	s.errMutex.RLock()
	if s.err != nil {
		return fmt.Errorf("There was a recorded internal error before closing the connection: %v", s.err)
	}
	s.errMutex.RUnlock()
	return err
}

func (s *Server) handleConn(c *client.Client) {
	s.conns.Set(c.Conn.ID, c.Conn)
	c.MiddlewareIn(s.middleware...)
	s.connHandler(c.Conn)
}

func (s *Server) handleMsg(c *client.Client, msg []byte) {
	ctx, _ := client.NewCtx(c.Conn, msg, s.middleware)
	ctx.Next()
}

func (s *Server) handleDisconn(c *client.Client) {
	s.conns.Delete(c.Conn.ID)
	s.disconnHandler(c.Conn)
}
<commit_msg>make disconnected event into middleware<commit_after>// Package neptulon is a socket framework with middleware support.
package neptulon

import (
	"fmt"
	"log"
	"sync"

	"github.com/neptulon/client"
	"github.com/neptulon/cmap"
)

// Server is a Neptulon server.
type Server struct {
	debug       bool
	err         error
	errMutex    sync.RWMutex
	listener    *Listener
	middleware  []func(ctx *client.Ctx)
	conns       *cmap.CMap // conn ID -> Conn
	connHandler func(conn *client.Conn)
}

// NewTLSServer creates a Neptulon server using Transport Layer Security.
// Debug mode dumps raw TCP data to stderr (log.Println() default).
func NewTLSServer(cert, privKey, clientCACert []byte, laddr string, debug bool) (*Server, error) {
	l, err := ListenTLS(cert, privKey, clientCACert, laddr, debug)
	if err != nil {
		return nil, err
	}

	return &Server{
		debug:       debug,
		listener:    l,
		conns:       cmap.New(),
		connHandler: func(conn *client.Conn) {},
	}, nil
}

// Conn registers a function to handle client connection events.
func (s *Server) Conn(handler func(conn *client.Conn)) {
	s.connHandler = handler
}

// Middleware registers middleware to handle incoming messages.
func (s *Server) Middleware(middleware ...func(ctx *client.Ctx)) {
	s.middleware = append(s.middleware, middleware...)
}

// Run starts accepting connections on the internal listener and handles connections with registered middleware.
// This function blocks and never returns, unless there was an error while accepting a new connection or the listner was closed.
func (s *Server) Run() error {
	err := s.listener.Accept(s.handleConn, s.handleMsg, s.handleDisconn)
	if err != nil && s.debug {
		log.Fatalln("Listener returned an error while closing:", err)
	}

	s.errMutex.Lock()
	s.err = err
	s.errMutex.Unlock()

	return err
}

// Send sends a message throught the connection denoted by the connection ID.
func (s *Server) Send(connID string, msg []byte) error {
	if conn, ok := s.conns.GetOk(connID); ok {
		return conn.(*client.Conn).Write(msg)
	}

	return fmt.Errorf("Connection ID not found: %v", connID)
}

// Stop stops a server instance.
func (s *Server) Stop() error {
	err := s.listener.Close()

	// close all active connections discarding any read/writes that is going on currently
	// this is not a problem as we always require an ACK but it will also mean that message deliveries will be at-least-once; to-and-from the server
	s.conns.Range(func(conn interface{}) {
		conn.(*client.Conn).Close()
	})

	s.errMutex.RLock()
	if s.err != nil {
		return fmt.Errorf("There was a recorded internal error before closing the connection: %v", s.err)
	}
	s.errMutex.RUnlock()
	return err
}

func (s *Server) handleConn(c *client.Client) {
	s.conns.Set(c.Conn.ID, c.Conn)
	c.MiddlewareIn(s.middleware...)
	s.connHandler(c.Conn)
}

func (s *Server) handleMsg(c *client.Client, msg []byte) {
	ctx, _ := client.NewCtx(c.Conn, msg, s.middleware)
	ctx.Next()
}

func (s *Server) handleDisconn(c *client.Client) {
	s.conns.Delete(c.Conn.ID)
	s.disconnHandler(c.Conn)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

/* Read functions
 */
func ListView(w http.ResponseWriter, r *http.Request,
	_ httprouter.Params) {
	defer PanicCatcher(w)

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewReadHandler"].(somaViewReadHandler)
	handler.input <- somaViewRequest{
		action: "list",
		reply:  returnChannel,
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

func ShowView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewReadHandler"].(somaViewReadHandler)
	handler.input <- somaViewRequest{
		action: "show",
		reply:  returnChannel,
		View: proto.View{
			Name: params.ByName("view"),
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

/* Write functions
 */
func AddView(w http.ResponseWriter, r *http.Request,
	_ httprouter.Params) {
	defer PanicCatcher(w)

	cReq := proto.NewViewRequest()
	err := DecodeJsonBody(r, &cReq)
	if err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewWriteHandler"].(somaViewWriteHandler)
	handler.input <- somaViewRequest{
		action: "add",
		reply:  returnChannel,
		View: proto.View{
			Name: cReq.View.Name,
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

func DeleteView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewWriteHandler"].(somaViewWriteHandler)
	handler.input <- somaViewRequest{
		action: "delete",
		reply:  returnChannel,
		View: proto.View{
			Name: params.ByName("view"),
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

func RenameView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)

	cReq := proto.NewViewRequest()
	err := DecodeJsonBody(r, &cReq)
	if err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewWriteHandler"].(somaViewWriteHandler)
	handler.input <- somaViewRequest{
		action: "rename",
		reply:  returnChannel,
		name:   params.ByName("view"),
		View: proto.View{
			Name: cReq.View.Name,
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

/* Utility
 */
func SendViewReply(w *http.ResponseWriter, r *somaResult) {
	result := proto.NewViewResult()
	if r.MarkErrors(&result) {
		goto dispatch
	}
	for _, i := range (*r).Views {
		*result.Views = append(*result.Views, i.View)
		if i.ResultError != nil {
			*result.Errors = append(*result.Errors, i.ResultError.Error())
		}
	}

dispatch:
	json, err := json.Marshal(result)
	if err != nil {
		DispatchInternalError(w, err)
		return
	}
	DispatchJsonReply(w, &json)
	return
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Add permission check: views<commit_after>package main

import (
	"encoding/json"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

/* Read functions
 */
func ListView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`view_list`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewReadHandler"].(somaViewReadHandler)
	handler.input <- somaViewRequest{
		action: "list",
		reply:  returnChannel,
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

func ShowView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`view_show`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewReadHandler"].(somaViewReadHandler)
	handler.input <- somaViewRequest{
		action: "show",
		reply:  returnChannel,
		View: proto.View{
			Name: params.ByName("view"),
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

/* Write functions
 */
func AddView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`view_create`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	cReq := proto.NewViewRequest()
	err := DecodeJsonBody(r, &cReq)
	if err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewWriteHandler"].(somaViewWriteHandler)
	handler.input <- somaViewRequest{
		action: "add",
		reply:  returnChannel,
		View: proto.View{
			Name: cReq.View.Name,
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

func DeleteView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`view_delete`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewWriteHandler"].(somaViewWriteHandler)
	handler.input <- somaViewRequest{
		action: "delete",
		reply:  returnChannel,
		View: proto.View{
			Name: params.ByName("view"),
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

func RenameView(w http.ResponseWriter, r *http.Request,
	params httprouter.Params) {
	defer PanicCatcher(w)
	if ok, _ := IsAuthorized(params.ByName(`AuthenticatedUser`),
		`view_rename`, ``, ``, ``); !ok {
		DispatchForbidden(&w, nil)
		return
	}

	cReq := proto.NewViewRequest()
	err := DecodeJsonBody(r, &cReq)
	if err != nil {
		DispatchBadRequest(&w, err)
		return
	}

	returnChannel := make(chan somaResult)
	handler := handlerMap["viewWriteHandler"].(somaViewWriteHandler)
	handler.input <- somaViewRequest{
		action: "rename",
		reply:  returnChannel,
		name:   params.ByName("view"),
		View: proto.View{
			Name: cReq.View.Name,
		},
	}
	result := <-returnChannel
	SendViewReply(&w, &result)
}

/* Utility
 */
func SendViewReply(w *http.ResponseWriter, r *somaResult) {
	result := proto.NewViewResult()
	if r.MarkErrors(&result) {
		goto dispatch
	}
	for _, i := range (*r).Views {
		*result.Views = append(*result.Views, i.View)
		if i.ResultError != nil {
			*result.Errors = append(*result.Errors, i.ResultError.Error())
		}
	}

dispatch:
	json, err := json.Marshal(result)
	if err != nil {
		DispatchInternalError(w, err)
		return
	}
	DispatchJsonReply(w, &json)
	return
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	rfc3164 "github.com/jeromer/syslogparser/rfc3164"
	"net"
	"os"
	"os/signal"
)

type server struct {
	port        int
	connections []net.Conn
}

func process(line []byte) {
	p := rfc3164.NewParser(line)
	if err := p.Parse(); err != nil {
		fmt.Fprintln(os.Stderr, "failed to parse:", err)
		return
	}

	for k, v := range p.Dump() {
		fmt.Println(k, ":", v)
	}
}

func handleConnection(conn net.Conn) {

	fmt.Fprintln(os.Stderr, "got connection from:", conn.RemoteAddr())
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		process([]byte(scanner.Text()))
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "error reading from connection:", err)
	}

}

func (s *server) handleInterrupt() {
	interrupts := make(chan os.Signal, 1)
	signal.Notify(interrupts, os.Interrupt)

	go func() {
		<-interrupts
		fmt.Fprintln(os.Stderr, "got interrupt signal, closing", len(s.connections), "connections")

		for _, conn := range s.connections {
			fmt.Fprintln(os.Stderr, "closing connection to", conn.RemoteAddr())
			conn.Close()
		}

		os.Exit(0)
	}()
}

var (
	port = flag.Int("port", 514, "port on which to listen")
)

func (s *server) start() error {
	s.handleInterrupt()

	fmt.Fprintf(os.Stderr, "starting to listen on %d\n", s.port)
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", s.port))
	if err != nil {
		return err
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Fprintln(os.Stderr, "failed to accept connection:", err)
			continue
		}
		s.connections = append(s.connections, conn)
		go handleConnection(conn)
	}
}

func main() {
	flag.Parse()

	server := &server{
		port:        *port,
		connections: []net.Conn{},
	}

	if err := server.start(); err != nil {
		fmt.Fprintln(os.Stderr, "failed to listen:", err)
		os.Exit(1)
	}
}
<commit_msg>jiggery<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	rfc3164 "github.com/jeromer/syslogparser/rfc3164"
	"net"
	"os"
	"os/signal"
)

var (
	port  = flag.Int("port", 514, "port on which to listen")
	debug = flag.Bool("debug", false, "print all messages to stdout")
)

type server struct {
	port        int
	debug       bool
	connections []net.Conn
}

func (s *server) process(line []byte) {
	p := rfc3164.NewParser(line)
	if err := p.Parse(); err != nil {
		fmt.Fprintln(os.Stderr, "failed to parse:", err)
		return
	}

	if s.debug {
		for k, v := range p.Dump() {
			fmt.Println(k, ":", v)
		}
	}
}

func (s *server) handleConnection(conn net.Conn) {

	fmt.Fprintln(os.Stderr, "got connection from:", conn.RemoteAddr())
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		s.process([]byte(scanner.Text()))
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "error reading from connection:", err)
	}

}

func (s *server) handleInterrupt() {
	interrupts := make(chan os.Signal, 1)
	signal.Notify(interrupts, os.Interrupt)

	go func() {
		<-interrupts
		fmt.Fprintln(os.Stderr, "got interrupt signal, closing", len(s.connections), "connections")

		for _, conn := range s.connections {
			fmt.Fprintln(os.Stderr, "closing connection to", conn.RemoteAddr())
			conn.Close()
		}

		os.Exit(0)
	}()
}

func (s *server) start() error {
	s.handleInterrupt()

	fmt.Fprintf(os.Stderr, "starting to listen on %d\n", s.port)
	if s.debug {
		fmt.Fprintln(os.Stderr, "debug is enabled, all messages will be printed to stderr")
	}

	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", s.port))
	if err != nil {
		return err
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Fprintln(os.Stderr, "failed to accept connection:", err)
			continue
		}
		s.connections = append(s.connections, conn)
		go s.handleConnection(conn)
	}
}

func main() {
	flag.Parse()

	server := &server{
		port:        *port,
		debug:       *debug,
		connections: []net.Conn{},
	}

	if err := server.start(); err != nil {
		fmt.Fprintln(os.Stderr, "failed to listen:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/byuoitav/authmiddleware"
	"github.com/byuoitav/device-monitoring-microservice/statusinfrastructure"
	"github.com/byuoitav/event-router-microservice/eventinfrastructure"
	"github.com/byuoitav/touchpanel-ui-microservice/events"
	"github.com/byuoitav/touchpanel-ui-microservice/handlers"
	"github.com/byuoitav/touchpanel-ui-microservice/socket"
	"github.com/byuoitav/touchpanel-ui-microservice/uiconfig"
	"github.com/jessemillar/health"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
	filters := []string{eventinfrastructure.UI, eventinfrastructure.UIFeature}
	en := eventinfrastructure.NewEventNode("Touchpanel UI", filters, os.Getenv("EVENT_ROUTER_ADDRESS"))

	// websocket hub
	hub := socket.NewHub()
	go events.WriteEventsToSocket(en, hub)
	go events.SendRefresh(hub, time.NewTimer(time.Second*10))

	port := ":8888"
	router := echo.New()
	router.Pre(middleware.RemoveTrailingSlash())
	router.Use(middleware.CORS())
	router.Use(echo.WrapMiddleware(authmiddleware.CAS))

	router.GET("/health", echo.WrapHandler(http.HandlerFunc(health.Check)))
	router.GET("/mstatus", GetStatus)

	// event endpoints
	router.POST("/publish", handlers.PublishEvent, BindEventNode(en))
	router.POST("/publishfeature", handlers.PublishFeature, BindEventNode(en))

	// websocket
	router.GET("/websocket", func(context echo.Context) error {
		socket.ServeWebsocket(hub, context.Response().Writer, context.Request())
		return nil
	})

	// socket endpoints
	router.PUT("/screenoff", func(context echo.Context) error {
		events.SendScreenTimeout(hub)
		return nil
	})
	router.PUT("/refresh", func(context echo.Context) error {
		events.SendRefresh(hub, time.NewTimer(0))
		return nil
	})
	router.GET("/wsinfo", func(context echo.Context) error {
		si, _ := socket.GetSocketInfo(hub)
		return context.JSON(http.StatusOK, si)
	})
	router.PUT("/socketTest", func(context echo.Context) error {
		events.SendTest(hub)
		return context.JSON(http.StatusOK, "sent")
	})

	router.GET("/pihostname", handlers.GetPiHostname)
	router.GET("/hostname", handlers.GetHostname)
	router.GET("/deviceinfo", handlers.GetDeviceInfo)
	router.GET("/reboot", handlers.Reboot)
	router.GET("/dockerstatus", handlers.GetDockerStatus)

	router.GET("/uiconfig", uiconfig.GetUIConfig)
	router.GET("/uipath", uiconfig.GetUIPath)
	router.GET("/api", uiconfig.GetAPI)
	router.GET("/nextapi", uiconfig.NextAPI)

	router.POST("/help", handlers.Help)
	router.POST("/confirmhelp", handlers.ConfirmHelp)
	router.POST("/cancelhelp", handlers.CancelHelp)

	// all the different ui's
	router.Static("/", "redirect.html")
	router.Any("/404", redirect)
	router.Static("/blueberry", "blueberry-dist")

	router.Start(port)
}

func BindEventNode(en *eventinfrastructure.EventNode) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set(eventinfrastructure.ContextEventNode, en)
			return next(c)
		}
	}
}

func GetStatus(context echo.Context) error {
	var s statusinfrastructure.Status
	var err error

	s.Version, err = statusinfrastructure.GetVersion("version.txt")
	if err != nil {
		s.Version = "missing"
		s.Status = statusinfrastructure.StatusSick
		s.StatusInfo = fmt.Sprintf("Error: %s", err.Error())
	} else {
		s.Status = statusinfrastructure.StatusOK
		s.StatusInfo = ""
	}

	return context.JSON(http.StatusOK, s)
}

func redirect(context echo.Context) error {
	http.Redirect(context.Response().Writer, context.Request(), "http://github.com/404", 302)
	return nil
}
<commit_msg>remove auth middleware<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/byuoitav/device-monitoring-microservice/statusinfrastructure"
	"github.com/byuoitav/event-router-microservice/eventinfrastructure"
	"github.com/byuoitav/touchpanel-ui-microservice/events"
	"github.com/byuoitav/touchpanel-ui-microservice/handlers"
	"github.com/byuoitav/touchpanel-ui-microservice/socket"
	"github.com/byuoitav/touchpanel-ui-microservice/uiconfig"
	"github.com/jessemillar/health"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
	filters := []string{eventinfrastructure.UI, eventinfrastructure.UIFeature}
	en := eventinfrastructure.NewEventNode("Touchpanel UI", filters, os.Getenv("EVENT_ROUTER_ADDRESS"))

	// websocket hub
	hub := socket.NewHub()
	go events.WriteEventsToSocket(en, hub)
	go events.SendRefresh(hub, time.NewTimer(time.Second*10))

	port := ":8888"
	router := echo.New()
	router.Pre(middleware.RemoveTrailingSlash())
	router.Use(middleware.CORS())

	router.GET("/health", echo.WrapHandler(http.HandlerFunc(health.Check)))
	router.GET("/mstatus", GetStatus)

	// event endpoints
	router.POST("/publish", handlers.PublishEvent, BindEventNode(en))
	router.POST("/publishfeature", handlers.PublishFeature, BindEventNode(en))

	// websocket
	router.GET("/websocket", func(context echo.Context) error {
		socket.ServeWebsocket(hub, context.Response().Writer, context.Request())
		return nil
	})

	// socket endpoints
	router.PUT("/screenoff", func(context echo.Context) error {
		events.SendScreenTimeout(hub)
		return nil
	})
	router.PUT("/refresh", func(context echo.Context) error {
		events.SendRefresh(hub, time.NewTimer(0))
		return nil
	})
	router.GET("/wsinfo", func(context echo.Context) error {
		si, _ := socket.GetSocketInfo(hub)
		return context.JSON(http.StatusOK, si)
	})
	router.PUT("/socketTest", func(context echo.Context) error {
		events.SendTest(hub)
		return context.JSON(http.StatusOK, "sent")
	})

	router.GET("/pihostname", handlers.GetPiHostname)
	router.GET("/hostname", handlers.GetHostname)
	router.GET("/deviceinfo", handlers.GetDeviceInfo)
	router.GET("/reboot", handlers.Reboot)
	router.GET("/dockerstatus", handlers.GetDockerStatus)

	router.GET("/uiconfig", uiconfig.GetUIConfig)
	router.GET("/uipath", uiconfig.GetUIPath)
	router.GET("/api", uiconfig.GetAPI)
	router.GET("/nextapi", uiconfig.NextAPI)

	router.POST("/help", handlers.Help)
	router.POST("/confirmhelp", handlers.ConfirmHelp)
	router.POST("/cancelhelp", handlers.CancelHelp)

	// all the different ui's
	router.Static("/", "redirect.html")
	router.Any("/404", redirect)
	router.Static("/blueberry", "blueberry-dist")

	router.Start(port)
}

func BindEventNode(en *eventinfrastructure.EventNode) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set(eventinfrastructure.ContextEventNode, en)
			return next(c)
		}
	}
}

func GetStatus(context echo.Context) error {
	var s statusinfrastructure.Status
	var err error

	s.Version, err = statusinfrastructure.GetVersion("version.txt")
	if err != nil {
		s.Version = "missing"
		s.Status = statusinfrastructure.StatusSick
		s.StatusInfo = fmt.Sprintf("Error: %s", err.Error())
	} else {
		s.Status = statusinfrastructure.StatusOK
		s.StatusInfo = ""
	}

	return context.JSON(http.StatusOK, s)
}

func redirect(context echo.Context) error {
	http.Redirect(context.Response().Writer, context.Request(), "http://github.com/404", 302)
	return nil
}
<|endoftext|>


<commit_before>package veneur

import (
	"bytes"
	"net"
	"net/http"
	"sync"
	"syscall"
	"time"

	"github.com/DataDog/datadog-go/statsd"
	"github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/getsentry/raven-go"
	"github.com/golang/protobuf/proto"
	"github.com/stripe/veneur/ssf"
	"github.com/zenazn/goji/bind"
	"github.com/zenazn/goji/graceful"

	"github.com/pkg/profile"

	"github.com/stripe/veneur/plugins"
	s3p "github.com/stripe/veneur/plugins/s3"
	"github.com/stripe/veneur/samplers"
)

// VERSION stores the current veneur version.
// It must be a var so it can be set at link time.
var VERSION = "dirty"

var profileStartOnce = sync.Once{}

var log = logrus.New()

// A Server is the actual veneur instance that will be run.
type Server struct {
	Workers     []*Worker
	EventWorker *EventWorker
	TraceWorker *TraceWorker

	statsd *statsd.Client
	sentry *raven.Client

	Hostname string
	Tags     []string

	DDHostname     string
	DDAPIKey       string
	DDTraceAddress string
	HTTPClient     *http.Client

	HTTPAddr    string
	ForwardAddr string
	UDPAddr     *net.UDPAddr
	TraceAddr   *net.UDPAddr
	RcvbufBytes int

	HistogramPercentiles []float64

	plugins   []plugins.Plugin
	pluginMtx sync.Mutex

	enableProfiling bool

	HistogramAggregates samplers.HistogramAggregates
}

// NewFromConfig creates a new veneur server from a configuration specification.
func NewFromConfig(conf Config) (ret Server, err error) {
	ret.Hostname = conf.Hostname
	ret.Tags = conf.Tags
	ret.DDHostname = conf.APIHostname
	ret.DDAPIKey = conf.Key
	ret.DDTraceAddress = conf.TraceAPIAddress
	ret.HistogramPercentiles = conf.Percentiles
	if len(conf.Aggregates) == 0 {
		ret.HistogramAggregates.Value = samplers.AggregateMin + samplers.AggregateMax + samplers.AggregateCount
		ret.HistogramAggregates.Count = 3
	} else {
		ret.HistogramAggregates.Value = 0
		for _, agg := range conf.Aggregates {
			ret.HistogramAggregates.Value += samplers.AggregatesLookup[agg]
		}
		ret.HistogramAggregates.Count = len(conf.Aggregates)
	}

	interval, err := time.ParseDuration(conf.Interval)
	if err != nil {
		return
	}
	ret.HTTPClient = &http.Client{
		// make sure that POSTs to datadog do not overflow the flush interval
		Timeout: interval * 9 / 10,
		// we're fine with using the default transport and redirect behavior
	}

	ret.statsd, err = statsd.NewBuffered(conf.StatsAddress, 1024)
	if err != nil {
		return
	}
	ret.statsd.Namespace = "veneur."
	ret.statsd.Tags = append(ret.Tags, "veneurlocalonly")

	// nil is a valid sentry client that noops all methods, if there is no DSN
	// we can just leave it as nil
	if conf.SentryDsn != "" {
		ret.sentry, err = raven.New(conf.SentryDsn)
		if err != nil {
			return
		}
	}

	if conf.Debug {
		log.Level = logrus.DebugLevel
	}

	if conf.EnableProfiling {
		ret.enableProfiling = true
	}

	log.Hooks.Add(sentryHook{
		c:        ret.sentry,
		hostname: ret.Hostname,
		lv: []logrus.Level{
			logrus.ErrorLevel,
			logrus.FatalLevel,
			logrus.PanicLevel,
		},
	})
	log.WithField("version", VERSION).Info("Starting server")

	log.WithField("number", conf.NumWorkers).Info("Starting workers")
	ret.Workers = make([]*Worker, conf.NumWorkers)
	for i := range ret.Workers {
		ret.Workers[i] = NewWorker(i+1, ret.statsd, log)
		// do not close over loop index
		go func(w *Worker) {
			defer func() {
				ret.ConsumePanic(recover())
			}()
			w.Work()
		}(ret.Workers[i])
	}

	ret.EventWorker = NewEventWorker(ret.statsd)
	go func() {
		defer func() {
			ret.ConsumePanic(recover())
		}()
		ret.EventWorker.Work()
	}()

	ret.TraceWorker = NewTraceWorker(ret.statsd)
	go func() {
		defer func() {
			ret.ConsumePanic(recover())
		}()
		ret.TraceWorker.Work()
	}()

	ret.UDPAddr, err = net.ResolveUDPAddr("udp", conf.UdpAddress)
	if err != nil {
		return
	}
	ret.RcvbufBytes = conf.ReadBufferSizeBytes
	ret.HTTPAddr = conf.HTTPAddress
	ret.ForwardAddr = conf.ForwardAddress

	conf.Key = "REDACTED"
	conf.SentryDsn = "REDACTED"
	log.WithField("config", conf).Debug("Initialized server")

	if len(conf.TraceAddress) > 0 {
		ret.TraceAddr, err = net.ResolveUDPAddr("udp", conf.TraceAddress)
		if err != nil {
			return
		}
	}

	var svc s3iface.S3API = nil
	aws_id := conf.AwsAccessKeyID
	aws_secret := conf.AwsSecretAccessKey

	conf.AwsAccessKeyID = "REDACTED"
	conf.AwsSecretAccessKey = "REDACTED"

	if len(aws_id) > 0 && len(aws_secret) > 0 {
		sess, err := session.NewSession(&aws.Config{
			Region:      aws.String(conf.AwsRegion),
			Credentials: credentials.NewStaticCredentials(aws_id, aws_secret, ""),
		})

		if err != nil {
			log.Info("error getting AWS session: %s", err)
			svc = nil
		} else {
			log.Info("Successfully created AWS session")
			svc = s3.New(sess)

			plugin := &s3p.S3Plugin{
				Logger:   log,
				Svc:      svc,
				S3Bucket: conf.AwsS3Bucket,
				Hostname: ret.Hostname,
			}
			ret.registerPlugin(plugin)
		}
	} else {
		log.Info("AWS credentials not found")
	}

	if svc == nil {
		log.Info("S3 archives are disabled")
	} else {
		log.Info("S3 archives are enabled")
	}

	return
}

// HandleMetricPacket processes each packet that is sent to the server, and sends to an
// appropriate worker (EventWorker or Worker).
func (s *Server) HandleMetricPacket(packet []byte) {
	// This is a very performance-sensitive function
	// and packets may be dropped if it gets slowed down.
	// Keep that in mind when modifying!

	if len(packet) == 0 {
		// a lot of clients send packets that accidentally have a trailing
		// newline, it's easier to just let them be
		return
	}

	if bytes.HasPrefix(packet, []byte{'_', 'e', '{'}) {
		event, err := samplers.ParseEvent(packet)
		if err != nil {
			log.WithFields(logrus.Fields{
				logrus.ErrorKey: err,
				"packet":        string(packet),
			}).Error("Could not parse packet")
			s.statsd.Count("packet.error_total", 1, []string{"packet_type:event"}, 1.0)
			return
		}
		s.EventWorker.EventChan <- *event
	} else if bytes.HasPrefix(packet, []byte{'_', 's', 'c'}) {
		svcheck, err := samplers.ParseServiceCheck(packet)
		if err != nil {
			log.WithFields(logrus.Fields{
				logrus.ErrorKey: err,
				"packet":        string(packet),
			}).Error("Could not parse packet")
			s.statsd.Count("packet.error_total", 1, []string{"packet_type:service_check"}, 1.0)
			return
		}
		s.EventWorker.ServiceCheckChan <- *svcheck
	} else {
		metric, err := samplers.ParseMetric(packet)
		if err != nil {
			log.WithFields(logrus.Fields{
				logrus.ErrorKey: err,
				"packet":        string(packet),
			}).Error("Could not parse packet")
			s.statsd.Count("packet.error_total", 1, []string{"packet_type:metric"}, 1.0)
			return
		}
		s.Workers[metric.Digest%uint32(len(s.Workers))].PacketChan <- *metric
	}
}

func (s *Server) HandleTracePacket(packet []byte) {
	if len(packet) == 0 {
		return
	}

	// Technically this could be anything, but we're only consuming trace spans
	// for now.
	newSample := &ssf.SSFSample{}
	err := proto.Unmarshal(packet, newSample)
	if err != nil {
		log.Fatal("Trace unmarshaling error: ", err)
	}
	log.WithField("proto", proto.CompactTextString(newSample)).Error("Handling trace packet")

	s.TraceWorker.TraceChan <- *newSample
}

// ReadMetricSocket listens for available packets to handle.
func (s *Server) ReadMetricSocket(packetPool *sync.Pool, reuseport bool) {
	// each goroutine gets its own socket
	// if the sockets support SO_REUSEPORT, then this will cause the
	// kernel to distribute datagrams across them, for better read
	// performance
	serverConn, err := NewSocket(s.UDPAddr, s.RcvbufBytes, reuseport)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		log.WithError(err).Fatal("Error listening for UDP metrics")
	}
	log.WithField("address", s.UDPAddr).Info("Listening for UDP metrics")

	for {
		buf := packetPool.Get().([]byte)
		n, _, err := serverConn.ReadFrom(buf)
		if err != nil {
			log.WithError(err).Error("Error reading from UDP metrics socket")
			continue
		}

		// statsd allows multiple packets to be joined by newlines and sent as
		// one larger packet
		// note that spurious newlines are not allowed in this format, it has
		// to be exactly one newline between each packet, with no leading or
		// trailing newlines
		splitPacket := samplers.NewSplitBytes(buf[:n], '\n')
		for splitPacket.Next() {
			s.HandleMetricPacket(splitPacket.Chunk())
		}

		// the Metric struct created by HandleMetricPacket has no byte slices in it,
		// only strings
		// therefore there are no outstanding references to this byte slice, we
		// can return it to the pool
		packetPool.Put(buf)
	}
}

// ReadTraceSocket listens for available packets to handle.
func (s *Server) ReadTraceSocket(packetPool *sync.Pool, reuseport bool) {
	// TODO This is duplicated from ReadMetricSocket and feels like it could be it's
	// own function?
	serverConn, err := NewSocket(s.TraceAddr, s.RcvbufBytes, reuseport)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		log.WithError(err).Fatal("Error listening for UDP traces")
	}
	log.WithField("address", s.TraceAddr).Info("Listening for UDP traces")

	for {
		buf := packetPool.Get().([]byte)
		n, _, err := serverConn.ReadFrom(buf)
		if err != nil {
			log.WithError(err).Error("Error reading from UDP metrics socket")
			continue
		}

		s.HandleTracePacket(buf[:n])
	}
}

// HTTPServe starts the HTTP server and listens perpetually until it encounters an unrecoverable error.
func (s *Server) HTTPServe() {
	var prf interface {
		Stop()
	}

	// We want to make sure the profile is stopped
	// exactly once (and only once), even if the
	// shutdown pre-hook does not run (which it may not)
	profileStopOnce := sync.Once{}

	if s.enableProfiling {
		profileStartOnce.Do(func() {
			prf = profile.Start()
		})

		defer func() {
			profileStopOnce.Do(prf.Stop)
		}()
	}
	httpSocket := bind.Socket(s.HTTPAddr)
	graceful.Timeout(10 * time.Second)
	graceful.PreHook(func() {

		if prf != nil {
			profileStopOnce.Do(prf.Stop)
		}

		log.Info("Terminating HTTP listener")
	})

	// Ensure that the server responds to SIGUSR2 even
	// when *not* running under einhorn.
	graceful.AddSignal(syscall.SIGUSR2, syscall.SIGHUP)
	graceful.HandleSignals()
	log.WithField("address", s.HTTPAddr).Info("HTTP server listening")
	bind.Ready()

	if err := graceful.Serve(httpSocket, s.Handler()); err != nil {
		log.WithError(err).Error("HTTP server shut down due to error")
	}

	graceful.Shutdown()
}

// Shutdown signals the server to shut down after closing all
// current connections.
func (s *Server) Shutdown() {
	// TODO(aditya) shut down workers and socket readers
	log.Info("Shutting down server gracefully")
	graceful.Shutdown()
}

// IsLocal indicates whether veneur is running as a local instance
// (forwarding non-local data to a global veneur instance) or is running as a global
// instance (sending all data directly to the final destination).
func (s *Server) IsLocal() bool {
	return s.ForwardAddr != ""
}

// registerPlugin registers a plugin for use
// on the veneur server. It is blocking
// and not threadsafe.
func (s *Server) registerPlugin(p plugins.Plugin) {
	s.pluginMtx.Lock()
	defer s.pluginMtx.Unlock()
	s.plugins = append(s.plugins, p)
}

func (s *Server) getPlugins() []plugins.Plugin {
	s.pluginMtx.Lock()
	plugins := make([]plugins.Plugin, len(s.plugins))
	copy(plugins, s.plugins)
	s.pluginMtx.Unlock()
	return plugins
}
<commit_msg>Check that UDP address resolves to non-nil value<commit_after>package veneur

import (
	"bytes"
	"errors"
	"net"
	"net/http"
	"sync"
	"syscall"
	"time"

	"github.com/DataDog/datadog-go/statsd"
	"github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/getsentry/raven-go"
	"github.com/golang/protobuf/proto"
	"github.com/stripe/veneur/ssf"
	"github.com/zenazn/goji/bind"
	"github.com/zenazn/goji/graceful"

	"github.com/pkg/profile"

	"github.com/stripe/veneur/plugins"
	s3p "github.com/stripe/veneur/plugins/s3"
	"github.com/stripe/veneur/samplers"
)

// VERSION stores the current veneur version.
// It must be a var so it can be set at link time.
var VERSION = "dirty"

var profileStartOnce = sync.Once{}

var log = logrus.New()

// A Server is the actual veneur instance that will be run.
type Server struct {
	Workers     []*Worker
	EventWorker *EventWorker
	TraceWorker *TraceWorker

	statsd *statsd.Client
	sentry *raven.Client

	Hostname string
	Tags     []string

	DDHostname     string
	DDAPIKey       string
	DDTraceAddress string
	HTTPClient     *http.Client

	HTTPAddr    string
	ForwardAddr string
	UDPAddr     *net.UDPAddr
	TraceAddr   *net.UDPAddr
	RcvbufBytes int

	HistogramPercentiles []float64

	plugins   []plugins.Plugin
	pluginMtx sync.Mutex

	enableProfiling bool

	HistogramAggregates samplers.HistogramAggregates
}

// NewFromConfig creates a new veneur server from a configuration specification.
func NewFromConfig(conf Config) (ret Server, err error) {
	ret.Hostname = conf.Hostname
	ret.Tags = conf.Tags
	ret.DDHostname = conf.APIHostname
	ret.DDAPIKey = conf.Key
	ret.DDTraceAddress = conf.TraceAPIAddress
	ret.HistogramPercentiles = conf.Percentiles
	if len(conf.Aggregates) == 0 {
		ret.HistogramAggregates.Value = samplers.AggregateMin + samplers.AggregateMax + samplers.AggregateCount
		ret.HistogramAggregates.Count = 3
	} else {
		ret.HistogramAggregates.Value = 0
		for _, agg := range conf.Aggregates {
			ret.HistogramAggregates.Value += samplers.AggregatesLookup[agg]
		}
		ret.HistogramAggregates.Count = len(conf.Aggregates)
	}

	interval, err := time.ParseDuration(conf.Interval)
	if err != nil {
		return
	}
	ret.HTTPClient = &http.Client{
		// make sure that POSTs to datadog do not overflow the flush interval
		Timeout: interval * 9 / 10,
		// we're fine with using the default transport and redirect behavior
	}

	ret.statsd, err = statsd.NewBuffered(conf.StatsAddress, 1024)
	if err != nil {
		return
	}
	ret.statsd.Namespace = "veneur."
	ret.statsd.Tags = append(ret.Tags, "veneurlocalonly")

	// nil is a valid sentry client that noops all methods, if there is no DSN
	// we can just leave it as nil
	if conf.SentryDsn != "" {
		ret.sentry, err = raven.New(conf.SentryDsn)
		if err != nil {
			return
		}
	}

	if conf.Debug {
		log.Level = logrus.DebugLevel
	}

	if conf.EnableProfiling {
		ret.enableProfiling = true
	}

	log.Hooks.Add(sentryHook{
		c:        ret.sentry,
		hostname: ret.Hostname,
		lv: []logrus.Level{
			logrus.ErrorLevel,
			logrus.FatalLevel,
			logrus.PanicLevel,
		},
	})
	log.WithField("version", VERSION).Info("Starting server")

	log.WithField("number", conf.NumWorkers).Info("Starting workers")
	ret.Workers = make([]*Worker, conf.NumWorkers)
	for i := range ret.Workers {
		ret.Workers[i] = NewWorker(i+1, ret.statsd, log)
		// do not close over loop index
		go func(w *Worker) {
			defer func() {
				ret.ConsumePanic(recover())
			}()
			w.Work()
		}(ret.Workers[i])
	}

	ret.EventWorker = NewEventWorker(ret.statsd)
	go func() {
		defer func() {
			ret.ConsumePanic(recover())
		}()
		ret.EventWorker.Work()
	}()

	ret.TraceWorker = NewTraceWorker(ret.statsd)
	go func() {
		defer func() {
			ret.ConsumePanic(recover())
		}()
		ret.TraceWorker.Work()
	}()

	ret.UDPAddr, err = net.ResolveUDPAddr("udp", conf.UdpAddress)
	if err != nil {
		return
	}
	ret.RcvbufBytes = conf.ReadBufferSizeBytes
	ret.HTTPAddr = conf.HTTPAddress
	ret.ForwardAddr = conf.ForwardAddress

	conf.Key = "REDACTED"
	conf.SentryDsn = "REDACTED"
	log.WithField("config", conf).Debug("Initialized server")

	if len(conf.TraceAddress) > 0 {
		ret.TraceAddr, err = net.ResolveUDPAddr("udp", conf.TraceAddress)
		if err == nil && ret.TraceAddr == nil {
			err = errors.New("resolved nil UDP address")
		}
		if err != nil {
			return
		}
	}

	var svc s3iface.S3API = nil
	aws_id := conf.AwsAccessKeyID
	aws_secret := conf.AwsSecretAccessKey

	conf.AwsAccessKeyID = "REDACTED"
	conf.AwsSecretAccessKey = "REDACTED"

	if len(aws_id) > 0 && len(aws_secret) > 0 {
		sess, err := session.NewSession(&aws.Config{
			Region:      aws.String(conf.AwsRegion),
			Credentials: credentials.NewStaticCredentials(aws_id, aws_secret, ""),
		})

		if err != nil {
			log.Info("error getting AWS session: %s", err)
			svc = nil
		} else {
			log.Info("Successfully created AWS session")
			svc = s3.New(sess)

			plugin := &s3p.S3Plugin{
				Logger:   log,
				Svc:      svc,
				S3Bucket: conf.AwsS3Bucket,
				Hostname: ret.Hostname,
			}
			ret.registerPlugin(plugin)
		}
	} else {
		log.Info("AWS credentials not found")
	}

	if svc == nil {
		log.Info("S3 archives are disabled")
	} else {
		log.Info("S3 archives are enabled")
	}

	return
}

// HandleMetricPacket processes each packet that is sent to the server, and sends to an
// appropriate worker (EventWorker or Worker).
func (s *Server) HandleMetricPacket(packet []byte) {
	// This is a very performance-sensitive function
	// and packets may be dropped if it gets slowed down.
	// Keep that in mind when modifying!

	if len(packet) == 0 {
		// a lot of clients send packets that accidentally have a trailing
		// newline, it's easier to just let them be
		return
	}

	if bytes.HasPrefix(packet, []byte{'_', 'e', '{'}) {
		event, err := samplers.ParseEvent(packet)
		if err != nil {
			log.WithFields(logrus.Fields{
				logrus.ErrorKey: err,
				"packet":        string(packet),
			}).Error("Could not parse packet")
			s.statsd.Count("packet.error_total", 1, []string{"packet_type:event"}, 1.0)
			return
		}
		s.EventWorker.EventChan <- *event
	} else if bytes.HasPrefix(packet, []byte{'_', 's', 'c'}) {
		svcheck, err := samplers.ParseServiceCheck(packet)
		if err != nil {
			log.WithFields(logrus.Fields{
				logrus.ErrorKey: err,
				"packet":        string(packet),
			}).Error("Could not parse packet")
			s.statsd.Count("packet.error_total", 1, []string{"packet_type:service_check"}, 1.0)
			return
		}
		s.EventWorker.ServiceCheckChan <- *svcheck
	} else {
		metric, err := samplers.ParseMetric(packet)
		if err != nil {
			log.WithFields(logrus.Fields{
				logrus.ErrorKey: err,
				"packet":        string(packet),
			}).Error("Could not parse packet")
			s.statsd.Count("packet.error_total", 1, []string{"packet_type:metric"}, 1.0)
			return
		}
		s.Workers[metric.Digest%uint32(len(s.Workers))].PacketChan <- *metric
	}
}

func (s *Server) HandleTracePacket(packet []byte) {
	if len(packet) == 0 {
		return
	}

	// Technically this could be anything, but we're only consuming trace spans
	// for now.
	newSample := &ssf.SSFSample{}
	err := proto.Unmarshal(packet, newSample)
	if err != nil {
		log.Fatal("Trace unmarshaling error: ", err)
	}
	log.WithField("proto", proto.CompactTextString(newSample)).Error("Handling trace packet")

	s.TraceWorker.TraceChan <- *newSample
}

// ReadMetricSocket listens for available packets to handle.
func (s *Server) ReadMetricSocket(packetPool *sync.Pool, reuseport bool) {
	// each goroutine gets its own socket
	// if the sockets support SO_REUSEPORT, then this will cause the
	// kernel to distribute datagrams across them, for better read
	// performance
	serverConn, err := NewSocket(s.UDPAddr, s.RcvbufBytes, reuseport)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		log.WithError(err).Fatal("Error listening for UDP metrics")
	}
	log.WithField("address", s.UDPAddr).Info("Listening for UDP metrics")

	for {
		buf := packetPool.Get().([]byte)
		n, _, err := serverConn.ReadFrom(buf)
		if err != nil {
			log.WithError(err).Error("Error reading from UDP metrics socket")
			continue
		}

		// statsd allows multiple packets to be joined by newlines and sent as
		// one larger packet
		// note that spurious newlines are not allowed in this format, it has
		// to be exactly one newline between each packet, with no leading or
		// trailing newlines
		splitPacket := samplers.NewSplitBytes(buf[:n], '\n')
		for splitPacket.Next() {
			s.HandleMetricPacket(splitPacket.Chunk())
		}

		// the Metric struct created by HandleMetricPacket has no byte slices in it,
		// only strings
		// therefore there are no outstanding references to this byte slice, we
		// can return it to the pool
		packetPool.Put(buf)
	}
}

// ReadTraceSocket listens for available packets to handle.
func (s *Server) ReadTraceSocket(packetPool *sync.Pool, reuseport bool) {
	// TODO This is duplicated from ReadMetricSocket and feels like it could be it's
	// own function?
	serverConn, err := NewSocket(s.TraceAddr, s.RcvbufBytes, reuseport)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		log.WithError(err).Fatal("Error listening for UDP traces")
	}
	log.WithField("address", s.TraceAddr).Info("Listening for UDP traces")

	for {
		buf := packetPool.Get().([]byte)
		n, _, err := serverConn.ReadFrom(buf)
		if err != nil {
			log.WithError(err).Error("Error reading from UDP metrics socket")
			continue
		}

		s.HandleTracePacket(buf[:n])
	}
}

// HTTPServe starts the HTTP server and listens perpetually until it encounters an unrecoverable error.
func (s *Server) HTTPServe() {
	var prf interface {
		Stop()
	}

	// We want to make sure the profile is stopped
	// exactly once (and only once), even if the
	// shutdown pre-hook does not run (which it may not)
	profileStopOnce := sync.Once{}

	if s.enableProfiling {
		profileStartOnce.Do(func() {
			prf = profile.Start()
		})

		defer func() {
			profileStopOnce.Do(prf.Stop)
		}()
	}
	httpSocket := bind.Socket(s.HTTPAddr)
	graceful.Timeout(10 * time.Second)
	graceful.PreHook(func() {

		if prf != nil {
			profileStopOnce.Do(prf.Stop)
		}

		log.Info("Terminating HTTP listener")
	})

	// Ensure that the server responds to SIGUSR2 even
	// when *not* running under einhorn.
	graceful.AddSignal(syscall.SIGUSR2, syscall.SIGHUP)
	graceful.HandleSignals()
	log.WithField("address", s.HTTPAddr).Info("HTTP server listening")
	bind.Ready()

	if err := graceful.Serve(httpSocket, s.Handler()); err != nil {
		log.WithError(err).Error("HTTP server shut down due to error")
	}

	graceful.Shutdown()
}

// Shutdown signals the server to shut down after closing all
// current connections.
func (s *Server) Shutdown() {
	// TODO(aditya) shut down workers and socket readers
	log.Info("Shutting down server gracefully")
	graceful.Shutdown()
}

// IsLocal indicates whether veneur is running as a local instance
// (forwarding non-local data to a global veneur instance) or is running as a global
// instance (sending all data directly to the final destination).
func (s *Server) IsLocal() bool {
	return s.ForwardAddr != ""
}

// registerPlugin registers a plugin for use
// on the veneur server. It is blocking
// and not threadsafe.
func (s *Server) registerPlugin(p plugins.Plugin) {
	s.pluginMtx.Lock()
	defer s.pluginMtx.Unlock()
	s.plugins = append(s.plugins, p)
}

func (s *Server) getPlugins() []plugins.Plugin {
	s.pluginMtx.Lock()
	plugins := make([]plugins.Plugin, len(s.plugins))
	copy(plugins, s.plugins)
	s.pluginMtx.Unlock()
	return plugins
}
<|endoftext|>


<commit_before>// Package build implements Pipe and can build Go projects for
// several platforms, with pre and post hook support.
package build

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/ext"
	"golang.org/x/sync/errgroup"
)

// Pipe for build
type Pipe struct{}

// Description of the pipe
func (Pipe) Description() string {
	return "Building binaries"
}

// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
	if err := runHook(ctx.Config.Build.Env, ctx.Config.Build.Hooks.Pre); err != nil {
		return err
	}
	sem := make(chan bool, 4)
	var g errgroup.Group
	for _, target := range buildTargets(ctx) {
		name, err := nameFor(ctx, target)
		if err != nil {
			return err
		}
		ctx.Archives[target.String()] = name

		sem <- true
		target := target
		g.Go(func() error {
			defer func() {
				<-sem
			}()
			return build(ctx, name, target)
		})
	}
	if err := g.Wait(); err != nil {
		return err
	}
	return runHook(ctx.Config.Build.Env, ctx.Config.Build.Hooks.Post)
}

func runHook(env []string, hook string) error {
	if hook == "" {
		return nil
	}
	log.Println("Running hook", hook)
	cmd := strings.Fields(hook)
	return run(runtimeTarget, cmd, env)
}

func build(ctx *context.Context, name string, target buildTarget) error {
	output := filepath.Join(
		ctx.Config.Dist,
		name,
		ctx.Config.Build.Binary+ext.For(target.goos),
	)
	log.Println("Building", output)
	cmd := []string{"go", "build"}
	if ctx.Config.Build.Flags != "" {
		cmd = append(cmd, strings.Fields(ctx.Config.Build.Flags)...)
	}
	flags, err := ldflags(ctx)
	if err != nil {
		return err
	}
	cmd = append(cmd, "-ldflags="+flags, "-o", output, ctx.Config.Build.Main)
	return run(target, cmd, ctx.Config.Build.Env)
}

func run(target buildTarget, command, env []string) error {
	cmd := exec.Command(command[0], command[1:]...)
	cmd.Env = append(cmd.Env, os.Environ()...)
	cmd.Env = append(cmd.Env, env...)
	cmd.Env = append(
		cmd.Env,
		"GOOS="+target.goos,
		"GOARCH="+target.goarch,
		"GOARM="+target.goarm,
	)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("build failed: %v\n%v", target, string(out))
	}
	return nil
}
<commit_msg>Clearify build failed error message (cc #244).<commit_after>// Package build implements Pipe and can build Go projects for
// several platforms, with pre and post hook support.
package build

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/ext"
	"golang.org/x/sync/errgroup"
)

// Pipe for build
type Pipe struct{}

// Description of the pipe
func (Pipe) Description() string {
	return "Building binaries"
}

// Run the pipe
func (Pipe) Run(ctx *context.Context) error {
	if err := runHook(ctx.Config.Build.Env, ctx.Config.Build.Hooks.Pre); err != nil {
		return err
	}
	sem := make(chan bool, 4)
	var g errgroup.Group
	for _, target := range buildTargets(ctx) {
		name, err := nameFor(ctx, target)
		if err != nil {
			return err
		}
		ctx.Archives[target.String()] = name

		sem <- true
		target := target
		g.Go(func() error {
			defer func() {
				<-sem
			}()
			return build(ctx, name, target)
		})
	}
	if err := g.Wait(); err != nil {
		return err
	}
	return runHook(ctx.Config.Build.Env, ctx.Config.Build.Hooks.Post)
}

func runHook(env []string, hook string) error {
	if hook == "" {
		return nil
	}
	log.Println("Running hook", hook)
	cmd := strings.Fields(hook)
	return run(runtimeTarget, cmd, env)
}

func build(ctx *context.Context, name string, target buildTarget) error {
	output := filepath.Join(
		ctx.Config.Dist,
		name,
		ctx.Config.Build.Binary+ext.For(target.goos),
	)
	log.Println("Building", output)
	cmd := []string{"go", "build"}
	if ctx.Config.Build.Flags != "" {
		cmd = append(cmd, strings.Fields(ctx.Config.Build.Flags)...)
	}
	flags, err := ldflags(ctx)
	if err != nil {
		return err
	}
	cmd = append(cmd, "-ldflags="+flags, "-o", output, ctx.Config.Build.Main)
	return run(target, cmd, ctx.Config.Build.Env)
}

func run(target buildTarget, command, env []string) error {
	cmd := exec.Command(command[0], command[1:]...)
	cmd.Env = append(cmd.Env, os.Environ()...)
	cmd.Env = append(cmd.Env, env...)
	cmd.Env = append(
		cmd.Env,
		"GOOS="+target.goos,
		"GOARCH="+target.goarch,
		"GOARM="+target.goarm,
	)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("build failed: %s/%s %s\n%v", target.goos, target.goarch, target.goarm, string(out))
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// +k8s:deepcopy-gen=package
// +groupName=metrics.k8s.io

// Package metrics defines an API for exposing metics.
package metrics // import "k8s.io/metrics/pkg/apis/metrics"
<commit_msg>Update Metrics doc as there is a typo in package<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// +k8s:deepcopy-gen=package
// +groupName=metrics.k8s.io

// Package metrics defines an API for exposing metrics.
package metrics // import "k8s.io/metrics/pkg/apis/metrics"
<|endoftext|>


<commit_before>package board

import (
	"fmt"
	"testing"
)

func TestLogBoard(t *testing.T) {

	bh := BoardHarvard{}

	bh.Initialize(9)

	fmt.Printf("%v", bh.LogBoard())

	//	expected := "Hello Go!"
	//	actual := hello()
	//	if actual != expected {
	//		t.Error("Test failed")
	//	}
}
<commit_msg>Add unit test.<commit_after>package board

import (
	"testing"
)

func TestLogBoard(t *testing.T) {

	bh, err := NewBoard(3)
	if err != nil {
		t.Error("Test failed")
	}

	expected := "####\n#...\n#...\n#...\n####\n"
	actual := bh.LogBoard()
	if actual != expected {
		t.Error("Test failed")
	}
}
<|endoftext|>


<commit_before>package chClient

import (
	"fmt"

	"git.containerum.net/ch/kube-client/pkg/cherry"
	"git.containerum.net/ch/kube-client/pkg/cherry/auth"
	"git.containerum.net/ch/kube-client/pkg/cherry/kube-api"
	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/containerum/chkit/pkg/model"
)

const (
	// ErrUnableToGetNamespace -- unable to get namespace
	ErrUnableToGetNamespace chkitErrors.Err = "unable to get namespace"
	// ErrYouDoNotHaveAccessToNamespace -- you don't have access to namespace
	ErrYouDoNotHaveAccessToNamespace chkitErrors.Err = "you don't have access to namespace"
	// ErrNamespaceNotExists -- namespace not exists
	ErrNamespaceNotExists chkitErrors.Err = "namespace not exists"
)

// GetNamespace -- returns info of namespace with given label.
// Returns:
// 	- ErrNamespaceNotExists
//  - ErrWrongPasswordLoginCombination
//  - ErrUserNotExist
func (client *Client) GetNamespace(label string) (model.Namespace, error) {
	var err error
	var namespace kubeClientModels.Namespace
	for i := uint(0); i == 0 || (i < 4 && err != nil); i++ {
		namespace, err = client.kubeAPIClient.GetNamespace(label)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, kubeErrors.ErrResourceNotExist()) ||
			cherry.Equals(err, kubeErrors.ErrAccessError()) ||
			cherry.Equals(err, kubeErrors.ErrUnableGetResource()):
			return model.Namespace{}, ErrNamespaceNotExists
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			switch client.Auth() {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return model.Namespace{}, err
			}
		}
		waitNextAttempt(i)
	}
	return model.NamespaceFromKube(namespace), err
}

func (client *Client) GetNamespaceList() (model.NamespaceList, error) {
	var err error
	var list []kubeClientModels.Namespace
	for i := uint(0); i == 0 || (i < 4 && err != nil); i++ {
		list, err = client.kubeAPIClient.GetNamespaceList(nil)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			fmt.Printf("reauth: %v\n", err)
			err = client.Auth()
			switch err {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return []model.Namespace{}, err
			default:
				fmt.Println(err)
			}
		case cherry.Equals(err, kubeErrors.ErrAccessError()):
			return model.NamespaceList{}, ErrYouDoNotHaveAccessToNamespace
		}
		waitNextAttempt(i)
	}
	return model.NamespaceListFromKube(list), err
}
<commit_msg>fix namespace import path<commit_after>package chClient

import (
	"fmt"

	"git.containerum.net/ch/kube-client/pkg/cherry"
	"git.containerum.net/ch/kube-client/pkg/cherry/auth"
	"git.containerum.net/ch/kube-client/pkg/cherry/kube-api"
	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/containerum/chkit/pkg/model/namespace"
)

const (
	// ErrUnableToGetNamespace -- unable to get namespace
	ErrUnableToGetNamespace chkitErrors.Err = "unable to get namespace"
	// ErrYouDoNotHaveAccessToNamespace -- you don't have access to namespace
	ErrYouDoNotHaveAccessToNamespace chkitErrors.Err = "you don't have access to namespace"
	// ErrNamespaceNotExists -- namespace not exists
	ErrNamespaceNotExists chkitErrors.Err = "namespace not exists"
)

// GetNamespace -- returns info of namespace with given label.
// Returns:
// 	- ErrNamespaceNotExists
//  - ErrWrongPasswordLoginCombination
//  - ErrUserNotExist
func (client *Client) GetNamespace(label string) (namespace.Namespace, error) {
	var err error
	var kubeNamespace kubeClientModels.Namespace
	for i := uint(0); i == 0 || (i < 4 && err != nil); i++ {
		kubeNamespace, err = client.kubeAPIClient.GetNamespace(label)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, kubeErrors.ErrResourceNotExist()) ||
			cherry.Equals(err, kubeErrors.ErrAccessError()) ||
			cherry.Equals(err, kubeErrors.ErrUnableGetResource()):
			return namespace.Namespace{}, ErrNamespaceNotExists
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			switch client.Auth() {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return namespace.Namespace{}, err
			}
		}
		waitNextAttempt(i)
	}
	return namespace.NamespaceFromKube(kubeNamespace), err
}

func (client *Client) GetNamespaceList() (namespace.NamespaceList, error) {
	var err error
	var list []kubeClientModels.Namespace
	for i := uint(0); i == 0 || (i < 4 && err != nil); i++ {
		list, err = client.kubeAPIClient.GetNamespaceList(nil)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			fmt.Printf("reauth: %v\n", err)
			err = client.Auth()
			switch err {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return []namespace.Namespace{}, err
			default:
				fmt.Println(err)
			}
		case cherry.Equals(err, kubeErrors.ErrAccessError()):
			return namespace.NamespaceList{}, ErrYouDoNotHaveAccessToNamespace
		}
		waitNextAttempt(i)
	}
	return namespace.NamespaceListFromKube(list), err
}
<|endoftext|>


<commit_before>package chClient

import (
	"time"

	"git.containerum.net/ch/kube-client/pkg/cherry"
	"git.containerum.net/ch/kube-client/pkg/cherry/auth"
	"git.containerum.net/ch/kube-client/pkg/cherry/kube-api"
	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/containerum/chkit/pkg/model"
)

const (
	// ErrUnableToGetNamespace -- unable to get namespace
	ErrUnableToGetNamespace chkitErrors.Err = "unable to get namespace"
	// ErrNamespaceNotExists -- namespace not exists
	ErrNamespaceNotExists chkitErrors.Err = "namespace not exists"
)

// GetNamespace -- returns info of namespace with given label.
// Returns:
// 	- ErrNamespaceNotExists
//  - ErrWrongPasswordLoginCombination
//  - ErrUserNotExist
func (client *Client) GetNamespace(label string) (model.Namespace, error) {
	var err error
	var namespace kubeClientModels.Namespace
	for i := 0; i == 0 || (i < 4 && err != nil); i++ {
		namespace, err = client.kubeAPIClient.GetNamespace(label)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, kubeErrors.ErrResourceNotExist()) ||
			cherry.Equals(err, kubeErrors.ErrAccessError()) ||
			cherry.Equals(err, kubeErrors.ErrUnableGetResource()):
			return model.Namespace{}, ErrNamespaceNotExists
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			switch client.Auth() {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return model.Namespace{}, err
			}
		}
		time.Sleep(time.Second)
	}
	return model.NamespaceFromKube(namespace), err
}
<commit_msg>add get namespace list method<commit_after>package chClient

import (
	"fmt"
	"time"

	"git.containerum.net/ch/kube-client/pkg/cherry"
	"git.containerum.net/ch/kube-client/pkg/cherry/auth"
	"git.containerum.net/ch/kube-client/pkg/cherry/kube-api"
	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/containerum/chkit/pkg/model"
)

const (
	// ErrUnableToGetNamespace -- unable to get namespace
	ErrUnableToGetNamespace chkitErrors.Err = "unable to get namespace"
	// ErrYouDoNotHaveAccessToNamespace -- you don't have access to namespace
	ErrYouDoNotHaveAccessToNamespace chkitErrors.Err = "you don't have access to namespace"
	// ErrNamespaceNotExists -- namespace not exists
	ErrNamespaceNotExists chkitErrors.Err = "namespace not exists"
)

// GetNamespace -- returns info of namespace with given label.
// Returns:
// 	- ErrNamespaceNotExists
//  - ErrWrongPasswordLoginCombination
//  - ErrUserNotExist
func (client *Client) GetNamespace(label string) (model.Namespace, error) {
	var err error
	var namespace kubeClientModels.Namespace
	for i := 0; i == 0 || (i < 4 && err != nil); i++ {
		namespace, err = client.kubeAPIClient.GetNamespace(label)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, kubeErrors.ErrResourceNotExist()) ||
			cherry.Equals(err, kubeErrors.ErrAccessError()) ||
			cherry.Equals(err, kubeErrors.ErrUnableGetResource()):
			return model.Namespace{}, ErrNamespaceNotExists
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			switch client.Auth() {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return model.Namespace{}, err
			}
		}
		time.Sleep(time.Second)
	}
	return model.NamespaceFromKube(namespace), err
}

func (client *Client) GetNamespaceList() (model.NamespaceList, error) {
	var err error
	var list []kubeClientModels.Namespace
	for i := 0; i == 0 || (i < 4 && err != nil); i++ {
		list, err = client.kubeAPIClient.GetNamespaceList(nil)
		switch {
		case err == nil:
			break
		case cherry.Equals(err, autherr.ErrInvalidToken()) ||
			cherry.Equals(err, autherr.ErrTokenNotFound()):
			fmt.Printf("reauth: %v\n", err)
			err = client.Auth()
			switch err {
			case ErrWrongPasswordLoginCombination, ErrUserNotExist:
				return []model.Namespace{}, err
			default:
				fmt.Println(err)
			}
		case cherry.Equals(err, kubeErrors.ErrAccessError()):
			return model.NamespaceList{}, ErrYouDoNotHaveAccessToNamespace
		}
		time.Sleep(200 * time.Duration(i) * time.Millisecond)
	}
	return model.NamespaceListFromKube(list), err
}
<|endoftext|>