<commit_before>package worker

import (
	"time"

	gocontext "context"

	"github.com/mitchellh/multistep"
	"github.com/sirupsen/logrus"
	"github.com/travis-ci/worker/backend"
	"github.com/travis-ci/worker/context"
)

// A Processor gets jobs off the job queue and coordinates running it with other
// components.
type Processor struct {
	ID       string
	hostname string

	hardTimeout             time.Duration
	initialSleep            time.Duration
	logTimeout              time.Duration
	maxLogLength            int
	scriptUploadTimeout     time.Duration
	startupTimeout          time.Duration
	payloadFilterExecutable string

	ctx                     gocontext.Context
	buildJobsChan           <-chan Job
	provider                backend.Provider
	generator               BuildScriptGenerator
	cancellationBroadcaster *CancellationBroadcaster

	graceful    chan struct{}
	terminate   gocontext.CancelFunc
	shutdown_at time.Time

	// ProcessedCount contains the number of jobs that has been processed
	// by this Processor. This value should not be modified outside of the
	// Processor.
	ProcessedCount int

	// CurrentStatus contains the current status of the processor, and can
	// be one of "new", "waiting", "processing" or "done".
	CurrentStatus string

	// LastJobID contains the ID of the last job the processor processed.
	LastJobID uint64

	SkipShutdownOnLogTimeout bool
}

type ProcessorConfig struct {
	HardTimeout             time.Duration
	InitialSleep            time.Duration
	LogTimeout              time.Duration
	MaxLogLength            int
	ScriptUploadTimeout     time.Duration
	StartupTimeout          time.Duration
	PayloadFilterExecutable string
}

// NewProcessor creates a new processor that will run the build jobs on the
// given channel using the given provider and getting build scripts from the
// generator.
func NewProcessor(ctx gocontext.Context, hostname string, queue JobQueue,
	provider backend.Provider, generator BuildScriptGenerator, cancellationBroadcaster *CancellationBroadcaster,
	config ProcessorConfig) (*Processor, error) {

	processorID, _ := context.ProcessorFromContext(ctx)

	ctx, cancel := gocontext.WithCancel(ctx)

	buildJobsChan, err := queue.Jobs(ctx)
	if err != nil {
		context.LoggerFromContext(ctx).WithField("err", err).Error("couldn't create jobs channel")
		cancel()
		return nil, err
	}

	return &Processor{
		ID:       processorID,
		hostname: hostname,

		initialSleep:            config.InitialSleep,
		hardTimeout:             config.HardTimeout,
		logTimeout:              config.LogTimeout,
		scriptUploadTimeout:     config.ScriptUploadTimeout,
		startupTimeout:          config.StartupTimeout,
		maxLogLength:            config.MaxLogLength,
		payloadFilterExecutable: config.PayloadFilterExecutable,

		ctx:                     ctx,
		buildJobsChan:           buildJobsChan,
		provider:                provider,
		generator:               generator,
		cancellationBroadcaster: cancellationBroadcaster,

		graceful:  make(chan struct{}),
		terminate: cancel,

		CurrentStatus: "new",
	}, nil
}

// Run starts the processor. This method will not return until the processor is
// terminated, either by calling the GracefulShutdown or Terminate methods, or
// if the build jobs channel is closed.
func (p *Processor) Run() {
	logger := context.LoggerFromContext(p.ctx).WithField("self", "processor")
	logger.Info("starting processor")
	defer logger.Info("processor done")
	defer func() { p.CurrentStatus = "done" }()

	for {
		select {
		case <-p.ctx.Done():
			logger.Info("processor is done, terminating")
			return
		case <-p.graceful:
			logger.WithField("shutdown_duration_s", time.Since(p.shutdown_at).Seconds()).Info("processor is done, terminating")
			p.terminate()
			return
		default:
		}

		select {
		case <-p.ctx.Done():
			logger.Info("processor is done, terminating")
			return
		case <-p.graceful:
			logger.WithField("shutdown_duration_s", time.Since(p.shutdown_at).Seconds()).Info("processor is done, terminating")
			p.terminate()
			return
		case buildJob, ok := <-p.buildJobsChan:
			if !ok {
				p.terminate()
				return
			}

			jobID := buildJob.Payload().Job.ID

			hardTimeout := p.hardTimeout
			if buildJob.Payload().Timeouts.HardLimit != 0 {
				hardTimeout = time.Duration(buildJob.Payload().Timeouts.HardLimit) * time.Second
			}
			logger.WithFields(logrus.Fields{
				"hard_timeout": hardTimeout,
				"job_id":       jobID,
			}).Debug("setting hard timeout")
			buildJob.StartAttributes().HardTimeout = hardTimeout

			ctx := context.FromJobID(context.FromRepository(p.ctx, buildJob.Payload().Repository.Slug), buildJob.Payload().Job.ID)
			if buildJob.Payload().UUID != "" {
				ctx = context.FromUUID(ctx, buildJob.Payload().UUID)
			}

			logger.WithFields(logrus.Fields{
				"hard_timeout": hardTimeout,
				"job_id":       jobID,
			}).Debug("getting wrapped context with timeout")
			ctx, cancel := gocontext.WithTimeout(ctx, hardTimeout)

			logger.WithFields(logrus.Fields{
				"job_id": jobID,
				"status": "processing",
			}).Debug("updating processor status and last id")
			p.LastJobID = jobID
			p.CurrentStatus = "processing"

			p.process(ctx, buildJob)

			logger.WithFields(logrus.Fields{
				"job_id": jobID,
				"status": "waiting",
			}).Debug("updating processor status")
			p.CurrentStatus = "waiting"
			cancel()
		case <-time.After(10 * time.Second):
			logger.Debug("timeout waiting for job, shutdown, or context done")
		}
	}
}

// GracefulShutdown tells the processor to finish the job it is currently
// processing, but not pick up any new jobs. This method will return
// immediately, the processor is done when Run() returns.
func (p *Processor) GracefulShutdown() {
	logger := context.LoggerFromContext(p.ctx).WithField("self", "processor")
	defer func() {
		err := recover()
		if err != nil {
			logger.WithField("err", err).Error("recovered from panic")
		}
	}()
	logger.Info("processor initiating graceful shutdown")
	p.shutdown_at = time.Now()
	tryClose(p.graceful)
}

// Terminate tells the processor to stop working on the current job as soon as
// possible.
func (p *Processor) Terminate() {
	p.terminate()
}

func (p *Processor) process(ctx gocontext.Context, buildJob Job) {
	state := new(multistep.BasicStateBag)
	state.Put("hostname", p.ID)
	state.Put("buildJob", buildJob)
	state.Put("procCtx", buildJob.SetupContext(p.ctx))
	state.Put("ctx", buildJob.SetupContext(ctx))

	logger := context.LoggerFromContext(ctx).WithFields(logrus.Fields{
		"job_id": buildJob.Payload().Job.ID,
		"self":   "processor",
	})

	logTimeout := p.logTimeout
	if buildJob.Payload().Timeouts.LogSilence != 0 {
		logTimeout = time.Duration(buildJob.Payload().Timeouts.LogSilence) * time.Second
	}

	steps := []multistep.Step{
		&stepSubscribeCancellation{
			cancellationBroadcaster: p.cancellationBroadcaster,
		},
		&stepTransformBuildJSON{
			payloadFilterExecutable: p.payloadFilterExecutable,
		},
		&stepGenerateScript{
			generator: p.generator,
		},
		&stepSendReceived{},
		&stepSleep{duration: p.initialSleep},
		&stepCheckCancellation{},
		&stepOpenLogWriter{
			maxLogLength:      p.maxLogLength,
			defaultLogTimeout: p.logTimeout,
		},
		&stepCheckCancellation{},
		&stepStartInstance{
			provider:     p.provider,
			startTimeout: p.startupTimeout,
		},
		&stepCheckCancellation{},
		&stepUploadScript{
			uploadTimeout: p.scriptUploadTimeout,
		},
		&stepCheckCancellation{},
		&stepUpdateState{},
		&stepWriteWorkerInfo{},
		&stepCheckCancellation{},
		&stepRunScript{
			logTimeout:               logTimeout,
			hardTimeout:              p.hardTimeout,
			skipShutdownOnLogTimeout: p.SkipShutdownOnLogTimeout,
		},
	}

	runner := &multistep.BasicRunner{Steps: steps}

	logger.Info("starting job")
	runner.Run(state)
	logger.Info("finished job")
	p.ProcessedCount++
}
<commit_msg>Rename a struct private var to golang convention (#446)<commit_after>package worker

import (
	"time"

	gocontext "context"

	"github.com/mitchellh/multistep"
	"github.com/sirupsen/logrus"
	"github.com/travis-ci/worker/backend"
	"github.com/travis-ci/worker/context"
)

// A Processor gets jobs off the job queue and coordinates running it with other
// components.
type Processor struct {
	ID       string
	hostname string

	hardTimeout             time.Duration
	initialSleep            time.Duration
	logTimeout              time.Duration
	maxLogLength            int
	scriptUploadTimeout     time.Duration
	startupTimeout          time.Duration
	payloadFilterExecutable string

	ctx                     gocontext.Context
	buildJobsChan           <-chan Job
	provider                backend.Provider
	generator               BuildScriptGenerator
	cancellationBroadcaster *CancellationBroadcaster

	graceful   chan struct{}
	terminate  gocontext.CancelFunc
	shutdownAt time.Time

	// ProcessedCount contains the number of jobs that has been processed
	// by this Processor. This value should not be modified outside of the
	// Processor.
	ProcessedCount int

	// CurrentStatus contains the current status of the processor, and can
	// be one of "new", "waiting", "processing" or "done".
	CurrentStatus string

	// LastJobID contains the ID of the last job the processor processed.
	LastJobID uint64

	SkipShutdownOnLogTimeout bool
}

type ProcessorConfig struct {
	HardTimeout             time.Duration
	InitialSleep            time.Duration
	LogTimeout              time.Duration
	MaxLogLength            int
	ScriptUploadTimeout     time.Duration
	StartupTimeout          time.Duration
	PayloadFilterExecutable string
}

// NewProcessor creates a new processor that will run the build jobs on the
// given channel using the given provider and getting build scripts from the
// generator.
func NewProcessor(ctx gocontext.Context, hostname string, queue JobQueue,
	provider backend.Provider, generator BuildScriptGenerator, cancellationBroadcaster *CancellationBroadcaster,
	config ProcessorConfig) (*Processor, error) {

	processorID, _ := context.ProcessorFromContext(ctx)

	ctx, cancel := gocontext.WithCancel(ctx)

	buildJobsChan, err := queue.Jobs(ctx)
	if err != nil {
		context.LoggerFromContext(ctx).WithField("err", err).Error("couldn't create jobs channel")
		cancel()
		return nil, err
	}

	return &Processor{
		ID:       processorID,
		hostname: hostname,

		initialSleep:            config.InitialSleep,
		hardTimeout:             config.HardTimeout,
		logTimeout:              config.LogTimeout,
		scriptUploadTimeout:     config.ScriptUploadTimeout,
		startupTimeout:          config.StartupTimeout,
		maxLogLength:            config.MaxLogLength,
		payloadFilterExecutable: config.PayloadFilterExecutable,

		ctx:                     ctx,
		buildJobsChan:           buildJobsChan,
		provider:                provider,
		generator:               generator,
		cancellationBroadcaster: cancellationBroadcaster,

		graceful:  make(chan struct{}),
		terminate: cancel,

		CurrentStatus: "new",
	}, nil
}

// Run starts the processor. This method will not return until the processor is
// terminated, either by calling the GracefulShutdown or Terminate methods, or
// if the build jobs channel is closed.
func (p *Processor) Run() {
	logger := context.LoggerFromContext(p.ctx).WithField("self", "processor")
	logger.Info("starting processor")
	defer logger.Info("processor done")
	defer func() { p.CurrentStatus = "done" }()

	for {
		select {
		case <-p.ctx.Done():
			logger.Info("processor is done, terminating")
			return
		case <-p.graceful:
			logger.WithField("shutdown_duration_s", time.Since(p.shutdownAt).Seconds()).Info("processor is done, terminating")
			p.terminate()
			return
		default:
		}

		select {
		case <-p.ctx.Done():
			logger.Info("processor is done, terminating")
			return
		case <-p.graceful:
			logger.WithField("shutdown_duration_s", time.Since(p.shutdownAt).Seconds()).Info("processor is done, terminating")
			p.terminate()
			return
		case buildJob, ok := <-p.buildJobsChan:
			if !ok {
				p.terminate()
				return
			}

			jobID := buildJob.Payload().Job.ID

			hardTimeout := p.hardTimeout
			if buildJob.Payload().Timeouts.HardLimit != 0 {
				hardTimeout = time.Duration(buildJob.Payload().Timeouts.HardLimit) * time.Second
			}
			logger.WithFields(logrus.Fields{
				"hard_timeout": hardTimeout,
				"job_id":       jobID,
			}).Debug("setting hard timeout")
			buildJob.StartAttributes().HardTimeout = hardTimeout

			ctx := context.FromJobID(context.FromRepository(p.ctx, buildJob.Payload().Repository.Slug), buildJob.Payload().Job.ID)
			if buildJob.Payload().UUID != "" {
				ctx = context.FromUUID(ctx, buildJob.Payload().UUID)
			}

			logger.WithFields(logrus.Fields{
				"hard_timeout": hardTimeout,
				"job_id":       jobID,
			}).Debug("getting wrapped context with timeout")
			ctx, cancel := gocontext.WithTimeout(ctx, hardTimeout)

			logger.WithFields(logrus.Fields{
				"job_id": jobID,
				"status": "processing",
			}).Debug("updating processor status and last id")
			p.LastJobID = jobID
			p.CurrentStatus = "processing"

			p.process(ctx, buildJob)

			logger.WithFields(logrus.Fields{
				"job_id": jobID,
				"status": "waiting",
			}).Debug("updating processor status")
			p.CurrentStatus = "waiting"
			cancel()
		case <-time.After(10 * time.Second):
			logger.Debug("timeout waiting for job, shutdown, or context done")
		}
	}
}

// GracefulShutdown tells the processor to finish the job it is currently
// processing, but not pick up any new jobs. This method will return
// immediately, the processor is done when Run() returns.
func (p *Processor) GracefulShutdown() {
	logger := context.LoggerFromContext(p.ctx).WithField("self", "processor")
	defer func() {
		err := recover()
		if err != nil {
			logger.WithField("err", err).Error("recovered from panic")
		}
	}()
	logger.Info("processor initiating graceful shutdown")
	p.shutdownAt = time.Now()
	tryClose(p.graceful)
}

// Terminate tells the processor to stop working on the current job as soon as
// possible.
func (p *Processor) Terminate() {
	p.terminate()
}

func (p *Processor) process(ctx gocontext.Context, buildJob Job) {
	state := new(multistep.BasicStateBag)
	state.Put("hostname", p.ID)
	state.Put("buildJob", buildJob)
	state.Put("procCtx", buildJob.SetupContext(p.ctx))
	state.Put("ctx", buildJob.SetupContext(ctx))

	logger := context.LoggerFromContext(ctx).WithFields(logrus.Fields{
		"job_id": buildJob.Payload().Job.ID,
		"self":   "processor",
	})

	logTimeout := p.logTimeout
	if buildJob.Payload().Timeouts.LogSilence != 0 {
		logTimeout = time.Duration(buildJob.Payload().Timeouts.LogSilence) * time.Second
	}

	steps := []multistep.Step{
		&stepSubscribeCancellation{
			cancellationBroadcaster: p.cancellationBroadcaster,
		},
		&stepTransformBuildJSON{
			payloadFilterExecutable: p.payloadFilterExecutable,
		},
		&stepGenerateScript{
			generator: p.generator,
		},
		&stepSendReceived{},
		&stepSleep{duration: p.initialSleep},
		&stepCheckCancellation{},
		&stepOpenLogWriter{
			maxLogLength:      p.maxLogLength,
			defaultLogTimeout: p.logTimeout,
		},
		&stepCheckCancellation{},
		&stepStartInstance{
			provider:     p.provider,
			startTimeout: p.startupTimeout,
		},
		&stepCheckCancellation{},
		&stepUploadScript{
			uploadTimeout: p.scriptUploadTimeout,
		},
		&stepCheckCancellation{},
		&stepUpdateState{},
		&stepWriteWorkerInfo{},
		&stepCheckCancellation{},
		&stepRunScript{
			logTimeout:               logTimeout,
			hardTimeout:              p.hardTimeout,
			skipShutdownOnLogTimeout: p.SkipShutdownOnLogTimeout,
		},
	}

	runner := &multistep.BasicRunner{Steps: steps}

	logger.Info("starting job")
	runner.Run(state)
	logger.Info("finished job")
	p.ProcessedCount++
}
<|endoftext|>


<commit_before>// This file represents the server for sensors
// It opens communication links (for each sensor) through http protocol
// Port # 8001 for Gyroscope Sensor,
// Port # 8002 for Accelerator Sensor,
// Port # 8003 for Temperature Sensor.
// If the sensor client sends data through appropriate port,
// each http handler is initiated, decoding data to appropriate JSON file.
// Those datas are then logged to each sensor's log file
// (log/Accel.log , log/Temp.log , log/Gyro.log)

package main

// 'modles' package		 : Stores basic sensor information in srtuct form
// 'net/http' package	 : To serve http connection and handle requests
// 'os' package			 : To open files for logging
// 'strings' package	 : To join strings for file path
// 'sync' package		 : To use 'WaitGroup' to hold main thread while goroutines are working

import (
	"encoding/json"
	"fmt"
	"github.com/mingrammer/go-codelab/models"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

// String constants that are used in sensor_server.go
// logDir	: Directory name to store logs
// tempLog	: File name to store temperature sensor log
// accelLog	: File name to store accelerator sensor log
// gyroLog	: File name to store gyroscope sensro log

const (
	logDir   = "log"
	tempLog  = "Temp.log"
	accelLog = "Accel.log"
	gyroLog  = "Gyro.log"
)

// This logContent struct is to store data (string) would be written in log file
// content 	: Actual string data, that would be logged in file
// location	: Indicator that where the 'content' should be stored (or written)

type logContent struct {
	content  string
	location string
	sensorName string

}

// Three structs below are to implement ServeHTTP method
// Each handler stores the pointer to data logging channel
// Also, channel is bidirectional in these handlers, which only can store data in channel
// TempHandler 	: Temperature sensor handler to implement ServeHTTP method
// GyroHandler	: Gyroscopte sensor handler to implement ServeHTTP method
// accelHandler : Accelerator sensro handler to implement ServeHTTP method

type TempHandler struct {
	buf chan<- logContent
}

type GyroHandler struct {
	buf chan<- logContent
}

type AccelHandler struct {
	buf chan<- logContent
}

// These methods are to handle request from each port.
// Body of request (which is in JSON format) is decoded and allocated to TempSensor variable
// and string, of which data would be saved in log fileis sent to logging channel
// Note that BOdy of http request CAN NOT BE unmarshalled, because body of request is in array of bytes.

func (m *TempHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.TempSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: tempLog, sensorName: data.Name}
}

func (m *GyroHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.GyroSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: gyroLog, sensorName: data.Name}
}

func (m *AccelHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.AccelSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: accelLog, sensorName: data.Name}
}

// This method loggs the content of sensor data
// This method waits incoming data from 'logContent' channel at range block,
// where ServeHTTP mehthod sends log data
// When data is detected, for/range block immediately processes data
// It checks the location, where the data should be stored,
// and opens file of desired location (by joining string constants)
// Note that channel used in this method is also BIDIRECTIONAL,
// You only can pop the data from channel.

func fileLogger(m <-chan logContent) {

	// When program is initialized, fileLogger checks if 'log' dir exists.
	// If it does not, it creates directory for the first time.
	// If there is problem with creating it, it throws panic and aborts the application.

	dir, _ := os.Open("log")
	dirInfo, _ := dir.Stat()

	if dirInfo == nil {
		err := os.Mkdir("log", os.ModePerm)

		if err != nil {
			log.Fatal("Error creating directory 'log'\n", err)
		}
	}
	dir.Close()

	// This part continuously wait for incoming data through channel

	for i := range m {
		joinee := []string{logDir, i.location}
		filePath := strings.Join(joinee, "/")

		fileHandle, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

		if err != nil {
			log.Fatal("Error Opening File\n", err)
		}

		logger := log.New(fileHandle, "", log.LstdFlags)

		logger.Printf("[%s Data Received]\n%s\n",i.sensorName, i.content)

		defer fileHandle.Close()
	}
}

// This method is for main thread. It starts go application.
// It first creates handler to serve http serve for each sensors
// sync.WaitGroup is to hold main thread while go routines are still working
// Main thread indicates WaitGroup to wait 4 routines to stop.
// After goroutines we need is created, main thread has WaitGroup to wait goroutines.

func main() {
	var wg sync.WaitGroup

	wg.Add(4)

	logBuf := make(chan logContent)
	gyroHander := &GyroHandler{buf: logBuf}
	accelHandler := &AccelHandler{buf: logBuf}
	tempHandler := &TempHandler{buf: logBuf}

	go http.ListenAndServe(":8001", gyroHander)
	go http.ListenAndServe(":8002", accelHandler)
	go http.ListenAndServe(":8003", tempHandler)
	go fileLogger(logBuf)

	wg.Wait()
}
<commit_msg>Apply 'Go fmt'<commit_after>// This file represents the server for sensors
// It opens communication links (for each sensor) through http protocol
// Port # 8001 for Gyroscope Sensor,
// Port # 8002 for Accelerator Sensor,
// Port # 8003 for Temperature Sensor.
// If the sensor client sends data through appropriate port,
// each http handler is initiated, decoding data to appropriate JSON file.
// Those datas are then logged to each sensor's log file
// (log/Accel.log , log/Temp.log , log/Gyro.log)

package main

// 'modles' package		 : Stores basic sensor information in srtuct form
// 'net/http' package	 : To serve http connection and handle requests
// 'os' package			 : To open files for logging
// 'strings' package	 : To join strings for file path
// 'sync' package		 : To use 'WaitGroup' to hold main thread while goroutines are working

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"

	"github.com/mingrammer/go-codelab/models"
)

// String constants that are used in sensor_server.go
// logDir	: Directory name to store logs
// tempLog	: File name to store temperature sensor log
// accelLog	: File name to store accelerator sensor log
// gyroLog	: File name to store gyroscope sensro log

const (
	logDir   = "log"
	tempLog  = "Temp.log"
	accelLog = "Accel.log"
	gyroLog  = "Gyro.log"
)

// This logContent struct is to store data (string) would be written in log file
// content 	: Actual string data, that would be logged in file
// location	: Indicator that where the 'content' should be stored (or written)

type logContent struct {
	content  string
	location string
	sensorName string

}

// Three structs below are to implement ServeHTTP method
// Each handler stores the pointer to data logging channel
// Also, channel is bidirectional in these handlers, which only can store data in channel
// TempHandler 	: Temperature sensor handler to implement ServeHTTP method
// GyroHandler	: Gyroscopte sensor handler to implement ServeHTTP method
// accelHandler : Accelerator sensro handler to implement ServeHTTP method

type TempHandler struct {
	buf chan<- logContent
}

type GyroHandler struct {
	buf chan<- logContent
}

type AccelHandler struct {
	buf chan<- logContent
}

// These methods are to handle request from each port.
// Body of request (which is in JSON format) is decoded and allocated to TempSensor variable
// and string, of which data would be saved in log fileis sent to logging channel
// Note that BOdy of http request CAN NOT BE unmarshalled, because body of request is in array of bytes.

func (m *TempHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.TempSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: tempLog, sensorName: data.Name}
}

func (m *GyroHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.GyroSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: gyroLog, sensorName: data.Name}
}

func (m *AccelHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.AccelSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: accelLog, sensorName: data.Name}
}

// This method loggs the content of sensor data
// This method waits incoming data from 'logContent' channel at range block,
// where ServeHTTP mehthod sends log data
// When data is detected, for/range block immediately processes data
// It checks the location, where the data should be stored,
// and opens file of desired location (by joining string constants)
// Note that channel used in this method is also BIDIRECTIONAL,
// You only can pop the data from channel.

func fileLogger(m <-chan logContent) {

	// When program is initialized, fileLogger checks if 'log' dir exists.
	// If it does not, it creates directory for the first time.
	// If there is problem with creating it, it throws panic and aborts the application.

	dir, _ := os.Open("log")
	dirInfo, _ := dir.Stat()

	if dirInfo == nil {
		err := os.Mkdir("log", os.ModePerm)

		if err != nil {
			log.Fatal("Error creating directory 'log'\n", err)
		}
	}
	dir.Close()

	// This part continuously wait for incoming data through channel

	for i := range m {
		joinee := []string{logDir, i.location}
		filePath := strings.Join(joinee, "/")

		fileHandle, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

		if err != nil {
			log.Fatal("Error Opening File\n", err)
		}

		logger := log.New(fileHandle, "", log.LstdFlags)

		logger.Printf("[%s Data Received]\n%s\n", i.sensorName, i.content)

		defer fileHandle.Close()
	}
}

// This method is for main thread. It starts go application.
// It first creates handler to serve http serve for each sensors
// sync.WaitGroup is to hold main thread while go routines are still working
// Main thread indicates WaitGroup to wait 4 routines to stop.
// After goroutines we need is created, main thread has WaitGroup to wait goroutines.

func main() {
	var wg sync.WaitGroup

	wg.Add(4)

	logBuf := make(chan logContent)
	gyroHander := &GyroHandler{buf: logBuf}
	accelHandler := &AccelHandler{buf: logBuf}
	tempHandler := &TempHandler{buf: logBuf}

	go http.ListenAndServe(":8001", gyroHander)
	go http.ListenAndServe(":8002", accelHandler)
	go http.ListenAndServe(":8003", tempHandler)
	go fileLogger(logBuf)

	wg.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2017 Diego Bernardes. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mongodb

import (
	"context"
	"fmt"

	"github.com/pkg/errors"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"

	"github.com/diegobernardes/flare"
)

// Document implements the data layer for the document service.
type Document struct {
	client     *Client
	database   string
	collection string
}

// FindOne return the document that match the id.
func (d *Document) FindOne(ctx context.Context, id string) (*flare.Document, error) {
	session := d.client.session()
	session.SetMode(mgo.Monotonic, true)
	defer session.Close()

	result := &flare.Document{}
	if err := session.DB(d.database).C(d.collection).Find(bson.M{"id": id}).One(result); err != nil {
		if err == mgo.ErrNotFound {
			return nil, &errMemory{message: fmt.Sprintf("document '%s' not found", id), notFound: true}
		}
		return nil, errors.Wrap(err, fmt.Sprintf("error during document '%s' find", id))
	}

	return result, nil
}

// Update a given document.
func (d *Document) Update(_ context.Context, document *flare.Document) error {
	session := d.client.session()
	session.SetMode(mgo.Monotonic, true)
	defer session.Close()

	_, err := session.DB(d.database).C(d.collection).Upsert(bson.M{"id": document.Id}, document)
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("error during document '%s' update", document.Id))
	}

	return nil
}

// Delete a given document.
func (d *Document) Delete(_ context.Context, id string) error {
	session := d.client.session()
	session.SetMode(mgo.Monotonic, true)
	defer session.Close()

	if err := session.DB(d.database).C(d.collection).Remove(bson.M{"id": id}); err != nil {
		if err == mgo.ErrNotFound {
			return &errMemory{message: fmt.Sprintf("document '%s' not found", id), notFound: true}
		}
		return errors.Wrap(err, fmt.Sprintf("error during document '%s' delete", id))
	}

	return nil
}

// NewDocument returns a configured document repository.
func NewDocument(options ...func(*Document)) (*Document, error) {
	d := &Document{}
	for _, option := range options {
		option(d)
	}

	if d.client == nil {
		return nil, errors.New("invalid client")
	}
	d.collection = "documents"
	d.database = d.client.database
	return d, nil
}

// DocumentClient set the client to access MongoDB.
func DocumentClient(client *Client) func(*Document) {
	return func(d *Document) {
		d.client = client
	}
}
<commit_msg>repository/mongodb: fix missing updatedAt<commit_after>// Copyright 2017 Diego Bernardes. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mongodb

import (
	"context"
	"fmt"
	"time"

	"github.com/pkg/errors"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"

	"github.com/diegobernardes/flare"
)

// Document implements the data layer for the document service.
type Document struct {
	client     *Client
	database   string
	collection string
}

// FindOne return the document that match the id.
func (d *Document) FindOne(ctx context.Context, id string) (*flare.Document, error) {
	session := d.client.session()
	session.SetMode(mgo.Monotonic, true)
	defer session.Close()

	result := &flare.Document{}
	if err := session.DB(d.database).C(d.collection).Find(bson.M{"id": id}).One(result); err != nil {
		if err == mgo.ErrNotFound {
			return nil, &errMemory{message: fmt.Sprintf("document '%s' not found", id), notFound: true}
		}
		return nil, errors.Wrap(err, fmt.Sprintf("error during document '%s' find", id))
	}

	return result, nil
}

// Update a given document.
func (d *Document) Update(_ context.Context, document *flare.Document) error {
	session := d.client.session()
	session.SetMode(mgo.Monotonic, true)
	defer session.Close()
	document.UpdatedAt = time.Now()

	_, err := session.DB(d.database).C(d.collection).Upsert(bson.M{"id": document.Id}, document)
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("error during document '%s' update", document.Id))
	}
	return nil
}

// Delete a given document.
func (d *Document) Delete(_ context.Context, id string) error {
	session := d.client.session()
	session.SetMode(mgo.Monotonic, true)
	defer session.Close()

	if err := session.DB(d.database).C(d.collection).Remove(bson.M{"id": id}); err != nil {
		if err == mgo.ErrNotFound {
			return &errMemory{message: fmt.Sprintf("document '%s' not found", id), notFound: true}
		}
		return errors.Wrap(err, fmt.Sprintf("error during document '%s' delete", id))
	}

	return nil
}

// NewDocument returns a configured document repository.
func NewDocument(options ...func(*Document)) (*Document, error) {
	d := &Document{}
	for _, option := range options {
		option(d)
	}

	if d.client == nil {
		return nil, errors.New("invalid client")
	}
	d.collection = "documents"
	d.database = d.client.database
	return d, nil
}

// DocumentClient set the client to access MongoDB.
func DocumentClient(client *Client) func(*Document) {
	return func(d *Document) {
		d.client = client
	}
}
<|endoftext|>


<commit_before>package request

import (
	"encoding/base64"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRequestBuilderPanicWithNoUrl(t *testing.T) {
	defer func() {
		err := recover().(error)

		assert.NotNil(t, err, "Should not be nil")
		assert.Equal(t, "URL is required.", err.Error(), "Should equal error message")
	}()

	builder := NewRequestBuilder()
	builder.Build()

	assert.True(t, false, "Should not have completed test")
}

func TestRequestBuilderWithUrl(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")
	assert.Equal(t, POSTMAN_ECHO_ROOT, r2.URL.String(), "Should equal URL")
}

func TestRequestBuilderWithDefaultMethod(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")
	assert.Equal(t, "GET", r2.Method, "Should equal GET method")
}

func TestRequestBuilderWithBasicAuth(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).WithBasicAuth("postman", "password").Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")

	basicAuthString := base64.StdEncoding.EncodeToString([]byte("postman:password"))
	basicAuthString = "Basic " + basicAuthString

	assert.Equal(t, basicAuthString, r2.Header.Get("Authorization"), "Should equal authorization header")
}

func TestRequestBuilderWithBearerAuth(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).WithBearerAuth(TEST_TOKEN).Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")

	bearerAuthString := "Bearer " + TEST_TOKEN

	assert.Equal(t, bearerAuthString, r2.Header.Get("Authorization"), "Should equal authorization header")
}
<commit_msg>Renamed test and check default Authorization.<commit_after>package request

import (
	"encoding/base64"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRequestBuilderPanicWithNoUrl(t *testing.T) {
	defer func() {
		err := recover().(error)

		assert.NotNil(t, err, "Should not be nil")
		assert.Equal(t, "URL is required.", err.Error(), "Should equal error message")
	}()

	builder := NewRequestBuilder()
	builder.Build()

	assert.True(t, false, "Should not have completed test")
}

func TestRequestBuilderWithUrl(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")
	assert.Equal(t, POSTMAN_ECHO_ROOT, r2.URL.String(), "Should equal URL")
}

func TestRequestBuilderWithDefaults(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")
	assert.Equal(t, "GET", r2.Method, "Should equal GET method")
	assert.Empty(t, r2.Header.Get("Authorization"), "Should not have set authorization header")
}

func TestRequestBuilderWithBasicAuth(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).WithBasicAuth("postman", "password").Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")

	basicAuthString := base64.StdEncoding.EncodeToString([]byte("postman:password"))
	basicAuthString = "Basic " + basicAuthString

	assert.Equal(t, basicAuthString, r2.Header.Get("Authorization"), "Should equal authorization header")
}

func TestRequestBuilderWithBearerAuth(t *testing.T) {
	r1 := NewRequestBuilder().WithUrl(POSTMAN_ECHO_ROOT).WithBearerAuth(TEST_TOKEN).Build()

	assert.NotNil(t, r1, "Should not be nil")

	r2 := r1.getUnderlyingRequest()

	assert.NotNil(t, r2, "Should not be nil")

	bearerAuthString := "Bearer " + TEST_TOKEN

	assert.Equal(t, bearerAuthString, r2.Header.Get("Authorization"), "Should equal authorization header")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"flag"
	"io/ioutil"
	"os"
	"github.com/robertkrimen/otto"
)

func main() {
	flag.Parse()
	var script []byte
	var err error
	filename := flag.Arg(0)
	if filename == "" || filename == "-" {
		script, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			fmt.Printf("Can't read stdin: %v\n", err)
			os.Exit(64)
		}
	} else {
		script, err = ioutil.ReadFile(filename)
		if err != nil {
			fmt.Printf("Can't open file \"%v\": %v\n", filename, err)
			os.Exit(64)
		}
	}
	Otto := otto.New()
	_, err = Otto.Run(string(script))
	if err != nil {
		fmt.Println(err)
		os.Exit(64)
	}
}
<commit_msg>Add underscore to the commandline<commit_after>package main

import (
	"fmt"
	"flag"
	"io/ioutil"
	"os"
	"github.com/robertkrimen/otto"
	"github.com/robertkrimen/otto/underscore"
)

var underscoreFlag *bool = flag.Bool("underscore", true, "Load underscore into the runtime environment")

func main() {
	flag.Parse()
	var script []byte
	var err error
	filename := flag.Arg(0)
	if filename == "" || filename == "-" {
		script, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			fmt.Printf("Can't read stdin: %v\n", err)
			os.Exit(64)
		}
	} else {
		script, err = ioutil.ReadFile(filename)
		if err != nil {
			fmt.Printf("Can't open file \"%v\": %v\n", filename, err)
			os.Exit(64)
		}
	}
	if !*underscoreFlag {
		underscore.Disable()
	}
	Otto := otto.New()
	_, err = Otto.Run(string(script))
	if err != nil {
		fmt.Println(err)
		os.Exit(64)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/davecgh/go-spew/spew"
	"github.com/fromanirh/procwatch/podfind"
	"github.com/fromanirh/procwatch/procnotify"
	flag "github.com/spf13/pflag"

	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)

const confFile string = "procwatch.json"

type Config struct {
	Targets     []procnotify.Config `json:"targets"`
	Interval    string              `json:"interval"`
	Hostname    string              `json:"hostname"`
	CRIEndPoint string              `json:"criendpoint"`
	AutoTrack   bool                `json:"autotrack"`
}

func (c Config) CountTargets() int {
	return len(c.Targets)
}

func readFile(conf *Config, path string) error {
	log.Printf("trying configuration: %s", path)

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}

	if len(content) > 0 {
		err = json.Unmarshal(content, conf)
		if err != nil {
			return err
		}
	}

	log.Printf("Read from file: %s", path)
	return nil
}

func findInterval(conf Config, args []string) (time.Duration, error) {
	if len(args) >= 2 {
		ival, err := strconv.Atoi(args[1])
		if err != nil {
			return 0, err
		}
		return time.Duration(ival) * time.Second, nil
	}

	envVar := os.Getenv("COLLECTD_INTERVAL")
	if envVar != "" {
		fval, err := strconv.ParseFloat(envVar, 64)
		if err != nil {
			return 0, err
		}
		return time.Duration(int(fval)) * time.Second, nil
	}

	if conf.Interval == "" {
		return 0, errors.New(fmt.Sprintf("invalid interval: %d", conf.Interval))
	}

	dval, err := time.ParseDuration(conf.Interval)
	if err != nil {
		return 0, err
	}
	return dval, nil
}

func needHelp() bool {
	if len(os.Args) < 2 || len(os.Args) > 3 {
		return true
	}
	if len(os.Args) >= 2 {
		if os.Args[1] == "-h" || os.Args[1] == "--help" {
			return true
		}
	}
	return false
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s /path/to/procwatch.json [interval_seconds]\n", os.Args[0])
		flag.PrintDefaults()
	}
	debugMode := flag.BoolP("debug", "D", false, "enable debug mode")
	sinkPath := flag.StringP("unixsock", "U", "", "send output to <unixsock> not to stdout")
	flag.Parse()

	args := flag.Args()

	if len(args) < 1 {
		flag.Usage()
		return
	}

	log.Printf("procwatcher started")
	defer log.Printf("procwatcher stopped")

	conf := Config{Interval: "5s"}
	err := readFile(&conf, args[0])
	if err != nil {
		log.Fatalf("error reading the configuration on '%s': %s", args[0], err)
	}

	conf.Hostname = os.Getenv("COLLECTD_HOSTNAME")
	if conf.Hostname == "" {
		conf.Hostname, err = os.Hostname()
		if err != nil {
			log.Fatalf("error getting the host name: %s", err)
		}
	}

	interval, err := findInterval(conf, args)
	if err != nil {
		log.Fatalf("error getting the polling interval: %s", err)
	} else {
		log.Printf("polling interval: %v", interval)
	}

	dryRun := os.Getenv("PROCWATCH_DRYRUN")
	if dryRun != "" {
		log.Printf("%s", spew.Sdump(conf))
		return
	}

	if conf.CountTargets() == 0 {
		log.Fatalf("missing process(es) to track")
	}

	var pr *podfind.PodResolver
	if conf.CRIEndPoint != "" {
		log.Printf("enabled POD ID resolution")
		pr, err = podfind.NewPodResolver(conf.CRIEndPoint, 10*time.Second)
		if err != nil {
			log.Fatalf("unable to set up pod resolution: %s", err)
		} else {
			pr.Debug = *debugMode
		}
	}

	var sink io.Writer = os.Stdout
	if *sinkPath != "" {
		sock, err := net.Dial("unix", *sinkPath)
		if err != nil {
			log.Fatalf("cannot open output sink '%s': %s", *sinkPath, err)
		}
		defer sock.Close()
		sink = sock
	}

	notifier := procnotify.NewNotifier(conf.Targets, pr, sink)
	log.Printf("Tracking:\n")
	notifier.Dump(os.Stderr)

	notifier.Loop(conf.Hostname, interval, conf.AutoTrack)
}
<commit_msg>main: don't fail if we can't connect to kubelet<commit_after>package main

import (
	"github.com/davecgh/go-spew/spew"
	"github.com/fromanirh/procwatch/podfind"
	"github.com/fromanirh/procwatch/procnotify"
	flag "github.com/spf13/pflag"

	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)

const confFile string = "procwatch.json"

type Config struct {
	Targets     []procnotify.Config `json:"targets"`
	Interval    string              `json:"interval"`
	Hostname    string              `json:"hostname"`
	CRIEndPoint string              `json:"criendpoint"`
	AutoTrack   bool                `json:"autotrack"`
}

func (c Config) CountTargets() int {
	return len(c.Targets)
}

func readFile(conf *Config, path string) error {
	log.Printf("trying configuration: %s", path)

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}

	if len(content) > 0 {
		err = json.Unmarshal(content, conf)
		if err != nil {
			return err
		}
	}

	log.Printf("Read from file: %s", path)
	return nil
}

func findInterval(conf Config, args []string) (time.Duration, error) {
	if len(args) >= 2 {
		ival, err := strconv.Atoi(args[1])
		if err != nil {
			return 0, err
		}
		return time.Duration(ival) * time.Second, nil
	}

	envVar := os.Getenv("COLLECTD_INTERVAL")
	if envVar != "" {
		fval, err := strconv.ParseFloat(envVar, 64)
		if err != nil {
			return 0, err
		}
		return time.Duration(int(fval)) * time.Second, nil
	}

	if conf.Interval == "" {
		return 0, errors.New(fmt.Sprintf("invalid interval: %d", conf.Interval))
	}

	dval, err := time.ParseDuration(conf.Interval)
	if err != nil {
		return 0, err
	}
	return dval, nil
}

func needHelp() bool {
	if len(os.Args) < 2 || len(os.Args) > 3 {
		return true
	}
	if len(os.Args) >= 2 {
		if os.Args[1] == "-h" || os.Args[1] == "--help" {
			return true
		}
	}
	return false
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s /path/to/procwatch.json [interval_seconds]\n", os.Args[0])
		flag.PrintDefaults()
	}
	debugMode := flag.BoolP("debug", "D", false, "enable debug mode")
	sinkPath := flag.StringP("unixsock", "U", "", "send output to <unixsock> not to stdout")
	flag.Parse()

	args := flag.Args()

	if len(args) < 1 {
		flag.Usage()
		return
	}

	log.Printf("procwatcher started")
	defer log.Printf("procwatcher stopped")

	conf := Config{Interval: "5s"}
	err := readFile(&conf, args[0])
	if err != nil {
		log.Fatalf("error reading the configuration on '%s': %s", args[0], err)
	}

	conf.Hostname = os.Getenv("COLLECTD_HOSTNAME")
	if conf.Hostname == "" {
		conf.Hostname, err = os.Hostname()
		if err != nil {
			log.Fatalf("error getting the host name: %s", err)
		}
	}

	interval, err := findInterval(conf, args)
	if err != nil {
		log.Fatalf("error getting the polling interval: %s", err)
	} else {
		log.Printf("polling interval: %v", interval)
	}

	dryRun := os.Getenv("PROCWATCH_DRYRUN")
	if dryRun != "" {
		log.Printf("%s", spew.Sdump(conf))
		return
	}

	if conf.CountTargets() == 0 {
		log.Fatalf("missing process(es) to track")
	}

	var pr *podfind.PodResolver
	if conf.CRIEndPoint != "" {
		log.Printf("enabled POD ID resolution")
		pr, err = podfind.NewPodResolver(conf.CRIEndPoint, 10*time.Second)
		if err != nil {
			log.Printf("unable to set up pod resolution: %s", err)
			pr = nil
		} else {
			pr.Debug = *debugMode
		}
	}

	var sink io.Writer = os.Stdout
	if *sinkPath != "" {
		sock, err := net.Dial("unix", *sinkPath)
		if err != nil {
			log.Fatalf("cannot open output sink '%s': %s", *sinkPath, err)
		}
		defer sock.Close()
		sink = sock
	}

	notifier := procnotify.NewNotifier(conf.Targets, pr, sink)
	log.Printf("Tracking:\n")
	notifier.Dump(os.Stderr)

	notifier.Loop(conf.Hostname, interval, conf.AutoTrack)
}
<|endoftext|>


<commit_before>package server

import (
	"confdis/go/confdis"
	"fmt"
	"github.com/ActiveState/log"
	"io/ioutil"
	"net/url"
)

// Config refers to Stackato configuration under a specific
// group, such as "dea" or "cluster".
type Config struct {
	name    string
	changes chan error
	*confdis.ConfDis
}

func NewConfig(group string, s interface{}) (*Config, error) {
	addr, pass, db, err := getStackatoRedisAddr()
	if err != nil {
		return nil, err
	}

	redis, err := NewRedisClientRetry(addr, pass, db, 3)
	if err != nil {
		return nil, err
	}

	c, err := confdis.New(redis, group, s)
	if err != nil {
		return nil, err
	}
	gc := &Config{group, nil, c}
	go gc.monitor()
	return gc, nil
}

// GetChangesChannel returns a channel of (always) nil values that
// updates upon config changes.
func (g *Config) GetChangesChannel() chan error {
	// XXX: not bothering to lock this, yet.
	if g.changes == nil {
		g.changes = make(chan error)
	}
	return g.changes
}

// monitor monitors config changes, and exits abruptly upon on any
// error.
func (g *Config) monitor() {
	for err := range g.Changes {
		if err != nil {
			log.Fatalf("Error reading config for %s: %v",
				g.name, err)
		}
		if g.changes != nil {
			g.changes <- err
		}
	}
}

// getStackatoRedisAddr returns the redis connection address, password
// and database of the Stackato redis instance storing configuration.
func getStackatoRedisAddr() (string, string, int64, error) {
	uridata, err := ioutil.ReadFile("/s/etc/kato/redis_uri")
	if err != nil {
		return "", "", -1, err
	}
	u, err := url.Parse(string(uridata))
	if err != nil {
		return "", "", -1, err
	}

	// extract database number from Path
	var database int64
	fmt.Sscanf(u.Path, "/%d", &database)

	var pass string
	if u.User != nil {
		var haspass bool
		pass, haspass = u.User.Password()
		if !haspass {
			pass = ""
		}
	}

	return u.Host, pass, database, nil
}
<commit_msg>if running under docker, read redis uri from env var<commit_after>package server

import (
	"confdis/go/confdis"
	"fmt"
	"github.com/ActiveState/log"
	"io/ioutil"
	"net/url"
	"os"
)

// Config refers to Stackato configuration under a specific
// group, such as "dea" or "cluster".
type Config struct {
	name    string
	changes chan error
	*confdis.ConfDis
}

func NewConfig(group string, s interface{}) (*Config, error) {
	addr, pass, db, err := getStackatoRedisAddr()
	if err != nil {
		return nil, err
	}

	redis, err := NewRedisClientRetry(addr, pass, db, 3)
	if err != nil {
		return nil, err
	}

	c, err := confdis.New(redis, group, s)
	if err != nil {
		return nil, err
	}
	gc := &Config{group, nil, c}
	go gc.monitor()
	return gc, nil
}

// GetChangesChannel returns a channel of (always) nil values that
// updates upon config changes.
func (g *Config) GetChangesChannel() chan error {
	// XXX: not bothering to lock this, yet.
	if g.changes == nil {
		g.changes = make(chan error)
	}
	return g.changes
}

// monitor monitors config changes, and exits abruptly upon on any
// error.
func (g *Config) monitor() {
	for err := range g.Changes {
		if err != nil {
			log.Fatalf("Error reading config for %s: %v",
				g.name, err)
		}
		if g.changes != nil {
			g.changes <- err
		}
	}
}

// getStackatoRedisAddr returns the redis connection address, password
// and database of the Stackato redis instance managing configuration.
func getStackatoRedisAddr() (string, string, int64, error) {
	uri, err := getStackatoRedisUri()
	if err != nil {
		return "", "", -1, err
	}

	u, err := url.Parse(uri)
	if err != nil {
		return "", "", -1, err
	}

	// extract database number from Path
	var database int64
	fmt.Sscanf(u.Path, "/%d", &database)

	var pass string
	if u.User != nil {
		var haspass bool
		pass, haspass = u.User.Password()
		if !haspass {
			pass = ""
		}
	}

	return u.Host, pass, database, nil
}

func getStackatoRedisUri() (string, error) {
	// If running under docker, use env var. Else, rely on kato configuration.
	if os.Getenv("STACKATO_DOCKER") == "" {
		uridata, err := ioutil.ReadFile("/s/etc/kato/redis_uri")
		if err != nil {
			return "", err
		}
		return string(uridata), nil
	} else {
		uri := os.Getenv("CONFIG_REDIS_URI")
		if uri == "" {
			return "", fmt.Errorf("CONFIG_REDIS_URI env is not set")
		}
		return uri, nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fmom

import (
	"math"
)

type EtEtaPhiM [4]float64

func NewEtEtaPhiM(et, eta, phi, m float64) EtEtaPhiM {
	return EtEtaPhiM([4]float64{et, eta, phi, m})
}

func (p4 *EtEtaPhiM) Clone() P4 {
	pp := *p4
	return &pp
}

func (p4 *EtEtaPhiM) Et() float64 {
	return p4[0]
}

func (p4 *EtEtaPhiM) Eta() float64 {
	return p4[1]
}

func (p4 *EtEtaPhiM) Phi() float64 {
	return p4[2]
}

func (p4 *EtEtaPhiM) M() float64 {
	return p4[3]
}

func (p4 *EtEtaPhiM) M2() float64 {
	m := p4.M()
	return m * m
}

func (p4 *EtEtaPhiM) P() float64 {
	m := p4.M()
	e := p4.E()
	if m == 0 {
		return e
	}
	sign := 1.0
	if e < 0 {
		sign = -1.0
	}
	return sign * math.Sqrt(e*e-m*m)
}
func (p4 *EtEtaPhiM) P2() float64 {
	m := p4.M()
	e := p4.E()
	return e*e - m*m
}

func (p4 *EtEtaPhiM) CosPhi() float64 {
	phi := p4.Phi()
	return math.Cos(phi)
}

func (p4 *EtEtaPhiM) SinPhi() float64 {
	phi := p4.Phi()
	return math.Sin(phi)
}

func (p4 *EtEtaPhiM) TanTh() float64 {
	eta := p4.Eta()
	abseta := math.Abs(eta)
	// avoid numeric overflow if very large eta
	if abseta > 710 {
		if eta > 0 {
			eta = +710
		} else {
			eta = -710
		}
	}
	return 1. / math.Sinh(eta)
}

func (p4 *EtEtaPhiM) CotTh() float64 {
	eta := p4.Eta()
	return math.Sinh(eta)
}

func (p4 *EtEtaPhiM) CosTh() float64 {
	eta := p4.Eta()
	return math.Tanh(eta)
}

func (p4 *EtEtaPhiM) SinTh() float64 {
	eta := p4.Eta()
	abseta := math.Abs(eta)
	if abseta > 710 {
		abseta = 710
	}
	return 1 / math.Cosh(abseta)
}

func (p4 *EtEtaPhiM) Pt() float64 {
	p := p4.P()
	sinth := p4.SinTh()
	return p * sinth
}

func (p4 *EtEtaPhiM) E() float64 {
	et := p4.Et()
	sinth := p4.SinTh()
	return et / sinth
}

func (p4 *EtEtaPhiM) IPt() float64 {
	pt := p4.Pt()
	return 1 / pt
}

func (p4 *EtEtaPhiM) Rapidity() float64 {
	e := p4.E()
	pz := p4.Pz()
	return 0.5 * math.Log((e+pz)/(e-pz))
}

func (p4 *EtEtaPhiM) Px() float64 {
	pt := p4.Pt()
	cosphi := p4.CosPhi()
	return pt * cosphi
}

func (p4 *EtEtaPhiM) Py() float64 {
	pt := p4.Pt()
	sinphi := p4.SinPhi()
	return pt * sinphi
}

func (p4 *EtEtaPhiM) Pz() float64 {
	p := p4.P()
	costh := p4.CosTh()
	return p * costh
}

func (p4 *EtEtaPhiM) Set(p P4) {
	p4[0] = p.Et()
	p4[1] = p.Eta()
	p4[2] = p.Phi()
	p4[3] = p.M()
}
<commit_msg>fmom: make EtEtaPhiM a struct instead of [4]float64<commit_after>// Copyright 2017 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fmom

import (
	"math"
)

type EtEtaPhiM struct {
	P4 Vec4
}

func NewEtEtaPhiM(et, eta, phi, m float64) EtEtaPhiM {
	return EtEtaPhiM{P4: Vec4{X: et, Y: eta, Z: phi, T: m}}
}

func (p4 *EtEtaPhiM) Clone() P4 {
	pp := *p4
	return &pp
}

func (p4 *EtEtaPhiM) Et() float64 {
	return p4.P4.X
}

func (p4 *EtEtaPhiM) Eta() float64 {
	return p4.P4.Y
}

func (p4 *EtEtaPhiM) Phi() float64 {
	return p4.P4.Z
}

func (p4 *EtEtaPhiM) M() float64 {
	return p4.P4.T
}

func (p4 *EtEtaPhiM) M2() float64 {
	m := p4.M()
	return m * m
}

func (p4 *EtEtaPhiM) P() float64 {
	m := p4.M()
	e := p4.E()
	if m == 0 {
		return e
	}
	sign := 1.0
	if e < 0 {
		sign = -1.0
	}
	return sign * math.Sqrt(e*e-m*m)
}
func (p4 *EtEtaPhiM) P2() float64 {
	m := p4.M()
	e := p4.E()
	return e*e - m*m
}

func (p4 *EtEtaPhiM) CosPhi() float64 {
	phi := p4.Phi()
	return math.Cos(phi)
}

func (p4 *EtEtaPhiM) SinPhi() float64 {
	phi := p4.Phi()
	return math.Sin(phi)
}

func (p4 *EtEtaPhiM) TanTh() float64 {
	eta := p4.Eta()
	abseta := math.Abs(eta)
	// avoid numeric overflow if very large eta
	if abseta > 710 {
		if eta > 0 {
			eta = +710
		} else {
			eta = -710
		}
	}
	return 1. / math.Sinh(eta)
}

func (p4 *EtEtaPhiM) CotTh() float64 {
	eta := p4.Eta()
	return math.Sinh(eta)
}

func (p4 *EtEtaPhiM) CosTh() float64 {
	eta := p4.Eta()
	return math.Tanh(eta)
}

func (p4 *EtEtaPhiM) SinTh() float64 {
	eta := p4.Eta()
	abseta := math.Abs(eta)
	if abseta > 710 {
		abseta = 710
	}
	return 1 / math.Cosh(abseta)
}

func (p4 *EtEtaPhiM) Pt() float64 {
	p := p4.P()
	sinth := p4.SinTh()
	return p * sinth
}

func (p4 *EtEtaPhiM) E() float64 {
	et := p4.Et()
	sinth := p4.SinTh()
	return et / sinth
}

func (p4 *EtEtaPhiM) IPt() float64 {
	pt := p4.Pt()
	return 1 / pt
}

func (p4 *EtEtaPhiM) Rapidity() float64 {
	e := p4.E()
	pz := p4.Pz()
	return 0.5 * math.Log((e+pz)/(e-pz))
}

func (p4 *EtEtaPhiM) Px() float64 {
	pt := p4.Pt()
	cosphi := p4.CosPhi()
	return pt * cosphi
}

func (p4 *EtEtaPhiM) Py() float64 {
	pt := p4.Pt()
	sinphi := p4.SinPhi()
	return pt * sinphi
}

func (p4 *EtEtaPhiM) Pz() float64 {
	p := p4.P()
	costh := p4.CosTh()
	return p * costh
}

func (p4 *EtEtaPhiM) Set(p P4) {
	p4.P4.X = p.Et()
	p4.P4.Y = p.Eta()
	p4.P4.Z = p.Phi()
	p4.P4.T = p.M()
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"
)

const (
	// Content Type header key
	contentTypeHeaderKey string = "Content-Type"
	// application/json header value for Content-Type header key
	appJSONContentTypeHeaderVal string = "application/json"
	// Default Realm used as part of the WWW-Authenticate response
	// header when returning a 401 Unauthorized response
	defaultRealm string = "go-api-basic"
	// extlID is used to represent an external id. This is a common
	// enough pattern in these services, that I've chosen to make it
	// a constant
	extlIDPathDir string = "/{extlID}"
	// organization V1 Path root
	orgsV1PathRoot string = "/v1/orgs"
	// app V1 Path root
	appsV1PathRoot string = "/v1/apps"
	// register V1 Path root
	registerV1PathRoot string = "/v1/register"
	// logger V1 Path root
	loggerV1PathRoot string = "/v1/logger"
	// ping V1 Path root
	pingV1PathRoot string = "/v1/ping"
	// genesis V1 Path root
	genesisV1PathRoot string = "/v1/genesis"
	// movies V1 Path root
	moviesV1PathRoot string = "/v1/movies"
)

// register routes/middleware/handlers to the Server router
func (s *Server) registerRoutes() {

	// Match only POST requests at /api/v1/movies
	// with Content-Type header = application/json
	s.router.Handle(moviesV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleMovieCreate)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only PUT requests having an ID at /api/v1/movies/{extlID}
	// with the Content-Type header = application/json
	s.router.Handle(moviesV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleMovieUpdate)).
		Methods(http.MethodPut).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only DELETE requests having an ID at /api/v1/movies/{extlID}
	s.router.Handle(moviesV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleMovieDelete)).
		Methods(http.MethodDelete)

	// Match only GET requests having an ID at /api/v1/movies/{extlID}
	s.router.Handle(moviesV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleFindMovieByID)).
		Methods(http.MethodGet)

	// Match only GET requests /api/v1/movies
	s.router.Handle(moviesV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleFindAllMovies)).
		Methods(http.MethodGet)

	// Match only GET requests at /api/v1/orgs
	s.router.Handle(orgsV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgFindAll)).
		Methods(http.MethodGet)

	// Match only GET requests at /api/v1/orgs/{extlID}
	s.router.Handle(orgsV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgFindByExtlID)).
		Methods(http.MethodGet)

	// Match only POST requests at /api/v1/orgs
	// with Content-Type header = application/json
	s.router.Handle(orgsV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgCreate)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only PUT requests at /api/v1/orgs/{extlID}
	// with Content-Type header = application/json
	s.router.Handle(orgsV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgUpdate)).
		Methods(http.MethodPut).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only POST requests at /api/v1/apps
	// with Content-Type header = application/json
	s.router.Handle(appsV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleAppCreate)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only POST requests at /api/v1/register
	s.router.Handle(registerV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.newUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleAppCreate)).
		Methods(http.MethodPost)

	// Match only GET requests /api/v1/logger
	s.router.Handle(loggerV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleLoggerRead)).
		Methods(http.MethodGet)

	// Match only PUT requests /api/v1/logger
	s.router.Handle(loggerV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleLoggerUpdate)).
		Methods(http.MethodPut).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only GET requests at /api/v1/ping
	s.router.Handle(pingV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handlePing)).
		Methods(http.MethodGet)

	// Match only POST requests at /api/v1/genesis
	s.router.Handle(genesisV1PathRoot,
		s.loggerChain().
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleGenesis)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)
}
<commit_msg>Remove app/json header requirement<commit_after>package server

import (
	"net/http"
)

const (
	// Content Type header key
	contentTypeHeaderKey string = "Content-Type"
	// application/json header value for Content-Type header key
	appJSONContentTypeHeaderVal string = "application/json"
	// Default Realm used as part of the WWW-Authenticate response
	// header when returning a 401 Unauthorized response
	defaultRealm string = "go-api-basic"
	// extlID is used to represent an external id. This is a common
	// enough pattern in these services, that I've chosen to make it
	// a constant
	extlIDPathDir string = "/{extlID}"
	// organization V1 Path root
	orgsV1PathRoot string = "/v1/orgs"
	// app V1 Path root
	appsV1PathRoot string = "/v1/apps"
	// register V1 Path root
	registerV1PathRoot string = "/v1/register"
	// logger V1 Path root
	loggerV1PathRoot string = "/v1/logger"
	// ping V1 Path root
	pingV1PathRoot string = "/v1/ping"
	// genesis V1 Path root
	genesisV1PathRoot string = "/v1/genesis"
	// movies V1 Path root
	moviesV1PathRoot string = "/v1/movies"
)

// register routes/middleware/handlers to the Server router
func (s *Server) registerRoutes() {

	// Match only POST requests at /api/v1/movies
	// with Content-Type header = application/json
	s.router.Handle(moviesV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleMovieCreate)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only PUT requests having an ID at /api/v1/movies/{extlID}
	// with the Content-Type header = application/json
	s.router.Handle(moviesV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleMovieUpdate)).
		Methods(http.MethodPut).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only DELETE requests having an ID at /api/v1/movies/{extlID}
	s.router.Handle(moviesV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleMovieDelete)).
		Methods(http.MethodDelete)

	// Match only GET requests having an ID at /api/v1/movies/{extlID}
	s.router.Handle(moviesV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleFindMovieByID)).
		Methods(http.MethodGet)

	// Match only GET requests /api/v1/movies
	s.router.Handle(moviesV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleFindAllMovies)).
		Methods(http.MethodGet)

	// Match only GET requests at /api/v1/orgs
	s.router.Handle(orgsV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgFindAll)).
		Methods(http.MethodGet)

	// Match only GET requests at /api/v1/orgs/{extlID}
	s.router.Handle(orgsV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgFindByExtlID)).
		Methods(http.MethodGet)

	// Match only POST requests at /api/v1/orgs
	// with Content-Type header = application/json
	s.router.Handle(orgsV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgCreate)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only PUT requests at /api/v1/orgs/{extlID}
	// with Content-Type header = application/json
	s.router.Handle(orgsV1PathRoot+extlIDPathDir,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleOrgUpdate)).
		Methods(http.MethodPut).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only POST requests at /api/v1/apps
	// with Content-Type header = application/json
	s.router.Handle(appsV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleAppCreate)).
		Methods(http.MethodPost).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only POST requests at /api/v1/register
	s.router.Handle(registerV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.newUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleAppCreate)).
		Methods(http.MethodPost)

	// Match only GET requests /api/v1/logger
	s.router.Handle(loggerV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleLoggerRead)).
		Methods(http.MethodGet)

	// Match only PUT requests /api/v1/logger
	s.router.Handle(loggerV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleLoggerUpdate)).
		Methods(http.MethodPut).
		Headers(contentTypeHeaderKey, appJSONContentTypeHeaderVal)

	// Match only GET requests at /api/v1/ping
	s.router.Handle(pingV1PathRoot,
		s.loggerChain().
			Append(s.appHandler).
			Append(s.userHandler).
			Append(s.authorizeUserHandler).
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handlePing)).
		Methods(http.MethodGet)

	// Match only POST requests at /api/v1/genesis
	s.router.Handle(genesisV1PathRoot,
		s.loggerChain().
			Append(s.jsonContentTypeResponseHandler).
			ThenFunc(s.handleGenesis)).
		Methods(http.MethodPost)
}
<|endoftext|>


<commit_before>package server

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/nelhage/livegrep/client"
	"log"
)

type searchConnection struct {
	srv      *server
	ws       *websocket.Conn
	errors   chan error
	incoming chan Op
	outgoing chan Op
	shutdown bool
}

func (s *searchConnection) recvLoop() {
	var op Op
	for {
		if err := OpCodec.Receive(s.ws, &op); err != nil {
			log.Printf("Error in receive: %s\n", err.Error())
			if _, ok := err.(*ProtocolError); ok {
				// TODO: is this a good idea?
				// s.outgoing <- &OpError{err.Error()}
				continue
			} else {
				s.errors <- err
				break
			}
		}
		log.Printf("Incoming: %v", op)
		s.incoming <- op
		if s.shutdown {
			break
		}
	}
	close(s.incoming)
}

func (s *searchConnection) sendLoop() {
	for op := range s.outgoing {
		OpCodec.Send(s.ws, op)
	}
}

func query(q *OpQuery) *client.Query {
	return &client.Query{
		Line: q.Line,
		File: q.File,
		Repo: q.Repo,
	}
}

func (s *searchConnection) handle() {
	s.incoming = make(chan Op, 1)
	s.outgoing = make(chan Op, 1)
	s.errors = make(chan error, 1)

	go s.recvLoop()
	go s.sendLoop()
	defer close(s.outgoing)

	cl := client.ClientWithRetry(func() (client.Client, error) { return client.Dial("tcp", s.srv.config.Backends[0].Addr) })

	var nextQuery *OpQuery
	var inFlight *OpQuery

	var search client.Search
	var results <-chan *client.Result
	var err error

	for {
		select {
		case op, ok := <-s.incoming:
			if !ok {
				break
			}
			switch t := op.(type) {
			case *OpQuery:
				nextQuery = t
			default:
				s.outgoing <- &OpError{fmt.Sprintf("Invalid opcode %s", op.Opcode())}
				break
			}

		case e := <-s.errors:
			log.Printf("error reading from client: %s", e.Error())
			break
		case res, ok := <-results:
			if ok {
				s.outgoing <- &OpResult{inFlight.Id, res}
			} else {
				st, err := search.Close()
				if err == nil {
					s.outgoing <- &OpSearchDone{inFlight.Id, st}
				} else {
					s.outgoing <- &OpQueryError{inFlight.Id, err.Error()}
				}
				results = nil
				search = nil
				inFlight = nil
			}
		}
		if nextQuery != nil && results == nil {
			inFlight = nextQuery
			search, err = cl.Query(query(nextQuery))
			if err != nil {
				s.outgoing <- &OpQueryError{nextQuery.Id, err.Error()}
			} else {
				inFlight = nextQuery
				results = search.Results()
			}
			nextQuery = nil
		}
	}

	s.shutdown = true
}

func (s *server) HandleWebsocket(ws *websocket.Conn) {
	c := &searchConnection{
		srv: s,
		ws:  ws,
	}
	c.handle()
}
<commit_msg>Improve logging, and actually exit on client errors.<commit_after>package server

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/nelhage/livegrep/client"
	"log"
)

type searchConnection struct {
	srv      *server
	ws       *websocket.Conn
	errors   chan error
	incoming chan Op
	outgoing chan Op
	shutdown bool
}

func (s *searchConnection) recvLoop() {
	var op Op
	for {
		if err := OpCodec.Receive(s.ws, &op); err != nil {
			log.Printf("Error in receive: %s\n", err.Error())
			if _, ok := err.(*ProtocolError); ok {
				// TODO: is this a good idea?
				// s.outgoing <- &OpError{err.Error()}
				continue
			} else {
				s.errors <- err
				break
			}
		}
		log.Printf("Incoming: %+v", op)
		s.incoming <- op
		if s.shutdown {
			break
		}
	}
	close(s.incoming)
}

func (s *searchConnection) sendLoop() {
	for op := range s.outgoing {
		log.Printf("Outgoing: %+v", op)
		OpCodec.Send(s.ws, op)
	}
}

func query(q *OpQuery) *client.Query {
	return &client.Query{
		Line: q.Line,
		File: q.File,
		Repo: q.Repo,
	}
}

func (s *searchConnection) handle() {
	s.incoming = make(chan Op, 1)
	s.outgoing = make(chan Op, 1)
	s.errors = make(chan error, 1)

	go s.recvLoop()
	go s.sendLoop()
	defer close(s.outgoing)

	cl := client.ClientWithRetry(func() (client.Client, error) { return client.Dial("tcp", s.srv.config.Backends[0].Addr) })

	var nextQuery *OpQuery
	var inFlight *OpQuery

	var search client.Search
	var results <-chan *client.Result
	var err error

SearchLoop:
	for {
		select {
		case op, ok := <-s.incoming:
			if !ok {
				break
			}
			switch t := op.(type) {
			case *OpQuery:
				nextQuery = t
			default:
				s.outgoing <- &OpError{fmt.Sprintf("Invalid opcode %s", op.Opcode())}
				break
			}

		case e := <-s.errors:
			log.Printf("error reading from client: %s\n", e.Error())
			break SearchLoop
		case res, ok := <-results:
			if ok {
				s.outgoing <- &OpResult{inFlight.Id, res}
			} else {
				st, err := search.Close()
				if err == nil {
					s.outgoing <- &OpSearchDone{inFlight.Id, st}
				} else {
					s.outgoing <- &OpQueryError{inFlight.Id, err.Error()}
				}
				results = nil
				search = nil
				inFlight = nil
			}
		}
		if nextQuery != nil && results == nil {
			inFlight = nextQuery
			search, err = cl.Query(query(nextQuery))
			if err != nil {
				s.outgoing <- &OpQueryError{nextQuery.Id, err.Error()}
			} else {
				inFlight = nextQuery
				results = search.Results()
			}
			nextQuery = nil
		}
	}

	s.shutdown = true
}

func (s *server) HandleWebsocket(ws *websocket.Conn) {
	c := &searchConnection{
		srv: s,
		ws:  ws,
	}
	c.handle()
}
<|endoftext|>


<commit_before>package controllers

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

	"golang.org/x/net/context"

	"github.com/solher/snakepit-seed/constants"
	"github.com/solher/snakepit-seed/errs"
	"github.com/solher/snakepit-seed/models"

	"github.com/Sirupsen/logrus"
	"github.com/ansel1/merry"
	"github.com/solher/arangolite/filters"
	"github.com/solher/snakepit"
	"github.com/spf13/viper"
)

type (
	UsersContext struct {
		AccessToken    string
		CurrentUser    *models.User
		CurrentSession *models.Session
		Key            string
		Filter         *filters.Filter
	}

	UsersInter interface {
		Find(userID string, f *filters.Filter) ([]models.User, error)
		FindByCred(cred *models.Credentials) (*models.User, error)
		FindByKey(userID, id string, f *filters.Filter) (*models.User, error)
		Create(userID string, users []models.User) ([]models.User, error)
		Delete(userID string, f *filters.Filter) ([]models.User, error)
		DeleteByKey(userID, id string) (*models.User, error)
		Update(userID string, user *models.User, f *filters.Filter) ([]models.User, error)
		UpdateByKey(userID, id string, user *models.User) (*models.User, error)
		UpdatePassword(userID, id, password string) (*models.User, error)
	}

	SessionsReaderWriter interface {
		Create(session *models.Session) (*models.Session, error)
		Delete(token string) (*models.Session, error)
	}

	UsersValidator interface {
		Signin(cred *models.Credentials) error
		Creation(users []models.User) error
		Update(user *models.User) error
	}

	Users struct {
		snakepit.Controller
		Context       UsersContext
		Inter         UsersInter
		SessionsInter SessionsReaderWriter
		Validator     UsersValidator
	}
)

func NewUsers(
	c *viper.Viper,
	l *logrus.Entry,
	j *snakepit.JSON,
	ctx UsersContext,
	i UsersInter,
	si SessionsReaderWriter,
	v UsersValidator,
) *Users {
	return &Users{
		Controller:    *snakepit.NewController(c, l, j),
		Context:       ctx,
		Inter:         i,
		SessionsInter: si,
		Validator:     v,
	}
}

// Signin swagger:route POST /users/signin Users UsersSignin
//
// Sign in
//
// Signs in a user and returns a new session.
//
// Responses:
//  200: SessionResponse
func (c *Users) Signin(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	cred := &models.Credentials{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, cred); !ok {
		return
	}

	if err := c.Validator.Signin(cred); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	user, err := c.Inter.FindByCred(cred)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	payload := &models.AuthServerPayload{
		User: user,
		Role: user.Role,
	}

	m, _ := json.Marshal(payload)

	session := &models.Session{
		OwnerToken: user.OwnerToken,
		Agent:      r.UserAgent(),
		Policies:   []string{c.Constants.GetString(constants.PolicyName)},
		Payload:    string(m),
	}

	session, err = c.SessionsInter.Create(session)
	if err != nil {
		c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		return
	}

	session.Policies = nil
	session.Payload = ""
	session.OwnerToken = ""

	c.JSON.Render(ctx, w, http.StatusCreated, session)
}

// CurrentSession swagger:route GET /users/me/session Users UsersCurrentSession
//
// Current session
//
// Returns the current session.
//
// Responses:
//  200: SessionResponse
func (c *Users) CurrentSession(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	c.JSON.Render(ctx, w, http.StatusOK, c.Context.CurrentSession)
}

// Signout swagger:route POST /users/me/signout Users UsersSignout
//
// Sign out
//
// Signs out the current user.
//
// Responses:
//  200: SessionResponse
func (c *Users) Signout(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	session, err := c.SessionsInter.Delete(c.Context.AccessToken)
	if err != nil {
		c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		return
	}

	session.Policies = nil
	session.Payload = ""
	session.OwnerToken = ""

	c.JSON.Render(ctx, w, http.StatusOK, session)
}

// Find swagger:route GET /users Users UsersFind
//
// Find
//
// Finds all the users matched by filter from the data source.
//
// Responses:
//  200: UsersResponse
func (c *Users) Find(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	users, err := c.Inter.Find(c.Context.CurrentUser.ID, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	for i := range users {
		users[i].Password = ""
	}

	c.JSON.Render(ctx, w, http.StatusOK, users)
}

// FindSelf swagger:route GET /users/me Users UsersFindSelf
//
// Find self
//
// Finds the user currently signed in.
//
// Responses:
//  200: UserResponse
func (c *Users) FindSelf(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, err := c.Inter.FindByKey(c.Context.CurrentUser.ID, c.Context.CurrentUser.ID, nil)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// FindByKey swagger:route GET /users/{key} Users UsersFindByKey
//
// Find by key
//
// Finds a user by key from the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) FindByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, err := c.Inter.FindByKey(c.Context.CurrentUser.ID, "users/"+c.Context.Key, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// Create swagger:route POST /users Users UsersCreate
//
// Create
//
// Creates one or multiple users in the data source.
//
// Responses:
//  201: UserResponse
func (c *Users) Create(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var users []models.User

	ok, bulk := c.JSON.UnmarshalBodyBulk(ctx, w, r.Body, &users)
	if !ok {
		return
	}

	if err := c.Validator.Creation(users); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	users, err := c.Inter.Create(c.Context.CurrentUser.ID, users)
	if err != nil {
		c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		return
	}

	if bulk {
		c.JSON.Render(ctx, w, http.StatusCreated, users)
	} else {
		c.JSON.Render(ctx, w, http.StatusCreated, users[0])
	}
}

// Delete swagger:route DELETE /users Users UsersDelete
//
// Delete
//
// Deletes all the users matched by filter in the data source.
//
// Responses:
//  200: UsersResponse
func (c *Users) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	users, err := c.Inter.Delete(c.Context.CurrentUser.ID, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, users)
}

// DeleteByKey swagger:route DELETE /users/{key} Users UsersDeleteByKey
//
// Delete by key
//
// Deletes a user by key in the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) DeleteByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, err := c.Inter.DeleteByKey(c.Context.CurrentUser.ID, "users/"+c.Context.Key)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// Update swagger:route PUT /users Users UsersUpdate
//
// Update
//
// Updates all the users matched by filter in the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) Update(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user := &models.User{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, user); !ok {
		return
	}

	if err := c.Validator.Update(user); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	user.Key = ""
	user.Password = ""
	user.OwnerToken = ""

	users, err := c.Inter.Update(c.Context.CurrentUser.ID, user, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, users)
}

// UpdateByKey swagger:route PUT /users/{key} Users UsersUpdateByKey
//
// Update by key
//
// Updates a user by key in the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) UpdateByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user := &models.User{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, user); !ok {
		return
	}

	if err := c.Validator.Update(user); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	user.Key = ""
	user.Password = ""
	user.OwnerToken = ""

	user, err := c.Inter.UpdateByKey(c.Context.CurrentUser.ID, "users/"+c.Context.Key, user)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// UpdateSelfPassword swagger:route POST /users/me/password Users UsersUpdateSelfPassword
//
// Update self password
//
// Updates the current user password.
//
// Responses:
//  200: UserResponse
func (c *Users) UpdateSelfPassword(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	pwd := &models.Password{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, pwd); !ok {
		return
	}

	if len(pwd.Password) == 0 {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, merry.New("password cannot be blank"))
		return
	}

	user, err := c.Inter.UpdatePassword(c.Context.CurrentUser.ID, c.Context.CurrentUser.ID, pwd.Password)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// // swagger:parameters Users UsersSignout UsersFindSelf
// type tokenParam struct {
// 	// Access token (can also be set via the 'Authorization' header. Ex: 'Authorization: Bearer jhPd6Gf3jIP2h')
// 	//
// 	// in: query
// 	AccessToken string `json:"accessToken"`
// }
<commit_msg>Debug version.<commit_after>package controllers

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

	"golang.org/x/net/context"

	"github.com/solher/snakepit-seed/constants"
	"github.com/solher/snakepit-seed/errs"
	"github.com/solher/snakepit-seed/models"

	"github.com/Sirupsen/logrus"
	"github.com/ansel1/merry"
	"github.com/solher/arangolite/filters"
	"github.com/solher/snakepit"
	"github.com/spf13/viper"
)

type (
	UsersContext struct {
		AccessToken    string
		CurrentUser    *models.User
		CurrentSession *models.Session
		Key            string
		Filter         *filters.Filter
	}

	UsersInter interface {
		Find(userID string, f *filters.Filter) ([]models.User, error)
		FindByCred(cred *models.Credentials) (*models.User, error)
		FindByKey(userID, id string, f *filters.Filter) (*models.User, error)
		Create(userID string, users []models.User) ([]models.User, error)
		Delete(userID string, f *filters.Filter) ([]models.User, error)
		DeleteByKey(userID, id string) (*models.User, error)
		Update(userID string, user *models.User, f *filters.Filter) ([]models.User, error)
		UpdateByKey(userID, id string, user *models.User) (*models.User, error)
		UpdatePassword(userID, id, password string) (*models.User, error)
	}

	SessionsReaderWriter interface {
		Create(session *models.Session) (*models.Session, error)
		Delete(token string) (*models.Session, error)
	}

	UsersValidator interface {
		Signin(cred *models.Credentials) error
		Creation(users []models.User) error
		Update(user *models.User) error
	}

	Users struct {
		snakepit.Controller
		Context       UsersContext
		Inter         UsersInter
		SessionsInter SessionsReaderWriter
		Validator     UsersValidator
	}
)

func NewUsers(
	c *viper.Viper,
	l *logrus.Entry,
	j *snakepit.JSON,
	ctx UsersContext,
	i UsersInter,
	si SessionsReaderWriter,
	v UsersValidator,
) *Users {
	return &Users{
		Controller:    *snakepit.NewController(c, l, j),
		Context:       ctx,
		Inter:         i,
		SessionsInter: si,
		Validator:     v,
	}
}

// Signin swagger:route POST /users/signin Users UsersSignin
//
// Sign in
//
// Signs in a user and returns a new session.
//
// Responses:
//  200: SessionResponse
func (c *Users) Signin(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	cred := &models.Credentials{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, cred); !ok {
		return
	}

	if err := c.Validator.Signin(cred); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	user, err := c.Inter.FindByCred(cred)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	payload := &models.AuthServerPayload{
		User: user,
		Role: user.Role,
	}

	m, _ := json.Marshal(payload)

	session := &models.Session{
		OwnerToken: user.OwnerToken,
		Agent:      r.UserAgent(),
		Policies:   []string{c.Constants.GetString(constants.PolicyName)},
		Payload:    string(m),
	}

	c.Logger.Debug(*session)

	session, err = c.SessionsInter.Create(session)
	if err != nil {
		c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		return
	}

	session.Policies = nil
	session.Payload = ""
	session.OwnerToken = ""

	c.JSON.Render(ctx, w, http.StatusCreated, session)
}

// CurrentSession swagger:route GET /users/me/session Users UsersCurrentSession
//
// Current session
//
// Returns the current session.
//
// Responses:
//  200: SessionResponse
func (c *Users) CurrentSession(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	c.JSON.Render(ctx, w, http.StatusOK, c.Context.CurrentSession)
}

// Signout swagger:route POST /users/me/signout Users UsersSignout
//
// Sign out
//
// Signs out the current user.
//
// Responses:
//  200: SessionResponse
func (c *Users) Signout(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	session, err := c.SessionsInter.Delete(c.Context.AccessToken)
	if err != nil {
		c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		return
	}

	session.Policies = nil
	session.Payload = ""
	session.OwnerToken = ""

	c.JSON.Render(ctx, w, http.StatusOK, session)
}

// Find swagger:route GET /users Users UsersFind
//
// Find
//
// Finds all the users matched by filter from the data source.
//
// Responses:
//  200: UsersResponse
func (c *Users) Find(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	users, err := c.Inter.Find(c.Context.CurrentUser.ID, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	for i := range users {
		users[i].Password = ""
	}

	c.JSON.Render(ctx, w, http.StatusOK, users)
}

// FindSelf swagger:route GET /users/me Users UsersFindSelf
//
// Find self
//
// Finds the user currently signed in.
//
// Responses:
//  200: UserResponse
func (c *Users) FindSelf(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, err := c.Inter.FindByKey(c.Context.CurrentUser.ID, c.Context.CurrentUser.ID, nil)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// FindByKey swagger:route GET /users/{key} Users UsersFindByKey
//
// Find by key
//
// Finds a user by key from the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) FindByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, err := c.Inter.FindByKey(c.Context.CurrentUser.ID, "users/"+c.Context.Key, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// Create swagger:route POST /users Users UsersCreate
//
// Create
//
// Creates one or multiple users in the data source.
//
// Responses:
//  201: UserResponse
func (c *Users) Create(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var users []models.User

	ok, bulk := c.JSON.UnmarshalBodyBulk(ctx, w, r.Body, &users)
	if !ok {
		return
	}

	if err := c.Validator.Creation(users); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	users, err := c.Inter.Create(c.Context.CurrentUser.ID, users)
	if err != nil {
		c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		return
	}

	if bulk {
		c.JSON.Render(ctx, w, http.StatusCreated, users)
	} else {
		c.JSON.Render(ctx, w, http.StatusCreated, users[0])
	}
}

// Delete swagger:route DELETE /users Users UsersDelete
//
// Delete
//
// Deletes all the users matched by filter in the data source.
//
// Responses:
//  200: UsersResponse
func (c *Users) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	users, err := c.Inter.Delete(c.Context.CurrentUser.ID, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, users)
}

// DeleteByKey swagger:route DELETE /users/{key} Users UsersDeleteByKey
//
// Delete by key
//
// Deletes a user by key in the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) DeleteByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, err := c.Inter.DeleteByKey(c.Context.CurrentUser.ID, "users/"+c.Context.Key)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// Update swagger:route PUT /users Users UsersUpdate
//
// Update
//
// Updates all the users matched by filter in the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) Update(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user := &models.User{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, user); !ok {
		return
	}

	if err := c.Validator.Update(user); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	user.Key = ""
	user.Password = ""
	user.OwnerToken = ""

	users, err := c.Inter.Update(c.Context.CurrentUser.ID, user, c.Context.Filter)
	if err != nil {
		switch {
		case merry.Is(err, errs.InvalidFilter):
			c.JSON.RenderError(ctx, w, 422, errs.APIInvalidFilter, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, users)
}

// UpdateByKey swagger:route PUT /users/{key} Users UsersUpdateByKey
//
// Update by key
//
// Updates a user by key in the data source.
//
// Responses:
//  200: UserResponse
func (c *Users) UpdateByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user := &models.User{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, user); !ok {
		return
	}

	if err := c.Validator.Update(user); err != nil {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, err)
		return
	}

	user.Key = ""
	user.Password = ""
	user.OwnerToken = ""

	user, err := c.Inter.UpdateByKey(c.Context.CurrentUser.ID, "users/"+c.Context.Key, user)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// UpdateSelfPassword swagger:route POST /users/me/password Users UsersUpdateSelfPassword
//
// Update self password
//
// Updates the current user password.
//
// Responses:
//  200: UserResponse
func (c *Users) UpdateSelfPassword(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	pwd := &models.Password{}

	if ok := c.JSON.UnmarshalBody(ctx, w, r.Body, pwd); !ok {
		return
	}

	if len(pwd.Password) == 0 {
		c.JSON.RenderError(ctx, w, 422, errs.APIValidation, merry.New("password cannot be blank"))
		return
	}

	user, err := c.Inter.UpdatePassword(c.Context.CurrentUser.ID, c.Context.CurrentUser.ID, pwd.Password)
	if err != nil {
		switch {
		case merry.Is(err, errs.NotFound):
			c.JSON.RenderError(ctx, w, http.StatusForbidden, errs.APIForbidden, err)
		default:
			c.JSON.RenderError(ctx, w, http.StatusInternalServerError, errs.APIInternal, err)
		}
		return
	}

	user.Password = ""

	c.JSON.Render(ctx, w, http.StatusOK, user)
}

// // swagger:parameters Users UsersSignout UsersFindSelf
// type tokenParam struct {
// 	// Access token (can also be set via the 'Authorization' header. Ex: 'Authorization: Bearer jhPd6Gf3jIP2h')
// 	//
// 	// in: query
// 	AccessToken string `json:"accessToken"`
// }
<|endoftext|>