<commit_before>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// +build gofuzz

package gofuzzdep

import (
	"runtime"
	"sync/atomic"
	"syscall"
	"time"
	"unsafe"

	. "go-fuzz-defs"
)

// Bool is just a bool.
// It is used by code autogenerated by go-fuzz-build
// to avoid compilation errors when a user's code shadows the built-in bool.
type Bool = bool

var (
	inFD  FD
	outFD FD

	CoverTab    *[CoverSize]byte
	input       []byte
	sonarRegion []byte
	sonarPos    uint32
)

func init() {
	var mem []byte
	mem, inFD, outFD = setupCommFile()
	CoverTab = (*[CoverSize]byte)(unsafe.Pointer(&mem[0]))
	input = mem[CoverSize : CoverSize+MaxInputSize]
	sonarRegion = mem[CoverSize+MaxInputSize:]
}

func Main(f func([]byte) int) {
	runtime.GOMAXPROCS(1) // makes coverage more deterministic, we parallelize on higher level
	for {
		n := read(inFD)
		if n > uint64(len(input)) {
			println("invalid input length")
			syscall.Exit(1)
		}
		for i := range CoverTab {
			CoverTab[i] = 0
		}
		atomic.StoreUint32(&sonarPos, 0)
		t0 := time.Now()
		res := f(input[:n])
		ns := time.Since(t0)
		write(outFD, uint64(res), uint64(ns), uint64(atomic.LoadUint32(&sonarPos)))
	}
}

// read reads little-endian-encoded uint64 from fd.
func read(fd FD) uint64 {
	rd := 0
	var buf [8]byte
	for rd != len(buf) {
		n, err := fd.read(buf[rd:])
		if err == syscall.EINTR {
			continue
		}
		if n == 0 {
			syscall.Exit(1)
		}
		if err != nil {
			println("failed to read fd =", fd, "errno =", err.(syscall.Errno))
			syscall.Exit(1)
		}
		rd += n
	}
	return deserialize64(buf[:])
}

// write writes little-endian-encoded vals... to fd.
func write(fd FD, vals ...uint64) {
	var tmp [3 * 8]byte
	buf := tmp[:len(vals)*8]
	for i, v := range vals {
		for j := 0; j < 8; j++ {
			buf[i*8+j] = byte(v)
			v >>= 8
		}
	}
	wr := 0
	for wr != len(buf) {
		n, err := fd.write(buf[wr:])
		if err == syscall.EINTR {
			continue
		}
		if err != nil {
			println("failed to read fd =", fd, "errno =", err.(syscall.Errno))
			syscall.Exit(1)
		}
		wr += n
	}
}

// writeStr writes strings s to fd.
func writeStr(fd FD, s string) {
	buf := []byte(s)
	wr := 0
	for wr != len(buf) {
		n, err := fd.write(buf[wr:])
		if err == syscall.EINTR {
			continue
		}
		if err != nil {
			println("failed to read fd =", fd, "errno =", err.(syscall.Errno))
			syscall.Exit(1)
		}
		wr += n
	}
}
<commit_msg>go-fuzz-dep: use serialize64 in write<commit_after>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// +build gofuzz

package gofuzzdep

import (
	"runtime"
	"sync/atomic"
	"syscall"
	"time"
	"unsafe"

	. "go-fuzz-defs"
)

// Bool is just a bool.
// It is used by code autogenerated by go-fuzz-build
// to avoid compilation errors when a user's code shadows the built-in bool.
type Bool = bool

var (
	inFD  FD
	outFD FD

	CoverTab    *[CoverSize]byte
	input       []byte
	sonarRegion []byte
	sonarPos    uint32
)

func init() {
	var mem []byte
	mem, inFD, outFD = setupCommFile()
	CoverTab = (*[CoverSize]byte)(unsafe.Pointer(&mem[0]))
	input = mem[CoverSize : CoverSize+MaxInputSize]
	sonarRegion = mem[CoverSize+MaxInputSize:]
}

func Main(f func([]byte) int) {
	runtime.GOMAXPROCS(1) // makes coverage more deterministic, we parallelize on higher level
	for {
		n := read(inFD)
		if n > uint64(len(input)) {
			println("invalid input length")
			syscall.Exit(1)
		}
		for i := range CoverTab {
			CoverTab[i] = 0
		}
		atomic.StoreUint32(&sonarPos, 0)
		t0 := time.Now()
		res := f(input[:n])
		ns := time.Since(t0)
		write(outFD, uint64(res), uint64(ns), uint64(atomic.LoadUint32(&sonarPos)))
	}
}

// read reads little-endian-encoded uint64 from fd.
func read(fd FD) uint64 {
	rd := 0
	var buf [8]byte
	for rd != len(buf) {
		n, err := fd.read(buf[rd:])
		if err == syscall.EINTR {
			continue
		}
		if n == 0 {
			syscall.Exit(1)
		}
		if err != nil {
			println("failed to read fd =", fd, "errno =", err.(syscall.Errno))
			syscall.Exit(1)
		}
		rd += n
	}
	return deserialize64(buf[:])
}

// write writes little-endian-encoded vals... to fd.
func write(fd FD, vals ...uint64) {
	var tmp [3 * 8]byte
	buf := tmp[:len(vals)*8]
	for i, v := range vals {
		serialize64(buf[i*8:], v)
	}
	wr := 0
	for wr != len(buf) {
		n, err := fd.write(buf[wr:])
		if err == syscall.EINTR {
			continue
		}
		if err != nil {
			println("failed to read fd =", fd, "errno =", err.(syscall.Errno))
			syscall.Exit(1)
		}
		wr += n
	}
}

// writeStr writes strings s to fd.
func writeStr(fd FD, s string) {
	buf := []byte(s)
	wr := 0
	for wr != len(buf) {
		n, err := fd.write(buf[wr:])
		if err == syscall.EINTR {
			continue
		}
		if err != nil {
			println("failed to read fd =", fd, "errno =", err.(syscall.Errno))
			syscall.Exit(1)
		}
		wr += n
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/ziutek/gst"
)

const (
	retryInterval = 5 * time.Second
	maxRetry      = 24
)

// ------------ manager

type Manager struct {
	Pipeline *gst.Pipeline
	ConfigSync chan *Config
	ConfigUri  string
	StaticUri  string
	State      gst.State
	Backend    Pinger
	RetryCount int
}

func NewManager() *Manager {
	m := Manager{}
	m.ConfigSync = make(chan *Config, 2)
	return &m
}

func (m *Manager) Receiver() *Receiver {
	return m.Backend.(*Receiver)
}

func (m *Manager) Server() *Server {
	return m.Backend.(*Server)
}

func (m *Manager) onMessage(bus *gst.Bus, msg *gst.Message) {
	t := msg.GetType()
	switch t {
	case gst.MESSAGE_STATE_CHANGED:
		pl := m.Pipeline
		if pl != nil {
			s, _, _ := pl.GetState(100)
			if s != m.State {
				log.Info("pipeline state: %s", s)
				m.State = s
			}
		}
	case gst.MESSAGE_EOS:
		log.Info("pipeline: end of stream")
	m.ConfigSync<-nil
	case gst.MESSAGE_ERROR:
		err, debug := msg.ParseError()
		log.Error("pipeline error: %s (debug: %s)", err, debug)
		// try to reconnect
		time.Sleep(retryInterval)
	m.ConfigSync<-nil
	case gst.MESSAGE_BUFFERING:
		// ignore
	default:
		log.Debug("pipeline message: %s", t)
	}
}

func (m *Manager) StartPipeline() {
	if m.Pipeline != nil {
		log.Info("start pipeline")
		m.Pipeline.SetState(gst.STATE_PLAYING)
	}
}

func (m *Manager) StopPipeline() {
	if m.Pipeline != nil {
		log.Info("stop pipeline")
		m.Pipeline.SetState(gst.STATE_NULL)
		m.Pipeline.Unref()
		m.Pipeline = nil
	}
}

// ------------ gst stuff

func checkElem(e interface{}, name string) {
	if e == nil {
		log.Fatal("can't make element: %s", name)
		os.Exit(1) // TODO don't exit
	}
}

func makeElem(name string) *gst.Element {
	e := gst.ElementFactoryMake(name, name)
	checkElem(e, name)
	return e
}

func addElem(pl *gst.Pipeline, e *gst.Element) bool {
	r := pl.Add(e)
	log.Debug("add %s to pipeline: %v", e.GetName(), r)
	return r
}

func linkElems(src, sink *gst.Element) bool {
	r := src.Link(sink)
	log.Debug("link %s -> %s: %v", src.GetName(), sink.GetName(), r)
	return r
}

func onPadAdded(sinkPad, newPad *gst.Pad) {
	log.Debug("pad-added: %s", newPad.GetName())
	log.Debug("sink pad: %s", sinkPad.GetName())
	if newPad.CanLink(sinkPad) {
		if newPad.Link(sinkPad) != gst.PAD_LINK_OK {
			log.Error("error linking pads: %s/%s", newPad.GetName(), sinkPad.GetName())
		}
	} else {
		log.Error("unable to link pads: %s/%s", newPad.GetName(), sinkPad.GetName())
	}
}

// ------------ config stuff

func pingConfig(uri string, obj Pinger) error {
	log.Debug("register object at path: %s %s", uri)

	j, _ := json.Marshal(obj)
	req, _ := http.NewRequest("POST", uri, bytes.NewBuffer(j))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	_, err := client.Do(req)
	return err
}

func fetchObject(uri string, wait bool, obj interface{}) (interface{}, error) {
	var u string
	if wait {
		u = uri+"?wait"
	} else {
		u = uri
	}
	log.Debug("fetch object: %s", u)
	resp, err := http.Get(u)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(body, obj)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func fetchConfig(base string, wait bool) (*Config, error) {
	var config Config
	_, err := fetchObject(base+"/api/config", wait, &config)
	return &config, err
}

func watchConfig(m *Manager) {
	for true {
		config, _ := fetchConfig(m.ConfigUri, true)
		log.Debug("got new config: %s", config)
		if config != nil {
			// send new config to pipeline
			m.ConfigSync<-config
		} else {
			time.Sleep(2 * time.Second)
		}
	}
}
<commit_msg>exponential back off for missing config server; fixes #2<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/ziutek/gst"
)

const (
	retryInterval = 5 * time.Second
	maxRetry      = 24
)

// ------------ manager

type Manager struct {
	Pipeline *gst.Pipeline
	ConfigSync chan *Config
	ConfigUri  string
	StaticUri  string
	State      gst.State
	Backend    Pinger
	RetryCount int
}

func NewManager() *Manager {
	m := Manager{}
	m.ConfigSync = make(chan *Config, 2)
	return &m
}

func (m *Manager) Receiver() *Receiver {
	return m.Backend.(*Receiver)
}

func (m *Manager) Server() *Server {
	return m.Backend.(*Server)
}

func (m *Manager) onMessage(bus *gst.Bus, msg *gst.Message) {
	t := msg.GetType()
	switch t {
	case gst.MESSAGE_STATE_CHANGED:
		pl := m.Pipeline
		if pl != nil {
			s, _, _ := pl.GetState(100)
			if s != m.State {
				log.Info("pipeline state: %s", s)
				m.State = s
			}
		}
	case gst.MESSAGE_EOS:
		log.Info("pipeline: end of stream")
	m.ConfigSync<-nil
	case gst.MESSAGE_ERROR:
		err, debug := msg.ParseError()
		log.Error("pipeline error: %s (debug: %s)", err, debug)
		// try to reconnect
		time.Sleep(retryInterval)
	m.ConfigSync<-nil
	case gst.MESSAGE_BUFFERING:
		// ignore
	default:
		log.Debug("pipeline message: %s", t)
	}
}

func (m *Manager) StartPipeline() {
	if m.Pipeline != nil {
		log.Info("start pipeline")
		m.Pipeline.SetState(gst.STATE_PLAYING)
	}
}

func (m *Manager) StopPipeline() {
	if m.Pipeline != nil {
		log.Info("stop pipeline")
		m.Pipeline.SetState(gst.STATE_NULL)
		m.Pipeline.Unref()
		m.Pipeline = nil
	}
}

// ------------ gst stuff

func checkElem(e interface{}, name string) {
	if e == nil {
		log.Fatal("can't make element: %s", name)
		os.Exit(1) // TODO don't exit
	}
}

func makeElem(name string) *gst.Element {
	e := gst.ElementFactoryMake(name, name)
	checkElem(e, name)
	return e
}

func addElem(pl *gst.Pipeline, e *gst.Element) bool {
	r := pl.Add(e)
	log.Debug("add %s to pipeline: %v", e.GetName(), r)
	return r
}

func linkElems(src, sink *gst.Element) bool {
	r := src.Link(sink)
	log.Debug("link %s -> %s: %v", src.GetName(), sink.GetName(), r)
	return r
}

func onPadAdded(sinkPad, newPad *gst.Pad) {
	log.Debug("pad-added: %s", newPad.GetName())
	log.Debug("sink pad: %s", sinkPad.GetName())
	if newPad.CanLink(sinkPad) {
		if newPad.Link(sinkPad) != gst.PAD_LINK_OK {
			log.Error("error linking pads: %s/%s", newPad.GetName(), sinkPad.GetName())
		}
	} else {
		log.Error("unable to link pads: %s/%s", newPad.GetName(), sinkPad.GetName())
	}
}

// ------------ config stuff

func pingConfig(uri string, obj Pinger) error {
	log.Debug("register object at path: %s %s", uri)

	j, _ := json.Marshal(obj)
	req, _ := http.NewRequest("POST", uri, bytes.NewBuffer(j))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	_, err := client.Do(req)
	return err
}

func fetchObject(uri string, wait bool, obj interface{}) (interface{}, error) {
	var u string
	if wait {
		u = uri+"?wait"
	} else {
		u = uri
	}
	log.Debug("fetch object: %s", u)
	resp, err := http.Get(u)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(body, obj)
	if err != nil {
		return nil, err
	}

	return obj, nil
}

func fetchConfig(base string, wait bool) (*Config, error) {
	var config Config
	_, err := fetchObject(base+"/api/config", wait, &config)
	return &config, err
}

func watchConfig(m *Manager) {
	backOff := time.Second
	for true {
		config, _ := fetchConfig(m.ConfigUri, true)
		log.Debug("got new config: %s", config)
		if config != nil {
			// send new config to pipeline
			m.ConfigSync<-config
			// reset back off
			backOff = time.Second
		} else {
			time.Sleep(backOff)
			// exponential back off, max = 1h
			if backOff < time.Hour {
				backOff *= 2
			} else {
				backOff = time.Hour
			}
		}
	}
}
<|endoftext|>


<commit_before>package ledger

import (
	"errors"
	"fmt"
	"math"
	"strconv"
)

type Entry struct {
	Date        string // "Y-m-d"
	Description string
	Change      int // in cents
}

func FormatLedger(currency string, locale string, entries []Entry) (output string, e error) {
	if !isValidCurrency(currency) {
		return "", errors.New("invalid currency")
	}
	if !isValidLocale(locale) {
		return "", errors.New("invalid locale")
	}
	if !isValidDate(entries) {
		return "", errors.New("invalid date")
	}

	entriesCopy := append([]Entry{}, entries...)

	m1 := map[bool]int{true: 0, false: 1}
	m2 := map[bool]int{true: -1, false: 1}
	es := entriesCopy
	for len(es) > 1 {
		first, rest := es[0], es[1:]
		success := false
		for !success {
			success = true
			for i, e := range rest {
				if (m1[e.Date == first.Date]*m2[e.Date < first.Date]*4 +
					m1[e.Description == first.Description]*m2[e.Description < first.Description]*2 +
					m1[e.Change == first.Change]*m2[e.Change < first.Change]*1) < 0 {
					es[0], es[i+1] = es[i+1], es[0]
					success = false
				}
			}
		}
		es = es[1:]
	}

	output += header(locale)
	for _, entry := range entriesCopy {
		output += formatEntry(locale, currency, entry)
	}
	return output, nil
}

func formatEntry(locale string, currency string, entry Entry) (formatted string) {
	date := formatDate(locale, entry.Date)
	description := formatDescription(entry.Description)
	change := formatChange(locale, currency, entry.Change)

	// This conditional is necessary because expected output is aligned
	// differently for negative vs. non-negative values
	if isNegative(entry.Change) {
		return fmt.Sprintf("%-10s | %-25s | %13s\n", date, description, change)
	} else {
		return fmt.Sprintf("%-10s | %-25s | %12s\n", date, description, change)
	}
}

func header(locale string) (output string) {
	if locale == "nl-NL" {
		return fmt.Sprintf("%-10s | %-25s | %s\n", "Datum", "Omschrijving", "Verandering")
	} else if locale == "en-US" {
		return fmt.Sprintf("%-10s | %-25s | %s\n", "Date", "Description", "Change")
	}
	panic("invalid locale")
}

func formatDate(locale string, date string) string {
	year, month, day := date[0:4], date[5:7], date[8:10]

	if locale == "nl-NL" {
		return fmt.Sprintf("%v-%v-%v", day, month, year)
	} else if locale == "en-US" {
		return fmt.Sprintf("%v/%v/%v", month, day, year)
	}
	panic("invalid locale")
}

// formatDescription will ellipsize the description if it is longer than 25
// characters
func formatDescription(description string) string {
	if len(description) > 25 {
		return description[:22] + "..."
	}
	return description
}

func formatChange(locale string, currency string, cents int) (change string) {
	isNegative := isNegative(cents)
	absoluteValueCents := int(math.Abs(float64(cents)))
	if locale == "nl-NL" {
		change += getCurrencySymbol(currency)
		change += " "
		centsStr := fmt.Sprintf("%03s", strconv.Itoa(absoluteValueCents))
		rest := centsStr[:len(centsStr)-2]
		var parts []string
		for len(rest) > 3 {
			parts = append(parts, rest[len(rest)-3:])
			rest = rest[:len(rest)-3]
		}
		if len(rest) > 0 {
			parts = append(parts, rest)
		}
		for i := len(parts) - 1; i >= 0; i-- {
			change += parts[i] + "."
		}
		change = change[:len(change)-1]
		change += ","
		change += centsStr[len(centsStr)-2:]
		if isNegative {
			// Append `-`
			change = fmt.Sprintf("%s-", change)
		}
	} else if locale == "en-US" {
		change += getCurrencySymbol(currency)
		centsStr := fmt.Sprintf("%03s", strconv.Itoa(absoluteValueCents))
		rest := centsStr[:len(centsStr)-2]
		var parts []string
		for len(rest) > 3 {
			parts = append(parts, rest[len(rest)-3:])
			rest = rest[:len(rest)-3]
		}
		if len(rest) > 0 {
			parts = append(parts, rest)
		}
		for i := len(parts) - 1; i >= 0; i-- {
			change += parts[i] + ","
		}
		change = change[:len(change)-1]
		change += "."
		change += centsStr[len(centsStr)-2:]
		if isNegative {
			// Surround with parenthesis
			change = fmt.Sprintf("(%s)", change)
		}
	}
	return change
}

func getCurrencySymbol(currency string) (symbol string) {
	if currency == "EUR" {
		return "€"
	} else if currency == "USD" {
		return "$"
	}
	panic("invalid currency")
}

func isValidCurrency(currency string) bool {
	return currency == "USD" || currency == "EUR"
}

func isValidLocale(locale string) bool {
	return locale == "en-US" || locale == "nl-NL"
}

func isValidDate(entries []Entry) bool {
	for _, entry := range entries {
		if len(entry.Date) != 10 {
			return false
		}
		_, d2, _, d4, _ := entry.Date[0:4], entry.Date[4], entry.Date[5:7], entry.Date[7], entry.Date[8:10]
		if d2 != '-' || d4 != '-' {
			return false
		}
	}
	return true
}

func isNegative(cents int) bool {
	return cents < 0
}
<commit_msg>Extract Locales<commit_after>package ledger

import (
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
)

type Entry struct {
	Date        string // "Y-m-d"
	Description string
	Change      int // in cents
}

type Locale struct {
	DateSeperator string
}

var locales = map[string]Locale{
	"en-US": {
		DateSeperator: "/",
	},
	"nl-NL": {
		DateSeperator: "-",
	},
}

func FormatLedger(currency string, locale string, entries []Entry) (output string, e error) {
	if !isValidCurrency(currency) {
		return "", errors.New("invalid currency")
	}
	if !isValidLocale(locale) {
		return "", errors.New("invalid locale")
	}
	if !isValidDate(entries) {
		return "", errors.New("invalid date")
	}

	entriesCopy := append([]Entry{}, entries...)

	m1 := map[bool]int{true: 0, false: 1}
	m2 := map[bool]int{true: -1, false: 1}
	es := entriesCopy
	for len(es) > 1 {
		first, rest := es[0], es[1:]
		success := false
		for !success {
			success = true
			for i, e := range rest {
				if (m1[e.Date == first.Date]*m2[e.Date < first.Date]*4 +
					m1[e.Description == first.Description]*m2[e.Description < first.Description]*2 +
					m1[e.Change == first.Change]*m2[e.Change < first.Change]*1) < 0 {
					es[0], es[i+1] = es[i+1], es[0]
					success = false
				}
			}
		}
		es = es[1:]
	}

	output += header(locale)
	for _, entry := range entriesCopy {
		output += formatEntry(locale, currency, entry)
	}
	return output, nil
}

func formatEntry(locale string, currency string, entry Entry) (formatted string) {
	date := formatDate(locale, entry.Date)
	description := formatDescription(entry.Description)
	change := formatChange(locale, currency, entry.Change)

	// This conditional is necessary because expected output is aligned
	// differently for negative vs. non-negative values
	if isNegative(entry.Change) {
		return fmt.Sprintf("%-10s | %-25s | %13s\n", date, description, change)
	} else {
		return fmt.Sprintf("%-10s | %-25s | %12s\n", date, description, change)
	}
}

func header(locale string) (output string) {
	if locale == "nl-NL" {
		return fmt.Sprintf("%-10s | %-25s | %s\n", "Datum", "Omschrijving", "Verandering")
	} else if locale == "en-US" {
		return fmt.Sprintf("%-10s | %-25s | %s\n", "Date", "Description", "Change")
	}
	panic("invalid locale")
}

func formatDate(locale string, date string) string {
	year, month, day := date[0:4], date[5:7], date[8:10]

	seperator := locales[locale].DateSeperator
	if locale == "nl-NL" {
		return strings.Join([]string{day, month, year}, seperator)
	} else if locale == "en-US" {
		return strings.Join([]string{month, day, year}, seperator)
	}
	panic("invalid locale")
}

// formatDescription will ellipsize the description if it is longer than 25
// characters
func formatDescription(description string) string {
	if len(description) > 25 {
		return description[:22] + "..."
	}
	return description
}

func formatChange(locale string, currency string, cents int) (change string) {
	isNegative := isNegative(cents)
	absoluteValueCents := int(math.Abs(float64(cents)))
	change += getCurrencySymbol(currency)
	if locale == "nl-NL" {
		change += " "
		centsStr := fmt.Sprintf("%03s", strconv.Itoa(absoluteValueCents))
		rest := centsStr[:len(centsStr)-2]
		var parts []string
		for len(rest) > 3 {
			parts = append(parts, rest[len(rest)-3:])
			rest = rest[:len(rest)-3]
		}
		if len(rest) > 0 {
			parts = append(parts, rest)
		}
		for i := len(parts) - 1; i >= 0; i-- {
			change += parts[i] + "."
		}
		change = change[:len(change)-1]
		change += ","
		change += centsStr[len(centsStr)-2:]
		if isNegative {
			// Append `-`
			change = fmt.Sprintf("%s-", change)
		}
	} else if locale == "en-US" {
		centsStr := fmt.Sprintf("%03s", strconv.Itoa(absoluteValueCents))
		rest := centsStr[:len(centsStr)-2]
		var parts []string
		for len(rest) > 3 {
			parts = append(parts, rest[len(rest)-3:])
			rest = rest[:len(rest)-3]
		}
		if len(rest) > 0 {
			parts = append(parts, rest)
		}
		for i := len(parts) - 1; i >= 0; i-- {
			change += parts[i] + ","
		}
		change = change[:len(change)-1]
		change += "."
		change += centsStr[len(centsStr)-2:]
		if isNegative {
			// Surround with parenthesis
			change = fmt.Sprintf("(%s)", change)
		}
	}
	return change
}

func getCurrencySymbol(currency string) (symbol string) {
	if currency == "EUR" {
		return "€"
	} else if currency == "USD" {
		return "$"
	}
	panic("invalid currency")
}

func isValidCurrency(currency string) bool {
	return currency == "USD" || currency == "EUR"
}

func isValidLocale(locale string) bool {
	_, ok := locales[locale]
	return ok
}

func isValidDate(entries []Entry) bool {
	for _, entry := range entries {
		if len(entry.Date) != 10 {
			return false
		}
		_, d2, _, d4, _ := entry.Date[0:4], entry.Date[4], entry.Date[5:7], entry.Date[7], entry.Date[8:10]
		if d2 != '-' || d4 != '-' {
			return false
		}
	}
	return true
}

func isNegative(cents int) bool {
	return cents < 0
}
<|endoftext|>


<commit_before>package libkb

import (
	"fmt"
	"sync"

	triplesec "github.com/keybase/go-triplesec"
)

type Account struct {
	localSession *Session
	loginSession *LoginSession
	streamCache  *StreamCache
	skbKeyring   *SKBKeyringFile
	Contextified
	sync.RWMutex
	secretSyncerMu sync.RWMutex
	secretSyncer   *SecretSyncer
}

func NewAccount(g *GlobalContext) *Account {
	return &Account{
		localSession: newSession(g),
		secretSyncer: NewSecretSyncer(g),
		Contextified: NewContextified(g),
	}
}

func (a *Account) LocalSession() *Session {
	a.RLock()
	defer a.RUnlock()
	return a.localSession
}

func (a *Account) UnloadLocalSession() {
	a.Lock()
	a.localSession = newSession(a.G())
	a.Unlock()
}

// LoggedIn returns true if the user is logged in.  It does not
// try to load the session.
func (a *Account) LoggedIn() bool {
	return a.LocalSession().IsLoggedIn()
}

// LoggedInLoad will load and check the session with the api server if necessary.
func (a *Account) LoggedInLoad() (bool, error) {
	return a.LocalSession().loadAndCheck()
}

func (a *Account) LoadLoginSession(emailOrUsername string) error {
	if a.LoginSession().ExistsFor(emailOrUsername) {
		return nil
	}

	ls := NewLoginSession(emailOrUsername, a.G())
	if err := ls.Load(); err != nil {
		return err
	}
	a.setLoginSession(ls)
	return nil
}

func (a *Account) CreateLoginSessionWithSalt(emailOrUsername string, salt []byte) error {
	if a.loginSessionExists() {
		return fmt.Errorf("CreateLoginSessionWithSalt called, but Account already has LoginSession")
	}

	ls := NewLoginSessionWithSalt(emailOrUsername, salt, a.G())
	a.setLoginSession(ls)
	return nil
}

func (a *Account) setLoginSession(ls *LoginSession) {
	a.Lock()
	defer a.Unlock()
	if a.loginSession != nil {
		// this usually happens in tests that don't call G.Logout() to logout.
		// But it probably signifies an error.
		a.G().Log.Warning("Account: overwriting loginSession")
	}

	a.loginSession = ls
}

func (a *Account) loginSessionExists() bool {
	return a.LoginSession() != nil
}

func (a *Account) LoginSession() *LoginSession {
	a.RLock()
	defer a.RUnlock()
	return a.loginSession
}

func (a *Account) Logout() error {
	a.ClearStreamCache()

	a.RLock()
	if err := a.localSession.Logout(); err != nil {
		a.RUnlock()
		return err
	}
	a.RUnlock()

	a.UnloadLocalSession()
	a.Lock()
	a.loginSession = nil
	a.skbKeyring = nil
	a.Unlock()

	a.secretSyncerMu.Lock()
	a.secretSyncer.Clear()
	a.secretSyncer = NewSecretSyncer(a.G())
	a.secretSyncerMu.Unlock()

	return nil
}

func (a *Account) CreateStreamCache(tsec *triplesec.Cipher, pps PassphraseStream) {
	a.Lock()
	defer a.Unlock()
	if a.streamCache != nil {
		a.G().Log.Warning("Account.CreateStreamCache overwriting exisitng StreamCache")
	}
	a.streamCache = NewStreamCache(tsec, pps)
}

func (a *Account) CreateStreamCacheViaStretch(passphrase string) error {
	a.Lock()
	defer a.Unlock()

	if a.streamCache.Valid() {
		return nil
	}

	salt, err := a.loginSession.Salt()
	if err != nil {
		return err
	}

	tsec, pps, err := StretchPassphrase(passphrase, salt)
	if err != nil {
		return err
	}

	a.streamCache = NewStreamCache(tsec, pps)

	return nil
}

func (a *Account) StreamCache() *StreamCache {
	a.RLock()
	defer a.RUnlock()
	return a.streamCache
}

func (a *Account) ClearStreamCache() {
	a.Lock()
	defer a.Unlock()
	a.streamCache.Clear()
	a.streamCache = nil
}

func (a *Account) SecretSyncer() *SecretSyncer {
	a.secretSyncerMu.RLock()
	defer a.secretSyncerMu.RUnlock()
	return a.secretSyncer
}

func (a *Account) RunSecretSyncer(uid *UID) error {
	return RunSyncer(a.SecretSyncer(), uid)
}

func (a *Account) Keyring() (*SKBKeyringFile, error) {
	if a.localSession == nil {
		a.G().Log.Warning("local session is nil")
	}
	a.LocalSession().loadAndCheck()
	if a.localSession == nil {
		a.G().Log.Warning("local session after load is nil")
	}
	a.RLock()
	kr := a.skbKeyring
	a.RUnlock()
	if kr != nil {
		return kr, nil
	}

	a.Lock()
	defer a.Unlock()
	unp := a.localSession.GetUsername()
	// not sure how this could happen, but just in case:
	if unp == nil {
		return nil, NoUsernameError{}
	}
	kr, err := LoadSKBKeyring(*unp, a.G())
	if err != nil {
		return nil, err
	}
	a.skbKeyring = kr
	return a.skbKeyring, nil
}

func (a *Account) Shutdown() error {
	return a.LocalSession().Write()
}

func (a *Account) EnsureUsername(username string) {
	su := a.LocalSession().GetUsername()
	if su == nil {
		a.LocalSession().SetUsername(username)
		return
	}
	if *su != username {
		panic(fmt.Sprintf("username for current session (%q) differs from param (%q)", *su, username))
	}

}

// XXX not sure this is the best place for this...
// XXX put it through loginstate external func?
func (a *Account) UserInfo() (uid UID, username, token string, deviceSubkeyKid KID, err error) {
	if !a.LoggedIn() {
		err = LoginRequiredError{}
		return
	}

	user, err := LoadMe(LoadUserArg{})
	if err != nil {
		return
	}

	// lock everything to make sure the values refer to same user
	a.RLock()
	defer a.RUnlock()
	deviceSubkeyKid, err = user.GetDeviceSubkeyKid(a.G())
	if err != nil {
		deviceSubkeyKid = KID{}
		return
	}

	uid = user.GetUid()
	username = user.GetName()
	token = a.localSession.GetToken()
	return
}
<commit_msg>ensure username clears account, then switches username<commit_after>package libkb

import (
	"fmt"
	"sync"

	triplesec "github.com/keybase/go-triplesec"
)

type Account struct {
	localSession *Session
	loginSession *LoginSession
	streamCache  *StreamCache
	skbKeyring   *SKBKeyringFile
	Contextified
	sync.RWMutex
	secretSyncerMu sync.RWMutex
	secretSyncer   *SecretSyncer
}

func NewAccount(g *GlobalContext) *Account {
	return &Account{
		localSession: newSession(g),
		secretSyncer: NewSecretSyncer(g),
		Contextified: NewContextified(g),
	}
}

func (a *Account) LocalSession() *Session {
	a.RLock()
	defer a.RUnlock()
	return a.localSession
}

func (a *Account) UnloadLocalSession() {
	a.Lock()
	a.localSession = newSession(a.G())
	a.Unlock()
}

// LoggedIn returns true if the user is logged in.  It does not
// try to load the session.
func (a *Account) LoggedIn() bool {
	return a.LocalSession().IsLoggedIn()
}

// LoggedInLoad will load and check the session with the api server if necessary.
func (a *Account) LoggedInLoad() (bool, error) {
	return a.LocalSession().loadAndCheck()
}

func (a *Account) LoadLoginSession(emailOrUsername string) error {
	if a.LoginSession().ExistsFor(emailOrUsername) {
		return nil
	}

	ls := NewLoginSession(emailOrUsername, a.G())
	if err := ls.Load(); err != nil {
		return err
	}
	a.setLoginSession(ls)
	return nil
}

func (a *Account) CreateLoginSessionWithSalt(emailOrUsername string, salt []byte) error {
	if a.loginSessionExists() {
		return fmt.Errorf("CreateLoginSessionWithSalt called, but Account already has LoginSession")
	}

	ls := NewLoginSessionWithSalt(emailOrUsername, salt, a.G())
	a.setLoginSession(ls)
	return nil
}

func (a *Account) setLoginSession(ls *LoginSession) {
	a.Lock()
	defer a.Unlock()
	if a.loginSession != nil {
		// this usually happens in tests that don't call G.Logout() to logout.
		// But it probably signifies an error.
		a.G().Log.Warning("Account: overwriting loginSession")
	}

	a.loginSession = ls
}

func (a *Account) loginSessionExists() bool {
	return a.LoginSession() != nil
}

func (a *Account) LoginSession() *LoginSession {
	a.RLock()
	defer a.RUnlock()
	return a.loginSession
}

func (a *Account) Logout() error {
	a.ClearStreamCache()

	a.RLock()
	if err := a.localSession.Logout(); err != nil {
		a.RUnlock()
		return err
	}
	a.RUnlock()

	a.UnloadLocalSession()
	a.Lock()
	a.loginSession = nil
	a.skbKeyring = nil
	a.Unlock()

	a.secretSyncerMu.Lock()
	a.secretSyncer.Clear()
	a.secretSyncer = NewSecretSyncer(a.G())
	a.secretSyncerMu.Unlock()

	return nil
}

func (a *Account) CreateStreamCache(tsec *triplesec.Cipher, pps PassphraseStream) {
	a.Lock()
	defer a.Unlock()
	if a.streamCache != nil {
		a.G().Log.Warning("Account.CreateStreamCache overwriting exisitng StreamCache")
	}
	a.streamCache = NewStreamCache(tsec, pps)
}

func (a *Account) CreateStreamCacheViaStretch(passphrase string) error {
	a.Lock()
	defer a.Unlock()

	if a.streamCache.Valid() {
		return nil
	}

	salt, err := a.loginSession.Salt()
	if err != nil {
		return err
	}

	tsec, pps, err := StretchPassphrase(passphrase, salt)
	if err != nil {
		return err
	}

	a.streamCache = NewStreamCache(tsec, pps)

	return nil
}

func (a *Account) StreamCache() *StreamCache {
	a.RLock()
	defer a.RUnlock()
	return a.streamCache
}

func (a *Account) ClearStreamCache() {
	a.Lock()
	defer a.Unlock()
	a.streamCache.Clear()
	a.streamCache = nil
}

func (a *Account) SecretSyncer() *SecretSyncer {
	a.secretSyncerMu.RLock()
	defer a.secretSyncerMu.RUnlock()
	return a.secretSyncer
}

func (a *Account) RunSecretSyncer(uid *UID) error {
	return RunSyncer(a.SecretSyncer(), uid)
}

func (a *Account) Keyring() (*SKBKeyringFile, error) {
	if a.localSession == nil {
		a.G().Log.Warning("local session is nil")
	}
	a.LocalSession().loadAndCheck()
	if a.localSession == nil {
		a.G().Log.Warning("local session after load is nil")
	}
	a.RLock()
	kr := a.skbKeyring
	a.RUnlock()
	if kr != nil {
		return kr, nil
	}

	a.Lock()
	defer a.Unlock()
	unp := a.localSession.GetUsername()
	// not sure how this could happen, but just in case:
	if unp == nil {
		return nil, NoUsernameError{}
	}
	kr, err := LoadSKBKeyring(*unp, a.G())
	if err != nil {
		return nil, err
	}
	a.skbKeyring = kr
	return a.skbKeyring, nil
}

func (a *Account) Shutdown() error {
	return a.LocalSession().Write()
}

func (a *Account) EnsureUsername(username string) {
	su := a.LocalSession().GetUsername()
	if su == nil {
		a.LocalSession().SetUsername(username)
		return
	}
	if *su != username {
		a.Logout()
		a.LocalSession().SetUsername(username)
	}

}

// XXX not sure this is the best place for this...
// XXX put it through loginstate external func?
func (a *Account) UserInfo() (uid UID, username, token string, deviceSubkeyKid KID, err error) {
	if !a.LoggedIn() {
		err = LoginRequiredError{}
		return
	}

	user, err := LoadMe(LoadUserArg{})
	if err != nil {
		return
	}

	// lock everything to make sure the values refer to same user
	a.RLock()
	defer a.RUnlock()
	deviceSubkeyKid, err = user.GetDeviceSubkeyKid(a.G())
	if err != nil {
		deviceSubkeyKid = KID{}
		return
	}

	uid = user.GetUid()
	username = user.GetName()
	token = a.localSession.GetToken()
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"fmt"
)

// NOTE: This file is the source of truth for our version number, but we have a
//       script that reads it at packaging/version.sh. If you refactor this
//       file, update that script.

// Version as MAJOR.MINOR.PATCH
const Version = "1.0.5"

// Build number
const Build = "5"

// VersionString returns semantic version string.
func VersionString() string {
	return fmt.Sprintf("%s-%s", Version, Build)
}
<commit_msg>Bumping build number: 1.0.5-6<commit_after>// This file is autogenerated, see packaging/increment_build.sh
package libkb

const Version = "1.0.5"
const Build = 6
<|endoftext|>


<commit_before>package goqless

import (
        //"github.com/zimulala/goqless"
	"log"
	"strconv"
	"time"
)

const (
	jobs_count      = 20
	queues_capacity = 5
	priority        = 10
	//If you don't want a job to be run right away but some time in the future, you can specify a delay
	delay          = -1
	retries        = 3
	interval       = 10
	test_move      = 1
	test_fail      = 2
	test_retry     = 3
	original_queue = "original_queue"
)

var clientCh = make(chan *Client)

type dataWorker struct {
}

func main() {
	log.SetFlags(log.Lshortfile | log.Ltime)

	client, err := Dial("127.0.0.1", "6379")
	if err != nil {
		log.Println("Dial err:", err)
	}
	defer client.Close()

	originalQueue := client.Queue(original_queue)
	err = initOriginalQueue(originalQueue)
	if err != nil {
		log.Println("initQueue failed, err:", err)
	}
	batchJobs(originalQueue)

	select {}
}

func initOriginalQueue(queue *Queue) (err error) {

	var klass string
	depends := []string{}

	for i := 0; i < jobs_count; i++ {
		if i%2 == 0 {
			klass = "klass.Add"
		} else {
			klass = "klass.Sub"
		}
		tags := []string{"e", "__call", "_haha", strconv.Itoa(i)}
		queue.Put("", klass, `"dataJson"`, delay, i, tags, retries, depends)
	}

	return
}

func batchJobs(queue *Queue) (err error) {

	queueCount := int(jobs_count / queues_capacity)
	// go ChannelDialClient("127.0.0.1", "6379", clientCh)

	for i := 0; i < queueCount; i++ {
		handlePerQueue(queue, i)
	}

	return
}

func handlePerQueue(queue *Queue, num int) {
	client, err := Dial("127.0.0.1", "6379")
	if err != nil {
		log.Println("Dial err:", err)
	}
	defer client.Close()

	queueStr := "queue_name_" + strconv.Itoa(num)
	readyQueue := client.Queue(queueStr)
	for i := 0; i < queues_capacity; i++ {
		jobs, err := queue.Pop(1)
		if err != nil {
			log.Println("pop failed, count:", len(jobs), " err:", err)
			return
		} else {
			// log.Printf("jobs :%+v", jobs[0].History)
		}
		jobPut, err := readyQueue.Put(queueStr+"lll_"+strconv.Itoa(i), jobs[0].Klass, "***dataJsondddd", delay,
			jobs[0].Priority, jobs[0].Tags, jobs[0].Retries, jobs[0].Dependents)
		if err != nil {
			log.Println("put failed, err:", err)
			continue
		}
		//testJobMoveFailRetry(i, jobs[0])
		jobs[0].Complete()
		//log.Printf("---jobPut:%+v, queue:%+v", jobs[0], jobs[0].Queue)
		log.Println("==jobPut : ", jobPut, " jobsPut.Priority:", jobs[0].Priority, "\n")
	}

	startWorkers(queueStr)
}

func testJobMoveFailRetry(QueueNo int, job *Job) {

	//Move to self.queue
	if test_move == QueueNo {
		//return jid
		moveStr, err := job.Move("queue_name_1")
		if err != nil {
			log.Println("Move failed. err:", err)
		}
		log.Printf("moveStr:%+v", moveStr)
	}
	//Fail
	// if test_fail == QueueNo {
	// 	failRet, err := job.Fail("typ", "message")
	// 	if err != nil {
	// 		log.Println("Fail failed. err:", err)
	// 	}
	// 	log.Println("failRet:", failRet)
	// }
	//Retry
	// if test_retry == QueueNo {
	// 	delay := 0
	// 	retryStr, err := job.Retry(delay)
	// 	if err != nil {
	// 		log.Println("Retry failed. err:", err)
	// 	}
	// 	log.Println("retryStr:", retryStr, " jid:", job.Jid)
	// 	log.Printf("===jobPut:%+v", job)
	// }
}

func startWorkers(queueStr string) (err error) {
	log.Println("worker queues", queueStr)

	startWorker := func(queueStr string) {
		client, err := Dial("127.0.0.1", "6379")
		if err != nil {
			log.Println("Dial err:", err)
		}
		defer client.Close()

		worker_x, err := initWorker(client, queueStr)
		if err != nil {
			log.Println("initWorker failed, err:", err)
		}
		log.Println("qStr:", queueStr)
		// client.SetConfig("heartbeat", 120)
		// heartbeatStr2 := client.GetConfig("heartbeat")
		// log.Println("heartbeatStr:", heartbeatStr2)
		worker_x.Start()
	}

	go startWorker(queueStr)
	go startWorker(queueStr)

	time.Sleep(10 * time.Second)

	return
}

func initWorker(cli *Client, queue string) (worker *Worker, err error) {

	worker = NewWorker(cli, queue, interval)
	log.Printf("worker: %+v, p:%p", worker, worker)
	dataW := &dataWorker{}
	worker.AddService("klass", dataW)

	return
}

func (dataW *dataWorker) Add(job *Job) (err error) {
	job.Data = map[string]interface{}{"id": "Add"}
	time.Sleep(190 * time.Second)
	job.Data = map[string]interface{}{"id": "sleepEndAdd"}

	return
}

func (dataW *dataWorker) Sub(job *Job) (err error) {
	job.Data = map[string]interface{}{"id": "Sub"}
	return
}
<commit_msg>remove goqless_test_new.go<commit_after><|endoftext|>


<commit_before>package gqt_test

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"path"
	"path/filepath"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("Destroying a Container", func() {
	var (
		args   []string
		client *runner.RunningGarden
	)

	BeforeEach(func() {
		args = []string{"--debug-bind-ip", "0.0.0.0", "--debug-bind-port", fmt.Sprintf("%d", 8080+GinkgoParallelNode())}
	})

	JustBeforeEach(func() {
		client = startGarden(args...)
	})

	AfterEach(func() {
		Expect(client.DestroyAndStop()).To(Succeed())
	})

	It("should not leak goroutines", func() {
		handle := fmt.Sprintf("goroutine-leak-test-%d", GinkgoParallelNode())

		numGoroutinesBefore, err := client.NumGoroutines()
		Expect(err).NotTo(HaveOccurred())

		dumpBefore, err := client.DumpGoroutines()
		Expect(err).NotTo(HaveOccurred())
		_, err = client.Create(garden.ContainerSpec{
			Handle: handle,
		})
		Expect(err).NotTo(HaveOccurred())
		client.NumGoroutines()
		client.Destroy(handle)

		var numGoroutinesAfter int
		for i := 0; i < 10; i++ {
			var err error
			numGoroutinesAfter, err = client.NumGoroutines()
			Expect(err).NotTo(HaveOccurred())
			if numGoroutinesBefore == numGoroutinesAfter {
				break
			}
			time.Sleep(time.Millisecond * 100)
		}

		dumpAfter, err := client.DumpGoroutines()
		Expect(err).NotTo(HaveOccurred())
		Expect(numGoroutinesAfter).Should(Equal(numGoroutinesBefore),
			`FAILED: there are leaked goroutines (got from /debug/pprof/goroutine?debug=2)
----------------------------------------- Before -------------------------------------
%s
-----------------------------------------  After -------------------------------------
%s`,
			dumpBefore, dumpAfter,
		)

	})

	It("should destroy the container's rootfs", func() {
		container, err := client.Create(garden.ContainerSpec{})
		Expect(err).NotTo(HaveOccurred())

		info, err := container.Info()
		Expect(err).NotTo(HaveOccurred())
		containerRootfs := info.ContainerPath

		Expect(client.Destroy(container.Handle())).To(Succeed())

		Expect(containerRootfs).NotTo(BeAnExistingFile())
	})

	It("should destroy the container's depot directory", func() {
		container, err := client.Create(garden.ContainerSpec{})
		Expect(err).NotTo(HaveOccurred())

		Expect(client.Destroy(container.Handle())).To(Succeed())

		Expect(filepath.Join(client.DepotDir, container.Handle())).NotTo(BeAnExistingFile())
	})

	It("should kill the container's init process", func() {
		container, err := client.Create(garden.ContainerSpec{})
		Expect(err).NotTo(HaveOccurred())

		initProcPid := initProcessPID(container.Handle())

		_, err = container.Run(garden.ProcessSpec{
			Path: "/bin/sh",
			Args: []string{
				"-c", "read x",
			},
		}, ginkgoIO)
		Expect(err).NotTo(HaveOccurred())

		Expect(client.Destroy(container.Handle())).To(Succeed())

		var killExitCode = func() int {
			sess, err := gexec.Start(exec.Command("kill", "-0", fmt.Sprintf("%d", initProcPid)), GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())
			sess.Wait(1 * time.Second)
			return sess.ExitCode()
		}

		Eventually(killExitCode).Should(Equal(1))
	})

	Context("when container destroy is interrupted half way through", func() {
		// simulate this scenario by starting guardian with a network plugin which
		// kill -9s <guardian pid> on 'down' (i.e. half way through a container delete)
		// then, start the guardian server backup without the plugin, and ensuring that
		// --destroy-containers-on-startup=false
		var netPluginArgs []string

		BeforeEach(func() {
			tmpDir, err := ioutil.TempDir("", "netplugtest")
			Expect(err).NotTo(HaveOccurred())

			argsFile := path.Join(tmpDir, "args.log")
			stdinFile := path.Join(tmpDir, "stdin.log")

			pluginReturn := `{"properties":{
					"garden.network.container-ip":"10.255.10.10",
					"garden.network.host-ip":"255.255.255.255"
				}}`

			netPluginArgs = []string{
				"--properties-path", path.Join(tmpDir, "props.json"),
				"--network-plugin", binaries.NetworkPlugin,
				"--network-plugin-extra-arg", argsFile,
				"--network-plugin-extra-arg", stdinFile,
				"--network-plugin-extra-arg", pluginReturn,
			}

			args = append(netPluginArgs, []string{"--network-plugin-extra-arg", "kill-garden-server"}...)
		})

		It("leaves the bundle dir in the depot", func() {
			container, err := client.Create(garden.ContainerSpec{})
			Expect(err).NotTo(HaveOccurred())

			Expect(client.Destroy(container.Handle())).NotTo(Succeed())
			Eventually(client).Should(gexec.Exit())

			// start guardian back up with the 'kill -9 <gdn pid> on down' behaviour disabled
			client = startGarden(netPluginArgs...)

			bundleDir := filepath.Join(client.DepotDir, container.Handle())
			Expect(bundleDir).To(BeADirectory())

			Expect(client.Destroy(container.Handle())).To(Succeed())

			bundleDir = filepath.Join(client.DepotDir, container.Handle())
			Expect(bundleDir).NotTo(BeADirectory())
		})
	})

	Describe("networking resources", func() {
		var (
			container         garden.Container
			networkSpec       string
			contIfaceName     string
			networkBridgeName string
		)

		JustBeforeEach(func() {
			var err error

			networkSpec = fmt.Sprintf("177.100.%d.0/24", GinkgoParallelNode())
			container, err = client.Create(garden.ContainerSpec{
				Network: networkSpec,
			})
			Expect(err).NotTo(HaveOccurred())
			contIfaceName = ethInterfaceName(container)

			networkBridgeName, err = container.Property("kawasaki.bridge-interface")
			Expect(err).NotTo(HaveOccurred())
		})

		var itCleansUpPerContainerNetworkingResources = func() {
			It("should remove iptable entries", func() {
				out, err := runIPTables("-S", "-t", "filter")
				Expect(err).NotTo(HaveOccurred())
				Expect(string(out)).NotTo(MatchRegexp("w-%d-instance.* 177.100.%d.0/24", GinkgoParallelNode(), GinkgoParallelNode()))
			})

			It("should remove virtual ethernet cards", func() {
				ifconfigExits := func() int {
					session, err := gexec.Start(exec.Command("ifconfig", contIfaceName), GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())

					return session.Wait().ExitCode()
				}
				Eventually(ifconfigExits).ShouldNot(Equal(0))
			})
		}

		var itRemovesTheNetworkBridge = func() {
			It("should remove the network bridge", func() {
				session, err := gexec.Start(
					exec.Command("ip", "link", "show", networkBridgeName),
					GinkgoWriter, GinkgoWriter,
				)
				Expect(err).NotTo(HaveOccurred())

				session.Wait()
				Expect(session.ExitCode()).NotTo(Equal(0))
			})
		}

		Context("when destroy is called", func() {
			JustBeforeEach(func() {
				Expect(client.Destroy(container.Handle())).To(Succeed())
			})

			itCleansUpPerContainerNetworkingResources()
			itRemovesTheNetworkBridge()

			Context("and there was more than one containers in the same subnet", func() {
				var otherContainer garden.Container

				JustBeforeEach(func() {
					var err error

					otherContainer, err = client.Create(garden.ContainerSpec{
						Network: networkSpec,
					})
					Expect(err).NotTo(HaveOccurred())
				})

				JustBeforeEach(func() {
					Expect(client.Destroy(otherContainer.Handle())).To(Succeed())
				})

				itRemovesTheNetworkBridge()
			})
		})
	})
})

func ethInterfaceName(container garden.Container) string {
	buffer := gbytes.NewBuffer()
	proc, err := container.Run(
		garden.ProcessSpec{
			Path: "sh",
			Args: []string{"-c", "ifconfig | grep 'Ethernet' | cut -f 1 -d ' '"},
			User: "root",
		},
		garden.ProcessIO{
			Stdout: buffer,
			Stderr: GinkgoWriter,
		},
	)
	Expect(err).NotTo(HaveOccurred())
	Expect(proc.Wait()).To(Equal(0))

	contIfaceName := string(buffer.Contents()) // g3-abc-1

	return contIfaceName[:len(contIfaceName)-2] + "0" // g3-abc-0
}
<commit_msg>Relax goroutine leak test constraint<commit_after>package gqt_test

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"path"
	"path/filepath"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("Destroying a Container", func() {
	var (
		args   []string
		client *runner.RunningGarden
	)

	BeforeEach(func() {
		args = []string{"--debug-bind-ip", "0.0.0.0", "--debug-bind-port", fmt.Sprintf("%d", 8080+GinkgoParallelNode())}
	})

	JustBeforeEach(func() {
		client = startGarden(args...)
	})

	AfterEach(func() {
		Expect(client.DestroyAndStop()).To(Succeed())
	})

	It("should not leak goroutines", func() {
		var numGoRoutines = func() int {
			numGoroutines, err := client.NumGoroutines()
			Expect(err).NotTo(HaveOccurred())

			return numGoroutines
		}

		handle := fmt.Sprintf("goroutine-leak-test-%d", GinkgoParallelNode())

		numGoroutinesBefore := numGoRoutines()

		_, err := client.Create(garden.ContainerSpec{
			Handle: handle,
		})
		Expect(err).NotTo(HaveOccurred())
		Expect(client.Destroy(handle)).To(Succeed())

		Consistently(numGoRoutines).Should(BeNumerically("<=", numGoroutinesBefore))
	})

	It("should destroy the container's rootfs", func() {
		container, err := client.Create(garden.ContainerSpec{})
		Expect(err).NotTo(HaveOccurred())

		info, err := container.Info()
		Expect(err).NotTo(HaveOccurred())
		containerRootfs := info.ContainerPath

		Expect(client.Destroy(container.Handle())).To(Succeed())

		Expect(containerRootfs).NotTo(BeAnExistingFile())
	})

	It("should destroy the container's depot directory", func() {
		container, err := client.Create(garden.ContainerSpec{})
		Expect(err).NotTo(HaveOccurred())

		Expect(client.Destroy(container.Handle())).To(Succeed())

		Expect(filepath.Join(client.DepotDir, container.Handle())).NotTo(BeAnExistingFile())
	})

	It("should kill the container's init process", func() {
		container, err := client.Create(garden.ContainerSpec{})
		Expect(err).NotTo(HaveOccurred())

		initProcPid := initProcessPID(container.Handle())

		_, err = container.Run(garden.ProcessSpec{
			Path: "/bin/sh",
			Args: []string{
				"-c", "read x",
			},
		}, ginkgoIO)
		Expect(err).NotTo(HaveOccurred())

		Expect(client.Destroy(container.Handle())).To(Succeed())

		var killExitCode = func() int {
			sess, err := gexec.Start(exec.Command("kill", "-0", fmt.Sprintf("%d", initProcPid)), GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())
			sess.Wait(1 * time.Second)
			return sess.ExitCode()
		}

		Eventually(killExitCode).Should(Equal(1))
	})

	Context("when container destroy is interrupted half way through", func() {
		// simulate this scenario by starting guardian with a network plugin which
		// kill -9s <guardian pid> on 'down' (i.e. half way through a container delete)
		// then, start the guardian server backup without the plugin, and ensuring that
		// --destroy-containers-on-startup=false
		var netPluginArgs []string

		BeforeEach(func() {
			tmpDir, err := ioutil.TempDir("", "netplugtest")
			Expect(err).NotTo(HaveOccurred())

			argsFile := path.Join(tmpDir, "args.log")
			stdinFile := path.Join(tmpDir, "stdin.log")

			pluginReturn := `{"properties":{
					"garden.network.container-ip":"10.255.10.10",
					"garden.network.host-ip":"255.255.255.255"
				}}`

			netPluginArgs = []string{
				"--properties-path", path.Join(tmpDir, "props.json"),
				"--network-plugin", binaries.NetworkPlugin,
				"--network-plugin-extra-arg", argsFile,
				"--network-plugin-extra-arg", stdinFile,
				"--network-plugin-extra-arg", pluginReturn,
			}

			args = append(netPluginArgs, []string{"--network-plugin-extra-arg", "kill-garden-server"}...)
		})

		It("leaves the bundle dir in the depot", func() {
			container, err := client.Create(garden.ContainerSpec{})
			Expect(err).NotTo(HaveOccurred())

			Expect(client.Destroy(container.Handle())).NotTo(Succeed())
			Eventually(client).Should(gexec.Exit())

			// start guardian back up with the 'kill -9 <gdn pid> on down' behaviour disabled
			client = startGarden(netPluginArgs...)

			bundleDir := filepath.Join(client.DepotDir, container.Handle())
			Expect(bundleDir).To(BeADirectory())

			Expect(client.Destroy(container.Handle())).To(Succeed())

			bundleDir = filepath.Join(client.DepotDir, container.Handle())
			Expect(bundleDir).NotTo(BeADirectory())
		})
	})

	Describe("networking resources", func() {
		var (
			container         garden.Container
			networkSpec       string
			contIfaceName     string
			networkBridgeName string
		)

		JustBeforeEach(func() {
			var err error

			networkSpec = fmt.Sprintf("177.100.%d.0/24", GinkgoParallelNode())
			container, err = client.Create(garden.ContainerSpec{
				Network: networkSpec,
			})
			Expect(err).NotTo(HaveOccurred())
			contIfaceName = ethInterfaceName(container)

			networkBridgeName, err = container.Property("kawasaki.bridge-interface")
			Expect(err).NotTo(HaveOccurred())
		})

		var itCleansUpPerContainerNetworkingResources = func() {
			It("should remove iptable entries", func() {
				out, err := runIPTables("-S", "-t", "filter")
				Expect(err).NotTo(HaveOccurred())
				Expect(string(out)).NotTo(MatchRegexp("w-%d-instance.* 177.100.%d.0/24", GinkgoParallelNode(), GinkgoParallelNode()))
			})

			It("should remove virtual ethernet cards", func() {
				ifconfigExits := func() int {
					session, err := gexec.Start(exec.Command("ifconfig", contIfaceName), GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())

					return session.Wait().ExitCode()
				}
				Eventually(ifconfigExits).ShouldNot(Equal(0))
			})
		}

		var itRemovesTheNetworkBridge = func() {
			It("should remove the network bridge", func() {
				session, err := gexec.Start(
					exec.Command("ip", "link", "show", networkBridgeName),
					GinkgoWriter, GinkgoWriter,
				)
				Expect(err).NotTo(HaveOccurred())

				session.Wait()
				Expect(session.ExitCode()).NotTo(Equal(0))
			})
		}

		Context("when destroy is called", func() {
			JustBeforeEach(func() {
				Expect(client.Destroy(container.Handle())).To(Succeed())
			})

			itCleansUpPerContainerNetworkingResources()
			itRemovesTheNetworkBridge()

			Context("and there was more than one containers in the same subnet", func() {
				var otherContainer garden.Container

				JustBeforeEach(func() {
					var err error

					otherContainer, err = client.Create(garden.ContainerSpec{
						Network: networkSpec,
					})
					Expect(err).NotTo(HaveOccurred())
				})

				JustBeforeEach(func() {
					Expect(client.Destroy(otherContainer.Handle())).To(Succeed())
				})

				itRemovesTheNetworkBridge()
			})
		})
	})
})

func ethInterfaceName(container garden.Container) string {
	buffer := gbytes.NewBuffer()
	proc, err := container.Run(
		garden.ProcessSpec{
			Path: "sh",
			Args: []string{"-c", "ifconfig | grep 'Ethernet' | cut -f 1 -d ' '"},
			User: "root",
		},
		garden.ProcessIO{
			Stdout: buffer,
			Stderr: GinkgoWriter,
		},
	)
	Expect(err).NotTo(HaveOccurred())
	Expect(proc.Wait()).To(Equal(0))

	contIfaceName := string(buffer.Contents()) // g3-abc-1

	return contIfaceName[:len(contIfaceName)-2] + "0" // g3-abc-0
}
<|endoftext|>


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

package developer

import (
	"bytes"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/gorilla/mux"
	"github.com/serulian/compiler/builder"
	"github.com/serulian/compiler/compilercommon"
	"github.com/serulian/compiler/generator/es5"
	"github.com/serulian/compiler/graphs/scopegraph"
	"github.com/serulian/compiler/sourcemap"
)

// developerRuntimeTemplateStr defines the template for the ES code emitted to allow for
// UI when running the developer tool.
const developerRuntimeTemplateStr = `
	console.group('Compilation of project {{ .Name }}');
	console.info('Compilation has begun');
	document.write('<script src="http://localhost{{ .Addr }}/{{ .Name }}.develop.js"></script>');
`

// developTransaction represents a single transaction of loading source via the development
// server.
type developTransaction struct {
	vcsDevelopmentDirectories []string             // VCS development directory paths.
	rootSourceFilePath        string               // The root source file
	addr                      string               // The address of the running server.
	name                      string               // The name of the source being developed.
	offsetCount               int                  // The number of emitted call lines that offsets the generated source.
	sourceMap                 *sourcemap.SourceMap // The constructed source map.
}

func newDevelopTransaction(rootSourceFilePath string, vcsDevelopmentDirectories []string, addr string, name string) *developTransaction {
	return &developTransaction{
		vcsDevelopmentDirectories: vcsDevelopmentDirectories,
		rootSourceFilePath:        rootSourceFilePath,
		addr:                      addr,
		name:                      name,
		offsetCount:               0,
		sourceMap:                 nil,
	}
}

// Start starts the develop transaction by emitting the runtime that logs the build
// and requests the built data URL (which actually starts the build).
func (dt *developTransaction) Start(w http.ResponseWriter, r *http.Request) {
	// Emit the runtime.
	context := struct {
		Addr string
		Name string
	}{dt.addr, dt.name}

	// Write the runtime template.
	t := template.New("runtimeTemplate")
	parsedTemplate, err := t.Parse(developerRuntimeTemplateStr)
	if err != nil {
		panic(err)
	}

	var source bytes.Buffer
	eerr := parsedTemplate.Execute(&source, context)
	if eerr != nil {
		panic(eerr)
	}

	fmt.Fprint(w, source.String())
}

// Build performs the build of the source, writing the result to the response writer.
func (dt *developTransaction) Build(w http.ResponseWriter, r *http.Request) {
	// Build a scope graph for the project. This will conduct parsing and type graph
	// construction on our behalf.
	scopeResult := scopegraph.ParseAndBuildScopeGraph(dt.rootSourceFilePath,
		dt.vcsDevelopmentDirectories,
		builder.CORE_LIBRARY)

	if !scopeResult.Status {
		dt.sourceMap = sourcemap.NewSourceMap(dt.name+".develop.js", "source/")

		for _, warning := range scopeResult.Warnings {
			dt.emitWarning(w, warning)
		}

		for _, err := range scopeResult.Errors {
			dt.emitError(w, err)
		}

		dt.emitInfo(w, "Build failed")
		dt.closeGroup(w)
	} else {
		// Generate the program's source.
		generated, sourceMap, err := es5.GenerateES5(scopeResult.Graph, dt.name+".develop.js", "source/")
		if err != nil {
			panic(err)
		}

		dt.sourceMap = sourceMap

		fmt.Fprint(w, generated)
		dt.emitInfo(w, "Build completed successfully")
		dt.closeGroup(w)

		dt.offsetCount = len(strings.Split(string(generated), "\n"))

		for _, warning := range scopeResult.Warnings {
			dt.emitWarning(w, warning)
		}
	}

	fmt.Fprintf(w, "//# sourceMappingURL=/%s.develop.js.map\n", dt.name)
}

func (dt *developTransaction) ServeSourceMap(w http.ResponseWriter, r *http.Request) {
	marshalled, err := dt.sourceMap.Build().Marshal()
	if err != nil {
		panic(err)
	}

	fmt.Fprint(w, string(marshalled))
}

func (dt *developTransaction) ServeSourceFile(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	path := params["path"]

	fullPath := filepath.Join(filepath.Dir(dt.rootSourceFilePath), string(path))
	contents, err := ioutil.ReadFile(fullPath)
	if err != nil {
		fmt.Fprintf(w, "Error when trying to read source file %s: %v", fullPath, err)
	}

	fmt.Fprint(w, string(contents))
}

func (dt *developTransaction) emitError(w http.ResponseWriter, err compilercommon.SourceError) {
	message := fmt.Sprintf("console.error(%v);\n", strconv.Quote(err.Error()))
	fmt.Fprint(w, message)

	dt.sourceMap.AddMapping(dt.offsetCount, 0, sourcemap.SourceMapping{
		SourcePath:     string(err.SourceAndLocation().Source()),
		LineNumber:     err.SourceAndLocation().Location().LineNumber(),
		ColumnPosition: err.SourceAndLocation().Location().ColumnPosition(),
	})

	dt.offsetCount++
}

func (dt *developTransaction) emitWarning(w http.ResponseWriter, warn compilercommon.SourceWarning) {
	message := fmt.Sprintf("console.warn(%v);\n", strconv.Quote(warn.String()))
	fmt.Fprint(w, message)

	dt.sourceMap.AddMapping(dt.offsetCount, 0, sourcemap.SourceMapping{
		SourcePath:     string(warn.SourceAndLocation().Source()),
		LineNumber:     warn.SourceAndLocation().Location().LineNumber(),
		ColumnPosition: warn.SourceAndLocation().Location().ColumnPosition(),
	})

	dt.offsetCount++
}

func (dt *developTransaction) emitInfo(w http.ResponseWriter, msg string, args ...interface{}) {
	fmt.Fprintf(w, "console.info('%v');\n", fmt.Sprintf(msg, args...))
	dt.offsetCount++
}

func (dt *developTransaction) closeGroup(w http.ResponseWriter) {
	fmt.Fprintf(w, "console.groupEnd();\n")
	dt.offsetCount++
}
<commit_msg>Fix develop lookup of VCS dev dir dependencies<commit_after>// Copyright 2015 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package developer

import (
	"bytes"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/gorilla/mux"
	"github.com/serulian/compiler/builder"
	"github.com/serulian/compiler/compilercommon"
	"github.com/serulian/compiler/generator/es5"
	"github.com/serulian/compiler/graphs/scopegraph"
	"github.com/serulian/compiler/sourcemap"
)

// developerRuntimeTemplateStr defines the template for the ES code emitted to allow for
// UI when running the developer tool.
const developerRuntimeTemplateStr = `
	console.group('Compilation of project {{ .Name }}');
	console.info('Compilation has begun');
	document.write('<script src="http://localhost{{ .Addr }}/{{ .Name }}.develop.js"></script>');
`

// developTransaction represents a single transaction of loading source via the development
// server.
type developTransaction struct {
	vcsDevelopmentDirectories []string             // VCS development directory paths.
	rootSourceFilePath        string               // The root source file
	addr                      string               // The address of the running server.
	name                      string               // The name of the source being developed.
	offsetCount               int                  // The number of emitted call lines that offsets the generated source.
	sourceMap                 *sourcemap.SourceMap // The constructed source map.
}

func newDevelopTransaction(rootSourceFilePath string, vcsDevelopmentDirectories []string, addr string, name string) *developTransaction {
	return &developTransaction{
		vcsDevelopmentDirectories: vcsDevelopmentDirectories,
		rootSourceFilePath:        rootSourceFilePath,
		addr:                      addr,
		name:                      name,
		offsetCount:               0,
		sourceMap:                 nil,
	}
}

// Start starts the develop transaction by emitting the runtime that logs the build
// and requests the built data URL (which actually starts the build).
func (dt *developTransaction) Start(w http.ResponseWriter, r *http.Request) {
	// Emit the runtime.
	context := struct {
		Addr string
		Name string
	}{dt.addr, dt.name}

	// Write the runtime template.
	t := template.New("runtimeTemplate")
	parsedTemplate, err := t.Parse(developerRuntimeTemplateStr)
	if err != nil {
		panic(err)
	}

	var source bytes.Buffer
	eerr := parsedTemplate.Execute(&source, context)
	if eerr != nil {
		panic(eerr)
	}

	fmt.Fprint(w, source.String())
}

// Build performs the build of the source, writing the result to the response writer.
func (dt *developTransaction) Build(w http.ResponseWriter, r *http.Request) {
	// Build a scope graph for the project. This will conduct parsing and type graph
	// construction on our behalf.
	scopeResult := scopegraph.ParseAndBuildScopeGraph(dt.rootSourceFilePath,
		dt.vcsDevelopmentDirectories,
		builder.CORE_LIBRARY)

	if !scopeResult.Status {
		dt.sourceMap = sourcemap.NewSourceMap(dt.name+".develop.js", "source/")

		for _, warning := range scopeResult.Warnings {
			dt.emitWarning(w, warning)
		}

		for _, err := range scopeResult.Errors {
			dt.emitError(w, err)
		}

		dt.emitInfo(w, "Build failed")
		dt.closeGroup(w)
	} else {
		// Generate the program's source.
		generated, sourceMap, err := es5.GenerateES5(scopeResult.Graph, dt.name+".develop.js", "source/")
		if err != nil {
			panic(err)
		}

		dt.sourceMap = sourceMap

		fmt.Fprint(w, generated)
		dt.emitInfo(w, "Build completed successfully")
		dt.closeGroup(w)

		dt.offsetCount = len(strings.Split(string(generated), "\n"))

		for _, warning := range scopeResult.Warnings {
			dt.emitWarning(w, warning)
		}
	}

	fmt.Fprintf(w, "//# sourceMappingURL=/%s.develop.js.map\n", dt.name)
}

func (dt *developTransaction) ServeSourceMap(w http.ResponseWriter, r *http.Request) {
	marshalled, err := dt.sourceMap.Build().Marshal()
	if err != nil {
		panic(err)
	}

	fmt.Fprint(w, string(marshalled))
}

func (dt *developTransaction) ServeSourceFile(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	path := params["path"]

	fullPath := filepath.Join(filepath.Dir(dt.rootSourceFilePath), string(path))
	if _, err := os.Stat(fullPath); err != nil {
		fullPath = "/" + path
	}

	contents, err := ioutil.ReadFile(fullPath)
	if err != nil {
		fmt.Fprintf(w, "Error when trying to read source file %s: %v", fullPath, err)
	}

	fmt.Fprint(w, string(contents))
}

func (dt *developTransaction) emitError(w http.ResponseWriter, err compilercommon.SourceError) {
	message := fmt.Sprintf("console.error(%v);\n", strconv.Quote(err.Error()))
	fmt.Fprint(w, message)

	dt.sourceMap.AddMapping(dt.offsetCount, 0, sourcemap.SourceMapping{
		SourcePath:     string(err.SourceAndLocation().Source()),
		LineNumber:     err.SourceAndLocation().Location().LineNumber(),
		ColumnPosition: err.SourceAndLocation().Location().ColumnPosition(),
	})

	dt.offsetCount++
}

func (dt *developTransaction) emitWarning(w http.ResponseWriter, warn compilercommon.SourceWarning) {
	message := fmt.Sprintf("console.warn(%v);\n", strconv.Quote(warn.String()))
	fmt.Fprint(w, message)

	dt.sourceMap.AddMapping(dt.offsetCount, 0, sourcemap.SourceMapping{
		SourcePath:     string(warn.SourceAndLocation().Source()),
		LineNumber:     warn.SourceAndLocation().Location().LineNumber(),
		ColumnPosition: warn.SourceAndLocation().Location().ColumnPosition(),
	})

	dt.offsetCount++
}

func (dt *developTransaction) emitInfo(w http.ResponseWriter, msg string, args ...interface{}) {
	fmt.Fprintf(w, "console.info('%v');\n", fmt.Sprintf(msg, args...))
	dt.offsetCount++
}

func (dt *developTransaction) closeGroup(w http.ResponseWriter) {
	fmt.Fprintf(w, "console.groupEnd();\n")
	dt.offsetCount++
}
<|endoftext|>


<commit_before>package dev

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/moomerman/phx-dev/multiproxy"
	"github.com/puma/puma-dev/homedir"
	"github.com/vektra/errors"
)

const appsPath = "~/.phx-dev"

var apps map[string]*App
var lock sync.Mutex

type App struct {
	Host    string
	Port    string
	Link    string
	Dir     string
	Command *exec.Cmd

	proxy    *multiproxy.MultiProxy
	stdout   io.Reader
	lastUsed time.Time
}

func (a *App) Start() error {
	path := homedir.MustExpand(appsPath) + "/" + a.Host
	stat, err := os.Stat(path)
	if err != nil {
		return err
	}

	dir, err := os.Readlink(path)
	if err != nil {
		return err
	}

	if stat.IsDir() {
		a.Link = path
		a.Dir = dir
	} else {
		return errors.New("unknown app")
	}

	return a.launch()
}

func (a *App) Stop(reason string, e error) error {
	fmt.Printf("! Stopping '%s' (%d) %s %s\n", a.Host, a.Command.Process.Pid, reason, e)
	lock.Lock()
	defer lock.Unlock()
	delete(apps, a.Host)

	err := a.Command.Process.Kill()
	if err != nil {
		fmt.Printf("! Error trying to stop %s: %s", a.Host, err)
		return err
	}

	a.Command.Wait()

	fmt.Printf("* App '%s' shutdown and cleaned up\n", a.Host)
	return nil
}

const executionShell = `exec bash -c '
cd %s
exec mix do deps.get, phx.server'
`

func (a *App) launch() error {
	shell := os.Getenv("SHELL")
	addr := findAvailableAddr()
	_, port, err := net.SplitHostPort(addr)
	a.Port = port

	cmd := exec.Command(shell, "-l", "-i", "-c",
		fmt.Sprintf(executionShell, a.Dir))

	cmd.Dir = a.Dir

	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env,
		fmt.Sprintf("PHX_PORT=%s", a.Port),
	)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	a.stdout = stdout
	cmd.Stderr = cmd.Stdout

	err = cmd.Start()
	if err != nil {
		return errors.Context(err, "starting app")
	}

	a.Command = cmd
	a.proxy = multiproxy.NewProxy("http://127.0.0.1:"+a.Port, a.Host)

	time.Sleep(5 * time.Second)

	go a.tail()
	go a.idleMonitor()

	return nil
}

func (a *App) tail() error {
	c := make(chan error)

	go func() {
		r := bufio.NewReader(a.stdout)

		for {
			line, err := r.ReadString('\n')
			if line != "" {
				fmt.Fprintf(os.Stdout, "  [app] %s:%s[%d]: %s", a.Host, a.Port, a.Command.Process.Pid, line)
				mustRestart, _ := regexp.Compile("You must restart your server")
				if mustRestart.MatchString(line) {
					c <- errors.New("Restart required")
					return
				}
			}

			if err != nil {
				c <- err
				return
			}
		}
	}()

	var err error

	select {
	case err = <-c:
		err = errors.Context(err, "stdout/stderr closed")
	}

	a.Stop("see error", err)

	return err
}

func (a *App) idleMonitor() error {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if a.idle() {
				a.Stop("app is idle", nil)
				return nil
			}
		}
	}

	return nil
}

func (a *App) idle() bool {
	diff := time.Since(a.lastUsed)
	if diff > 60*60*time.Second {
		lock.Lock()
		defer lock.Unlock()
		return true
	}

	return false
}

func findAppForHost(host string) (*App, error) {
	lock.Lock()
	defer lock.Unlock()

	hostParts := strings.Split(host, ":")
	host = hostParts[0]

	if apps == nil {
		apps = make(map[string]*App)
	}

	app := apps[host]
	if app != nil {
		app.lastUsed = time.Now()
		return app, nil
	}

	fmt.Println("[app] attempting to start app for host", host)

	app = &App{
		Host:     host,
		lastUsed: time.Now(),
	}

	err := app.Start()
	if err != nil {
		fmt.Println("[app] error starting app for host", host, err)
		return nil, err
	}

	fmt.Println("[app] created app for host", host, app.Port)
	// TODO: apps should be keyed by Dir not host as you might have multiple
	// hosts pointing to the same app
	apps[host] = app
	return app, nil
}

func findAvailableAddr() string {
	l, _ := net.Listen("tcp", ":0")
	l.Close()
	return l.Addr().String()
}
<commit_msg>Properly waiting for app to start on request<commit_after>package dev

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/moomerman/phx-dev/multiproxy"
	"github.com/puma/puma-dev/homedir"
	"github.com/vektra/errors"
)

const appsPath = "~/.phx-dev"

var apps map[string]*App
var lock sync.Mutex

type App struct {
	Host    string
	Port    string
	Link    string
	Dir     string
	Command *exec.Cmd

	proxy     *multiproxy.MultiProxy
	stdout    io.Reader
	lastUsed  time.Time
	readyChan chan struct{}
}

func (a *App) Start() error {
	path := homedir.MustExpand(appsPath) + "/" + a.Host
	stat, err := os.Stat(path)
	if err != nil {
		return err
	}

	dir, err := os.Readlink(path)
	if err != nil {
		return err
	}

	if stat.IsDir() {
		a.Link = path
		a.Dir = dir
	} else {
		return errors.New("unknown app")
	}

	return a.launch()
}

func (a *App) Stop(reason string, e error) error {
	fmt.Printf("! Stopping '%s' (%d) %s %s\n", a.Host, a.Command.Process.Pid, reason, e)
	lock.Lock()
	defer lock.Unlock()
	delete(apps, a.Host)

	err := a.Command.Process.Kill()
	if err != nil {
		fmt.Printf("! Error trying to stop %s: %s", a.Host, err)
		return err
	}

	a.Command.Wait()

	fmt.Printf("* App '%s' shutdown and cleaned up\n", a.Host)
	return nil
}

const executionShell = `exec bash -c '
cd %s
exec mix do deps.get, phx.server'
`

func (a *App) launch() error {
	shell := os.Getenv("SHELL")

	port, err := findAvailablePort()
	if err != nil {
		return errors.Context(err, "couldn't find available port")
	}

	a.Port = port

	cmd := exec.Command(shell, "-l", "-i", "-c",
		fmt.Sprintf(executionShell, a.Dir))

	cmd.Dir = a.Dir

	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env,
		fmt.Sprintf("PHX_PORT=%s", a.Port),
	)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	a.stdout = stdout
	cmd.Stderr = cmd.Stdout

	err = cmd.Start()
	if err != nil {
		return errors.Context(err, "starting app")
	}

	a.Command = cmd
	a.proxy = multiproxy.NewProxy("http://127.0.0.1:"+a.Port, a.Host)

	go a.tail()

	err = a.wait()
	if err != nil {
		return errors.Context(err, "failed waiting for app to start")
	}

	go a.idleMonitor()

	return nil
}

func (a *App) tail() error {
	c := make(chan error)

	go func() {
		r := bufio.NewReader(a.stdout)

		for {
			line, err := r.ReadString('\n')
			if line != "" {
				fmt.Fprintf(os.Stdout, "  [app] %s:%s[%d]: %s", a.Host, a.Port, a.Command.Process.Pid, line)

				mustRestart, _ := regexp.Compile("You must restart your server")
				if mustRestart.MatchString(line) {
					c <- errors.New("Restart required")
					return
				}

				ready, _ := regexp.Compile("Running .*.Endpoint") // TODO: also grep for the port
				if ready.MatchString(line) {
					close(a.readyChan)
				}
			}

			if err != nil {
				c <- err
				return
			}
		}
	}()

	var err error

	select {
	case err = <-c:
		err = errors.Context(err, "stdout/stderr closed")
	}

	a.Stop("see error", err)

	return err
}

func (a *App) idleMonitor() error {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if a.idle() {
				a.Stop("app is idle", nil)
				return nil
			}
		}
	}

	return nil
}

func (a *App) idle() bool {
	diff := time.Since(a.lastUsed)
	if diff > 60*60*time.Second {
		lock.Lock()
		defer lock.Unlock()
		return true
	}

	return false
}

func findAppForHost(host string) (*App, error) {
	lock.Lock()
	defer lock.Unlock()

	hostParts := strings.Split(host, ":")
	host = hostParts[0]

	if apps == nil {
		apps = make(map[string]*App)
	}

	app := apps[host]
	if app != nil {
		app.lastUsed = time.Now()
		return app, nil
	}

	fmt.Println("[app] attempting to start app for host", host)

	app = &App{
		Host:      host,
		readyChan: make(chan struct{}),
	}

	err := app.Start()
	if err != nil {
		fmt.Println("[app] error starting app for host", host, err)
		return nil, err
	}

	fmt.Println("[app] created app for host", host, app.Port)
	// TODO: apps should be keyed by Dir not host as you might have multiple
	// hosts pointing to the same app
	apps[host] = app
	return app, nil
}

func findAvailablePort() (string, error) {
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		return "", err
	}
	l.Close()

	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return "", err
	}

	return port, nil
}

func (a *App) wait() error {
	select {
	case <-a.readyChan:
		fmt.Println("[app] app ready", a.Host)
		a.lastUsed = time.Now()
		return nil
	}
}
<|endoftext|>


<commit_before>package genericsite

// Dismisses various attempts at accessing this site

import (
	"github.com/xyproto/web"
)

// Honeypot?
func ServeForFun() {
	// These appeared in the log
	bogus := []string{"/signup", "/wp-login.php", "/join.php", "/register.php", "/profile.php", "/user/register/", "/tools/quicklogin.one", "/sign_up.html", "/profile.php", "/ucp.php", "/account/register.php", "/join_form.php", "/tiki-register.php", "/YaBB.cgi/", "/YaBB.pl/", "/member/register", "/signup.php", "/blogs/load/recent", "/member/join.php"}
	for _, location := range bogus {
		web.Get(location, Hello)
	}

	bogusParam := []string{"/index.php", "/viewtopic.php"}
	for _, location := range bogusParam {
		web.Get(location, ParamExample)
	}
}
<commit_msg>Added two functions<commit_after>package genericsite

// Dismisses various attempts at accessing this site. Honeypot?

import (
	"fmt"

	"github.com/xyproto/instapage"
	"github.com/xyproto/web"
)

func Hello() string {
	msg := "Hi"
	return instapage.Message("Hello", msg)
}

func ParamExample(ctx *web.Context) string {
	return fmt.Sprintf("%v\n", ctx.Params)
}

func ServeForFun() {
	// These appeared in the log
	bogus := []string{"/signup", "/wp-login.php", "/join.php", "/register.php", "/profile.php", "/user/register/", "/tools/quicklogin.one", "/sign_up.html", "/profile.php", "/ucp.php", "/account/register.php", "/join_form.php", "/tiki-register.php", "/YaBB.cgi/", "/YaBB.pl/", "/member/register", "/signup.php", "/blogs/load/recent", "/member/join.php"}
	for _, location := range bogus {
		web.Get(location, Hello)
	}

	bogusParam := []string{"/index.php", "/viewtopic.php"}
	for _, location := range bogusParam {
		web.Get(location, ParamExample)
	}
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * This is very experimental code and probably a long way from perfect or
 * ideal.  Please provide feed back on areas that would improve performance
 *
 */

// **********************************************************************
// NOTE :: This is getting closer to a Opus<->PCM layer for Discordgo and will
// probably eventually move into a sub-folder of the Discordgo package.
// **********************************************************************

// Package dgvoice provides opus encoding and audio file playback for the
// Discordgo package.
package dgvoice

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"sync"

	"github.com/bwmarrin/discordgo"
	"layeh.com/gopus"
)

// NOTE: This API is not final and these are likely to change.

// Technically the below settings can be adjusted however that poses
// a lot of other problems that are not handled well at this time.
// These below values seem to provide the best overall performance
const (
	channels  int = 2                   // 1 for mono, 2 for stereo
	frameRate int = 48000               // audio sampling rate
	frameSize int = 960                 // uint16 size of each audio frame
	maxBytes  int = (frameSize * 2) * 2 // max size of opus data
)

var (
	speakers    map[uint32]*gopus.Decoder
	opusEncoder *gopus.Encoder
	run         *exec.Cmd
	sendpcm     bool
	recvpcm     bool
	recv        chan *discordgo.Packet
	send        chan []int16
	mu          sync.Mutex
)

// SendPCM will receive on the provied channel encode
// received PCM data into Opus then send that to Discordgo
func SendPCM(v *discordgo.VoiceConnection, pcm <-chan []int16) {

	// make sure this only runs one instance at a time.
	mu.Lock()
	if sendpcm || pcm == nil {
		mu.Unlock()
		return
	}
	sendpcm = true
	mu.Unlock()

	defer func() { sendpcm = false }()

	var err error

	opusEncoder, err = gopus.NewEncoder(frameRate, channels, gopus.Audio)

	if err != nil {
		fmt.Println("NewEncoder Error:", err)
		return
	}

	for {

		// read pcm from chan, exit if channel is closed.
		recv, ok := <-pcm
		if !ok {
			fmt.Println("PCM Channel closed.")
			return
		}

		// try encoding pcm frame with Opus
		opus, err := opusEncoder.Encode(recv, frameSize, maxBytes)
		if err != nil {
			fmt.Println("Encoding Error:", err)
			return
		}

		if v.Ready == false || v.OpusSend == nil {
			fmt.Printf("Discordgo not ready for opus packets. %+v : %+v", v.Ready, v.OpusSend)
			return
		}
		// send encoded opus data to the sendOpus channel
		v.OpusSend <- opus
	}
}

// ReceivePCM will receive on the the Discordgo OpusRecv channel and decode
// the opus audio into PCM then send it on the provided channel.
func ReceivePCM(v *discordgo.VoiceConnection, c chan *discordgo.Packet) {

	// make sure this only runs one instance at a time.
	mu.Lock()
	if recvpcm || c == nil {
		mu.Unlock()
		return
	}
	recvpcm = true
	mu.Unlock()

	defer func() { sendpcm = false }()
	var err error

	for {

		if v.Ready == false || v.OpusRecv == nil {
			fmt.Printf("Discordgo not ready to receive opus packets. %+v : %+v", v.Ready, v.OpusRecv)
			return
		}

		p, ok := <-v.OpusRecv
		if !ok {
			return
		}

		if speakers == nil {
			speakers = make(map[uint32]*gopus.Decoder)
		}

		_, ok = speakers[p.SSRC]
		if !ok {
			speakers[p.SSRC], err = gopus.NewDecoder(48000, 2)
			if err != nil {
				fmt.Println("error creating opus decoder:", err)
				continue
			}
		}

		p.PCM, err = speakers[p.SSRC].Decode(p.Opus, 960, false)
		if err != nil {
			fmt.Println("Error decoding opus data: ", err)
			continue
		}

		c <- p
	}
}

// PlayAudioFile will play the given filename to the already connected
// Discord voice server/channel.  voice websocket and udp socket
// must already be setup before this will work.
func PlayAudioFile(v *discordgo.VoiceConnection, filename string) {

	// Create a shell command "object" to run.
	run = exec.Command("ffmpeg", "-i", filename, "-f", "s16le", "-ar", strconv.Itoa(frameRate), "-ac", strconv.Itoa(channels), "pipe:1")
	ffmpegout, err := run.StdoutPipe()
	if err != nil {
		fmt.Println("StdoutPipe Error:", err)
		return
	}

	ffmpegbuf := bufio.NewReaderSize(ffmpegout, 16384)

	// Starts the ffmpeg command
	err = run.Start()
	if err != nil {
		fmt.Println("RunStart Error:", err)
		return
	}

	// Send "speaking" packet over the voice websocket
	v.Speaking(true)

	// Send not "speaking" packet over the websocket when we finish
	defer v.Speaking(false)

	// will actually only spawn one instance, a bit hacky.
	if send == nil {
		send = make(chan []int16, 2)
	}
	go SendPCM(v, send)

	for {

		// read data from ffmpeg stdout
		audiobuf := make([]int16, frameSize*channels)
		err = binary.Read(ffmpegbuf, binary.LittleEndian, &audiobuf)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			return
		}
		if err != nil {
			fmt.Println("error reading from ffmpeg stdout :", err)
			return
		}

		// Send received PCM to the sendPCM channel
		send <- audiobuf
	}
}

// KillPlayer forces the player to stop by killing the ffmpeg cmd process
// this method may be removed later in favor of using chans or bools to
// request a stop.
func KillPlayer() {
	run.Process.Kill()
}
<commit_msg>Clean up comments<commit_after>/*******************************************************************************
 * This is very experimental code and probably a long way from perfect or
 * ideal.  Please provide feed back on areas that would improve performance
 *
 */

// Package dgvoice provides opus encoding and audio file playback for the
// Discordgo package.
package dgvoice

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"sync"

	"github.com/bwmarrin/discordgo"
	"layeh.com/gopus"
)

// NOTE: This API is not final and these are likely to change.

// Technically the below settings can be adjusted however that poses
// a lot of other problems that are not handled well at this time.
// These below values seem to provide the best overall performance
const (
	channels  int = 2                   // 1 for mono, 2 for stereo
	frameRate int = 48000               // audio sampling rate
	frameSize int = 960                 // uint16 size of each audio frame
	maxBytes  int = (frameSize * 2) * 2 // max size of opus data
)

var (
	speakers    map[uint32]*gopus.Decoder
	opusEncoder *gopus.Encoder
	run         *exec.Cmd
	sendpcm     bool
	recvpcm     bool
	recv        chan *discordgo.Packet
	send        chan []int16
	mu          sync.Mutex
)

// SendPCM will receive on the provied channel encode
// received PCM data into Opus then send that to Discordgo
func SendPCM(v *discordgo.VoiceConnection, pcm <-chan []int16) {

	// make sure this only runs one instance at a time.
	mu.Lock()
	if sendpcm || pcm == nil {
		mu.Unlock()
		return
	}
	sendpcm = true
	mu.Unlock()

	defer func() { sendpcm = false }()

	var err error

	opusEncoder, err = gopus.NewEncoder(frameRate, channels, gopus.Audio)

	if err != nil {
		fmt.Println("NewEncoder Error:", err)
		return
	}

	for {

		// read pcm from chan, exit if channel is closed.
		recv, ok := <-pcm
		if !ok {
			fmt.Println("PCM Channel closed.")
			return
		}

		// try encoding pcm frame with Opus
		opus, err := opusEncoder.Encode(recv, frameSize, maxBytes)
		if err != nil {
			fmt.Println("Encoding Error:", err)
			return
		}

		if v.Ready == false || v.OpusSend == nil {
			fmt.Printf("Discordgo not ready for opus packets. %+v : %+v", v.Ready, v.OpusSend)
			return
		}
		// send encoded opus data to the sendOpus channel
		v.OpusSend <- opus
	}
}

// ReceivePCM will receive on the the Discordgo OpusRecv channel and decode
// the opus audio into PCM then send it on the provided channel.
func ReceivePCM(v *discordgo.VoiceConnection, c chan *discordgo.Packet) {

	// make sure this only runs one instance at a time.
	mu.Lock()
	if recvpcm || c == nil {
		mu.Unlock()
		return
	}
	recvpcm = true
	mu.Unlock()

	defer func() { sendpcm = false }()
	var err error

	for {

		if v.Ready == false || v.OpusRecv == nil {
			fmt.Printf("Discordgo not ready to receive opus packets. %+v : %+v", v.Ready, v.OpusRecv)
			return
		}

		p, ok := <-v.OpusRecv
		if !ok {
			return
		}

		if speakers == nil {
			speakers = make(map[uint32]*gopus.Decoder)
		}

		_, ok = speakers[p.SSRC]
		if !ok {
			speakers[p.SSRC], err = gopus.NewDecoder(48000, 2)
			if err != nil {
				fmt.Println("error creating opus decoder:", err)
				continue
			}
		}

		p.PCM, err = speakers[p.SSRC].Decode(p.Opus, 960, false)
		if err != nil {
			fmt.Println("Error decoding opus data: ", err)
			continue
		}

		c <- p
	}
}

// PlayAudioFile will play the given filename to the already connected
// Discord voice server/channel.  voice websocket and udp socket
// must already be setup before this will work.
func PlayAudioFile(v *discordgo.VoiceConnection, filename string) {

	// Create a shell command "object" to run.
	run = exec.Command("ffmpeg", "-i", filename, "-f", "s16le", "-ar", strconv.Itoa(frameRate), "-ac", strconv.Itoa(channels), "pipe:1")
	ffmpegout, err := run.StdoutPipe()
	if err != nil {
		fmt.Println("StdoutPipe Error:", err)
		return
	}

	ffmpegbuf := bufio.NewReaderSize(ffmpegout, 16384)

	// Starts the ffmpeg command
	err = run.Start()
	if err != nil {
		fmt.Println("RunStart Error:", err)
		return
	}

	// Send "speaking" packet over the voice websocket
	v.Speaking(true)

	// Send not "speaking" packet over the websocket when we finish
	defer v.Speaking(false)

	// will actually only spawn one instance, a bit hacky.
	if send == nil {
		send = make(chan []int16, 2)
	}
	go SendPCM(v, send)

	for {

		// read data from ffmpeg stdout
		audiobuf := make([]int16, frameSize*channels)
		err = binary.Read(ffmpegbuf, binary.LittleEndian, &audiobuf)
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			return
		}
		if err != nil {
			fmt.Println("error reading from ffmpeg stdout :", err)
			return
		}

		// Send received PCM to the sendPCM channel
		send <- audiobuf
	}
}

// KillPlayer forces the player to stop by killing the ffmpeg cmd process
// this method may be removed later in favor of using chans or bools to
// request a stop.
func KillPlayer() {
	run.Process.Kill()
}
<|endoftext|>