<commit_before>package gode

import (
	"archive/tar"
	"compress/gzip"
	"io"
	"os"
	"path/filepath"
	"runtime"

	"github.com/franela/goreq"
)

// IsSetup returns true if node is setup in the client's RootPath directory
func (c *Client) IsSetup() bool {
	if exists, _ := fileExists(c.nodePath()); !exists {
		return false
	}

	exists, _ := fileExists(c.npmPath())
	return exists
}

// Setup downloads and sets up node in the client's RootPath directory
func (c *Client) Setup() error {
	if c.IsSetup() {
		return nil
	}
	if runtime.GOOS == "windows" {
		return c.setupWindows()
	}
	return c.setupUnix()
}

func (c *Client) setupUnix() error {
	err := os.MkdirAll(filepath.Join(c.RootPath, "node_modules"), 0755)
	if err != nil {
		return err
	}
	resp, err := goreq.Request{Uri: c.nodeURL()}.Do()
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	uncompressed, err := gzip.NewReader(resp.Body)
	if err != nil {
		return err
	}
	tmpDir := c.tmpDir("node")
	extractTar(tar.NewReader(uncompressed), tmpDir)
	newDir := filepath.Join(c.RootPath, c.NodeBase())
	os.RemoveAll(newDir)
	err = os.Rename(filepath.Join(tmpDir, c.NodeBase()), newDir)
	if err != nil {
		return err
	}
	return os.Remove(tmpDir)
}

func (c *Client) setupWindows() error {
	os.RemoveAll(filepath.Join(c.RootPath, c.NodeBase()))
	modulesDir := filepath.Join(c.RootPath, c.NodeBase(), "lib", "node_modules")
	if err := os.MkdirAll(modulesDir, 0755); err != nil {
		return err
	}
	if err := c.downloadNpm(modulesDir); err != nil {
		return err
	}
	return c.downloadFile(c.nodePath(), c.nodeURL())
}

func (c *Client) downloadFile(path, url string) error {
	tmp := filepath.Join(c.tmpDir("download"), "file")
	resp, err := goreq.Request{Uri: url}.Do()
	if err != nil {
		return err
	}
	file, err := os.Create(tmp)
	if err != nil {
		return err
	}
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		return err
	}
	file.Close()
	resp.Body.Close()
	err = os.MkdirAll(filepath.Dir(path), 0755)
	if err != nil {
		return err
	}
	os.Remove(path)
	err = os.Rename(tmp, path)
	if err != nil {
		return err
	}
	return os.RemoveAll(filepath.Dir(tmp))
}

func (c *Client) downloadNpm(modulesDir string) error {
	tmpDir := c.tmpDir("node")
	zipfile := filepath.Join(tmpDir, "npm.zip")
	err := c.downloadFile(zipfile, c.npmURL())
	if err != nil {
		return err
	}
	err = extractZip(zipfile, tmpDir)
	if err != nil {
		return err
	}
	os.Rename(filepath.Join(tmpDir, "npm-"+c.NpmVersion), filepath.Join(modulesDir, "npm"))
	if err != nil {
		return err
	}
	return os.RemoveAll(tmpDir)
}
<commit_msg>fix windows iojs download<commit_after>package gode

import (
	"archive/tar"
	"compress/gzip"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"runtime"

	"github.com/franela/goreq"
)

// IsSetup returns true if node is setup in the client's RootPath directory
func (c *Client) IsSetup() bool {
	if exists, _ := fileExists(c.nodePath()); !exists {
		return false
	}

	exists, _ := fileExists(c.npmPath())
	return exists
}

// Setup downloads and sets up node in the client's RootPath directory
func (c *Client) Setup() error {
	if c.IsSetup() {
		return nil
	}
	if runtime.GOOS == "windows" {
		return c.setupWindows()
	}
	return c.setupUnix()
}

func (c *Client) setupUnix() error {
	err := os.MkdirAll(filepath.Join(c.RootPath, "node_modules"), 0755)
	if err != nil {
		return err
	}
	resp, err := goreq.Request{Uri: c.nodeURL()}.Do()
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	uncompressed, err := gzip.NewReader(resp.Body)
	if err != nil {
		return err
	}
	tmpDir := c.tmpDir("node")
	extractTar(tar.NewReader(uncompressed), tmpDir)
	newDir := filepath.Join(c.RootPath, c.NodeBase())
	os.RemoveAll(newDir)
	err = os.Rename(filepath.Join(tmpDir, c.NodeBase()), newDir)
	if err != nil {
		return err
	}
	return os.Remove(tmpDir)
}

func (c *Client) setupWindows() error {
	os.RemoveAll(filepath.Join(c.RootPath, c.NodeBase()))
	modulesDir := filepath.Join(c.RootPath, c.NodeBase(), "lib", "node_modules")
	if err := os.MkdirAll(modulesDir, 0755); err != nil {
		return err
	}
	if err := c.downloadNpm(modulesDir); err != nil {
		return err
	}
	return c.downloadFile(c.nodePath(), c.nodeURL())
}

func (c *Client) downloadFile(path, url string) error {
	tmp := filepath.Join(c.tmpDir("download"), "file")
	// TODO: make this work with goreq
	// right now it fails because the body is closed for some reason
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	file, err := os.Create(tmp)
	if err != nil {
		return err
	}
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		return err
	}
	file.Close()
	resp.Body.Close()
	err = os.MkdirAll(filepath.Dir(path), 0755)
	if err != nil {
		return err
	}
	os.Remove(path)
	err = os.Rename(tmp, path)
	if err != nil {
		return err
	}
	return os.RemoveAll(filepath.Dir(tmp))
}

func (c *Client) downloadNpm(modulesDir string) error {
	tmpDir := c.tmpDir("node")
	zipfile := filepath.Join(tmpDir, "npm.zip")
	err := c.downloadFile(zipfile, c.npmURL())
	if err != nil {
		return err
	}
	err = extractZip(zipfile, tmpDir)
	if err != nil {
		return err
	}
	os.Rename(filepath.Join(tmpDir, "npm-"+c.NpmVersion), filepath.Join(modulesDir, "npm"))
	if err != nil {
		return err
	}
	return os.RemoveAll(tmpDir)
}
<|endoftext|>


<commit_before>package main

import (
	stdlog "log"
	"os"
	"fmt"

	"github.com/kyleterry/tenyks-go/config"
	"github.com/kyleterry/tenyks-go/irc"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("tenyks")
var connections map[string]*irc.Connection
var ircObservers []<-chan bool

var banner string = `
  _                   _
 | |                 | |
 | |_ ___ _ __  _   _| | _____
 | __/ _ \ '_ \| | | | |/ / __|
 | ||  __/ | | | |_| |   <\__ \
  \__\___|_| |_|\__, |_|\_\___/
                 __/ |
                |___/
`

func connectionObserver(conn *irc.Connection, observerCtl <-chan bool) {
	log.Info("[%s] Connecting", conn.Name)
	connected := <-conn.Connect()
	if connected == true {
		irc.Bootstrap(conn)
		for {
			select {
			case rawmsg := <-conn.In:
				msg := irc.ParseMessage(rawmsg)
				fmt.Println(*msg)
				if msg != nil { // Just ignore invalid messages. Who knows...
					//Dispatch(msg)
				}
			case <-observerCtl:
				break
			}
		}
	} else {
		log.Error("[%s] Could not connect.", conn.Name)
	}
}

func main() {
	quit := make(chan bool, 1)

	fmt.Printf(banner + "\n")

	// Make configuration from json file
	conf, conferr := config.NewConfigAutoDiscover()
	if conferr != nil {
		log.Fatal(conferr)
	}

	// Configure logging
	logBackend := logging.NewLogBackend(os.Stdout, "", stdlog.LstdFlags|stdlog.Lshortfile)
	logBackend.Color = true
	logging.SetBackend(logBackend)
	if conf.Debug {
		logging.SetLevel(logging.DEBUG, "tenyks")
	} else {
		logging.SetLevel(logging.INFO, "tenyks")
	}

	// Connections map
	connections = make(map[string]*irc.Connection)
	ircObservers = make([]<-chan bool, 0)

	for _, c := range conf.Connections {
		conn := irc.NewConn(c.Name, c)
		ctl := make(<-chan bool, 1)
		ircObservers = append(ircObservers, ctl)
		go connectionObserver(conn, ctl)
		connections[c.Name] = conn
	}

	<-quit
}
<commit_msg>Hack to keep the thing running<commit_after>package main

import (
	stdlog "log"
	"os"
	"fmt"

	"github.com/kyleterry/tenyks-go/config"
	"github.com/kyleterry/tenyks-go/irc"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("tenyks")
var connections map[string]*irc.Connection
var ircObservers []<-chan bool
var ircDispatchCommands map[string]bool = make(map[string]bool)
var serviceDispatchCommands map[string]bool = make(map[string]bool)

var banner string = `
  _                   _
 | |                 | |
 | |_ ___ _ __  _   _| | _____
 | __/ _ \ '_ \| | | | |/ / __|
 | ||  __/ | | | |_| |   <\__ \
  \__\___|_| |_|\__, |_|\_\___/
                 __/ |
                |___/
`

func connectionObserver(conn *irc.Connection, observerCtl <-chan bool) {
	log.Info("[%s] Connecting", conn.Name)
	connected := <-conn.Connect()
	if connected == true {
		irc.Bootstrap(conn)
		for {
			select {
			case rawmsg := <-conn.In:
				msg := irc.ParseMessage(rawmsg)
				log.Debug("%+v", *msg)
				if msg != nil { // Just ignore invalid messages. Who knows...
					dispatch(conn, msg)
				}
			case <-observerCtl:
				break
			}
		}
	} else {
		log.Error("[%s] Could not connect.", conn.Name)
	}
}

func dispatch(conn *irc.Connection, msg *irc.Message) {
	if ircDispatchCommands[msg.Command] {
		if msg.Command == "PING" {
			conn.Out <- fmt.Sprintf("PONG %s\r\n", msg.Trail)
		}

	} else if serviceDispatchCommands[msg.Command] {

	}
}

func main() {
	quit := make(chan bool, 1)

	fmt.Printf(banner + "\n")

	// Make configuration from json file
	conf, conferr := config.NewConfigAutoDiscover()
	if conferr != nil {
		log.Fatal(conferr)
	}

	// Configure logging
	logBackend := logging.NewLogBackend(os.Stdout, "", stdlog.LstdFlags|stdlog.Lshortfile)
	logBackend.Color = true
	logging.SetBackend(logBackend)
	if conf.Debug {
		logging.SetLevel(logging.DEBUG, "tenyks")
	} else {
		logging.SetLevel(logging.INFO, "tenyks")
	}

	// Connections map
	connections = make(map[string]*irc.Connection)
	ircObservers = make([]<-chan bool, 0)

	ircDispatchCommands["PING"] = true
	serviceDispatchCommands["PRIVMSG"] = true

	// Create connection, spawn observers and add to the map
	for _, c := range conf.Connections {
		conn := irc.NewConn(c.Name, c)
		ctl := make(<-chan bool, 1)
		ircObservers = append(ircObservers, ctl)
		go connectionObserver(conn, ctl)
		connections[c.Name] = conn
	}

	<-quit
}
<|endoftext|>


<commit_before>// xorcipher is a set of tools for analyzing and cracking cipher text that
// has been encyrpted using simple 1 and multibyte repeating xor sequences
package xorcipher

import (
	"fmt"
	"unicode"
)

type Solution struct {
	Score float64
	Text  string
	Key   rune
}

// Crack Simple will attempt to find the best 1 byte key that a provided ciphertext
// has been xor'd with and returns a Solution detailing that result
func CrackSimple(bytes []byte) *Solution {

	best := new(Solution)
	for key := 0; key < 256; key++ {
		xord := make([]byte, len(bytes))
		for i := range bytes {
			xord[i] = bytes[i] ^ byte(key)
		}

		decrypted := string(xord)
		score := score(decrypted)
		if score > best.Score {
			best = &Solution{score, decrypted, rune(key)}
		}
	}
	return best
}

// frequency returns a value indicating a given rune's frequency
// in the english language, values are only guarunteed to be useful in
// comparison to each other and not as any absolute metric
var runeFreq = map[rune]float64{
	' ': 24.50,
	'E': 12.51,
	'T': 9.25,
	'A': 8.04,
	'O': 7.60,
	'I': 7.26,
	'N': 7.09,
	'S': 6.54,
	'R': 6.12,
	'H': 5.49,
	'L': 4.14,
	'D': 3.99,
	'C': 3.06,
	'U': 2.71,
	'M': 2.53,
	'F': 2.30,
	'P': 2.00,
	'G': 1.96,
	'W': 1.92,
	'Y': 1.73,
	'B': 1.54,
	'V': 0.99,
	'K': 0.67,
	'X': 0.19,
	'J': 0.16,
	'Q': 0.11,
	'Z': 0.09,
}

func score(s string) float64 {
	score := 0.0
	for _, r := range s {
		// penalize heavily for non printable characters, since they are pretty good indicators
		// that the bytes being examined are not english/characters
		if r > 255 {
			score -= 240
		} else {
			score += runeFreq[unicode.ToUpper(r)]
		}
	}
	return score / float64(len(s))
}

func xor(a []byte, b []byte) []byte {
	if len(a) != len(b) {
		panic(fmt.Sprintf("array a and b had differing lengths (%v and %v respectievely", len(a), len(b)))
	}

	l := len(a)
	out := make([]byte, l)
	for i := 0; i < len(a); i++ {
		out[i] = a[i] ^ b[i]
	}
	return out
}
<commit_msg>Formatting changes/remove duplicate function from xorcipher<commit_after>// xorcipher is a set of tools for analyzing and cracking cipher text that
// has been encyrpted using simple 1 and multibyte repeating xor sequences
package xorcipher

import (
	"unicode"
)

type Solution struct {
	Score float64
	Text  string
	Key   rune
}

// Crack Simple will attempt to find the best 1 byte key that a provided ciphertext
// has been xor'd with and returns a Solution detailing that result
func CrackSimple(bytes []byte) *Solution {
	best := new(Solution)
	for key := 0; key < 256; key++ {
		xord := make([]byte, len(bytes))
		for i := range bytes {
			xord[i] = bytes[i] ^ byte(key)
		}

		decrypted := string(xord)
		score := score(decrypted)
		if score > best.Score {
			best = &Solution{score, decrypted, rune(key)}
		}
	}
	return best
}

// frequency returns a value indicating a given rune's frequency
// in the english language, values are only guarunteed to be useful in
// comparison to each other and not as any absolute metric
var runeFreq = map[rune]float64{
	' ': 24.50,
	'E': 12.51,
	'T': 9.25,
	'A': 8.04,
	'O': 7.60,
	'I': 7.26,
	'N': 7.09,
	'S': 6.54,
	'R': 6.12,
	'H': 5.49,
	'L': 4.14,
	'D': 3.99,
	'C': 3.06,
	'U': 2.71,
	'M': 2.53,
	'F': 2.30,
	'P': 2.00,
	'G': 1.96,
	'W': 1.92,
	'Y': 1.73,
	'B': 1.54,
	'V': 0.99,
	'K': 0.67,
	'X': 0.19,
	'J': 0.16,
	'Q': 0.11,
	'Z': 0.09,
}

func score(s string) float64 {
	score := 0.0
	for _, r := range s {
		// penalize heavily for non-ascii characters, since they are pretty good indicators
		// that the bytes being examined are not english/characters
		if r > 255 {
			score -= 240
		} else {
			score += runeFreq[unicode.ToUpper(r)]
		}
	}
	return score / float64(len(s))
}
<|endoftext|>


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

package librdkafka

// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -L/usr/local/opt/librdkafka/lib -L/usr/local/lib -lrdkafka
// #include "wrapper.h"
import "C"

import (
	"unsafe"
)

// Topic wrapper handle for rd_kafka_topic_t
type Topic struct {
	handle   *C.rd_kafka_topic_t
	client   *Client
	name     string
	shutdown bool
}

// NewTopic creates a new topic representation in librdkafka.
// You have to call Close() to free any internal state. As this struct holds a
// pointer to the client make sure that Client.Close is called after closing
// objects of this type.
func NewTopic(name string, config TopicConfig, client *Client) *Topic {
	return &Topic{
		handle:   C.rd_kafka_topic_new(client.handle, C.CString(name), config.handle),
		client:   client,
		name:     name,
		shutdown: false,
	}
}

// TriggerShutdown signals a topic to stop producing messages (unblocks any
// waiting topics).
func (t *Topic) TriggerShutdown() {
	t.shutdown = true
}

// Close frees the internal handle and tries to flush the queue.
func (t *Topic) Close() {
	oldQueueLen := C.int(0x7FFFFFFF)
	queueLen := C.rd_kafka_outq_len(t.client.handle)

	// Wait as long as we're flushing
	for queueLen > 0 && queueLen < oldQueueLen {
		C.rd_kafka_poll(t.client.handle, 1000)
		oldQueueLen = queueLen
		queueLen = C.rd_kafka_outq_len(t.client.handle)
	}

	if queueLen > 0 {
		Log.Printf("%d messages have been lost as the internal queue could not be flushed", queueLen)
	}
	C.rd_kafka_topic_destroy(t.handle)
}

// GetName returns the name of the topic
func (t *Topic) GetName() string {
	return t.name
}

// Poll polls for new data to be sent to the async handler functions
func (t *Topic) Poll() {
	C.rd_kafka_poll(t.client.handle, 1000)
}

// Produce produces a single messages.
// If a message cannot be produced because of internal (non-wire) problems an
// error is immediately returned instead of being asynchronously handled via
// MessageDelivery interface.
func (t *Topic) Produce(message Message) error {
	keyLen, keyPtr, payLen, payPtr, usrLen, usrPtr := MarshalMessage(message)
	usrData := C.CreateBuffer(usrLen, usrPtr)
	success := C.rd_kafka_produce(t.handle, C.RD_KAFKA_PARTITION_UA, C.RD_KAFKA_MSG_F_COPY, payPtr, payLen, keyPtr, keyLen, usrData)

	if success != 0 {
		defer C.DestroyBuffer(usrData)
		rspErr := ResponseError{
			Userdata: message.GetUserdata(),
			Code:     int(C.GetLastError()),
		}
		return rspErr // ### return, error ###
	}

	C.rd_kafka_poll(t.client.handle, 0)
	return nil
}

// ProduceBatch produces a set of messages.
// Messages that cannot be produced because of internal (non-wire) problems are
// immediately returned instead of asynchronously handled via MessageDelivery
// interface.
func (t *Topic) ProduceBatch(messages []Message) []error {
	errors := []error{}
	if len(messages) == 0 {
		return errors // ### return, nothing to do ###
	}

	batch := PrepareBatch(messages)
	batchLen := C.int(len(messages))
	defer C.DestroyBatch(unsafe.Pointer(batch))

	enqueued := C.rd_kafka_produce_batch(t.handle, C.RD_KAFKA_PARTITION_UA, C.RD_KAFKA_MSG_F_COPY, batch, batchLen)
	if enqueued != batchLen {
		offset := C.int(0)
		for offset >= 0 {
			offset = C.BatchGetNextError(batch, batchLen, offset)
			if offset >= 0 {
				bufferPtr := C.BatchGetUserdataAt(batch, offset)
				errCode := C.BatchGetErrAt(batch, offset)

				rspErr := ResponseError{
					Userdata: UnmarshalBuffer(bufferPtr),
					Code:     int(errCode),
				}

				errors = append(errors, rspErr)
				offset++
			}
		}
	}

	for C.rd_kafka_outq_len(t.client.handle) > 0 && !t.shutdown {
		C.rd_kafka_poll(t.client.handle, 20)
	}

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

package librdkafka

// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -L/usr/local/opt/librdkafka/lib -L/usr/local/lib -lrdkafka
// #include "wrapper.h"
import "C"

import (
	"unsafe"
)

// Topic wrapper handle for rd_kafka_topic_t
type Topic struct {
	handle   *C.rd_kafka_topic_t
	client   *Client
	name     string
	shutdown bool
}

// NewTopic creates a new topic representation in librdkafka.
// You have to call Close() to free any internal state. As this struct holds a
// pointer to the client make sure that Client.Close is called after closing
// objects of this type.
func NewTopic(name string, config TopicConfig, client *Client) *Topic {
	return &Topic{
		handle:   C.rd_kafka_topic_new(client.handle, C.CString(name), config.handle),
		client:   client,
		name:     name,
		shutdown: false,
	}
}

// TriggerShutdown signals a topic to stop producing messages (unblocks any
// waiting topics).
func (t *Topic) TriggerShutdown() {
	t.shutdown = true
}

// Close frees the internal handle and tries to flush the queue.
func (t *Topic) Close() {
	oldQueueLen := C.int(0x7FFFFFFF)
	queueLen := C.rd_kafka_outq_len(t.client.handle)

	// Wait as long as we're flushing
	for queueLen > 0 && queueLen < oldQueueLen {
		C.rd_kafka_poll(t.client.handle, 1000)
		oldQueueLen = queueLen
		queueLen = C.rd_kafka_outq_len(t.client.handle)
	}

	if queueLen > 0 {
		Log.Printf("%d messages have been lost as the internal queue could not be flushed", queueLen)
	}
	C.rd_kafka_topic_destroy(t.handle)
}

// GetName returns the name of the topic
func (t *Topic) GetName() string {
	return t.name
}

// Poll polls for new data to be sent to the async handler functions
func (t *Topic) Poll() {
	C.rd_kafka_poll(t.client.handle, 1000)
}

// Produce produces a single messages.
// If a message cannot be produced because of internal (non-wire) problems an
// error is immediately returned instead of being asynchronously handled via
// MessageDelivery interface.
func (t *Topic) Produce(message Message) error {
	keyLen, keyPtr, payLen, payPtr, usrLen, usrPtr := MarshalMessage(message)
	usrData := C.CreateBuffer(usrLen, usrPtr)
	success := C.rd_kafka_produce(t.handle, C.RD_KAFKA_PARTITION_UA, C.RD_KAFKA_MSG_F_COPY, payPtr, payLen, keyPtr, keyLen, usrData)

	if success != 0 {
		defer C.DestroyBuffer(usrData)
		rspErr := ResponseError{
			Userdata: message.GetUserdata(),
			Code:     int(C.GetLastError()),
		}
		return rspErr // ### return, error ###
	}

	C.rd_kafka_poll(t.client.handle, 0)
	return nil
}

// ProduceBatch produces a set of messages.
// Messages that cannot be produced because of internal (non-wire) problems are
// immediately returned instead of asynchronously handled via MessageDelivery
// interface.
/*func (t *Topic) ProduceBatch(messages []Message) []error {
	errors := []error{}
	if len(messages) == 0 {
		return errors // ### return, nothing to do ###
	}

	batch := PrepareBatch(messages)
	batchLen := C.int(len(messages))
	defer C.DestroyBatch(unsafe.Pointer(batch))

	enqueued := C.rd_kafka_produce_batch(t.handle, C.RD_KAFKA_PARTITION_UA, C.RD_KAFKA_MSG_F_COPY, batch, batchLen)
	if enqueued != batchLen {
		offset := C.int(0)
		for offset >= 0 {
			offset = C.BatchGetNextError(batch, batchLen, offset)
			if offset >= 0 {
				bufferPtr := C.BatchGetUserdataAt(batch, offset)
				errCode := C.BatchGetErrAt(batch, offset)

				rspErr := ResponseError{
					Userdata: UnmarshalBuffer(bufferPtr),
					Code:     int(errCode),
				}

				errors = append(errors, rspErr)
				offset++
			}
		}
	}

	for C.rd_kafka_outq_len(t.client.handle) > 0 && !t.shutdown {
		C.rd_kafka_poll(t.client.handle, 20)
	}

	return errors
}*/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"

	"github.com/mkideal/cli"
	"github.com/vburenin/ifacemaker/maker"
)

type cmdlineArgs struct {
	cli.Helper
	Files      []string `cli:"*f,file" usage:"Go source file to read"`
	StructType string   `cli:"*s,struct" usage:"Generate an interface for this structure name"`
	IfaceName  string   `cli:"*i,iface" usage:"Name of the generated interface"`
	PkgName    string   `cli:"*p,pkg" usage:"Package name for the generated interface"`
	CopyDocs   bool     `cli:"d,doc" usage:"Copy docs from methods" dft:"true"`
	Output     string   `cli:"o,output" usage:"Output file name. If not provided, result will be printed to stdout."`
}

func run(args *cmdlineArgs) {
	allMethods := []string{}
	allImports := []string{}
	mset := make(map[string]struct{})
	iset := make(map[string]struct{})
	for _, f := range args.Files {
		src, err := ioutil.ReadFile(f)
		if err != nil {
			log.Fatal(err.Error())
		}
		methods, imports := maker.ParseStruct(src, args.StructType, args.CopyDocs)
		for _, m := range methods {
			if _, ok := mset[m.Code]; !ok {
				allMethods = append(allMethods, m.Lines()...)
				mset[m.Code] = struct{}{}
			}
		}
		for _, i := range imports {
			if _, ok := iset[i]; !ok {
				allImports = append(allImports, i)
				iset[i] = struct{}{}
			}
		}
	}

	result, err := maker.MakeInterface(args.PkgName, args.IfaceName, allMethods, allImports)
	if err != nil {
		log.Fatal(err.Error())
	}

	if args.Output == "" {
		fmt.Println(string(result))
	} else {
		ioutil.WriteFile(args.Output, result, 0644)
	}

}

func main() {
	cli.Run(&cmdlineArgs{}, func(ctx *cli.Context) error {
		argv := ctx.Argv().(*cmdlineArgs)
		run(argv)
		return nil
	})
}
<commit_msg>Add comment to top of file so people don't edit it<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"

	"github.com/mkideal/cli"
	"github.com/vburenin/ifacemaker/maker"
)

type cmdlineArgs struct {
	cli.Helper
	Files      []string `cli:"*f,file" usage:"Go source file to read"`
	StructType string   `cli:"*s,struct" usage:"Generate an interface for this structure name"`
	IfaceName  string   `cli:"*i,iface" usage:"Name of the generated interface"`
	PkgName    string   `cli:"*p,pkg" usage:"Package name for the generated interface"`
	CopyDocs   bool     `cli:"d,doc" usage:"Copy docs from methods" dft:"true"`
	Comment    string   `cli:"c,comment" usage:"Append comment to top"`
	Output     string   `cli:"o,output" usage:"Output file name. If not provided, result will be printed to stdout."`
}

func run(args *cmdlineArgs) {
	allMethods := []string{}
	allImports := []string{}
	mset := make(map[string]struct{})
	iset := make(map[string]struct{})
	for _, f := range args.Files {
		src, err := ioutil.ReadFile(f)
		if err != nil {
			log.Fatal(err.Error())
		}
		methods, imports := maker.ParseStruct(src, args.StructType, args.CopyDocs)
		for _, m := range methods {
			if _, ok := mset[m.Code]; !ok {
				allMethods = append(allMethods, m.Lines()...)
				mset[m.Code] = struct{}{}
			}
		}
		for _, i := range imports {
			if _, ok := iset[i]; !ok {
				allImports = append(allImports, i)
				iset[i] = struct{}{}
			}
		}
	}

	result, err := maker.MakeInterface(args.Comment, args.PkgName, args.IfaceName, allMethods, allImports)
	if err != nil {
		log.Fatal(err.Error())
	}

	if args.Output == "" {
		fmt.Println(string(result))
	} else {
		ioutil.WriteFile(args.Output, result, 0644)
	}

}

func main() {
	cli.Run(&cmdlineArgs{}, func(ctx *cli.Context) error {
		argv := ctx.Argv().(*cmdlineArgs)
		run(argv)
		return nil
	})
}
<|endoftext|>


<commit_before>package inigo_test

import (
	"fmt"
	"strings"

	"github.com/cloudfoundry-incubator/inigo/stager_runner"
	"github.com/cloudfoundry/yagnats"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Stager", func() {
	var otherStagerRunner *stager_runner.StagerRunner

	Context("with one stager", func() {
		BeforeEach(func() {
			executorRunner.Start()
			stagerRunner.Start()
		})

		It("returns error if no compiler for stack defined", func() {
			errorMessages := 0
			natsRunner.MessageBus.Subscribe("compiler-stagers-test", func(message *yagnats.Message) {
				if strings.Contains(string(message.Payload), "error") {
					errorMessages++
				}
			})

			natsRunner.MessageBus.PublishWithReplyTo(
				"diego.staging.start",
				"compiler-stagers-test",
				[]byte(`{"app_id": "some-app-guid", "task_id": "some-task-id", "stack": "no-compiler"}`))

			Eventually(func() int {
				return errorMessages
			}, 2.0).Should(Equal(1))

			Consistently(func() int {
				return errorMessages
			}, 2.0).Should(Equal(1))
		})
	})

	Context("with two stagers running", func() {
		BeforeEach(func() {
			executorRunner.Start()
			stagerRunner.Start()
			otherStagerRunner = stager_runner.New(
				stagerPath,
				etcdRunner.NodeURLS(),
				[]string{fmt.Sprintf("127.0.0.1:%d", natsPort)},
			)
			otherStagerRunner.Start()
		})

		AfterEach(func() {
			otherStagerRunner.Stop()
		})

		It("only one returns a staging completed response", func() {
			successMessages := 0
			natsRunner.MessageBus.Subscribe("two-stagers-test", func(message *yagnats.Message) {
				if !strings.Contains(string(message.Payload), "error") {
					successMessages++
				}
			})

			natsRunner.MessageBus.PublishWithReplyTo(
				"diego.staging.start",
				"two-stagers-test",
				[]byte(`{"app_id": "some-app-guid", "task_id": "some-task-id", "stack": "default"}`))

			Eventually(func() int {
				return successMessages
			}, 2.0).Should(Equal(1))

			Consistently(func() int {
				return successMessages
			}, 2.0).Should(Equal(1))
		})
	})
})
<commit_msg>Add admin_buildpacks to staging request<commit_after>package inigo_test

import (
	"fmt"
	"strings"

	"github.com/cloudfoundry-incubator/inigo/stager_runner"
	"github.com/cloudfoundry/yagnats"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Stager", func() {
	var otherStagerRunner *stager_runner.StagerRunner

	Context("with one stager", func() {
		BeforeEach(func() {
			executorRunner.Start()
			stagerRunner.Start()
		})

		It("returns error if no compiler for stack defined", func() {
			errorMessages := 0
			natsRunner.MessageBus.Subscribe("compiler-stagers-test", func(message *yagnats.Message) {
				if strings.Contains(string(message.Payload), "error") {
					errorMessages++
				}
			})

			natsRunner.MessageBus.PublishWithReplyTo(
				"diego.staging.start",
				"compiler-stagers-test",
				[]byte(`{"app_id": "some-app-guid", "task_id": "some-task-id", "stack": "no-compiler"}`))

			Eventually(func() int {
				return errorMessages
			}, 2.0).Should(Equal(1))

			Consistently(func() int {
				return errorMessages
			}, 2.0).Should(Equal(1))
		})
	})

	Context("with two stagers running", func() {
		BeforeEach(func() {
			executorRunner.Start()
			stagerRunner.Start()
			otherStagerRunner = stager_runner.New(
				stagerPath,
				etcdRunner.NodeURLS(),
				[]string{fmt.Sprintf("127.0.0.1:%d", natsPort)},
			)
			otherStagerRunner.Start()
		})

		AfterEach(func() {
			otherStagerRunner.Stop()
		})

		It("only one returns a staging completed response", func() {
			successMessages := 0
			natsRunner.MessageBus.Subscribe("two-stagers-test", func(message *yagnats.Message) {
				if !strings.Contains(string(message.Payload), "error") {
					successMessages++
				}
			})

			natsRunner.MessageBus.PublishWithReplyTo(
				"diego.staging.start",
				"two-stagers-test",
				[]byte(`{"app_id": "some-app-guid", "task_id": "some-task-id", "stack": "default", "admin_buildpacks" : [{"key": "ruby", "url": "ruby-url"}]}`))

			Eventually(func() int {
				return successMessages
			}, 2.0).Should(Equal(1))

			Consistently(func() int {
				return successMessages
			}, 2.0).Should(Equal(1))
		})
	})
})
<|endoftext|>


<commit_before>package sol

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"testing"
	"time"

	"github.com/aodin/sol/dialect"
	"github.com/aodin/sol/types"
)

// callerInfo returns a string containing the file and line number of the
// assert call that failed.
// https://github.com/stretchr/testify/blob/master/assert/assertions.go
// Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
func callerInfo() string {
	file := ""
	line := 0
	ok := false

	for i := 0; ; i++ {
		_, file, line, ok = runtime.Caller(i)
		if !ok {
			return ""
		}
		parts := strings.Split(file, "/")
		file = parts[len(parts)-1]

		// dir := parts[len(parts)-2]
		if file == "tester.go" {
			continue
		}
		break
	}
	return fmt.Sprintf("%s:%d", file, line)
}

type tester struct {
	t       *testing.T
	dialect dialect.Dialect
}

// Error tests that the given Compiles instances generates an error for the
// current dialect.
func (t *tester) Error(stmt Compiles) {
	// TODO Allow a specific error
	if _, err := stmt.Compile(t.dialect, Params()); err == nil {
		t.t.Errorf("%s: expected error, received nil", callerInfo())
	}
}

// SQL tests that the given Compiles instance matches the expected string for
// the current dialect.
func (t *tester) SQL(stmt Compiles, expect string, ps ...interface{}) {
	// Get caller information in case of failure
	caller := callerInfo()

	// Start a new parameters instance
	params := Params()

	// Compile the given stmt with the tester's dialect
	actual, err := stmt.Compile(t.dialect, params)
	if err != nil {
		t.t.Errorf("%s: unexpected error from Compile(): %s", caller, err)
		return
	}

	if expect != actual {
		t.t.Errorf(
			"%s: unexpected SQL from Compile(): \n - have: %s\n - want: %s",
			caller,
			actual,
			expect,
		)
	}
	// Test that the parameters are equal
	if len(*params) != len(ps) {
		t.t.Errorf(
			"%s: unexpected number of parameters for %s: \n - have %d, want %d",
			caller,
			actual,
			len(ps),
			len(*params),
		)
		return
	}

	// Examine individual parameters for equality
	for i, param := range *params {
		if !reflect.DeepEqual(ps[i], param) {
			t.t.Errorf(
				"%s: unequal parameters at index %d: \n - have %#v, want %#v",
				caller,
				i,
				param,
				ps[i],
			)
		}
	}
}

// NewTester creates a new SQL/Error tester that uses the given dialect
func NewTester(t *testing.T, d dialect.Dialect) *tester {
	return &tester{t: t, dialect: d}
}

// IntegrationTest runs a large, neutral dialect test
func IntegrationTest(t *testing.T, conn *DB) {
	// Perform all tests in a transaction
	// TODO What features should be testing outside of a transaction?
	tx, err := conn.Begin()
	if err != nil {
		t.Fatalf("Creating a new transaction should not error: %s", err)
	}
	defer tx.Rollback()

	// CREATE TABLE
	// TODO foreign keys
	testusers := Table("testusers",
		Column("id", types.Integer()),
		Column("email", types.Varchar().Limit(255).NotNull()),
		Column("is_admin", types.Boolean().NotNull()),
		Column("created_at", types.Timestamp()),
		PrimaryKey("id"),
		Unique("email"),
	)

	type testuser struct {
		ID        int64
		Email     string
		IsAdmin   bool
		CreatedAt time.Time
	}

	if err = tx.Query(testusers.Create()); err != nil {
		t.Fatalf("CREATE TABLE should not error: %s", err)
	}

	// INSERT by struct
	// Truncate the time.Time field to avoid significant digit errors
	admin := testuser{
		ID:        1,
		Email:     "admin@example.com",
		IsAdmin:   true,
		CreatedAt: time.Now().UTC().Truncate(time.Second),
	}

	if err = tx.Query(testusers.Insert().Values(admin)); err != nil {
		t.Fatalf("INSERT by struct should not fail %s", err)
	}

	// SELECT
	var selected testuser
	if err = tx.Query(
		testusers.Select().Where(testusers.C("id").Equals(admin.ID)),
		&selected,
	); err != nil {
		t.Fatalf("SELECT should not fail: %s", err)
	}

	// TODO test with direct comparison: selected == admin
	// For now, test each field since DATETIME handling is terribly
	// inconsistent across databases
	if selected.ID != admin.ID {
		t.Errorf(
			"Unequal testusers id: have %d, want %d",
			selected.ID, admin.ID,
		)
	}
	if selected.Email != admin.Email {
		t.Errorf(
			"Unequal testusers email: have %s, want %s",
			selected.Email, admin.Email,
		)
	}
	if selected.IsAdmin != admin.IsAdmin {
		t.Errorf(
			"Unequal testusers is_admin: have %t, want %t",
			selected.IsAdmin, admin.IsAdmin,
		)
	}
	if !selected.CreatedAt.Equal(admin.CreatedAt) {
		t.Errorf(
			"Unequal testusers created_at: have %v, want %v",
			selected.CreatedAt, admin.CreatedAt,
		)
	}

	// UPDATE
	if err = tx.Query(
		testusers.Update().Values(
			Values{"is_admin": false},
		).Where(testusers.C("id").Equals(admin.ID)),
	); err != nil {
		t.Fatalf("UPDATE should not fail: %s", err)
	}

	var updated testuser
	if err = tx.Query(testusers.Select().Limit(1), &updated); err != nil {
		t.Fatalf("SELECT should not fail: %s", err)
	}

	selected.IsAdmin = false
	if updated != selected {
		t.Errorf(
			"Unequal testusers: have %+v, want %+v",
			updated, selected,
		)
	}

	// INSERT by values
	client := Values{
		"id":         2,
		"email":      "client@example.com",
		"is_admin":   false,
		"created_at": time.Now().UTC().Truncate(time.Second),
	}

	if err = tx.Query(testusers.Insert().Values(client)); err != nil {
		t.Fatalf("INSERT by values should not fail %s", err)
	}
	var list []testuser
	if err = tx.Query(
		testusers.Select().OrderBy(testusers.C("id").Desc()),
		&list,
	); err != nil {
		t.Fatalf("SELECT with ORDER BY should not fail: %s", err)
	}

	if len(list) != 2 {
		t.Fatalf("Unexpected length of list: want 2, have %d", len(list))
	}

	// The client should be first
	if list[0].Email != "client@example.com" {
		t.Errorf(
			"Unexpected email: want client@example.com, have %d",
			list[0].Email,
		)
	}

	// DELETE
	if err = tx.Query(
		testusers.Delete().Where(testusers.C("email").Equals(admin.Email)),
	); err != nil {
		t.Fatalf("DELETE should not fail: %s", err)
	}

	// DROP TABLE
	if err = tx.Query(testusers.Drop()); err != nil {
		t.Fatalf("DROP TABLE should not fail %s", err)
	}

	// Test a recover
	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("Connection failed to panic on error")
			}
		}()
		conn.Must().Query(testusers.Select(), list)
	}()
}
<commit_msg>Cleaner test output<commit_after>package sol

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"testing"
	"time"

	"github.com/aodin/sol/dialect"
	"github.com/aodin/sol/types"
)

// callerInfo returns a string containing the file and line number of the
// assert call that failed.
// https://github.com/stretchr/testify/blob/master/assert/assertions.go
// Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
func callerInfo() string {
	file := ""
	line := 0
	ok := false

	for i := 0; ; i++ {
		_, file, line, ok = runtime.Caller(i)
		if !ok {
			return ""
		}
		if file == "<autogenerated>" {
			break
		}
		parts := strings.Split(file, "/")
		file = parts[len(parts)-1]

		// dir := parts[len(parts)-2]
		if file == "tester.go" {
			continue
		}
		break
	}
	return fmt.Sprintf("%s:%d", file, line)
}

type tester struct {
	t       *testing.T
	dialect dialect.Dialect
}

// Error tests that the given Compiles instances generates an error for the
// current dialect.
func (t *tester) Error(stmt Compiles) {
	// TODO Allow a specific error
	if _, err := stmt.Compile(t.dialect, Params()); err == nil {
		t.t.Errorf("%s: expected error, received nil", callerInfo())
	}
}

// SQL tests that the given Compiles instance matches the expected string for
// the current dialect.
func (t *tester) SQL(stmt Compiles, expect string, ps ...interface{}) {
	// Get caller information in case of failure
	caller := callerInfo()

	// Start a new parameters instance
	params := Params()

	// Compile the given stmt with the tester's dialect
	actual, err := stmt.Compile(t.dialect, params)
	if err != nil {
		t.t.Errorf("%s:\n\rUnexpected error from Compile: %s", caller, err)
		return
	}

	if expect != actual {
		t.t.Errorf(
			"%s:\n\rUnexpected SQL from Compile: \n\r - have: %s\n\r - want: %s",
			caller, actual, expect,
		)
	}
	// Test that the parameters are equal
	if len(*params) != len(ps) {
		t.t.Errorf(
			"%s:\n\rUnexpected parameter length for %T: \n\r - have %d, want %d",
			caller, stmt, len(ps), len(*params),
		)
		return
	}

	// Examine individual parameters for equality
	for i, param := range *params {
		if !reflect.DeepEqual(ps[i], param) {
			t.t.Errorf(
				"%s:\n\rUnequal parameters at index %d: \n\r - have %#v (%T), want %#v (%T)",
				caller, i, param, param, ps[i], ps[i],
			)
		}
	}
}

// NewTester creates a new SQL/Error tester that uses the given dialect
func NewTester(t *testing.T, d dialect.Dialect) *tester {
	return &tester{t: t, dialect: d}
}

// IntegrationTest runs a large, neutral dialect test
func IntegrationTest(t *testing.T, conn *DB) {
	// Perform all tests in a transaction
	// TODO What features should be testing outside of a transaction?
	tx, err := conn.Begin()
	if err != nil {
		t.Fatalf("Creating a new transaction should not error: %s", err)
	}
	defer tx.Rollback()

	// CREATE TABLE
	// TODO foreign keys
	testusers := Table("testusers",
		Column("id", types.Integer()),
		Column("email", types.Varchar().Limit(255).NotNull()),
		Column("is_admin", types.Boolean().NotNull()),
		Column("created_at", types.Timestamp()),
		PrimaryKey("id"),
		Unique("email"),
	)

	type testuser struct {
		ID        int64
		Email     string
		IsAdmin   bool
		CreatedAt time.Time
	}

	if err = tx.Query(testusers.Create()); err != nil {
		t.Fatalf("CREATE TABLE should not error: %s", err)
	}

	// INSERT by struct
	// Truncate the time.Time field to avoid significant digit errors
	admin := testuser{
		ID:        1,
		Email:     "admin@example.com",
		IsAdmin:   true,
		CreatedAt: time.Now().UTC().Truncate(time.Second),
	}

	if err = tx.Query(testusers.Insert().Values(admin)); err != nil {
		t.Fatalf("INSERT by struct should not fail %s", err)
	}

	// SELECT
	var selected testuser
	if err = tx.Query(
		testusers.Select().Where(testusers.C("id").Equals(admin.ID)),
		&selected,
	); err != nil {
		t.Fatalf("SELECT should not fail: %s", err)
	}

	// TODO test with direct comparison: selected == admin
	// For now, test each field since DATETIME handling is terribly
	// inconsistent across databases
	if selected.ID != admin.ID {
		t.Errorf(
			"Unequal testusers id: have %d, want %d",
			selected.ID, admin.ID,
		)
	}
	if selected.Email != admin.Email {
		t.Errorf(
			"Unequal testusers email: have %s, want %s",
			selected.Email, admin.Email,
		)
	}
	if selected.IsAdmin != admin.IsAdmin {
		t.Errorf(
			"Unequal testusers is_admin: have %t, want %t",
			selected.IsAdmin, admin.IsAdmin,
		)
	}
	if !selected.CreatedAt.Equal(admin.CreatedAt) {
		t.Errorf(
			"Unequal testusers created_at: have %v, want %v",
			selected.CreatedAt, admin.CreatedAt,
		)
	}

	// UPDATE
	if err = tx.Query(
		testusers.Update().Values(
			Values{"is_admin": false},
		).Where(testusers.C("id").Equals(admin.ID)),
	); err != nil {
		t.Fatalf("UPDATE should not fail: %s", err)
	}

	var updated testuser
	if err = tx.Query(testusers.Select().Limit(1), &updated); err != nil {
		t.Fatalf("SELECT should not fail: %s", err)
	}

	selected.IsAdmin = false
	if updated != selected {
		t.Errorf(
			"Unequal testusers: have %+v, want %+v",
			updated, selected,
		)
	}

	// INSERT by values
	client := Values{
		"id":         2,
		"email":      "client@example.com",
		"is_admin":   false,
		"created_at": time.Now().UTC().Truncate(time.Second),
	}

	if err = tx.Query(testusers.Insert().Values(client)); err != nil {
		t.Fatalf("INSERT by values should not fail %s", err)
	}
	var list []testuser
	if err = tx.Query(
		testusers.Select().OrderBy(testusers.C("id").Desc()),
		&list,
	); err != nil {
		t.Fatalf("SELECT with ORDER BY should not fail: %s", err)
	}

	if len(list) != 2 {
		t.Fatalf("Unexpected length of list: want 2, have %d", len(list))
	}

	// The client should be first
	if list[0].Email != "client@example.com" {
		t.Errorf(
			"Unexpected email: want client@example.com, have %d",
			list[0].Email,
		)
	}

	// DELETE
	if err = tx.Query(
		testusers.Delete().Where(testusers.C("email").Equals(admin.Email)),
	); err != nil {
		t.Fatalf("DELETE should not fail: %s", err)
	}

	// DROP TABLE
	if err = tx.Query(testusers.Drop()); err != nil {
		t.Fatalf("DROP TABLE should not fail %s", err)
	}

	// Test a recover
	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("Connection failed to panic on error")
			}
		}()
		conn.Must().Query(testusers.Select(), list)
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/ansible-semaphore/semaphore/db"
	"github.com/ansible-semaphore/semaphore/db/sql"
	"github.com/ansible-semaphore/semaphore/util"
	"github.com/snikch/goodman/transaction"
	"math/rand"
	"os"
	"time"
)

var tablesShouldBeTruncated = [...]string{
	"access_key",
	"event",
	"user__token",
	"project",
	"task__output",
	"task",
	"session",
	"project__environment",
	"project__inventory",
	"project__repository",
	"project__template",
	"project__schedule",
	"project__user",
	"user",
	"project__view",
}

// Test Runner User
func addTestRunnerUser() {
	uid := getUUID()
	testRunnerUser = &db.User{
		Username: "ITU-" + uid,
		Name:     "ITU-" + uid,
		Email:    uid + "@semaphore.test",
		Created:  db.GetParsedTime(time.Now()),
		Admin:    true,
	}

	dbConnect()
	defer store.Sql().Db.Close()

	truncateAll()

	newUser, err := store.CreateUserWithoutPassword(*testRunnerUser)

	if err != nil {
		panic(err)
	}

	testRunnerUser.ID = newUser.ID

	addToken(adminToken, testRunnerUser.ID)
}

func truncateAll() {
	tx, err := store.Sql().Begin()
	if err != nil {
		panic(err)
	}

	_, err = tx.Exec("SET FOREIGN_KEY_CHECKS = 0")
	if err == nil {
		for _, tableName := range tablesShouldBeTruncated {
			tx.Exec("TRUNCATE TABLE " + tableName)
		}
		tx.Exec("SET FOREIGN_KEY_CHECKS = 1")
	}

	if err := tx.Commit(); err != nil {
		panic(err)
	}
}

func removeTestRunnerUser(transactions []*transaction.Transaction) {
	dbConnect()
	defer store.Sql().Db.Close()
	deleteToken(adminToken, testRunnerUser.ID)
	deleteObject(testRunnerUser)
}

// Parameter Substitution
func setupObjectsAndPaths(t *transaction.Transaction) {
	alterRequestPath(t)
	alterRequestBody(t)
}

// Object Lifecycle
func addUserProjectRelation(pid int, user int) {
	_, err := store.CreateProjectUser(db.ProjectUser{
		ProjectID: pid,
		UserID:    user,
		Admin:     true,
	})
	if err != nil {
		panic(err)
	}
}

func deleteUserProjectRelation(pid int, user int) {
	err := store.DeleteProjectUser(pid, user)
	if err != nil {
		panic(err)
	}
}

func addAccessKey(pid *int) *db.AccessKey {
	uid := getUUID()
	secret := "5up3r53cr3t\n"

	key, err := store.CreateAccessKey(db.AccessKey{
		Name:      "ITK-" + uid,
		Type:      "ssh",
		Secret:    &secret,
		ProjectID: pid,
	})

	if err != nil {
		panic(err)
	}
	return &key
}

func addProject() *db.Project {
	uid := getUUID()
	project := db.Project{
		Name:    "ITP-" + uid,
		Created: time.Now(),
	}
	project, err := store.CreateProject(project)
	if err != nil {
		panic(err)
	}
	return &project
}

func addUser() *db.User {
	uid := getUUID()
	user := db.User{
		Created:  time.Now(),
		Username: "ITU-" + uid,
		Email:    "test@semaphore." + uid,
	}

	user, err := store.CreateUserWithoutPassword(user)

	if err != nil {
		panic(err)
	}
	return &user
}

func addView() *db.View {
	view, err := store.CreateView(db.View{
		ProjectID: userProject.ID,
		Title:     "Test",
		Position:  1,
	})

	if err != nil {
		panic(err)
	}

	return &view
}

func addSchedule() *db.Schedule {
	schedule, err := store.CreateSchedule(db.Schedule{
		TemplateID: int(templateID),
		CronFormat: "* * * 1 *",
		ProjectID:  userProject.ID,
	})

	if err != nil {
		panic(err)
	}

	return &schedule
}

func addTask() *db.Task {
	t := db.Task{
		ProjectID:  userProject.ID,
		TemplateID: int(templateID),
		Status:     "testing",
		UserID:     &userPathTestUser.ID,
		Created:    db.GetParsedTime(time.Now()),
	}
	_, err := store.CreateTask(t)
	if err != nil {
		fmt.Println("error during insertion of task:")
		if j, err := json.Marshal(t); err == nil {
			fmt.Println(string(j))
		} else {
			fmt.Println("can not stringify task object")
		}
		panic(err)
	}
	return &t
}

func deleteObject(i interface{}) {
	_, err := store.Sql().Delete(i)
	if err != nil {
		panic(err)
	}
}

// Token Handling
func addToken(tok string, user int) {
	_, err := store.CreateAPIToken(db.APIToken{
		ID:      tok,
		Created: time.Now(),
		UserID:  user,
		Expired: false,
	})
	if err != nil {
		panic(err)
	}
}

func deleteToken(tok string, user int) {
	token := db.APIToken{
		ID:     tok,
		UserID: user,
	}
	deleteObject(&token)
}

// HELPERS
var r *rand.Rand
var randSetup = false

func getUUID() string {
	if !randSetup {
		r = rand.New(rand.NewSource(time.Now().UnixNano()))
		randSetup = true
	}
	return randomString(8)
}
func randomString(strlen int) string {
	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := ""
	for i := 0; i < strlen; i++ {
		index := r.Intn(len(chars))
		result += chars[index : index+1]
	}
	return result
}

func loadConfig() {
	cwd, _ := os.Getwd()
	file, _ := os.Open(cwd + "/.dredd/config.json")
	if err := json.NewDecoder(file).Decode(&util.Config); err != nil {
		fmt.Println("Could not decode configuration!")
		panic(err)
	}
}

var store sql.SqlDb

func dbConnect() {
	store = sql.SqlDb{}

	if err := store.Connect(); err != nil {
		panic(err)
	}
}

func stringInSlice(a string, list []string) (int, bool) {
	for k, b := range list {
		if b == a {
			return k, true
		}
	}
	return 0, false
}

func printError(err error) {
	if err != nil {
		//fmt.Println(err)
		panic(err)
	}
}
<commit_msg>test: delete user via store method<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/ansible-semaphore/semaphore/db"
	"github.com/ansible-semaphore/semaphore/db/sql"
	"github.com/ansible-semaphore/semaphore/util"
	"github.com/snikch/goodman/transaction"
	"math/rand"
	"os"
	"time"
)

var tablesShouldBeTruncated = [...]string{
	"access_key",
	"event",
	"user__token",
	"project",
	"task__output",
	"task",
	"session",
	"project__environment",
	"project__inventory",
	"project__repository",
	"project__template",
	"project__schedule",
	"project__user",
	"user",
	"project__view",
}

// Test Runner User
func addTestRunnerUser() {
	uid := getUUID()
	testRunnerUser = &db.User{
		Username: "ITU-" + uid,
		Name:     "ITU-" + uid,
		Email:    uid + "@semaphore.test",
		Created:  db.GetParsedTime(time.Now()),
		Admin:    true,
	}

	dbConnect()
	defer store.Sql().Db.Close()

	truncateAll()

	newUser, err := store.CreateUserWithoutPassword(*testRunnerUser)

	if err != nil {
		panic(err)
	}

	testRunnerUser.ID = newUser.ID

	addToken(adminToken, testRunnerUser.ID)
}

func truncateAll() {
	tx, err := store.Sql().Begin()
	if err != nil {
		panic(err)
	}

	_, err = tx.Exec("SET FOREIGN_KEY_CHECKS = 0")
	if err == nil {
		for _, tableName := range tablesShouldBeTruncated {
			tx.Exec("TRUNCATE TABLE " + tableName)
		}
		tx.Exec("SET FOREIGN_KEY_CHECKS = 1")
	}

	if err := tx.Commit(); err != nil {
		panic(err)
	}
}

func removeTestRunnerUser(transactions []*transaction.Transaction) {
	dbConnect()
	defer store.Sql().Db.Close()
	deleteToken(adminToken, testRunnerUser.ID)
	_ = store.DeleteUser(testRunnerUser.ID)
	//deleteObject(testRunnerUser)
}

// Parameter Substitution
func setupObjectsAndPaths(t *transaction.Transaction) {
	alterRequestPath(t)
	alterRequestBody(t)
}

// Object Lifecycle
func addUserProjectRelation(pid int, user int) {
	_, err := store.CreateProjectUser(db.ProjectUser{
		ProjectID: pid,
		UserID:    user,
		Admin:     true,
	})
	if err != nil {
		panic(err)
	}
}

func deleteUserProjectRelation(pid int, user int) {
	err := store.DeleteProjectUser(pid, user)
	if err != nil {
		panic(err)
	}
}

func addAccessKey(pid *int) *db.AccessKey {
	uid := getUUID()
	secret := "5up3r53cr3t\n"

	key, err := store.CreateAccessKey(db.AccessKey{
		Name:      "ITK-" + uid,
		Type:      "ssh",
		Secret:    &secret,
		ProjectID: pid,
	})

	if err != nil {
		panic(err)
	}
	return &key
}

func addProject() *db.Project {
	uid := getUUID()
	project := db.Project{
		Name:    "ITP-" + uid,
		Created: time.Now(),
	}
	project, err := store.CreateProject(project)
	if err != nil {
		panic(err)
	}
	return &project
}

func addUser() *db.User {
	uid := getUUID()
	user := db.User{
		Created:  time.Now(),
		Username: "ITU-" + uid,
		Email:    "test@semaphore." + uid,
	}

	user, err := store.CreateUserWithoutPassword(user)

	if err != nil {
		panic(err)
	}
	return &user
}

func addView() *db.View {
	view, err := store.CreateView(db.View{
		ProjectID: userProject.ID,
		Title:     "Test",
		Position:  1,
	})

	if err != nil {
		panic(err)
	}

	return &view
}

func addSchedule() *db.Schedule {
	schedule, err := store.CreateSchedule(db.Schedule{
		TemplateID: int(templateID),
		CronFormat: "* * * 1 *",
		ProjectID:  userProject.ID,
	})

	if err != nil {
		panic(err)
	}

	return &schedule
}

func addTask() *db.Task {
	t := db.Task{
		ProjectID:  userProject.ID,
		TemplateID: int(templateID),
		Status:     "testing",
		UserID:     &userPathTestUser.ID,
		Created:    db.GetParsedTime(time.Now()),
	}
	_, err := store.CreateTask(t)
	if err != nil {
		fmt.Println("error during insertion of task:")
		if j, err := json.Marshal(t); err == nil {
			fmt.Println(string(j))
		} else {
			fmt.Println("can not stringify task object")
		}
		panic(err)
	}
	return &t
}

func deleteObject(i interface{}) {
	_, err := store.Sql().Delete(i)
	if err != nil {
		panic(err)
	}
}

// Token Handling
func addToken(tok string, user int) {
	_, err := store.CreateAPIToken(db.APIToken{
		ID:      tok,
		Created: time.Now(),
		UserID:  user,
		Expired: false,
	})
	if err != nil {
		panic(err)
	}
}

func deleteToken(tok string, user int) {
	token := db.APIToken{
		ID:     tok,
		UserID: user,
	}

	deleteObject(&token)
}

// HELPERS
var r *rand.Rand
var randSetup = false

func getUUID() string {
	if !randSetup {
		r = rand.New(rand.NewSource(time.Now().UnixNano()))
		randSetup = true
	}
	return randomString(8)
}
func randomString(strlen int) string {
	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := ""
	for i := 0; i < strlen; i++ {
		index := r.Intn(len(chars))
		result += chars[index : index+1]
	}
	return result
}

func loadConfig() {
	cwd, _ := os.Getwd()
	file, _ := os.Open(cwd + "/.dredd/config.json")
	if err := json.NewDecoder(file).Decode(&util.Config); err != nil {
		fmt.Println("Could not decode configuration!")
		panic(err)
	}
}

var store sql.SqlDb

func dbConnect() {
	store = sql.SqlDb{}

	if err := store.Connect(); err != nil {
		panic(err)
	}
}

func stringInSlice(a string, list []string) (int, bool) {
	for k, b := range list {
		if b == a {
			return k, true
		}
	}
	return 0, false
}

func printError(err error) {
	if err != nil {
		//fmt.Println(err)
		panic(err)
	}
}
<|endoftext|>


<commit_before>package stats

import (
	"github.com/rcrowley/go-librato"
	"log"
	"time"
)

type StatsSink struct {
	accountsCreated  int64
	errorsRendered   int64
	dbxAuthCancelled int64
	usersProcessed   int64
	batchesProcessed int64
	pageRenderErrors int64
	runs             int64
	sink             chan int
	metrics          librato.Metrics
	env              string
}

// The various events we track
const (
	ACCOUNT_CREATE    = 1
	RENDER_ERROR      = 2
	CANCEL_DBX_AUTH   = 3
	USER_PROCESSED    = 4
	BATCH_PROCESSED   = 5
	PAGE_RENDER_ERROR = 6
	RUN_COMPLETE      = 7
	ENV_WEB           = "web"
	ENV_WORKER        = "worker"
)

func NewStatsSink(user string, token string, environment string) *StatsSink {
	// Inital sink
	sink := &StatsSink{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		make(chan int),
		librato.NewSimpleMetrics(user, token, environment),
		environment,
	}

	go sink.handle()
	go sink.flushTimer()

	return sink
}

// Report an event
func (s *StatsSink) Event(event int) {
	s.sink <- event
}

func (s *StatsSink) handle() {
	for {
		event, ok := <-s.sink

		if !ok {
			return
		}

		switch event {
		case ACCOUNT_CREATE:
			s.accountsCreated += 1
		case RENDER_ERROR:
			s.errorsRendered += 1
		case CANCEL_DBX_AUTH:
			s.dbxAuthCancelled += 1
		case USER_PROCESSED:
			s.usersProcessed += 1
		case BATCH_PROCESSED:
			s.batchesProcessed += 1
		case PAGE_RENDER_ERROR:
			s.pageRenderErrors += 1
		case RUN_COMPLETE:
			s.runs += 1
		}
	}
}

// This runs forever and just sends statistics on the given interval.
func (s *StatsSink) flushTimer() {
	for {
		<-time.After(120 * time.Second)
		log.Println("METRICS: Flushing statistics to Librato")

		if s.env == ENV_WEB {
			// Send the created users
			ac := s.metrics.GetGauge(s.env + "_accounts_created")
			ac <- s.accountsCreated

			// Send the rendered errors
			er := s.metrics.GetGauge(s.env + "_errors_rendered")
			er <- s.errorsRendered

			// end the cancelled dropbox auth
			dr := s.metrics.GetGauge(s.env + "_dropbox_auth_cancelled")
			dr <- s.dbxAuthCancelled

			// Zero out the counters
			s.accountsCreated = 0
			s.errorsRendered = 0
			s.dbxAuthCancelled = 0
		}

		if s.env == ENV_WORKER {
			us := s.metrics.GetGauge(s.env + "_users_processed")
			us <- s.usersProcessed

			ba := s.metrics.GetGauge(s.env + "_batches_processed")
			ba <- s.batchesProcessed

			pa := s.metrics.GetGauge(s.env + "_page_render_errors")
			pa <- s.pageRenderErrors

			ru := s.metrics.GetGauge(s.env + "_runs")
			ru <- s.runs

			// Zero out the counters

			s.usersProcessed = 0
			s.batchesProcessed = 0
			s.pageRenderErrors = 0
			s.runs = 0
		}
	}
}
<commit_msg>stats: add a method for reporting raw metric values<commit_after>package stats

import (
	"github.com/rcrowley/go-librato"
	"log"
	"time"
)

type StatsSink struct {
	accountsCreated  int64
	errorsRendered   int64
	dbxAuthCancelled int64
	usersProcessed   int64
	batchesProcessed int64
	pageRenderErrors int64
	runs             int64
	sink             chan int
	metrics          librato.Metrics
	env              string
}

// The various events we track
const (
	ACCOUNT_CREATE    = 1
	RENDER_ERROR      = 2
	CANCEL_DBX_AUTH   = 3
	USER_PROCESSED    = 4
	BATCH_PROCESSED   = 5
	PAGE_RENDER_ERROR = 6
	RUN_COMPLETE      = 7
	ENV_WEB           = "web"
	ENV_WORKER        = "worker"
)

func NewStatsSink(user string, token string, environment string) *StatsSink {
	// Inital sink
	sink := &StatsSink{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		make(chan int),
		librato.NewSimpleMetrics(user, token, environment),
		environment,
	}

	go sink.handle()
	go sink.flushTimer()

	return sink
}

// Report an event
func (s *StatsSink) Event(event int) {
	s.sink <- event
}

// Report a raw event
func (s *StatsSink) Raw(value int64, key string) {
	g := s.metrics.GetGauge(s.env + key)
	g <- value
}

func (s *StatsSink) handle() {
	for {
		event, ok := <-s.sink

		if !ok {
			return
		}

		switch event {
		case ACCOUNT_CREATE:
			s.accountsCreated += 1
		case RENDER_ERROR:
			s.errorsRendered += 1
		case CANCEL_DBX_AUTH:
			s.dbxAuthCancelled += 1
		case USER_PROCESSED:
			s.usersProcessed += 1
		case BATCH_PROCESSED:
			s.batchesProcessed += 1
		case PAGE_RENDER_ERROR:
			s.pageRenderErrors += 1
		case RUN_COMPLETE:
			s.runs += 1
		}
	}
}

// This runs forever and just sends statistics on the given interval.
func (s *StatsSink) flushTimer() {
	for {
		<-time.After(120 * time.Second)
		log.Println("METRICS: Flushing statistics to Librato")

		if s.env == ENV_WEB {
			// Send the created users
			ac := s.metrics.GetGauge(s.env + "_accounts_created")
			ac <- s.accountsCreated

			// Send the rendered errors
			er := s.metrics.GetGauge(s.env + "_errors_rendered")
			er <- s.errorsRendered

			// end the cancelled dropbox auth
			dr := s.metrics.GetGauge(s.env + "_dropbox_auth_cancelled")
			dr <- s.dbxAuthCancelled

			// Zero out the counters
			s.accountsCreated = 0
			s.errorsRendered = 0
			s.dbxAuthCancelled = 0
		}

		if s.env == ENV_WORKER {
			us := s.metrics.GetGauge(s.env + "_users_processed")
			us <- s.usersProcessed

			ba := s.metrics.GetGauge(s.env + "_batches_processed")
			ba <- s.batchesProcessed

			pa := s.metrics.GetGauge(s.env + "_page_render_errors")
			pa <- s.pageRenderErrors

			ru := s.metrics.GetGauge(s.env + "_runs")
			ru <- s.runs

			// Zero out the counters

			s.usersProcessed = 0
			s.batchesProcessed = 0
			s.pageRenderErrors = 0
			s.runs = 0
		}
	}
}
<|endoftext|>


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

package main

import (
	"testing"
)

func TestBasicPartitionFunc(t *testing.T) {
	stream := make(Stream)
	s, err := BasicPartitionFunc(nil, "", map[string]Stream{"": stream})
	if err != nil || s != stream {
		t.Errorf("expected BasicPartitionFunc to work")
	}
	s, err = BasicPartitionFunc(nil, "", map[string]Stream{"foo": stream})
	if err == nil || s == stream {
		t.Errorf("expected BasicPartitionFunc to not work")
	}
	s, err = BasicPartitionFunc(nil, "foo", map[string]Stream{"foo": stream})
	if err != nil || s != stream {
		t.Errorf("expected BasicPartitionFunc to work on partition hit")
	}
}
<commit_msg>more tests of BasicPartitionFunc<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package main

import (
	"testing"
)

func TestBasicPartitionFunc(t *testing.T) {
	stream := make(Stream)
	stream2 := make(Stream)
	s, err := BasicPartitionFunc(nil, "", map[string]Stream{"": stream})
	if err != nil || s != stream {
		t.Errorf("expected BasicPartitionFunc to work")
	}
	s, err = BasicPartitionFunc(nil, "foo", map[string]Stream{"": stream})
	if err != nil || s != stream {
		t.Errorf("expected BasicPartitionFunc to hit the catch-all stream")
	}
	s, err = BasicPartitionFunc(nil, "", map[string]Stream{"foo": stream})
	if err == nil || s == stream {
		t.Errorf("expected BasicPartitionFunc to not work")
	}
	s, err = BasicPartitionFunc(nil, "foo", map[string]Stream{"foo": stream})
	if err != nil || s != stream {
		t.Errorf("expected BasicPartitionFunc to work on partition hit")
	}
	s, err = BasicPartitionFunc(nil, "foo", map[string]Stream{"foo": stream, "": stream2})
	if err != nil || s != stream {
		t.Errorf("expected BasicPartitionFunc to work on partition hit")
	}
}
<|endoftext|>


<commit_before>package splaytree

import "testing"
import "time"
import "math/rand"
import "sort"

func TestStress(t *testing.T) {
	seed := time.Now().UnixNano()
	source := rand.NewSource(seed)
	rand := rand.New(source)
	atLeast := func(lower int) int {
		return lower + rand.Intn(lower)
	}
	findSorted := func(x int, a []int, n int) (int, bool) {
		i := sort.Search(n, func(i int) bool { return x <= a[i] })
		return i, i < n && x == a[i]
	}
	shuffle := func(a []int, n int) {
		for i := 0; i < n-1; i++ {
			r := i + rand.Intn(n-i)
			a[i], a[r] = a[r], a[i]
		}
	}

	for outer := 0; outer < 10; outer++ {
		tree := NewSplayTree()
		size := atLeast(3000)
		nums := make([]int, size)
		for i := 0; i < size; i++ {
			nums[i] = i * 2
		}
		shuffle(nums, size)

		for i := 0; i < size; i++ {
			if !tree.Insert(Int(nums[i])) {
				t.Errorf("insert failed %v %v", i, nums[i])
			}
		}
		sort.Ints(nums)

		doit := atLeast(2 * size)
		dels := make([]bool, size)
		for i := 0; i < doit; i++ {
			k := rand.Intn(2 * size)
			f, have := findSorted(k, nums, size)
			_, look := tree.Lookup(Int(k))
			if look != have && (!have || !dels[f]) {
				t.Errorf("lookup failed %v %v", look, have)
			} else if look {
				r := rand.Intn(1000)
				if r < 250 {
					_, del := tree.Delete(Int(k))
					if del != look {
						t.Errorf("delete failed %v %v %v %v", look, del, have, dels[f])
					}
					if del {
						dels[f] = true
					}
				}
			} else if have && dels[f] {
				r := rand.Intn(1000)
				if r < 100 {
					if !tree.Insert(Int(k)) {
						t.Errorf("insert failed %v %v %v", look, have, dels[f])
					} else {
						dels[f] = false
					}
				} else if r < 200 {
					if tree.Replace(Int(k)) {
						t.Errorf("replace failed %v %v %v", look, have, dels[f])
					} else {
						dels[f] = false
					}
				}
			} else if _, del := tree.Delete(Int(k)); del {
				t.Errorf("delete should have failed %v %v %v", look, have, dels[f])
			}
		}
	}
}
<commit_msg>simplify shuffle with Perm<commit_after>package splaytree

import "testing"
import "time"
import "math/rand"
import "sort"

func TestStress(t *testing.T) {
	seed := time.Now().UnixNano()
	source := rand.NewSource(seed)
	rand := rand.New(source)
	atLeast := func(lower int) int {
		return lower + rand.Intn(lower)
	}
	findSorted := func(x int, a []int, n int) (int, bool) {
		i := sort.Search(n, func(i int) bool { return x <= a[i] })
		return i, i < n && x == a[i]
	}

	for outer := 0; outer < 10; outer++ {
		tree := NewSplayTree()
		size := atLeast(3000)
		nums := rand.Perm(size)
		for i := 0; i < size; i++ {
			nums[i] *= 2
		}

		for i := 0; i < size; i++ {
			if !tree.Insert(Int(nums[i])) {
				t.Errorf("insert failed %v %v", i, nums[i])
			}
		}
		sort.Ints(nums)

		doit := atLeast(2 * size)
		dels := make([]bool, size)
		for i := 0; i < doit; i++ {
			k := rand.Intn(2 * size)
			f, have := findSorted(k, nums, size)
			_, look := tree.Lookup(Int(k))
			if look != have && (!have || !dels[f]) {
				t.Errorf("lookup failed %v %v", look, have)
			} else if look {
				r := rand.Intn(1000)
				if r < 250 {
					_, del := tree.Delete(Int(k))
					if del != look {
						t.Errorf("delete failed %v %v %v %v", look, del, have, dels[f])
					}
					if del {
						dels[f] = true
					}
				}
			} else if have && dels[f] {
				r := rand.Intn(1000)
				if r < 100 {
					if !tree.Insert(Int(k)) {
						t.Errorf("insert failed %v %v %v", look, have, dels[f])
					} else {
						dels[f] = false
					}
				} else if r < 200 {
					if tree.Replace(Int(k)) {
						t.Errorf("replace failed %v %v %v", look, have, dels[f])
					} else {
						dels[f] = false
					}
				}
			} else if _, del := tree.Delete(Int(k)); del {
				t.Errorf("delete should have failed %v %v %v", look, have, dels[f])
			}
		}
	}
}
<|endoftext|>


<commit_before>package backup

import (
	"bytes"
	"context"
	"fmt"
	"github.com/apex/log"
	"github.com/pkg/errors"
	"github.com/pterodactyl/wings/api"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"
)

type S3Backup struct {
	Backup
}

var _ BackupInterface = (*S3Backup)(nil)

// Generates a new backup on the disk, moves it into the S3 bucket via the provided
// presigned URL, and then deletes the backup from the disk.
func (s *S3Backup) Generate(included *IncludedFiles, prefix string) (*ArchiveDetails, error) {
	defer s.Remove()

	a := &Archive{
		TrimPrefix: prefix,
		Files:      included,
	}

	if err := a.Create(s.Path(), context.Background()); err != nil {
		return nil, errors.WithStack(err)
	}

	rc, err := os.Open(s.Path())
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer rc.Close()

	if err := s.generateRemoteRequest(rc); err != nil {
		return nil, errors.WithStack(err)
	}

	return s.Details(), err
}

// Removes a backup from the system.
func (s *S3Backup) Remove() error {
	return os.Remove(s.Path())
}

// Reader provides a wrapper around an existing io.Reader
// but implements io.Closer in order to satisfy an io.ReadCloser.
type Reader struct {
	io.Reader
}

func (Reader) Close() error {
	return nil
}

// Generates the remote S3 request and begins the upload.
func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error {
	defer rc.Close()

	size, err := s.Backup.Size()
	if err != nil {
		return err
	}

	urls, err := api.New().GetBackupRemoteUploadURLs(s.Backup.Uuid, size)
	if err != nil {
		return err
	}

	log.Debug("attempting to upload backup to remote S3 endpoint")

	handlePart := func(part string, size int64) (string, error) {
		r, err := http.NewRequest(http.MethodPut, part, nil)
		if err != nil {
			return "", err
		}

		r.ContentLength = size
		r.Header.Add("Content-Length", strconv.Itoa(int(size)))
		r.Header.Add("Content-Type", "application/x-gzip")

		// Limit the reader to the size of the part.
		r.Body = Reader{io.LimitReader(rc, size)}

		// This http request can block forever due to it not having a timeout,
		// but we are uploading up to 5GB of data, so there is not really
		// a good way to handle a timeout on this.
		res, err := http.DefaultClient.Do(r)
		if err != nil {
			return "", err
		}
		defer res.Body.Close()

		// Handle non-200 status codes.
		if res.StatusCode != http.StatusOK {
			return "", fmt.Errorf("failed to put S3 object part, %d:%s", res.StatusCode, res.Status)
		}

		// Get the ETag from the uploaded part, this should be sent with the CompleteMultipartUpload request.
		return res.Header.Get("ETag"), nil
	}

	// Start assembling the body that will be sent as apart of the CompleteMultipartUpload request.
	var completeUploadBody bytes.Buffer
	completeUploadBody.WriteString("<CompleteMultipartUpload>\n")

	partCount := len(urls.Parts)
	for i, part := range urls.Parts {
		// Get the size for the current part.
		var partSize int64
		if i+1 < partCount {
			partSize = urls.PartSize
		} else {
			// This is the remaining size for the last part,
			// there is not a minimum size limit for the last part.
			partSize = size - (int64(i) * urls.PartSize)
		}

		// Attempt to upload the part.
		etag, err := handlePart(part, partSize)
		if err != nil {
			log.WithError(err).Warn("failed to upload part")

			// Send an AbortMultipartUpload request.
			if err := s.finishUpload(urls.AbortMultipartUpload, nil); err != nil {
				log.WithError(err).Warn("failed to abort multipart backup upload")
			}

			return err
		}

		// Add the part to the CompleteMultipartUpload body.
		completeUploadBody.WriteString("\t<Part>\n")
		completeUploadBody.WriteString("\t\t<ETag>\"" + etag + "\"</ETag>\n")
		completeUploadBody.WriteString("\t\t<PartNumber>" + strconv.Itoa(i+1) + "</PartNumber>\n")
		completeUploadBody.WriteString("\t</Part>\n")
	}
	completeUploadBody.WriteString("</CompleteMultipartUpload>")

	// Send a CompleteMultipartUpload request.
	if err := s.finishUpload(urls.CompleteMultipartUpload, &completeUploadBody); err != nil {
		return err
	}

	return nil
}

// finishUpload sends a requests to the specified url to either complete or abort the upload.
func (s *S3Backup) finishUpload(url string, body io.Reader) error {
	r, err := http.NewRequest(http.MethodPost, url, body)
	if err != nil {
		return err
	}

	// Create a new http client with a 10 second timeout.
	c := &http.Client{
		Timeout: 10 * time.Second,
	}

	res, err := c.Do(r)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// Handle non-200 status codes.
	if res.StatusCode != http.StatusOK {
		// If no body was sent, we were aborting the upload.
		if body == nil {
			return fmt.Errorf("failed to abort S3 multipart upload, %d:%s", res.StatusCode, res.Status)
		}

		// If a body was sent we were completing the upload.
		// TODO: Attempt to send abort request?
		return fmt.Errorf("failed to complete S3 multipart upload, %d:%s", res.StatusCode, res.Status)
	}

	return nil
}
<commit_msg>Add better logging for s3 backup uploads<commit_after>package backup

import (
	"bytes"
	"context"
	"fmt"
	"github.com/apex/log"
	"github.com/pkg/errors"
	"github.com/pterodactyl/wings/api"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"
)

type S3Backup struct {
	Backup
}

var _ BackupInterface = (*S3Backup)(nil)

// Generates a new backup on the disk, moves it into the S3 bucket via the provided
// presigned URL, and then deletes the backup from the disk.
func (s *S3Backup) Generate(included *IncludedFiles, prefix string) (*ArchiveDetails, error) {
	defer s.Remove()

	a := &Archive{
		TrimPrefix: prefix,
		Files:      included,
	}

	if err := a.Create(s.Path(), context.Background()); err != nil {
		return nil, errors.WithStack(err)
	}

	rc, err := os.Open(s.Path())
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer rc.Close()

	if err := s.generateRemoteRequest(rc); err != nil {
		return nil, errors.WithStack(err)
	}

	return s.Details(), err
}

// Removes a backup from the system.
func (s *S3Backup) Remove() error {
	return os.Remove(s.Path())
}

// Reader provides a wrapper around an existing io.Reader
// but implements io.Closer in order to satisfy an io.ReadCloser.
type Reader struct {
	io.Reader
}

func (Reader) Close() error {
	return nil
}

// Generates the remote S3 request and begins the upload.
func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) error {
	defer rc.Close()

	size, err := s.Backup.Size()
	if err != nil {
		return err
	}

	urls, err := api.New().GetBackupRemoteUploadURLs(s.Backup.Uuid, size)
	if err != nil {
		return err
	}

	log.WithFields(log.Fields{
		"backup_id": s.Uuid,
		"adapter":   "s3",
	}).Info("attempting to upload backup..")

	handlePart := func(part string, size int64) (string, error) {
		r, err := http.NewRequest(http.MethodPut, part, nil)
		if err != nil {
			return "", err
		}

		r.ContentLength = size
		r.Header.Add("Content-Length", strconv.Itoa(int(size)))
		r.Header.Add("Content-Type", "application/x-gzip")

		// Limit the reader to the size of the part.
		r.Body = Reader{io.LimitReader(rc, size)}

		// This http request can block forever due to it not having a timeout,
		// but we are uploading up to 5GB of data, so there is not really
		// a good way to handle a timeout on this.
		res, err := http.DefaultClient.Do(r)
		if err != nil {
			return "", err
		}
		defer res.Body.Close()

		// Handle non-200 status codes.
		if res.StatusCode != http.StatusOK {
			return "", fmt.Errorf("failed to put S3 object part, %d:%s", res.StatusCode, res.Status)
		}

		// Get the ETag from the uploaded part, this should be sent with the CompleteMultipartUpload request.
		return res.Header.Get("ETag"), nil
	}

	// Start assembling the body that will be sent as apart of the CompleteMultipartUpload request.
	var completeUploadBody bytes.Buffer
	completeUploadBody.WriteString("<CompleteMultipartUpload>\n")

	partCount := len(urls.Parts)
	for i, part := range urls.Parts {
		// Get the size for the current part.
		var partSize int64
		if i+1 < partCount {
			partSize = urls.PartSize
		} else {
			// This is the remaining size for the last part,
			// there is not a minimum size limit for the last part.
			partSize = size - (int64(i) * urls.PartSize)
		}

		// Attempt to upload the part.
		etag, err := handlePart(part, partSize)
		if err != nil {
			log.WithError(err).Warn("failed to upload part")

			// Send an AbortMultipartUpload request.
			if err := s.finishUpload(urls.AbortMultipartUpload, nil); err != nil {
				log.WithError(err).Warn("failed to abort multipart backup upload")
			}

			return err
		}

		// Add the part to the CompleteMultipartUpload body.
		completeUploadBody.WriteString("\t<Part>\n")
		completeUploadBody.WriteString("\t\t<ETag>\"" + etag + "\"</ETag>\n")
		completeUploadBody.WriteString("\t\t<PartNumber>" + strconv.Itoa(i+1) + "</PartNumber>\n")
		completeUploadBody.WriteString("\t</Part>\n")
	}
	completeUploadBody.WriteString("</CompleteMultipartUpload>")

	// Send a CompleteMultipartUpload request.
	if err := s.finishUpload(urls.CompleteMultipartUpload, &completeUploadBody); err != nil {
		return err
	}

	log.WithFields(log.Fields{
		"backup_id": s.Uuid,
		"adapter":   "s3",
	}).Info("backup has been successfully uploaded")
	return nil
}

// finishUpload sends a requests to the specified url to either complete or abort the upload.
func (s *S3Backup) finishUpload(url string, body io.Reader) error {
	r, err := http.NewRequest(http.MethodPost, url, body)
	if err != nil {
		return err
	}

	// Create a new http client with a 10 second timeout.
	c := &http.Client{
		Timeout: 10 * time.Second,
	}

	res, err := c.Do(r)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// Handle non-200 status codes.
	if res.StatusCode != http.StatusOK {
		// If no body was sent, we were aborting the upload.
		if body == nil {
			return fmt.Errorf("failed to abort S3 multipart upload, %d:%s", res.StatusCode, res.Status)
		}

		// If a body was sent we were completing the upload.
		// TODO: Attempt to send abort request?
		return fmt.Errorf("failed to complete S3 multipart upload, %d:%s", res.StatusCode, res.Status)
	}

	return nil
}
<|endoftext|>


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

// Package notifier fetches notifications from the database and sends them
// to the specified remote handler.
package notifier

import (
	"time"

	"github.com/coreos/pkg/capnslog"
	"github.com/coreos/pkg/timeutil"
	"github.com/pborman/uuid"

	"github.com/coreos/clair/config"
	"github.com/coreos/clair/database"
	"github.com/coreos/clair/health"
	"github.com/coreos/clair/utils"
)

var log = capnslog.NewPackageLogger("github.com/coreos/clair", "notifier")

const (
	checkInterval       = 5 * time.Minute
	refreshLockDuration = time.Minute * 2
	lockDuration        = time.Minute*8 + refreshLockDuration
	maxBackOff          = 15 * time.Minute
)

// TODO(Quentin-M): Allow registering custom notification handlers.

// A Notification represents the structure of the notifications that are sent by a Notifier.
type Notification struct {
	Name, Type string
	Content    interface{}
}

var notifiers = make(map[string]Notifier)

// Notifier represents anything that can transmit notifications.
type Notifier interface {
	// Configure attempts to initialize the notifier with the provided configuration.
	// It returns whether the notifier is enabled or not.
	Configure(*config.NotifierConfig) (bool, error)
	// Send transmits the specified notification.
	Send(notification *Notification) error
}

// RegisterNotifier makes a Fetcher available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func RegisterNotifier(name string, n Notifier) {
	if name == "" {
		panic("notifier: could not register a Notifier with an empty name")
	}

	if n == nil {
		panic("notifier: could not register a nil Notifier")
	}

	if _, dup := notifiers[name]; dup {
		panic("notifier: RegisterNotifier called twice for " + name)
	}

	notifiers[name] = n
}

// Run starts the Notifier service.
func Run(config *config.NotifierConfig, stopper *utils.Stopper) {
	defer stopper.End()

	// Configure registered notifiers.
	for notifierName, notifier := range notifiers {
		if configured, err := notifier.Configure(config); configured {
			log.Infof("notifier '%s' configured\n", notifierName)
		} else {
			delete(notifiers, notifierName)
			if err != nil {
				log.Errorf("could not configure notifier '%s': %s", notifierName, err)
			}
		}
	}

	// Do not run the updater if there is no notifier enabled.
	if len(notifiers) == 0 {
		log.Infof("notifier service is disabled")
		return
	}

	whoAmI := uuid.New()
	log.Infof("notifier service started. lock identifier: %s\n", whoAmI)

	// Register healthchecker.
	health.RegisterHealthchecker("notifier", Healthcheck)

	for {
		// Find task.
		// TODO(Quentin-M): Combine node and notification.
		node, notification := findTask(whoAmI, stopper)
		if node == "" && notification == nil {
			break
		}

		// Handle task.
		done := make(chan bool, 1)
		go func() {
			if handleTask(notification, stopper, config.Attempts) {
				database.MarkNotificationAsSent(node)
			}
			database.Unlock(node, whoAmI)
			done <- true
		}()

		// Refresh task lock until done.
	outer:
		for {
			select {
			case <-done:
				break outer
			case <-time.After(refreshLockDuration):
				database.Lock(node, lockDuration, whoAmI)
			}
		}
	}

	log.Info("notifier service stopped")
}

func findTask(whoAmI string, stopper *utils.Stopper) (string, database.Notification) {
	for {
		// Find a notification to send.
		node, notification, err := database.FindOneNotificationToSend(database.GetDefaultNotificationWrapper())
		if err != nil {
			log.Warningf("could not get notification to send: %s", err)
		}

		// No notification or error: wait.
		if notification == nil || err != nil {
			if !stopper.Sleep(checkInterval) {
				return "", nil
			}
			continue
		}

		// Lock the notification.
		if hasLock, _ := database.Lock(node, lockDuration, whoAmI); hasLock {
			log.Infof("found and locked a notification: %s", notification.GetName())
			return node, notification
		}
	}
}

func handleTask(notification database.Notification, st *utils.Stopper, maxAttempts int) bool {
	// Get notification content.
	// TODO(Quentin-M): Split big notifications.
	notificationContent, err := notification.GetContent()
	if err != nil {
		log.Warningf("could not get content of notification '%s': %s", notification.GetName(), err)
		return false
	}

	// Create notification.
	payload := &Notification{
		Name:    notification.GetName(),
		Type:    notification.GetType(),
		Content: notificationContent,
	}

	// Send notification.
	for notifierName, notifier := range notifiers {
		var attempts int
		var backOff time.Duration
		for {
			// Max attempts exceeded.
			if attempts >= maxAttempts {
				log.Infof("giving up on sending notification '%s' to notifier '%s': max attempts exceeded (%d)\n", notification.GetName(), notifierName, maxAttempts)
				return false
			}

			// Backoff.
			if backOff > 0 {
				log.Infof("waiting %v before retrying to send notification '%s' to notifier '%s' (Attempt %d / %d)\n", backOff, notification.GetName(), notifierName, attempts+1, maxAttempts)
				if !st.Sleep(backOff) {
					return false
				}
			}

			// Send using the current notifier.
			if err := notifier.Send(payload); err == nil {
				// Send has been successful. Go to the next one.
				break
			}

			// Send failed; increase attempts/backoff and retry.
			log.Errorf("could not send notification '%s' to notifier '%s': %s", notification.GetName(), notifierName, err)
			backOff = timeutil.ExpBackoff(backOff, maxBackOff)
			attempts++
		}
	}

	log.Infof("successfully sent notification '%s'\n", notification.GetName())
	return true
}

// Healthcheck returns the health of the notifier service.
func Healthcheck() health.Status {
	queueSize, err := database.CountNotificationsToSend()
	return health.Status{IsEssential: false, IsHealthy: err == nil, Details: struct{ QueueSize int }{QueueSize: queueSize}}
}
<commit_msg>notifier: fix a bug that prevented graceful shutdown in certain cases<commit_after>// Copyright 2015 clair authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package notifier fetches notifications from the database and sends them
// to the specified remote handler.
package notifier

import (
	"time"

	"github.com/coreos/pkg/capnslog"
	"github.com/coreos/pkg/timeutil"
	"github.com/pborman/uuid"

	"github.com/coreos/clair/config"
	"github.com/coreos/clair/database"
	"github.com/coreos/clair/health"
	"github.com/coreos/clair/utils"
)

var log = capnslog.NewPackageLogger("github.com/coreos/clair", "notifier")

const (
	checkInterval       = 5 * time.Minute
	refreshLockDuration = time.Minute * 2
	lockDuration        = time.Minute*8 + refreshLockDuration
	maxBackOff          = 15 * time.Minute
)

// TODO(Quentin-M): Allow registering custom notification handlers.

// A Notification represents the structure of the notifications that are sent by a Notifier.
type Notification struct {
	Name, Type string
	Content    interface{}
}

var notifiers = make(map[string]Notifier)

// Notifier represents anything that can transmit notifications.
type Notifier interface {
	// Configure attempts to initialize the notifier with the provided configuration.
	// It returns whether the notifier is enabled or not.
	Configure(*config.NotifierConfig) (bool, error)
	// Send transmits the specified notification.
	Send(notification *Notification) error
}

// RegisterNotifier makes a Fetcher available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func RegisterNotifier(name string, n Notifier) {
	if name == "" {
		panic("notifier: could not register a Notifier with an empty name")
	}

	if n == nil {
		panic("notifier: could not register a nil Notifier")
	}

	if _, dup := notifiers[name]; dup {
		panic("notifier: RegisterNotifier called twice for " + name)
	}

	notifiers[name] = n
}

// Run starts the Notifier service.
func Run(config *config.NotifierConfig, stopper *utils.Stopper) {
	defer stopper.End()

	// Configure registered notifiers.
	for notifierName, notifier := range notifiers {
		if configured, err := notifier.Configure(config); configured {
			log.Infof("notifier '%s' configured\n", notifierName)
		} else {
			delete(notifiers, notifierName)
			if err != nil {
				log.Errorf("could not configure notifier '%s': %s", notifierName, err)
			}
		}
	}

	// Do not run the updater if there is no notifier enabled.
	if len(notifiers) == 0 {
		log.Infof("notifier service is disabled")
		return
	}

	whoAmI := uuid.New()
	log.Infof("notifier service started. lock identifier: %s\n", whoAmI)

	// Register healthchecker.
	health.RegisterHealthchecker("notifier", Healthcheck)

	for running := true; running; {
		// Find task.
		// TODO(Quentin-M): Combine node and notification.
		node, notification := findTask(whoAmI, stopper)
		if node == "" && notification == nil {
			// Interrupted while finding a task, Clair is stopping.
			break
		}

		// Handle task.
		done := make(chan bool, 1)
		go func() {
			success, interrupted := handleTask(notification, stopper, config.Attempts)
			if success {
				database.MarkNotificationAsSent(node)
			}
			if interrupted {
				running = false
			}
			database.Unlock(node, whoAmI)
			done <- true
		}()

		// Refresh task lock until done.
	outer:
		for {
			select {
			case <-done:
				break outer
			case <-time.After(refreshLockDuration):
				database.Lock(node, lockDuration, whoAmI)
			}
		}
	}

	log.Info("notifier service stopped")
}

func findTask(whoAmI string, stopper *utils.Stopper) (string, database.Notification) {
	for {
		// Find a notification to send.
		node, notification, err := database.FindOneNotificationToSend(database.GetDefaultNotificationWrapper())
		if err != nil {
			log.Warningf("could not get notification to send: %s", err)
		}

		// No notification or error: wait.
		if notification == nil || err != nil {
			if !stopper.Sleep(checkInterval) {
				return "", nil
			}
			continue
		}

		// Lock the notification.
		if hasLock, _ := database.Lock(node, lockDuration, whoAmI); hasLock {
			log.Infof("found and locked a notification: %s", notification.GetName())
			return node, notification
		}
	}
}

func handleTask(notification database.Notification, st *utils.Stopper, maxAttempts int) (bool, bool) {
	// Get notification content.
	// TODO(Quentin-M): Split big notifications.
	notificationContent, err := notification.GetContent()
	if err != nil {
		log.Warningf("could not get content of notification '%s': %s", notification.GetName(), err)
		return false, false
	}

	// Create notification.
	payload := &Notification{
		Name:    notification.GetName(),
		Type:    notification.GetType(),
		Content: notificationContent,
	}

	// Send notification.
	for notifierName, notifier := range notifiers {
		var attempts int
		var backOff time.Duration
		for {
			// Max attempts exceeded.
			if attempts >= maxAttempts {
				log.Infof("giving up on sending notification '%s' to notifier '%s': max attempts exceeded (%d)\n", notification.GetName(), notifierName, maxAttempts)
				return false, false
			}

			// Backoff.
			if backOff > 0 {
				log.Infof("waiting %v before retrying to send notification '%s' to notifier '%s' (Attempt %d / %d)\n", backOff, notification.GetName(), notifierName, attempts+1, maxAttempts)
				if !st.Sleep(backOff) {
					return false, true
				}
			}

			// Send using the current notifier.
			if err := notifier.Send(payload); err == nil {
				// Send has been successful. Go to the next one.
				break
			}

			// Send failed; increase attempts/backoff and retry.
			log.Errorf("could not send notification '%s' to notifier '%s': %s", notification.GetName(), notifierName, err)
			backOff = timeutil.ExpBackoff(backOff, maxBackOff)
			attempts++
		}
	}

	log.Infof("successfully sent notification '%s'\n", notification.GetName())
	return true, false
}

// Healthcheck returns the health of the notifier service.
func Healthcheck() health.Status {
	queueSize, err := database.CountNotificationsToSend()
	return health.Status{IsEssential: false, IsHealthy: err == nil, Details: struct{ QueueSize int }{QueueSize: queueSize}}
}
<|endoftext|>


<commit_before>package notifier

import ("appengine"
	"appengine/xmpp"

func Send(from string, to []string, text string, messageType string) {
	m := &xmpp.Message{
		From: from,
		To:   to,
		Body: text,
		Type: messageType,
	}
	err := m.Send(c)
}
<commit_msg>Missing closing parenthesis<commit_after>package notifier

import ("appengine"
	"appengine/xmpp")

func Send(from string, to []string, text string, messageType string) {
	m := &xmpp.Message{
		From: from,
		To:   to,
		Body: text,
		Type: messageType,
	}
	err := m.Send(c)
}
<|endoftext|>


<commit_before>package relay

import (
	"net"
	"sync"

	"github.com/fsouza/go-dockerclient"

	"code.google.com/p/go-uuid/uuid"
)

var (
	DefaultSessionGenerator = func() string { return uuid.New() }

	// DefaultOptions is a default Options instance that can be passed when
	// intializing a new Relay.
	DefaultOptions = Options{SessionGenerator: DefaultSessionGenerator}
)

// DockerOptions is a set of options to configure a docker api client.
type DockerOptions struct {
	// The default docker organization to use.
	Organization string

	// The unix socket to connect to the docker api.
	Socket string

	// Path to a certificate to use for TLS connections.
	CertPath string

	// A set of docker registry credentials.
	Auth *docker.AuthConfigurations
}

type Options struct {
	Host             string
	SessionGenerator func() string
	Docker           DockerOptions
}

// Container represents a docker container to run.
type Container struct {
	Image     string            `json:"image"`
	Name      string            `json:"name"`
	Command   string            `json:"command"`
	State     string            `json:"state"`
	Env       map[string]string `json:"env"`
	Attach    bool              `json:"attach"`
	AttachURL string            `json:"attach_url"`
}

type Relay struct {
	sync.Mutex

	// The rendezvous host
	Host string

	runner ContainerRunner

	genSessionId func() string
	sessions     map[string]bool
}

// New returns a new Relay instance.
func New(options Options) *Relay {
	sg := options.SessionGenerator
	if sg == nil {
		sg = DefaultSessionGenerator
	}

	var runner ContainerRunner
	var err error
	if options.Docker.Socket == "fake" {
		runner = &fakeRunner{}
	} else {
		runner, err = newDockerRunner(options.Docker.Socket, options.Docker.CertPath, options.Docker.Auth)
		if err != nil {
			panic(err)
		}
	}

	return &Relay{
		Host:         options.Host,
		runner:       runner,
		genSessionId: sg,
		sessions:     map[string]bool{},
	}
}

func (r *Relay) NewSession() string {
	r.Lock()
	defer r.Unlock()
	id := r.genSessionId()
	r.sessions[id] = true
	return id
}

func (r *Relay) CreateContainer(c *Container) error {
	if err := r.runner.Pull(c); err != nil {
		return err
	}
	return r.runner.Run(c)
}

func (r *Relay) AttachToContainer(name string, conn net.Conn) error {
	return r.runner.Attach(name, conn, conn)
}
<commit_msg>Add canonical import comment<commit_after>package relay // import "github.com/remind101/empire/relay"

import (
	"net"
	"sync"

	"github.com/fsouza/go-dockerclient"

	"code.google.com/p/go-uuid/uuid"
)

var (
	DefaultSessionGenerator = func() string { return uuid.New() }

	// DefaultOptions is a default Options instance that can be passed when
	// intializing a new Relay.
	DefaultOptions = Options{SessionGenerator: DefaultSessionGenerator}
)

// DockerOptions is a set of options to configure a docker api client.
type DockerOptions struct {
	// The default docker organization to use.
	Organization string

	// The unix socket to connect to the docker api.
	Socket string

	// Path to a certificate to use for TLS connections.
	CertPath string

	// A set of docker registry credentials.
	Auth *docker.AuthConfigurations
}

type Options struct {
	Host             string
	SessionGenerator func() string
	Docker           DockerOptions
}

// Container represents a docker container to run.
type Container struct {
	Image     string            `json:"image"`
	Name      string            `json:"name"`
	Command   string            `json:"command"`
	State     string            `json:"state"`
	Env       map[string]string `json:"env"`
	Attach    bool              `json:"attach"`
	AttachURL string            `json:"attach_url"`
}

type Relay struct {
	sync.Mutex

	// The rendezvous host
	Host string

	runner ContainerRunner

	genSessionId func() string
	sessions     map[string]bool
}

// New returns a new Relay instance.
func New(options Options) *Relay {
	sg := options.SessionGenerator
	if sg == nil {
		sg = DefaultSessionGenerator
	}

	var runner ContainerRunner
	var err error
	if options.Docker.Socket == "fake" {
		runner = &fakeRunner{}
	} else {
		runner, err = newDockerRunner(options.Docker.Socket, options.Docker.CertPath, options.Docker.Auth)
		if err != nil {
			panic(err)
		}
	}

	return &Relay{
		Host:         options.Host,
		runner:       runner,
		genSessionId: sg,
		sessions:     map[string]bool{},
	}
}

func (r *Relay) NewSession() string {
	r.Lock()
	defer r.Unlock()
	id := r.genSessionId()
	r.sessions[id] = true
	return id
}

func (r *Relay) CreateContainer(c *Container) error {
	if err := r.runner.Pull(c); err != nil {
		return err
	}
	return r.runner.Run(c)
}

func (r *Relay) AttachToContainer(name string, conn net.Conn) error {
	return r.runner.Attach(name, conn, conn)
}
<|endoftext|>