<commit_before>package main

import (
	"flag"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/fubarhouse/golang-drush/command"
	"strings"
)

func main() {
	var strAliases = flag.String("aliases", "", "comma-separated list of aliases for action")
	var strCommands = flag.String("commands", "rr,updb --yes,cc all", "comma-separated list of commands for action")
	var strPattern = flag.String("pattern", "%v", "A modifier which allows rewriting of aliases replacing '%v' in the pattern with the alias.")
	var boolVerbose = flag.Bool("verbose", false, "adds raw output to end of program.")
	flag.Parse()

	var FinalOutput []string

	if !strings.Contains(*strPattern, "%v") {
		log.Errorln("Specified pattern does not include alias modifier.")
	}

	if *strAliases != "" {
		log.Errorln("Aliases are not specified.")
	}

	if *strCommands != "" {
		log.Errorln("Commands are not specified.")
	}

	if *strAliases != "" {
		for _, Alias := range strings.Split(*strAliases, ",") {
			Alias = strings.Replace(*strPattern, "%v", Alias, 1)
			for _, Command := range strings.Split(*strCommands, ",") {
				FinalOutput = append(FinalOutput, fmt.Sprintf("\n\ndrush @%v %v\n", Alias, Command))
				DrushCommand := command.NewDrushCommand()
				DrushCommand.SetAlias(Alias)
				DrushCommand.SetCommand(Command)
				DrushCommandOut, DrushCommandError := DrushCommand.Output()
				if DrushCommandError != nil {
					log.Warnf("%v, %v, unsuccessful.", DrushCommand.GetAlias(), DrushCommand.GetCommand())
					StdOutLines := DrushCommandOut
					for _, StdOutLine := range StdOutLines {
						FinalOutput = append(FinalOutput, StdOutLine)
					}
				} else {
					log.Infof("%v, %v, successful.", DrushCommand.GetAlias(), DrushCommand.GetCommand())
					StdOutLines := DrushCommandOut
					for _, StdOutLine := range StdOutLines {
						FinalOutput = append(FinalOutput, StdOutLine)
					}
				}
			}
		}
		if *boolVerbose {
			for _, value := range FinalOutput {
				log.Println(value)
			}
		}
	} else {
		flag.Usage()
	}
}
<commit_msg>reorganise and adjust logic for reporting.<commit_after>package main

import (
	"flag"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/fubarhouse/golang-drush/command"
	"strings"
)

func main() {
	var strAliases = flag.String("aliases", "", "comma-separated list of aliases for action")
	var strCommands = flag.String("commands", "rr,updb --yes,cc all", "comma-separated list of commands for action")
	var strPattern = flag.String("pattern", "%v", "A modifier which allows rewriting of aliases replacing '%v' in the pattern with the alias.")
	var boolVerbose = flag.Bool("verbose", false, "adds raw output to end of program.")
	flag.Parse()

	var FinalOutput []string

	if !strings.Contains(*strPattern, "%v") {
		log.Errorln("Specified pattern does not include alias modifier.")
	}

	if *strCommands != "" {
		log.Errorln("Commands are not specified.")
	}

	if *strAliases == "" {
		flag.Usage()
		log.Errorln("Aliases are not specified.")
	} else {
		for _, Alias := range strings.Split(*strAliases, ",") {
			Alias = strings.Replace(*strPattern, "%v", Alias, 1)
			for _, Command := range strings.Split(*strCommands, ",") {
				FinalOutput = append(FinalOutput, fmt.Sprintf("\n\ndrush @%v %v\n", Alias, Command))
				DrushCommand := command.NewDrushCommand()
				DrushCommand.SetAlias(Alias)
				DrushCommand.SetCommand(Command)
				DrushCommandOut, DrushCommandError := DrushCommand.Output()
				if DrushCommandError != nil {
					log.Warnf("%v, %v, unsuccessful.", DrushCommand.GetAlias(), DrushCommand.GetCommand())
					StdOutLines := DrushCommandOut
					for _, StdOutLine := range StdOutLines {
						FinalOutput = append(FinalOutput, StdOutLine)
					}
				} else {
					log.Infof("%v, %v, successful.", DrushCommand.GetAlias(), DrushCommand.GetCommand())
					StdOutLines := DrushCommandOut
					for _, StdOutLine := range StdOutLines {
						FinalOutput = append(FinalOutput, StdOutLine)
					}
				}
			}
		}
		if *boolVerbose {
			for _, value := range FinalOutput {
				log.Println(value)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	"errors"
	"fmt"
	"log"

	"github.com/go-openapi/loads"
	"github.com/go-openapi/strfmt"
	"github.com/go-openapi/validate"
)

const (
	// Output messages
	missingArgMsg  = "The validate command requires the swagger document url to be specified"
	validSpecMsg   = "\nThe swagger spec at %q is valid against swagger specification %s\n"
	invalidSpecMsg = "\nThe swagger spec at %q is invalid against swagger specification %s.\nSee errors below:\n"
	warningSpecMsg = "\nThe swagger spec at %q showed up some valid but possiby unwanted constructs."
)

// ValidateSpec is a command that validates a swagger document
// against the swagger specification
type ValidateSpec struct {
	// SchemaURL string `long:"schema" description:"The schema url to use" default:"http://swagger.io/v2/schema.json"`
	SkipWarnings bool `long:"skip-warnings" description:"when present will not show up warnings upon validation"`
	StopOnError  bool `long:"stop-on-error" description:"when present will not continue validation after critical errors are found"`
}

// Execute validates the spec
func (c *ValidateSpec) Execute(args []string) error {
	if len(args) == 0 {
		return errors.New(missingArgMsg)
	}

	swaggerDoc := args[0]

	specDoc, err := loads.Spec(swaggerDoc)
	if err != nil {
		log.Fatalln(err)
	}

	// Attempts to report about all errors
	validate.SetContinueOnErrors(!c.StopOnError)

	v := validate.NewSpecValidator(specDoc.Schema(), strfmt.Default)
	result, _ := v.Validate(specDoc) // returns fully detailed result with errors and warnings
	//result := validate.Spec(specDoc, strfmt.Default)		// returns single error

	if result.IsValid() {
		log.Printf(validSpecMsg, swaggerDoc, specDoc.Version())
	}
	if result.HasWarnings() {
		log.Printf(warningSpecMsg, swaggerDoc)
		if !c.SkipWarnings {
			log.Printf("See warnings below:\n")
			for _, desc := range result.Warnings {
				log.Printf("- WARNING: %s\n", desc.Error())
			}
		}
	}
	if result.HasErrors() {
		str := fmt.Sprintf(invalidSpecMsg, swaggerDoc, specDoc.Version())
		for _, desc := range result.Errors {
			str += fmt.Sprintf("- %s\n", desc.Error())
		}
		return errors.New(str)
	}

	return nil
}
<commit_msg>missing letter in message (possiby => possibly)<commit_after>// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	"errors"
	"fmt"
	"log"

	"github.com/go-openapi/loads"
	"github.com/go-openapi/strfmt"
	"github.com/go-openapi/validate"
)

const (
	// Output messages
	missingArgMsg  = "The validate command requires the swagger document url to be specified"
	validSpecMsg   = "\nThe swagger spec at %q is valid against swagger specification %s\n"
	invalidSpecMsg = "\nThe swagger spec at %q is invalid against swagger specification %s.\nSee errors below:\n"
	warningSpecMsg = "\nThe swagger spec at %q showed up some valid but possibly unwanted constructs."
)

// ValidateSpec is a command that validates a swagger document
// against the swagger specification
type ValidateSpec struct {
	// SchemaURL string `long:"schema" description:"The schema url to use" default:"http://swagger.io/v2/schema.json"`
	SkipWarnings bool `long:"skip-warnings" description:"when present will not show up warnings upon validation"`
	StopOnError  bool `long:"stop-on-error" description:"when present will not continue validation after critical errors are found"`
}

// Execute validates the spec
func (c *ValidateSpec) Execute(args []string) error {
	if len(args) == 0 {
		return errors.New(missingArgMsg)
	}

	swaggerDoc := args[0]

	specDoc, err := loads.Spec(swaggerDoc)
	if err != nil {
		log.Fatalln(err)
	}

	// Attempts to report about all errors
	validate.SetContinueOnErrors(!c.StopOnError)

	v := validate.NewSpecValidator(specDoc.Schema(), strfmt.Default)
	result, _ := v.Validate(specDoc) // returns fully detailed result with errors and warnings
	//result := validate.Spec(specDoc, strfmt.Default)		// returns single error

	if result.IsValid() {
		log.Printf(validSpecMsg, swaggerDoc, specDoc.Version())
	}
	if result.HasWarnings() {
		log.Printf(warningSpecMsg, swaggerDoc)
		if !c.SkipWarnings {
			log.Printf("See warnings below:\n")
			for _, desc := range result.Warnings {
				log.Printf("- WARNING: %s\n", desc.Error())
			}
		}
	}
	if result.HasErrors() {
		str := fmt.Sprintf(invalidSpecMsg, swaggerDoc, specDoc.Version())
		for _, desc := range result.Errors {
			str += fmt.Sprintf("- %s\n", desc.Error())
		}
		return errors.New(str)
	}

	return nil
}
<|endoftext|>


<commit_before>package bothandlers

import (
	"fmt"
	"github.com/djosephsen/hal"
)

var ListChores = &hal.Handler{
	Method:  hal.RESPOND,
	Pattern: `(list chores)|(chore list)`,
	Run: func(res *hal.Response) error {
		var reply string
		if len(res.Robot.Chores) == 0{
			reply=`No chores have been registered (sorry?)`
		}else{
			for _,c := range res.Robot.Chores{
				reply = fmt.Sprintf("%s\n%s:%s:%s:%s",reply,c.Name, c.Schedule, c.Next, c.State)
			}
		}
		return res.Reply(reply)
	},
}
<commit_msg>formmating<commit_after>package bothandlers

import (
	"fmt"
	"github.com/djosephsen/hal"
)

var ListChores = &hal.Handler{
	Method:  hal.RESPOND,
	Pattern: `(list chores)|(chore list)`,
	Run: func(res *hal.Response) error {
		var reply string
		if len(res.Robot.Chores) == 0{
			reply=`No chores have been registered (sorry?)`
		}else{
			for _,c := range res.Robot.Chores{
				reply = fmt.Sprintf("%s\n%s:small_blue_diamond:%s:small_blue_diamond:%s:small_blue_diamond:%s",reply,c.Name, c.Schedule, c.Next, c.State)
			}
		}
		return res.Reply(reply)
	},
}
<|endoftext|>


<commit_before>package service

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/kardianos/osext"
)

const (
	initSystemV = initFlavor(iota)
	initUpstart
	initSystemd
)

// the default flavor is initSystemV. we lookup the command line of
// process 1 to detect systemd or upstart
func getFlavor() (initFlavor, error) {
	initCmd, err := ioutil.ReadFile("/proc/1/cmdline")
	if err != nil {
		return initSystemV, err
	}
	// Trim any nul bytes from the result, which are present with some
	// kernels but not others
	init := string(bytes.TrimRight(initCmd, "\x00"))
	if strings.Contains(init, "init [") {
		return initSystemV, nil
	}
	if strings.Contains(init, "systemd") {
		return initSystemd, nil
	}
	if strings.Contains(init, "init") {
		// not so fast! you may think this is upstart, but it may be
		// a symlink to systemd... yeah, debian does that... ( x )
		var target string
		if len(init) > 9 && init[0:10] == "/sbin/init" {
			target, err = filepath.EvalSymlinks("/sbin/init")
		} else {
			target, err = filepath.EvalSymlinks(init)
		}
		if err == nil && strings.Contains(target, "systemd") {
			return initSystemd, nil
		}
		return initUpstart, nil
	}
	// failed to detect init system, falling back to sysvinit
	return initSystemV, nil
}

func newService(c *Config) (Service, error) {
	var err error
	flavor, err := getFlavor()
	if err != nil {
		return nil, err
	}
	s := &linuxService{
		flavor:      flavor,
		name:        c.Name,
		displayName: c.DisplayName,
		description: c.Description,
	}
	s.logger, err = syslog.New(syslog.LOG_INFO, s.name)
	if err != nil {
		return nil, err
	}
	return s, nil
}

type linuxService struct {
	flavor                         initFlavor
	name, displayName, description string
	logger                         *syslog.Writer
}

func (ls *linuxService) String() string {
	return fmt.Sprintf("Linux %s", ls.flavor.String())
}

type initFlavor uint8

func (f initFlavor) String() string {
	switch f {
	case initSystemV:
		return "sysvinit"
	case initUpstart:
		return "upstart"
	case initSystemd:
		return "systemd"
	default:
		return "unknown"
	}
}

func (f initFlavor) ConfigPath(name string) string {
	switch f {
	case initSystemd:
		return "/etc/systemd/system/" + name + ".service"
	case initSystemV:
		return "/etc/init.d/" + name
	case initUpstart:
		return "/etc/init/" + name + ".conf"
	default:
		return ""
	}
}

func (f initFlavor) GetTemplate() *template.Template {
	var templ string
	switch f {
	case initSystemd:
		templ = systemdScript
	case initSystemV:
		templ = systemVScript
	case initUpstart:
		templ = upstartScript
	}
	return template.Must(template.New(f.String() + "Script").Parse(templ))
}

func (s *linuxService) Install() error {
	confPath := s.flavor.ConfigPath(s.name)
	_, err := os.Stat(confPath)
	if err == nil {
		return fmt.Errorf("Init already exists: %s", confPath)
	}

	f, err := os.Create(confPath)
	if err != nil {
		return err
	}
	defer f.Close()

	path, err := osext.Executable()
	if err != nil {
		return err
	}

	var to = &struct {
		Display     string
		Description string
		Path        string
	}{
		s.displayName,
		s.description,
		path,
	}

	err = s.flavor.GetTemplate().Execute(f, to)
	if err != nil {
		return err
	}

	if s.flavor == initSystemV {
		if err = os.Chmod(confPath, 0755); err != nil {
			return err
		}
		for _, i := range [...]string{"2", "3", "4", "5"} {
			if err = os.Symlink(confPath, "/etc/rc"+i+".d/S50"+s.name); err != nil {
				continue
			}
		}
		for _, i := range [...]string{"0", "1", "6"} {
			if err = os.Symlink(confPath, "/etc/rc"+i+".d/K02"+s.name); err != nil {
				continue
			}
		}
	}

	if s.flavor == initSystemd {
		err = exec.Command("systemctl", "enable", s.name+".service").Run()
		if err != nil {
			return err
		}
		return exec.Command("systemctl", "daemon-reload").Run()
	}

	return nil
}

func (s *linuxService) Remove() error {
	if s.flavor == initSystemd {
		exec.Command("systemctl", "disable", s.name+".service").Run()
	}
	if err := os.Remove(s.flavor.ConfigPath(s.name)); err != nil {
		return err
	}
	return nil
}

func (s *linuxService) Run(onStart, onStop func() error) (err error) {
	err = onStart()
	if err != nil {
		return err
	}
	defer func() {
		err = onStop()
	}()

	sigChan := make(chan os.Signal, 3)

	signal.Notify(sigChan, os.Interrupt, os.Kill)

	<-sigChan

	return nil
}

func (s *linuxService) Start() error {
	switch s.flavor {
	case initSystemd:
		return exec.Command("systemctl", "start", s.name+".service").Run()
	case initUpstart:
		return exec.Command("initctl", "start", s.name).Run()
	default:
		return exec.Command("service", s.name, "start").Run()
	}
}

func (s *linuxService) Stop() error {
	switch s.flavor {
	case initSystemd:
		return exec.Command("systemctl", "stop", s.name+".service").Start()
	case initUpstart:
		return exec.Command("initctl", "stop", s.name).Start()
	default:
		return exec.Command("service", s.name, "stop").Start()
	}
}

func (s *linuxService) IntervalMode(interval int) error {
	return fmt.Errorf("interval mode service only supported on darwin")
}

func (s *linuxService) Error(format string, a ...interface{}) error {
	return s.logger.Err(fmt.Sprintf(format, a...))
}
func (s *linuxService) Warning(format string, a ...interface{}) error {
	return s.logger.Warning(fmt.Sprintf(format, a...))
}
func (s *linuxService) Info(format string, a ...interface{}) error {
	return s.logger.Info(fmt.Sprintf(format, a...))
}

const systemVScript = `#!/bin/sh
# For RedHat and cousins:
# chkconfig: - 99 01
# description: {{.Description}}
# processname: {{.Path}}

### BEGIN INIT INFO
# Provides:          {{.Path}}
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: {{.Display}}
# Description:       {{.Description}}
### END INIT INFO

cmd="{{.Path}}"

name=$(basename $0)
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err"

get_pid() {
    cat "$pid_file"
}

is_running() {
    [ -f "$pid_file" ] && ps $(get_pid) > /dev/null 2>&1
}

case "$1" in
    start)
        if is_running; then
            echo "Already started"
        else
            echo "Starting $name"
            $cmd >> "$stdout_log" 2>> "$stderr_log" &
            echo $! > "$pid_file"
            if ! is_running; then
                echo "Unable to start, see $stdout_log and $stderr_log"
                exit 1
            fi
        fi
    ;;
    stop)
        if is_running; then
            echo -n "Stopping $name.."
            kill $(get_pid)
            for i in {1..10}
            do
                if ! is_running; then
                    break
                fi
                echo -n "."
                sleep 1
            done
            echo
            if is_running; then
                echo "Not stopped; may still be shutting down or shutdown may have failed"
                exit 1
            else
                echo "Stopped"
                if [ -f "$pid_file" ]; then
                    rm "$pid_file"
                fi
            fi
        else
            echo "Not running"
        fi
    ;;
    restart)
        $0 stop
        if is_running; then
            echo "Unable to stop, will not attempt to start"
            exit 1
        fi
        $0 start
    ;;
    status)
        if is_running; then
            echo "Running"
        else
            echo "Stopped"
            exit 1
        fi
    ;;
    *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac
exit 0`

const upstartScript = `# {{.Description}}

description     "{{.Display}}"

start on filesystem or runlevel [2345]
stop on runlevel [!2345]

#setuid username

# stop the respawn is process fails to start 5 times within 5 minutes
respawn
respawn limit 5 300
umask 022

console none

pre-start script
    test -x {{.Path}} || { stop; exit 0; }
end script

# Start
exec {{.Path}}
`

const systemdScript = `[Unit]
Description={{.Description}}
ConditionFileIsExecutable={{.Path}}

[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart={{.Path}}

# respawn process on crash after a 3s wait
# if fails to start 5 times within 5 minutes, stop trying
Restart=on-failure
RestartSec=3s
StartLimitInterval=300
StartLimitBurst=5

[Install]
WantedBy=multi-user.target
`
<commit_msg>[minor] revendor service-go<commit_after>package service

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/kardianos/osext"
)

const (
	initSystemV = initFlavor(iota)
	initUpstart
	initSystemd
)

// the default flavor is initSystemV. we lookup the command line of
// process 1 to detect systemd or upstart
func getFlavor() (initFlavor, error) {
	initCmd, err := ioutil.ReadFile("/proc/1/cmdline")
	if err != nil {
		return initSystemV, err
	}
	// Trim any nul bytes from the result, which are present with some
	// kernels but not others
	init := string(bytes.TrimRight(initCmd, "\x00"))
	if strings.Contains(init, "init [") {
		return initSystemV, nil
	}
	if strings.Contains(init, "systemd") {
		return initSystemd, nil
	}
	if strings.Contains(init, "init") {
		// not so fast! you may think this is upstart, but it may be
		// a symlink to systemd... yeah, debian does that... ( x )
		var target string
		if len(init) > 9 && init[0:10] == "/sbin/init" {
			target, err = filepath.EvalSymlinks("/sbin/init")
		} else {
			target, err = filepath.EvalSymlinks(init)
		}
		if err == nil && strings.Contains(target, "systemd") {
			return initSystemd, nil
		}
		return initUpstart, nil
	}
	// failed to detect init system, falling back to sysvinit
	return initSystemV, nil
}

func newService(c *Config) (Service, error) {
	var err error
	flavor, err := getFlavor()
	if err != nil {
		return nil, err
	}
	s := &linuxService{
		flavor:      flavor,
		name:        c.Name,
		displayName: c.DisplayName,
		description: c.Description,
	}
	s.logger, err = syslog.New(syslog.LOG_INFO, s.name)
	if err != nil {
		return nil, err
	}
	return s, nil
}

type linuxService struct {
	flavor                         initFlavor
	name, displayName, description string
	logger                         *syslog.Writer
}

func (ls *linuxService) String() string {
	return fmt.Sprintf("Linux %s", ls.flavor.String())
}

type initFlavor uint8

func (f initFlavor) String() string {
	switch f {
	case initSystemV:
		return "sysvinit"
	case initUpstart:
		return "upstart"
	case initSystemd:
		return "systemd"
	default:
		return "unknown"
	}
}

func (f initFlavor) ConfigPath(name string) string {
	switch f {
	case initSystemd:
		return "/etc/systemd/system/" + name + ".service"
	case initSystemV:
		return "/etc/init.d/" + name
	case initUpstart:
		return "/etc/init/" + name + ".conf"
	default:
		return ""
	}
}

func (f initFlavor) GetTemplate() *template.Template {
	var templ string
	switch f {
	case initSystemd:
		templ = systemdScript
	case initSystemV:
		templ = systemVScript
	case initUpstart:
		templ = upstartScript
	}
	return template.Must(template.New(f.String() + "Script").Parse(templ))
}

func (s *linuxService) Install() error {
	confPath := s.flavor.ConfigPath(s.name)
	_, err := os.Stat(confPath)
	if err == nil {
		return fmt.Errorf("Init already exists: %s", confPath)
	}

	f, err := os.Create(confPath)
	if err != nil {
		return err
	}
	defer f.Close()

	path, err := osext.Executable()
	if err != nil {
		return err
	}

	var to = &struct {
		Display     string
		Description string
		Path        string
	}{
		s.displayName,
		s.description,
		path,
	}

	err = s.flavor.GetTemplate().Execute(f, to)
	if err != nil {
		return err
	}

	if s.flavor == initSystemV {
		if err = os.Chmod(confPath, 0755); err != nil {
			return err
		}
		for _, i := range [...]string{"2", "3", "4", "5"} {
			if err = os.Symlink(confPath, "/etc/rc"+i+".d/S50"+s.name); err != nil {
				continue
			}
		}
		for _, i := range [...]string{"0", "1", "6"} {
			if err = os.Symlink(confPath, "/etc/rc"+i+".d/K02"+s.name); err != nil {
				continue
			}
		}
	}

	if s.flavor == initSystemd {
		err = exec.Command("systemctl", "enable", s.name+".service").Run()
		if err != nil {
			return err
		}
		return exec.Command("systemctl", "daemon-reload").Run()
	}

	return nil
}

func (s *linuxService) Remove() error {
	if s.flavor == initSystemd {
		exec.Command("systemctl", "disable", s.name+".service").Run()
	}
	if err := os.Remove(s.flavor.ConfigPath(s.name)); err != nil {
		return err
	}
	return nil
}

func (s *linuxService) Run(onStart, onStop func() error) (err error) {
	err = onStart()
	if err != nil {
		return err
	}
	defer func() {
		err = onStop()
	}()

	sigChan := make(chan os.Signal, 3)

	signal.Notify(sigChan, os.Interrupt, os.Kill)

	<-sigChan

	return nil
}

func (s *linuxService) Start() error {
	switch s.flavor {
	case initSystemd:
		return exec.Command("systemctl", "start", s.name+".service").Run()
	case initUpstart:
		return exec.Command("initctl", "start", s.name).Run()
	default:
		return exec.Command("service", s.name, "start").Run()
	}
}

func (s *linuxService) Stop() error {
	switch s.flavor {
	case initSystemd:
		return exec.Command("systemctl", "stop", s.name+".service").Start()
	case initUpstart:
		return exec.Command("initctl", "stop", s.name).Start()
	default:
		return exec.Command("service", s.name, "stop").Start()
	}
}

func (s *linuxService) IntervalMode(interval int) error {
	return fmt.Errorf("interval mode service only supported on darwin")
}

func (s *linuxService) Error(format string, a ...interface{}) error {
	return s.logger.Err(fmt.Sprintf(format, a...))
}
func (s *linuxService) Warning(format string, a ...interface{}) error {
	return s.logger.Warning(fmt.Sprintf(format, a...))
}
func (s *linuxService) Info(format string, a ...interface{}) error {
	return s.logger.Info(fmt.Sprintf(format, a...))
}

const systemVScript = `#!/bin/sh
# For RedHat and cousins:
# chkconfig: - 99 01
# description: {{.Description}}
# processname: {{.Path}}

### BEGIN INIT INFO
# Provides:          {{.Path}}
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: {{.Display}}
# Description:       {{.Description}}
### END INIT INFO

cmd="{{.Path}}"

name=$(basename $0)
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err"

get_pid() {
    cat "$pid_file"
}

is_running() {
    [ -f "$pid_file" ] && ps $(get_pid) > /dev/null 2>&1
}

case "$1" in
    start)
        if is_running; then
            echo "Already started"
        else
            echo "Starting $name"
            $cmd >> "$stdout_log" 2>> "$stderr_log" &
            echo $! > "$pid_file"
            if ! is_running; then
                echo "Unable to start, see $stdout_log and $stderr_log"
                exit 1
            fi
        fi
    ;;
    stop)
        if is_running; then
            echo -n "Stopping $name.."
            kill $(get_pid)
            for i in {1..10}
            do
                if ! is_running; then
                    break
                fi
                echo -n "."
                sleep 1
            done
            echo
            if is_running; then
                echo "Not stopped; may still be shutting down or shutdown may have failed"
                exit 1
            else
                echo "Stopped"
                if [ -f "$pid_file" ]; then
                    rm "$pid_file"
                fi
            fi
        else
            echo "Not running"
        fi
    ;;
    restart)
        $0 stop
        if is_running; then
            echo "Unable to stop, will not attempt to start"
            exit 1
        fi
        $0 start
    ;;
    status)
        if is_running; then
            echo "Running"
        else
            echo "Stopped"
            exit 1
        fi
    ;;
    *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac
exit 0`

const upstartScript = `# {{.Description}}

description     "{{.Display}}"

start on filesystem or runlevel [2345]
stop on runlevel [!2345]

#setuid username

# stop the respawn is process fails to start 5 times within 5 minutes
respawn
respawn limit 5 300
umask 022

console none

pre-start script
    test -x {{.Path}} || { stop; exit 0; }
end script

# Start
exec {{.Path}}
`

const systemdScript = `[Unit]
Description={{.Description}}
ConditionFileIsExecutable={{.Path}}
After=network.target

[Service]
ExecStart={{.Path}}
# respawn process on crash after a 3s wait
# if fails to start 5 times within 5 minutes, stop trying
Restart=on-failure
RestartSec=3s
StartLimitInterval=300
StartLimitBurst=5

[Install]
WantedBy=multi-user.target
`
<|endoftext|>


<commit_before>package headlessChrome

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/integrii/interactive"
)

// Debug enables debug output for this package to console
var Debug bool

// ChromePath is the command to execute chrome
var ChromePath = `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`

// Args are the args that will be used to start chrome
var Args = []string{
	"--headless",
	"--disable-gpu",
	"--repl",
	// "--dump-dom",
	// "--window-size=1024,768",
	// "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
	// "--verbose",
}

const expectedFirstLine = `Type a Javascript expression to evaluate or "quit" to exit.`
const promptPrefix = `>>>`

// OutputSanitizer puts output coming from the consolw that
// does not begin with the input prompt into the session
// output channel
func (cs *ChromeSession) OutputSanitizer() {
	for text := range cs.Session.Output {
		if !strings.HasPrefix(text, promptPrefix) {
			cs.Output <- text
		}
	}
}

// ChromeSession is an interactive console Session with a Chrome
// instance.
type ChromeSession struct {
	Session *interactive.Session
	Output  chan string
	Input   chan string
}

// Exit exits the running command out by ossuing a 'quit'
// to the chrome console
func (cs *ChromeSession) Exit() {
	cs.Session.Write(`quit`)
	cs.Session.Exit()
}

// Write writes to the Session
func (cs *ChromeSession) Write(s string) {
	if Debug {
		fmt.Println("Writing to console:")
		fmt.Println(s)
	}
	cs.Session.Write(s)
}

// OutputPrinter prints all outputs from the output channel to the cli
func (cs *ChromeSession) OutputPrinter() {
	for l := range cs.Session.Output {
		fmt.Println(l)
	}
}

// forceClose issues a force kill to the command
func (cs *ChromeSession) forceClose() {
	cs.Session.ForceClose()
}

// ClickSelector calls a click() on the supplied selector
func (cs *ChromeSession) ClickSelector(s string) {
	cs.Write(`document.querySelector("` + s + `").click()`)
}

// ClickItemWithInnerHTML clicks an item that has the matching inner html
func (cs *ChromeSession) ClickItemWithInnerHTML(elementType string, s string, itemIndex int) {
	cs.Write(`var spans = $("` + elementType + `").filter(function(idx) { return this.innerHTML.indexOf("` + s + `") == 0; }); spans[` + strconv.Itoa(itemIndex) + `].click()`)
}

// GetContentOfItemWithClasses fetches the content of the element with the specified classes
func (cs *ChromeSession) GetContentOfItemWithClasses(classes string, itemIndex int) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].innerHTML`)
}

// GetContentOfItemWithSelector gets the content of an element with the specified selector
func (cs *ChromeSession) GetContentOfItemWithSelector(selector string) {
	cs.Write(`document.querySelector("` + selector + `").innerHTML()`)
}

// ClickItemWithClasses clicks on the first item it finds with the provided classes.
// Multiple classes are separated by spaces
func (cs *ChromeSession) ClickItemWithClasses(classes string, itemIndex int) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].click()`)
}

// SetTextByID sets the text on the div with the specified id
func (cs *ChromeSession) SetTextByID(id string, text string) {
	cs.Write(`document.getElementById("` + id + `").innerHTML = "` + text + `"`)
}

// ClickItemWithID clicks an item with the specified id
func (cs *ChromeSession) ClickItemWithID(id string) {
	cs.Write(`document.getElementById("` + id + `").click()`)
}

// SetTextByClasses sets the text on the div with the specified id
func (cs *ChromeSession) SetTextByClasses(classes string, itemIndex int, text string) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].innerHTML = "` + text + `"`)
}

// SetInputTextByClasses sets the input text for an input field
func (cs *ChromeSession) SetInputTextByClasses(classes string, itemIndex int, text string) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].value = "` + text + `"`)
}

// NewBrowser starts a new chrome headless Session.
func NewBrowser(url string) (*ChromeSession, error) {
	var err error

	chromeSession := ChromeSession{}
	chromeSession.Output = make(chan string, 5000)

	// add url as last arg and create new Session
	args := append(Args, url)
	chromeSession.Session, err = interactive.NewSession(ChromePath, args)

	// map output and input channels for easy use
	chromeSession.Input = chromeSession.Session.Input

	go chromeSession.OutputSanitizer()

	firstLine := <-chromeSession.Output
	if !strings.Contains(firstLine, expectedFirstLine) {
		log.Println("ERROR: Unespected first line when initializing headless Chrome console:", firstLine)
	}

	return &chromeSession, err
}
<commit_msg>get an element based on its inner html<commit_after>package headlessChrome

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/integrii/interactive"
)

// Debug enables debug output for this package to console
var Debug bool

// ChromePath is the command to execute chrome
var ChromePath = `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`

// Args are the args that will be used to start chrome
var Args = []string{
	"--headless",
	"--disable-gpu",
	"--repl",
	// "--dump-dom",
	// "--window-size=1024,768",
	// "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
	// "--verbose",
}

const expectedFirstLine = `Type a Javascript expression to evaluate or "quit" to exit.`
const promptPrefix = `>>>`

// OutputSanitizer puts output coming from the consolw that
// does not begin with the input prompt into the session
// output channel
func (cs *ChromeSession) OutputSanitizer() {
	for text := range cs.Session.Output {
		if !strings.HasPrefix(text, promptPrefix) {
			cs.Output <- text
		}
	}
}

// ChromeSession is an interactive console Session with a Chrome
// instance.
type ChromeSession struct {
	Session *interactive.Session
	Output  chan string
	Input   chan string
}

// Exit exits the running command out by ossuing a 'quit'
// to the chrome console
func (cs *ChromeSession) Exit() {
	cs.Session.Write(`quit`)
	cs.Session.Exit()
}

// Write writes to the Session
func (cs *ChromeSession) Write(s string) {
	if Debug {
		fmt.Println("Writing to console:")
		fmt.Println(s)
	}
	cs.Session.Write(s)
}

// OutputPrinter prints all outputs from the output channel to the cli
func (cs *ChromeSession) OutputPrinter() {
	for l := range cs.Session.Output {
		fmt.Println(l)
	}
}

// forceClose issues a force kill to the command
func (cs *ChromeSession) forceClose() {
	cs.Session.ForceClose()
}

// ClickSelector calls a click() on the supplied selector
func (cs *ChromeSession) ClickSelector(s string) {
	cs.Write(`document.querySelector("` + s + `").click()`)
}

// ClickItemWithInnerHTML clicks an item that has the matching inner html
func (cs *ChromeSession) ClickItemWithInnerHTML(elementType string, s string, itemIndex int) {
	cs.Write(`var spans = $("` + elementType + `").filter(function(idx) { return this.innerHTML.indexOf("` + s + `") == 0; }); spans[` + strconv.Itoa(itemIndex) + `].click()`)
}

// GetItemWithInnerHTML fetches the item with the specified innerHTML content
func (cs *ChromeSession) GetItemWithInnerHTML(elementType string, s string, itemIndex int) {
	cs.Write(`var items = $("` + elementType + `").filter(function(idx) { return this.innerHTML.indexOf("` + s + `") == 0; }); items[` + strconv.Itoa(itemIndex) + `]`)
}

// GetContentOfItemWithClasses fetches the content of the element with the specified classes
func (cs *ChromeSession) GetContentOfItemWithClasses(classes string, itemIndex int) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].innerHTML`)
}

// GetContentOfItemWithSelector gets the content of an element with the specified selector
func (cs *ChromeSession) GetContentOfItemWithSelector(selector string) {
	cs.Write(`document.querySelector("` + selector + `").innerHTML()`)
}

// ClickItemWithClasses clicks on the first item it finds with the provided classes.
// Multiple classes are separated by spaces
func (cs *ChromeSession) ClickItemWithClasses(classes string, itemIndex int) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].click()`)
}

// SetTextByID sets the text on the div with the specified id
func (cs *ChromeSession) SetTextByID(id string, text string) {
	cs.Write(`document.getElementById("` + id + `").innerHTML = "` + text + `"`)
}

// ClickItemWithID clicks an item with the specified id
func (cs *ChromeSession) ClickItemWithID(id string) {
	cs.Write(`document.getElementById("` + id + `").click()`)
}

// SetTextByClasses sets the text on the div with the specified id
func (cs *ChromeSession) SetTextByClasses(classes string, itemIndex int, text string) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].innerHTML = "` + text + `"`)
}

// SetInputTextByClasses sets the input text for an input field
func (cs *ChromeSession) SetInputTextByClasses(classes string, itemIndex int, text string) {
	cs.Write(`var x = document.getElementsByClassName("` + classes + `");x[` + strconv.Itoa(itemIndex) + `].value = "` + text + `"`)
}

// NewBrowser starts a new chrome headless Session.
func NewBrowser(url string) (*ChromeSession, error) {
	var err error

	chromeSession := ChromeSession{}
	chromeSession.Output = make(chan string, 5000)

	// add url as last arg and create new Session
	args := append(Args, url)
	chromeSession.Session, err = interactive.NewSession(ChromePath, args)

	// map output and input channels for easy use
	chromeSession.Input = chromeSession.Session.Input

	go chromeSession.OutputSanitizer()

	firstLine := <-chromeSession.Output
	if !strings.Contains(firstLine, expectedFirstLine) {
		log.Println("ERROR: Unespected first line when initializing headless Chrome console:", firstLine)
	}

	return &chromeSession, err
}
<|endoftext|>


<commit_before>package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"

import (
	"context"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/services/server/config"
	"github.com/containerd/containerd/sys"
	"github.com/docker/docker/pkg/system"
	"github.com/pelletier/go-toml"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	maxConnectionRetryCount = 3
	healthCheckTimeout      = 3 * time.Second
	shutdownTimeout         = 15 * time.Second
	startupTimeout          = 15 * time.Second
	configFile              = "containerd.toml"
	binaryName              = "containerd"
	pidFile                 = "containerd.pid"
)

type remote struct {
	config.Config

	daemonPid int
	pidFile   string
	logger    *logrus.Entry

	daemonWaitCh  chan struct{}
	daemonStartCh chan error
	daemonStopCh  chan struct{}

	stateDir string

	// oomScore adjusts the OOM score for the containerd process.
	oomScore int
}

// Daemon represents a running containerd daemon
type Daemon interface {
	WaitTimeout(time.Duration) error
	Address() string
}

// DaemonOpt allows to configure parameters of container daemons
type DaemonOpt func(c *remote) error

// Start starts a containerd daemon and monitors it
func Start(ctx context.Context, rootDir, stateDir string, opts ...DaemonOpt) (Daemon, error) {
	r := &remote{
		stateDir: stateDir,
		Config: config.Config{
			Version: 2,
			Root:    filepath.Join(rootDir, "daemon"),
			State:   filepath.Join(stateDir, "daemon"),
		},
		daemonPid:     -1,
		pidFile:       filepath.Join(stateDir, pidFile),
		logger:        logrus.WithField("module", "libcontainerd"),
		daemonStartCh: make(chan error, 1),
		daemonStopCh:  make(chan struct{}),
	}

	for _, opt := range opts {
		if err := opt(r); err != nil {
			return nil, err
		}
	}
	r.setDefaults()

	if err := system.MkdirAll(stateDir, 0700); err != nil {
		return nil, err
	}

	go r.monitorDaemon(ctx)

	timeout := time.NewTimer(startupTimeout)
	defer timeout.Stop()

	select {
	case <-timeout.C:
		return nil, errors.New("timeout waiting for containerd to start")
	case err := <-r.daemonStartCh:
		if err != nil {
			return nil, err
		}
	}

	return r, nil
}
func (r *remote) WaitTimeout(d time.Duration) error {
	timeout := time.NewTimer(d)
	defer timeout.Stop()

	select {
	case <-timeout.C:
		return errors.New("timeout waiting for containerd to stop")
	case <-r.daemonStopCh:
	}

	return nil
}

func (r *remote) Address() string {
	return r.GRPC.Address
}
func (r *remote) getContainerdPid() (int, error) {
	f, err := os.OpenFile(r.pidFile, os.O_RDWR, 0600)
	if err != nil {
		if os.IsNotExist(err) {
			return -1, nil
		}
		return -1, err
	}
	defer f.Close()

	b := make([]byte, 8)
	n, err := f.Read(b)
	if err != nil && err != io.EOF {
		return -1, err
	}

	if n > 0 {
		pid, err := strconv.ParseUint(string(b[:n]), 10, 64)
		if err != nil {
			return -1, err
		}
		if system.IsProcessAlive(int(pid)) {
			return int(pid), nil
		}
	}

	return -1, nil
}

func (r *remote) getContainerdConfig() (string, error) {
	path := filepath.Join(r.stateDir, configFile)
	f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	if err != nil {
		return "", errors.Wrapf(err, "failed to open containerd config file at %s", path)
	}
	defer f.Close()

	if err := toml.NewEncoder(f).Encode(r); err != nil {
		return "", errors.Wrapf(err, "failed to write containerd config file (%s)", path)
	}
	return path, nil
}

func (r *remote) startContainerd() error {
	pid, err := r.getContainerdPid()
	if err != nil {
		return err
	}

	if pid != -1 {
		r.daemonPid = pid
		r.logger.WithField("pid", pid).Infof("%s is still running", binaryName)
		return nil
	}

	configFile, err := r.getContainerdConfig()
	if err != nil {
		return err
	}

	args := []string{"--config", configFile}

	if r.Debug.Level != "" {
		args = append(args, "--log-level", r.Debug.Level)
	}

	cmd := exec.Command(binaryName, args...)
	// redirect containerd logs to docker logs
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = containerdSysProcAttr()
	// clear the NOTIFY_SOCKET from the env when starting containerd
	cmd.Env = nil
	for _, e := range os.Environ() {
		if !strings.HasPrefix(e, "NOTIFY_SOCKET") {
			cmd.Env = append(cmd.Env, e)
		}
	}
	if err := cmd.Start(); err != nil {
		return err
	}

	r.daemonWaitCh = make(chan struct{})
	go func() {
		// Reap our child when needed
		if err := cmd.Wait(); err != nil {
			r.logger.WithError(err).Errorf("containerd did not exit successfully")
		}
		close(r.daemonWaitCh)
	}()

	r.daemonPid = cmd.Process.Pid

	if err := r.adjustOOMScore(); err != nil {
		r.logger.WithError(err).Warn("failed to adjust OOM score")
	}

	err = os.WriteFile(r.pidFile, []byte(strconv.Itoa(r.daemonPid)), 0660)
	if err != nil {
		system.KillProcess(r.daemonPid)
		return errors.Wrap(err, "libcontainerd: failed to save daemon pid to disk")
	}

	r.logger.WithField("pid", r.daemonPid).Infof("started new %s process", binaryName)

	return nil
}

func (r *remote) adjustOOMScore() error {
	if r.oomScore == 0 || r.daemonPid <= 1 {
		// no score configured, or daemonPid contains an invalid PID (we don't
		// expect containerd to be running as PID 1 :)).
		return nil
	}
	if err := sys.SetOOMScore(r.daemonPid, r.oomScore); err != nil {
		return errors.Wrap(err, "failed to adjust OOM score for containerd process")
	}
	return nil
}

func (r *remote) monitorDaemon(ctx context.Context) {
	var (
		transientFailureCount = 0
		client                *containerd.Client
		err                   error
		delay                 time.Duration
		timer                 = time.NewTimer(0)
		started               bool
	)

	defer func() {
		if r.daemonPid != -1 {
			r.stopDaemon()
		}

		// cleanup some files
		_ = os.Remove(r.pidFile)

		r.platformCleanup()

		close(r.daemonStopCh)
		timer.Stop()
	}()

	// ensure no races on sending to timer.C even though there is a 0 duration.
	if !timer.Stop() {
		<-timer.C
	}

	for {
		timer.Reset(delay)

		select {
		case <-ctx.Done():
			r.logger.Info("stopping healthcheck following graceful shutdown")
			if client != nil {
				client.Close()
			}
			return
		case <-timer.C:
		}

		if r.daemonPid == -1 {
			if r.daemonWaitCh != nil {
				select {
				case <-ctx.Done():
					r.logger.Info("stopping containerd startup following graceful shutdown")
					return
				case <-r.daemonWaitCh:
				}
			}

			os.RemoveAll(r.GRPC.Address)
			if err := r.startContainerd(); err != nil {
				if !started {
					r.daemonStartCh <- err
					return
				}
				r.logger.WithError(err).Error("failed restarting containerd")
				delay = 50 * time.Millisecond
				continue
			}

			client, err = containerd.New(r.GRPC.Address, containerd.WithTimeout(60*time.Second))
			if err != nil {
				r.logger.WithError(err).Error("failed connecting to containerd")
				delay = 100 * time.Millisecond
				continue
			}
			r.logger.WithField("address", r.GRPC.Address).Debug("created containerd monitoring client")
		}

		if client != nil {
			tctx, cancel := context.WithTimeout(ctx, healthCheckTimeout)
			_, err := client.IsServing(tctx)
			cancel()
			if err == nil {
				if !started {
					close(r.daemonStartCh)
					started = true
				}

				transientFailureCount = 0

				select {
				case <-r.daemonWaitCh:
				case <-ctx.Done():
				}

				// Set a small delay in case there is a recurring failure (or bug in this code)
				// to ensure we don't end up in a super tight loop.
				delay = 500 * time.Millisecond
				continue
			}

			r.logger.WithError(err).WithField("binary", binaryName).Debug("daemon is not responding")

			transientFailureCount++
			if transientFailureCount < maxConnectionRetryCount || system.IsProcessAlive(r.daemonPid) {
				delay = time.Duration(transientFailureCount) * 200 * time.Millisecond
				continue
			}
			client.Close()
			client = nil
		}

		if system.IsProcessAlive(r.daemonPid) {
			r.logger.WithField("pid", r.daemonPid).Info("killing and restarting containerd")
			r.killDaemon()
		}

		r.daemonPid = -1
		delay = 0
		transientFailureCount = 0
	}
}
<commit_msg>libcontainerd/supervisor: store location of config-file<commit_after>package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"

import (
	"context"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/services/server/config"
	"github.com/containerd/containerd/sys"
	"github.com/docker/docker/pkg/system"
	"github.com/pelletier/go-toml"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	maxConnectionRetryCount = 3
	healthCheckTimeout      = 3 * time.Second
	shutdownTimeout         = 15 * time.Second
	startupTimeout          = 15 * time.Second
	configFile              = "containerd.toml"
	binaryName              = "containerd"
	pidFile                 = "containerd.pid"
)

type remote struct {
	config.Config

	// configFile is the location where the generated containerd configuration
	// file is saved.
	configFile string

	daemonPid int
	pidFile   string
	logger    *logrus.Entry

	daemonWaitCh  chan struct{}
	daemonStartCh chan error
	daemonStopCh  chan struct{}

	stateDir string

	// oomScore adjusts the OOM score for the containerd process.
	oomScore int
}

// Daemon represents a running containerd daemon
type Daemon interface {
	WaitTimeout(time.Duration) error
	Address() string
}

// DaemonOpt allows to configure parameters of container daemons
type DaemonOpt func(c *remote) error

// Start starts a containerd daemon and monitors it
func Start(ctx context.Context, rootDir, stateDir string, opts ...DaemonOpt) (Daemon, error) {
	r := &remote{
		stateDir: stateDir,
		Config: config.Config{
			Version: 2,
			Root:    filepath.Join(rootDir, "daemon"),
			State:   filepath.Join(stateDir, "daemon"),
		},
		configFile:    filepath.Join(stateDir, configFile),
		daemonPid:     -1,
		pidFile:       filepath.Join(stateDir, pidFile),
		logger:        logrus.WithField("module", "libcontainerd"),
		daemonStartCh: make(chan error, 1),
		daemonStopCh:  make(chan struct{}),
	}

	for _, opt := range opts {
		if err := opt(r); err != nil {
			return nil, err
		}
	}
	r.setDefaults()

	if err := system.MkdirAll(stateDir, 0700); err != nil {
		return nil, err
	}

	go r.monitorDaemon(ctx)

	timeout := time.NewTimer(startupTimeout)
	defer timeout.Stop()

	select {
	case <-timeout.C:
		return nil, errors.New("timeout waiting for containerd to start")
	case err := <-r.daemonStartCh:
		if err != nil {
			return nil, err
		}
	}

	return r, nil
}
func (r *remote) WaitTimeout(d time.Duration) error {
	timeout := time.NewTimer(d)
	defer timeout.Stop()

	select {
	case <-timeout.C:
		return errors.New("timeout waiting for containerd to stop")
	case <-r.daemonStopCh:
	}

	return nil
}

func (r *remote) Address() string {
	return r.GRPC.Address
}
func (r *remote) getContainerdPid() (int, error) {
	f, err := os.OpenFile(r.pidFile, os.O_RDWR, 0600)
	if err != nil {
		if os.IsNotExist(err) {
			return -1, nil
		}
		return -1, err
	}
	defer f.Close()

	b := make([]byte, 8)
	n, err := f.Read(b)
	if err != nil && err != io.EOF {
		return -1, err
	}

	if n > 0 {
		pid, err := strconv.ParseUint(string(b[:n]), 10, 64)
		if err != nil {
			return -1, err
		}
		if system.IsProcessAlive(int(pid)) {
			return int(pid), nil
		}
	}

	return -1, nil
}

func (r *remote) getContainerdConfig() (string, error) {
	f, err := os.OpenFile(r.configFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	if err != nil {
		return "", errors.Wrapf(err, "failed to open containerd config file (%s)", r.configFile)
	}
	defer f.Close()

	if err := toml.NewEncoder(f).Encode(r); err != nil {
		return "", errors.Wrapf(err, "failed to write containerd config file (%s)", r.configFile)
	}
	return r.configFile, nil
}

func (r *remote) startContainerd() error {
	pid, err := r.getContainerdPid()
	if err != nil {
		return err
	}

	if pid != -1 {
		r.daemonPid = pid
		r.logger.WithField("pid", pid).Infof("%s is still running", binaryName)
		return nil
	}

	configFile, err := r.getContainerdConfig()
	if err != nil {
		return err
	}

	args := []string{"--config", configFile}

	if r.Debug.Level != "" {
		args = append(args, "--log-level", r.Debug.Level)
	}

	cmd := exec.Command(binaryName, args...)
	// redirect containerd logs to docker logs
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = containerdSysProcAttr()
	// clear the NOTIFY_SOCKET from the env when starting containerd
	cmd.Env = nil
	for _, e := range os.Environ() {
		if !strings.HasPrefix(e, "NOTIFY_SOCKET") {
			cmd.Env = append(cmd.Env, e)
		}
	}
	if err := cmd.Start(); err != nil {
		return err
	}

	r.daemonWaitCh = make(chan struct{})
	go func() {
		// Reap our child when needed
		if err := cmd.Wait(); err != nil {
			r.logger.WithError(err).Errorf("containerd did not exit successfully")
		}
		close(r.daemonWaitCh)
	}()

	r.daemonPid = cmd.Process.Pid

	if err := r.adjustOOMScore(); err != nil {
		r.logger.WithError(err).Warn("failed to adjust OOM score")
	}

	err = os.WriteFile(r.pidFile, []byte(strconv.Itoa(r.daemonPid)), 0660)
	if err != nil {
		system.KillProcess(r.daemonPid)
		return errors.Wrap(err, "libcontainerd: failed to save daemon pid to disk")
	}

	r.logger.WithField("pid", r.daemonPid).Infof("started new %s process", binaryName)

	return nil
}

func (r *remote) adjustOOMScore() error {
	if r.oomScore == 0 || r.daemonPid <= 1 {
		// no score configured, or daemonPid contains an invalid PID (we don't
		// expect containerd to be running as PID 1 :)).
		return nil
	}
	if err := sys.SetOOMScore(r.daemonPid, r.oomScore); err != nil {
		return errors.Wrap(err, "failed to adjust OOM score for containerd process")
	}
	return nil
}

func (r *remote) monitorDaemon(ctx context.Context) {
	var (
		transientFailureCount = 0
		client                *containerd.Client
		err                   error
		delay                 time.Duration
		timer                 = time.NewTimer(0)
		started               bool
	)

	defer func() {
		if r.daemonPid != -1 {
			r.stopDaemon()
		}

		// cleanup some files
		_ = os.Remove(r.pidFile)

		r.platformCleanup()

		close(r.daemonStopCh)
		timer.Stop()
	}()

	// ensure no races on sending to timer.C even though there is a 0 duration.
	if !timer.Stop() {
		<-timer.C
	}

	for {
		timer.Reset(delay)

		select {
		case <-ctx.Done():
			r.logger.Info("stopping healthcheck following graceful shutdown")
			if client != nil {
				client.Close()
			}
			return
		case <-timer.C:
		}

		if r.daemonPid == -1 {
			if r.daemonWaitCh != nil {
				select {
				case <-ctx.Done():
					r.logger.Info("stopping containerd startup following graceful shutdown")
					return
				case <-r.daemonWaitCh:
				}
			}

			os.RemoveAll(r.GRPC.Address)
			if err := r.startContainerd(); err != nil {
				if !started {
					r.daemonStartCh <- err
					return
				}
				r.logger.WithError(err).Error("failed restarting containerd")
				delay = 50 * time.Millisecond
				continue
			}

			client, err = containerd.New(r.GRPC.Address, containerd.WithTimeout(60*time.Second))
			if err != nil {
				r.logger.WithError(err).Error("failed connecting to containerd")
				delay = 100 * time.Millisecond
				continue
			}
			r.logger.WithField("address", r.GRPC.Address).Debug("created containerd monitoring client")
		}

		if client != nil {
			tctx, cancel := context.WithTimeout(ctx, healthCheckTimeout)
			_, err := client.IsServing(tctx)
			cancel()
			if err == nil {
				if !started {
					close(r.daemonStartCh)
					started = true
				}

				transientFailureCount = 0

				select {
				case <-r.daemonWaitCh:
				case <-ctx.Done():
				}

				// Set a small delay in case there is a recurring failure (or bug in this code)
				// to ensure we don't end up in a super tight loop.
				delay = 500 * time.Millisecond
				continue
			}

			r.logger.WithError(err).WithField("binary", binaryName).Debug("daemon is not responding")

			transientFailureCount++
			if transientFailureCount < maxConnectionRetryCount || system.IsProcessAlive(r.daemonPid) {
				delay = time.Duration(transientFailureCount) * 200 * time.Millisecond
				continue
			}
			client.Close()
			client = nil
		}

		if system.IsProcessAlive(r.daemonPid) {
			r.logger.WithField("pid", r.daemonPid).Info("killing and restarting containerd")
			r.killDaemon()
		}

		r.daemonPid = -1
		delay = 0
		transientFailureCount = 0
	}
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package player

// create new player and return assigned ID or an error
func (p *PlayerController) CreateNewPlayer(name string, aliases []string) (uint, error) {
	return 0, nil
}
<commit_msg>controllers/player: create player (does not claim aliases)<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package player

import (
	"github.com/bboozzoo/q3stats/models"
	"github.com/pkg/errors"
)

// create new player and return assigned ID or an error
func (p *PlayerController) CreateNewPlayer(name string, aliases []string) (uint, error) {

	if models.HasPlayer(p.db, name) == true {
		return 0, errors.New("player already present")
	}

	id := models.NewPlayer(p.db, name, "")

	// claim aliases

	return id, nil
}
<|endoftext|>


<commit_before>package video

import (
	"fmt"

	"bitbucket.org/ikeikeikeike/antenna/ormapper"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/blog"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/diva"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/entry"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/video"
	"github.com/astaxie/beego/utils/pagination"
	"github.com/ikeikeikeike/gopkg/convert"
	// "github.com/k0kubun/pp"
)

type EntriesController struct {
	BaseController
}

// func (c *EntriesController) NestPrepare() {}

func (c *EntriesController) NestFinish() {
	c.PushInAccessLog()
}

func (c *EntriesController) Home() {
	c.TplNames = "video/entries/home.tpl"

	var summaries []*ormapper.Summary
	ormapper.VideoSummaries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo).
		Limit(c.DefaultPers).
		Order("summary.sort ASC").
		Find(&summaries)
	for _, s := range summaries {
		s.NewsLoader()
	}
	c.Data["Summaries"] = summaries

	var entries []*ormapper.Entry
	ormapper.VideoEntries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo).
		Limit(c.DefaultPers).
		Order("entry.id DESC").
		Find(&entries)
	for _, e := range entries {
		e.NewsLoader()
	}
	c.Data["Entries"] = entries

	var divas []*ormapper.Diva
	ormapper.VideoGoddess().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(diva.VideoCountMoreThanZero).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(diva.FilterNameKana(convert.StrTo(c.GetString("q")).MultiWord())).
		Limit(4).
		Order("diva.videos_count DESC").
		Find(&divas)
	c.Data["Divas"] = divas

	var animes []*ormapper.Anime
	c.Data["Animes"] = animes
}

func (c *EntriesController) News() {
	c.TplNames = "video/entries/news.tpl"

	db := ormapper.VideoEntries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo)

	var count int64
	db.Count(&count)

	pager := pagination.SetPaginator(c.Ctx, c.DefaultPers, count)
	db = db.Limit(c.DefaultPers).Offset(pager.Offset())

	var entries []*ormapper.Entry
	db.Order("entry.id DESC").Find(&entries)

	for _, e := range entries {
		e.NewsLoader()
	}

	c.Data["QURL"] = ""
	c.Data["Entries"] = entries
}

func (c *EntriesController) Hots() {
	c.TplNames = "video/entries/hots.tpl"

	db := ormapper.VideoSummaries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo)

	var count int64
	db.Count(&count)

	pager := pagination.SetPaginator(c.Ctx, c.DefaultPers, count)
	db = db.Limit(c.DefaultPers).Offset(pager.Offset())

	var summaries []*ormapper.Summary
	db.Order("summary.sort ASC").Find(&summaries)

	for _, s := range summaries {
		s.NewsLoader()
	}

	c.Data["QURL"] = ""
	c.Data["Summaries"] = summaries
}

func (c *EntriesController) Show() {
	c.TplNames = "video/entries/show.tpl"

	id := c.Ctx.Input.Param(":id")
	if id == "" {
		c.Ctx.Abort(404, "404")
		return
	}

	uid, _ := convert.StrTo(id).Int64()

	m := &ormapper.Entry{Id: uid}
	ormapper.DB.
		Preload("Picture").Preload("Video").Preload("Blog").
		First(m)

	if !m.IsLiving() || m.Blog.Mediatype != "movie" || m.HasBan()  {
		c.Ctx.Abort(404, "404")
		return
	}

	m.VideoShowLoader()

	var (
		divas      []*ormapper.Diva
		animes     []*ormapper.Anime
		summaries  []*ormapper.Summary
		characters []*ormapper.Character
	)

	if m.Video != nil {
		divas = m.Video.Divas
	}
	if m.Picture != nil {
		characters = m.Picture.Characters
		if m.Picture.Anime != nil {
			animes = []*ormapper.Anime{m.Picture.Anime}
		}
	}

	var in []string
	for _, t := range m.Tags {
		if t.Name != "" {
			in = append(in, t.Name)
		}
	}
	if len(in) <= 0 {
		in = append(in, "ギャル")
	}
	ormapper.VideoShowSummaries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(video.HasVideo).
		Where("entry.id != ?", m.Id).
		Where("tag.name IN (?) OR entry.q like ?", in, fmt.Sprintf("%%%s%%", in[0])).
		Group("summary.id").
		Order("summary.sort ASC").
		Limit(15).
		Find(&summaries)
	for _, s := range summaries {
		s.ShowLoader()
	}

	c.Data["PrevEntry"], _ = m.PreviousByBlog()
	c.Data["NextEntry"], _ = m.NextByBlog()

	c.Data["Entry"] = m
	c.Data["Divas"] = divas
	c.Data["Animes"] = animes
	c.Data["Summaries"] = summaries
	c.Data["Characters"] = characters
}

func (c *EntriesController) Search() {
	c.TplNames = "public/entries/search.tpl"
}
<commit_msg>rankings video<commit_after>package video

import (
	"fmt"

	"bitbucket.org/ikeikeikeike/antenna/ormapper"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/blog"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/diva"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/entry"
	"bitbucket.org/ikeikeikeike/antenna/ormapper/video"
	"github.com/astaxie/beego/utils/pagination"
	"github.com/ikeikeikeike/gopkg/convert"
	// "github.com/k0kubun/pp"
)

type EntriesController struct {
	BaseController
}

// func (c *EntriesController) NestPrepare() {}

func (c *EntriesController) NestFinish() {
	c.PushInAccessLog()
}

func (c *EntriesController) Home() {
	c.TplNames = "video/entries/home.tpl"

	var summaries []*ormapper.Summary
	ormapper.VideoSummaries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo).
		Limit(c.DefaultPers).
		Order("summary.sort ASC").
		Find(&summaries)
	for _, s := range summaries {
		s.NewsLoader()
	}
	c.Data["Summaries"] = summaries

	var entries []*ormapper.Entry
	ormapper.VideoEntries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo).
		Limit(c.DefaultPers).
		Order("entry.id DESC").
		Find(&entries)
	for _, e := range entries {
		e.NewsLoader()
	}
	c.Data["Entries"] = entries

	var divas []*ormapper.Diva
	ormapper.VideoGoddess().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(diva.VideoCountMoreThanZero).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(diva.FilterNameKana(convert.StrTo(c.GetString("q")).MultiWord())).
		Limit(4).
		Order("diva.videos_count DESC").
		Find(&divas)
	c.Data["Divas"] = divas

	var animes []*ormapper.Anime
	c.Data["Animes"] = animes

	var rankings []*ormapper.VideoRanking
	ormapper.VideoRankings().
		Where("video_ranking.rank > ?", 0).
		Where("video_ranking.begin_name = ?", "dayly").
		Where("video_ranking.begin_time = ?", c.GetParamatedNow().BeginningOfDay()).
		Limit(3).
		Order("video_ranking.rank ASC").
		Find(&rankings)
	for _, s := range rankings {
		s.RankingsLoader()
	}
	c.Data["Rankings"] = rankings
}

func (c *EntriesController) News() {
	c.TplNames = "video/entries/news.tpl"

	db := ormapper.VideoEntries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo)

	var count int64
	db.Count(&count)

	pager := pagination.SetPaginator(c.Ctx, c.DefaultPers, count)
	db = db.Limit(c.DefaultPers).Offset(pager.Offset())

	var entries []*ormapper.Entry
	db.Order("entry.id DESC").Find(&entries)

	for _, e := range entries {
		e.NewsLoader()
	}

	c.Data["QURL"] = ""
	c.Data["Entries"] = entries
}

func (c *EntriesController) Hots() {
	c.TplNames = "video/entries/hots.tpl"

	db := ormapper.VideoSummaries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(blog.FilterAdsensetype(c.GetString("at"))).
		Scopes(diva.FilterBlood(c.GetString("blood"))).
		Scopes(diva.FilterBracup(c.GetStrings("cup"))).
		Scopes(diva.FilterPrefixLines(c.GetString("line"))).
		Scopes(entry.FilterQ(convert.StrTo(c.GetString("q")).MultiWord())).
		Scopes(video.HasVideo)

	var count int64
	db.Count(&count)

	pager := pagination.SetPaginator(c.Ctx, c.DefaultPers, count)
	db = db.Limit(c.DefaultPers).Offset(pager.Offset())

	var summaries []*ormapper.Summary
	db.Order("summary.sort ASC").Find(&summaries)

	for _, s := range summaries {
		s.NewsLoader()
	}

	c.Data["QURL"] = ""
	c.Data["Summaries"] = summaries
}

func (c *EntriesController) Show() {
	c.TplNames = "video/entries/show.tpl"

	id := c.Ctx.Input.Param(":id")
	if id == "" {
		c.Ctx.Abort(404, "404")
		return
	}

	uid, _ := convert.StrTo(id).Int64()

	m := &ormapper.Entry{Id: uid}
	ormapper.DB.
		Preload("Picture").Preload("Video").Preload("Blog").
		First(m)

	if !m.IsLiving() || m.Blog.Mediatype != "movie" || m.HasBan() {
		c.Ctx.Abort(404, "404")
		return
	}

	m.VideoShowLoader()

	var (
		divas      []*ormapper.Diva
		animes     []*ormapper.Anime
		summaries  []*ormapper.Summary
		characters []*ormapper.Character
	)

	if m.Video != nil {
		divas = m.Video.Divas
	}
	if m.Picture != nil {
		characters = m.Picture.Characters
		if m.Picture.Anime != nil {
			animes = []*ormapper.Anime{m.Picture.Anime}
		}
	}

	var in []string
	for _, t := range m.Tags {
		if t.Name != "" {
			in = append(in, t.Name)
		}
	}
	if len(in) <= 0 {
		in = append(in, "ギャル")
	}
	ormapper.VideoShowSummaries().
		Scopes(blog.FilterMediatype("movie")).
		Scopes(video.HasVideo).
		Where("entry.id != ?", m.Id).
		Where("tag.name IN (?) OR entry.q like ?", in, fmt.Sprintf("%%%s%%", in[0])).
		Group("summary.id").
		Order("summary.sort ASC").
		Limit(15).
		Find(&summaries)
	for _, s := range summaries {
		s.ShowLoader()
	}

	c.Data["PrevEntry"], _ = m.PreviousByBlog()
	c.Data["NextEntry"], _ = m.NextByBlog()

	c.Data["Entry"] = m
	c.Data["Divas"] = divas
	c.Data["Animes"] = animes
	c.Data["Summaries"] = summaries
	c.Data["Characters"] = characters
}

func (c *EntriesController) Search() {
	c.TplNames = "public/entries/search.tpl"
}
<|endoftext|>


<commit_before>package cli

import (
	"os"
	"os/signal"
	"sync"
	"syscall"
)

type LifecycleData struct {
	lock sync.Mutex

	ranShutdown bool
	onShutdown  []func()
}

var Lifecycle = &LifecycleData{}

func (l *LifecycleData) OnShutdown(handle func()) {
	l.lock.Lock()
	defer l.lock.Unlock()

	l.onShutdown = append(l.onShutdown, handle)
}

func (l *LifecycleData) Shutdown(code int) {
	l.RunCleanup()
	os.Exit(code)
}

func (l *LifecycleData) RunCleanup() {
	l.lock.Lock()
	defer l.lock.Unlock()

	if l.ranShutdown {
		return
	}

	l.ranShutdown = true

	for _, h := range l.onShutdown {
		h()
	}
}

func (l *LifecycleData) Start() {
	c := make(chan os.Signal)

	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)

	go l.watchTheThrone(c)
}

func (l *LifecycleData) watchTheThrone(c chan os.Signal) {
	<-c

	l.Shutdown(0)
}
<commit_msg>Add env var to control profiling<commit_after>package cli

import (
	"log"
	"os"
	"os/signal"
	"runtime/pprof"
	"sync"
	"syscall"
)

type LifecycleData struct {
	lock sync.Mutex

	ranShutdown bool
	onShutdown  []func()
}

var Lifecycle = &LifecycleData{}

func (l *LifecycleData) OnShutdown(handle func()) {
	l.lock.Lock()
	defer l.lock.Unlock()

	l.onShutdown = append(l.onShutdown, handle)
}

func (l *LifecycleData) Shutdown(code int) {
	l.RunCleanup()
	os.Exit(code)
}

func (l *LifecycleData) RunCleanup() {
	l.lock.Lock()
	defer l.lock.Unlock()

	if l.ranShutdown {
		return
	}

	pprof.StopCPUProfile()

	l.ranShutdown = true

	for _, h := range l.onShutdown {
		h()
	}
}

func (l *LifecycleData) Start() {
	path := os.Getenv("PROFILE")
	if path != "" {
		f, err := os.Create(path)
		if err != nil {
			log.Fatal(err)
		}

		pprof.StartCPUProfile(f)
	}

	c := make(chan os.Signal)

	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)

	go l.watchTheThrone(c)
}

func (l *LifecycleData) watchTheThrone(c chan os.Signal) {
	<-c

	l.Shutdown(0)
}
<|endoftext|>


<commit_before>package couchbase

import (
	"errors"
	"time"

	"github.com/dustin/gomemcached/client"
)

var TimeoutError = errors.New("timeout waiting to build connection")

type connectionPool struct {
	host        string
	mkConn      func(host string, ah AuthHandler) (*memcached.Client, error)
	auth        AuthHandler
	connections chan *memcached.Client
	createsem   chan bool
}

func newConnectionPool(host string, ah AuthHandler, poolSize int) *connectionPool {
	return &connectionPool{
		host:        host,
		connections: make(chan *memcached.Client, poolSize),
		createsem:   make(chan bool, 2*poolSize),
		mkConn:      defaultMkConn,
		auth:        ah,
	}
}

func defaultMkConn(host string, ah AuthHandler) (*memcached.Client, error) {
	conn, err := memcached.Connect("tcp", host)
	if err != nil {
		return nil, err
	}
	name, pass := ah.GetCredentials()
	if name != "default" {
		_, err = conn.Auth(name, pass)
		if err != nil {
			return nil, err
		}
	}
	return conn, nil
}

func (cp *connectionPool) Close() (err error) {
	defer func() { err, _ = recover().(error) }()
	close(cp.connections)
	for c := range cp.connections {
		c.Close()
	}
	return
}

func (cp *connectionPool) GetWithTimeout(d time.Duration) (*memcached.Client, error) {
	if cp == nil {
		return nil, errors.New("no pool")
	}

	select {
	case rv := <-cp.connections:
		return rv, nil
	case <-time.After(time.Millisecond):
		select {
		case rv := <-cp.connections:
			return rv, nil
		case cp.createsem <- true:
			// Build a connection if we can't get a real one.
			// This can potentially be an overflow connection, or
			// a pooled connection.
			rv, err := cp.mkConn(cp.host, cp.auth)
			if err != nil {
				// On error, release our create hold
				<-cp.createsem
			}
			return rv, err
		case <-time.After(d):
			return nil, TimeoutError
		}
	}
}

func (cp *connectionPool) Get() (*memcached.Client, error) {
	return cp.GetWithTimeout(time.Hour * 24 * 30)
}

func (cp *connectionPool) Return(c *memcached.Client) {
	if cp == nil || c == nil {
		return
	}

	if c.IsHealthy() {
		select {
		case cp.connections <- c:
		default:
			// Overflow connection.
			<-cp.createsem
			c.Close()
		}
	} else {
		<-cp.createsem
		c.Close()
	}
}

func (cp *connectionPool) StartTapFeed(args *memcached.TapArguments) (*memcached.TapFeed, error) {
	if cp == nil {
		return nil, errors.New("no pool")
	}
	mc, err := cp.Get()
	if err != nil {
		return nil, err
	}
	return mc.StartTapFeed(*args)
}
<commit_msg>Expose connection pool timeout<commit_after>package couchbase

import (
	"errors"
	"time"

	"github.com/dustin/gomemcached/client"
)

var TimeoutError = errors.New("timeout waiting to build connection")

var ConnPoolTimeout = time.Hour * 24 * 30

type connectionPool struct {
	host        string
	mkConn      func(host string, ah AuthHandler) (*memcached.Client, error)
	auth        AuthHandler
	connections chan *memcached.Client
	createsem   chan bool
}

func newConnectionPool(host string, ah AuthHandler, poolSize int) *connectionPool {
	return &connectionPool{
		host:        host,
		connections: make(chan *memcached.Client, poolSize),
		createsem:   make(chan bool, 2*poolSize),
		mkConn:      defaultMkConn,
		auth:        ah,
	}
}

func defaultMkConn(host string, ah AuthHandler) (*memcached.Client, error) {
	conn, err := memcached.Connect("tcp", host)
	if err != nil {
		return nil, err
	}
	name, pass := ah.GetCredentials()
	if name != "default" {
		_, err = conn.Auth(name, pass)
		if err != nil {
			return nil, err
		}
	}
	return conn, nil
}

func (cp *connectionPool) Close() (err error) {
	defer func() { err, _ = recover().(error) }()
	close(cp.connections)
	for c := range cp.connections {
		c.Close()
	}
	return
}

func (cp *connectionPool) GetWithTimeout(d time.Duration) (*memcached.Client, error) {
	if cp == nil {
		return nil, errors.New("no pool")
	}

	select {
	case rv := <-cp.connections:
		return rv, nil
	case <-time.After(time.Millisecond):
		select {
		case rv := <-cp.connections:
			return rv, nil
		case cp.createsem <- true:
			// Build a connection if we can't get a real one.
			// This can potentially be an overflow connection, or
			// a pooled connection.
			rv, err := cp.mkConn(cp.host, cp.auth)
			if err != nil {
				// On error, release our create hold
				<-cp.createsem
			}
			return rv, err
		case <-time.After(d):
			return nil, TimeoutError
		}
	}
}

func (cp *connectionPool) Get() (*memcached.Client, error) {
	return cp.GetWithTimeout(ConnPoolTimeout)
}

func (cp *connectionPool) Return(c *memcached.Client) {
	if cp == nil || c == nil {
		return
	}

	if c.IsHealthy() {
		select {
		case cp.connections <- c:
		default:
			// Overflow connection.
			<-cp.createsem
			c.Close()
		}
	} else {
		<-cp.createsem
		c.Close()
	}
}

func (cp *connectionPool) StartTapFeed(args *memcached.TapArguments) (*memcached.TapFeed, error) {
	if cp == nil {
		return nil, errors.New("no pool")
	}
	mc, err := cp.Get()
	if err != nil {
		return nil, err
	}
	return mc.StartTapFeed(*args)
}
<|endoftext|>


<commit_before>package couchbase

import (
	"errors"
	"time"

	"github.com/dustin/gomemcached/client"
)

var PoolFull = errors.New("connection pool is full")

type connectionPool struct {
	host, name  string
	mkConn      func(host, name string) (*memcached.Client, error)
	connections chan *memcached.Client
}

func newConnectionPool(host, name string, poolSize int) *connectionPool {
	return &connectionPool{
		host:        host,
		name:        name,
		connections: make(chan *memcached.Client, poolSize),
		mkConn:      defaultMkConn,
	}
}

func defaultMkConn(host, name string) (*memcached.Client, error) {
	conn, err := memcached.Connect("tcp", host)
	if err != nil {
		return nil, err
	}
	if name != "default" {
		conn.Auth(name, "") // error checking?
	}
	return conn, nil
}

func (cp *connectionPool) Close() error {
	for c := range cp.connections {
		c.Close()
	}
	return nil
}

func (cp *connectionPool) Get() (*memcached.Client, error) {
	if cp == nil {
		return nil, errors.New("no pool")
	}

	select {
	case rv := <-cp.connections:
		return rv, nil
	case <-time.After(time.Millisecond):
		// Build a connection if we can't get a real one.
		// This can potentially be an overflow connection, or
		// a pooled connection.
		return cp.mkConn(cp.host, cp.name)
	}

	panic("unreachable")
}

func (cp *connectionPool) Return(c *memcached.Client) {
	if cp == nil {
		return
	}

	if c != nil {
		if c.IsHealthy() {
			select {
			case cp.connections <- c:
			default:
				// Overflow connection.
				c.Close()
			}
		} else {
			c.Close()
		}
	}
}
<commit_msg>Remove unused variable.<commit_after>package couchbase

import (
	"errors"
	"time"

	"github.com/dustin/gomemcached/client"
)

type connectionPool struct {
	host, name  string
	mkConn      func(host, name string) (*memcached.Client, error)
	connections chan *memcached.Client
}

func newConnectionPool(host, name string, poolSize int) *connectionPool {
	return &connectionPool{
		host:        host,
		name:        name,
		connections: make(chan *memcached.Client, poolSize),
		mkConn:      defaultMkConn,
	}
}

func defaultMkConn(host, name string) (*memcached.Client, error) {
	conn, err := memcached.Connect("tcp", host)
	if err != nil {
		return nil, err
	}
	if name != "default" {
		conn.Auth(name, "") // error checking?
	}
	return conn, nil
}

func (cp *connectionPool) Close() error {
	for c := range cp.connections {
		c.Close()
	}
	return nil
}

func (cp *connectionPool) Get() (*memcached.Client, error) {
	if cp == nil {
		return nil, errors.New("no pool")
	}

	select {
	case rv := <-cp.connections:
		return rv, nil
	case <-time.After(time.Millisecond):
		// Build a connection if we can't get a real one.
		// This can potentially be an overflow connection, or
		// a pooled connection.
		return cp.mkConn(cp.host, cp.name)
	}

	panic("unreachable")
}

func (cp *connectionPool) Return(c *memcached.Client) {
	if cp == nil {
		return
	}

	if c != nil {
		if c.IsHealthy() {
			select {
			case cp.connections <- c:
			default:
				// Overflow connection.
				c.Close()
			}
		} else {
			c.Close()
		}
	}
}
<|endoftext|>


<commit_before>package invdapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/Invoiced/invoiced-go/invdendpoint"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

const requestURL = "https://api.invoiced.com"
const devRequestURL = "https://api.sandbox.invoiced.com"
const requestType = "application/json"
const InvoicedTokenString = "invoicedToken"

const version = "0.1"

func Version() string {
	return version
}

type Connection struct {
	key             string
	itemsPerRequest int
	client          *http.Client
	url             string
}

type InvoicedToken struct {
	Key string `json:"invoicedApiKey"`
}

func NewConnection(key string, devMode bool) *Connection {
	c := new(Connection)
	c.key = key
	c.client = new(http.Client)
	if devMode {
		c.url = devRequestURL
	} else {
		c.url = requestURL
	}

	return c
}

func checkStatusForError(status int, r io.Reader) error {
	if status < 400 {
		return nil
	}

	body, err := ioutil.ReadAll(r)
	if err != nil {
		panic(err)
	}

	apiError := new(APIError)

	log.Printlns("json body => ", string(body))
	err = json.Unmarshal(body, apiError)

	if err != nil {
		apiError.Type = string(body)

	}

	return errors.New(apiError.Error())

}

func pushDataIntoStruct(endPointData interface{}, respBody io.Reader) {

	body, err := ioutil.ReadAll(respBody)

	if err != nil {
		panic(err)
	}

	err = json.Unmarshal(body, endPointData)

	if err != nil {
		panic(err)
	}

}

func parseURLLinksFromString(s string) map[string]string {

	urlAndLinkMap := make(map[string]string)

	rawURLLinksAndRelations := strings.Split(s, ",")

	for _, rawURLLinkRelation := range rawURLLinksAndRelations {
		parsedRawURLAndRelation := strings.Split(rawURLLinkRelation, ";")
		url := parseRawURL(parsedRawURLAndRelation[0])
		relation := parseRawRelation(parsedRawURLAndRelation[1])

		urlAndLinkMap[relation] = url
	}

	return urlAndLinkMap
}

func parseRawRelation(s string) string {
	//parse rel="last" => last

	first := strings.Index(s, "\"")
	last := strings.LastIndex(s, "\"")

	trimmed := s[first+1 : last]

	trimmed = strings.TrimSpace(trimmed)

	return trimmed

}

func parseRawURL(s string) string {
	//<https://api.invoiced.com/invoices?page=1>

	trimmed := strings.Trim(s, " < ")

	trimmed = strings.Trim(trimmed, " > ")

	trimmed = strings.TrimSpace(trimmed)

	return trimmed

}

func addFilterSortToEndPoint(endpoint string, filter *invdendpoint.Filter, sort *invdendpoint.Sort) string {

	emptyFilter := true
	emptySort := true

	if filter != nil && filter.String() != "" {
		emptyFilter = false
	}

	if sort != nil && sort.String() != "" {
		emptySort = false
	}

	if !emptyFilter && !emptySort {
		return endpoint + "?" + filter.String() + "&" + sort.String()
	} else if !emptyFilter && emptySort {
		return endpoint + "?" + filter.String()
	} else if emptyFilter && !emptySort {
		return endpoint + "?" + sort.String()
	}

	return endpoint

}

func makeEndPointSingular(endpoint string, id int64) string {
	return endpoint + "/" + strconv.FormatInt(id, 10)
}

func (c *Connection) makeEndPointURL(endPoint string) string {

	return c.url + endPoint
}

func (c *Connection) setItemsPerRequest(items int) {
	c.itemsPerRequest = items
}

func (c *Connection) get(endPoint string) *http.Response {

	req, err := http.NewRequest("GET", endPoint, nil)
	req.SetBasicAuth(c.key, "")

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) post(endPoint string, body io.Reader) *http.Response {

	req, err := http.NewRequest("POST", endPoint, body)
	req.SetBasicAuth(c.key, "")
	req.Header.Set("Content-Type", requestType)

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) patch(endPoint string, body io.Reader) *http.Response {

	req, err := http.NewRequest("PATCH", endPoint, body)
	req.SetBasicAuth(c.key, "")
	req.Header.Set("Content-Type", requestType)

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) deleteRequest(endPoint string) *http.Response {

	req, err := http.NewRequest("DELETE", endPoint, nil)
	req.SetBasicAuth(c.key, "")
	req.Header.Set("Content-Type", requestType)

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) create(endPoint string, requestData interface{}, responseData interface{}) error {

	b, err := json.Marshal(requestData)

	if err != nil {
		panic(err)
	}

	body := bytes.NewBuffer(b)

	resp := c.post(endPoint, body)

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return apiError
	}

	pushDataIntoStruct(responseData, resp.Body)

	return nil

}

func (c *Connection) delete(endPoint string) error {

	resp := c.deleteRequest(endPoint)

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return apiError
	}

	return nil

}

func (c *Connection) update(endPoint string, requestData interface{}, responseData interface{}) error {

	b, err := json.Marshal(requestData)

	if err != nil {
		panic(err)
	}

	body := bytes.NewBuffer(b)

	resp := c.patch(endPoint, body)

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return apiError
	}

	pushDataIntoStruct(responseData, resp.Body)

	return nil

}

func (c *Connection) count(endPoint string) (int64, error) {
	resp := c.get(endPoint)

	defer resp.Body.Close()

	apiErr := checkStatusForError(resp.StatusCode, resp.Body)

	if apiErr != nil {
		return 0, apiErr
	}

	s := resp.Header.Get("X-Total-Count")

	i, err := strconv.ParseInt(s, 10, 64)

	if err != nil {
		panic(err)
	}

	return i, nil

}

func (c *Connection) retrieveDataFromAPI(endPoint string, endPointData interface{}) (string, error) {

	nextURL := ""

	resp := c.get(endPoint)

	defer resp.Body.Close()

	link := resp.Header.Get("Link")

	if link != "" {
		nextMap := parseURLLinksFromString(link)

		if nextMap["self"] != nextMap["next"] {
			nextURL = nextMap["next"]
		}
	}

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return "", apiError
	}

	pushDataIntoStruct(endPointData, resp.Body)

	return nextURL, nil

}
<commit_msg>Debugging<commit_after>package invdapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/Invoiced/invoiced-go/invdendpoint"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

const requestURL = "https://api.invoiced.com"
const devRequestURL = "https://api.sandbox.invoiced.com"
const requestType = "application/json"
const InvoicedTokenString = "invoicedToken"

const version = "0.1"

func Version() string {
	return version
}

type Connection struct {
	key             string
	itemsPerRequest int
	client          *http.Client
	url             string
}

type InvoicedToken struct {
	Key string `json:"invoicedApiKey"`
}

func NewConnection(key string, devMode bool) *Connection {
	c := new(Connection)
	c.key = key
	c.client = new(http.Client)
	if devMode {
		c.url = devRequestURL
	} else {
		c.url = requestURL
	}

	return c
}

func checkStatusForError(status int, r io.Reader) error {
	if status < 400 {
		return nil
	}

	body, err := ioutil.ReadAll(r)
	if err != nil {
		panic(err)
	}

	apiError := new(APIError)

	log.Println("json body => ", string(body))
	err = json.Unmarshal(body, apiError)

	if err != nil {
		apiError.Type = string(body)

	}

	return errors.New(apiError.Error())

}

func pushDataIntoStruct(endPointData interface{}, respBody io.Reader) {

	body, err := ioutil.ReadAll(respBody)

	if err != nil {
		panic(err)
	}

	err = json.Unmarshal(body, endPointData)

	if err != nil {
		panic(err)
	}

}

func parseURLLinksFromString(s string) map[string]string {

	urlAndLinkMap := make(map[string]string)

	rawURLLinksAndRelations := strings.Split(s, ",")

	for _, rawURLLinkRelation := range rawURLLinksAndRelations {
		parsedRawURLAndRelation := strings.Split(rawURLLinkRelation, ";")
		url := parseRawURL(parsedRawURLAndRelation[0])
		relation := parseRawRelation(parsedRawURLAndRelation[1])

		urlAndLinkMap[relation] = url
	}

	return urlAndLinkMap
}

func parseRawRelation(s string) string {
	//parse rel="last" => last

	first := strings.Index(s, "\"")
	last := strings.LastIndex(s, "\"")

	trimmed := s[first+1 : last]

	trimmed = strings.TrimSpace(trimmed)

	return trimmed

}

func parseRawURL(s string) string {
	//<https://api.invoiced.com/invoices?page=1>

	trimmed := strings.Trim(s, " < ")

	trimmed = strings.Trim(trimmed, " > ")

	trimmed = strings.TrimSpace(trimmed)

	return trimmed

}

func addFilterSortToEndPoint(endpoint string, filter *invdendpoint.Filter, sort *invdendpoint.Sort) string {

	emptyFilter := true
	emptySort := true

	if filter != nil && filter.String() != "" {
		emptyFilter = false
	}

	if sort != nil && sort.String() != "" {
		emptySort = false
	}

	if !emptyFilter && !emptySort {
		return endpoint + "?" + filter.String() + "&" + sort.String()
	} else if !emptyFilter && emptySort {
		return endpoint + "?" + filter.String()
	} else if emptyFilter && !emptySort {
		return endpoint + "?" + sort.String()
	}

	return endpoint

}

func makeEndPointSingular(endpoint string, id int64) string {
	return endpoint + "/" + strconv.FormatInt(id, 10)
}

func (c *Connection) makeEndPointURL(endPoint string) string {

	return c.url + endPoint
}

func (c *Connection) setItemsPerRequest(items int) {
	c.itemsPerRequest = items
}

func (c *Connection) get(endPoint string) *http.Response {

	req, err := http.NewRequest("GET", endPoint, nil)
	req.SetBasicAuth(c.key, "")

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) post(endPoint string, body io.Reader) *http.Response {

	req, err := http.NewRequest("POST", endPoint, body)
	req.SetBasicAuth(c.key, "")
	req.Header.Set("Content-Type", requestType)

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) patch(endPoint string, body io.Reader) *http.Response {

	req, err := http.NewRequest("PATCH", endPoint, body)
	req.SetBasicAuth(c.key, "")
	req.Header.Set("Content-Type", requestType)

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) deleteRequest(endPoint string) *http.Response {

	req, err := http.NewRequest("DELETE", endPoint, nil)
	req.SetBasicAuth(c.key, "")
	req.Header.Set("Content-Type", requestType)

	resp, err := c.client.Do(req)

	if err != nil {
		panic(err)
	}

	return resp

}

func (c *Connection) create(endPoint string, requestData interface{}, responseData interface{}) error {

	b, err := json.Marshal(requestData)

	if err != nil {
		panic(err)
	}

	body := bytes.NewBuffer(b)

	resp := c.post(endPoint, body)

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return apiError
	}

	pushDataIntoStruct(responseData, resp.Body)

	return nil

}

func (c *Connection) delete(endPoint string) error {

	resp := c.deleteRequest(endPoint)

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return apiError
	}

	return nil

}

func (c *Connection) update(endPoint string, requestData interface{}, responseData interface{}) error {

	b, err := json.Marshal(requestData)

	if err != nil {
		panic(err)
	}

	body := bytes.NewBuffer(b)

	resp := c.patch(endPoint, body)

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return apiError
	}

	pushDataIntoStruct(responseData, resp.Body)

	return nil

}

func (c *Connection) count(endPoint string) (int64, error) {
	resp := c.get(endPoint)

	defer resp.Body.Close()

	apiErr := checkStatusForError(resp.StatusCode, resp.Body)

	if apiErr != nil {
		return 0, apiErr
	}

	s := resp.Header.Get("X-Total-Count")

	i, err := strconv.ParseInt(s, 10, 64)

	if err != nil {
		panic(err)
	}

	return i, nil

}

func (c *Connection) retrieveDataFromAPI(endPoint string, endPointData interface{}) (string, error) {

	nextURL := ""

	resp := c.get(endPoint)

	defer resp.Body.Close()

	link := resp.Header.Get("Link")

	if link != "" {
		nextMap := parseURLLinksFromString(link)

		if nextMap["self"] != nextMap["next"] {
			nextURL = nextMap["next"]
		}
	}

	apiError := checkStatusForError(resp.StatusCode, resp.Body)

	if apiError != nil {
		return "", apiError
	}

	pushDataIntoStruct(endPointData, resp.Body)

	return nextURL, nil

}
<|endoftext|>