<commit_before>// An app that draws and moves triangles on the screen and pushes them on to
// other screens.
//
// See https://github.com/asimshankar/triangles
package main

import (
	"fmt"
	"github.com/asimshankar/triangles/spec"
	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/gl"
	"log"
	"time"
)

func main() {
	app.Main(func(a app.App) {
		var (
			myGL    *GL
			sz      size.Event
			touches = make(map[touch.Sequence]*touchEvents) // Active touch events
			scene   = Scene{}
			debug   *GLDebug

			chMyScreen      = make(chan *spec.Triangle) // New triangles to draw on my screen
			leftScreen      = newOtherScreen(nil, chMyScreen)
			rightScreen     = newOtherScreen(nil, chMyScreen)
			networkChannels = SetupNetwork(chMyScreen)

			spawnTriangle = func(x float32) {
				c := scene.TopBanner
				scene.Triangles = append(scene.Triangles, &spec.Triangle{
					X: x, Y: 1, R: c.R, G: c.G, B: c.B})
			}

			invitationActive       bool
			invitation             Invitation
			invitationTicker       *time.Ticker
			invitationBannerTicker <-chan time.Time

			clearInvitation = func() {
				invitationActive = false
				invitation = Invitation{}
				invitationTicker.Stop()
				invitationBannerTicker = nil
				scene.LeftBanner = nil
			}
		)
		for {
			select {
			case ready := <-networkChannels.Ready:
				switch v := ready.(type) {
				case error:
					log.Panic(v)
				case Color:
					scene.TopBanner = v
					spawnTriangle(0)
				default:
					log.Panicf("Unexpected type from the Ready channel: %T (%v)", ready, ready)
				}
				networkChannels.Ready = nil // To stop this select clause from being hit again.
			case inv := <-networkChannels.Invitations:
				invitationActive = true
				invitation = inv
				invitationTicker = time.NewTicker(time.Second)
				invitationBannerTicker = invitationTicker.C
				log.Printf("Notifying user of invitation from %v", inv.Name)
			case <-invitationBannerTicker:
				// Flash the banner
				if scene.LeftBanner == nil {
					scene.LeftBanner = &invitation.Color
					break
				}
				scene.LeftBanner = nil
			case <-invitation.Withdrawn:
				log.Printf("Invitation from %v withdrawn", invitation.Name)
				clearInvitation()
			case ch := <-networkChannels.NewLeftScreen:
				leftScreen.close()
				leftScreen = newOtherScreen(ch, chMyScreen)
			case ch := <-networkChannels.NewRightScreen:
				rightScreen.close()
				rightScreen = newOtherScreen(ch, chMyScreen)
			case t := <-chMyScreen:
				scene.Triangles = append(scene.Triangles, t)
			case e := <-a.Events():
				switch e := a.Filter(e).(type) {
				case lifecycle.Event:
					switch e.Crosses(lifecycle.StageVisible) {
					case lifecycle.CrossOn:
						glctx, _ := e.DrawContext.(gl.Context)
						var err error
						if myGL, err = NewGL(glctx); err != nil {
							log.Panic(err)
						}
						debug = NewGLDebug(glctx)
						a.Send(paint.Event{})
					case lifecycle.CrossOff:
						if exitOnLifecycleCrossOff() {
							return
						}
						myGL.Release()
						debug.Release()
						myGL = nil
					}
				case paint.Event:
					if e.External {
						continue
					}
					var mine, left, right []*spec.Triangle
					for _, t := range scene.Triangles {
						moveTriangle(t)
						switch {
						case t.X <= -1:
							left = append(left, t)
						case t.X >= 1:
							right = append(right, t)
						default:
							mine = append(mine, t)
						}
					}
					if len(left) > 0 {
						go leftScreen.send(left)
					}
					if len(right) > 0 {
						go rightScreen.send(right)
					}
					scene.Triangles = mine
					myGL.Paint(scene)
					debug.Paint(sz)
					a.Publish()
					a.Send(paint.Event{})
				case size.Event:
					sz = e
				case touch.Event:
					switch e.Type {
					case touch.TypeBegin:
						touches[e.Sequence] = &touchEvents{Start: e}
					case touch.TypeMove:
						touches[e.Sequence].Count++
					case touch.TypeEnd:
						tch := touches[e.Sequence]
						delete(touches, e.Sequence)
						x, y := touch2coords(tch.Start, sz)
						if invitationActive && x < bannerWidth {
							// Touched in the left invitation banner:
							// Swipe = reject, Tap = accept.
							if x, y := (e.X - tch.Start.X), (e.Y - tch.Start.Y); x*x+y*y > 0 {
								log.Printf("Swiped (%d, %d) pixels, rejecting invitation from %q", x, y, invitation.Name)
								invitation.Response <- fmt.Errorf("user rejected")
							} else {
								log.Printf("Accepting invitation from %q", invitation.Name)
								invitation.Response <- nil
							}
							clearInvitation()
							break
						}
						if y <= -1+bannerWidth {
							// Touched top banner, spawn a new triangle
							log.Printf("Top banner touched, spawning new triangle (Y=%v, threshold=%v)", y, -1+bannerWidth)
							spawnTriangle(x)
							break
						}
						if c := tch.Count; c > maxTouchCount {
							log.Printf("Ignoring long touch (%d > %d)", c, maxTouchCount)
							break
						}
						// Find the closest triangle to the touch start and adjust its velocity.
						var (
							// Normalize the touch coordinates to the triangle coordinates ([-1,1])
							closestT      *spec.Triangle
							minDistanceSq float32
						)
						for idx, t := range scene.Triangles {
							if d := (x-t.X)*(x-t.X) + (y-t.Y)*(y-t.Y); d < minDistanceSq || idx == 0 {
								minDistanceSq = d
								closestT = t
							}
						}
						if closestT != nil {
							closestT.Dx += (e.X - tch.Start.X) / float32(sz.WidthPx)
							closestT.Dy += (e.Y - tch.Start.Y) / float32(sz.HeightPx)
						}
					}
				}
			}
		}
	})
}

type touchEvents struct {
	Start touch.Event // Starting event
	Count int         // Number of moves before the end event
}

type otherScreen struct {
	chTriangles chan<- *spec.Triangle
	chLost      chan struct{}
	chSelf      chan<- *spec.Triangle
}

func newOtherScreen(other, self chan<- *spec.Triangle) *otherScreen {
	return &otherScreen{
		chTriangles: other,
		chLost:      make(chan struct{}),
		chSelf:      self,
	}
}

func (s *otherScreen) close() {
	close(s.chLost)
}

func (s *otherScreen) send(triangles []*spec.Triangle) {
	if s.chTriangles == nil {
		for _, t := range triangles {
			returnTriangle(t, s.chSelf)
		}
		return
	}
	for i, t := range triangles {
		select {
		case <-s.chLost:
			// Lost the other screen, so reflect the remaining triangles back onto my screen.
			for i < len(triangles) {
				returnTriangle(t, s.chSelf)
				i++
			}
			return
		case s.chTriangles <- t:
		}
	}
}

// touch2coords transforms coordinates from the touch.Event coordinate system
// to the GL and Triangles coordinate system.
func touch2coords(t touch.Event, sz size.Event) (x, y float32) {
	return 2*t.X/float32(sz.WidthPx) - 1, 2*t.Y/float32(sz.HeightPx) - 1
}

func moveTriangle(t *spec.Triangle) {
	t.Dy = t.Dy - gravity
	t.X = t.X + t.Dx*timeBetweenPaints
	t.Y = t.Y + t.Dy*timeBetweenPaints
	if t.Y <= -1 {
		t.Dy = -1 * t.Dy
		t.Y = -1
	} else if maxY := 1 - triangleCenterHeight; t.Y >= maxY {
		t.Dy = -1 * t.Dy
		t.Y = maxY
	}
}

func returnTriangle(t *spec.Triangle, myScreen chan<- *spec.Triangle) {
	t.Dx = -1 * t.Dx
	moveTriangle(t)
	myScreen <- t
}

const (
	maxTouchCount            = 30
	acceptInvitationDuration = time.Second
	gravity                  = 0.01
	timeBetweenPaints        = 0.1
)
<commit_msg>Better selection and velocity updates for triangles.<commit_after>// An app that draws and moves triangles on the screen and pushes them on to
// other screens.
//
// See https://github.com/asimshankar/triangles
package main

import (
	"fmt"
	"github.com/asimshankar/triangles/spec"
	"golang.org/x/mobile/app"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
	"golang.org/x/mobile/event/touch"
	"golang.org/x/mobile/gl"
	"log"
	"time"
)

func main() {
	app.Main(func(a app.App) {
		var (
			myGL             *GL
			sz               size.Event
			touches          = make(map[touch.Sequence]*touchEvents) // Active touch events
			touchedTriangles = make(map[*spec.Triangle]struct{})     // Triangles currently being touched
			scene            = Scene{}
			debug            *GLDebug

			chMyScreen      = make(chan *spec.Triangle) // New triangles to draw on my screen
			leftScreen      = newOtherScreen(nil, chMyScreen)
			rightScreen     = newOtherScreen(nil, chMyScreen)
			networkChannels = SetupNetwork(chMyScreen)

			spawnTriangle = func(x float32) {
				c := scene.TopBanner
				scene.Triangles = append(scene.Triangles, &spec.Triangle{
					X: x, Y: 1, R: c.R, G: c.G, B: c.B})
			}

			invitationActive       bool
			invitation             Invitation
			invitationTicker       *time.Ticker
			invitationBannerTicker <-chan time.Time

			clearInvitation = func() {
				invitationActive = false
				invitation = Invitation{}
				invitationTicker.Stop()
				invitationBannerTicker = nil
				scene.LeftBanner = nil
			}
		)
		for {
			select {
			case ready := <-networkChannels.Ready:
				switch v := ready.(type) {
				case error:
					log.Panic(v)
				case Color:
					scene.TopBanner = v
					spawnTriangle(0)
				default:
					log.Panicf("Unexpected type from the Ready channel: %T (%v)", ready, ready)
				}
				networkChannels.Ready = nil // To stop this select clause from being hit again.
			case inv := <-networkChannels.Invitations:
				invitationActive = true
				invitation = inv
				invitationTicker = time.NewTicker(time.Second)
				invitationBannerTicker = invitationTicker.C
				log.Printf("Notifying user of invitation from %v", inv.Name)
			case <-invitationBannerTicker:
				// Flash the banner
				if scene.LeftBanner == nil {
					scene.LeftBanner = &invitation.Color
					break
				}
				scene.LeftBanner = nil
			case <-invitation.Withdrawn:
				log.Printf("Invitation from %v withdrawn", invitation.Name)
				clearInvitation()
			case ch := <-networkChannels.NewLeftScreen:
				leftScreen.close()
				leftScreen = newOtherScreen(ch, chMyScreen)
			case ch := <-networkChannels.NewRightScreen:
				rightScreen.close()
				rightScreen = newOtherScreen(ch, chMyScreen)
			case t := <-chMyScreen:
				scene.Triangles = append(scene.Triangles, t)
			case e := <-a.Events():
				switch e := a.Filter(e).(type) {
				case lifecycle.Event:
					switch e.Crosses(lifecycle.StageVisible) {
					case lifecycle.CrossOn:
						glctx, _ := e.DrawContext.(gl.Context)
						var err error
						if myGL, err = NewGL(glctx); err != nil {
							log.Panic(err)
						}
						debug = NewGLDebug(glctx)
						a.Send(paint.Event{})
					case lifecycle.CrossOff:
						if exitOnLifecycleCrossOff() {
							return
						}
						myGL.Release()
						debug.Release()
						myGL = nil
					}
				case paint.Event:
					if e.External {
						continue
					}
					var mine, left, right []*spec.Triangle
					for _, t := range scene.Triangles {
						if _, touched := touchedTriangles[t]; !touched {
							// Only move a triangle if it is not currently being manipulated by the user.
							moveTriangle(t)
						}
						switch {
						case t.X < -1:
							left = append(left, t)
						case t.X > 1:
							right = append(right, t)
						default:
							mine = append(mine, t)
						}
					}
					if len(left) > 0 {
						go leftScreen.send(left)
					}
					if len(right) > 0 {
						go rightScreen.send(right)
					}
					scene.Triangles = mine
					myGL.Paint(scene)
					debug.Paint(sz)
					a.Publish()
					a.Send(paint.Event{})
				case size.Event:
					sz = e
				case touch.Event:
					switch e.Type {
					case touch.TypeBegin:
						var (
							touchedT *spec.Triangle
							x, y     = touch2coords(e, sz)
						)
						for _, t := range scene.Triangles {
							if dx, dy := (x - t.X), (y - t.Y); dx*dx+dy*dy < triangleSide*triangleSide {
								log.Printf("Triangle %+v touched by user", t)
								touchedT = t
								touchedTriangles[t] = struct{}{}
								break
							}
						}
						touches[e.Sequence] = &touchEvents{Start: e, Triangle: touchedT}
					case touch.TypeMove:
						tch := touches[e.Sequence]
						if tch.Triangle != nil {
							tch.Triangle.X, tch.Triangle.Y = touch2coords(e, sz)
						}
					case touch.TypeEnd:
						tch := touches[e.Sequence]
						delete(touches, e.Sequence)
						x, y := touch2coords(tch.Start, sz)
						if t := tch.Triangle; t != nil {
							// Set triangle velocity based on movement from the original position.
							t.X, t.Y = touch2coords(e, sz)
							t.Dx = (e.X - tch.Start.X) / float32(sz.WidthPx)
							t.Dy = (e.Y - tch.Start.Y) / float32(sz.HeightPx)
							delete(touchedTriangles, t)
							break
						}
						if invitationActive && x < bannerWidth {
							// Touched in the left invitation banner:
							// Swipe = reject, Tap = accept.
							if x, y := (e.X - tch.Start.X), (e.Y - tch.Start.Y); x*x+y*y > 0 {
								log.Printf("Swiped (%d, %d) pixels, rejecting invitation from %q", x, y, invitation.Name)
								invitation.Response <- fmt.Errorf("user rejected")
							} else {
								log.Printf("Accepting invitation from %q", invitation.Name)
								invitation.Response <- nil
							}
							clearInvitation()
							break
						}
						if y >= 1-bannerWidth {
							// Touched top banner, spawn a new triangle
							log.Printf("Top banner touched, spawning new triangle (Y=%v, threshold=%v)", y, -1+bannerWidth)
							spawnTriangle(x)
							break
						}
					}
				}
			}
		}
	})
}

type touchEvents struct {
	Start    touch.Event    // Where the touch event began
	Triangle *spec.Triangle // The triangle being manipulated by touch, if any
}

type otherScreen struct {
	chTriangles chan<- *spec.Triangle
	chLost      chan struct{}
	chSelf      chan<- *spec.Triangle
}

func newOtherScreen(other, self chan<- *spec.Triangle) *otherScreen {
	return &otherScreen{
		chTriangles: other,
		chLost:      make(chan struct{}),
		chSelf:      self,
	}
}

func (s *otherScreen) close() {
	close(s.chLost)
}

func (s *otherScreen) send(triangles []*spec.Triangle) {
	if s.chTriangles == nil {
		for _, t := range triangles {
			returnTriangle(t, s.chSelf)
		}
		return
	}
	for i, t := range triangles {
		select {
		case <-s.chLost:
			// Lost the other screen, so reflect the remaining triangles back onto my screen.
			for i < len(triangles) {
				returnTriangle(t, s.chSelf)
				i++
			}
			return
		case s.chTriangles <- t:
		}
	}
}

// touch2coords transforms coordinates from the touch.Event coordinate system
// to the GL and Triangles coordinate system.
//
// Pixel coordinates <--> GL coordinates;
//            (0, 0) <--> (-1, 1)  // bottom left
//        (W/2, H/2) <--> (0, 0)
//            (W, H) <--> (1, -1)  // top right
func touch2coords(t touch.Event, sz size.Event) (x, y float32) {
	return 2*t.X/float32(sz.WidthPx) - 1, 1 - 2*t.Y/float32(sz.HeightPx)
}

func moveTriangle(t *spec.Triangle) {
	t.Dy = t.Dy - gravity
	t.X = t.X + t.Dx*timeBetweenPaints
	t.Y = t.Y + t.Dy*timeBetweenPaints
	if t.Y <= -1 {
		t.Dy = -1 * t.Dy
		t.Y = -1
	} else if maxY := 1 - triangleCenterHeight; t.Y >= maxY {
		t.Dy = -1 * t.Dy
		t.Y = maxY
	}
}

func returnTriangle(t *spec.Triangle, myScreen chan<- *spec.Triangle) {
	t.Dx = -1 * t.Dx
	moveTriangle(t)
	myScreen <- t
}

const (
	acceptInvitationDuration = time.Second
	gravity                  = 0.001
	timeBetweenPaints        = 0.1
)
<|endoftext|>


<commit_before>package kubernetes

import (
	"code.cloudfoundry.org/lager"

	"github.com/concourse/atc/creds"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

type KubernetesManager struct {
	ConfigPath string `long:"config-path" description:"Path to kubernetes config. Leave empty for in-cluster ATC."`
	NamespacePrefix string `long:"namespace-prefix" default:"concourse-" description:"Prefix to use for Kubernetes namespaces under which secrets will be looked up."`
}

func (manager KubernetesManager) IsConfigured() bool {
	if manager.ConfigPath != "" {
		return true
	}
	_, err := rest.InClusterConfig()
	if err == nil {
		return true
	}
	return false
}

func (manager KubernetesManager) buildConfig() (*rest.Config, error) {
	if manager.ConfigPath != "" {
		return clientcmd.BuildConfigFromFlags("", manager.ConfigPath)
	}
	return rest.InClusterConfig()
}

func (manager KubernetesManager) Validate() error {
	_, err := manager.buildConfig()
	return err
}

func (manager KubernetesManager) NewVariablesFactory(logger lager.Logger) (creds.VariablesFactory, error) {
	config, err := manager.buildConfig()
	if err != nil {
		return nil, err
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return NewKubernetesFactory(logger, clientset, manager.NamespacePrefix), nil
}
<commit_msg>Add a flag for using k8s secrets when running in cluster.<commit_after>package kubernetes

import (
	"errors"

	"code.cloudfoundry.org/lager"

	"github.com/concourse/atc/creds"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

type KubernetesManager struct {
	InClusterConfig bool `long:"in-cluster" description:"Enables the in-cluster client."`
	ConfigPath string `long:"config-path" description:"Path to Kubernetes config when running ATC outside Kubernetes."`
	NamespacePrefix string `long:"namespace-prefix" default:"concourse-" description:"Prefix to use for Kubernetes namespaces under which secrets will be looked up."`
}

func (manager KubernetesManager) IsConfigured() bool {
	return manager.InClusterConfig || manager.ConfigPath != ""
}

func (manager KubernetesManager) buildConfig() (*rest.Config, error) {
	if manager.InClusterConfig {
		return rest.InClusterConfig()
	}

	return clientcmd.BuildConfigFromFlags("", manager.ConfigPath)
}

func (manager KubernetesManager) Validate() error {
	if (manager.InClusterConfig && manager.ConfigPath != "") {
		return errors.New("Either in-cluster or config-path can be used, not both.")
	}
	_, err := manager.buildConfig()
	return err
}

func (manager KubernetesManager) NewVariablesFactory(logger lager.Logger) (creds.VariablesFactory, error) {
	config, err := manager.buildConfig()
	if err != nil {
		return nil, err
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return NewKubernetesFactory(logger, clientset, manager.NamespacePrefix), nil
}
<|endoftext|>


<commit_before>// Package main ...
package main

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strings"

	"github.com/bugsnag/bugsnag-go"
	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox/commands"
	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/processors"
	"github.com/nanobox-io/nanobox/util"
	"github.com/nanobox-io/nanobox/util/config"
	"github.com/nanobox-io/nanobox/util/provider"
	// "github.com/nanobox-io/nanobox/util/display"
)

var bugsnagToken string

type bugLog struct {
}

func (bugLog) Printf(fmt string, v ...interface{}) {
	lumber.Info(fmt, v...)
}

// main
func main() {
	// verify that we support the prompt they are using
	if badTerminal() {
		fmt.Println("This console is currently not supported by nanobox")
		fmt.Println("Please refer to the docs for more information")
		os.Exit(1)
	}

	// do the commands configure check here because we need it to happen before setupBugsnag creates the config
	if !config.ConfigExists() {
		processors.Configure()
	}

	migrationCheck()

	fixRunArgs()

	// build the viper config because viper cannot handle concurrency
	// so it has to be done at the beginning even if we dont need it
	providerName := config.Viper().GetString("provider")

	// make sure nanobox has all the necessry parts
	valid, missingParts := provider.Valid()
	if !valid {
		fmt.Printf("Using nanobox with %s requires tools that appear to not be available on your system.\n", providerName)
		fmt.Println(strings.Join(missingParts, "\n"))
		if providerName == "native" {
			providerName = "docker"
		}
		fmt.Printf("View these requirements at docs.nanobox.io/install/requirements/%s/\n", providerName)
		os.Exit(1)
	}

	// setup a file logger, this will be replaced in verbose mode.
	fileLogger, err := lumber.NewAppendLogger(filepath.ToSlash(filepath.Join(config.GlobalDir(), "nanobox.log")))
	if err != nil {
		fmt.Println("logging error:", err)
	}

	//
	lumber.SetLogger(fileLogger)
	lumber.Level(lumber.INFO)
	defer lumber.Close()

	// global panic handler; this is done to avoid showing any panic output if
	// something happens to fail. The output is logged and "pretty" message is
	// shown
	defer func() {
		if r := recover(); r != nil {
			// put r into your log ( it contains the panic message)
			// Then log debug.Stack (from the runtime/debug package)

			stack := debug.Stack()

			bugsnag.Notify(fmt.Errorf("panic"), bugsnag.SeverityError, bugsnag.User{Id: util.UniqueID()}, r, stack)

			lumber.Fatal(fmt.Sprintf("Cause of failure: %v", r))
			lumber.Fatal(fmt.Sprintf("Error output:\n%v\n", string(stack)))
			lumber.Close()
			fmt.Println("Nanobox encountered an unexpected error. Please see ~/.nanobox/nanobox.log and submit the issue to us.")
			os.Exit(1)
		}
	}()

	// get the bugsnag variables ready
	setupBugsnag()

	//
	commands.NanoboxCmd.Execute()
}

func setupBugsnag() {
	update, _ := models.LoadUpdate()
	md5Parts := strings.Fields(update.CurrentVersion)
	version := ""
	if len(md5Parts) > 1 {
		version = md5Parts[len(md5Parts)-1]
	}

	bugsnag.Configure(bugsnag.Configuration{
		APIKey:       bugsnagToken,
		Logger:       bugLog{},
		Synchronous:  true,
		AppVersion:   version,
		PanicHandler: func() {}, // the built in panic handler reexicutes our code
	})

	bugsnag.OnBeforeNotify(func(event *bugsnag.Event, config *bugsnag.Configuration) error {
		// set the grouping hash to a md5 of the message. which should seperate the grouping in the dashboard
		event.GroupingHash = fmt.Sprintf("%x", md5.Sum([]byte(event.Message)))
		return nil
	})

}

func badTerminal() bool {
	return runtime.GOOS == "windows" && strings.Contains(os.Getenv("shell"), "bash")
}

func fixRunArgs() {
	found := false
	lastLocation := 0
LOOP:
	for i, arg := range os.Args {
		switch arg {
		case "run":
			found = true
			lastLocation = i
		case "--debug", "--trace", "--verbose", "-t", "-v":
			// if we hit a argument of ours after 'found'
			// we will reset the last location
			if found == true {
				lastLocation = i
			}
		default:
			// if we hit this after we have found run
			// we are done
			if found == true {
				break LOOP
			}
		}

	}
	if found {
		os.Args = append(os.Args[:lastLocation+1], strings.Join(os.Args[lastLocation+1:], " "))
	}
}

// check to see if we need to wipe the old
func migrationCheck() {
	providerName := config.Viper().GetString("provider")
	providerModel, err := models.LoadProvider()

	// if the provider hasnt changed or its a new provider
	// no migration required
	if util.IsPrivileged() || err != nil || providerModel.Name == providerName {
		return
	}

	// remember the new provider
	newProviderName := providerName

	// when migrating from the old system
	// the provider.Name may be blank
	if providerModel.Name == "" {
		providerModel.Name = newProviderName
	}

	// adjust cached config to be the old provider
	config.Viper().Set("provider", providerModel.Name)

	// alert the user of our actions
	fmt.Println("manditory migration message")
	fmt.Println("press enter to continue")
	reader := bufio.NewReader(os.Stdin)
	reader.ReadString('\n')

	// implode the old system
	processors.Implode()

	// on implode success
	// adjust the provider to the new one and save the provider model
	config.Viper().Set("provider", newProviderName)
	providerModel.Name = newProviderName
	providerModel.Save()
}
<commit_msg>messaging<commit_after>// Package main ...
package main

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strings"

	"github.com/bugsnag/bugsnag-go"
	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox/commands"
	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/processors"
	"github.com/nanobox-io/nanobox/util"
	"github.com/nanobox-io/nanobox/util/config"
	"github.com/nanobox-io/nanobox/util/provider"
	// "github.com/nanobox-io/nanobox/util/display"
)

var bugsnagToken string

type bugLog struct {
}

func (bugLog) Printf(fmt string, v ...interface{}) {
	lumber.Info(fmt, v...)
}

// main
func main() {
	// verify that we support the prompt they are using
	if badTerminal() {
		fmt.Println("This console is currently not supported by nanobox")
		fmt.Println("Please refer to the docs for more information")
		os.Exit(1)
	}

	// do the commands configure check here because we need it to happen before setupBugsnag creates the config
	if !config.ConfigExists() {
		processors.Configure()
	}

	migrationCheck()

	fixRunArgs()

	// build the viper config because viper cannot handle concurrency
	// so it has to be done at the beginning even if we dont need it
	providerName := config.Viper().GetString("provider")

	// make sure nanobox has all the necessry parts
	valid, missingParts := provider.Valid()
	if !valid {
		fmt.Printf("Using nanobox with %s requires tools that appear to not be available on your system.\n", providerName)
		fmt.Println(strings.Join(missingParts, "\n"))
		if providerName == "native" {
			providerName = "docker"
		}
		fmt.Printf("View these requirements at docs.nanobox.io/install/requirements/%s/\n", providerName)
		os.Exit(1)
	}

	// setup a file logger, this will be replaced in verbose mode.
	fileLogger, err := lumber.NewAppendLogger(filepath.ToSlash(filepath.Join(config.GlobalDir(), "nanobox.log")))
	if err != nil {
		fmt.Println("logging error:", err)
	}

	//
	lumber.SetLogger(fileLogger)
	lumber.Level(lumber.INFO)
	defer lumber.Close()

	// global panic handler; this is done to avoid showing any panic output if
	// something happens to fail. The output is logged and "pretty" message is
	// shown
	defer func() {
		if r := recover(); r != nil {
			// put r into your log ( it contains the panic message)
			// Then log debug.Stack (from the runtime/debug package)

			stack := debug.Stack()

			bugsnag.Notify(fmt.Errorf("panic"), bugsnag.SeverityError, bugsnag.User{Id: util.UniqueID()}, r, stack)

			lumber.Fatal(fmt.Sprintf("Cause of failure: %v", r))
			lumber.Fatal(fmt.Sprintf("Error output:\n%v\n", string(stack)))
			lumber.Close()
			fmt.Println("Nanobox encountered an unexpected error. Please see ~/.nanobox/nanobox.log and submit the issue to us.")
			os.Exit(1)
		}
	}()

	// get the bugsnag variables ready
	setupBugsnag()

	//
	commands.NanoboxCmd.Execute()
}

func setupBugsnag() {
	update, _ := models.LoadUpdate()
	md5Parts := strings.Fields(update.CurrentVersion)
	version := ""
	if len(md5Parts) > 1 {
		version = md5Parts[len(md5Parts)-1]
	}

	bugsnag.Configure(bugsnag.Configuration{
		APIKey:       bugsnagToken,
		Logger:       bugLog{},
		Synchronous:  true,
		AppVersion:   version,
		PanicHandler: func() {}, // the built in panic handler reexicutes our code
	})

	bugsnag.OnBeforeNotify(func(event *bugsnag.Event, config *bugsnag.Configuration) error {
		// set the grouping hash to a md5 of the message. which should seperate the grouping in the dashboard
		event.GroupingHash = fmt.Sprintf("%x", md5.Sum([]byte(event.Message)))
		return nil
	})

}

func badTerminal() bool {
	return runtime.GOOS == "windows" && strings.Contains(os.Getenv("shell"), "bash")
}

func fixRunArgs() {
	found := false
	lastLocation := 0
LOOP:
	for i, arg := range os.Args {
		switch arg {
		case "run":
			found = true
			lastLocation = i
		case "--debug", "--trace", "--verbose", "-t", "-v":
			// if we hit a argument of ours after 'found'
			// we will reset the last location
			if found == true {
				lastLocation = i
			}
		default:
			// if we hit this after we have found run
			// we are done
			if found == true {
				break LOOP
			}
		}

	}
	if found {
		os.Args = append(os.Args[:lastLocation+1], strings.Join(os.Args[lastLocation+1:], " "))
	}
}

// check to see if we need to wipe the old
func migrationCheck() {
	providerName := config.Viper().GetString("provider")
	providerModel, err := models.LoadProvider()

	// if the provider hasnt changed or its a new provider
	// no migration required
	if util.IsPrivileged() || err != nil || providerModel.Name == providerName {
		return
	}

	// remember the new provider
	newProviderName := providerName

	// when migrating from the old system
	// the provider.Name may be blank
	if providerModel.Name == "" {
		providerModel.Name = newProviderName
	}

	// adjust cached config to be the old provider
	config.Viper().Set("provider", providerModel.Name)

	// alert the user of our actions
	fmt.Println(`Great news! Nanobox can now optionally run directly on top of Docker. This change constitutes a major architectural refactor as well as data re-structure. To use this version we need to purge your current apps. Fortunately, nanobox will re-build them for you the next time you use "nanobox run".`)
	fmt.Println("press enter to continue")
	reader := bufio.NewReader(os.Stdin)
	reader.ReadString('\n')

	// implode the old system
	processors.Implode()

	// on implode success
	// adjust the provider to the new one and save the provider model
	config.Viper().Set("provider", newProviderName)
	providerModel.Name = newProviderName
	providerModel.Save()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"

	"github.com/satori/go.uuid"
)

type forestCustodian struct {
	input     chan somaRepositoryRequest
	system    chan msg.Request
	shutdown  chan bool
	conn      *sql.DB
	add_stmt  *sql.Stmt
	load_stmt *sql.Stmt
	name_stmt *sql.Stmt
}

func (f *forestCustodian) run() {
	var err error

	f.add_stmt, err = f.conn.Prepare(`
INSERT INTO soma.repositories (
	repository_id,
	repository_name,
	repository_active,
	repository_deleted,
	organizational_team_id,
	created_by)
SELECT $1::uuid, $2::varchar, $3::boolean, $4::boolean, $5::uuid, user_id
FROM inventory.users iu
WHERE iu.user_uid = $6::varchar
AND   NOT EXISTS (
	SELECT repository_id
	FROM   soma.repositories
	WHERE  repository_id = $1::uuid
	OR     repository_name = $2::varchar);`)
	if err != nil {
		log.Fatal("repository/add: ", err)
	}
	defer f.add_stmt.Close()

	f.load_stmt, err = f.conn.Prepare(`
SELECT repository_id,
	   repository_name,
	   repository_deleted,
	   repository_active,
	   organizational_team_id
FROM   soma.repositories;`)
	if err != nil {
		log.Fatal("repository/load: ", err)
	}
	defer f.load_stmt.Close()

	f.name_stmt, err = f.conn.Prepare(`
SELECT repository_name,
       organizational_team_id
FROM   soma.repositories
WHERE  repository_id = $1::uuid;`)
	if err != nil {
		log.Fatal("forestCustodian/reponame-by-id: ", err)
	}
	defer f.name_stmt.Close()

	f.initialLoad()

runloop:
	for {
		select {
		case <-f.shutdown:
			break runloop
		case req := <-f.input:
			f.process(&req)
		case req := <-f.system:
			f.sysprocess(&req)
		}
	}
}

func (f *forestCustodian) process(q *somaRepositoryRequest) {
	var (
		res        sql.Result
		err        error
		sTree      *tree.Tree
		actionChan chan *tree.Action
		errChan    chan *tree.Error
		team       string
	)
	result := somaResult{}

	switch q.action {
	case "add":
		log.Printf(LogStrReq,
			`ForestCustodian`,
			fmt.Sprintf("%s/%s", `CreateRepository`, q.Repository.Name),
			q.user, q.remoteAddr,
		)
		actionChan = make(chan *tree.Action, 1024000)
		errChan = make(chan *tree.Error, 1024000)

		id := uuid.NewV4()
		q.Repository.Id = id.String()

		sTree = tree.New(tree.TreeSpec{
			Id:     uuid.NewV4().String(),
			Name:   fmt.Sprintf("root_%s", q.Repository.Name),
			Action: actionChan,
		})
		tree.NewRepository(tree.RepositorySpec{
			Id:      q.Repository.Id,
			Name:    q.Repository.Name,
			Team:    q.Repository.TeamId,
			Deleted: false,
			Active:  q.Repository.IsActive,
		}).Attach(tree.AttachRequest{
			Root:       sTree,
			ParentType: "root",
			ParentId:   sTree.GetID(),
		})
		sTree.SetError(errChan)

		for i := len(actionChan); i > 0; i-- {
			action := <-actionChan
			switch action.Action {
			case "create":
				if action.Type == "fault" {
					continue
				}
				if action.Type == "repository" {
					res, err = f.add_stmt.Exec(
						action.Repository.Id,
						action.Repository.Name,
						action.Repository.IsActive,
						false,
						action.Repository.TeamId,
						q.user,
					)
					team = action.Repository.TeamId
				}
			case "attached":
			default:
				log.Printf("R: Unhandled action during tree creation: %s", q.action)
				result.SetNotImplemented()
				q.reply <- result
				return
			}
		}
	default:
		log.Printf("R: unimplemented repository/%s", q.action)
		result.SetNotImplemented()
		q.reply <- result
		return
	}
	if result.SetRequestError(err) {
		q.reply <- result
		return
	}

	rowCnt, _ := res.RowsAffected()
	switch {
	case rowCnt == 0:
		result.Append(errors.New("No rows affected"), &somaRepositoryResult{})
	case rowCnt > 1:
		result.Append(fmt.Errorf("Too many rows affected: %d", rowCnt),
			&somaRepositoryResult{})
	default:
		if team == "" {
			result.SetRequestError(
				fmt.Errorf("Team has not been set prior to spawning TreeKeeper for repo: %s", q.Repository.Name),
			)
			q.reply <- result
			return
		}
		result.Append(nil, &somaRepositoryResult{
			Repository: q.Repository,
		})
		if q.action == "add" {
			f.spawnTreeKeeper(q, sTree, errChan, actionChan, team)
		}
	}
	q.reply <- result
}

func (f *forestCustodian) sysprocess(q *msg.Request) {
	var (
		repoId, repoName, teamId, keeper string
		err                              error
		handler                          *treeKeeper
	)
	result := msg.Result{
		Type:   `guidepost`,
		Action: `systemoperation`,
		System: []proto.SystemOperation{q.System},
	}

	switch q.System.Request {
	case `rebuild_repository`:
		repoId = q.System.RepositoryId
	default:
		result.NotImplemented(
			fmt.Errorf("Unknown requested system operation: %s",
				q.System.Request),
		)
		goto exit
	}

	// look up name of the repository
	if err = f.name_stmt.QueryRow(repoId).
		Scan(&repoName, &teamId); err != nil {
		if err == sql.ErrNoRows {
			result.NotFound(fmt.Errorf(`No such repository`))
		} else {
			result.ServerError(err)
		}
		goto exit
	}

	// get the treekeeper for the repository
	keeper = fmt.Sprintf("repository_%s", repoName)
	if _, ok := handlerMap[keeper].(*treeKeeper); !ok {
		result.NotFound(
			fmt.Errorf("No handler for repository %s registered.",
				repoName),
		)
		goto exit
	}

	// stop the handler if it is still running
	if !handler.isStopped() {
		handler.stopchan <- true
	}

	// remove handler from lookup table and shut it down
	delete(handlerMap, keeper)
	handler.shutdown <- true

	// TODO Delete items according to q.System.RebuildLevel

	// load the tree again, with requested rebuild active
	f.loadSomaTree(&somaRepositoryRequest{
		rebuild: true,
		rbLevel: q.System.RebuildLevel,
		Repository: proto.Repository{
			Id:        repoId,
			Name:      repoName,
			TeamId:    teamId,
			IsDeleted: false,
			IsActive:  true,
		},
	})

	// rebuild has finished, restart the tree
	f.loadSomaTree(&somaRepositoryRequest{
		rebuild: false,
		rbLevel: "",
		Repository: proto.Repository{
			Id:        repoId,
			Name:      repoName,
			TeamId:    teamId,
			IsDeleted: false,
			IsActive:  true,
		},
	})

	// TODO issue result.OK()

exit:
	q.Reply <- result
}

func (f *forestCustodian) initialLoad() {
	var (
		rows                     *sql.Rows
		err                      error
		repoId, repoName, teamId string
		repoActive, repoDeleted  bool
	)
	log.Printf("Loading existing repositories")
	rows, err = f.load_stmt.Query()
	if err != nil {
		log.Fatal("Error loading repositories: ", err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(
			&repoId,
			&repoName,
			&repoDeleted,
			&repoActive,
			&teamId,
		)
		if err != nil {
			log.Printf("Error: %s", err.Error())
		}
		f.loadSomaTree(&somaRepositoryRequest{
			Repository: proto.Repository{
				Id:        repoId,
				Name:      repoName,
				TeamId:    teamId,
				IsDeleted: repoDeleted,
				IsActive:  repoActive,
			},
		})
	}
}

func (f *forestCustodian) loadSomaTree(q *somaRepositoryRequest) {
	actionChan := make(chan *tree.Action, 1024000)
	errChan := make(chan *tree.Error, 1024000)

	sTree := tree.New(tree.TreeSpec{
		Id:     uuid.NewV4().String(),
		Name:   fmt.Sprintf("root_%s", q.Repository.Name),
		Action: actionChan,
	})
	tree.NewRepository(tree.RepositorySpec{
		Id:      q.Repository.Id,
		Name:    q.Repository.Name,
		Team:    q.Repository.TeamId,
		Deleted: q.Repository.IsDeleted,
		Active:  q.Repository.IsActive,
	}).Attach(tree.AttachRequest{
		Root:       sTree,
		ParentType: "root",
		ParentId:   sTree.GetID(),
	})
	sTree.SetError(errChan)
	for i := len(actionChan); i > 0; i-- {
		// discard actions on initial load
		<-actionChan
	}
	for i := len(errChan); i > 0; i-- {
		// discard actions on initial load
		<-errChan
	}
	f.spawnTreeKeeper(q, sTree, errChan, actionChan, q.Repository.TeamId)
}

func (f *forestCustodian) spawnTreeKeeper(q *somaRepositoryRequest, s *tree.Tree,
	ec chan *tree.Error, ac chan *tree.Action, team string) {

	// only start the single requested repo in observer mode with
	// set repo flag
	if SomaCfg.Observer && SomaCfg.ObserverRepo != `` && q.Repository.Name != SomaCfg.ObserverRepo {
		return
	}

	db, err := newDatabaseConnection()
	if err != nil {
		return
	}
	tK := new(treeKeeper)
	tK.input = make(chan treeRequest, 1024)
	tK.shutdown = make(chan bool)
	tK.conn = db
	tK.tree = s
	tK.errChan = ec
	tK.actionChan = ac
	tK.broken = false
	tK.ready = false
	tK.frozen = false
	tK.stopped = false
	tK.rebuild = q.rebuild
	tK.rbLevel = q.rbLevel
	tK.repoId = q.Repository.Id
	tK.repoName = q.Repository.Name
	tK.team = team
	keeperName := fmt.Sprintf("repository_%s", q.Repository.Name)

	// during rebuild the treekeeper will not run in background
	if tK.rebuild {
		tK.run()
	} else {
		// non-rebuild, register TK and detach
		handlerMap[keeperName] = tK
		go tK.run()
	}
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Forest/rebuild: issues required deletions<commit_after>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"

	"github.com/satori/go.uuid"
)

type forestCustodian struct {
	input     chan somaRepositoryRequest
	system    chan msg.Request
	shutdown  chan bool
	conn      *sql.DB
	add_stmt  *sql.Stmt
	load_stmt *sql.Stmt
	name_stmt *sql.Stmt
	rbck_stmt *sql.Stmt
	rbci_stmt *sql.Stmt
}

func (f *forestCustodian) run() {
	var err error

	f.add_stmt, err = f.conn.Prepare(`
INSERT INTO soma.repositories (
	repository_id,
	repository_name,
	repository_active,
	repository_deleted,
	organizational_team_id,
	created_by)
SELECT $1::uuid, $2::varchar, $3::boolean, $4::boolean, $5::uuid, user_id
FROM inventory.users iu
WHERE iu.user_uid = $6::varchar
AND   NOT EXISTS (
	SELECT repository_id
	FROM   soma.repositories
	WHERE  repository_id = $1::uuid
	OR     repository_name = $2::varchar);`)
	if err != nil {
		log.Fatal("repository/add: ", err)
	}
	defer f.add_stmt.Close()

	f.load_stmt, err = f.conn.Prepare(`
SELECT repository_id,
	   repository_name,
	   repository_deleted,
	   repository_active,
	   organizational_team_id
FROM   soma.repositories;`)
	if err != nil {
		log.Fatal("repository/load: ", err)
	}
	defer f.load_stmt.Close()

	f.name_stmt, err = f.conn.Prepare(`
SELECT repository_name,
       organizational_team_id
FROM   soma.repositories
WHERE  repository_id = $1::uuid;`)
	if err != nil {
		log.Fatal("forestCustodian/reponame-by-id: ", err)
	}
	defer f.name_stmt.Close()

	if f.rbck_stmt, err = f.conn.Prepare(
		stmt.ForestRebuildDeleteChecks,
	); err != nil {
		log.Fatal("forestCustodian/delete-checks-for-repo: ", err)
	}
	defer f.rbck_stmt.Close()

	if f.rbci_stmt, err = f.conn.Prepare(
		stmt.ForestRebuildDeleteInstances,
	); err != nil {
		log.Fatal("forestCustodian/delete-check-instances-for-repo: ",
			err)
	}
	defer f.rbci_stmt.Close()

	f.initialLoad()

runloop:
	for {
		select {
		case <-f.shutdown:
			break runloop
		case req := <-f.input:
			f.process(&req)
		case req := <-f.system:
			f.sysprocess(&req)
		}
	}
}

func (f *forestCustodian) process(q *somaRepositoryRequest) {
	var (
		res        sql.Result
		err        error
		sTree      *tree.Tree
		actionChan chan *tree.Action
		errChan    chan *tree.Error
		team       string
	)
	result := somaResult{}

	switch q.action {
	case "add":
		log.Printf(LogStrReq,
			`ForestCustodian`,
			fmt.Sprintf("%s/%s", `CreateRepository`, q.Repository.Name),
			q.user, q.remoteAddr,
		)
		actionChan = make(chan *tree.Action, 1024000)
		errChan = make(chan *tree.Error, 1024000)

		id := uuid.NewV4()
		q.Repository.Id = id.String()

		sTree = tree.New(tree.TreeSpec{
			Id:     uuid.NewV4().String(),
			Name:   fmt.Sprintf("root_%s", q.Repository.Name),
			Action: actionChan,
		})
		tree.NewRepository(tree.RepositorySpec{
			Id:      q.Repository.Id,
			Name:    q.Repository.Name,
			Team:    q.Repository.TeamId,
			Deleted: false,
			Active:  q.Repository.IsActive,
		}).Attach(tree.AttachRequest{
			Root:       sTree,
			ParentType: "root",
			ParentId:   sTree.GetID(),
		})
		sTree.SetError(errChan)

		for i := len(actionChan); i > 0; i-- {
			action := <-actionChan
			switch action.Action {
			case "create":
				if action.Type == "fault" {
					continue
				}
				if action.Type == "repository" {
					res, err = f.add_stmt.Exec(
						action.Repository.Id,
						action.Repository.Name,
						action.Repository.IsActive,
						false,
						action.Repository.TeamId,
						q.user,
					)
					team = action.Repository.TeamId
				}
			case "attached":
			default:
				log.Printf("R: Unhandled action during tree creation: %s", q.action)
				result.SetNotImplemented()
				q.reply <- result
				return
			}
		}
	default:
		log.Printf("R: unimplemented repository/%s", q.action)
		result.SetNotImplemented()
		q.reply <- result
		return
	}
	if result.SetRequestError(err) {
		q.reply <- result
		return
	}

	rowCnt, _ := res.RowsAffected()
	switch {
	case rowCnt == 0:
		result.Append(errors.New("No rows affected"), &somaRepositoryResult{})
	case rowCnt > 1:
		result.Append(fmt.Errorf("Too many rows affected: %d", rowCnt),
			&somaRepositoryResult{})
	default:
		if team == "" {
			result.SetRequestError(
				fmt.Errorf("Team has not been set prior to spawning TreeKeeper for repo: %s", q.Repository.Name),
			)
			q.reply <- result
			return
		}
		result.Append(nil, &somaRepositoryResult{
			Repository: q.Repository,
		})
		if q.action == "add" {
			f.spawnTreeKeeper(q, sTree, errChan, actionChan, team)
		}
	}
	q.reply <- result
}

func (f *forestCustodian) sysprocess(q *msg.Request) {
	var (
		repoId, repoName, teamId, keeper string
		err                              error
		handler                          *treeKeeper
	)
	result := msg.Result{
		Type:   `guidepost`,
		Action: `systemoperation`,
		System: []proto.SystemOperation{q.System},
	}

	switch q.System.Request {
	case `rebuild_repository`:
		repoId = q.System.RepositoryId
	default:
		result.NotImplemented(
			fmt.Errorf("Unknown requested system operation: %s",
				q.System.Request),
		)
		goto exit
	}

	// look up name of the repository
	if err = f.name_stmt.QueryRow(repoId).
		Scan(&repoName, &teamId); err != nil {
		if err == sql.ErrNoRows {
			result.NotFound(fmt.Errorf(`No such repository`))
		} else {
			result.ServerError(err)
		}
		goto exit
	}

	// get the treekeeper for the repository
	keeper = fmt.Sprintf("repository_%s", repoName)
	if _, ok := handlerMap[keeper].(*treeKeeper); !ok {
		result.NotFound(
			fmt.Errorf("No handler for repository %s registered.",
				repoName),
		)
		goto exit
	}

	// stop the handler if it is still running
	if !handler.isStopped() {
		handler.stopchan <- true
	}

	// remove handler from lookup table and shut it down
	delete(handlerMap, keeper)
	handler.shutdown <- true

	// mark all existing check instances as deleted - instances
	// are deleted for both rebuild levels checks and instances
	if _, err = f.rbci_stmt.Exec(repoId); err != nil {
		result.ServerError(err)
		goto exit
	}
	// only delete checks for rebuild level checks
	if q.System.RebuildLevel == `checks` {
		if _, err = f.rbck_stmt.Exec(repoId); err != nil {
			result.ServerError(err)
			goto exit
		}
	}

	// load the tree again, with requested rebuild active
	f.loadSomaTree(&somaRepositoryRequest{
		rebuild: true,
		rbLevel: q.System.RebuildLevel,
		Repository: proto.Repository{
			Id:        repoId,
			Name:      repoName,
			TeamId:    teamId,
			IsDeleted: false,
			IsActive:  true,
		},
	})

	// rebuild has finished, restart the tree. If the rebuild did not
	// work, this will simply be a broken tree once more
	f.loadSomaTree(&somaRepositoryRequest{
		rebuild: false,
		rbLevel: "",
		Repository: proto.Repository{
			Id:        repoId,
			Name:      repoName,
			TeamId:    teamId,
			IsDeleted: false,
			IsActive:  true,
		},
	})
	result.OK()

exit:
	q.Reply <- result
}

func (f *forestCustodian) initialLoad() {
	var (
		rows                     *sql.Rows
		err                      error
		repoId, repoName, teamId string
		repoActive, repoDeleted  bool
	)
	log.Printf("Loading existing repositories")
	rows, err = f.load_stmt.Query()
	if err != nil {
		log.Fatal("Error loading repositories: ", err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(
			&repoId,
			&repoName,
			&repoDeleted,
			&repoActive,
			&teamId,
		)
		if err != nil {
			log.Printf("Error: %s", err.Error())
		}
		f.loadSomaTree(&somaRepositoryRequest{
			Repository: proto.Repository{
				Id:        repoId,
				Name:      repoName,
				TeamId:    teamId,
				IsDeleted: repoDeleted,
				IsActive:  repoActive,
			},
		})
	}
}

func (f *forestCustodian) loadSomaTree(q *somaRepositoryRequest) {
	actionChan := make(chan *tree.Action, 1024000)
	errChan := make(chan *tree.Error, 1024000)

	sTree := tree.New(tree.TreeSpec{
		Id:     uuid.NewV4().String(),
		Name:   fmt.Sprintf("root_%s", q.Repository.Name),
		Action: actionChan,
	})
	tree.NewRepository(tree.RepositorySpec{
		Id:      q.Repository.Id,
		Name:    q.Repository.Name,
		Team:    q.Repository.TeamId,
		Deleted: q.Repository.IsDeleted,
		Active:  q.Repository.IsActive,
	}).Attach(tree.AttachRequest{
		Root:       sTree,
		ParentType: "root",
		ParentId:   sTree.GetID(),
	})
	sTree.SetError(errChan)
	for i := len(actionChan); i > 0; i-- {
		// discard actions on initial load
		<-actionChan
	}
	for i := len(errChan); i > 0; i-- {
		// discard actions on initial load
		<-errChan
	}
	f.spawnTreeKeeper(q, sTree, errChan, actionChan, q.Repository.TeamId)
}

func (f *forestCustodian) spawnTreeKeeper(q *somaRepositoryRequest, s *tree.Tree,
	ec chan *tree.Error, ac chan *tree.Action, team string) {

	// only start the single requested repo in observer mode with
	// set repo flag
	if SomaCfg.Observer && SomaCfg.ObserverRepo != `` && q.Repository.Name != SomaCfg.ObserverRepo {
		return
	}

	db, err := newDatabaseConnection()
	if err != nil {
		return
	}
	tK := new(treeKeeper)
	tK.input = make(chan treeRequest, 1024)
	tK.shutdown = make(chan bool)
	tK.conn = db
	tK.tree = s
	tK.errChan = ec
	tK.actionChan = ac
	tK.broken = false
	tK.ready = false
	tK.frozen = false
	tK.stopped = false
	tK.rebuild = q.rebuild
	tK.rbLevel = q.rbLevel
	tK.repoId = q.Repository.Id
	tK.repoName = q.Repository.Name
	tK.team = team
	keeperName := fmt.Sprintf("repository_%s", q.Repository.Name)

	// during rebuild the treekeeper will not run in background
	if tK.rebuild {
		tK.run()
	} else {
		// non-rebuild, register TK and detach
		handlerMap[keeperName] = tK
		go tK.run()
	}
}

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


<commit_before>package main

import (
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"

	"github.com/couchbaselabs/gateload/api"
	"github.com/couchbaselabs/gateload/workload"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	// start up an http server, just to serve up expvars
	go http.ListenAndServe(":9876", nil)

	var config workload.Config
	workload.ReadConfig(&config)

	admin := api.SyncGatewayClient{}
	admin.Init(
		config.Hostname,
		config.Database,
		config.Port,
		config.AdminPort,
		config.LogRequests,
	)
	if !admin.Valid() {
		log.Fatalf("unable to connect to sync_gateway, check the hostname and database")
	}

	pendingUsers := make(chan *workload.User)
	users := make([]*workload.User, config.NumPullers+config.NumPushers)

	// start a routine to place pending users into array
	go func() {
		for pendingUser := range pendingUsers {

			// users = append(users, pendingUser)
			users[pendingUser.SeqId-config.UserOffset] = pendingUser
		}
	}()

	rampUpDelay := config.RampUpIntervalMs / (config.NumPullers + config.NumPushers)

	// use a fixed number of workers to create the users/sessions
	userIterator := workload.UserIterator(
		config.NumPullers,
		config.NumPushers,
		config.UserOffset,
		config.ChannelActiveUsers,
		config.ChannelConcurrentUsers,
		config.MinUserOffTimeMs,
		config.MaxUserOffTimeMs,
		rampUpDelay,
		config.RunTimeMs,
	)
	adminWg := sync.WaitGroup{}
	worker := func() {
		defer adminWg.Done()
		for user := range userIterator {
			createSession(&admin, user, config)
			pendingUsers <- user
		}
	}

	for i := 0; i < 16; i++ {
		adminWg.Add(1)
		go worker()
	}

	// wait for all the workers to finish
	adminWg.Wait()
	// close the pending users channel to free that routine
	close(pendingUsers)

	numChannels := (config.NumPullers + config.NumPushers) / config.ChannelActiveUsers
	channelRampUpDelayMs := time.Duration(config.RampUpIntervalMs/numChannels) * time.Millisecond

	wg := sync.WaitGroup{}
	channel := ""
	for _, user := range users {
		nextChannel := user.Channel
		if channel != nextChannel {
			if channel != "" {
				time.Sleep(channelRampUpDelayMs)
			}
			channel = nextChannel
		}
		wg := sync.WaitGroup{}
		go runUser(user, config, &wg)
		wg.Add(1)
	}

	if config.RunTimeMs > 0 {
		time.Sleep(time.Duration(config.RunTimeMs-config.RampUpIntervalMs) * time.Millisecond)
		log.Println("Shutting down clients")
	} else {
		wg.Wait()
	}
}

func createSession(admin *api.SyncGatewayClient, user *workload.User, config workload.Config) {
	userMeta := api.UserAuth{
		Name:          user.Name,
		Password:      "password",
		AdminChannels: []string{user.Channel},
	}
	admin.AddUser(user.Name, userMeta)

	session := api.Session{Name: user.Name, TTL: 2592000} // 1 month
	user.Cookie = admin.CreateSession(user.Name, session)
}

func runUser(user *workload.User, config workload.Config, wg *sync.WaitGroup) {
	c := api.SyncGatewayClient{}
	c.Init(
		config.Hostname,
		config.Database,
		config.Port,
		config.AdminPort,
		config.LogRequests,
	)
	c.AddCookie(&user.Cookie)

	log.Printf("Starting new %s (%s)", user.Type, user.Name)
	if user.Type == "pusher" {
		go workload.RunNewPusher(
			user.Schedule,
			user.Name,
			&c,
			user.Channel,
			config.DocSize,
			config.SendAttachment,
			config.DocSizeDistribution,
			user.SeqId,
			config.SleepTimeMs,
			wg,
		)
	} else {
		go workload.RunNewPuller(
			user.Schedule,
			&c,
			user.Channel,
			user.Name,
			config.FeedType,
			wg,
		)
	}

}
<commit_msg>Add some comments that had been added on gateload1<commit_after>package main

import (
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"

	"github.com/couchbaselabs/gateload/api"
	"github.com/couchbaselabs/gateload/workload"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	// start up an http server, just to serve up expvars
	go http.ListenAndServe(":9876", nil)

	var config workload.Config
	workload.ReadConfig(&config)

	admin := api.SyncGatewayClient{}
	admin.Init(
		config.Hostname,
		config.Database,
		config.Port,
		config.AdminPort,
		config.LogRequests,
	)
	if !admin.Valid() {
		log.Fatalf("unable to connect to sync_gateway, check the hostname and database")
	}

	pendingUsers := make(chan *workload.User)
	users := make([]*workload.User, config.NumPullers+config.NumPushers)

	// start a routine to place pending users into array
	go func() {
		for pendingUser := range pendingUsers {

			// users = append(users, pendingUser)
			users[pendingUser.SeqId-config.UserOffset] = pendingUser
		}
	}()

	rampUpDelay := config.RampUpIntervalMs / (config.NumPullers + config.NumPushers)

	// use a fixed number of workers to create the users/sessions
	userIterator := workload.UserIterator(
		config.NumPullers,
		config.NumPushers,
		config.UserOffset,
		config.ChannelActiveUsers,
		config.ChannelConcurrentUsers,
		config.MinUserOffTimeMs,
		config.MaxUserOffTimeMs,
		rampUpDelay,
		config.RunTimeMs,
	)
	adminWg := sync.WaitGroup{}
	worker := func() {
		defer adminWg.Done()
		for user := range userIterator {
			createSession(&admin, user, config)
			pendingUsers <- user
		}
	}

	for i := 0; i < 16; i++ {
		adminWg.Add(1)
		go worker()
	}

	// wait for all the workers to finish
	adminWg.Wait()
	// close the pending users channel to free that routine
	close(pendingUsers)

	numChannels := (config.NumPullers + config.NumPushers) / config.ChannelActiveUsers
	channelRampUpDelayMs := time.Duration(config.RampUpIntervalMs/numChannels) * time.Millisecond

	wg := sync.WaitGroup{}
	channel := ""
	for _, user := range users {
		nextChannel := user.Channel
		if channel != nextChannel {
			if channel != "" {
				time.Sleep(channelRampUpDelayMs)
			}
			channel = nextChannel
		}
		wg := sync.WaitGroup{}
		go runUser(user, config, &wg)
		wg.Add(1)
	}

	if config.RunTimeMs > 0 {
		time.Sleep(time.Duration(config.RunTimeMs-config.RampUpIntervalMs) * time.Millisecond)
		log.Println("Shutting down clients")
	} else {
		wg.Wait()
	}
}

func createSession(admin *api.SyncGatewayClient, user *workload.User, config workload.Config) {
	userMeta := api.UserAuth{
		Name:          user.Name,
		Password:      "password",
		AdminChannels: []string{user.Channel},
	}
	admin.AddUser(user.Name, userMeta)

	session := api.Session{Name: user.Name, TTL: 2592000} // 1 month
	log.Printf("====== Creating new session for %s (%s)", user.Type, user.Name)
	user.Cookie = admin.CreateSession(user.Name, session)
	log.Printf("====== Done Creating new session for %s (%s)", user.Type, user.Name)

}

func runUser(user *workload.User, config workload.Config, wg *sync.WaitGroup) {
	c := api.SyncGatewayClient{}
	c.Init(
		config.Hostname,
		config.Database,
		config.Port,
		config.AdminPort,
		config.LogRequests,
	)
	c.AddCookie(&user.Cookie)

	log.Printf("Starting new %s (%s)", user.Type, user.Name)
	if user.Type == "pusher" {
		go workload.RunNewPusher(
			user.Schedule,
			user.Name,
			&c,
			user.Channel,
			config.DocSize,
			config.SendAttachment,
			config.DocSizeDistribution,
			user.SeqId,
			config.SleepTimeMs,
			wg,
		)
	} else {
		go workload.RunNewPuller(
			user.Schedule,
			&c,
			user.Channel,
			user.Name,
			config.FeedType,
			wg,
		)
	}
	log.Printf("------ Done Starting new %s (%s)", user.Type, user.Name)

}
<|endoftext|>


<commit_before>package main

import (
	"os"

	log "github.com/Sirupsen/logrus"

	"github.com/ernoaapa/fetch-ssh-keys/fetch"
	"github.com/ernoaapa/fetch-ssh-keys/output"
	"github.com/urfave/cli"
)

// Version string to be set at compile time via command line (-ldflags "-X main.VersionString=1.2.3")
var (
	VersionString string
)

// StatsdConfig for statsd client
type StatsdConfig struct {
	Host       string `default:"localhost"`
	Port       int    `default:"8125"`
	Prefix     string `default:"stats"`
	MetricName string `envconfig:"metric_name",required:"true"`
}

func main() {
	app := cli.NewApp()
	app.Name = "fetch-ssh-keys"
	app.Usage = "Fetch user public SSH keys"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "format, f",
			Usage: "Output format. One of: ssh",
			Value: "ssh",
		},
		cli.StringFlag{
			Name:  "file-mode",
			Usage: "File permissions for file",
			Value: "0600",
		},
	}
	app.Version = VersionString
	app.Commands = []cli.Command{
		{
			Name:  "github",
			Usage: "Get user GitHub public SSH key",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "organization, o",
					Usage:  "GitHub organization which users public keys to get",
					EnvVar: "GITHUB_ORGANIZATION",
				},
				cli.StringFlag{
					Name:   "token, t",
					Usage:  "GitHub access token",
					EnvVar: "GITHUB_TOKEN",
				},
				cli.BoolFlag{
					Name:  "public-only",
					Usage: "Return only public members of organization",
				},
				cli.StringFlag{
					Name:  "team",
					Usage: "Return only members of one team",
				},
			},
			Action: func(c *cli.Context) error {
				if c.String("organization") == "" {
					log.Fatalln("You must give --organization value")
				}

				keys, err := fetch.GitHubKeys(c.String("organization"), fetch.GithubFetchParams{
					Token:             c.String("token"),
					TeamName:          c.String("team"),
					PublicMembersOnly: c.Bool("public-only"),
				})
				if err != nil {
					log.Fatalln("Failed to fetch keys", err)
				}

				return output.Write(c.GlobalString("format"), c.Args().Get(0), os.FileMode(c.GlobalInt("file-mode")), keys)
			},
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Cleanup unused code<commit_after>package main

import (
	"os"

	log "github.com/Sirupsen/logrus"

	"github.com/ernoaapa/fetch-ssh-keys/fetch"
	"github.com/ernoaapa/fetch-ssh-keys/output"
	"github.com/urfave/cli"
)

// Version string to be set at compile time via command line (-ldflags "-X main.VersionString=1.2.3")
var (
	VersionString string
)

func main() {
	app := cli.NewApp()
	app.Name = "fetch-ssh-keys"
	app.Usage = "Fetch user public SSH keys"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "format, f",
			Usage: "Output format. One of: ssh",
			Value: "ssh",
		},
		cli.StringFlag{
			Name:  "file-mode",
			Usage: "File permissions for file",
			Value: "0600",
		},
	}
	app.Version = VersionString
	app.Commands = []cli.Command{
		{
			Name:  "github",
			Usage: "Get user GitHub public SSH key",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "organization, o",
					Usage:  "GitHub organization which users public keys to get",
					EnvVar: "GITHUB_ORGANIZATION",
				},
				cli.StringFlag{
					Name:   "token, t",
					Usage:  "GitHub access token",
					EnvVar: "GITHUB_TOKEN",
				},
				cli.BoolFlag{
					Name:  "public-only",
					Usage: "Return only public members of organization",
				},
				cli.StringFlag{
					Name:  "team",
					Usage: "Return only members of one team",
				},
			},
			Action: func(c *cli.Context) error {
				if c.String("organization") == "" {
					log.Fatalln("You must give --organization value")
				}

				keys, err := fetch.GitHubKeys(c.String("organization"), fetch.GithubFetchParams{
					Token:             c.String("token"),
					TeamName:          c.String("team"),
					PublicMembersOnly: c.Bool("public-only"),
				})
				if err != nil {
					log.Fatalln("Failed to fetch keys", err)
				}

				return output.Write(c.GlobalString("format"), c.Args().Get(0), os.FileMode(c.GlobalInt("file-mode")), keys)
			},
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"net/http"

	"strings"
	"syscall"

	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/op/go-logging"
	"github.com/pressly/gohttpware/auth"
	"github.com/pressly/gohttpware/route"
	"github.com/zenazn/goji/graceful"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var (
	configPath = flag.String("config-file", "./config.toml", "path to qmd config file")
	log        = logging.MustGetLogger("qmd")

	config   Config
	producer *nsq.Producer
	consumer *nsq.Consumer
	redisDB  *redis.Pool
)

const (
	VERSION = "0.1.0"
)

func main() {
	var err error

	flag.Parse()

	// Server config
	err = config.Load(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	err = config.Setup()
	if err != nil {
		log.Fatal(err)
	}

	log.Info("=====> [ QMD v%s ] <=====", VERSION)

	// Setup facilities
	producer, err = nsq.NewProducer(config.QueueAddr, nsq.NewConfig())
	if err != nil {
		log.Fatal(err)
	}
	redisDB = newRedisPool(config.RedisAddr)

	// Script processing worker
	worker, err := NewWorker(config)
	if err != nil {
		log.Fatal(err)
	}
	go worker.Run()

	// Http server
	w := web.New()

	w.Use(middleware.Logger)
	w.Use(middleware.Recoverer)
	w.Use(Heartbeat)
	if config.Auth.Enabled {
		basicAuthWithRedis := func(r *http.Request, s []string) bool {
			user, pass := s[0], s[1]
			check, err := checkRedisUser(user)
			if err != nil || check != true {
				log.Error(err.Error())
				return false
			}

			authString := fmt.Sprintf("%s:%s", user, pass)
			auth := r.Header.Get("Authorization")
			if !strings.HasPrefix(auth, "Basic ") {
				return false
			}
			p, err := base64.StdEncoding.DecodeString(auth[6:])
			if err != nil || string(p) != authString {
				err = failRedisUser(user)
				if err != nil {
					log.Error(err.Error())
				}
				return false
			}
			return true
		}

		authFunc := auth.Wrap(
			basicAuthWithRedis,
			"Restricted",
			config.Auth.Username,
			config.Auth.Password,
		)
		w.Use(authFunc)
	}
	w.Use(route.AllowSlash)

	w.Get("/scripts", GetAllScripts)
	w.Put("/scripts", ReloadScripts)
	w.Post("/scripts/:name", RunScript)
	w.Get("/scripts/:name/logs", GetAllLogs)
	w.Get("/scripts/:name/logs/:id", GetLog)
	w.Handle("/*", AdminProxy)

	// Spin up the server with graceful hooks
	graceful.PreHook(func() {
		log.Info("Stopping queue producer")
		producer.Stop()

		log.Info("Stopping queue workers")
		worker.Stop()

		log.Info("Closing redis connections")
		redisDB.Close()
	})

	graceful.AddSignal(syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	err = graceful.ListenAndServe(config.ListenOnAddr, w)
	if err != nil {
		log.Fatal(err)
	}
	graceful.Wait()
}
<commit_msg>Fixed crashing error when err is nil.<commit_after>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"net/http"

	"strings"
	"syscall"

	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/op/go-logging"
	"github.com/pressly/gohttpware/auth"
	"github.com/pressly/gohttpware/route"
	"github.com/zenazn/goji/graceful"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var (
	configPath = flag.String("config-file", "./config.toml", "path to qmd config file")
	log        = logging.MustGetLogger("qmd")

	config   Config
	producer *nsq.Producer
	consumer *nsq.Consumer
	redisDB  *redis.Pool
)

const (
	VERSION = "0.1.0"
)

func main() {
	var err error

	flag.Parse()

	// Server config
	err = config.Load(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	err = config.Setup()
	if err != nil {
		log.Fatal(err)
	}

	log.Info("=====> [ QMD v%s ] <=====", VERSION)

	// Setup facilities
	producer, err = nsq.NewProducer(config.QueueAddr, nsq.NewConfig())
	if err != nil {
		log.Fatal(err)
	}
	redisDB = newRedisPool(config.RedisAddr)

	// Script processing worker
	worker, err := NewWorker(config)
	if err != nil {
		log.Fatal(err)
	}
	go worker.Run()

	// Http server
	w := web.New()

	w.Use(middleware.Logger)
	w.Use(middleware.Recoverer)
	w.Use(Heartbeat)
	if config.Auth.Enabled {
		basicAuthWithRedis := func(r *http.Request, s []string) bool {
			user, pass := s[0], s[1]
			check, err := checkRedisUser(user)
			if err != nil {
				log.Error(err.Error())
				return false
			}
			if check != true {
				log.Error("User: %s is blocked", user)
				return false
			}

			authString := fmt.Sprintf("%s:%s", user, pass)
			auth := r.Header.Get("Authorization")
			if !strings.HasPrefix(auth, "Basic ") {
				return false
			}
			p, err := base64.StdEncoding.DecodeString(auth[6:])
			if err != nil || string(p) != authString {
				err = failRedisUser(user)
				if err != nil {
					log.Error(err.Error())
				}
				return false
			}
			return true
		}

		authFunc := auth.Wrap(
			basicAuthWithRedis,
			"Restricted",
			config.Auth.Username,
			config.Auth.Password,
		)
		w.Use(authFunc)
	}
	w.Use(route.AllowSlash)

	w.Get("/scripts", GetAllScripts)
	w.Put("/scripts", ReloadScripts)
	w.Post("/scripts/:name", RunScript)
	w.Get("/scripts/:name/logs", GetAllLogs)
	w.Get("/scripts/:name/logs/:id", GetLog)
	w.Handle("/*", AdminProxy)

	// Spin up the server with graceful hooks
	graceful.PreHook(func() {
		log.Info("Stopping queue producer")
		producer.Stop()

		log.Info("Stopping queue workers")
		worker.Stop()

		log.Info("Closing redis connections")
		redisDB.Close()
	})

	graceful.AddSignal(syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	err = graceful.ListenAndServe(config.ListenOnAddr, w)
	if err != nil {
		log.Fatal(err)
	}
	graceful.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"os/signal"
	"time"

	pb "github.com/noffle/ipget/Godeps/_workspace/src/github.com/cheggaaa/pb"
	humanize "github.com/noffle/ipget/Godeps/_workspace/src/github.com/dustin/go-humanize"
	core "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/core"
	path "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/path"
	uarchive "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/unixfs/archive"
	cli "github.com/noffle/ipget/Godeps/_workspace/src/github.com/jawher/mow.cli"
	tar "github.com/noffle/ipget/Godeps/_workspace/src/github.com/whyrusleeping/tar-utils"
	context "github.com/noffle/ipget/Godeps/_workspace/src/golang.org/x/net/context"
)

func main() {
	cmd := cli.App("ipget", "Retrieve and save IPFS objects.")
	cmd.Spec = "IPFS_PATH [-o]"

	hash := cmd.String(cli.StringArg{
		Name:  "IPFS_PATH",
		Value: "",
		Desc:  "the IPFS object path",
	})

	outFile := cmd.StringOpt("o output", "", "output file path")

	cmd.Action = func() {
		// Use the final segment of the object's path if no path was given.
		if *outFile == "" {
			ipfsPath, err := path.ParsePath(*hash)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ParsePath failure: %s", err)
				os.Exit(1)
			}
			segments := ipfsPath.Segments()
			*outFile = segments[len(segments)-1]
		}

		if err := get(*hash, *outFile); err != nil {
			os.Remove(*outFile)
			fmt.Fprintf(os.Stderr, "ipget failed: %s\n", err)
			os.Exit(2)
		}
	}
	cmd.Run(os.Args)
}

func get(path, outFile string) error {
	start := time.Now()
	ctx, cancel := context.WithCancel(context.Background())

	// Cancel the ipfs node context if the process gets interrupted or killed.
	go func() {
		interrupts := make(chan os.Signal, 1)
		signal.Notify(interrupts, os.Interrupt, os.Kill)
		<-interrupts
		cancel()
	}()

	// Create the ipfs node.
	node, err := core.NewNode(ctx, &core.BuildCfg{
		Online: true,
	})
	if err != nil {
		return fmt.Errorf("ipfs NewNode() failed: %s", err)
	}

	// Bootstrap.
	err = node.Bootstrap(core.DefaultBootstrapConfig)
	if err != nil {
		return fmt.Errorf("node Bootstrap() failed: %s", err)
	}
	fmt.Fprintf(os.Stderr, "IPFS Node bootstrapping (took %v)\n", time.Since(start))

	// Get a reader for downloading the object content.
	reader, length, err := cat(node.Context(), node, path)
	if err != nil {
		return fmt.Errorf("cat failed: %s", err)
	}

	bar, barR := progressBarForReader(os.Stderr, reader, int(length))
	bar.ShowSpeed = false
	bar.Start()

	// Stream the file content from the IPFS node to the output file.
	extractor := &tar.Extractor{outFile}
	if err := extractor.Extract(barR); err != nil {
		return fmt.Errorf("copy failed: %s", err)
	}

	// Done!
	bar.Finish()
	fmt.Fprintf(os.Stderr, "Wrote %q to %q (%s) (took %v)\n", path, outFile,
		humanize.Bytes(length), time.Since(start))

	return nil
}

func cat(ctx context.Context, node *core.IpfsNode, fpath string) (io.Reader, uint64, error) {
	dagnode, err := core.Resolve(ctx, node, path.Path(fpath))
	if err != nil {
		return nil, 0, err
	}

	reader, err := uarchive.DagArchive(node.Context(), dagnode, fpath, node.DAG, false, 0)
	if err != nil {
		return nil, 0, err
	}

	// TODO: modify uarchive.DagArchive to output pb size
	length, err := dagnode.Size()
	if err != nil {
		return nil, 0, err
	}
	return reader, length, nil

func progressBarForReader(out io.Writer, r io.Reader, l int) (*pb.ProgressBar, *pb.Reader) {
	// setup bar reader
	bar := pb.New(l).SetUnits(pb.U_BYTES)
	bar.Output = out
	barR := bar.NewProxyReader(r)
	return bar, barR
}
<commit_msg>Fixes the build (testing Travis).<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"os/signal"
	"time"

	pb "github.com/noffle/ipget/Godeps/_workspace/src/github.com/cheggaaa/pb"
	humanize "github.com/noffle/ipget/Godeps/_workspace/src/github.com/dustin/go-humanize"
	core "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/core"
	path "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/path"
	uarchive "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/unixfs/archive"
	cli "github.com/noffle/ipget/Godeps/_workspace/src/github.com/jawher/mow.cli"
	tar "github.com/noffle/ipget/Godeps/_workspace/src/github.com/whyrusleeping/tar-utils"
	context "github.com/noffle/ipget/Godeps/_workspace/src/golang.org/x/net/context"
)

func main() {
	cmd := cli.App("ipget", "Retrieve and save IPFS objects.")
	cmd.Spec = "IPFS_PATH [-o]"

	hash := cmd.String(cli.StringArg{
		Name:  "IPFS_PATH",
		Value: "",
		Desc:  "the IPFS object path",
	})

	outFile := cmd.StringOpt("o output", "", "output file path")

	cmd.Action = func() {
		// Use the final segment of the object's path if no path was given.
		if *outFile == "" {
			ipfsPath, err := path.ParsePath(*hash)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ParsePath failure: %s", err)
				os.Exit(1)
			}
			segments := ipfsPath.Segments()
			*outFile = segments[len(segments)-1]
		}

		if err := get(*hash, *outFile); err != nil {
			os.Remove(*outFile)
			fmt.Fprintf(os.Stderr, "ipget failed: %s\n", err)
			os.Exit(2)
		}
	}
	cmd.Run(os.Args)
}

func get(path, outFile string) error {
	start := time.Now()
	ctx, cancel := context.WithCancel(context.Background())

	// Cancel the ipfs node context if the process gets interrupted or killed.
	go func() {
		interrupts := make(chan os.Signal, 1)
		signal.Notify(interrupts, os.Interrupt, os.Kill)
		<-interrupts
		cancel()
	}()

	// Create the ipfs node.
	node, err := core.NewNode(ctx, &core.BuildCfg{
		Online: true,
	})
	if err != nil {
		return fmt.Errorf("ipfs NewNode() failed: %s", err)
	}

	// Bootstrap.
	err = node.Bootstrap(core.DefaultBootstrapConfig)
	if err != nil {
		return fmt.Errorf("node Bootstrap() failed: %s", err)
	}
	fmt.Fprintf(os.Stderr, "IPFS Node bootstrapping (took %v)\n", time.Since(start))

	// Get a reader for downloading the object content.
	reader, length, err := cat(node.Context(), node, path)
	if err != nil {
		return fmt.Errorf("cat failed: %s", err)
	}

	bar, barR := progressBarForReader(os.Stderr, reader, int(length))
	bar.ShowSpeed = false
	bar.Start()

	// Stream the file content from the IPFS node to the output file.
	extractor := &tar.Extractor{outFile}
	if err := extractor.Extract(barR); err != nil {
		return fmt.Errorf("copy failed: %s", err)
	}

	// Done!
	bar.Finish()
	fmt.Fprintf(os.Stderr, "Wrote %q to %q (%s) (took %v)\n", path, outFile,
		humanize.Bytes(length), time.Since(start))

	return nil
}

func cat(ctx context.Context, node *core.IpfsNode, fpath string) (io.Reader, uint64, error) {
	dagnode, err := core.Resolve(ctx, node, path.Path(fpath))
	if err != nil {
		return nil, 0, err
	}

	reader, err := uarchive.DagArchive(node.Context(), dagnode, fpath, node.DAG, false, 0)
	if err != nil {
		return nil, 0, err
	}

	// TODO: modify uarchive.DagArchive to output pb size
	length, err := dagnode.Size()
	if err != nil {
		return nil, 0, err
	}
	return reader, length, nil
}

func progressBarForReader(out io.Writer, r io.Reader, l int) (*pb.ProgressBar, *pb.Reader) {
	// setup bar reader
	bar := pb.New(l).SetUnits(pb.U_BYTES)
	bar.Output = out
	barR := bar.NewProxyReader(r)
	return bar, barR
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"runtime"
	"runtime/debug"

	"github.com/eBay/fabio/admin"
	"github.com/eBay/fabio/config"
	"github.com/eBay/fabio/exit"
	"github.com/eBay/fabio/metrics"
	"github.com/eBay/fabio/proxy"
	"github.com/eBay/fabio/registry"
	"github.com/eBay/fabio/registry/consul"
	"github.com/eBay/fabio/registry/file"
	"github.com/eBay/fabio/registry/static"
	"github.com/eBay/fabio/route"
)

// version contains the version number
//
// It is set by build/release.sh for tagged releases
// so that 'go get' just works.
//
// It is also set by the linker when fabio
// is built via the Makefile or the build/docker.sh
// script to ensure the correct version nubmer
var version = "1.3.5"

func main() {
	cfg, err := config.Load(os.Args, os.Environ())
	if err != nil {
		exit.Fatalf("[FATAL] %s. %s", version, err)
	}
	if cfg == nil {
		fmt.Println(version)
		return
	}

	log.Printf("[INFO] Runtime config\n" + toJSON(cfg))
	log.Printf("[INFO] Version %s starting", version)
	log.Printf("[INFO] Go runtime is %s", runtime.Version())

	exit.Listen(func(s os.Signal) {
		if registry.Default == nil {
			return
		}
		registry.Default.Deregister()
	})

	httpProxy := newHTTPProxy(cfg)
	tcpProxy := proxy.NewTCPSNIProxy(cfg.Proxy)

	initRuntime(cfg)
	initMetrics(cfg)
	initBackend(cfg)
	go watchBackend()
	startAdmin(cfg)
	startListeners(cfg.Listen, cfg.Proxy.ShutdownWait, httpProxy, tcpProxy)
	exit.Wait()
}

func newHTTPProxy(cfg *config.Config) http.Handler {
	if err := route.SetPickerStrategy(cfg.Proxy.Strategy); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing strategy %q", cfg.Proxy.Strategy)

	if err := route.SetMatcher(cfg.Proxy.Matcher); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing matching %q", cfg.Proxy.Matcher)

	tr := &http.Transport{
		ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout,
		MaxIdleConnsPerHost:   cfg.Proxy.MaxConn,
		Dial: (&net.Dialer{
			Timeout:   cfg.Proxy.DialTimeout,
			KeepAlive: cfg.Proxy.KeepAliveTimeout,
		}).Dial,
	}

	return proxy.NewHTTPProxy(tr, cfg.Proxy)
}

func startAdmin(cfg *config.Config) {
	log.Printf("[INFO] Admin server listening on %q", cfg.UI.Addr)
	go func() {
		if err := admin.ListenAndServe(cfg, version); err != nil {
			exit.Fatal("[FATAL] ui: ", err)
		}
	}()
}

func initMetrics(cfg *config.Config) {
	if cfg.Metrics.Target == "" {
		log.Printf("[INFO] Metrics disabled")
		return
	}

	var err error
	if metrics.DefaultRegistry, err = metrics.NewRegistry(cfg.Metrics); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
	if route.ServiceRegistry, err = metrics.NewRegistry(cfg.Metrics); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
}

func initRuntime(cfg *config.Config) {
	if os.Getenv("GOGC") == "" {
		log.Print("[INFO] Setting GOGC=", cfg.Runtime.GOGC)
		debug.SetGCPercent(cfg.Runtime.GOGC)
	} else {
		log.Print("[INFO] Using GOGC=", os.Getenv("GOGC"), " from env")
	}

	if os.Getenv("GOMAXPROCS") == "" {
		log.Print("[INFO] Setting GOMAXPROCS=", cfg.Runtime.GOMAXPROCS)
		runtime.GOMAXPROCS(cfg.Runtime.GOMAXPROCS)
	} else {
		log.Print("[INFO] Using GOMAXPROCS=", os.Getenv("GOMAXPROCS"), " from env")
	}
}

func initBackend(cfg *config.Config) {
	var err error

	switch cfg.Registry.Backend {
	case "file":
		registry.Default, err = file.NewBackend(cfg.Registry.File.Path)
	case "static":
		registry.Default, err = static.NewBackend(cfg.Registry.Static.Routes)
	case "consul":
		registry.Default, err = consul.NewBackend(&cfg.Registry.Consul)
	default:
		exit.Fatal("[FATAL] Unknown registry backend ", cfg.Registry.Backend)
	}

	if err != nil {
		exit.Fatal("[FATAL] Error initializing backend. ", err)
	}
	if err := registry.Default.Register(); err != nil {
		exit.Fatal("[FATAL] Error registering backend. ", err)
	}
}

func watchBackend() {
	var (
		last   string
		svccfg string
		mancfg string
	)

	svc := registry.Default.WatchServices()
	man := registry.Default.WatchManual()

	for {
		select {
		case svccfg = <-svc:
		case mancfg = <-man:
		}

		// manual config overrides service config
		// order matters
		next := svccfg + "\n" + mancfg
		if next == last {
			continue
		}

		t, err := route.NewTable(next)
		if err != nil {
			log.Printf("[WARN] %s", err)
			continue
		}
		route.SetTable(t)

		last = next
	}
}

func toJSON(v interface{}) string {
	data, err := json.MarshalIndent(v, "", "    ")
	if err != nil {
		panic("json: " + err.Error())
	}
	return string(data)
}
<commit_msg>Release v1.3.6<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"runtime"
	"runtime/debug"

	"github.com/eBay/fabio/admin"
	"github.com/eBay/fabio/config"
	"github.com/eBay/fabio/exit"
	"github.com/eBay/fabio/metrics"
	"github.com/eBay/fabio/proxy"
	"github.com/eBay/fabio/registry"
	"github.com/eBay/fabio/registry/consul"
	"github.com/eBay/fabio/registry/file"
	"github.com/eBay/fabio/registry/static"
	"github.com/eBay/fabio/route"
)

// version contains the version number
//
// It is set by build/release.sh for tagged releases
// so that 'go get' just works.
//
// It is also set by the linker when fabio
// is built via the Makefile or the build/docker.sh
// script to ensure the correct version nubmer
var version = "1.3.6"

func main() {
	cfg, err := config.Load(os.Args, os.Environ())
	if err != nil {
		exit.Fatalf("[FATAL] %s. %s", version, err)
	}
	if cfg == nil {
		fmt.Println(version)
		return
	}

	log.Printf("[INFO] Runtime config\n" + toJSON(cfg))
	log.Printf("[INFO] Version %s starting", version)
	log.Printf("[INFO] Go runtime is %s", runtime.Version())

	exit.Listen(func(s os.Signal) {
		if registry.Default == nil {
			return
		}
		registry.Default.Deregister()
	})

	httpProxy := newHTTPProxy(cfg)
	tcpProxy := proxy.NewTCPSNIProxy(cfg.Proxy)

	initRuntime(cfg)
	initMetrics(cfg)
	initBackend(cfg)
	go watchBackend()
	startAdmin(cfg)
	startListeners(cfg.Listen, cfg.Proxy.ShutdownWait, httpProxy, tcpProxy)
	exit.Wait()
}

func newHTTPProxy(cfg *config.Config) http.Handler {
	if err := route.SetPickerStrategy(cfg.Proxy.Strategy); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing strategy %q", cfg.Proxy.Strategy)

	if err := route.SetMatcher(cfg.Proxy.Matcher); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
	log.Printf("[INFO] Using routing matching %q", cfg.Proxy.Matcher)

	tr := &http.Transport{
		ResponseHeaderTimeout: cfg.Proxy.ResponseHeaderTimeout,
		MaxIdleConnsPerHost:   cfg.Proxy.MaxConn,
		Dial: (&net.Dialer{
			Timeout:   cfg.Proxy.DialTimeout,
			KeepAlive: cfg.Proxy.KeepAliveTimeout,
		}).Dial,
	}

	return proxy.NewHTTPProxy(tr, cfg.Proxy)
}

func startAdmin(cfg *config.Config) {
	log.Printf("[INFO] Admin server listening on %q", cfg.UI.Addr)
	go func() {
		if err := admin.ListenAndServe(cfg, version); err != nil {
			exit.Fatal("[FATAL] ui: ", err)
		}
	}()
}

func initMetrics(cfg *config.Config) {
	if cfg.Metrics.Target == "" {
		log.Printf("[INFO] Metrics disabled")
		return
	}

	var err error
	if metrics.DefaultRegistry, err = metrics.NewRegistry(cfg.Metrics); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
	if route.ServiceRegistry, err = metrics.NewRegistry(cfg.Metrics); err != nil {
		exit.Fatal("[FATAL] ", err)
	}
}

func initRuntime(cfg *config.Config) {
	if os.Getenv("GOGC") == "" {
		log.Print("[INFO] Setting GOGC=", cfg.Runtime.GOGC)
		debug.SetGCPercent(cfg.Runtime.GOGC)
	} else {
		log.Print("[INFO] Using GOGC=", os.Getenv("GOGC"), " from env")
	}

	if os.Getenv("GOMAXPROCS") == "" {
		log.Print("[INFO] Setting GOMAXPROCS=", cfg.Runtime.GOMAXPROCS)
		runtime.GOMAXPROCS(cfg.Runtime.GOMAXPROCS)
	} else {
		log.Print("[INFO] Using GOMAXPROCS=", os.Getenv("GOMAXPROCS"), " from env")
	}
}

func initBackend(cfg *config.Config) {
	var err error

	switch cfg.Registry.Backend {
	case "file":
		registry.Default, err = file.NewBackend(cfg.Registry.File.Path)
	case "static":
		registry.Default, err = static.NewBackend(cfg.Registry.Static.Routes)
	case "consul":
		registry.Default, err = consul.NewBackend(&cfg.Registry.Consul)
	default:
		exit.Fatal("[FATAL] Unknown registry backend ", cfg.Registry.Backend)
	}

	if err != nil {
		exit.Fatal("[FATAL] Error initializing backend. ", err)
	}
	if err := registry.Default.Register(); err != nil {
		exit.Fatal("[FATAL] Error registering backend. ", err)
	}
}

func watchBackend() {
	var (
		last   string
		svccfg string
		mancfg string
	)

	svc := registry.Default.WatchServices()
	man := registry.Default.WatchManual()

	for {
		select {
		case svccfg = <-svc:
		case mancfg = <-man:
		}

		// manual config overrides service config
		// order matters
		next := svccfg + "\n" + mancfg
		if next == last {
			continue
		}

		t, err := route.NewTable(next)
		if err != nil {
			log.Printf("[WARN] %s", err)
			continue
		}
		route.SetTable(t)

		last = next
	}
}

func toJSON(v interface{}) string {
	data, err := json.MarshalIndent(v, "", "    ")
	if err != nil {
		panic("json: " + err.Error())
	}
	return string(data)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"net/http"

	"strings"
	"syscall"

	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/op/go-logging"
	"github.com/pressly/gohttpware/auth"
	"github.com/pressly/gohttpware/route"
	"github.com/zenazn/goji/graceful"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var (
	configPath = flag.String("config-file", "./config.toml", "path to qmd config file")
	log        = logging.MustGetLogger("qmd")

	config   Config
	producer *nsq.Producer
	consumer *nsq.Consumer
	redisDB  *redis.Pool
)

const (
	VERSION = "0.1.0"
)

func main() {
	var err error

	flag.Parse()

	// Server config
	err = config.Load(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	err = config.Setup()
	if err != nil {
		log.Fatal(err)
	}

	log.Info("=====> [ QMD v%s ] <=====", VERSION)

	// Setup facilities
	producer, err = nsq.NewProducer(config.QueueAddr, nsq.NewConfig())
	if err != nil {
		log.Fatal(err)
	}
	redisDB = newRedisPool(config.RedisAddr)

	// Script processing worker
	worker, err := NewWorker(config)
	if err != nil {
		log.Fatal(err)
	}
	go worker.Run()

	// Http server
	w := web.New()

	w.Use(middleware.Logger)
	w.Use(middleware.Recoverer)
	w.Use(Heartbeat)
	if config.Auth.Enabled {
		basicAuthWithRedis := func(r *http.Request, secrets []string) bool {
			var err error
			secret := fmt.Sprintf("%s:%s", secrets[0], secrets[1])

			auth := r.Header.Get("Authorization")
			prefix := "Basic "
			if !strings.HasPrefix(auth, prefix) {
				return false
			}
			givenSecret := auth[len(prefix):]
			decodedSecret, err := base64.StdEncoding.DecodeString(givenSecret)
			if err != nil {
				log.Error(err.Error())
				return false
			}

			user := strings.Split(string(decodedSecret), ":")[0]
			check, err := checkRedisUser(user)
			if err != nil {
				log.Error(err.Error())
				return false
			}
			if check != true {
				log.Error("User: %s is blocked", user)
				return false
			}

			if string(decodedSecret) == secret {
				return true
			}
			if err := failRedisUser(user); err != nil {
				log.Error(err.Error())
			}
			return false
		}

		authFunc := auth.Wrap(
			basicAuthWithRedis,
			"Restricted",
			config.Auth.Username,
			config.Auth.Password,
		)
		w.Use(authFunc)
	}
	w.Use(route.AllowSlash)

	w.Get("/scripts", GetAllScripts)
	w.Put("/scripts", ReloadScripts)
	w.Post("/scripts/:name", RunScript)
	w.Get("/scripts/:name/logs", GetAllLogs)
	w.Get("/scripts/:name/logs/:id", GetLog)
	w.Handle("/*", AdminProxy)

	// Spin up the server with graceful hooks
	graceful.PreHook(func() {
		log.Info("Stopping queue producer")
		producer.Stop()

		log.Info("Stopping queue workers")
		worker.Stop()

		log.Info("Closing redis connections")
		redisDB.Close()
	})

	graceful.AddSignal(syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	err = graceful.ListenAndServe(config.ListenOnAddr, w)
	if err != nil {
		log.Fatal(err)
	}
	graceful.Wait()
}
<commit_msg>Use Heartbeat middleware from gohttpware instead.<commit_after>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"net/http"

	"strings"
	"syscall"

	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/op/go-logging"
	"github.com/pressly/gohttpware/auth"
	"github.com/pressly/gohttpware/route"
	"github.com/zenazn/goji/graceful"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var (
	configPath = flag.String("config-file", "./config.toml", "path to qmd config file")
	log        = logging.MustGetLogger("qmd")

	config   Config
	producer *nsq.Producer
	consumer *nsq.Consumer
	redisDB  *redis.Pool
)

const (
	VERSION = "0.1.0"
)

func main() {
	var err error

	flag.Parse()

	// Server config
	err = config.Load(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	err = config.Setup()
	if err != nil {
		log.Fatal(err)
	}

	log.Info("=====> [ QMD v%s ] <=====", VERSION)

	// Setup facilities
	producer, err = nsq.NewProducer(config.QueueAddr, nsq.NewConfig())
	if err != nil {
		log.Fatal(err)
	}
	redisDB = newRedisPool(config.RedisAddr)

	// Script processing worker
	worker, err := NewWorker(config)
	if err != nil {
		log.Fatal(err)
	}
	go worker.Run()

	// Http server
	w := web.New()

	w.Use(middleware.Logger)
	w.Use(middleware.Recoverer)
	w.Use(route.Heartbeat)
	if config.Auth.Enabled {
		basicAuthWithRedis := func(r *http.Request, secrets []string) bool {
			var err error
			secret := fmt.Sprintf("%s:%s", secrets[0], secrets[1])

			auth := r.Header.Get("Authorization")
			prefix := "Basic "
			if !strings.HasPrefix(auth, prefix) {
				return false
			}
			givenSecret := auth[len(prefix):]
			decodedSecret, err := base64.StdEncoding.DecodeString(givenSecret)
			if err != nil {
				log.Error(err.Error())
				return false
			}

			user := strings.Split(string(decodedSecret), ":")[0]
			check, err := checkRedisUser(user)
			if err != nil {
				log.Error(err.Error())
				return false
			}
			if check != true {
				log.Error("User: %s is blocked", user)
				return false
			}

			if string(decodedSecret) == secret {
				return true
			}
			if err := failRedisUser(user); err != nil {
				log.Error(err.Error())
			}
			return false
		}

		authFunc := auth.Wrap(
			basicAuthWithRedis,
			"Restricted",
			config.Auth.Username,
			config.Auth.Password,
		)
		w.Use(authFunc)
	}
	w.Use(route.AllowSlash)

	w.Get("/scripts", GetAllScripts)
	w.Put("/scripts", ReloadScripts)
	w.Post("/scripts/:name", RunScript)
	w.Get("/scripts/:name/logs", GetAllLogs)
	w.Get("/scripts/:name/logs/:id", GetLog)
	w.Handle("/*", AdminProxy)

	// Spin up the server with graceful hooks
	graceful.PreHook(func() {
		log.Info("Stopping queue producer")
		producer.Stop()

		log.Info("Stopping queue workers")
		worker.Stop()

		log.Info("Closing redis connections")
		redisDB.Close()
	})

	graceful.AddSignal(syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	err = graceful.ListenAndServe(config.ListenOnAddr, w)
	if err != nil {
		log.Fatal(err)
	}
	graceful.Wait()
}
<|endoftext|>