<commit_before>package service

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"runtime"
	"syscall"
	"time"
)

const (
	// Service defaults.
	DefaultStartTimeout = 1 * time.Second
	DefaultStartRetries = 3
	DefaultStopSignal   = syscall.SIGINT
	DefaultStopTimeout  = 5 * time.Second
	DefaultStopRestart  = true

	// Service commands.
	Start    = "start"
	Stop     = "stop"
	Restart  = "restart"
	Shutdown = "shutdown"

	// Service states.
	Starting = "starting"
	Running  = "running"
	Stopping = "stopping"
	Stopped  = "stopped"
	Exited   = "exited"
	Backoff  = "backoff"
	Fatal    = "fatal"
)

// Command is sent to a Service to initiate a state change.
type Command struct {
	Name     string
	Response chan<- Response
}

// respond creates and sends a command Response.
func (cmd Command) respond(service *Service, err error) {
	if cmd.Response != nil {
		cmd.Response <- Response{service, cmd.Name, err}
	}
}

// Response contains the result of a Command.
type Response struct {
	Service *Service
	Name    string
	Error   error
}

// Success returns True if the Command was successful.
func (r Response) Success() bool {
	return r.Error == nil
}

// Event is sent by a Service on a state change.
type Event struct {
	Service *Service // The service from which the event originated.
	State   string   // The new state of the service.
	Error   error    // An error indicating why the service is in Exited or Backoff.
}

// ExitError indicated why the service entered an Exited or Backoff state.
type ExitError string

// Error returns the error message of the ExitError.
func (err ExitError) Error() string {
	return string(err)
}

// Service represents a controllable process. Exported fields may be set to configure the service.
type Service struct {
	Directory    string         // The process's working directory. Defaults to the current directory.
	Environment  []string       // The environment of the process. Defaults to nil which indicatesA the current environment.
	StartTimeout time.Duration  // How long the process has to run before it's considered Running.
	StartRetries int            // How many times to restart a process if it fails to start. Defaults to 3.
	StopSignal   syscall.Signal // The signal to send when stopping the process. Defaults to SIGINT.
	StopTimeout  time.Duration  // How long to wait for a process to stop before sending a SIGKILL. Defaults to 5s.
	StopRestart  bool           // Whether or not to restart the process if it exits unexpectedly. Defaults to true.
	Stdout       io.Writer      // Where to send the process's stdout. Defaults to /dev/null.
	Stderr       io.Writer      // Where to send the process's stderr. Defaults to /dev/null.
	args         []string       // The command line of the process to run.
	command      *exec.Cmd      // The os/exec command running the process.
	state        string         // The state of the Service.
}

// New creates a new service with the default configution.
func NewService(args []string) (svc *Service, err error) {
	if cwd, err := os.Getwd(); err == nil {
		svc = &Service{
			cwd,
			nil,
			DefaultStartTimeout,
			DefaultStartRetries,
			DefaultStopSignal,
			DefaultStopTimeout,
			DefaultStopRestart,
			nil,
			nil,
			args,
			nil,
			Stopped,
		}
	}
	return
}

// State gets the current state of the service.
func (s Service) State() string {
	return s.state
}

// Pid gets the PID of the service or 0 if not Running or Stopping.
func (s Service) Pid() int {
	if s.state != Running && s.state != Stopping {
		return 0
	}
	return s.command.Process.Pid
}

func (s Service) makeCommand() *exec.Cmd {
	cmd := exec.Command(s.args[0], s.args[1:]...)
	cmd.Stdout = s.Stdout
	cmd.Stderr = s.Stderr
	cmd.Stdin = nil
	cmd.Env = s.Environment
	cmd.Dir = s.Directory
	return cmd
}

func (s *Service) Run(commands <-chan Command, events chan<- Event) {
	type ProcessState struct {
		State string
		Error error
	}

	var command *Command = nil
	states := make(chan ProcessState)
	kill := make(chan int, 2)
	retries := 0

	defer func() {
		close(states)
		close(kill)
	}()

	sendResponse := func(err error) {
		if command != nil {
			if command.Response != nil {
				command.respond(s, err)
			}
			command = nil
		}
	}

	sendEvent := func(state string, err error) {
		s.state = state
		events <- Event{s, state, err}

		if command == nil {
			return
		}

		switch command.Name {
		case Restart:
			fallthrough
		case Start:
			if state == Running {
				sendResponse(nil)
			} else if state == Exited || state == Fatal {
				sendResponse(err)
			}
		case Stop:
			if state == Stopped {
				sendResponse(nil)
			} else if state == Exited {
				sendResponse(err)
			}
		}
	}

	invalidStateError := func(state string) error {
		return errors.New(fmt.Sprintf("invalid state transition: %s -> %s", s.state, state))
	}

	start := func() {
		if s.state != Stopped && s.state != Exited && s.state != Backoff && s.state != Fatal {
			sendResponse(invalidStateError(Starting))
			return
		}

		sendEvent(Starting, nil)
		go func() {
			s.command = s.makeCommand()
			if err := s.command.Start(); err == nil {
				waitOver := make(chan bool, 1)
				checkOver := make(chan bool, 1)

				defer func() {
					close(waitOver)
					close(checkOver)
				}()

				go func() {
					time.Sleep(s.StartTimeout)
					select {
					case <-waitOver:
						checkOver <-false
					default:
						states <- ProcessState{Running, nil}
						checkOver <-true
					}
				}()

				exitErr := s.command.Wait()
				waitOver <-true

				msg := ""
				if check := <-checkOver; check {
					if exitErr == nil {
						msg = "process exited normally with success"
					} else {
						msg = fmt.Sprintf("process exited normally with failure: %s", exitErr)
					}
					states <- ProcessState{Exited, ExitError(msg)}
				} else {
					if exitErr == nil {
						msg = "process exited prematurely with success"
					} else {
						msg = fmt.Sprintf("process exited prematurely with failure: %s", exitErr)
					}
					states <- ProcessState{Backoff, ExitError(msg)}
				}
			} else {
				states <- ProcessState{Exited, err}
			}
		}()
	}

	stop := func() {
		if s.state != Running {
			sendResponse(invalidStateError(Stopping))
			return
		}

		sendEvent(Stopping, nil)
		pid := s.Pid()
		s.command.Process.Signal(s.StopSignal) //TODO: Check for error.
		go func() {
			time.Sleep(s.StopTimeout)
			defer func() {
				if err := recover(); err != nil {
					if _, ok := err.(runtime.Error); !ok {
						panic(err)
					}
				}
			}()
			kill <- pid
		}()
	}

	shouldShutdown := func() bool {
		return command != nil && command.Name == Shutdown
	}

	shouldQuit := func() bool {
		return shouldShutdown() && (s.state == Stopped || s.state == Exited || s.state == Fatal)
	}

	for !shouldQuit() {
		select {
		case state := <-states:
			switch state.State {
			case Running:
				retries = 0
				if shouldShutdown() {
					stop()
				} else {
					sendEvent(Running, nil)
				}
			case Exited:
				retries = 0
				if s.state == Stopping {
					sendEvent(Stopped, nil)
				} else {
					sendEvent(Exited, state.Error)
					if s.StopRestart {
						start()
					}
				}
			case Backoff:
				if s.state == Stopping {
					retries = 0
					sendEvent(Stopped, nil)
				} else {
					if retries < s.StartRetries {
						retries++
						sendEvent(Backoff, state.Error)
						start()
					} else {
						retries = 0
						sendEvent(Fatal, state.Error)
					}
				}
			}
		case newCommand := <-commands:
			if command != nil {
				if newCommand.Name == Shutdown {
					// Fail previous command to force shutdown.
					command.respond(s, errors.New("service is shuttind down"))
				} else {
					// Don't allow execution of more than one command at a time.
					newCommand.respond(s, errors.New("command %s is currently executing"))
					continue
				}
			}

			command = &newCommand
			switch command.Name {
			case Start:
				start()
			case Stop:
				stop()
			case Restart:
				switch s.state {
				case Running:
					stop()
				case Stopped:
					start()
				case Exited:
					start()
				case Fatal:
					start()
				default:
					sendResponse(invalidStateError(Stopping))
				}
			case Shutdown:
				switch s.state {
				case Running:
					stop()
				case Backoff:
					s.state = Fatal
				}
			}
		case pid := <-kill:
			if pid == s.Pid() {
				s.command.Process.Kill() //TODO: Check for error.
			}
		}
	}

	if command != nil {
		command.respond(s, nil)
	}
}
<commit_msg>Add EventHook to Service.<commit_after>package service

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"runtime"
	"syscall"
	"time"
)

const (
	// Service defaults.
	DefaultStartTimeout = 1 * time.Second
	DefaultStartRetries = 3
	DefaultStopSignal   = syscall.SIGINT
	DefaultStopTimeout  = 5 * time.Second
	DefaultStopRestart  = true

	// Service commands.
	Start    = "start"
	Stop     = "stop"
	Restart  = "restart"
	Shutdown = "shutdown"

	// Service states.
	Starting = "starting"
	Running  = "running"
	Stopping = "stopping"
	Stopped  = "stopped"
	Exited   = "exited"
	Backoff  = "backoff"
	Fatal    = "fatal"
)

// Command is sent to a Service to initiate a state change.
type Command struct {
	Name     string
	Response chan<- Response
}

// respond creates and sends a command Response.
func (cmd Command) respond(service *Service, err error) {
	if cmd.Response != nil {
		cmd.Response <- Response{service, cmd.Name, err}
	}
}

// Response contains the result of a Command.
type Response struct {
	Service *Service
	Name    string
	Error   error
}

// Success returns True if the Command was successful.
func (r Response) Success() bool {
	return r.Error == nil
}

// Event is sent by a Service on a state change.
type Event struct {
	Service *Service // The service from which the event originated.
	State   string   // The new state of the service.
	Error   error    // An error indicating why the service is in Exited or Backoff.
}

// ExitError indicated why the service entered an Exited or Backoff state.
type ExitError string

// Error returns the error message of the ExitError.
func (err ExitError) Error() string {
	return string(err)
}

// Service represents a controllable process. Exported fields may be set to configure the service.
type Service struct {
	EventHook    func(*Service, string) // Function to call before an event is sent.
	Directory    string         // The process's working directory. Defaults to the current directory.
	Environment  []string       // The environment of the process. Defaults to nil which indicatesA the current environment.
	StartTimeout time.Duration  // How long the process has to run before it's considered Running.
	StartRetries int            // How many times to restart a process if it fails to start. Defaults to 3.
	StopSignal   syscall.Signal // The signal to send when stopping the process. Defaults to SIGINT.
	StopTimeout  time.Duration  // How long to wait for a process to stop before sending a SIGKILL. Defaults to 5s.
	StopRestart  bool           // Whether or not to restart the process if it exits unexpectedly. Defaults to true.
	Stdout       io.Writer      // Where to send the process's stdout. Defaults to /dev/null.
	Stderr       io.Writer      // Where to send the process's stderr. Defaults to /dev/null.
	args         []string       // The command line of the process to run.
	command      *exec.Cmd      // The os/exec command running the process.
	state        string         // The state of the Service.
}

// New creates a new service with the default configution.
func NewService(args []string) (svc *Service, err error) {
	if cwd, err := os.Getwd(); err == nil {
		svc = &Service{
			cwd,
			nil,
			DefaultStartTimeout,
			DefaultStartRetries,
			DefaultStopSignal,
			DefaultStopTimeout,
			DefaultStopRestart,
			nil,
			nil,
			nil,
			args,
			nil,
			Stopped,
		}
	}
	return
}

// State gets the current state of the service.
func (s Service) State() string {
	return s.state
}

// Pid gets the PID of the service or 0 if not Running or Stopping.
func (s Service) Pid() int {
	if s.state != Running && s.state != Stopping {
		return 0
	}
	return s.command.Process.Pid
}

func (s Service) makeCommand() *exec.Cmd {
	cmd := exec.Command(s.args[0], s.args[1:]...)
	cmd.Stdout = s.Stdout
	cmd.Stderr = s.Stderr
	cmd.Stdin = nil
	cmd.Env = s.Environment
	cmd.Dir = s.Directory
	return cmd
}

func (s *Service) Run(commands <-chan Command, events chan<- Event) {
	type ProcessState struct {
		State string
		Error error
	}

	var command *Command = nil
	states := make(chan ProcessState)
	kill := make(chan int, 2)
	retries := 0

	defer func() {
		close(states)
		close(kill)
	}()

	sendResponse := func(err error) {
		if command != nil {
			if command.Response != nil {
				command.respond(s, err)
			}
			command = nil
		}
	}

	sendEvent := func(state string, err error) {
		if s.EventHook != nil {
			s.EventHook(s, state)
		}
		s.state = state
		events <- Event{s, state, err}

		if command == nil {
			return
		}

		switch command.Name {
		case Restart:
			fallthrough
		case Start:
			if state == Running {
				sendResponse(nil)
			} else if state == Exited || state == Fatal {
				sendResponse(err)
			}
		case Stop:
			if state == Stopped {
				sendResponse(nil)
			} else if state == Exited {
				sendResponse(err)
			}
		}
	}

	invalidStateError := func(state string) error {
		return errors.New(fmt.Sprintf("invalid state transition: %s -> %s", s.state, state))
	}

	start := func() {
		if s.state != Stopped && s.state != Exited && s.state != Backoff && s.state != Fatal {
			sendResponse(invalidStateError(Starting))
			return
		}

		sendEvent(Starting, nil)
		go func() {
			s.command = s.makeCommand()
			if err := s.command.Start(); err == nil {
				waitOver := make(chan bool, 1)
				checkOver := make(chan bool, 1)

				defer func() {
					close(waitOver)
					close(checkOver)
				}()

				go func() {
					time.Sleep(s.StartTimeout)
					select {
					case <-waitOver:
						checkOver <-false
					default:
						states <- ProcessState{Running, nil}
						checkOver <-true
					}
				}()

				exitErr := s.command.Wait()
				waitOver <-true

				msg := ""
				if check := <-checkOver; check {
					if exitErr == nil {
						msg = "process exited normally with success"
					} else {
						msg = fmt.Sprintf("process exited normally with failure: %s", exitErr)
					}
					states <- ProcessState{Exited, ExitError(msg)}
				} else {
					if exitErr == nil {
						msg = "process exited prematurely with success"
					} else {
						msg = fmt.Sprintf("process exited prematurely with failure: %s", exitErr)
					}
					states <- ProcessState{Backoff, ExitError(msg)}
				}
			} else {
				states <- ProcessState{Exited, err}
			}
		}()
	}

	stop := func() {
		if s.state != Running {
			sendResponse(invalidStateError(Stopping))
			return
		}

		sendEvent(Stopping, nil)
		pid := s.Pid()
		s.command.Process.Signal(s.StopSignal) //TODO: Check for error.
		go func() {
			time.Sleep(s.StopTimeout)
			defer func() {
				if err := recover(); err != nil {
					if _, ok := err.(runtime.Error); !ok {
						panic(err)
					}
				}
			}()
			kill <- pid
		}()
	}

	shouldShutdown := func() bool {
		return command != nil && command.Name == Shutdown
	}

	shouldQuit := func() bool {
		return shouldShutdown() && (s.state == Stopped || s.state == Exited || s.state == Fatal)
	}

	for !shouldQuit() {
		select {
		case state := <-states:
			switch state.State {
			case Running:
				retries = 0
				if shouldShutdown() {
					stop()
				} else {
					sendEvent(Running, nil)
				}
			case Exited:
				retries = 0
				if s.state == Stopping {
					sendEvent(Stopped, nil)
				} else {
					sendEvent(Exited, state.Error)
					if s.StopRestart {
						start()
					}
				}
			case Backoff:
				if s.state == Stopping {
					retries = 0
					sendEvent(Stopped, nil)
				} else {
					if retries < s.StartRetries {
						retries++
						sendEvent(Backoff, state.Error)
						start()
					} else {
						retries = 0
						sendEvent(Fatal, state.Error)
					}
				}
			}
		case newCommand := <-commands:
			if command != nil {
				if newCommand.Name == Shutdown {
					// Fail previous command to force shutdown.
					command.respond(s, errors.New("service is shuttind down"))
				} else {
					// Don't allow execution of more than one command at a time.
					newCommand.respond(s, errors.New("command %s is currently executing"))
					continue
				}
			}

			command = &newCommand
			switch command.Name {
			case Start:
				start()
			case Stop:
				stop()
			case Restart:
				switch s.state {
				case Running:
					stop()
				case Stopped:
					start()
				case Exited:
					start()
				case Fatal:
					start()
				default:
					sendResponse(invalidStateError(Stopping))
				}
			case Shutdown:
				switch s.state {
				case Running:
					stop()
				case Backoff:
					s.state = Fatal
				}
			}
		case pid := <-kill:
			if pid == s.Pid() {
				s.command.Process.Kill() //TODO: Check for error.
			}
		}
	}

	if command != nil {
		command.respond(s, nil)
	}
}
<|endoftext|>


<commit_before>package console

import (
	"github.com/mibk/syd/event"
	"github.com/nsf/termbox-go"
)

const (
	AttrDefault = 0
	AttrReverse = 1 << iota
	AttrBold
)

type Console struct{}

func (c Console) Init() {
	c.Reinit()
	go c.translateEvents()
}

func (c Console) Reinit() {
	termbox.Init()
}

func (Console) Close() {
	termbox.Close()
}

func (Console) SetCursor(x, y int) {
	termbox.SetCursor(x, y)
}

func (Console) SetCell(x, y int, r rune, attrs uint8) {
	a := termbox.ColorDefault
	if attrs&AttrReverse == AttrReverse {
		a |= termbox.AttrReverse
	}
	if attrs&AttrBold == AttrBold {
		a |= termbox.AttrBold
	}
	termbox.SetCell(x, y, r, a, a)
}

func (Console) Clear() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
}

func (Console) Flush() {
	termbox.Flush()
}

func (Console) Size() (w, h int) {
	return termbox.Size()
}

func (Console) translateEvents() {
Loop:
	for {
		ev := termbox.PollEvent()
		switch ev.Type {
		case termbox.EventKey:
			var outEv event.KeyPress
			if ev.Ch == 0 {
				switch ev.Key {
				case termbox.KeyCtrlSpace:
					outEv = event.KeyPress{Key: ' ', Ctrl: true}
				case termbox.KeyCtrlA:
					outEv = event.KeyPress{Key: 'a', Ctrl: true}
				case termbox.KeyCtrlB:
					outEv = event.KeyPress{Key: 'b', Ctrl: true}
				case termbox.KeyCtrlC:
					outEv = event.KeyPress{Key: 'c', Ctrl: true}
				case termbox.KeyCtrlD:
					outEv = event.KeyPress{Key: 'd', Ctrl: true}
				case termbox.KeyCtrlE:
					outEv = event.KeyPress{Key: 'e', Ctrl: true}
				case termbox.KeyCtrlF:
					outEv = event.KeyPress{Key: 'f', Ctrl: true}
				case termbox.KeyCtrlG:
					outEv = event.KeyPress{Key: 'g', Ctrl: true}
				case termbox.KeyCtrlH:
					outEv = event.KeyPress{Key: 'h', Ctrl: true}
				// Ctrl+I is the same as termbox.KeyTab
				case termbox.KeyCtrlJ:
					outEv = event.KeyPress{Key: 'j', Ctrl: true}
				case termbox.KeyCtrlK:
					outEv = event.KeyPress{Key: 'k', Ctrl: true}
				case termbox.KeyCtrlL:
					outEv = event.KeyPress{Key: 'l', Ctrl: true}
				// Ctrl+M is the same as termbox.KeyEnter
				case termbox.KeyCtrlN:
					outEv = event.KeyPress{Key: 'n', Ctrl: true}
				case termbox.KeyCtrlO:
					outEv = event.KeyPress{Key: 'o', Ctrl: true}
				case termbox.KeyCtrlP:
					outEv = event.KeyPress{Key: 'p', Ctrl: true}
				case termbox.KeyCtrlQ:
					outEv = event.KeyPress{Key: 'q', Ctrl: true}
				case termbox.KeyCtrlR:
					outEv = event.KeyPress{Key: 'r', Ctrl: true}
				case termbox.KeyCtrlS:
					outEv = event.KeyPress{Key: 's', Ctrl: true}
				case termbox.KeyCtrlT:
					outEv = event.KeyPress{Key: 't', Ctrl: true}
				case termbox.KeyCtrlU:
					outEv = event.KeyPress{Key: 'u', Ctrl: true}
				case termbox.KeyCtrlV:
					outEv = event.KeyPress{Key: 'v', Ctrl: true}
				case termbox.KeyCtrlW:
					outEv = event.KeyPress{Key: 'w', Ctrl: true}
				case termbox.KeyCtrlX:
					outEv = event.KeyPress{Key: 'x', Ctrl: true}
				case termbox.KeyCtrlY:
					outEv = event.KeyPress{Key: 'y', Ctrl: true}
				case termbox.KeyCtrlZ:
					outEv = event.KeyPress{Key: 'z', Ctrl: true}

				case termbox.KeySpace:
					outEv = event.KeyPress{Key: ' '}
				case termbox.KeyTab:
					outEv = event.KeyPress{Key: '\t'}
				case termbox.KeyEnter:
					outEv = event.KeyPress{Key: event.Enter}
				case termbox.KeyBackspace2:
					outEv = event.KeyPress{Key: event.Backspace}
				case termbox.KeyDelete:
					outEv = event.KeyPress{Key: event.Delete}
				case termbox.KeyEsc:
					outEv = event.KeyPress{Key: event.Escape}

				case termbox.KeyArrowLeft:
					outEv = event.KeyPress{Key: event.Left}
				case termbox.KeyArrowRight:
					outEv = event.KeyPress{Key: event.Right}
				case termbox.KeyArrowUp:
					outEv = event.KeyPress{Key: event.Up}
				case termbox.KeyArrowDown:
					outEv = event.KeyPress{Key: event.Down}

				case termbox.KeyPgup:
					outEv = event.KeyPress{Key: event.PageUp}
				case termbox.KeyPgdn:
					outEv = event.KeyPress{Key: event.PageDown}

				default:
					continue Loop
				}
			} else {
				outEv = event.KeyPress{Key: event.Key(ev.Ch)}
			}
			event.MakeEvent(outEv)
		}
	}
}
<commit_msg>ui/console: Remove Reinit method<commit_after>package console

import (
	"github.com/mibk/syd/event"
	"github.com/nsf/termbox-go"
)

const (
	AttrDefault = 0
	AttrReverse = 1 << iota
	AttrBold
)

type Console struct{}

func (c Console) Init() {
	termbox.Init()
	go c.translateEvents()
}

func (Console) Close() {
	termbox.Close()
}

func (Console) SetCursor(x, y int) {
	termbox.SetCursor(x, y)
}

func (Console) SetCell(x, y int, r rune, attrs uint8) {
	a := termbox.ColorDefault
	if attrs&AttrReverse == AttrReverse {
		a |= termbox.AttrReverse
	}
	if attrs&AttrBold == AttrBold {
		a |= termbox.AttrBold
	}
	termbox.SetCell(x, y, r, a, a)
}

func (Console) Clear() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
}

func (Console) Flush() {
	termbox.Flush()
}

func (Console) Size() (w, h int) {
	return termbox.Size()
}

func (Console) translateEvents() {
Loop:
	for {
		ev := termbox.PollEvent()
		switch ev.Type {
		case termbox.EventKey:
			var outEv event.KeyPress
			if ev.Ch == 0 {
				switch ev.Key {
				case termbox.KeyCtrlSpace:
					outEv = event.KeyPress{Key: ' ', Ctrl: true}
				case termbox.KeyCtrlA:
					outEv = event.KeyPress{Key: 'a', Ctrl: true}
				case termbox.KeyCtrlB:
					outEv = event.KeyPress{Key: 'b', Ctrl: true}
				case termbox.KeyCtrlC:
					outEv = event.KeyPress{Key: 'c', Ctrl: true}
				case termbox.KeyCtrlD:
					outEv = event.KeyPress{Key: 'd', Ctrl: true}
				case termbox.KeyCtrlE:
					outEv = event.KeyPress{Key: 'e', Ctrl: true}
				case termbox.KeyCtrlF:
					outEv = event.KeyPress{Key: 'f', Ctrl: true}
				case termbox.KeyCtrlG:
					outEv = event.KeyPress{Key: 'g', Ctrl: true}
				case termbox.KeyCtrlH:
					outEv = event.KeyPress{Key: 'h', Ctrl: true}
				// Ctrl+I is the same as termbox.KeyTab
				case termbox.KeyCtrlJ:
					outEv = event.KeyPress{Key: 'j', Ctrl: true}
				case termbox.KeyCtrlK:
					outEv = event.KeyPress{Key: 'k', Ctrl: true}
				case termbox.KeyCtrlL:
					outEv = event.KeyPress{Key: 'l', Ctrl: true}
				// Ctrl+M is the same as termbox.KeyEnter
				case termbox.KeyCtrlN:
					outEv = event.KeyPress{Key: 'n', Ctrl: true}
				case termbox.KeyCtrlO:
					outEv = event.KeyPress{Key: 'o', Ctrl: true}
				case termbox.KeyCtrlP:
					outEv = event.KeyPress{Key: 'p', Ctrl: true}
				case termbox.KeyCtrlQ:
					outEv = event.KeyPress{Key: 'q', Ctrl: true}
				case termbox.KeyCtrlR:
					outEv = event.KeyPress{Key: 'r', Ctrl: true}
				case termbox.KeyCtrlS:
					outEv = event.KeyPress{Key: 's', Ctrl: true}
				case termbox.KeyCtrlT:
					outEv = event.KeyPress{Key: 't', Ctrl: true}
				case termbox.KeyCtrlU:
					outEv = event.KeyPress{Key: 'u', Ctrl: true}
				case termbox.KeyCtrlV:
					outEv = event.KeyPress{Key: 'v', Ctrl: true}
				case termbox.KeyCtrlW:
					outEv = event.KeyPress{Key: 'w', Ctrl: true}
				case termbox.KeyCtrlX:
					outEv = event.KeyPress{Key: 'x', Ctrl: true}
				case termbox.KeyCtrlY:
					outEv = event.KeyPress{Key: 'y', Ctrl: true}
				case termbox.KeyCtrlZ:
					outEv = event.KeyPress{Key: 'z', Ctrl: true}

				case termbox.KeySpace:
					outEv = event.KeyPress{Key: ' '}
				case termbox.KeyTab:
					outEv = event.KeyPress{Key: '\t'}
				case termbox.KeyEnter:
					outEv = event.KeyPress{Key: event.Enter}
				case termbox.KeyBackspace2:
					outEv = event.KeyPress{Key: event.Backspace}
				case termbox.KeyDelete:
					outEv = event.KeyPress{Key: event.Delete}
				case termbox.KeyEsc:
					outEv = event.KeyPress{Key: event.Escape}

				case termbox.KeyArrowLeft:
					outEv = event.KeyPress{Key: event.Left}
				case termbox.KeyArrowRight:
					outEv = event.KeyPress{Key: event.Right}
				case termbox.KeyArrowUp:
					outEv = event.KeyPress{Key: event.Up}
				case termbox.KeyArrowDown:
					outEv = event.KeyPress{Key: event.Down}

				case termbox.KeyPgup:
					outEv = event.KeyPress{Key: event.PageUp}
				case termbox.KeyPgdn:
					outEv = event.KeyPress{Key: event.PageDown}

				default:
					continue Loop
				}
			} else {
				outEv = event.KeyPress{Key: event.Key(ev.Ch)}
			}
			event.MakeEvent(outEv)
		}
	}
}
<|endoftext|>


<commit_before>package meow-data-structures

import (
	"fmt"
	"math/rand"
	"sync"
	"bytes"
	"time"
)

type meowArrayList struct {
	meowCount int
	meowLock *sync.Mutex
	stuffs []interface()
}

func meowNewArrayList() *meowArrayList {
	meowInstance := &meowArrayList {}
	meowInstance.meowLock = &sync.Mutex{}
	meowInstance.stuffs = make([]interface{}, 10)
	meowInstance.meowCount = 0
	rand.Seed(time.Now().UTC()UnixNano())
	return meowInstance
}

func (my *meowArrayList) meowLen() int {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	return my.meowCount
}<commit_msg>add some more<commit_after>// package
package meow-data-structures

// importing other packages
import (
	"fmt"
	"math/rand"
	"sync"
	"bytes"
	"time"
)

// type
type meowArrayList struct {
	meowCount int
	meowLock *sync.Mutex
	stuffs []interface()
}

// meowNewArrayList
func meowNewArrayList() *meowArrayList {
	meowInstance := &meowArrayList {}
	meowInstance.meowLock = &sync.Mutex{}
	meowInstance.stuffs = make([]interface{}, 10)
	meowInstance.meowCount = 0
	rand.Seed(time.Now().UTC()UnixNano())
	return meowInstance
}

// meowLen
func (my *meowArrayList) meowLen() int {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	return my.meowCount
}

// if empty
func (my *meowArrayList) meowEmpty() bool {
	return my.meowLen() == 0
}<|endoftext|>


<commit_before>package utils

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"

	"github.com/techjanitor/pram-post/config"
)

var db *sql.DB

// NewDb initializes a connection to MySQL and tries to connect.
func NewDb() {
	var err error

	db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/%s",
		config.Settings.Database.User,
		config.Settings.Database.Password,
		config.Settings.Database.Proto,
		config.Settings.Database.Host,
		config.Settings.Database.Database,
	))
	if err != nil {
		panic(err)
	}

	err = db.Ping()
	if err != nil {
		panic(err)
	}

	db.SetMaxIdleConns(config.Settings.Database.MaxIdle)
	db.SetMaxOpenConns(config.Settings.Database.MaxConnections)
}

// GetDb returns a connection to MySQL
func GetDb() (*sql.DB, error) {
	return db, nil
}

// GetTransaction will return a transaction
func GetTransaction() (*sql.Tx, error) {
	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	return tx, err
}
<commit_msg>db bool functions<commit_after>package utils

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"

	"github.com/techjanitor/pram-post/config"
)

var db *sql.DB

// NewDb initializes a connection to MySQL and tries to connect.
func NewDb() {
	var err error

	db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/%s",
		config.Settings.Database.User,
		config.Settings.Database.Password,
		config.Settings.Database.Proto,
		config.Settings.Database.Host,
		config.Settings.Database.Database,
	))
	if err != nil {
		panic(err)
	}

	err = db.Ping()
	if err != nil {
		panic(err)
	}

	db.SetMaxIdleConns(config.Settings.Database.MaxIdle)
	db.SetMaxOpenConns(config.Settings.Database.MaxConnections)
}

// GetDb returns a connection to MySQL
func GetDb() (*sql.DB, error) {
	return db, nil
}

// GetTransaction will return a transaction
func GetTransaction() (*sql.Tx, error) {
	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	return tx, err
}

// Check a bool in the database
func GetBool(column, table, row string, id uint) (boolean bool) {
	var boolean bool

	// Check if thread is closed and get the total amount of posts
	err := db.QueryRow("SELECT ? FROM ? WHERE ? = ?", column, table, row, id).Scan(&boolean)
	if err != nil {
		return false
	}

	return

}

// Set a bool in the database
func SetBool(table, column, row string, boolean bool, id uint) (err error) {

	ps, err = db.Prepare("UPDATE ? SET ?=? WHERE ?=?")
	if err != nil {
		return
	}
	defer ps.Close()

	_, err = updatestatus.Exec(table, column, boolean, row, id)
	if err != nil {
		return
	}

	return

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"time"

	"github.com/anacrolix/utp"
)

var (
	flClientMode = flag.Bool("c", true, "client mode")
	flServerMode = flag.Bool("s", false, "server mode")
	flHost       = flag.String("h", "127.0.0.1", "host")
	flPort       = flag.Int("p", 6001, "port")
	flLen        = flag.Int("l", 1400, "length of data")
	flThreads    = flag.Int("t", 1, "threads")
	flDuration   = flag.Duration("d", time.Second*10, "duration")
)

func main() {
	log.Printf("UTP Benchmark Tool by Artem Andreenko (miolini@gmail.com)")
	flag.Parse()
	ts := time.Now()
	wg := sync.WaitGroup{}
	if *flServerMode {
		wg.Add(1)
		go server(&wg, *flHost, *flPort)
	} else {
		wg.Add(*flThreads)
		for i := 0; i < *flThreads; i++ {
			go client(&wg, *flHost, *flPort, *flLen, *flDuration)
		}
	}
	wg.Wait()
	log.Printf("time takes %.2fsec", time.Since(ts).Seconds())
}

func server(wg *sync.WaitGroup, host string, port int) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("error: %s", r)
		}
		wg.Done()
	}()
	log.Printf("server listen %s:%d", host, port)
	s, err := utp.NewSocket("udp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		panic(err)
	}
	defer s.Close()
	for {
		conn, err := s.Accept()
		if err != nil {
			panic(err)
		}
		wg.Add(1)
		go readConn(conn)
	}
}

func readConn(conn net.Conn) {
	defer conn.Close()
	defer log.Printf("client disconnected")
	log.Printf("new connection")
	buf := make([]byte, 4096)
	for {
		_, err := conn.Read(buf)
		if err != nil {
			if err != io.EOF {
				log.Printf("err: %s", err)
			}
			break
		}
	}
}

func client(wg *sync.WaitGroup, host string, port, len int, duration time.Duration) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("error: %s", r)
		}
		log.Printf("disconnected")
		wg.Done()
	}()
	log.Printf("connecting to %s:%d, len %d, duration %s", host, port, len, duration.String())
	conn, err := utp.DialTimeout(fmt.Sprintf("%s:%d", host, port), time.Second)
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	log.Printf("connected")
	buf := bytes.Repeat([]byte("H"), len)
	ts := time.Now()
	te := ts
	count := 0
	for time.Since(ts) < duration {
		since := time.Since(te)
		if since >= time.Second {
			te = time.Now()
			log.Printf("speed %.4f mbit/sec", float64(count)*8/since.Seconds()/1024/1024)
			count = 0
		}
		n, err := conn.Write(buf)
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}
		count += n
	}
}
<commit_msg>disable client mode by default<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"time"

	"github.com/anacrolix/utp"
)

var (
	flClientMode = flag.Bool("c", false, "client mode")
	flServerMode = flag.Bool("s", false, "server mode")
	flHost       = flag.String("h", "127.0.0.1", "host")
	flPort       = flag.Int("p", 6001, "port")
	flLen        = flag.Int("l", 1400, "length of data")
	flThreads    = flag.Int("t", 1, "threads")
	flDuration   = flag.Duration("d", time.Second*10, "duration")
)

func main() {
	log.Printf("UTP Benchmark Tool by Artem Andreenko (miolini@gmail.com)")
	flag.Parse()
	ts := time.Now()
	wg := sync.WaitGroup{}
	if *flServerMode {
		wg.Add(1)
		go server(&wg, *flHost, *flPort)
	} else {
		wg.Add(*flThreads)
		for i := 0; i < *flThreads; i++ {
			go client(&wg, *flHost, *flPort, *flLen, *flDuration)
		}
	}
	wg.Wait()
	log.Printf("time takes %.2fsec", time.Since(ts).Seconds())
}

func server(wg *sync.WaitGroup, host string, port int) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("error: %s", r)
		}
		wg.Done()
	}()
	log.Printf("server listen %s:%d", host, port)
	s, err := utp.NewSocket("udp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		panic(err)
	}
	defer s.Close()
	for {
		conn, err := s.Accept()
		if err != nil {
			panic(err)
		}
		wg.Add(1)
		go readConn(conn)
	}
}

func readConn(conn net.Conn) {
	defer conn.Close()
	defer log.Printf("client disconnected")
	log.Printf("new connection")
	buf := make([]byte, 4096)
	for {
		_, err := conn.Read(buf)
		if err != nil {
			if err != io.EOF {
				log.Printf("err: %s", err)
			}
			break
		}
	}
}

func client(wg *sync.WaitGroup, host string, port, len int, duration time.Duration) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("error: %s", r)
		}
		log.Printf("disconnected")
		wg.Done()
	}()
	log.Printf("connecting to %s:%d, len %d, duration %s", host, port, len, duration.String())
	conn, err := utp.DialTimeout(fmt.Sprintf("%s:%d", host, port), time.Second)
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	log.Printf("connected")
	buf := bytes.Repeat([]byte("H"), len)
	ts := time.Now()
	te := ts
	count := 0
	for time.Since(ts) < duration {
		since := time.Since(te)
		if since >= time.Second {
			te = time.Now()
			log.Printf("speed %.4f mbit/sec", float64(count)*8/since.Seconds()/1024/1024)
			count = 0
		}
		n, err := conn.Write(buf)
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}
		count += n
	}
}
<|endoftext|>


<commit_before>package session

import (
	"bytes"
	"net/http"

	"github.com/alexedwards/scs"
)

func Manage(engine scs.Engine, opts ...Option) func(next http.Handler) http.Handler {
	return func(h http.Handler) http.Handler {
		do := *defaultOptions

		m := &manager{
			h:      h,
			engine: engine,
			opts:   &do,
		}

		for _, option := range opts {
			option(m.opts)
		}

		return m
	}
}

type manager struct {
	h      http.Handler
	engine scs.Engine
	opts   *options
}

func (m *manager) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	sr, err := load(r, m.engine, m.opts)
	if err != nil {
		m.opts.errorFunc(w, r, err)
		return
	}
	bw := &bufferedResponseWriter{ResponseWriter: w}
	m.h.ServeHTTP(bw, sr)

	err = write(w, sr)
	if err != nil {
		m.opts.errorFunc(w, r, err)
		return
	}

	if bw.code != 0 {
		w.WriteHeader(bw.code)
	}
	w.Write(bw.buf.Bytes())
}

type bufferedResponseWriter struct {
	http.ResponseWriter
	buf  bytes.Buffer
	code int
}

func (bw *bufferedResponseWriter) Write(b []byte) (int, error) {
	return bw.buf.Write(b)
}

func (bw *bufferedResponseWriter) WriteHeader(code int) {
	bw.code = code
}

func defaultErrorFunc(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}
<commit_msg>[docs] Make an explicit Middleware type<commit_after>package session

import (
	"bytes"
	"net/http"

	"github.com/alexedwards/scs"
)

type Middleware func(h http.Handler) http.Handler

func Manage(engine scs.Engine, opts ...Option) Middleware {
	return func(h http.Handler) http.Handler {
		do := *defaultOptions

		m := &manager{
			h:      h,
			engine: engine,
			opts:   &do,
		}

		for _, option := range opts {
			option(m.opts)
		}

		return m
	}
}

type manager struct {
	h      http.Handler
	engine scs.Engine
	opts   *options
}

func (m *manager) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	sr, err := load(r, m.engine, m.opts)
	if err != nil {
		m.opts.errorFunc(w, r, err)
		return
	}
	bw := &bufferedResponseWriter{ResponseWriter: w}
	m.h.ServeHTTP(bw, sr)

	err = write(w, sr)
	if err != nil {
		m.opts.errorFunc(w, r, err)
		return
	}

	if bw.code != 0 {
		w.WriteHeader(bw.code)
	}
	w.Write(bw.buf.Bytes())
}

type bufferedResponseWriter struct {
	http.ResponseWriter
	buf  bytes.Buffer
	code int
}

func (bw *bufferedResponseWriter) Write(b []byte) (int, error) {
	return bw.buf.Write(b)
}

func (bw *bufferedResponseWriter) WriteHeader(code int) {
	bw.code = code
}

func defaultErrorFunc(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}
<|endoftext|>


<commit_before>package consul

import (
	"fmt"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/acl"
	"github.com/hashicorp/consul/consul/structs"
	"github.com/hashicorp/go-uuid"
)

// ACL endpoint is used to manipulate ACLs
type ACL struct {
	srv *Server
}

// aclApplyInternal is used to apply an ACL request after it has been vetted that
// this is a valid operation. It is used when users are updating ACLs, in which
// case we check their token to make sure they have management privileges. It is
// also used for ACL replication. We want to run the replicated ACLs through the
// same checks on the change itself. If an operation needs to generate an ID,
// routine will fill in an ID with the args as part of the request.
func aclApplyInternal(srv *Server, args *structs.ACLRequest, reply *string) error {
	switch args.Op {
	case structs.ACLSet:
		// Verify the ACL type
		switch args.ACL.Type {
		case structs.ACLTypeClient:
		case structs.ACLTypeManagement:
		default:
			return fmt.Errorf("Invalid ACL Type")
		}

		// Verify this is not a root ACL
		if acl.RootACL(args.ACL.ID) != nil {
			return fmt.Errorf("%s: Cannot modify root ACL", permissionDenied)
		}

		// Validate the rules compile
		_, err := acl.Parse(args.ACL.Rules)
		if err != nil {
			return fmt.Errorf("ACL rule compilation failed: %v", err)
		}

		// If no ID is provided, generate a new ID. This must
		// be done prior to appending to the raft log, because the ID is not
		// deterministic. Once the entry is in the log, the state update MUST
		// be deterministic or the followers will not converge.
		if args.ACL.ID == "" {
			state := srv.fsm.State()
			for {
				if args.ACL.ID, err = uuid.GenerateUUID(); err != nil {
					srv.logger.Printf("[ERR] consul.acl: UUID generation failed: %v", err)
					return err
				}

				_, acl, err := state.ACLGet(args.ACL.ID)
				if err != nil {
					srv.logger.Printf("[ERR] consul.acl: ACL lookup failed: %v", err)
					return err
				}
				if acl == nil {
					break
				}
			}
		}

	case structs.ACLDelete:
		if args.ACL.ID == "" {
			return fmt.Errorf("Missing ACL ID")
		} else if args.ACL.ID == anonymousToken {
			return fmt.Errorf("%s: Cannot delete anonymous token", permissionDenied)
		}

	default:
		return fmt.Errorf("Invalid ACL Operation")
	}

	// Apply the update
	resp, err := srv.raftApply(structs.ACLRequestType, args)
	if err != nil {
		srv.logger.Printf("[ERR] consul.acl: Apply failed: %v", err)
		return err
	}
	if respErr, ok := resp.(error); ok {
		return respErr
	}

	// Check if the return type is a string
	if respString, ok := resp.(string); ok {
		*reply = respString
	}

	return nil
}

// Apply is used to apply a modifying request to the data store. This should
// only be used for operations that modify the data
func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error {
	if done, err := a.srv.forward("ACL.Apply", args, args, reply); done {
		return err
	}
	defer metrics.MeasureSince([]string{"consul", "acl", "apply"}, time.Now())

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Verify token is permitted to modify ACLs
	if acl, err := a.srv.resolveToken(args.Token); err != nil {
		return err
	} else if acl == nil || !acl.ACLModify() {
		return permissionDeniedErr
	}

	// Do the apply now that this update is vetted.
	if err := aclApplyInternal(a.srv, args, reply); err != nil {
		return err
	}

	// Clear the cache if applicable
	if args.ACL.ID != "" {
		a.srv.aclAuthCache.ClearACL(args.ACL.ID)
	}

	return nil
}

// Get is used to retrieve a single ACL
func (a *ACL) Get(args *structs.ACLSpecificRequest,
	reply *structs.IndexedACLs) error {
	if done, err := a.srv.forward("ACL.Get", args, args, reply); done {
		return err
	}

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Get the local state
	state := a.srv.fsm.State()
	return a.srv.blockingRPC(&args.QueryOptions,
		&reply.QueryMeta,
		state.GetQueryWatch("ACLGet"),
		func() error {
			index, acl, err := state.ACLGet(args.ACL)
			if err != nil {
				return err
			}

			reply.Index = index
			if acl != nil {
				reply.ACLs = structs.ACLs{acl}
			} else {
				reply.ACLs = nil
			}
			return nil
		})
}

// makeACLETag returns an ETag for the given parent and policy.
func makeACLETag(parent string, policy *acl.Policy) string {
	return fmt.Sprintf("%s:%s", parent, policy.ID)
}

// GetPolicy is used to retrieve a compiled policy object with a TTL. Does not
// support a blocking query.
func (a *ACL) GetPolicy(args *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error {
	if done, err := a.srv.forward("ACL.GetPolicy", args, args, reply); done {
		return err
	}

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Get the policy via the cache
	parent, policy, err := a.srv.aclAuthCache.GetACLPolicy(args.ACL)
	if err != nil {
		return err
	}

	// Generate an ETag
	conf := a.srv.config
	etag := makeACLETag(parent, policy)

	// Setup the response
	reply.ETag = etag
	reply.TTL = conf.ACLTTL
	a.srv.setQueryMeta(&reply.QueryMeta)

	// Only send the policy on an Etag mis-match
	if args.ETag != etag {
		reply.Parent = parent
		reply.Policy = policy
	}
	return nil
}

// List is used to list all the ACLs
func (a *ACL) List(args *structs.DCSpecificRequest,
	reply *structs.IndexedACLs) error {
	if done, err := a.srv.forward("ACL.List", args, args, reply); done {
		return err
	}

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Verify token is permitted to list ACLs
	if acl, err := a.srv.resolveToken(args.Token); err != nil {
		return err
	} else if acl == nil || !acl.ACLList() {
		return permissionDeniedErr
	}

	// Get the local state
	state := a.srv.fsm.State()
	return a.srv.blockingRPC(&args.QueryOptions,
		&reply.QueryMeta,
		state.GetQueryWatch("ACLList"),
		func() error {
			index, acls, err := state.ACLList()
			if err != nil {
				return err
			}

			reply.Index, reply.ACLs = index, acls
			return nil
		})
}

// ReplicationStatus is used to retrieve the current ACL replication status.
func (a *ACL) ReplicationStatus(args *structs.DCSpecificRequest,
	reply *structs.ACLReplicationStatus) error {
	// This must be sent to the leader, so we fix the args since we are
	// re-using a structure where we don't support all the options.
	args.RequireConsistent = true
	args.AllowStale = false
	if done, err := a.srv.forward("ACL.ReplicationStatus", args, args, reply); done {
		return err
	}

	// There's no ACL token required here since this doesn't leak any
	// sensitive information, and we don't want people to have to use
	// management tokens if they are querying this via a health check.

	// Poll the latest status.
	a.srv.aclReplicationStatusLock.RLock()
	*reply = a.srv.aclReplicationStatus
	a.srv.aclReplicationStatusLock.RUnlock()
	return nil
}
<commit_msg>Moves ACL ID generation down into the endpoint.<commit_after>package consul

import (
	"fmt"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/consul/acl"
	"github.com/hashicorp/consul/consul/structs"
	"github.com/hashicorp/go-uuid"
)

// ACL endpoint is used to manipulate ACLs
type ACL struct {
	srv *Server
}

// aclApplyInternal is used to apply an ACL request after it has been vetted that
// this is a valid operation. It is used when users are updating ACLs, in which
// case we check their token to make sure they have management privileges. It is
// also used for ACL replication. We want to run the replicated ACLs through the
// same checks on the change itself.
func aclApplyInternal(srv *Server, args *structs.ACLRequest, reply *string) error {
	// All ACLs must have an ID by this point.
	if args.ACL.ID == "" {
		return fmt.Errorf("Missing ACL ID")
	}

	switch args.Op {
	case structs.ACLSet:
		// Verify the ACL type
		switch args.ACL.Type {
		case structs.ACLTypeClient:
		case structs.ACLTypeManagement:
		default:
			return fmt.Errorf("Invalid ACL Type")
		}

		// Verify this is not a root ACL
		if acl.RootACL(args.ACL.ID) != nil {
			return fmt.Errorf("%s: Cannot modify root ACL", permissionDenied)
		}

		// Validate the rules compile
		_, err := acl.Parse(args.ACL.Rules)
		if err != nil {
			return fmt.Errorf("ACL rule compilation failed: %v", err)
		}

	case structs.ACLDelete:
		if args.ACL.ID == anonymousToken {
			return fmt.Errorf("%s: Cannot delete anonymous token", permissionDenied)
		}

	default:
		return fmt.Errorf("Invalid ACL Operation")
	}

	// Apply the update
	resp, err := srv.raftApply(structs.ACLRequestType, args)
	if err != nil {
		srv.logger.Printf("[ERR] consul.acl: Apply failed: %v", err)
		return err
	}
	if respErr, ok := resp.(error); ok {
		return respErr
	}

	// Check if the return type is a string
	if respString, ok := resp.(string); ok {
		*reply = respString
	}

	return nil
}

// Apply is used to apply a modifying request to the data store. This should
// only be used for operations that modify the data
func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error {
	if done, err := a.srv.forward("ACL.Apply", args, args, reply); done {
		return err
	}
	defer metrics.MeasureSince([]string{"consul", "acl", "apply"}, time.Now())

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Verify token is permitted to modify ACLs
	if acl, err := a.srv.resolveToken(args.Token); err != nil {
		return err
	} else if acl == nil || !acl.ACLModify() {
		return permissionDeniedErr
	}

	// If no ID is provided, generate a new ID. This must be done prior to
	// appending to the Raft log, because the ID is not deterministic. Once
	// the entry is in the log, the state update MUST be deterministic or
	// the followers will not converge.
	if args.Op == structs.ACLSet && args.ACL.ID == "" {
		state := a.srv.fsm.State()
		for {
			var err error
			args.ACL.ID, err = uuid.GenerateUUID()
			if err != nil {
				a.srv.logger.Printf("[ERR] consul.acl: UUID generation failed: %v", err)
				return err
			}

			_, acl, err := state.ACLGet(args.ACL.ID)
			if err != nil {
				a.srv.logger.Printf("[ERR] consul.acl: ACL lookup failed: %v", err)
				return err
			}
			if acl == nil {
				break
			}
		}
	}

	// Do the apply now that this update is vetted.
	if err := aclApplyInternal(a.srv, args, reply); err != nil {
		return err
	}

	// Clear the cache if applicable
	if args.ACL.ID != "" {
		a.srv.aclAuthCache.ClearACL(args.ACL.ID)
	}

	return nil
}

// Get is used to retrieve a single ACL
func (a *ACL) Get(args *structs.ACLSpecificRequest,
	reply *structs.IndexedACLs) error {
	if done, err := a.srv.forward("ACL.Get", args, args, reply); done {
		return err
	}

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Get the local state
	state := a.srv.fsm.State()
	return a.srv.blockingRPC(&args.QueryOptions,
		&reply.QueryMeta,
		state.GetQueryWatch("ACLGet"),
		func() error {
			index, acl, err := state.ACLGet(args.ACL)
			if err != nil {
				return err
			}

			reply.Index = index
			if acl != nil {
				reply.ACLs = structs.ACLs{acl}
			} else {
				reply.ACLs = nil
			}
			return nil
		})
}

// makeACLETag returns an ETag for the given parent and policy.
func makeACLETag(parent string, policy *acl.Policy) string {
	return fmt.Sprintf("%s:%s", parent, policy.ID)
}

// GetPolicy is used to retrieve a compiled policy object with a TTL. Does not
// support a blocking query.
func (a *ACL) GetPolicy(args *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error {
	if done, err := a.srv.forward("ACL.GetPolicy", args, args, reply); done {
		return err
	}

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Get the policy via the cache
	parent, policy, err := a.srv.aclAuthCache.GetACLPolicy(args.ACL)
	if err != nil {
		return err
	}

	// Generate an ETag
	conf := a.srv.config
	etag := makeACLETag(parent, policy)

	// Setup the response
	reply.ETag = etag
	reply.TTL = conf.ACLTTL
	a.srv.setQueryMeta(&reply.QueryMeta)

	// Only send the policy on an Etag mis-match
	if args.ETag != etag {
		reply.Parent = parent
		reply.Policy = policy
	}
	return nil
}

// List is used to list all the ACLs
func (a *ACL) List(args *structs.DCSpecificRequest,
	reply *structs.IndexedACLs) error {
	if done, err := a.srv.forward("ACL.List", args, args, reply); done {
		return err
	}

	// Verify we are allowed to serve this request
	if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
		return fmt.Errorf(aclDisabled)
	}

	// Verify token is permitted to list ACLs
	if acl, err := a.srv.resolveToken(args.Token); err != nil {
		return err
	} else if acl == nil || !acl.ACLList() {
		return permissionDeniedErr
	}

	// Get the local state
	state := a.srv.fsm.State()
	return a.srv.blockingRPC(&args.QueryOptions,
		&reply.QueryMeta,
		state.GetQueryWatch("ACLList"),
		func() error {
			index, acls, err := state.ACLList()
			if err != nil {
				return err
			}

			reply.Index, reply.ACLs = index, acls
			return nil
		})
}

// ReplicationStatus is used to retrieve the current ACL replication status.
func (a *ACL) ReplicationStatus(args *structs.DCSpecificRequest,
	reply *structs.ACLReplicationStatus) error {
	// This must be sent to the leader, so we fix the args since we are
	// re-using a structure where we don't support all the options.
	args.RequireConsistent = true
	args.AllowStale = false
	if done, err := a.srv.forward("ACL.ReplicationStatus", args, args, reply); done {
		return err
	}

	// There's no ACL token required here since this doesn't leak any
	// sensitive information, and we don't want people to have to use
	// management tokens if they are querying this via a health check.

	// Poll the latest status.
	a.srv.aclReplicationStatusLock.RLock()
	*reply = a.srv.aclReplicationStatus
	a.srv.aclReplicationStatusLock.RUnlock()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"time"

	"github.com/Sirupsen/logrus"
)

type GetConfigPayload struct {
	FromHostname string
	FromNodeID   string
	TimeStamp    int64
}

type ReturnConfigPayload struct {
	FromHostname  string
	FromNodeID    string
	Configuration MicroConfig
	TimeStamp     int64
}

type MicroConfig map[string]interface{}

func sanitizeConfig(mc MicroConfig) MicroConfig {

	sanitzeFields := []string{
		"secret",
		"node_secret",
		"storage",
		"slave_options",
		"auth_override",
	}

	for _, field_name := range sanitzeFields {
		delete(mc, field_name)
	}

	return mc
}

func getExistingConfig() (MicroConfig, error) {
	microConfig := MicroConfig{}
	dat, err := ioutil.ReadFile(usedConfPath)
	if err != nil {
		return microConfig, err
	}
	if err := json.Unmarshal(dat, &microConfig); err != nil {
		return microConfig, err
	}
	return sanitizeConfig(microConfig), nil
}

func handleSendMiniConfig(payload string) {
	// Decode the configuration from the payload
	configPayload := GetConfigPayload{}
	err := json.Unmarshal([]byte(payload), &configPayload)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Error("Failed unmarshal request: ", err)
		return
	}

	// Make sure payload matches nodeID and hostname
	if configPayload.FromHostname != HostDetails.Hostname && configPayload.FromNodeID != NodeID {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Debug("Configuration request received, no NodeID/Hostname match found, ignoring")
		return
	}

	config, err := getExistingConfig()
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Error("Failed to get existing configuration: ", err)
		return
	}

	returnPayload := ReturnConfigPayload{
		FromHostname:  HostDetails.Hostname,
		FromNodeID:    NodeID,
		Configuration: config,
		TimeStamp:     time.Now().Unix(),
	}

	payloadAsJSON, err := json.Marshal(returnPayload)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Error("Failed to get marshal configuration: ", err)
		return
	}

	asNotification := Notification{
		Command: NoticeGatewayConfigResponse,
		Payload: string(payloadAsJSON),
	}

	MainNotifier.Notify(asNotification)
	log.WithFields(logrus.Fields{
		"prefix": "pub-sub",
	}).Debug("Configuration request responded.")

}
<commit_msg>redis: remove MicroConfig type<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"time"

	"github.com/Sirupsen/logrus"
)

type GetConfigPayload struct {
	FromHostname string
	FromNodeID   string
	TimeStamp    int64
}

type ReturnConfigPayload struct {
	FromHostname  string
	FromNodeID    string
	Configuration map[string]interface{}
	TimeStamp     int64
}

func sanitizeConfig(mc map[string]interface{}) map[string]interface{} {

	sanitzeFields := []string{
		"secret",
		"node_secret",
		"storage",
		"slave_options",
		"auth_override",
	}

	for _, field_name := range sanitzeFields {
		delete(mc, field_name)
	}

	return mc
}

func getExistingConfig() (map[string]interface{}, error) {
	var microConfig map[string]interface{}
	dat, err := ioutil.ReadFile(usedConfPath)
	if err != nil {
		return microConfig, err
	}
	if err := json.Unmarshal(dat, &microConfig); err != nil {
		return microConfig, err
	}
	return sanitizeConfig(microConfig), nil
}

func handleSendMiniConfig(payload string) {
	// Decode the configuration from the payload
	configPayload := GetConfigPayload{}
	err := json.Unmarshal([]byte(payload), &configPayload)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Error("Failed unmarshal request: ", err)
		return
	}

	// Make sure payload matches nodeID and hostname
	if configPayload.FromHostname != HostDetails.Hostname && configPayload.FromNodeID != NodeID {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Debug("Configuration request received, no NodeID/Hostname match found, ignoring")
		return
	}

	config, err := getExistingConfig()
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Error("Failed to get existing configuration: ", err)
		return
	}

	returnPayload := ReturnConfigPayload{
		FromHostname:  HostDetails.Hostname,
		FromNodeID:    NodeID,
		Configuration: config,
		TimeStamp:     time.Now().Unix(),
	}

	payloadAsJSON, err := json.Marshal(returnPayload)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "pub-sub",
		}).Error("Failed to get marshal configuration: ", err)
		return
	}

	asNotification := Notification{
		Command: NoticeGatewayConfigResponse,
		Payload: string(payloadAsJSON),
	}

	MainNotifier.Notify(asNotification)
	log.WithFields(logrus.Fields{
		"prefix": "pub-sub",
	}).Debug("Configuration request responded.")

}
<|endoftext|>


<commit_before>package bandit

import (
	"fmt"
	"math"
	"math/rand"
	"time"
)

// Bandit can select arm or update information
type Bandit interface {
	SelectArm() int
	Update(arm int, reward float64)
	Reset()
	Version() string
}

// NewEpsilonGreedy constructs an epsilon greedy bandit.
func NewEpsilonGreedy(arms int, epsilon float64) (Bandit, error) {
	if !(epsilon >= 0 && epsilon <= 1) {
		return &epsilonGreedy{}, fmt.Errorf("epsilon not in [0, 1]")
	}

	return &epsilonGreedy{
		counts:  make([]int, arms),
		values:  make([]float64, arms),
		rand:    rand.New(rand.NewSource(time.Now().UnixNano())),
		arms:    arms,
		epsilon: epsilon,
	}, nil
}

// epsilonGreedy randomly selects arms with a probability of ε. The rest of
// the time, epsilonGreedy selects the currently best known arm.
type epsilonGreedy struct {
	counts  []int
	values  []float64
	epsilon float64
	arms    int
	rand    *rand.Rand
}

// SelectArm according to EpsilonGreedy strategy
func (e *epsilonGreedy) SelectArm() int {
	arm := 0
	if e.rand.Float64() > e.epsilon {
		// best arm
		for i := range e.values {
			if e.values[i] > e.values[arm] {
				arm = i
			}
		}
	} else {
		// random arm
		arm = e.rand.Intn(e.arms)
	}

	e.counts[arm]++
	return arm + 1
}

// Update the running average
func (e *epsilonGreedy) Update(arm int, reward float64) {
	arm--
	e.counts[arm]++
	count := e.counts[arm]
	e.values[arm] = ((e.values[arm] * float64(count-1)) + reward) / float64(count)
}

// Version returns information on this bandit
func (e *epsilonGreedy) Version() string {
	return fmt.Sprintf("EpsilonGreedy(epsilon=%.2f)", e.epsilon)
}

// Reset returns the bandit to it's newly constructed state
func (e *epsilonGreedy) Reset() {
	e.counts = make([]int, e.arms)
	e.values = make([]float64, e.arms)
	e.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
}

// NewSoftmax constructs a softmax bandit. Softmax explores non randomly
func NewSoftmax(arms int, τ float64) (Bandit, error) {
	if !(τ >= 0.0) {
		return &softmax{}, fmt.Errorf("τ not in [0, ∞]")
	}

	return &softmax{
		counts: make([]int, arms),
		values: make([]float64, arms),
		rand:   rand.New(rand.NewSource(time.Now().UnixNano())),
		arms:   arms,
		tau:    τ,
	}, nil
}

// softmax holds counts values and temperature τ
type softmax struct {
	counts []int
	values []float64
	tau    float64
	arms   int
	rand   *rand.Rand
}

// SelectArm
func (s *softmax) SelectArm() int {
	z := 0.0
	for _, value := range s.values {
		z = z + math.Exp(value/s.tau)
	}

	var distribution []float64
	for _, value := range s.values {
		distribution = append(distribution, math.Exp(value/s.tau)/z)
	}

	accum := 0.0
	for i, p := range distribution {
		accum = accum + p
		if accum > z {
			return i
		}
	}

	return len(distribution) - 1
}

// Update the running average
func (s *softmax) Update(arm int, reward float64) {
	arm--
	s.counts[arm]++
	count := s.counts[arm]
	s.values[arm] = ((s.values[arm] * float64(count-1)) + reward) / float64(count)
}

// Version returns information on this bandit
func (s *softmax) Version() string {
	return fmt.Sprintf("Softmax(tau=%.2f)", s.tau)
}

// Reset returns the bandit to it's newly constructed state
func (s *softmax) Reset() {
	s.counts = make([]int, s.arms)
	s.values = make([]float64, s.arms)
	s.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
}
<commit_msg>EpsilonGreedy should randomly select equally best<commit_after>package bandit

import (
	"fmt"
	"math"
	"math/rand"
	"time"
)

// Bandit can select arm or update information
type Bandit interface {
	SelectArm() int
	Update(arm int, reward float64)
	Reset()
	Version() string
}

// NewEpsilonGreedy constructs an epsilon greedy bandit.
func NewEpsilonGreedy(arms int, epsilon float64) (Bandit, error) {
	if !(epsilon >= 0 && epsilon <= 1) {
		return &epsilonGreedy{}, fmt.Errorf("epsilon not in [0, 1]")
	}

	return &epsilonGreedy{
		counts:  make([]int, arms),
		values:  make([]float64, arms),
		rand:    rand.New(rand.NewSource(time.Now().UnixNano())),
		arms:    arms,
		epsilon: epsilon,
	}, nil
}

// epsilonGreedy randomly selects arms with a probability of ε. The rest of
// the time, epsilonGreedy selects the currently best known arm.
type epsilonGreedy struct {
	counts  []int
	values  []float64
	epsilon float64
	arms    int
	rand    *rand.Rand
}

// SelectArm according to EpsilonGreedy strategy
func (e *epsilonGreedy) SelectArm() int {
	arm := 0
	if e.rand.Float64() > e.epsilon {
		imax, max := []int{}, 0.0
		for i, value := range e.values {
			if value > max {
				max = value
				imax = []int{i}
			} else if value == max {
				imax = append(imax, i)
			}
		}

		// best arm. randomly pick because there may be equally best arms.
		arm = imax[e.rand.Intn(len(imax))]
	} else {
		// random arm
		arm = e.rand.Intn(e.arms)
	}

	e.counts[arm]++
	return arm + 1
}

// Update the running average
func (e *epsilonGreedy) Update(arm int, reward float64) {
	arm--
	e.counts[arm]++
	count := e.counts[arm]
	e.values[arm] = ((e.values[arm] * float64(count-1)) + reward) / float64(count)
}

// Version returns information on this bandit
func (e *epsilonGreedy) Version() string {
	return fmt.Sprintf("EpsilonGreedy(epsilon=%.2f)", e.epsilon)
}

// Reset returns the bandit to it's newly constructed state
func (e *epsilonGreedy) Reset() {
	e.counts = make([]int, e.arms)
	e.values = make([]float64, e.arms)
	e.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
}

// NewSoftmax constructs a softmax bandit. Softmax explores non randomly
func NewSoftmax(arms int, τ float64) (Bandit, error) {
	if !(τ >= 0.0) {
		return &softmax{}, fmt.Errorf("τ not in [0, ∞]")
	}

	return &softmax{
		counts: make([]int, arms),
		values: make([]float64, arms),
		rand:   rand.New(rand.NewSource(time.Now().UnixNano())),
		arms:   arms,
		tau:    τ,
	}, nil
}

// softmax holds counts values and temperature τ
type softmax struct {
	counts []int
	values []float64
	tau    float64
	arms   int
	rand   *rand.Rand
}

// SelectArm
func (s *softmax) SelectArm() int {
	z := 0.0
	for _, value := range s.values {
		z = z + math.Exp(value/s.tau)
	}

	var distribution []float64
	for _, value := range s.values {
		distribution = append(distribution, math.Exp(value/s.tau)/z)
	}

	accum := 0.0
	for i, p := range distribution {
		accum = accum + p
		if accum > z {
			return i
		}
	}

	return len(distribution) - 1
}

// Update the running average
func (s *softmax) Update(arm int, reward float64) {
	arm--
	s.counts[arm]++
	count := s.counts[arm]
	s.values[arm] = ((s.values[arm] * float64(count-1)) + reward) / float64(count)
}

// Version returns information on this bandit
func (s *softmax) Version() string {
	return fmt.Sprintf("Softmax(tau=%.2f)", s.tau)
}

// Reset returns the bandit to it's newly constructed state
func (s *softmax) Reset() {
	s.counts = make([]int, s.arms)
	s.values = make([]float64, s.arms)
	s.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
}
<|endoftext|>


<commit_before>package baudio

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"math"
	//"os"
	"os/exec"
	"runtime"
	"strconv"
	//"time"
)

const (
	FuncValueTypeFloat    = 0
	FuncValueTypeNotFloat = 1
)

type BChannel struct {
	funcValueType int
	funcs         []func(float64, int) float64
}

func newBChannel(fvt int) *BChannel {
	bc := &BChannel{
		funcValueType: fvt,
		funcs:         make([]func(float64, int) float64, 0),
	}
	return bc
}

func (bc *BChannel) push(fn func(float64, int) float64) {
	bc.funcs = append(bc.funcs, fn)
}

type BOptions struct {
	Size int
	Rate int
}

func NewBOptions() *BOptions {
	return &BOptions{
		Size: 2048,
		Rate: 44000,
	}
}

type B struct {
	readable   bool
	size       int
	rate       int
	t          float64
	i          int
	paused     bool
	ended      bool
	destroyed  bool
	channels   []*BChannel
	chEnd      chan bool
	chEndSox   chan bool
	chResume   chan func()
	chNextTick chan bool
	pipeReader *io.PipeReader
	pipeWriter *io.PipeWriter
}

func New(opts *BOptions, fn func(float64, int) float64) *B {
	b := &B{
		readable:   true,
		size:       2048,
		rate:       44000,
		t:          0,
		i:          0,
		paused:     false,
		ended:      false,
		destroyed:  false,
		chEnd:      make(chan bool),
		chEndSox:   make(chan bool),
		chResume:   make(chan func()),
		chNextTick: make(chan bool),
	}
	b.pipeReader, b.pipeWriter = io.Pipe()
	if opts != nil {
		b.size = opts.Size
		b.rate = opts.Rate
	}
	if fn != nil {
		b.Push(fn)
	}
	go func() {
		if b.paused {
			b.chResume <- func() {
				go b.loop()
				b.main()
			}
		} else {
			go b.loop()
			b.main()
		}
	}()
	//go b.loop()
	return b
}

func (b *B) main() {
	for {
		// 2013-02-28 koyachi ここで何かしないとループまわらないのなぜ
		// => fmt.PrinfすることでnodeのnextTick的なものがつまれててそのうちPlay()のread待ちまで進めるのでは。
		//L1:
		//fmt.Println("main loop header")
		//fmt.Printf(".")
		//time.Sleep(1 * time.Millisecond)
		runtime.Gosched()
		select {
		case <-b.chEnd:
			fmt.Println("main chEnd")
			b.terminateMain()
			break
		case fn := <-b.chResume:
			//fmt.Println("main chResume")
			fn()
		case <-b.chNextTick:
			//fmt.Println("main chNextTick")
			go b.loop()
			//b.loop()
		default:
			//fmt.Println("main default")
			//go b.loop()
			//goto L1
		}
	}
}

func (b *B) terminateMain() {
	b.pipeWriter.Close()
	b.ended = true
	b.chEndSox <- true
}

func (b *B) End() {
	b.ended = true
}

func (b *B) Destroy() {
	b.destroyed = true
	b.chEnd <- true
}

func (b *B) Pause() {
	b.paused = true
}

func (b *B) Resume() {
	if !b.paused {
		return
	}
	b.paused = false
	b.chResume <- func() {}
}

func (b *B) AddChannel(funcValueType int, fn func(float64, int) float64) {
	bc := newBChannel(funcValueType)
	bc.push(fn)
	b.channels = append(b.channels, bc)
}

func (b *B) Push(fn func(float64, int) float64) {
	index := len(b.channels)
	if len(b.channels) <= index {
		bc := newBChannel(FuncValueTypeFloat)
		b.channels = append(b.channels, bc)
	}
	b.channels[index].funcs = append(b.channels[index].funcs, fn)
}

func (b *B) loop() {
	buf := b.tick()
	if b.destroyed {
		// no more events
		//fmt.Println("loop destroyed")
	} else if b.paused {
		//fmt.Println("loop paused")
		b.chResume <- func() {
			b.pipeWriter.Write(buf.Bytes())
			b.chNextTick <- true
		}
	} else {
		//fmt.Println("loop !(destroyed || paused)")
		b.pipeWriter.Write(buf.Bytes())
		if b.ended {
			//fmt.Println("loop ended")
			b.chEnd <- true
		} else {
			//fmt.Println("loop !ended")
			b.chNextTick <- true
		}
	}
}

func (b *B) tick() *bytes.Buffer {
	bufSize := b.size * len(b.channels)
	byteBuffer := make([]byte, 0)
	buf := bytes.NewBuffer(byteBuffer)
	for i := 0; i < bufSize; i += 2 {
		lrIndex := int(i / 2)
		lenCh := len(b.channels)
		ch := b.channels[lrIndex%lenCh]
		t := float64(b.t) + math.Floor(float64(lrIndex))/float64(b.rate)/float64(lenCh)
		counter := b.i + int(math.Floor(float64(lrIndex)/float64(lenCh)))

		value := float64(0)
		n := float64(0)
		for j := 0; j < len(ch.funcs); j++ {
			x := ch.funcs[j](float64(t), counter)
			n += x
		}
		n /= float64(len(ch.funcs))

		if ch.funcValueType == FuncValueTypeFloat {
			value = signed(n)
		} else {
			b_ := math.Pow(2, float64(ch.funcValueType))
			x := math.Mod(math.Floor(n), b_) / b_ * math.Pow(2, 15)
			value = x
		}
		if err := binary.Write(buf, binary.LittleEndian, int16(clamp(value))); err != nil {
			panic(err)
		}
	}
	b.i += b.size / 2
	b.t += float64(b.size) / float64(2) / float64(b.rate)
	return buf
}

func clamp(x float64) float64 {
	return math.Max(math.Min(x, math.Pow(2, 15)-1), -math.Pow(2, 15))
}

func signed(n float64) float64 {
	b := math.Pow(2, 15)
	if n > 0 {
		return math.Min(b-1, math.Floor(b*n-1))
	}
	return math.Max(-b, math.Ceil(b*n-1))
}

func mergeArgs(opts, args map[string]string) []string {
	for k, _ := range opts {
		args[k] = opts[k]
	}
	var resultsLast []string
	var results []string
	for k, _ := range args {
		switch k {
		case "-":
			resultsLast = append(resultsLast, k)
		case "-o":
			resultsLast = append(resultsLast, k, args[k])
		default:
			var dash string
			if len(k) == 1 {
				dash = "-"
			} else {
				dash = "--"
			}
			results = append(results, dash+k, args[k])
		}
	}
	results = append(results, resultsLast...)
	fmt.Printf("results = %v\n", results)
	return results
}

func (b *B) runCommand(command string, mergedArgs []string) {
	cmd := exec.Command(command, mergedArgs...)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		panic(err)
	}
	defer func() {
		fmt.Println("runCommand: before stdin.Close()")
		stdin.Close()
	}()
	var out bytes.Buffer
	cmd.Stdout = &out
	// TODO: option
	//cmd.Stdout = os.Stdout
	//cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	defer func() {
		if p := cmd.Process; p != nil {
			fmt.Println("runCommand: before p.Kill()")
			p.Kill()
		}
	}()

	readBuf := make([]byte, b.size*len(b.channels))
	for {
		//fmt.Println("play loop header")
		if _, err := b.pipeReader.Read(readBuf); err != nil {
			panic(err)
		}
		if _, err = stdin.Write(readBuf); err != nil {
			// TODO: more better error handling
			if err.Error() == "write |1: broken pipe" {
				fmt.Printf("ERR: stdin.Write(readBuf): err = %v\n", err)
				runtime.Gosched()
				break
			}
			panic(err)
		}
	}
}

func (b *B) Play(opts map[string]string) {
	go b.runCommand("play", mergeArgs(opts, map[string]string{
		"c": strconv.Itoa(len(b.channels)),
		"r": strconv.Itoa(b.rate),
		"t": "s16",
		"-": "DUMMY",
	}))
	<-b.chEndSox
	b.pipeReader.Close()
}

func (b *B) Record(file string, opts map[string]string) {
	go b.runCommand("sox", mergeArgs(opts, map[string]string{
		"c":  strconv.Itoa(len(b.channels)),
		"r":  strconv.Itoa(b.rate),
		"t":  "s16",
		"-":  "DUMMY",
		"-o": file,
	}))
	<-b.chEndSox
	b.pipeReader.Close()
}
<commit_msg>rename stdin to pipeWriter.<commit_after>package baudio

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"math"
	//"os"
	"os/exec"
	"runtime"
	"strconv"
	//"time"
)

const (
	FuncValueTypeFloat    = 0
	FuncValueTypeNotFloat = 1
)

type BChannel struct {
	funcValueType int
	funcs         []func(float64, int) float64
}

func newBChannel(fvt int) *BChannel {
	bc := &BChannel{
		funcValueType: fvt,
		funcs:         make([]func(float64, int) float64, 0),
	}
	return bc
}

func (bc *BChannel) push(fn func(float64, int) float64) {
	bc.funcs = append(bc.funcs, fn)
}

type BOptions struct {
	Size int
	Rate int
}

func NewBOptions() *BOptions {
	return &BOptions{
		Size: 2048,
		Rate: 44000,
	}
}

type B struct {
	readable   bool
	size       int
	rate       int
	t          float64
	i          int
	paused     bool
	ended      bool
	destroyed  bool
	channels   []*BChannel
	chEnd      chan bool
	chEndSox   chan bool
	chResume   chan func()
	chNextTick chan bool
	pipeReader *io.PipeReader
	pipeWriter *io.PipeWriter
}

func New(opts *BOptions, fn func(float64, int) float64) *B {
	b := &B{
		readable:   true,
		size:       2048,
		rate:       44000,
		t:          0,
		i:          0,
		paused:     false,
		ended:      false,
		destroyed:  false,
		chEnd:      make(chan bool),
		chEndSox:   make(chan bool),
		chResume:   make(chan func()),
		chNextTick: make(chan bool),
	}
	b.pipeReader, b.pipeWriter = io.Pipe()
	if opts != nil {
		b.size = opts.Size
		b.rate = opts.Rate
	}
	if fn != nil {
		b.Push(fn)
	}
	go func() {
		if b.paused {
			b.chResume <- func() {
				go b.loop()
				b.main()
			}
		} else {
			go b.loop()
			b.main()
		}
	}()
	//go b.loop()
	return b
}

func (b *B) main() {
	for {
		// 2013-02-28 koyachi ここで何かしないとループまわらないのなぜ
		// => fmt.PrinfすることでnodeのnextTick的なものがつまれててそのうちPlay()のread待ちまで進めるのでは。
		//L1:
		//fmt.Println("main loop header")
		//fmt.Printf(".")
		//time.Sleep(1 * time.Millisecond)
		runtime.Gosched()
		select {
		case <-b.chEnd:
			fmt.Println("main chEnd")
			b.terminateMain()
			break
		case fn := <-b.chResume:
			//fmt.Println("main chResume")
			fn()
		case <-b.chNextTick:
			//fmt.Println("main chNextTick")
			go b.loop()
			//b.loop()
		default:
			//fmt.Println("main default")
			//go b.loop()
			//goto L1
		}
	}
}

func (b *B) terminateMain() {
	b.pipeWriter.Close()
	b.ended = true
	b.chEndSox <- true
}

func (b *B) End() {
	b.ended = true
}

func (b *B) Destroy() {
	b.destroyed = true
	b.chEnd <- true
}

func (b *B) Pause() {
	b.paused = true
}

func (b *B) Resume() {
	if !b.paused {
		return
	}
	b.paused = false
	b.chResume <- func() {}
}

func (b *B) AddChannel(funcValueType int, fn func(float64, int) float64) {
	bc := newBChannel(funcValueType)
	bc.push(fn)
	b.channels = append(b.channels, bc)
}

func (b *B) Push(fn func(float64, int) float64) {
	index := len(b.channels)
	if len(b.channels) <= index {
		bc := newBChannel(FuncValueTypeFloat)
		b.channels = append(b.channels, bc)
	}
	b.channels[index].funcs = append(b.channels[index].funcs, fn)
}

func (b *B) loop() {
	buf := b.tick()
	if b.destroyed {
		// no more events
		//fmt.Println("loop destroyed")
	} else if b.paused {
		//fmt.Println("loop paused")
		b.chResume <- func() {
			b.pipeWriter.Write(buf.Bytes())
			b.chNextTick <- true
		}
	} else {
		//fmt.Println("loop !(destroyed || paused)")
		b.pipeWriter.Write(buf.Bytes())
		if b.ended {
			//fmt.Println("loop ended")
			b.chEnd <- true
		} else {
			//fmt.Println("loop !ended")
			b.chNextTick <- true
		}
	}
}

func (b *B) tick() *bytes.Buffer {
	bufSize := b.size * len(b.channels)
	byteBuffer := make([]byte, 0)
	buf := bytes.NewBuffer(byteBuffer)
	for i := 0; i < bufSize; i += 2 {
		lrIndex := int(i / 2)
		lenCh := len(b.channels)
		ch := b.channels[lrIndex%lenCh]
		t := float64(b.t) + math.Floor(float64(lrIndex))/float64(b.rate)/float64(lenCh)
		counter := b.i + int(math.Floor(float64(lrIndex)/float64(lenCh)))

		value := float64(0)
		n := float64(0)
		for j := 0; j < len(ch.funcs); j++ {
			x := ch.funcs[j](float64(t), counter)
			n += x
		}
		n /= float64(len(ch.funcs))

		if ch.funcValueType == FuncValueTypeFloat {
			value = signed(n)
		} else {
			b_ := math.Pow(2, float64(ch.funcValueType))
			x := math.Mod(math.Floor(n), b_) / b_ * math.Pow(2, 15)
			value = x
		}
		if err := binary.Write(buf, binary.LittleEndian, int16(clamp(value))); err != nil {
			panic(err)
		}
	}
	b.i += b.size / 2
	b.t += float64(b.size) / float64(2) / float64(b.rate)
	return buf
}

func clamp(x float64) float64 {
	return math.Max(math.Min(x, math.Pow(2, 15)-1), -math.Pow(2, 15))
}

func signed(n float64) float64 {
	b := math.Pow(2, 15)
	if n > 0 {
		return math.Min(b-1, math.Floor(b*n-1))
	}
	return math.Max(-b, math.Ceil(b*n-1))
}

func mergeArgs(opts, args map[string]string) []string {
	for k, _ := range opts {
		args[k] = opts[k]
	}
	var resultsLast []string
	var results []string
	for k, _ := range args {
		switch k {
		case "-":
			resultsLast = append(resultsLast, k)
		case "-o":
			resultsLast = append(resultsLast, k, args[k])
		default:
			var dash string
			if len(k) == 1 {
				dash = "-"
			} else {
				dash = "--"
			}
			results = append(results, dash+k, args[k])
		}
	}
	results = append(results, resultsLast...)
	fmt.Printf("results = %v\n", results)
	return results
}

func (b *B) runCommand(command string, mergedArgs []string) {
	cmd := exec.Command(command, mergedArgs...)
	pipeWriter, err := cmd.StdinPipe()
	if err != nil {
		panic(err)
	}
	defer func() {
		fmt.Println("runCommand: before pipeWriter.Close()")
		pipeWriter.Close()
	}()
	var out bytes.Buffer
	cmd.Stdout = &out
	// TODO: option
	//cmd.Stdout = os.Stdout
	//cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	defer func() {
		if p := cmd.Process; p != nil {
			fmt.Println("runCommand: before p.Kill()")
			p.Kill()
		}
	}()

	readBuf := make([]byte, b.size*len(b.channels))
	for {
		//fmt.Println("play loop header")
		if _, err := b.pipeReader.Read(readBuf); err != nil {
			panic(err)
		}
		if _, err = pipeWriter.Write(readBuf); err != nil {
			// TODO: more better error handling
			if err.Error() == "write |1: broken pipe" {
				fmt.Printf("ERR: pipeWriter.Write(readBuf): err = %v\n", err)
				runtime.Gosched()
				break
			}
			panic(err)
		}
	}
}

func (b *B) Play(opts map[string]string) {
	go b.runCommand("play", mergeArgs(opts, map[string]string{
		"c": strconv.Itoa(len(b.channels)),
		"r": strconv.Itoa(b.rate),
		"t": "s16",
		"-": "DUMMY",
	}))
	<-b.chEndSox
	b.pipeReader.Close()
}

func (b *B) Record(file string, opts map[string]string) {
	go b.runCommand("sox", mergeArgs(opts, map[string]string{
		"c":  strconv.Itoa(len(b.channels)),
		"r":  strconv.Itoa(b.rate),
		"t":  "s16",
		"-":  "DUMMY",
		"-o": file,
	}))
	<-b.chEndSox
	b.pipeReader.Close()
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/lint/lintutil"

import (
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"honnef.co/go/lint"

	"github.com/kisielk/gotool"
)

func usage(name string) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flag.PrintDefaults()
	}
}

type runner struct {
	funcs         []lint.Func
	minConfidence float64
}

func resolveRelative(importPaths []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	// ctx.BuildTags = c.Tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func ProcessArgs(name string, funcs []lint.Func, args []string) {
	flags := flag.FlagSet{
		Usage: usage(name),
	}
	var minConfidence = flags.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
	flags.Parse(args)

	runner := runner{funcs, *minConfidence}
	paths := gotool.ImportPaths(flags.Args())
	goFiles, err := resolveRelative(paths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	if goFiles {
		runner.lintFiles(paths...)
	} else {
		for _, path := range paths {
			runner.lintPackage(path)
		}
	}
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func exists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

func (runner runner) lintFiles(filenames ...string) {
	files := make(map[string][]byte)
	for _, filename := range filenames {
		src, err := ioutil.ReadFile(filename)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			continue
		}
		files[filename] = src
	}

	l := &lint.Linter{
		Funcs: runner.funcs,
	}
	ps, err := l.LintFiles(files)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return
	}
	for _, p := range ps {
		if p.Confidence >= runner.minConfidence {
			fmt.Printf("%v: %s\n", p.Position, p.Text)
		}
	}
}

func (runner runner) lintPackage(pkgname string) {
	pkg, err := build.Import(pkgname, ".", 0)
	runner.lintImportedPackage(pkg, err)
}

func (runner runner) lintImportedPackage(pkg *build.Package, err error) {
	if err != nil {
		if _, nogo := err.(*build.NoGoError); nogo {
			// Don't complain if the failure is due to no Go source files.
			return
		}
		fmt.Fprintln(os.Stderr, err)
		return
	}

	var files []string
	xtest := pkg.XTestGoFiles
	files = append(files, pkg.GoFiles...)
	files = append(files, pkg.CgoFiles...)
	files = append(files, pkg.TestGoFiles...)
	if pkg.Dir != "." {
		for i, f := range files {
			files[i] = filepath.Join(pkg.Dir, f)
		}
		for i, f := range xtest {
			xtest[i] = filepath.Join(pkg.Dir, f)
		}
	}
	runner.lintFiles(xtest...)
	runner.lintFiles(files...)
}
<commit_msg>Support build tags<commit_after>// Copyright (c) 2013 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/lint/lintutil"

import (
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"honnef.co/go/lint"

	"github.com/kisielk/gotool"
)

func usage(name string) func() {
	return func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
		fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flag.PrintDefaults()
	}
}

type runner struct {
	funcs         []lint.Func
	minConfidence float64
	tags          []string
}

func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
	if len(importPaths) == 0 {
		return false, nil
	}
	if strings.HasSuffix(importPaths[0], ".go") {
		// User is specifying a package in terms of .go files, don't resolve
		return true, nil
	}
	wd, err := os.Getwd()
	if err != nil {
		return false, err
	}
	ctx := build.Default
	ctx.BuildTags = runner.tags
	for i, path := range importPaths {
		bpkg, err := ctx.Import(path, wd, build.FindOnly)
		if err != nil {
			return false, fmt.Errorf("can't load package %q: %v", path, err)
		}
		importPaths[i] = bpkg.ImportPath
	}
	return false, nil
}

func ProcessArgs(name string, funcs []lint.Func, args []string) {
	flags := flag.FlagSet{
		Usage: usage(name),
	}
	var minConfidence = flags.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
	var tags = flags.String("tags", "", "List of `build tags`")
	flags.Parse(args)

	runner := runner{funcs, *minConfidence, strings.Fields(*tags)}
	paths := gotool.ImportPaths(flags.Args())
	goFiles, err := runner.resolveRelative(paths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	if goFiles {
		runner.lintFiles(paths...)
	} else {
		for _, path := range paths {
			runner.lintPackage(path)
		}
	}
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func exists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

func (runner runner) lintFiles(filenames ...string) {
	files := make(map[string][]byte)
	for _, filename := range filenames {
		src, err := ioutil.ReadFile(filename)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			continue
		}
		files[filename] = src
	}

	l := &lint.Linter{
		Funcs: runner.funcs,
	}
	ps, err := l.LintFiles(files)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return
	}
	for _, p := range ps {
		if p.Confidence >= runner.minConfidence {
			fmt.Printf("%v: %s\n", p.Position, p.Text)
		}
	}
}

func (runner runner) lintPackage(pkgname string) {
	ctx := build.Default
	ctx.BuildTags = runner.tags
	pkg, err := ctx.Import(pkgname, ".", 0)
	runner.lintImportedPackage(pkg, err)
}

func (runner runner) lintImportedPackage(pkg *build.Package, err error) {
	if err != nil {
		if _, nogo := err.(*build.NoGoError); nogo {
			// Don't complain if the failure is due to no Go source files.
			return
		}
		fmt.Fprintln(os.Stderr, err)
		return
	}

	var files []string
	xtest := pkg.XTestGoFiles
	files = append(files, pkg.GoFiles...)
	files = append(files, pkg.CgoFiles...)
	files = append(files, pkg.TestGoFiles...)
	if pkg.Dir != "." {
		for i, f := range files {
			files[i] = filepath.Join(pkg.Dir, f)
		}
		for i, f := range xtest {
			xtest[i] = filepath.Join(pkg.Dir, f)
		}
	}
	runner.lintFiles(xtest...)
	runner.lintFiles(files...)
}
<|endoftext|>


<commit_before>package cddb

import (
	"bufio"
	"fmt"
	"github.com/hakkin/cddb/abstract"
	"github.com/hakkin/cddb/gracenote"
	"io"
	"net/http"
	"strconv"
	"strings"

	"golang.org/x/net/context"
)

func CddbHttp(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.Trim(r.URL.Path, "/"), "/")

	ctx := abstract.GetContext(r)

	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	var reader io.Reader
	switch r.Method {
	case http.MethodGet:
		reader = strings.NewReader(r.URL.Query().Get("cmd"))
	case http.MethodPost:
		reader = r.Body
	default:
		fmt.Fprint(w, cddbStatus(530, "Unsupported method", true))
		return
	}

	scanner := bufio.NewScanner(reader)
	scanner.Split(bufio.ScanWords)

	scanner.Scan()
	if scanner.Text() != "cddb" {
		fmt.Fprint(w, cddbStatus(500, "Unknown command", true))
		return
	}

	scanner.Scan()
	command := scanner.Text()
	cmdArray := []string{}
	for scanner.Scan() {
		cmdArray = append(cmdArray, scanner.Text())
	}
	switch command {
	case "query":
		queryCmd, ok := createQueryCmd(cmdArray)
		if ok != true {
			abstract.Errorf(ctx, "Query syntax error: %v", cmdArray)
			fmt.Fprint(w, cddbStatus(500, "Command syntax error", true))
			return
		}
		for i, v := range path {
			switch i {
			case 1:
				queryCmd.language = v
			case 2:
				queryCmd.country = v
			}
		}
		response, err := Query(ctx, queryCmd)
		if err != nil {
			abstract.Errorf(ctx, "Query error: %v", err)
			fmt.Fprint(w, err)
			return
		}
		fmt.Fprint(w, response)
	case "read":
		readCmd, ok := createReadCmd(cmdArray)
		if ok != true {
			abstract.Errorf(ctx, "Read syntax error: %v", cmdArray)
			fmt.Fprint(w, cddbStatus(500, "Command syntax error", true))
			return
		}
		for i, v := range path {
			switch i {
			case 1:
				readCmd.language = v
			case 2:
				readCmd.country = v
			}
		}
		response, err := Read(ctx, readCmd)
		if err != nil {
			abstract.Errorf(ctx, "Read error: %v", err)
			fmt.Fprint(w, err)
			return
		}
		fmt.Fprint(w, response)
	default:
		fmt.Fprint(w, cddbStatus(500, "Unknown command", true))
		return
	}
}

func Query(ctx context.Context, queryCmd QueryCmd) (response string, err error) {
	query := gracenote.Queries{Language: queryCmd.language, Country: queryCmd.country}
	query.Auth = gracenote.Auth{Client: cddbConfig.Client, User: cddbConfig.User}
	query.Query = gracenote.Query{Command: "ALBUM_TOC"}

	var offsetsString = []string{}
	for i := range queryCmd.offsets {
		offset := strconv.Itoa(queryCmd.offsets[i])
		offsetsString = append(offsetsString, offset)
	}
	query.Query.TOC = gracenote.TOC{Offsets: strings.Join(offsetsString, " ")}

	albums, err := gracenote.QueryAlbum(ctx, query)
	if err != nil {
		return "", err
	}

	abstract.Infof(ctx, "Query returned %v results", len(albums))

	response, err = queryResponse(albums)
	if err != nil {
		return "", err
	}

	return response, nil
}

func Read(ctx context.Context, readCmd ReadCmd) (response string, err error) {
	query := gracenote.Queries{Language: readCmd.language, Country: readCmd.country}
	query.Auth = gracenote.Auth{Client: cddbConfig.Client, User: cddbConfig.User}
	query.Query = gracenote.Query{Command: "ALBUM_FETCH"}
	query.Query.GN_ID = readCmd.discID

	albums, err := gracenote.QueryAlbum(ctx, query)
	if err != nil {
		return "", err
	}

	if len(albums) != 0 {
		abstract.Infof(ctx, "Read returned %v / %v", albums[0].Artist, albums[0].Title)
	} else {
		abstract.Infof(ctx, "Read didn't find a match")
	}

	response, err = readResponse(albums, readCmd)
	if err != nil {
		return "", nil
	}

	return response, nil
}
<commit_msg>Give generic server error to end users, errors can leak information.<commit_after>package cddb

import (
	"bufio"
	"fmt"
	"github.com/hakkin/cddb/abstract"
	"github.com/hakkin/cddb/gracenote"
	"io"
	"net/http"
	"strconv"
	"strings"

	"golang.org/x/net/context"
)

func CddbHttp(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.Trim(r.URL.Path, "/"), "/")

	ctx := abstract.GetContext(r)

	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	var reader io.Reader
	switch r.Method {
	case http.MethodGet:
		reader = strings.NewReader(r.URL.Query().Get("cmd"))
	case http.MethodPost:
		reader = r.Body
	default:
		fmt.Fprint(w, cddbStatus(530, "Unsupported method", true))
		return
	}

	scanner := bufio.NewScanner(reader)
	scanner.Split(bufio.ScanWords)

	scanner.Scan()
	if scanner.Text() != "cddb" {
		fmt.Fprint(w, cddbStatus(500, "Unknown command", true))
		return
	}

	scanner.Scan()
	command := scanner.Text()
	cmdArray := []string{}
	for scanner.Scan() {
		cmdArray = append(cmdArray, scanner.Text())
	}
	switch command {
	case "query":
		queryCmd, ok := createQueryCmd(cmdArray)
		if ok != true {
			abstract.Errorf(ctx, "Query syntax error: %v", cmdArray)
			fmt.Fprint(w, cddbStatus(500, "Command syntax error", true))
			return
		}
		for i, v := range path {
			switch i {
			case 1:
				queryCmd.language = v
			case 2:
				queryCmd.country = v
			}
		}
		response, err := Query(ctx, queryCmd)
		if err != nil {
			abstract.Errorf(ctx, "Query error: %v", err)
			fmt.Fprint(w, cddbStatus(402, "Server error", true))
			return
		}
		fmt.Fprint(w, response)
	case "read":
		readCmd, ok := createReadCmd(cmdArray)
		if ok != true {
			abstract.Errorf(ctx, "Read syntax error: %v", cmdArray)
			fmt.Fprint(w, cddbStatus(500, "Command syntax error", true))
			return
		}
		for i, v := range path {
			switch i {
			case 1:
				readCmd.language = v
			case 2:
				readCmd.country = v
			}
		}
		response, err := Read(ctx, readCmd)
		if err != nil {
			abstract.Errorf(ctx, "Read error: %v", err)
			fmt.Fprint(w, cddbStatus(402, "Server error", true))
			return
		}
		fmt.Fprint(w, response)
	default:
		fmt.Fprint(w, cddbStatus(500, "Unknown command", true))
		return
	}
}

func Query(ctx context.Context, queryCmd QueryCmd) (response string, err error) {
	query := gracenote.Queries{Language: queryCmd.language, Country: queryCmd.country}
	query.Auth = gracenote.Auth{Client: cddbConfig.Client, User: cddbConfig.User}
	query.Query = gracenote.Query{Command: "ALBUM_TOC"}

	var offsetsString = []string{}
	for i := range queryCmd.offsets {
		offset := strconv.Itoa(queryCmd.offsets[i])
		offsetsString = append(offsetsString, offset)
	}
	query.Query.TOC = gracenote.TOC{Offsets: strings.Join(offsetsString, " ")}

	albums, err := gracenote.QueryAlbum(ctx, query)
	if err != nil {
		return "", err
	}

	abstract.Infof(ctx, "Query returned %v results", len(albums))

	response, err = queryResponse(albums)
	if err != nil {
		return "", err
	}

	return response, nil
}

func Read(ctx context.Context, readCmd ReadCmd) (response string, err error) {
	query := gracenote.Queries{Language: readCmd.language, Country: readCmd.country}
	query.Auth = gracenote.Auth{Client: cddbConfig.Client, User: cddbConfig.User}
	query.Query = gracenote.Query{Command: "ALBUM_FETCH"}
	query.Query.GN_ID = readCmd.discID

	albums, err := gracenote.QueryAlbum(ctx, query)
	if err != nil {
		return "", err
	}

	if len(albums) != 0 {
		abstract.Infof(ctx, "Read returned %v / %v", albums[0].Artist, albums[0].Title)
	} else {
		abstract.Infof(ctx, "Read didn't find a match")
	}

	response, err = readResponse(albums, readCmd)
	if err != nil {
		return "", nil
	}

	return response, nil
}
<|endoftext|>