<commit_before>package service

import (
	"fmt"

	"github.com/juju/errors"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

var _ Service = (*upstart.Service)(nil)
var _ Service = (*windows.Service)(nil)

// Service represents a service running on the current system
type Service interface {
	// Name returns the service's name.
	Name() string

	// Conf returns the service's conf data.
	Conf() common.Conf

	// Config adds a config to the service, overwritting the current one
	UpdateConfig(conf common.Conf)

	// Running returns a boolean value that denotes
	// whether or not the service is running
	Running() bool

	// Start will try to start the service
	Start() error

	// Stop will try to stop the service
	Stop() error

	// TODO(ericsnow) Eliminate StopAndRemove.

	// StopAndRemove will stop the service and remove it
	StopAndRemove() error

	// Exists returns whether the service configuration exists in the
	// init directory with the same content that this Service would have
	// if installed.
	Exists() bool

	// Installed will return a boolean value that denotes
	// whether or not the service is installed
	Installed() bool

	// Install installs a service
	Install() error

	// Remove will remove the service
	Remove() error

	// InstallCommands returns the list of commands to run on a
	// (remote) host to install the service.
	InstallCommands() ([]string, error)
}

// TODO(ericsnow) Eliminate the need to pass an empty conf here for
// most service methods.

// NewService returns a new Service based on the provided info.
func NewService(name string, conf common.Conf, initSystem string) (Service, error) {
	switch initSystem {
	case "windows":
		return windows.NewService(name, conf), nil
	case "upstart":
		return upstart.NewService(name, conf), nil
	default:
		return nil, errors.NotFoundf("init system %q", initSystem)
	}
}

// DiscoverService returns an interface to a service apropriate
// for the current system
func DiscoverService(name string, conf common.Conf) (Service, error) {
	initName := VersionInitSystem(version.Current)
	if initName == "" {
		return nil, errors.NotFoundf("init system on local host")
	}

	service, err := NewService(name, conf, initName)
	return service, errors.Trace(err)
}

// VersionInitSystem returns an init system name based on the provided
// version info.
func VersionInitSystem(vers version.Binary) string {
	switch vers.OS {
	case version.Windows:
		return "windows"
	case version.Ubuntu:
		switch vers.Series {
		case "precise", "quantal", "raring", "saucy", "trusty", "utopic":
			return "upstart"
		default:
			// vivid and later
			return "systemd"
		}
		// TODO(ericsnow) Support other OSes, like version.CentOS.
	default:
		return ""
	}
}

// ListServices lists all installed services on the running system
func ListServices(initDir string) ([]string, error) {
	initName := VersionInitSystem(version.Current)
	if initName == "" {
		return nil, errors.NotFoundf("init system on local host")
	}

	switch initName {
	case "windows":
		services, err := windows.ListServices()
		return services, errors.Trace(err)
	case "upstart":
		services, err := upstart.ListServices(initDir)
		return services, errors.Trace(err)
	default:
		return nil, errors.NotFoundf("init system %q", initName)
	}
}

var linuxExecutables = map[string]string{
	"/sbin/init": "upstart",
}

// TODO(ericsnow) Is it to much to cat once for each executable?
const initSystemTest = `[[ "$(cat /proc/1/cmdline)" == "%s" ]]`

// ListServicesCommand returns the command that should be run to get
// a list of service names on a host.
func ListServicesCommand() string {
	// TODO(ericsnow) Allow passing in "initSystems ...string".
	executables := linuxExecutables

	// TODO(ericsnow) build the command in a better way?

	cmdAll := ""
	for executable, initSystem := range executables {
		cmd := listServicesCommand(initSystem)
		if cmd == "" {
			continue
		}

		test := fmt.Sprintf(initSystemTest, executable)
		cmd = fmt.Sprintf("if %s; then %s\n", test, cmd)
		if cmdAll != "" {
			cmd = "el" + cmd
		}
		cmdAll += cmd
	}
	if cmdAll != "" {
		cmdAll += "fi"
	}
	return cmdAll
}

func listServicesCommand(initSystem string) string {
	switch initSystem {
	case "windows":
		return windows.ListCommand()
	case "upstart":
		return upstart.ListCommand()
	default:
		return ""
	}
}
<commit_msg>Fix a TODO typo.<commit_after>package service

import (
	"fmt"

	"github.com/juju/errors"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

var _ Service = (*upstart.Service)(nil)
var _ Service = (*windows.Service)(nil)

// Service represents a service running on the current system
type Service interface {
	// Name returns the service's name.
	Name() string

	// Conf returns the service's conf data.
	Conf() common.Conf

	// Config adds a config to the service, overwritting the current one
	UpdateConfig(conf common.Conf)

	// Running returns a boolean value that denotes
	// whether or not the service is running
	Running() bool

	// Start will try to start the service
	Start() error

	// Stop will try to stop the service
	Stop() error

	// TODO(ericsnow) Eliminate StopAndRemove.

	// StopAndRemove will stop the service and remove it
	StopAndRemove() error

	// Exists returns whether the service configuration exists in the
	// init directory with the same content that this Service would have
	// if installed.
	Exists() bool

	// Installed will return a boolean value that denotes
	// whether or not the service is installed
	Installed() bool

	// Install installs a service
	Install() error

	// Remove will remove the service
	Remove() error

	// InstallCommands returns the list of commands to run on a
	// (remote) host to install the service.
	InstallCommands() ([]string, error)
}

// TODO(ericsnow) Eliminate the need to pass an empty conf here for
// most service methods.

// NewService returns a new Service based on the provided info.
func NewService(name string, conf common.Conf, initSystem string) (Service, error) {
	switch initSystem {
	case "windows":
		return windows.NewService(name, conf), nil
	case "upstart":
		return upstart.NewService(name, conf), nil
	default:
		return nil, errors.NotFoundf("init system %q", initSystem)
	}
}

// DiscoverService returns an interface to a service apropriate
// for the current system
func DiscoverService(name string, conf common.Conf) (Service, error) {
	initName := VersionInitSystem(version.Current)
	if initName == "" {
		return nil, errors.NotFoundf("init system on local host")
	}

	service, err := NewService(name, conf, initName)
	return service, errors.Trace(err)
}

// VersionInitSystem returns an init system name based on the provided
// version info.
func VersionInitSystem(vers version.Binary) string {
	switch vers.OS {
	case version.Windows:
		return "windows"
	case version.Ubuntu:
		switch vers.Series {
		case "precise", "quantal", "raring", "saucy", "trusty", "utopic":
			return "upstart"
		default:
			// vivid and later
			return "systemd"
		}
		// TODO(ericsnow) Support other OSes, like version.CentOS.
	default:
		return ""
	}
}

// ListServices lists all installed services on the running system
func ListServices(initDir string) ([]string, error) {
	initName := VersionInitSystem(version.Current)
	if initName == "" {
		return nil, errors.NotFoundf("init system on local host")
	}

	switch initName {
	case "windows":
		services, err := windows.ListServices()
		return services, errors.Trace(err)
	case "upstart":
		services, err := upstart.ListServices(initDir)
		return services, errors.Trace(err)
	default:
		return nil, errors.NotFoundf("init system %q", initName)
	}
}

var linuxExecutables = map[string]string{
	"/sbin/init": "upstart",
}

// TODO(ericsnow) Is it too much to cat once for each executable?
const initSystemTest = `[[ "$(cat /proc/1/cmdline)" == "%s" ]]`

// ListServicesCommand returns the command that should be run to get
// a list of service names on a host.
func ListServicesCommand() string {
	// TODO(ericsnow) Allow passing in "initSystems ...string".
	executables := linuxExecutables

	// TODO(ericsnow) build the command in a better way?

	cmdAll := ""
	for executable, initSystem := range executables {
		cmd := listServicesCommand(initSystem)
		if cmd == "" {
			continue
		}

		test := fmt.Sprintf(initSystemTest, executable)
		cmd = fmt.Sprintf("if %s; then %s\n", test, cmd)
		if cmdAll != "" {
			cmd = "el" + cmd
		}
		cmdAll += cmd
	}
	if cmdAll != "" {
		cmdAll += "fi"
	}
	return cmdAll
}

func listServicesCommand(initSystem string) string {
	switch initSystem {
	case "windows":
		return windows.ListCommand()
	case "upstart":
		return upstart.ListCommand()
	default:
		return ""
	}
}
<|endoftext|>


<commit_before>package service

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
	"time"

	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/go-etcd/etcd"
	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/manners"
	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/metrics"
	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/scroll"
	"github.com/FoxComm/vulcand/api"
	"github.com/FoxComm/vulcand/engine"
	"github.com/FoxComm/vulcand/engine/etcdng"
	"github.com/FoxComm/vulcand/engine/memng"
	"github.com/FoxComm/vulcand/engine/tomlng"
	"github.com/FoxComm/vulcand/log"
	"github.com/FoxComm/vulcand/plugin"
	"github.com/FoxComm/vulcand/proxy"
	"github.com/FoxComm/vulcand/secret"
	"github.com/FoxComm/vulcand/stapler"
	"github.com/FoxComm/vulcand/supervisor"
)

func Run(registry *plugin.Registry) error {
	options, err := ParseCommandLine()
	if err != nil {
		return fmt.Errorf("failed to parse command line: %s", err)
	}
	service := NewService(options, registry)
	if err := service.Start(); err != nil {
		log.Errorf("Failed to start service: %v", err)
		return fmt.Errorf("service start failure: %s", err)
	} else {
		log.Infof("Service exited gracefully")
	}
	return nil
}

type Service struct {
	client        *etcd.Client
	options       Options
	registry      *plugin.Registry
	apiApp        *scroll.App
	errorC        chan error
	sigC          chan os.Signal
	stopC         chan bool
	supervisor    *supervisor.Supervisor
	metricsClient metrics.Client
	apiServer     *manners.GracefulServer
	ng            engine.Engine
	stapler       stapler.Stapler
}

func NewService(options Options, registry *plugin.Registry) *Service {
	return &Service{
		registry: registry,
		options:  options,
		errorC:   make(chan error),
		// Channel receiving signals has to be non blocking, otherwise the service can miss a signal.
		sigC:  make(chan os.Signal, 1024),
		stopC: make(chan bool, 1),
	}
}

func (s *Service) Start() error {
	log.EnsureLoggerExist(s.options.Log, s.options.LogSeverity.String())

	log.Infof("Service starts with options: %#v", s.options)

	if s.options.PidPath != "" {
		ioutil.WriteFile(s.options.PidPath, []byte(fmt.Sprint(os.Getpid())), 0644)
	}

	if s.options.StatsdAddr != "" {
		var err error
		s.metricsClient, err = metrics.NewWithOptions(s.options.StatsdAddr, s.options.StatsdPrefix, metrics.Options{UseBuffering: true})
		if err != nil {
			return err
		}
	}

	apiFile, muxFiles, err := s.getFiles()
	if err != nil {
		return err
	}

	if err := s.newEngine(); err != nil {
		return err
	}

	s.stapler = stapler.New()
	s.supervisor = supervisor.New(
		s.newProxy, s.ng, s.errorC, supervisor.Options{Files: muxFiles})

	// Tells configurator to perform initial proxy configuration and start watching changes
	if err := s.supervisor.Start(); err != nil {
		return err
	}

	if err := s.initApi(); err != nil {
		return err
	}

	go func() {
		s.errorC <- s.startApi(apiFile)
	}()

	if s.metricsClient != nil {
		go s.reportSystemMetrics()
	}
	signal.Notify(s.sigC, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGUSR2, syscall.SIGCHLD)

	// Block until a signal is received or we got an error
	for {
		select {
		case <-s.stopC:
			log.Infof("Get stop message, shutting down gracefully")
			s.supervisor.Stop(true)
			log.Infof("All servers stopped")
			return nil
		case signal := <-s.sigC:
			switch signal {
			case syscall.SIGTERM, syscall.SIGINT:
				log.Infof("Got signal '%s', shutting down gracefully", signal)
				s.supervisor.Stop(true)
				log.Infof("All servers stopped")
				return nil
			case syscall.SIGKILL:
				log.Infof("Got signal '%s', exiting now without waiting", signal)
				s.supervisor.Stop(false)
				return nil
			case syscall.SIGUSR2:
				log.Infof("Got signal '%s', forking a new self", signal)
				if err := s.startChild(); err != nil {
					log.Infof("Failed to start self: %s", err)
				} else {
					log.Infof("Successfully started self")
				}
			case syscall.SIGCHLD:
				log.Warningf("Child exited, got '%s', collecting status", signal)
				var wait syscall.WaitStatus
				syscall.Wait4(-1, &wait, syscall.WNOHANG, nil)
				log.Warningf("Collected exit status from child")
			default:
				log.Infof("Ignoring '%s'", signal)
			}
		case err := <-s.errorC:
			log.Infof("Got request to shutdown with error: %s", err)
			return err
		}
	}
}

func (s *Service) Stop() {
	s.stopC <- true
}

func (s Service) GetEngine() engine.Engine {
	return s.ng
}

func (s *Service) getFiles() (*proxy.FileDescriptor, []*proxy.FileDescriptor, error) {
	// These files may be passed in by the parent process
	filesString := os.Getenv(vulcandFilesKey)
	if filesString == "" {
		return nil, nil, nil
	}

	files, err := filesFromString(filesString)
	if err != nil {
		return nil, nil, fmt.Errorf("child failed to start: failed to read files from string, error %s", err)
	}

	if len(files) != 0 {
		log.Infof("I am a child that has been passed files: %s", files)
	}

	return s.splitFiles(files)
}

func (s *Service) splitFiles(files []*proxy.FileDescriptor) (*proxy.FileDescriptor, []*proxy.FileDescriptor, error) {
	apiAddr := fmt.Sprintf("%s:%d", s.options.ApiInterface, s.options.ApiPort)
	for i, f := range files {
		if f.Address.Address == apiAddr {
			return files[i], append(files[:i], files[i+1:]...), nil
		}
	}
	return nil, nil, fmt.Errorf("API address %s not found in %s", apiAddr, files)
}

func (s *Service) startChild() error {
	log.Infof("Starting child")
	path, err := execPath()
	if err != nil {
		return err
	}

	wd, err := os.Getwd()
	if nil != err {
		return err
	}

	// Get socket files currently in use by the underlying http server controlled by supervisor
	extraFiles, err := s.supervisor.GetFiles()
	if err != nil {
		return err
	}

	apiFile, err := s.GetAPIFile()
	if err != nil {
		return err
	}

	extraFiles = append(extraFiles, apiFile)

	// These files will be passed to the child process
	files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
	for _, f := range extraFiles {
		files = append(files, f.File)
	}

	// Serialize files to JSON string representation
	vals, err := filesToString(extraFiles)
	if err != nil {
		return err
	}

	log.Infof("Passing %s to child", vals)
	os.Setenv(vulcandFilesKey, vals)

	p, err := os.StartProcess(path, os.Args, &os.ProcAttr{
		Dir:   wd,
		Env:   os.Environ(),
		Files: files,
		Sys:   &syscall.SysProcAttr{},
	})

	if err != nil {
		return err
	}

	log.Infof("Started new child pid=%d binary=%s", p.Pid, path)
	return nil
}

func (s *Service) GetAPIFile() (*proxy.FileDescriptor, error) {
	file, err := s.apiServer.GetFile()
	if err != nil {
		return nil, err
	}
	a := engine.Address{
		Network: "tcp",
		Address: fmt.Sprintf("%s:%d", s.options.ApiInterface, s.options.ApiPort),
	}
	return &proxy.FileDescriptor{File: file, Address: a}, nil
}

func (s *Service) newBox() (*secret.Box, error) {
	if s.options.SealKey == "" {
		return nil, nil
	}
	key, err := secret.KeyFromString(s.options.SealKey)
	if err != nil {
		return nil, err
	}
	return secret.NewBox(key)
}

func (s *Service) newEngine() error {
	box, err := s.newBox()
	if err != nil {
		return err
	}
	var ng engine.Engine

	switch s.options.EngineType {
	case "etcd":
		ng, err = etcdng.New(
			s.options.EtcdNodes,
			s.options.EtcdKey,
			s.registry,
			etcdng.Options{
				EtcdCaFile:      s.options.EtcdCaFile,
				EtcdCertFile:    s.options.EtcdCertFile,
				EtcdKeyFile:     s.options.EtcdKeyFile,
				EtcdConsistency: s.options.EtcdConsistency,
				Box:             box,
			})
	case "toml":
		ng, err = tomlng.New(s.registry,
			tomlng.Options{
				MainConfigFilepath: s.options.TomlPath,
				ConfigPaths:        s.options.TomlConfigPaths,
				WatchConfigChanges: s.options.TomlWatchConfigChanges,
			})
	case "mem":
		ng = memng.New(s.registry)
	}

	if err != nil {
		return fmt.Errorf("Engine creation error: %v", err)
	}
	s.ng = ng
	return nil
}

func (s *Service) reportSystemMetrics() {
	defer func() {
		if r := recover(); r != nil {
			log.Infof("Recovered in reportSystemMetrics", r)
		}
	}()
	for {
		s.metricsClient.ReportRuntimeMetrics("sys", 1.0)
		// we have 256 time buckets for gc stats, GC is being executed every 4ms on average
		// so we have 256 * 4 = 1024 around one second to report it. To play safe, let's report every 300ms
		time.Sleep(300 * time.Millisecond)
	}
}

func (s *Service) newProxy(id int) (proxy.Proxy, error) {
	return proxy.New(id, s.stapler, proxy.Options{
		MetricsClient:  s.metricsClient,
		DialTimeout:    s.options.EndpointDialTimeout,
		ReadTimeout:    s.options.ServerReadTimeout,
		WriteTimeout:   s.options.ServerWriteTimeout,
		MaxHeaderBytes: s.options.ServerMaxHeaderBytes,
		DefaultListener: &engine.Listener{
			Id:       "DefaultListener",
			Protocol: "http",
			Address: engine.Address{
				Network: "tcp",
				Address: fmt.Sprintf("%s:%d", s.options.Interface, s.options.Port),
			},
		},
		NotFoundMiddleware: s.registry.GetNotFoundMiddleware(),
	})
}

func (s *Service) initApi() error {
	s.apiApp = scroll.NewApp()
	api.InitProxyController(s.ng, s.supervisor, s.apiApp)
	return nil
}

func (s *Service) startApi(file *proxy.FileDescriptor) error {
	addr := fmt.Sprintf("%s:%d", s.options.ApiInterface, s.options.ApiPort)

	server := &http.Server{
		Addr:           addr,
		Handler:        s.apiApp.GetHandler(),
		ReadTimeout:    s.options.ServerReadTimeout,
		WriteTimeout:   s.options.ServerWriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}

	var listener net.Listener
	if file != nil {
		var err error
		listener, err = file.ToListener()
		if err != nil {
			return err
		}
	}

	s.apiServer = manners.NewWithOptions(manners.Options{Server: server, Listener: listener})
	return s.apiServer.ListenAndServe()
}

func execPath() (string, error) {
	name, err := exec.LookPath(os.Args[0])
	if err != nil {
		return "", err
	}
	if _, err = os.Stat(name); nil != err {
		return "", err
	}
	return name, err
}

type fileDescriptor struct {
	Address  engine.Address
	FileFD   int
	FileName string
}

// filesToString serializes file descriptors as well as accompanying information (like socket host and port)
func filesToString(files []*proxy.FileDescriptor) (string, error) {
	out := make([]fileDescriptor, len(files))
	for i, f := range files {
		out[i] = fileDescriptor{
			// Once files will be passed to the child process and their FDs will change.
			// The first three passed files are stdin, stdout and stderr, every next file will have the index + 3
			// That's why we rearrange the FDs for child processes to get the correct file descriptors.
			FileFD:   i + 3,
			FileName: f.File.Name(),
			Address:  f.Address,
		}
	}
	bytes, err := json.Marshal(out)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

// filesFromString de-serializes the file descriptors and turns them in the os.Files
func filesFromString(in string) ([]*proxy.FileDescriptor, error) {
	var out []fileDescriptor
	if err := json.Unmarshal([]byte(in), &out); err != nil {
		return nil, err
	}
	files := make([]*proxy.FileDescriptor, len(out))
	for i, o := range out {
		files[i] = &proxy.FileDescriptor{
			File:    os.NewFile(uintptr(o.FileFD), o.FileName),
			Address: o.Address,
		}
	}
	return files, nil
}

const vulcandFilesKey = "VULCAND_FILES_KEY"
<commit_msg>Check err<commit_after>package service

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
	"time"

	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/go-etcd/etcd"
	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/manners"
	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/metrics"
	"github.com/FoxComm/vulcand/Godeps/_workspace/src/github.com/mailgun/scroll"
	"github.com/FoxComm/vulcand/api"
	"github.com/FoxComm/vulcand/engine"
	"github.com/FoxComm/vulcand/engine/etcdng"
	"github.com/FoxComm/vulcand/engine/memng"
	"github.com/FoxComm/vulcand/engine/tomlng"
	"github.com/FoxComm/vulcand/log"
	"github.com/FoxComm/vulcand/plugin"
	"github.com/FoxComm/vulcand/proxy"
	"github.com/FoxComm/vulcand/secret"
	"github.com/FoxComm/vulcand/stapler"
	"github.com/FoxComm/vulcand/supervisor"
)

func Run(registry *plugin.Registry) error {
	options, err := ParseCommandLine()
	if err != nil {
		return fmt.Errorf("failed to parse command line: %s", err)
	}
	service := NewService(options, registry)
	if err := service.Start(); err != nil {
		log.Errorf("Failed to start service: %v", err)
		return fmt.Errorf("service start failure: %s", err)
	} else {
		log.Infof("Service exited gracefully")
	}
	return nil
}

type Service struct {
	client        *etcd.Client
	options       Options
	registry      *plugin.Registry
	apiApp        *scroll.App
	errorC        chan error
	sigC          chan os.Signal
	stopC         chan bool
	supervisor    *supervisor.Supervisor
	metricsClient metrics.Client
	apiServer     *manners.GracefulServer
	ng            engine.Engine
	stapler       stapler.Stapler
}

func NewService(options Options, registry *plugin.Registry) *Service {
	return &Service{
		registry: registry,
		options:  options,
		errorC:   make(chan error),
		// Channel receiving signals has to be non blocking, otherwise the service can miss a signal.
		sigC:  make(chan os.Signal, 1024),
		stopC: make(chan bool, 1),
	}
}

func (s *Service) Start() error {
	if err := log.EnsureLoggerExist(s.options.Log, s.options.LogSeverity.String()); err != nil {
		return err
	}

	log.Infof("Service starts with options: %#v", s.options)

	if s.options.PidPath != "" {
		ioutil.WriteFile(s.options.PidPath, []byte(fmt.Sprint(os.Getpid())), 0644)
	}

	if s.options.StatsdAddr != "" {
		var err error
		s.metricsClient, err = metrics.NewWithOptions(s.options.StatsdAddr, s.options.StatsdPrefix, metrics.Options{UseBuffering: true})
		if err != nil {
			return err
		}
	}

	apiFile, muxFiles, err := s.getFiles()
	if err != nil {
		return err
	}

	if err := s.newEngine(); err != nil {
		return err
	}

	s.stapler = stapler.New()
	s.supervisor = supervisor.New(
		s.newProxy, s.ng, s.errorC, supervisor.Options{Files: muxFiles})

	// Tells configurator to perform initial proxy configuration and start watching changes
	if err := s.supervisor.Start(); err != nil {
		return err
	}

	if err := s.initApi(); err != nil {
		return err
	}

	go func() {
		s.errorC <- s.startApi(apiFile)
	}()

	if s.metricsClient != nil {
		go s.reportSystemMetrics()
	}
	signal.Notify(s.sigC, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGUSR2, syscall.SIGCHLD)

	// Block until a signal is received or we got an error
	for {
		select {
		case <-s.stopC:
			log.Infof("Get stop message, shutting down gracefully")
			s.supervisor.Stop(true)
			log.Infof("All servers stopped")
			return nil
		case signal := <-s.sigC:
			switch signal {
			case syscall.SIGTERM, syscall.SIGINT:
				log.Infof("Got signal '%s', shutting down gracefully", signal)
				s.supervisor.Stop(true)
				log.Infof("All servers stopped")
				return nil
			case syscall.SIGKILL:
				log.Infof("Got signal '%s', exiting now without waiting", signal)
				s.supervisor.Stop(false)
				return nil
			case syscall.SIGUSR2:
				log.Infof("Got signal '%s', forking a new self", signal)
				if err := s.startChild(); err != nil {
					log.Infof("Failed to start self: %s", err)
				} else {
					log.Infof("Successfully started self")
				}
			case syscall.SIGCHLD:
				log.Warningf("Child exited, got '%s', collecting status", signal)
				var wait syscall.WaitStatus
				syscall.Wait4(-1, &wait, syscall.WNOHANG, nil)
				log.Warningf("Collected exit status from child")
			default:
				log.Infof("Ignoring '%s'", signal)
			}
		case err := <-s.errorC:
			log.Infof("Got request to shutdown with error: %s", err)
			return err
		}
	}
}

func (s *Service) Stop() {
	s.stopC <- true
}

func (s Service) GetEngine() engine.Engine {
	return s.ng
}

func (s *Service) getFiles() (*proxy.FileDescriptor, []*proxy.FileDescriptor, error) {
	// These files may be passed in by the parent process
	filesString := os.Getenv(vulcandFilesKey)
	if filesString == "" {
		return nil, nil, nil
	}

	files, err := filesFromString(filesString)
	if err != nil {
		return nil, nil, fmt.Errorf("child failed to start: failed to read files from string, error %s", err)
	}

	if len(files) != 0 {
		log.Infof("I am a child that has been passed files: %s", files)
	}

	return s.splitFiles(files)
}

func (s *Service) splitFiles(files []*proxy.FileDescriptor) (*proxy.FileDescriptor, []*proxy.FileDescriptor, error) {
	apiAddr := fmt.Sprintf("%s:%d", s.options.ApiInterface, s.options.ApiPort)
	for i, f := range files {
		if f.Address.Address == apiAddr {
			return files[i], append(files[:i], files[i+1:]...), nil
		}
	}
	return nil, nil, fmt.Errorf("API address %s not found in %s", apiAddr, files)
}

func (s *Service) startChild() error {
	log.Infof("Starting child")
	path, err := execPath()
	if err != nil {
		return err
	}

	wd, err := os.Getwd()
	if nil != err {
		return err
	}

	// Get socket files currently in use by the underlying http server controlled by supervisor
	extraFiles, err := s.supervisor.GetFiles()
	if err != nil {
		return err
	}

	apiFile, err := s.GetAPIFile()
	if err != nil {
		return err
	}

	extraFiles = append(extraFiles, apiFile)

	// These files will be passed to the child process
	files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
	for _, f := range extraFiles {
		files = append(files, f.File)
	}

	// Serialize files to JSON string representation
	vals, err := filesToString(extraFiles)
	if err != nil {
		return err
	}

	log.Infof("Passing %s to child", vals)
	os.Setenv(vulcandFilesKey, vals)

	p, err := os.StartProcess(path, os.Args, &os.ProcAttr{
		Dir:   wd,
		Env:   os.Environ(),
		Files: files,
		Sys:   &syscall.SysProcAttr{},
	})

	if err != nil {
		return err
	}

	log.Infof("Started new child pid=%d binary=%s", p.Pid, path)
	return nil
}

func (s *Service) GetAPIFile() (*proxy.FileDescriptor, error) {
	file, err := s.apiServer.GetFile()
	if err != nil {
		return nil, err
	}
	a := engine.Address{
		Network: "tcp",
		Address: fmt.Sprintf("%s:%d", s.options.ApiInterface, s.options.ApiPort),
	}
	return &proxy.FileDescriptor{File: file, Address: a}, nil
}

func (s *Service) newBox() (*secret.Box, error) {
	if s.options.SealKey == "" {
		return nil, nil
	}
	key, err := secret.KeyFromString(s.options.SealKey)
	if err != nil {
		return nil, err
	}
	return secret.NewBox(key)
}

func (s *Service) newEngine() error {
	box, err := s.newBox()
	if err != nil {
		return err
	}
	var ng engine.Engine

	switch s.options.EngineType {
	case "etcd":
		ng, err = etcdng.New(
			s.options.EtcdNodes,
			s.options.EtcdKey,
			s.registry,
			etcdng.Options{
				EtcdCaFile:      s.options.EtcdCaFile,
				EtcdCertFile:    s.options.EtcdCertFile,
				EtcdKeyFile:     s.options.EtcdKeyFile,
				EtcdConsistency: s.options.EtcdConsistency,
				Box:             box,
			})
	case "toml":
		ng, err = tomlng.New(s.registry,
			tomlng.Options{
				MainConfigFilepath: s.options.TomlPath,
				ConfigPaths:        s.options.TomlConfigPaths,
				WatchConfigChanges: s.options.TomlWatchConfigChanges,
			})
	case "mem":
		ng = memng.New(s.registry)
	}

	if err != nil {
		return fmt.Errorf("Engine creation error: %v", err)
	}
	s.ng = ng
	return nil
}

func (s *Service) reportSystemMetrics() {
	defer func() {
		if r := recover(); r != nil {
			log.Infof("Recovered in reportSystemMetrics", r)
		}
	}()
	for {
		s.metricsClient.ReportRuntimeMetrics("sys", 1.0)
		// we have 256 time buckets for gc stats, GC is being executed every 4ms on average
		// so we have 256 * 4 = 1024 around one second to report it. To play safe, let's report every 300ms
		time.Sleep(300 * time.Millisecond)
	}
}

func (s *Service) newProxy(id int) (proxy.Proxy, error) {
	return proxy.New(id, s.stapler, proxy.Options{
		MetricsClient:  s.metricsClient,
		DialTimeout:    s.options.EndpointDialTimeout,
		ReadTimeout:    s.options.ServerReadTimeout,
		WriteTimeout:   s.options.ServerWriteTimeout,
		MaxHeaderBytes: s.options.ServerMaxHeaderBytes,
		DefaultListener: &engine.Listener{
			Id:       "DefaultListener",
			Protocol: "http",
			Address: engine.Address{
				Network: "tcp",
				Address: fmt.Sprintf("%s:%d", s.options.Interface, s.options.Port),
			},
		},
		NotFoundMiddleware: s.registry.GetNotFoundMiddleware(),
	})
}

func (s *Service) initApi() error {
	s.apiApp = scroll.NewApp()
	api.InitProxyController(s.ng, s.supervisor, s.apiApp)
	return nil
}

func (s *Service) startApi(file *proxy.FileDescriptor) error {
	addr := fmt.Sprintf("%s:%d", s.options.ApiInterface, s.options.ApiPort)

	server := &http.Server{
		Addr:           addr,
		Handler:        s.apiApp.GetHandler(),
		ReadTimeout:    s.options.ServerReadTimeout,
		WriteTimeout:   s.options.ServerWriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}

	var listener net.Listener
	if file != nil {
		var err error
		listener, err = file.ToListener()
		if err != nil {
			return err
		}
	}

	s.apiServer = manners.NewWithOptions(manners.Options{Server: server, Listener: listener})
	return s.apiServer.ListenAndServe()
}

func execPath() (string, error) {
	name, err := exec.LookPath(os.Args[0])
	if err != nil {
		return "", err
	}
	if _, err = os.Stat(name); nil != err {
		return "", err
	}
	return name, err
}

type fileDescriptor struct {
	Address  engine.Address
	FileFD   int
	FileName string
}

// filesToString serializes file descriptors as well as accompanying information (like socket host and port)
func filesToString(files []*proxy.FileDescriptor) (string, error) {
	out := make([]fileDescriptor, len(files))
	for i, f := range files {
		out[i] = fileDescriptor{
			// Once files will be passed to the child process and their FDs will change.
			// The first three passed files are stdin, stdout and stderr, every next file will have the index + 3
			// That's why we rearrange the FDs for child processes to get the correct file descriptors.
			FileFD:   i + 3,
			FileName: f.File.Name(),
			Address:  f.Address,
		}
	}
	bytes, err := json.Marshal(out)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

// filesFromString de-serializes the file descriptors and turns them in the os.Files
func filesFromString(in string) ([]*proxy.FileDescriptor, error) {
	var out []fileDescriptor
	if err := json.Unmarshal([]byte(in), &out); err != nil {
		return nil, err
	}
	files := make([]*proxy.FileDescriptor, len(out))
	for i, o := range out {
		files[i] = &proxy.FileDescriptor{
			File:    os.NewFile(uintptr(o.FileFD), o.FileName),
			Address: o.Address,
		}
	}
	return files, nil
}

const vulcandFilesKey = "VULCAND_FILES_KEY"
<|endoftext|>


<commit_before>package service

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"

	"github.com/takama/daemon"
	"github.com/takama/whoisd/client"
	"github.com/takama/whoisd/config"
	"github.com/takama/whoisd/storage"
)

// Version of the Whois Daemon
// Date of current version release
const (
	Version = "0.2.3"
	Date    = "2015-10-07T17:00:17Z"
)

// Record - standard record (struct) for service package
type Record struct {
	Name   string
	Config *config.Record
	daemon.Daemon
}

// New - Create a new service record
func New(name, description string) (*Record, error) {
	daemonInstance, err := daemon.New(name, description)
	if err != nil {
		return nil, err
	}

	return &Record{name, config.New(), daemonInstance}, nil
}

// Run or manage the service
func (service *Record) Run() (string, error) {

	// if received any kind of command, do it
	if len(os.Args) > 1 {
		command := os.Args[1]
		switch command {
		case "install":
			return service.Install()
		case "remove":
			return service.Remove()
		case "start":
			return service.Start()
		case "stop":
			return service.Stop()
		case "status":
			return service.Status()
		}
	}

	// Load configuration and get mapping
	bundle, err := service.Config.Load()
	if err != nil {
		return "Loading mapping file was unsuccessful", err
	}

	// Logs for what is host&port used
	serviceHostPort := fmt.Sprintf("%s:%d", service.Config.Host, service.Config.Port)
	log.Printf("%s started on %s\n", service.Name, serviceHostPort)
	log.Printf("Used storage %s on %s:%d\n",
		service.Config.Storage.StorageType,
		service.Config.Storage.Host,
		service.Config.Storage.Port,
	)

	// Set up listener for defined host and port
	listener, err := net.Listen("tcp", serviceHostPort)
	if err != nil {
		return "Possibly was a problem with the port binding", err
	}

	// set up channel to collect client queries
	channel := make(chan client.Record, service.Config.Connections)

	// set up current storage
	repository := storage.New(service.Config, bundle)

	// init workers
	for i := 0; i < service.Config.Workers; i++ {
		go client.ProcessClient(channel, repository)
	}

	// This block is for testing purpose only
	if service.Config.TestMode == true {
		// make pipe connections for testing
		// connIn will ready to write into by function ProcessClient
		connIn, connOut := net.Pipe()
		defer connIn.Close()
		defer connOut.Close()
		newClient := client.Record{Conn: connIn}

		// prepare query for ProcessClient
		newClient.Query = []byte(service.Config.TestQuery)

		// send it into channel
		channel <- newClient
		// just read answer from channel pipe
		buffer := make([]byte, 4096)
		numBytes, err := connOut.Read(buffer)
		log.Println("Read bytes:", numBytes)
		return string(buffer), err
	}

	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	// set up channel on which to send accepted connections
	listen := make(chan net.Conn, service.Config.Connections)
	go acceptConnection(listener, listen)

	// loop work cycle with accept connections or interrupt
	// by system signal
	for {
		select {
		case conn := <-listen:
			newClient := client.Record{Conn: conn}
			go newClient.HandleClient(channel)
		case killSignal := <-interrupt:
			log.Println("Got signal:", killSignal)
			log.Println("Stoping listening on ", listener.Addr())
			listener.Close()
			if killSignal == os.Interrupt {
				return "Daemon was interruped by system signal", nil
			}
			return "Daemon was killed", nil
		}
	}

	// never happen, but need to complete code
	return "If you see that, you are lucky bastard", nil
}

// Accept a client connection and collect it in a channel
func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
	defer func() {
		if recovery := recover(); recovery != nil {
			log.Println("Recovered in ListenConnection:", recovery)
		}
	}()
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		listen <- conn
	}
}
<commit_msg>Bumped version number to 0.2.4<commit_after>package service

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"

	"github.com/takama/daemon"
	"github.com/takama/whoisd/client"
	"github.com/takama/whoisd/config"
	"github.com/takama/whoisd/storage"
)

// Version of the Whois Daemon
// Date of current version release
const (
	Version = "0.2.4"
	Date    = "2015-10-07T23:50:17Z"
)

// Record - standard record (struct) for service package
type Record struct {
	Name   string
	Config *config.Record
	daemon.Daemon
}

// New - Create a new service record
func New(name, description string) (*Record, error) {
	daemonInstance, err := daemon.New(name, description)
	if err != nil {
		return nil, err
	}

	return &Record{name, config.New(), daemonInstance}, nil
}

// Run or manage the service
func (service *Record) Run() (string, error) {

	// if received any kind of command, do it
	if len(os.Args) > 1 {
		command := os.Args[1]
		switch command {
		case "install":
			return service.Install()
		case "remove":
			return service.Remove()
		case "start":
			return service.Start()
		case "stop":
			return service.Stop()
		case "status":
			return service.Status()
		}
	}

	// Load configuration and get mapping
	bundle, err := service.Config.Load()
	if err != nil {
		return "Loading mapping file was unsuccessful", err
	}

	// Logs for what is host&port used
	serviceHostPort := fmt.Sprintf("%s:%d", service.Config.Host, service.Config.Port)
	log.Printf("%s started on %s\n", service.Name, serviceHostPort)
	log.Printf("Used storage %s on %s:%d\n",
		service.Config.Storage.StorageType,
		service.Config.Storage.Host,
		service.Config.Storage.Port,
	)

	// Set up listener for defined host and port
	listener, err := net.Listen("tcp", serviceHostPort)
	if err != nil {
		return "Possibly was a problem with the port binding", err
	}

	// set up channel to collect client queries
	channel := make(chan client.Record, service.Config.Connections)

	// set up current storage
	repository := storage.New(service.Config, bundle)

	// init workers
	for i := 0; i < service.Config.Workers; i++ {
		go client.ProcessClient(channel, repository)
	}

	// This block is for testing purpose only
	if service.Config.TestMode == true {
		// make pipe connections for testing
		// connIn will ready to write into by function ProcessClient
		connIn, connOut := net.Pipe()
		defer connIn.Close()
		defer connOut.Close()
		newClient := client.Record{Conn: connIn}

		// prepare query for ProcessClient
		newClient.Query = []byte(service.Config.TestQuery)

		// send it into channel
		channel <- newClient
		// just read answer from channel pipe
		buffer := make([]byte, 4096)
		numBytes, err := connOut.Read(buffer)
		log.Println("Read bytes:", numBytes)
		return string(buffer), err
	}

	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	// set up channel on which to send accepted connections
	listen := make(chan net.Conn, service.Config.Connections)
	go acceptConnection(listener, listen)

	// loop work cycle with accept connections or interrupt
	// by system signal
	for {
		select {
		case conn := <-listen:
			newClient := client.Record{Conn: conn}
			go newClient.HandleClient(channel)
		case killSignal := <-interrupt:
			log.Println("Got signal:", killSignal)
			log.Println("Stoping listening on ", listener.Addr())
			listener.Close()
			if killSignal == os.Interrupt {
				return "Daemon was interruped by system signal", nil
			}
			return "Daemon was killed", nil
		}
	}

	// never happen, but need to complete code
	return "If you see that, you are lucky bastard", nil
}

// Accept a client connection and collect it in a channel
func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
	defer func() {
		if recovery := recover(); recovery != nil {
			log.Println("Recovered in ListenConnection:", recovery)
		}
	}()
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		listen <- conn
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"

	"github.com/bgentry/heroku-go"
)

var cmdCreate = &Command{
	Run:      runCreate,
	Usage:    "create [-r <region>] [-o <org>] [<name>]",
	Category: "app",
	Short:    "create an app",
	Long: `
Create creates a new Heroku app. If <name> is not specified, the
app is created with a random haiku name.

Options:

    -r <region>  Heroku region to create app in
    -o <org>     Name of Heroku organization to create app in
    <name>       optional name for the app

Examples:

    $ hk create
    Created dodging-samurai-42.

    $ hk create -r eu myapp
    Created myapp.
`,
}

var flagRegion string
var flagOrgName string

func init() {
	cmdCreate.Flag.StringVarP(&flagRegion, "region", "r", "", "region name")
	cmdCreate.Flag.StringVarP(&flagOrgName, "org", "o", "", "organization name")
}

func runCreate(cmd *Command, args []string) {
	appname := ""
	if len(args) > 0 {
		appname = args[0]
	}

	orgName := ""
	// "personal" means "no org", skip the org lookup stuff
	if flagOrgName != "personal" {
		orgs, err := client.OrganizationList(nil)
		must(err)
		for _, org := range orgs {
			if flagOrgName != "" {
				// match org in orgs list
				if org.Name == flagOrgName {
					orgName = org.Name
				}
			} else {
				// check for default org
				if org.Default {
					orgName = org.Name
					break
				}
			}
		}
		if flagOrgName != "" && flagOrgName != orgName {
			// flagOrgName was provided but not found in orgs list
			printFatal("Heroku organization %s not found", flagOrgName)
		}
	}

	if orgName == "" {
		var opts heroku.AppCreateOpts
		if flagRegion != "" {
			opts.Region = &flagRegion
		}
		if appname != "" {
			opts.Name = &appname
		}

		app, err := client.AppCreate(&opts)
		must(err)
		exec.Command("git", "remote", "add", "heroku", app.GitURL).Run()
		log.Printf("Created %s.", app.Name)
	} else {
		var opts heroku.OrganizationAppCreateOpts
		if flagRegion != "" {
			opts.Region = &flagRegion
		}
		if appname != "" {
			opts.Name = &appname
		}

		app, err := client.OrganizationAppCreate(orgName, &opts)
		must(err)
		exec.Command("git", "remote", "add", "heroku", app.GitURL).Run()
		log.Printf("Created %s.", app.Name)
	}
}
<commit_msg>tell the user which org we created an app in<commit_after>package main

import (
	"log"
	"os/exec"

	"github.com/bgentry/heroku-go"
)

var cmdCreate = &Command{
	Run:      runCreate,
	Usage:    "create [-r <region>] [-o <org>] [<name>]",
	Category: "app",
	Short:    "create an app",
	Long: `
Create creates a new Heroku app. If <name> is not specified, the
app is created with a random haiku name.

Options:

    -r <region>  Heroku region to create app in
    -o <org>     Name of Heroku organization to create app in
    <name>       optional name for the app

Examples:

    $ hk create
    Created dodging-samurai-42.

    $ hk create -r eu myapp
    Created myapp.
`,
}

var flagRegion string
var flagOrgName string

func init() {
	cmdCreate.Flag.StringVarP(&flagRegion, "region", "r", "", "region name")
	cmdCreate.Flag.StringVarP(&flagOrgName, "org", "o", "", "organization name")
}

func runCreate(cmd *Command, args []string) {
	appname := ""
	if len(args) > 0 {
		appname = args[0]
	}

	orgName := ""
	// "personal" means "no org", skip the org lookup stuff
	if flagOrgName != "personal" {
		orgs, err := client.OrganizationList(nil)
		must(err)
		for _, org := range orgs {
			if flagOrgName != "" {
				// match org in orgs list
				if org.Name == flagOrgName {
					orgName = org.Name
				}
			} else {
				// check for default org
				if org.Default {
					orgName = org.Name
					break
				}
			}
		}
		if flagOrgName != "" && flagOrgName != orgName {
			// flagOrgName was provided but not found in orgs list
			printFatal("Heroku organization %s not found", flagOrgName)
		}
	}

	if orgName == "" {
		var opts heroku.AppCreateOpts
		if flagRegion != "" {
			opts.Region = &flagRegion
		}
		if appname != "" {
			opts.Name = &appname
		}

		app, err := client.AppCreate(&opts)
		must(err)
		exec.Command("git", "remote", "add", "heroku", app.GitURL).Run()
		log.Printf("Created %s.", app.Name)
	} else {
		var opts heroku.OrganizationAppCreateOpts
		if flagRegion != "" {
			opts.Region = &flagRegion
		}
		if appname != "" {
			opts.Name = &appname
		}

		app, err := client.OrganizationAppCreate(orgName, &opts)
		must(err)
		exec.Command("git", "remote", "add", "heroku", app.GitURL).Run()
		log.Printf("Created %s in the %s org.", app.Name, orgName)
	}
}
<|endoftext|>


<commit_before>package xesende

import "errors"

// Sent returns a list of messages sent by the account.
func (c *AccountClient) Sent(opts ...Option) (*MessagesResponse, error) {
	req, err := c.newRequest("GET", "/v1.0/messageheaders?accountReference="+c.reference, nil)
	if err != nil {
		return nil, err
	}

	for _, opt := range opts {
		opt(req)
	}

	var v messageHeadersResponse
	resp, err := c.do(req, &v)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, errors.New("Expected 200")
	}

	response := &MessagesResponse{
		Paging: Paging{
			StartIndex: v.StartIndex,
			Count:      v.Count,
			TotalCount: v.TotalCount,
		},
		Messages: make([]MessageResponse, len(v.Messages)),
	}

	for i, message := range v.Messages {
		response.Messages[i] = MessageResponse{
			ID:           message.ID,
			URI:          message.URI,
			Reference:    message.Reference,
			Status:       message.Status,
			LastStatusAt: message.LastStatusAt.Time,
			SubmittedAt:  message.SubmittedAt.Time,
			Type:         message.Type,
			To:           message.To,
			From:         message.From,
			Summary:      message.Summary,
			BodyURI:      message.Body.URI,
			Direction:    message.Direction,
			Parts:        message.Parts,
			Username:     message.Username,
		}
	}

	return response, nil
}

// Received returns the messages sent to the account.
func (c *AccountClient) Received(opts ...Option) (*MessagesReceivedResponse, error) {
	req, err := c.newRequest("GET", "/v1.0/inbox/"+c.reference+"/messages", nil)
	if err != nil {
		return nil, err
	}

	for _, opt := range opts {
		opt(req)
	}

	var v inboxResponse
	resp, err := c.do(req, &v)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, errors.New("Expected 200")
	}

	response := &MessagesReceivedResponse{
		Paging: Paging{
			StartIndex: v.StartIndex,
			Count:      v.Count,
			TotalCount: v.TotalCount,
		},
		Messages: make([]MessageReceivedResponse, len(v.Messages)),
	}

	for i, message := range v.Messages {
		response.Messages[i] = MessageReceivedResponse{
			ID:         message.ID,
			URI:        message.URI,
			Reference:  message.Reference,
			Status:     message.Status,
			ReceivedAt: message.ReceivedAt.Time,
			Type:       message.Type,
			To:         message.To,
			From:       message.From,
			Summary:    message.Summary,
			BodyURI:    message.Body.URI,
			Direction:  message.Direction,
			Parts:      message.Parts,
			ReadAt:     message.ReadAt.Time,
			ReadBy:     message.ReadBy,
		}
	}

	return response, nil
}
<commit_msg>Refactor account based Sent messages to use general version<commit_after>package xesende

import (
	"errors"
	"net/http"
)

// Sent returns a list of messages sent by the account.
func (c *AccountClient) Sent(opts ...Option) (*MessagesResponse, error) {
	accountOption := func(r *http.Request) {
		q := r.URL.Query()

		q.Add("accountReference", c.reference)

		r.URL.RawQuery = q.Encode()
	}

	return c.Client.Sent(append(opts, accountOption)...)
}

// Received returns the messages sent to the account.
func (c *AccountClient) Received(opts ...Option) (*MessagesReceivedResponse, error) {
	req, err := c.newRequest("GET", "/v1.0/inbox/"+c.reference+"/messages", nil)
	if err != nil {
		return nil, err
	}

	for _, opt := range opts {
		opt(req)
	}

	var v inboxResponse
	resp, err := c.do(req, &v)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, errors.New("Expected 200")
	}

	response := &MessagesReceivedResponse{
		Paging: Paging{
			StartIndex: v.StartIndex,
			Count:      v.Count,
			TotalCount: v.TotalCount,
		},
		Messages: make([]MessageReceivedResponse, len(v.Messages)),
	}

	for i, message := range v.Messages {
		response.Messages[i] = MessageReceivedResponse{
			ID:         message.ID,
			URI:        message.URI,
			Reference:  message.Reference,
			Status:     message.Status,
			ReceivedAt: message.ReceivedAt.Time,
			Type:       message.Type,
			To:         message.To,
			From:       message.From,
			Summary:    message.Summary,
			BodyURI:    message.Body.URI,
			Direction:  message.Direction,
			Parts:      message.Parts,
			ReadAt:     message.ReadAt.Time,
			ReadBy:     message.ReadBy,
		}
	}

	return response, nil
}
<|endoftext|>


<commit_before>package acccumulator

import (
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestAccumulator(t *testing.T) {
	Convey("Given the acccumulator", t, func() {
		acc := NewAccumulator()
		Convey("When a positive element is added", func() {
			acc.Add("test", 1.22)
			Convey("It should go to the positive acccumulator", func() {
				So((*acc)["test"][Positive], ShouldEqual, 1.22)
			})
			Convey("When a positive value is added to the same key", func() {
				acc.Add("test", 2.33)
				Convey("It is accumulated in the positive register", func() {
					So((*acc)["test"][Positive], ShouldEqual, 3.55)
				})
			})
			Convey("When a negative value is added to the same key", func() {
				acc.Add("test", -2.33)
				Convey("It is accumulated in the positive register", func() {
					So((*acc)["test"][Negative], ShouldEqual, -2.33)
					So((*acc)["test"][Positive], ShouldEqual, 1.22)
				})
			})
			Convey("When negative element is added", func() {
				acc.Add("test2", -1.32)
				Convey("It should go to the negative acccumulator", func() {
					So((*acc)["test2"][Negative], ShouldEqual, -1.32)
				})
			})
		})
	})
}
<commit_msg>Fixed typo<commit_after>package accumulator

import (
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestAccumulator(t *testing.T) {
	Convey("Given the acccumulator", t, func() {
		acc := NewAccumulator()
		Convey("When a positive element is added", func() {
			acc.Add("test", 1.22)
			Convey("It should go to the positive acccumulator", func() {
				So((*acc)["test"][Positive], ShouldEqual, 1.22)
			})
			Convey("When a positive value is added to the same key", func() {
				acc.Add("test", 2.33)
				Convey("It is accumulated in the positive register", func() {
					So((*acc)["test"][Positive], ShouldEqual, 3.55)
				})
			})
			Convey("When a negative value is added to the same key", func() {
				acc.Add("test", -2.33)
				Convey("It is accumulated in the positive register", func() {
					So((*acc)["test"][Negative], ShouldEqual, -2.33)
					So((*acc)["test"][Positive], ShouldEqual, 1.22)
				})
			})
			Convey("When negative element is added", func() {
				acc.Add("test2", -1.32)
				Convey("It should go to the negative acccumulator", func() {
					So((*acc)["test2"][Negative], ShouldEqual, -1.32)
				})
			})
		})
	})
}
<|endoftext|>


<commit_before>package session

import (
	"github.com/astaxie/beego/session"
)

var (
	Manager *session.Manager
)

func Init() {
	Manager, _ = session.NewManager("memory", `{"cookieName":"gosessionid","gclifetime":3600}`)
	go Manager.GC()
}
<commit_msg>session manager signature changed<commit_after>package session

import (
	"github.com/astaxie/beego/session"
)

var (
	Manager *session.Manager
)

func Init() {
	Manager, _ = session.NewManager("memory",
		&session.ManagerConfig{CookieName: "gosessionid", Gclifetime: 3600})

	go Manager.GC()
}
<|endoftext|>


<commit_before>// multicastservice.go
package main

import (
	"fmt"
	"log"
	"net"
)

type tagfields struct {
	hkid        HKID
	namesegment string
}

type multicastservice struct {
	conn             *net.UDPConn
	mcaddr           *net.UDPAddr
	responsechannel  chan response
	waitingforblob   map[string]chan blob
	waitingfortag    map[string]chan tag
	waitingforcommit map[string]chan commit
	waitingforkey    map[string]chan blob
}

func (m multicastservice) GetBlob(h HCID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"blob\", \"hcid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	blobchannel := make(chan blob)
	m.waitingforblob[h.Hex()] = blobchannel
	b = <-blobchannel
	return b, err

}

func (m multicastservice) GetCommit(h HKID) (c commit, err error) {
	message := fmt.Sprintf("{\"type\":\"commit\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	commitchannel := make(chan commit)
	m.waitingforcommit[h.Hex()] = commitchannel
	c = <-commitchannel
	return c, err
}

func (m multicastservice) GetTag(h HKID, namesegment string) (t tag, err error) {
	message := fmt.Sprintf("{\"type\":\"tag\", \"hkid\": \"%s\", \"namesegment\": \"%s\"}", h.Hex(), namesegment)
	m.sendmessage(message)
	tagchannel := make(chan tag)
	m.waitingfortag[h.Hex()] = tagchannel
	t = <-tagchannel
	return t, err

}

func (m multicastservice) GetKey(h HKID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"key\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	keychannel := make(chan blob)
	m.waitingforkey[h.Hex()] = keychannel
	b = <-keychannel
	return b, err
}

func (m multicastservice) listenmessage() (err error) {
	//It is taking only 256 bytes of data.
	go func() {
		for {
			b := make([]byte, 256)
			_, _, err := m.conn.ReadFromUDP(b)
			if err != nil {
				log.Printf("multicasterror, %s, \n", err)
				return
			}
			m.receivemessage(string(b))
		}
	}()
	return
}

func (m multicastservice) sendmessage(message string) (err error) {
	b := make([]byte, 256)
	copy(b, message)
	_, err = m.conn.WriteToUDP(b, m.mcaddr)
	if err != nil {
		log.Printf("multicasterror, %s, \n", err)
		return
	}

	return err
}

func (m multicastservice) receivemessage(message string) (err error) {
	log.Printf("Received message, %s,\n", message)
	hkid, hcid, typestring, namesegment := parseMessage(message)

	log.Printf("HCID message, %s,\n", hcid.String())
	log.Printf("HKID message, %s,\n", hkid.String())
	log.Printf("typestring message, %s,\n", typestring)
	log.Printf("namesegment message, %s,\n", namesegment)
	//parse message
	//if in waiting map send on channel

	return err
}

func multicastservicefactory() (m multicastservice) {
	mcaddr, err := net.ResolveUDPAddr("udp", "224.0.1.20:5354")
	if err != nil {
		return multicastservice{}
	}

	conn, err := net.ListenMulticastUDP("udp", nil, mcaddr)
	if err != nil {
		return multicastservice{}
	}

	return multicastservice{conn: conn, mcaddr: mcaddr}
}

func init() {
	multicastserviceInstance := multicastservicefactory()
	multicastserviceInstance.listenmessage()

}

type response struct {
	typestring  string
	hkid        HKID
	hcid        HCID
	namesegment string
	url         string
}

type responseblob struct {
	hcid HCID
	url  string
}

type responsecommit struct {
	hkid HKID
	url  string
}

type responsetag struct {
	hkid        HKID
	namesegment string
	url         string
}

type responsekey struct {
	hkid HKID
	url  string
}
<commit_msg>Added geturl function<commit_after>// multicastservice.go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
)

type tagfields struct {
	hkid        HKID
	namesegment string
}

type multicastservice struct {
	conn             *net.UDPConn
	mcaddr           *net.UDPAddr
	responsechannel  chan response
	waitingforblob   map[string]chan blob
	waitingfortag    map[string]chan tag
	waitingforcommit map[string]chan commit
	waitingforkey    map[string]chan blob
}

func (m multicastservice) GetBlob(h HCID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"blob\", \"hcid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	blobchannel := make(chan blob)
	m.waitingforblob[h.Hex()] = blobchannel
	b = <-blobchannel
	return b, err

}

func (m multicastservice) GetCommit(h HKID) (c commit, err error) {
	message := fmt.Sprintf("{\"type\":\"commit\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	commitchannel := make(chan commit)
	m.waitingforcommit[h.Hex()] = commitchannel
	c = <-commitchannel
	return c, err
}

func (m multicastservice) GetTag(h HKID, namesegment string) (t tag, err error) {
	message := fmt.Sprintf("{\"type\":\"tag\", \"hkid\": \"%s\", \"namesegment\": \"%s\"}", h.Hex(), namesegment)
	m.sendmessage(message)
	tagchannel := make(chan tag)
	m.waitingfortag[h.Hex()+namesegment] = tagchannel
	t = <-tagchannel
	return t, err

}

func (m multicastservice) GetKey(h HKID) (b blob, err error) {
	message := fmt.Sprintf("{\"type\":\"key\",\"hkid\": \"%s\"}", h.Hex())
	m.sendmessage(message)
	keychannel := make(chan blob)
	m.waitingforkey[h.Hex()] = keychannel
	b = <-keychannel
	return b, err
}

func (m multicastservice) listenmessage() (err error) {
	//It is taking only 256 bytes of data.
	go func() {
		for {
			b := make([]byte, 256)
			_, _, err := m.conn.ReadFromUDP(b)
			if err != nil {
				log.Printf("multicasterror, %s, \n", err)
				return
			}
			m.receivemessage(string(b))
		}
	}()
	return
}

func (m multicastservice) sendmessage(message string) (err error) {
	b := make([]byte, 256)
	copy(b, message)
	_, err = m.conn.WriteToUDP(b, m.mcaddr)
	if err != nil {
		log.Printf("multicasterror, %s, \n", err)
		return
	}

	return err
}

func (m multicastservice) receivemessage(message string) (err error) {
	log.Printf("Received message, %s,\n", message)
	hkid, hcid, typestring, namesegment := parseMessage(message)
	url := "www.google.com"
	if typestring == "blob" {
		blobchannel, present := m.waitingforblob[hcid.String()]
		if present {

			data, err := m.geturl(url)
			if err == nil {
				blobchannel <- data
			}
		}
	}
	if typestring == "tag" {
		tagchannel, present := m.waitingfortag[hkid.String()+namesegment]
		if present {
			data, err := m.geturl(url)
			t, err := TagFromBytes(data)
			if err == nil {
				tagchannel <- t
			}
		}
	}
	if typestring == "commit" {
		commitchannel, present := m.waitingforcommit[hkid.String()]
		if present {
			data, err := m.geturl(url)
			c, err := CommitFromBytes(data)
			if err == nil {
				commitchannel <- c
			}
		}
	}
	if typestring == "key" {
		keychannel, present := m.waitingforkey[hcid.String()]
		if present {
			data, err := m.geturl(url)
			if err == nil {
				keychannel <- data
			}
		}
	}
	log.Printf("HCID message, %s,\n", hcid.String())
	log.Printf("HKID message, %s,\n", hkid.String())
	log.Printf("typestring message, %s,\n", typestring)
	log.Printf("namesegment message, %s,\n", namesegment)
	//parse message
	//if in waiting map send on channel

	return err
}

func (m multicastservice) geturl(url string) (data []byte, err error) {
	resp, err := http.Get(url) //Takes the http channel and makes it a channel object
	if err != nil {
		return data, err
	}
	defer resp.Body.Close() //Do this after return is called
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return data, err
	} else {
		return data, nil
	}

}

func multicastservicefactory() (m multicastservice) {
	mcaddr, err := net.ResolveUDPAddr("udp", "224.0.1.20:5354")
	if err != nil {
		return multicastservice{}
	}

	conn, err := net.ListenMulticastUDP("udp", nil, mcaddr)
	if err != nil {
		return multicastservice{}
	}

	return multicastservice{conn: conn, mcaddr: mcaddr}
}

func init() {
	multicastserviceInstance := multicastservicefactory()
	multicastserviceInstance.listenmessage()

}

type response struct {
	typestring  string
	hkid        HKID
	hcid        HCID
	namesegment string
	url         string
}

type responseblob struct {
	hcid HCID
	url  string
}

type responsecommit struct {
	hkid HKID
	url  string
}

type responsetag struct {
	hkid        HKID
	namesegment string
	url         string
}

type responsekey struct {
	hkid HKID
	url  string
}
<|endoftext|>


<commit_before>package hawk

import (
	"crypto/hmac"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"hash"
	"net"
	"net/url"
	"strconv"
	"strings"
)

const headerVersion = 1

type AuthType int

const (
	Header AuthType = iota
	Response
	Bewit
)

type Mac struct {
	Type       AuthType
	Credential *Credential
	Uri        string
	Method     string
	HostPort   string
	Option     *Option
}

type TsMac struct {
	TimeStamp  int64
	Credential *Credential
}

type PayloadHash struct {
	ContentType string
	Payload     string
	Alg         Alg
}

// String returns a base64 encoded message authentication code.
func (m *Mac) String() (string, error) {
	digest, err := m.digest()
	return base64.StdEncoding.EncodeToString(digest), err
}

func (m *Mac) digest() ([]byte, error) {
	s := getHash(m.Credential.Alg)

	mac := hmac.New(s, []byte(m.Credential.Key))
	ns, err := m.normalized()
	if err != nil {
		return nil, err
	}
	mac.Write([]byte(ns))

	return mac.Sum(nil), nil
}

func (m *Mac) normalized() (string, error) {
	return normalized(m.Type, m.Uri, m.Method, m.HostPort, m.Option)
}

// String returns a base64 encoded message authentication code for timestamp
func (tm *TsMac) String() string {
	digest := tm.digest()
	return base64.StdEncoding.EncodeToString(digest)
}

func (tm *TsMac) digest() []byte {
	s := getHash(tm.Credential.Alg)

	mac := hmac.New(s, []byte(tm.Credential.Key))
	ns := "hawk." + strconv.Itoa(headerVersion) + ".ts" + "\n" + strconv.FormatInt(tm.TimeStamp, 10) + "\n"
	mac.Write([]byte(ns))

	return mac.Sum(nil)
}

// String returns a base64 encoded hash value of payload
func (h *PayloadHash) String() string {
	hash := h.hash()
	return base64.StdEncoding.EncodeToString(hash)
}

func (h *PayloadHash) hash() []byte {
	s := getHash(h.Alg)()

	ns := "hawk." + strconv.Itoa(headerVersion) + ".payload" + "\n" + strings.ToLower(h.ContentType) + "\n" + h.Payload + "\n"
	s.Write([]byte(ns))

	return s.Sum(nil)
}

func normalized(authType AuthType, uri, method, customHost string, option *Option) (string, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}

	var h string
	if customHost != "" {
		h = customHost
	} else {
		h = u.Host
	}

	host, port, _ := net.SplitHostPort(h)
	if port == "" {
		switch u.Scheme {
		case "http":
			port = "80"
		case "https":
			port = "443"
		}
	}
	if host == "" {
		if customHost != "" {
			host = customHost
		} else {
			host = u.Host
		}
	}

	path := u.Path
	if u.Query().Encode() != "" {
		path = path + "?" + u.RawQuery
	}

	header := "hawk" + "." + strconv.Itoa(headerVersion) + "." + strings.ToLower(authType.String())

	ext := ""
	if option.Ext != "" {
		ext = strings.Replace(option.Ext, "\\", "\\\\", -1)
		ext = strings.Replace(ext, "\n", "\\n", -1)
	}

	ns := header + "\n" +
		strconv.FormatInt(option.TimeStamp, 10) + "\n" +
		option.Nonce + "\n" +
		strings.ToUpper(method) + "\n" +
		path + "\n" +
		strings.ToLower(host) + "\n" +
		port + "\n" +
		option.Hash + "\n" +
		ext + "\n"

	if option.App != "" {
		ns = ns + option.App + "\n"
		ns = ns + option.Dlg + "\n"
	}

	return ns, nil
}

func getHash(alg Alg) func() hash.Hash {
	switch alg {
	case SHA256:
		return sha256.New
	case SHA512:
		return sha512.New
	default:
		return sha256.New
	}
}
<commit_msg>ContentType used in hash shouldn't include parameters according to Hawk protocol<commit_after>package hawk

import (
	"crypto/hmac"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"hash"
	"net"
	"net/url"
	"strconv"
	"strings"
)

const headerVersion = 1

type AuthType int

const (
	Header AuthType = iota
	Response
	Bewit
)

type Mac struct {
	Type       AuthType
	Credential *Credential
	Uri        string
	Method     string
	HostPort   string
	Option     *Option
}

type TsMac struct {
	TimeStamp  int64
	Credential *Credential
}

type PayloadHash struct {
	ContentType string
	Payload     string
	Alg         Alg
}

// String returns a base64 encoded message authentication code.
func (m *Mac) String() (string, error) {
	digest, err := m.digest()
	return base64.StdEncoding.EncodeToString(digest), err
}

func (m *Mac) digest() ([]byte, error) {
	s := getHash(m.Credential.Alg)

	mac := hmac.New(s, []byte(m.Credential.Key))
	ns, err := m.normalized()
	if err != nil {
		return nil, err
	}
	mac.Write([]byte(ns))

	return mac.Sum(nil), nil
}

func (m *Mac) normalized() (string, error) {
	return normalized(m.Type, m.Uri, m.Method, m.HostPort, m.Option)
}

// String returns a base64 encoded message authentication code for timestamp
func (tm *TsMac) String() string {
	digest := tm.digest()
	return base64.StdEncoding.EncodeToString(digest)
}

func (tm *TsMac) digest() []byte {
	s := getHash(tm.Credential.Alg)

	mac := hmac.New(s, []byte(tm.Credential.Key))
	ns := "hawk." + strconv.Itoa(headerVersion) + ".ts" + "\n" + strconv.FormatInt(tm.TimeStamp, 10) + "\n"
	mac.Write([]byte(ns))

	return mac.Sum(nil)
}

// String returns a base64 encoded hash value of payload
func (h *PayloadHash) String() string {
	hash := h.hash()
	return base64.StdEncoding.EncodeToString(hash)
}

func sanitizeContentType(contentType string) string {
	return strings.TrimSpace(strings.ToLower(strings.Split(contentType, ";")[0]))
}

func (h *PayloadHash) hash() []byte {
	s := getHash(h.Alg)()

	ns := "hawk." + strconv.Itoa(headerVersion) + ".payload" + "\n" + sanitizeContentType(h.ContentType) + "\n" + h.Payload + "\n"
	s.Write([]byte(ns))

	return s.Sum(nil)
}

func normalized(authType AuthType, uri, method, customHost string, option *Option) (string, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}

	var h string
	if customHost != "" {
		h = customHost
	} else {
		h = u.Host
	}

	host, port, _ := net.SplitHostPort(h)
	if port == "" {
		switch u.Scheme {
		case "http":
			port = "80"
		case "https":
			port = "443"
		}
	}
	if host == "" {
		if customHost != "" {
			host = customHost
		} else {
			host = u.Host
		}
	}

	path := u.Path
	if u.Query().Encode() != "" {
		path = path + "?" + u.RawQuery
	}

	header := "hawk" + "." + strconv.Itoa(headerVersion) + "." + strings.ToLower(authType.String())

	ext := ""
	if option.Ext != "" {
		ext = strings.Replace(option.Ext, "\\", "\\\\", -1)
		ext = strings.Replace(ext, "\n", "\\n", -1)
	}

	ns := header + "\n" +
		strconv.FormatInt(option.TimeStamp, 10) + "\n" +
		option.Nonce + "\n" +
		strings.ToUpper(method) + "\n" +
		path + "\n" +
		strings.ToLower(host) + "\n" +
		port + "\n" +
		option.Hash + "\n" +
		ext + "\n"

	if option.App != "" {
		ns = ns + option.App + "\n"
		ns = ns + option.Dlg + "\n"
	}

	return ns, nil
}

func getHash(alg Alg) func() hash.Hash {
	switch alg {
	case SHA256:
		return sha256.New
	case SHA512:
		return sha512.New
	default:
		return sha256.New
	}
}
<|endoftext|>


<commit_before>package curses

// struct ldat{};
// struct _win_st{};
// #define _Bool int
// #define NCURSES_OPAQUE 1
// #include <curses.h>
import "C"

import (
	"fmt";
	"os";
	"unsafe";
)

type void unsafe.Pointer;

type Window C.WINDOW;

type CursesError struct {
	message string;
}

func (ce CursesError) String() string {
	return ce.message;
}

// Cursor options.
const (
	CURS_HIDE = iota;
	CURS_NORM;
	CURS_HIGH;
)

// Pointers to the values in curses, which may change values.
var Cols *int = nil;
var Rows *int = nil;

var Colors *int = nil;
var ColorPairs *int = nil;

var Tabsize *int = nil;

// The window returned from C.initscr()
var Stdwin *Window = nil;

// Initializes gocurses
func init() {
	Cols = (*int)(void(&C.COLS));
	Rows = (*int)(void(&C.LINES));

	Colors = (*int)(void(&C.COLORS));
	ColorPairs = (*int)(void(&C.COLOR_PAIRS));

	Tabsize = (*int)(void(&C.TABSIZE));
}

func Initscr() (*Window, os.Error) {
	Stdwin = (*Window)(C.initscr());

	if Stdwin == nil {
		return nil, CursesError{"Initscr failed"};
	}

	return Stdwin, nil;
}

func Newwin(rows int16, cols int16, starty int16, startx int16) *Window {
	nw := (*Window)(C.newwin(C.int(rows), C.int(cols), C.int(starty), C.int(startx)));

	return nw;
}

func (win *Window) Subwin(rows int16, cols int16, starty int16, startx int16) *Window {
	sw := (*Window)(C.subwin((*C.WINDOW)(win), C.int(rows), C.int(cols), C.int(starty), C.int(startx)));

	return sw;
}

func (win *Window) Derwin(rows int16, cols int16, starty int16, startx int16) *Window {
	dw := (*Window)(C.derwin((*C.WINDOW)(win), C.int(rows), C.int(cols), C.int(starty), C.int(startx)));

	return dw;
}

func Start_color() os.Error {
	if int(C.has_colors()) == 0 {
		return CursesError{"terminal does not support color"};
	}
	C.start_color();

	return nil;
}

func Init_pair(pair int16, fg int16, bg int16) os.Error {
	if C.init_pair(C.short(pair), C.short(fg), C.short(bg)) == 0 {
		return CursesError{"Init_pair failed"};
	}
	return nil;
}

func Color_pair(pair int) int32 {
	return int32(C.COLOR_PAIR(C.int(pair)));
}

func Noecho() os.Error {
	if int(C.noecho()) == 0 {
		return CursesError{"Noecho failed"};
	}
	return nil;
}

func Echo() os.Error {
	if int(C.noecho()) == 0 {
		return CursesError{"Echo failed"};
	}
	return nil;
}

func Curs_set(c int) os.Error {
	if C.curs_set(C.int(c)) == 0 {
		return CursesError{"Curs_set failed"};
	}
	return nil;
}

func Nocbreak() os.Error {
	if C.nocbreak() == 0 {
		return CursesError{"Nocbreak failed"};
	}
	return nil;
}

func Cbreak() os.Error {
	if C.cbreak() == 0 {
		return CursesError{"Cbreak failed"};
	}
	return nil;
}

func Endwin() os.Error {
	if C.endwin() == 0 {
		return CursesError{"Endwin failed"};
	}
	return nil;
}

func (win *Window) Getch() int {
	return int(C.wgetch((*C.WINDOW)(win)));
}

func (win *Window) Addch(x, y int, c int32, flags int32) {
	C.mvwaddch((*C.WINDOW)(win), C.int(y), C.int(x), C.chtype(c) | C.chtype(flags));
}

// Since CGO currently can't handle varg C functions we'll mimic the
// ncurses addstr functions.
func (win *Window) Addstr(x, y int, str string, flags int32, v ...) {
	newstr := fmt.Sprintf(str, v);

	win.Move(x, y);

	for i := 0; i < len(newstr); i++ {
		C.waddch((*C.WINDOW)(win), C.chtype(newstr[i]) | C.chtype(flags));
	}
}

// Normally Y is the first parameter passed in curses.
func (win *Window) Move(x, y int) {
	C.wmove((*C.WINDOW)(win), C.int(y), C.int(x));
}

func (w *Window) Keypad(tf bool) os.Error {
	var outint int;
	if tf == true {outint = 1;}
	if tf == false {outint = 0;}
	if C.keypad((*C.WINDOW)(w), C.int(outint)) == 0 {
		return CursesError{"Keypad failed"};
	}
	return nil;
}

func (win *Window) Refresh() os.Error {
	if C.wrefresh((*C.WINDOW)(win)) == 0 {
		return CursesError{"refresh failed"};
	}
	return nil;
}

func (win *Window) Redrawln(beg_line, num_lines int) {
	C.wredrawln((*C.WINDOW)(win), C.int(beg_line), C.int(num_lines));
}

func (win *Window) Redraw() {
	C.redrawwin((*C.WINDOW)(win));
}

func (win *Window) Clear() {
	C.wclear((*C.WINDOW)(win));
}

func (win *Window) Erase() {
	C.werase((*C.WINDOW)(win));
}

func (win *Window) Clrtobot() {
	C.wclrtobot((*C.WINDOW)(win));
}

func (win *Window) Clrtoeol() {
	C.wclrtoeol((*C.WINDOW)(win));
}

func (win *Window) Box(verch, horch int16) {
	C.box((*C.WINDOW)(win), C.chtype(verch), C.chtype(horch));
}
<commit_msg>Applied the path from mattn!<commit_after>package curses

// struct ldat{};
// struct _win_st{};
// #define _Bool int
// #define NCURSES_OPAQUE 1
// #include <curses.h>
import "C"

import (
	"fmt";
	"os";
	"unsafe";
)

type void unsafe.Pointer;

type Window C.WINDOW;

type CursesError struct {
	message string;
}

func (ce CursesError) String() string {
	return ce.message;
}

// Cursor options.
const (
	CURS_HIDE = iota;
	CURS_NORM;
	CURS_HIGH;
)

// Pointers to the values in curses, which may change values.
var Cols *int = nil;
var Rows *int = nil;

var Colors *int = nil;
var ColorPairs *int = nil;

var Tabsize *int = nil;

// The window returned from C.initscr()
var Stdwin *Window = nil;

// Initializes gocurses
func init() {
	Cols = (*int)(void(&C.COLS));
	Rows = (*int)(void(&C.LINES));

	Colors = (*int)(void(&C.COLORS));
	ColorPairs = (*int)(void(&C.COLOR_PAIRS));

	Tabsize = (*int)(void(&C.TABSIZE));
}

func Initscr() (*Window, os.Error) {
	Stdwin = (*Window)(C.initscr());

	if Stdwin == nil {
		return nil, CursesError{"Initscr failed"};
	}

	return Stdwin, nil;
}

func Newwin(rows int16, cols int16, starty int16, startx int16) *Window {
	nw := (*Window)(C.newwin(C.int(rows), C.int(cols), C.int(starty), C.int(startx)));

	return nw;
}

func (win *Window) Subwin(rows int16, cols int16, starty int16, startx int16) *Window {
	sw := (*Window)(C.subwin((*C.WINDOW)(win), C.int(rows), C.int(cols), C.int(starty), C.int(startx)));

	return sw;
}

func (win *Window) Derwin(rows int16, cols int16, starty int16, startx int16) *Window {
	dw := (*Window)(C.derwin((*C.WINDOW)(win), C.int(rows), C.int(cols), C.int(starty), C.int(startx)));

	return dw;
}

func Start_color() os.Error {
	if int(C.has_colors()) == 0 {
		return CursesError{"terminal does not support color"};
	}
	C.start_color();

	return nil;
}

func Init_pair(pair int16, fg int16, bg int16) os.Error {
	if C.init_pair(C.short(pair), C.short(fg), C.short(bg)) == 0 {
		return CursesError{"Init_pair failed"};
	}
	return nil;
}

func Color_pair(pair int) int32 {
	return int32(C.COLOR_PAIR(C.int(pair)));
}

func Noecho() os.Error {
	if int(C.noecho()) == 0 {
		return CursesError{"Noecho failed"};
	}
	return nil;
}

func Echo() os.Error {
	if int(C.noecho()) == 0 {
		return CursesError{"Echo failed"};
	}
	return nil;
}

func Curs_set(c int) os.Error {
	if C.curs_set(C.int(c)) == 0 {
		return CursesError{"Curs_set failed"};
	}
	return nil;
}

func Nocbreak() os.Error {
	if C.nocbreak() == 0 {
		return CursesError{"Nocbreak failed"};
	}
	return nil;
}

func Cbreak() os.Error {
	if C.cbreak() == 0 {
		return CursesError{"Cbreak failed"};
	}
	return nil;
}

func Endwin() os.Error {
	if C.endwin() == 0 {
		return CursesError{"Endwin failed"};
	}
	return nil;
}

func (win *Window) Getch() int {
	return int(C.wgetch((*C.WINDOW)(win)));
}

func (win *Window) Addch(x, y int, c int32, flags int32) {
	C.mvwaddch((*C.WINDOW)(win), C.int(y), C.int(x), C.chtype(c) | C.chtype(flags));
}

// Since CGO currently can't handle varg C functions we'll mimic the
// ncurses addstr functions.
func (win *Window) Addstr(x, y int, str string, flags int32, v ...interface{}) {
	newstr := fmt.Sprintf(str, v);

	win.Move(x, y);

	for i := 0; i < len(newstr); i++ {
		C.waddch((*C.WINDOW)(win), C.chtype(newstr[i]) | C.chtype(flags));
	}
}

// Normally Y is the first parameter passed in curses.
func (win *Window) Move(x, y int) {
	C.wmove((*C.WINDOW)(win), C.int(y), C.int(x));
}

func (w *Window) Keypad(tf bool) os.Error {
	var outint int;
	if tf == true {outint = 1;}
	if tf == false {outint = 0;}
	if C.keypad((*C.WINDOW)(w), C.int(outint)) == 0 {
		return CursesError{"Keypad failed"};
	}
	return nil;
}

func (win *Window) Refresh() os.Error {
	if C.wrefresh((*C.WINDOW)(win)) == 0 {
		return CursesError{"refresh failed"};
	}
	return nil;
}

func (win *Window) Redrawln(beg_line, num_lines int) {
	C.wredrawln((*C.WINDOW)(win), C.int(beg_line), C.int(num_lines));
}

func (win *Window) Redraw() {
	C.redrawwin((*C.WINDOW)(win));
}

func (win *Window) Clear() {
	C.wclear((*C.WINDOW)(win));
}

func (win *Window) Erase() {
	C.werase((*C.WINDOW)(win));
}

func (win *Window) Clrtobot() {
	C.wclrtobot((*C.WINDOW)(win));
}

func (win *Window) Clrtoeol() {
	C.wclrtoeol((*C.WINDOW)(win));
}

func (win *Window) Box(verch, horch int16) {
	C.box((*C.WINDOW)(win), C.chtype(verch), C.chtype(horch));
}
<|endoftext|>


<commit_before>package term

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

// Default color/attribute settings
var (
	BG          = Blue
	TITLECOLOR  = Cyan | Bold
	TEXTCOLOR   = Black
	BOXBG       = White
	BOXLIGHT    = White | Bold
	BOXDARK     = Black
	BUTTONFOCUS = Yellow | Bold
	BUTTONTEXT  = White | Bold
	LISTFOCUS   = Red
	LISTTEXT    = Black
)

// Place text at the given x and y coordinate.
// fg is the foreground color, while bg is the background color.
func Write(x int, y int, text string, fg termbox.Attribute, bg termbox.Attribute) {
	for pos, r := range text {
		termbox.SetCell(x+pos, y, r, fg, bg)
	}
}

// Place a rune at the given x and y coordinate.
// fg is the foreground color, while bg is the background color.
func WriteRune(x int, y int, r rune, fg termbox.Attribute, bg termbox.Attribute) {
	termbox.SetCell(x, y, r, fg, bg)
}

// Place text at the given x and y coordinate,
// using the default color scheme.
func Say(x int, y int, text string) {
	for pos, r := range text {
		termbox.SetCell(x+pos, y, r, TEXTCOLOR, BG)
	}
}

// Remove all text. Clear the screen.
func Clear() {
	termbox.Clear(TEXTCOLOR, BG)
}

// Retrieve the number of character columns available on the current screen
func ScreenWidth() int {
	return First(termbox.Size)
}

// Retrieve the number of lines of characters available on the current screen
func ScreenHeight() int {
	return Second(termbox.Size)
}

// Update the screen with what has been written so far
func Flush() {
	termbox.Flush()
}

// Initialize the text screen (using curses)
func Init() error {
	return termbox.Init()
}

// Close the text screen (using curses)
func Close() {
	termbox.Close()
}

// Retrieve the next event in the queue (like a keypress)
func PollEvent() *termbox.Event {
	e := termbox.PollEvent()
	return &e
}

// Wait for Esc, Enter or Space to be pressed
func WaitForKey() {
	for {
		e := PollEvent()
		switch e.Type {
		case termbox.EventKey:
			switch e.Key {
			case termbox.KeyEsc, termbox.KeyEnter, termbox.KeySpace:
				return
			}
		}
	}
}

// Set the text/forground color
func SetFg(fg termbox.Attribute) {
	TEXTCOLOR = fg
}

// Set the background color
func SetBg(bg termbox.Attribute) {
	BG = bg
}
<commit_msg>Fix positioning of UTF-8 characters<commit_after>package term

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

// Default color/attribute settings
var (
	BG          = Blue
	TITLECOLOR  = Cyan | Bold
	TEXTCOLOR   = Black
	BOXBG       = White
	BOXLIGHT    = White | Bold
	BOXDARK     = Black
	BUTTONFOCUS = Yellow | Bold
	BUTTONTEXT  = White | Bold
	LISTFOCUS   = Red
	LISTTEXT    = Black
)

// Place text at the given x and y coordinate.
// fg is the foreground color, while bg is the background color.
func Write(x int, y int, text string, fg termbox.Attribute, bg termbox.Attribute) {
	//runeCount := utf8.RuneCountInString(text)
	pos := x
	for _, r := range text {
		termbox.SetCell(pos, y, r, fg, bg)
		pos++
	}
}

// Place a rune at the given x and y coordinate.
// fg is the foreground color, while bg is the background color.
func WriteRune(x int, y int, r rune, fg termbox.Attribute, bg termbox.Attribute) {
	termbox.SetCell(x, y, r, fg, bg)
}

// Place text at the given x and y coordinate,
// using the default color scheme.
func Say(x int, y int, text string) {
	pos := x
	for _, r := range text {
		termbox.SetCell(pos, y, r, TEXTCOLOR, BG)
		pos++
	}
}

// Remove all text. Clear the screen.
func Clear() {
	termbox.Clear(TEXTCOLOR, BG)
}

// Retrieve the number of character columns available on the current screen
func ScreenWidth() int {
	return First(termbox.Size)
}

// Retrieve the number of lines of characters available on the current screen
func ScreenHeight() int {
	return Second(termbox.Size)
}

// Update the screen with what has been written so far
func Flush() {
	termbox.Flush()
}

// Initialize the text screen (using curses)
func Init() error {
	return termbox.Init()
}

// Close the text screen (using curses)
func Close() {
	termbox.Close()
}

// Retrieve the next event in the queue (like a keypress)
func PollEvent() *termbox.Event {
	e := termbox.PollEvent()
	return &e
}

// Wait for Esc, Enter or Space to be pressed
func WaitForKey() {
	for {
		e := PollEvent()
		switch e.Type {
		case termbox.EventKey:
			switch e.Key {
			case termbox.KeyEsc, termbox.KeyEnter, termbox.KeySpace:
				return
			}
		}
	}
}

// Set the text/forground color
func SetFg(fg termbox.Attribute) {
	TEXTCOLOR = fg
}

// Set the background color
func SetBg(bg termbox.Attribute) {
	BG = bg
}
<|endoftext|>


<commit_before>package stash

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

	"github.com/drone/drone/shared/httputil"
	"github.com/drone/drone/shared/model"
	"github.com/reinbach/go-stash/oauth1"
	"github.com/reinbach/go-stash/stash"
)

type Stash struct {
	URL        string
	API        string
	Secret     string
	PrivateKey string
	Hook       string
	Open       bool
}

func New(url, api, secret, private_key, hook string, open bool) *Stash {
	return &Stash{
		URL:        url,
		API:        api,
		Secret:     secret,
		PrivateKey: private_key,
		Hook:       hook,
		Open:       open,
	}
}

// GetLogin handles authentication to third party, remote services
// and returns the required user data in a standard format.
func (r *Stash) Authorize(w http.ResponseWriter, req *http.Request) (*model.Login, error) {
	var consumer = oauth1.Consumer{
		RequestTokenURL:       r.URL + "/plugins/servlet/oauth/request-token",
		AuthorizationURL:      r.URL + "/plugins/servlet/oauth/authorize",
		AccessTokenURL:        r.URL + "/plugins/servlet/oauth/access-token",
		CallbackURL:           httputil.GetScheme(req) + "://" + httputil.GetHost(req) + "/api/auth/stash.atlassian.com",
		ConsumerKey:           r.Secret,
		ConsumerPrivateKeyPem: r.PrivateKey,
	}

	// get the oauth verifier
	verifier := req.FormValue("oauth_verifier")
	if len(verifier) == 0 {
		// Generate a Request Token
		requestToken, err := consumer.RequestToken()
		if err != nil {
			return nil, err
		}

		// add the request token as a signed cookie
		httputil.SetCookie(w, req, "stash_token", requestToken.Encode())

		url, _ := consumer.AuthorizeRedirect(requestToken)
		http.Redirect(w, req, url, http.StatusSeeOther)
		return nil, nil
	}

	// remove stash token data once before redirecting
	// back to the application.
	defer httputil.DelCookie(w, req, "stash_token")

	// get the tokens from the request
	requestTokenStr := httputil.GetCookie(req, "stash_token")
	requestToken, err := oauth1.ParseRequestTokenStr(requestTokenStr)
	if err != nil {
		return nil, err
	}

	// exchange for an access token
	accessToken, err := consumer.AuthorizeToken(requestToken, verifier)
	if err != nil {
		return nil, err
	}

	// create the Stash client
	var client = stash.New(
		r.URL,
		r.Secret,
		accessToken.Token(),
		accessToken.Secret(),
		r.PrivateKey,
	)

	// get the currently authenticated Stash User
	user, err := client.Users.Current()
	if err != nil {
		return nil, err
	}

	// put the user data in the common format
	login := model.Login{
		Login:  user.Username,
		Access: accessToken.Token(),
		Secret: accessToken.Secret(),
		//Name:   user.DisplayName,
	}

	return &login, nil
}

// GetKind returns the internal identifier of this remote Stash instance.
func (r *Stash) GetKind() string {
	return model.RemoteStash
}

// GetHost returns the url.Host of this remote system.
func (r *Stash) GetHost() string {
	uri, _ := url.Parse(r.URL)
	return uri.Host
}

// GetRepos fetches all repositories that the specified
// user has access to in the remote system.
func (r *Stash) GetRepos(user *model.User) ([]*model.Repo, error) {
	var repos []*model.Repo
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)

	// parse the hostname from the stash url
	var stashurl, err = url.Parse(r.URL)
	if err != nil {
		return nil, err
	}

	// parse the hostname from the stash api
	stashapi, err := url.Parse(r.API)
	if err != nil {
		return nil, err
	}

	list, err := client.Repos.List()
	if err != nil {
		return nil, err
	}

	var remote = r.GetKind()
	var hostname = r.GetHost()

	for _, item := range list {
		// for now we only support git repos
		if item.ScmId != "git" {
			continue
		}

		// these are the urls required to clone the repository
		var clone = fmt.Sprintf("https://%s%s/%s/%s.git", stashurl.Host, stashurl.Path, item.Project.Key, item.Name)
		var ssh = fmt.Sprintf("ssh://git@%s/%s/%s.git", stashapi.Host, item.Project.Key, item.Name)

		var repo = model.Repo{
			UserID:   user.ID,
			Remote:   remote,
			Host:     hostname,
			Owner:    item.Project.Key,
			Name:     item.Name,
			Private:  !item.Public,
			CloneURL: clone,
			GitURL:   clone,
			SSHURL:   ssh,
			Role: &model.Perm{
				Admin: true,
				Write: true,
				Read:  true,
			},
		}

		if repo.Private {
			repo.CloneURL = repo.SSHURL
		}

		repos = append(repos, &repo)
	}

	return repos, err
}

// GetScript fetches the build script (.drone.yml) from the remote
// repository and returns in string format.
func (r *Stash) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
	// create the Atlassian Stash client
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)

	// get the yaml from the database
	var raw, err = client.Contents.Find(hook.Owner, hook.Repo, ".drone.yml")
	if err != nil {
		return nil, err
	}

	return []byte(raw), nil
}

// Activate activates a repository by adding a Post-Commit hook and
// a Public Deploy key, if applicable.
func (r *Stash) Activate(user *model.User, repo *model.Repo, link string) error {
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)

	// if the repository is private we'll need
	// to upload a stash key to the repository
	if repo.Private {
		var _, err = client.Keys.CreateUpdate(repo.PublicKey)
		if err != nil {
			return err
		}
	}

	// add the hook
	var hook = GetHook(user, repo, link)
	var _, err = client.Repos.CreateHook(repo.Owner, repo.Name, r.Hook, hook)
	return err
}

// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link. SSH key is not removed as this is on the user,
// not the repo
func (r *Stash) Deactivate(user *model.User, repo *model.Repo, link string) error {
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)
	var hook = GetHook(user, repo, link)
	return client.Repos.DeleteHook(repo.Owner, repo.Name, r.Hook, hook)
}

// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Stash) ParseHook(req *http.Request) (*model.Hook, error) {
	// get the project and repo from the request
	var owner = req.FormValue("owner")
	var name = req.FormValue("name")
	var branch = req.FormValue("branch")
	var hash = req.FormValue("hash")
	var message = req.FormValue("type")
	var author = req.FormValue("displayName")

	// verify the payload has the minimum amount of required data.
	if owner == "" || branch == "" {
		return nil, fmt.Errorf("Invalid Atlassian Stash post-commit Hook. Missing Repo or Branch data.")
	}

	return &model.Hook{
		Owner:     owner,
		Repo:      name,
		Sha:       hash,
		Branch:    branch,
		Author:    author,
		Timestamp: time.Now().UTC().String(),
		Message:   message,
	}, nil
}

func (s *Stash) OpenRegistration() bool {
	return s.Open
}

func (s *Stash) GetToken(user *model.User) (*model.Token, error) {
	return nil, nil
}

// GetKeyTitle is a helper function that generates a title for the
// RSA public key based on the username and domain name.
func GetKeyTitle(rawurl string) (string, error) {
	var uri, err = url.Parse(rawurl)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("drone@%s", uri.Host), nil
}

func GetHook(user *model.User, repo *model.Repo, link string) string {
	return fmt.Sprintf("%s?owner=%s&name=%s&branch=${refChange.name}&hash=${refChange.toHash}&message=${refChange.type}&author=${user.displayName}", link, repo.Owner, repo.Name)
}
<commit_msg>go-stash client updated<commit_after>package stash

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

	"github.com/drone/drone/shared/httputil"
	"github.com/drone/drone/shared/model"
	"github.com/reinbach/go-stash/oauth1"
	"github.com/reinbach/go-stash/stash"
)

type Stash struct {
	URL        string
	API        string
	Secret     string
	PrivateKey string
	Hook       string
	Open       bool
}

func New(url, api, secret, private_key, hook string, open bool) *Stash {
	return &Stash{
		URL:        url,
		API:        api,
		Secret:     secret,
		PrivateKey: private_key,
		Hook:       hook,
		Open:       open,
	}
}

// GetLogin handles authentication to third party, remote services
// and returns the required user data in a standard format.
func (r *Stash) Authorize(w http.ResponseWriter, req *http.Request) (*model.Login, error) {
	var consumer = oauth1.Consumer{
		RequestTokenURL:       r.URL + "/plugins/servlet/oauth/request-token",
		AuthorizationURL:      r.URL + "/plugins/servlet/oauth/authorize",
		AccessTokenURL:        r.URL + "/plugins/servlet/oauth/access-token",
		CallbackURL:           httputil.GetScheme(req) + "://" + httputil.GetHost(req) + "/api/auth/stash.atlassian.com",
		ConsumerKey:           r.Secret,
		ConsumerPrivateKeyPem: r.PrivateKey,
	}

	// get the oauth verifier
	verifier := req.FormValue("oauth_verifier")
	if len(verifier) == 0 {
		// Generate a Request Token
		requestToken, err := consumer.RequestToken()
		if err != nil {
			return nil, err
		}

		// add the request token as a signed cookie
		httputil.SetCookie(w, req, "stash_token", requestToken.Encode())

		url, _ := consumer.AuthorizeRedirect(requestToken)
		http.Redirect(w, req, url, http.StatusSeeOther)
		return nil, nil
	}

	// remove stash token data once before redirecting
	// back to the application.
	defer httputil.DelCookie(w, req, "stash_token")

	// get the tokens from the request
	requestTokenStr := httputil.GetCookie(req, "stash_token")
	requestToken, err := oauth1.ParseRequestTokenStr(requestTokenStr)
	if err != nil {
		return nil, err
	}

	// exchange for an access token
	accessToken, err := consumer.AuthorizeToken(requestToken, verifier)
	if err != nil {
		return nil, err
	}

	// create the Stash client
	var client = stash.New(
		r.URL,
		r.Secret,
		accessToken.Token(),
		accessToken.Secret(),
		r.PrivateKey,
	)

	// get the currently authenticated Stash User
	user, err := client.Users.Current()
	if err != nil {
		return nil, err
	}

	// put the user data in the common format
	login := model.Login{
		Login:  user.Username,
		Access: accessToken.Token(),
		Secret: accessToken.Secret(),
		//Name:   user.DisplayName,
	}

	return &login, nil
}

// GetKind returns the internal identifier of this remote Stash instance.
func (r *Stash) GetKind() string {
	return model.RemoteStash
}

// GetHost returns the url.Host of this remote system.
func (r *Stash) GetHost() string {
	uri, _ := url.Parse(r.URL)
	return uri.Host
}

// GetRepos fetches all repositories that the specified
// user has access to in the remote system.
func (r *Stash) GetRepos(user *model.User) ([]*model.Repo, error) {
	var repos []*model.Repo
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)

	// parse the hostname from the stash url
	var stashurl, err = url.Parse(r.URL)
	if err != nil {
		return nil, err
	}

	// parse the hostname from the stash api
	stashapi, err := url.Parse(r.API)
	if err != nil {
		return nil, err
	}

	list, err := client.Repos.List()
	if err != nil {
		return nil, err
	}

	var remote = r.GetKind()
	var hostname = r.GetHost()

	for _, item := range list {
		// for now we only support git repos
		if item.ScmId != "git" {
			continue
		}

		// these are the urls required to clone the repository
		var clone = fmt.Sprintf("https://%s%s/%s/%s.git", stashurl.Host, stashurl.Path, item.Project.Key, item.Name)
		var ssh = fmt.Sprintf("ssh://git@%s/%s/%s.git", stashapi.Host, item.Project.Key, item.Name)

		var repo = model.Repo{
			UserID:   user.ID,
			Remote:   remote,
			Host:     hostname,
			Owner:    item.Project.Key,
			Name:     item.Name,
			Private:  !item.Public,
			CloneURL: clone,
			GitURL:   clone,
			SSHURL:   ssh,
			Role: &model.Perm{
				Admin: true,
				Write: true,
				Read:  true,
			},
		}

		if repo.Private {
			repo.CloneURL = repo.SSHURL
		}

		repos = append(repos, &repo)
	}

	return repos, err
}

// GetScript fetches the build script (.drone.yml) from the remote
// repository and returns in string format.
func (r *Stash) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
	// create the Atlassian Stash client
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)

	// get the yaml from the database
	var raw, err = client.Contents.Find(hook.Owner, hook.Repo, ".drone.yml")
	if err != nil {
		return nil, err
	}

	return []byte(raw), nil
}

// Activate activates a repository by adding a Post-Commit hook and
// a Public Deploy key, if applicable.
func (r *Stash) Activate(user *model.User, repo *model.Repo, link string) error {
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)

	// if the repository is private we'll need
	// to upload a stash key to the repository
	if repo.Private {
		var _, err = client.Keys.CreateUpdate(repo.PublicKey)
		if err != nil {
			return err
		}
	}

	// add the hook
	var hook = GetHook(user, repo, link)
	var _, err = client.Hooks.CreateHook(repo.Owner, repo.Name, r.Hook, hook)
	return err
}

// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link. SSH key is not removed as this is on the user,
// not the repo
func (r *Stash) Deactivate(user *model.User, repo *model.Repo, link string) error {
	var client = stash.New(
		r.URL,
		r.Secret,
		user.Access,
		user.Secret,
		r.PrivateKey,
	)
	var hook = GetHook(user, repo, link)
	return client.Hooks.DeleteHook(repo.Owner, repo.Name, r.Hook, hook)
}

// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Stash) ParseHook(req *http.Request) (*model.Hook, error) {
	// get the project and repo from the request
	var owner = req.FormValue("owner")
	var name = req.FormValue("name")
	var branch = req.FormValue("branch")
	var hash = req.FormValue("hash")
	var message = req.FormValue("type")
	var author = req.FormValue("displayName")

	// verify the payload has the minimum amount of required data.
	if owner == "" || branch == "" {
		return nil, fmt.Errorf("Invalid Atlassian Stash post-commit Hook. Missing Repo or Branch data.")
	}

	return &model.Hook{
		Owner:     owner,
		Repo:      name,
		Sha:       hash,
		Branch:    branch,
		Author:    author,
		Timestamp: time.Now().UTC().String(),
		Message:   message,
	}, nil
}

func (s *Stash) OpenRegistration() bool {
	return s.Open
}

func (s *Stash) GetToken(user *model.User) (*model.Token, error) {
	return nil, nil
}

// GetKeyTitle is a helper function that generates a title for the
// RSA public key based on the username and domain name.
func GetKeyTitle(rawurl string) (string, error) {
	var uri, err = url.Parse(rawurl)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("drone@%s", uri.Host), nil
}

func GetHook(user *model.User, repo *model.Repo, link string) string {
	return fmt.Sprintf("%s?owner=%s&name=%s&branch=${refChange.name}&hash=${refChange.toHash}&message=${refChange.type}&author=${user.displayName}", link, repo.Owner, repo.Name)
}
<|endoftext|>