<commit_before>package helpers

/*

import (
	"html/template"
	"net/url"
	"testing"
	. "github.com/acsellers/assert"
)

func TestFormTag(t *testing.T) {
	Within(t, func(test *Test) {
		for _, formTagTest := range assetTests {
			test.Section("Helper: " + assetTest.Helper)
			if f, ok := formTagFuncs[assetTest.Helper]; ok {
				var r string
				switch af := f.(type) {
				case func(...string) template.HTML:
					r = string(af(assetTest.Args...))
				case func(string) template.HTML:
					r = string(af(assetTest.Args[0]))
				case func(string) string:
					r = af(assetTest.Args[0])
				case func(string, ...AttrList) template.HTML:
					r = string(af(assetTest.Args[0], assetTest.Attrs...))
				default:
					t.Fatalf("Function %s was not type asserted", assetTest.Helper)
				}
				test.AreEqual(r, assetTest.Expected)
			} else {
				t.Errorf("Could not find function %s", assetTest.Helper)
			}
		}
	})
}

var formTagTests = []helperTest{
	helperTest{
		Helper:   "atom_link",
		Args:     []string{"/api/atom"},
		Expected: `<link rel="alternate" type="application/atom+xml" title="ATOM" href="http://localhost/api/atom" />`,
	},
	helperTest{
		Helper: "favicon_link",
		Args:   []string{"favicon.png"},
		Expected: string(buildTag("link", "", AttrList{
			"rel":  "shortcut icon",
			"type": "image/png",
			"href": "/img/favicon.png",
		})),
	},
}
*/
<commit_msg>Start working on form tag helper testing<commit_after>package helpers

import (
	"html/template"
	"testing"
	. "github.com/acsellers/assert"
)

func TestFormTag(t *testing.T) {
	Within(t, func(test *Test) {
		for _, formTagTest := range formTagTests {
			test.Section("Helper: " + formTagTest.Helper)
			if f, ok := formTagFuncs[formTagTest.Helper]; ok {
				var r string
				switch af := f.(type) {
				case func(string, interface{}, ...AttrList) template.HTML:
					r = string(af(formTagTest.Args[0], formTagTest.Args[1]))
				case func(string, ...AttrList) template.HTML:
					r = string(af(formTagTest.Args[0], formTagTest.Attrs...))
				default:
					t.Fatalf("Function %s was not type asserted", formTagTest.Helper)
				}
				test.AreEqual(r, formTagTest.Expected)
			} else {
				t.Errorf("Could not find function %s", formTagTest.Helper)
			}
		}
	})
}

var formTagTests = []helperTest{
	helperTest{
		Helper:   "button_tag",
		Args:     []string{"Hello"},
		Expected: `<button name="hello">Hello</button>`,
	},
	helperTest{
		Helper:   "check_box_tag",
		Args:     []string{"is_active", "true"},
		Expected: `<input name="is_active" id="is_active" value="true" type="checkbox" />`,
	},
}

/*
type helperTest struct {
	Helper   string
	Args     []string
	Attrs    []AttrList
	Expected string
}
*/
<|endoftext|>


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

// Package crypto collects common cryptographic constants.
package crypto

import (
	"hash"
	"io"
	"strconv"
)

// Hash identifies a cryptographic hash function that is implemented in another
// package.
type Hash uint

// HashFunc simply returns the value of h so that Hash implements SignerOpts.
func (h Hash) HashFunc() Hash {
	return h
}

const (
	MD4        Hash = 1 + iota // import golang.org/x/crypto/md4
	MD5                        // import crypto/md5
	SHA1                       // import crypto/sha1
	SHA224                     // import crypto/sha256
	SHA256                     // import crypto/sha256
	SHA384                     // import crypto/sha512
	SHA512                     // import crypto/sha512
	MD5SHA1                    // no implementation; MD5+SHA1 used for TLS RSA
	RIPEMD160                  // import golang.org/x/crypto/ripemd160
	SHA3_224                   // import golang.org/x/crypto/sha3
	SHA3_256                   // import golang.org/x/crypto/sha3
	SHA3_384                   // import golang.org/x/crypto/sha3
	SHA3_512                   // import golang.org/x/crypto/sha3
	SHA512_224                 // import crypto/sha512
	SHA512_256                 // import crypto/sha512
	maxHash
)

var digestSizes = []uint8{
	MD4:        16,
	MD5:        16,
	SHA1:       20,
	SHA224:     28,
	SHA256:     32,
	SHA384:     48,
	SHA512:     64,
	SHA512_224: 28,
	SHA512_256: 32,
	SHA3_224:   28,
	SHA3_256:   32,
	SHA3_384:   48,
	SHA3_512:   64,
	MD5SHA1:    36,
	RIPEMD160:  20,
}

// Size returns the length, in bytes, of a digest resulting from the given hash
// function. It doesn't require that the hash function in question be linked
// into the program.
func (h Hash) Size() int {
	if h > 0 && h < maxHash {
		return int(digestSizes[h])
	}
	panic("crypto: Size of unknown hash function")
}

var hashes = make([]func() hash.Hash, maxHash)

// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
	if h > 0 && h < maxHash {
		f := hashes[h]
		if f != nil {
			return f()
		}
	}
	panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}

// Available reports whether the given hash function is linked into the binary.
func (h Hash) Available() bool {
	return h < maxHash && hashes[h] != nil
}

// RegisterHash registers a function that returns a new instance of the given
// hash function. This is intended to be called from the init function in
// packages that implement hash functions.
func RegisterHash(h Hash, f func() hash.Hash) {
	if h >= maxHash {
		panic("crypto: RegisterHash of unknown hash function")
	}
	hashes[h] = f
}

// PublicKey represents a public key using an unspecified algorithm.
type PublicKey interface{}

// PrivateKey represents a private key using an unspecified algorithm.
type PrivateKey interface{}

// Signer is an interface for an opaque private key that can be used for
// signing operations. For example, an RSA key kept in a hardware module.
type Signer interface {
	// Public returns the public key corresponding to the opaque,
	// private key.
	Public() PublicKey

	// Sign signs msg with the private key, possibly using entropy from
	// rand. For an RSA key, the resulting signature should be either a
	// PKCS#1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA
	// key, it should be a DER-serialised, ASN.1 signature structure.
	//
	// Hash implements the SignerOpts interface and, in most cases, one can
	// simply pass in the hash function used as opts. Sign may also attempt
	// to type assert opts to other types in order to obtain algorithm
	// specific values. See the documentation in each package for details.
	Sign(rand io.Reader, msg []byte, opts SignerOpts) (signature []byte, err error)
}

// SignerOpts contains options for signing with a Signer.
type SignerOpts interface {
	// HashFunc returns an identifier for the hash function used to produce
	// the message passed to Signer.Sign, or else zero to indicate that no
	// hashing was done.
	HashFunc() Hash
}

// Decrypter is an interface for an opaque private key that can be used for
// asymmetric decryption operations. An example would be an RSA key
// kept in a hardware module.
type Decrypter interface {
	// Public returns the public key corresponding to the opaque,
	// private key.
	Public() PublicKey

	// Decrypt decrypts msg. The opts argument should be appropriate for
	// the primitive used. See the documentation in each implementation for
	// details.
	Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
}

type DecrypterOpts interface{}
<commit_msg>crypto: document that Signer.Sign does not hash<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package crypto collects common cryptographic constants.
package crypto

import (
	"hash"
	"io"
	"strconv"
)

// Hash identifies a cryptographic hash function that is implemented in another
// package.
type Hash uint

// HashFunc simply returns the value of h so that Hash implements SignerOpts.
func (h Hash) HashFunc() Hash {
	return h
}

const (
	MD4        Hash = 1 + iota // import golang.org/x/crypto/md4
	MD5                        // import crypto/md5
	SHA1                       // import crypto/sha1
	SHA224                     // import crypto/sha256
	SHA256                     // import crypto/sha256
	SHA384                     // import crypto/sha512
	SHA512                     // import crypto/sha512
	MD5SHA1                    // no implementation; MD5+SHA1 used for TLS RSA
	RIPEMD160                  // import golang.org/x/crypto/ripemd160
	SHA3_224                   // import golang.org/x/crypto/sha3
	SHA3_256                   // import golang.org/x/crypto/sha3
	SHA3_384                   // import golang.org/x/crypto/sha3
	SHA3_512                   // import golang.org/x/crypto/sha3
	SHA512_224                 // import crypto/sha512
	SHA512_256                 // import crypto/sha512
	maxHash
)

var digestSizes = []uint8{
	MD4:        16,
	MD5:        16,
	SHA1:       20,
	SHA224:     28,
	SHA256:     32,
	SHA384:     48,
	SHA512:     64,
	SHA512_224: 28,
	SHA512_256: 32,
	SHA3_224:   28,
	SHA3_256:   32,
	SHA3_384:   48,
	SHA3_512:   64,
	MD5SHA1:    36,
	RIPEMD160:  20,
}

// Size returns the length, in bytes, of a digest resulting from the given hash
// function. It doesn't require that the hash function in question be linked
// into the program.
func (h Hash) Size() int {
	if h > 0 && h < maxHash {
		return int(digestSizes[h])
	}
	panic("crypto: Size of unknown hash function")
}

var hashes = make([]func() hash.Hash, maxHash)

// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
	if h > 0 && h < maxHash {
		f := hashes[h]
		if f != nil {
			return f()
		}
	}
	panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}

// Available reports whether the given hash function is linked into the binary.
func (h Hash) Available() bool {
	return h < maxHash && hashes[h] != nil
}

// RegisterHash registers a function that returns a new instance of the given
// hash function. This is intended to be called from the init function in
// packages that implement hash functions.
func RegisterHash(h Hash, f func() hash.Hash) {
	if h >= maxHash {
		panic("crypto: RegisterHash of unknown hash function")
	}
	hashes[h] = f
}

// PublicKey represents a public key using an unspecified algorithm.
type PublicKey interface{}

// PrivateKey represents a private key using an unspecified algorithm.
type PrivateKey interface{}

// Signer is an interface for an opaque private key that can be used for
// signing operations. For example, an RSA key kept in a hardware module.
type Signer interface {
	// Public returns the public key corresponding to the opaque,
	// private key.
	Public() PublicKey

	// Sign signs digest with the private key, possibly using entropy from
	// rand. For an RSA key, the resulting signature should be either a
	// PKCS#1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA
	// key, it should be a DER-serialised, ASN.1 signature structure.
	//
	// Hash implements the SignerOpts interface and, in most cases, one can
	// simply pass in the hash function used as opts. Sign may also attempt
	// to type assert opts to other types in order to obtain algorithm
	// specific values. See the documentation in each package for details.
	//
	// Note that when a signature of a hash of a larger message is needed,
	// the caller is responsible for hashing the larger message and passing
	// the hash (as digest) and the hash function (as opts) to Sign.
	Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)
}

// SignerOpts contains options for signing with a Signer.
type SignerOpts interface {
	// HashFunc returns an identifier for the hash function used to produce
	// the message passed to Signer.Sign, or else zero to indicate that no
	// hashing was done.
	HashFunc() Hash
}

// Decrypter is an interface for an opaque private key that can be used for
// asymmetric decryption operations. An example would be an RSA key
// kept in a hardware module.
type Decrypter interface {
	// Public returns the public key corresponding to the opaque,
	// private key.
	Public() PublicKey

	// Decrypt decrypts msg. The opts argument should be appropriate for
	// the primitive used. See the documentation in each implementation for
	// details.
	Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
}

type DecrypterOpts interface{}
<|endoftext|>


<commit_before>package gomanager

import (
	"github.com/labstack/echo"
)

// SimpleWebEcho ...
type SimpleWebEcho struct {
	*echo.Echo
	host    string
	started bool
}

// NewSimpleWebEcho...
func NewSimpleWebEcho(host string) IWeb {
	e := echo.New()
	e.HideBanner = true

	return &SimpleWebEcho{
		Echo: e,
		host: host,
	}
}

// AddRoute ...
func (web *SimpleWebEcho) AddRoute(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) error {
	web.Add(method, path, handler.(func(echo.Context) error))
	for _, item := range middleware {
		web.Use(item.(echo.MiddlewareFunc))
	}
	return nil
}

// Start ...
func (web *SimpleWebEcho) Start() error {
	if !web.started {
		if err := web.Echo.Start(web.host); err != nil {
			log.Error(err)
			return err
		}
		web.started = true
	}

	return nil
}

// Stop ...
func (web *SimpleWebEcho) Stop() error {
	if web.started {
		if err := web.Echo.Close(); err != nil {
			return err
		}
		web.started = false
	}
	return nil
}

// Started ...
func (web *SimpleWebEcho) Started() bool {
	return web.started
}
<commit_msg>fix middlware<commit_after>package gomanager

import (
	"github.com/labstack/echo"
)

// SimpleWebEcho ...
type SimpleWebEcho struct {
	*echo.Echo
	host    string
	started bool
}

// NewSimpleWebEcho...
func NewSimpleWebEcho(host string) IWeb {
	e := echo.New()
	e.HideBanner = true

	return &SimpleWebEcho{
		Echo: e,
		host: host,
	}
}

// AddRoute ...
func (web *SimpleWebEcho) AddRoute(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) error {
	web.Add(method, path, handler.(func(echo.Context) error))
	for _, item := range middleware {
		web.Group(path, item.(echo.MiddlewareFunc))
	}
	return nil
}

// Start ...
func (web *SimpleWebEcho) Start() error {
	if !web.started {
		if err := web.Echo.Start(web.host); err != nil {
			log.Error(err)
			return err
		}
		web.started = true
	}

	return nil
}

// Stop ...
func (web *SimpleWebEcho) Stop() error {
	if web.started {
		if err := web.Echo.Close(); err != nil {
			return err
		}
		web.started = false
	}
	return nil
}

// Started ...
func (web *SimpleWebEcho) Started() bool {
	return web.started
}
<|endoftext|>


<commit_before>package main

import (
	"log"
)

func main() {
	log.Println("hello world")
}
<commit_msg>Added stub of flags<commit_after>package main

import (
	"flag"
	"log"
	"os"
)

type appOptions struct {
	message string
	help    bool
	flagSet *flag.FlagSet
}

func (a *appOptions) defineFlags() {
	if a.flagSet == nil {
		return
	}
	a.flagSet.StringVar(&a.message, "m", "Hello, world!", "The message to print to the screen")
	a.flagSet.BoolVar(&a.help, "h", false, "If provided, will print help and exit.")
}

func (a *appOptions) parse(args []string) {
	a.flagSet.Parse(args)
}

func newAppOptions(flagSet *flag.FlagSet) *appOptions {
	a := &appOptions{
		flagSet: flagSet,
	}
	a.defineFlags()
	return a
}

func main() {
	a := newAppOptions(flag.CommandLine)
	a.parse(os.Args[1:])

	log.Println(a.message)
}
<|endoftext|>


<commit_before>package src

import (
	"fmt"
	"log"
	"os/exec"
	"strconv"
	"testing"
)

func TestNoop(t *testing.T) {

}

func BenchmarkHead(b *testing.B) {
	benchmarkFmt(0, b)
}
func BenchmarkHeadMinus1(b *testing.B) {
	benchmarkFmt(1, b)
}
func BenchmarkHeadMinus2(b *testing.B) {
	benchmarkFmt(2, b)
}
func BenchmarkHeadMinus3(b *testing.B) {
	benchmarkFmt(3, b)
}
func BenchmarkHeadMinus4(b *testing.B) {
	benchmarkFmt(4, b)
}
func BenchmarkHeadMinus5(b *testing.B) {
	benchmarkFmt(5, b)
}

func benchmarkFmt(commits int, b *testing.B) {
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	exec.Command("git", "checkout", "-b", "performance").Output()
	exec.Command("git", "reset", "--hard", "HEAD~"+strconv.Itoa(commits)).Output()
	out, err := exec.Command("git", "log", "--pretty=oneline", "-n1").Output()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", out)

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		exec.Command("php", "test.php", "-v").Output()
	}
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	b.StartTimer()
}
<commit_msg>Outputting content of benchmark through testing.Benchmark<commit_after>package src

import (
	"os/exec"
	"strconv"
	"testing"
)

func TestNoop(t *testing.T) {

}

func BenchmarkHead(b *testing.B) {
	benchmarkFmt(0, b)
}
func BenchmarkHeadMinus1(b *testing.B) {
	benchmarkFmt(1, b)
}
func BenchmarkHeadMinus2(b *testing.B) {
	benchmarkFmt(2, b)
}
func BenchmarkHeadMinus3(b *testing.B) {
	benchmarkFmt(3, b)
}
func BenchmarkHeadMinus4(b *testing.B) {
	benchmarkFmt(4, b)
}
func BenchmarkHeadMinus5(b *testing.B) {
	benchmarkFmt(5, b)
}

func benchmarkFmt(commits int, b *testing.B) {
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	exec.Command("git", "checkout", "-b", "performance").Output()
	exec.Command("git", "reset", "--hard", "HEAD~"+strconv.Itoa(commits)).Output()
	out, err := exec.Command("git", "log", "--pretty=oneline", "-n1").Output()
	if err != nil {
		b.Fatal(err)
	}
	b.Logf("%s", out)

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		exec.Command("php", "test.php", "-v").Output()
	}
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	b.StartTimer()
}
<|endoftext|>


<commit_before>// Package bot provides the interfaces for creating a chatops
// bot.
package bot

/* bot.go defines core data structures and public methods for startup.
   handler.go has the methods for callbacks from the connector, */

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"regexp"
	"sync"
	"syscall"
	"time"
)

// Version is the current version of Gopherbot
var Version = "v1.1.1-snapshot"

// mkdist.* creates a temporary commit.go that sets commit to the current
// git commit in an init() function
var commit = "(manual build)"

var globalLock sync.RWMutex
var random *rand.Rand

var connectors = make(map[string]func(Handler, *log.Logger) Connector)

// RegisterConnector should be called in an init function to register a type
// of connector. Currently only Slack is implemented.
func RegisterConnector(name string, connstarter func(Handler, *log.Logger) Connector) {
	if stopRegistrations {
		return
	}
	if connectors[name] != nil {
		log.Fatal("Attempted registration of duplicate connector:", name)
	}
	connectors[name] = connstarter
}

// robot holds all the interal data relevant to the Bot. Most of it is populated
// by loadConfig, other stuff is populated by the connector.
var robot struct {
	Connector                             // Connector interface, implemented by each specific protocol
	configPath           string           // Directory for configuration files overriding defaults / installed
	installPath          string           // Path to the bot's installation directory
	adminUsers           []string         // List of users with access to administrative commands
	alias                rune             // single-char alias for addressing the bot
	name                 string           // e.g. "Gort"
	fullName             string           // e.g. "Robbie Robot"
	adminContact         string           // who to contact for problems with the robot.
	email                string           // the from: when the robot sends email
	mailConf             botMailer        // configuration to use when sending email
	ignoreUsers          []string         // list of users to never listen to, like other bots
	preRegex             *regexp.Regexp   // regex for matching prefixed commands, e.g. "Gort, drop your weapon"
	postRegex            *regexp.Regexp   // regex for matching, e.g. "open the pod bay doors, hal"
	bareRegex            *regexp.Regexp   // regex for matching the robot's bare name, if you forgot it in the previous command
	joinChannels         []string         // list of channels to join
	defaultAllowDirect   bool             // whether plugins are available in DM by default
	defaultMessageFormat MessageFormat    // Raw unless set to Variable or Fixed
	plugChannels         []string         // list of channels where plugins are active by default
	sync.RWMutex                          // for safe updating of bot data structures
	protocol             string           // Name of the protocol, e.g. "slack"
	brainProvider        string           // Type of Brain provider to use
	brain                SimpleBrain      // Interface for robot to Store and Retrieve data
	defaultElevator      string           // Plugin name for performing elevation
	defaultAuthorizer    string           // Plugin name for performing authorization
	externalPlugins      []externalPlugin // List of external plugins to load
	port                 string           // Localhost port to listen on
	stop                 chan struct{}    // stop channel for stopping the connector
	done                 chan struct{}    // channel closed when robot finishes shutting down
	shuttingDown         bool             // to prevent new plugins from starting
	pluginsRunning       int              // a count of how many plugins are currently running
	paused               bool             // it's a Windows thing
	sync.WaitGroup                        // for keeping track of running plugins
}

// initBot sets up the global robot and loads
// configuration.
func initBot(cpath, epath string, logger *log.Logger) {
	globalLock.Lock()
	// Prevent plugin registration after program init
	stopRegistrations = true
	// Seed the pseudo-random number generator, for plugin IDs, RandomString, etc.
	random = rand.New(rand.NewSource(time.Now().UnixNano()))

	globalLock.Unlock()

	botLogger.Lock()
	botLogger.l = logger
	botLogger.Unlock()

	robot.Lock()
	robot.configPath = cpath
	robot.installPath = epath
	robot.stop = make(chan struct{})
	robot.done = make(chan struct{})
	robot.shuttingDown = false
	robot.Unlock()

	handle := handler{}
	bot := &Robot{}
	if err := bot.loadConfig(); err != nil {
		Log(Fatal, fmt.Sprintf("Error loading initial configuration: %v", err))
	}

	if len(robot.brainProvider) > 0 {
		if bprovider, ok := brains[robot.brainProvider]; !ok {
			Log(Fatal, fmt.Sprintf("No provider registered for brain: \"%s\"", robot.brainProvider))
		} else {
			brain := bprovider(handle, logger)
			robot.Lock()
			robot.brain = brain
			robot.Unlock()
		}
	}
}

// set connector sets the connector, which should already be initialized
func setConnector(c Connector) {
	robot.Lock()
	robot.Connector = c
	robot.Unlock()
}

// run starts all the loops and returns a channel that closes when the robot
// shuts down. It should return after the connector loop has started and
// plugins are initialized.
func run() <-chan struct{} {
	robot.RLock()
	port := robot.port
	robot.RUnlock()
	if len(port) > 0 {
		// Only start the HttpListener once, runs for life of process
		botHttpListener.Lock()
		if !botHttpListener.listening {
			botHttpListener.listening = true
			go listenHTTPJSON()
		}
		botHttpListener.Unlock()
	}

	var cl []string
	robot.RLock()
	cl = append(cl, robot.joinChannels...)
	robot.RUnlock()
	for _, channel := range cl {
		robot.JoinChannel(channel)
	}

	// Start the brain loop
	go runBrain()

	// signal handler
	go func() {
		robot.RLock()
		done := robot.done
		robot.RUnlock()
		sigs := make(chan os.Signal, 1)

		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	loop:
		for {
			select {
			case sig := <-sigs:
				robot.Lock()
				if robot.shuttingDown {
					Log(Warn, "Received SIGINT/SIGTERM while shutdown in progress")
					robot.Unlock()
				} else {
					robot.shuttingDown = true
					robot.Unlock()
					signal.Stop(sigs)
					Log(Info, fmt.Sprintf("Exiting on signal: %s", sig))
					stop()
				}
			case <-done:
				break loop
			}
		}
	}()

	// connector loop
	robot.RLock()
	go func(conn Connector, stop <-chan struct{}, done chan<- struct{}) {
		conn.Run(stop)
		close(done)
	}(robot.Connector, robot.stop, robot.done)
	robot.RUnlock()

	initializePlugins()
	robot.RLock()
	defer robot.RUnlock()
	return robot.done
}

// stop is called whenever the robot needs to shut down gracefully. All callers
// should lock the bot and check the value of robot.shuttingDown; see
// builtins.go and win_svc_run.go
func stop() {
	robot.RLock()
	pr := robot.pluginsRunning
	stop := robot.stop
	robot.RUnlock()
	Log(Debug, fmt.Sprintf("stop called with %d plugins running", pr))
	robot.Wait()
	brainQuit()
	close(stop)
}
<commit_msg>Release v1.1.1<commit_after>// Package bot provides the interfaces for creating a chatops
// bot.
package bot

/* bot.go defines core data structures and public methods for startup.
   handler.go has the methods for callbacks from the connector, */

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"regexp"
	"sync"
	"syscall"
	"time"
)

// Version is the current version of Gopherbot
var Version = "v1.1.1"

// mkdist.* creates a temporary commit.go that sets commit to the current
// git commit in an init() function
var commit = "(manual build)"

var globalLock sync.RWMutex
var random *rand.Rand

var connectors = make(map[string]func(Handler, *log.Logger) Connector)

// RegisterConnector should be called in an init function to register a type
// of connector. Currently only Slack is implemented.
func RegisterConnector(name string, connstarter func(Handler, *log.Logger) Connector) {
	if stopRegistrations {
		return
	}
	if connectors[name] != nil {
		log.Fatal("Attempted registration of duplicate connector:", name)
	}
	connectors[name] = connstarter
}

// robot holds all the interal data relevant to the Bot. Most of it is populated
// by loadConfig, other stuff is populated by the connector.
var robot struct {
	Connector                             // Connector interface, implemented by each specific protocol
	configPath           string           // Directory for configuration files overriding defaults / installed
	installPath          string           // Path to the bot's installation directory
	adminUsers           []string         // List of users with access to administrative commands
	alias                rune             // single-char alias for addressing the bot
	name                 string           // e.g. "Gort"
	fullName             string           // e.g. "Robbie Robot"
	adminContact         string           // who to contact for problems with the robot.
	email                string           // the from: when the robot sends email
	mailConf             botMailer        // configuration to use when sending email
	ignoreUsers          []string         // list of users to never listen to, like other bots
	preRegex             *regexp.Regexp   // regex for matching prefixed commands, e.g. "Gort, drop your weapon"
	postRegex            *regexp.Regexp   // regex for matching, e.g. "open the pod bay doors, hal"
	bareRegex            *regexp.Regexp   // regex for matching the robot's bare name, if you forgot it in the previous command
	joinChannels         []string         // list of channels to join
	defaultAllowDirect   bool             // whether plugins are available in DM by default
	defaultMessageFormat MessageFormat    // Raw unless set to Variable or Fixed
	plugChannels         []string         // list of channels where plugins are active by default
	sync.RWMutex                          // for safe updating of bot data structures
	protocol             string           // Name of the protocol, e.g. "slack"
	brainProvider        string           // Type of Brain provider to use
	brain                SimpleBrain      // Interface for robot to Store and Retrieve data
	defaultElevator      string           // Plugin name for performing elevation
	defaultAuthorizer    string           // Plugin name for performing authorization
	externalPlugins      []externalPlugin // List of external plugins to load
	port                 string           // Localhost port to listen on
	stop                 chan struct{}    // stop channel for stopping the connector
	done                 chan struct{}    // channel closed when robot finishes shutting down
	shuttingDown         bool             // to prevent new plugins from starting
	pluginsRunning       int              // a count of how many plugins are currently running
	paused               bool             // it's a Windows thing
	sync.WaitGroup                        // for keeping track of running plugins
}

// initBot sets up the global robot and loads
// configuration.
func initBot(cpath, epath string, logger *log.Logger) {
	globalLock.Lock()
	// Prevent plugin registration after program init
	stopRegistrations = true
	// Seed the pseudo-random number generator, for plugin IDs, RandomString, etc.
	random = rand.New(rand.NewSource(time.Now().UnixNano()))

	globalLock.Unlock()

	botLogger.Lock()
	botLogger.l = logger
	botLogger.Unlock()

	robot.Lock()
	robot.configPath = cpath
	robot.installPath = epath
	robot.stop = make(chan struct{})
	robot.done = make(chan struct{})
	robot.shuttingDown = false
	robot.Unlock()

	handle := handler{}
	bot := &Robot{}
	if err := bot.loadConfig(); err != nil {
		Log(Fatal, fmt.Sprintf("Error loading initial configuration: %v", err))
	}

	if len(robot.brainProvider) > 0 {
		if bprovider, ok := brains[robot.brainProvider]; !ok {
			Log(Fatal, fmt.Sprintf("No provider registered for brain: \"%s\"", robot.brainProvider))
		} else {
			brain := bprovider(handle, logger)
			robot.Lock()
			robot.brain = brain
			robot.Unlock()
		}
	}
}

// set connector sets the connector, which should already be initialized
func setConnector(c Connector) {
	robot.Lock()
	robot.Connector = c
	robot.Unlock()
}

// run starts all the loops and returns a channel that closes when the robot
// shuts down. It should return after the connector loop has started and
// plugins are initialized.
func run() <-chan struct{} {
	robot.RLock()
	port := robot.port
	robot.RUnlock()
	if len(port) > 0 {
		// Only start the HttpListener once, runs for life of process
		botHttpListener.Lock()
		if !botHttpListener.listening {
			botHttpListener.listening = true
			go listenHTTPJSON()
		}
		botHttpListener.Unlock()
	}

	var cl []string
	robot.RLock()
	cl = append(cl, robot.joinChannels...)
	robot.RUnlock()
	for _, channel := range cl {
		robot.JoinChannel(channel)
	}

	// Start the brain loop
	go runBrain()

	// signal handler
	go func() {
		robot.RLock()
		done := robot.done
		robot.RUnlock()
		sigs := make(chan os.Signal, 1)

		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	loop:
		for {
			select {
			case sig := <-sigs:
				robot.Lock()
				if robot.shuttingDown {
					Log(Warn, "Received SIGINT/SIGTERM while shutdown in progress")
					robot.Unlock()
				} else {
					robot.shuttingDown = true
					robot.Unlock()
					signal.Stop(sigs)
					Log(Info, fmt.Sprintf("Exiting on signal: %s", sig))
					stop()
				}
			case <-done:
				break loop
			}
		}
	}()

	// connector loop
	robot.RLock()
	go func(conn Connector, stop <-chan struct{}, done chan<- struct{}) {
		conn.Run(stop)
		close(done)
	}(robot.Connector, robot.stop, robot.done)
	robot.RUnlock()

	initializePlugins()
	robot.RLock()
	defer robot.RUnlock()
	return robot.done
}

// stop is called whenever the robot needs to shut down gracefully. All callers
// should lock the bot and check the value of robot.shuttingDown; see
// builtins.go and win_svc_run.go
func stop() {
	robot.RLock()
	pr := robot.pluginsRunning
	stop := robot.stop
	robot.RUnlock()
	Log(Debug, fmt.Sprintf("stop called with %d plugins running", pr))
	robot.Wait()
	brainQuit()
	close(stop)
}
<|endoftext|>


<commit_before>package mailgun

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
	"strconv"
	"net/url"
)

type BounceItem struct {
	CreatedAt string `json:"created_at"`
	Code      string    `json:"code"`
	Address   string    `json:"address"`
	Error     string    `json:"error"`
}

type Bounces struct {
	TotalCount int          `json:"total_count"`
	Items      []BounceItem `json:"items"`
}

type singleBounce struct {
	Bounce BounceItem `json:"bounce"`
}

func (i BounceItem) GetCreatedAt() (t time.Time, err error) {
	t, err = time.Parse("Mon, 2 Jan 2006 15:04:05 MST", i.CreatedAt)
	return
}

func (m *mailgunImpl) GetBounces(limit, skip int) (Bounces, error) {
	u, err := url.Parse(generateApiUrl(m, bouncesEndpoint))
	if err != nil {
		return Bounces{}, err
	}

	q := u.Query()
	if limit != -1 {
		q.Set("limit", strconv.Itoa(limit))
	}
	if skip != -1 {
		q.Set("skip", strconv.Itoa(skip))
	}
	u.RawQuery = q.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return Bounces{}, err
	}
	req.SetBasicAuth(basicAuthUser, m.ApiKey())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return Bounces{}, err
	}
	if resp.StatusCode != http.StatusOK {
		return Bounces{}, errors.New(fmt.Sprintf("Status is not 200. It was %d", resp.StatusCode))
	}

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

	var response Bounces
	err2 := json.Unmarshal(body, &response)
	if err2 != nil {
		return Bounces{}, err2
	}

	return response, nil
}

func (m *mailgunImpl) GetSingleBounce(address string) (BounceItem, error) {
	return BounceItem{}, nil
}

func (m *mailgunImpl) AddBounce(address, code, error string) error {
	return nil
}

func (m *mailgunImpl) DeleteBounce(address string) error {
	return nil
}
<commit_msg>Gofmt.<commit_after>package mailgun

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

type BounceItem struct {
	CreatedAt string `json:"created_at"`
	Code      string `json:"code"`
	Address   string `json:"address"`
	Error     string `json:"error"`
}

type Bounces struct {
	TotalCount int          `json:"total_count"`
	Items      []BounceItem `json:"items"`
}

type singleBounce struct {
	Bounce BounceItem `json:"bounce"`
}

func (i BounceItem) GetCreatedAt() (t time.Time, err error) {
	t, err = time.Parse("Mon, 2 Jan 2006 15:04:05 MST", i.CreatedAt)
	return
}

func (m *mailgunImpl) GetBounces(limit, skip int) (Bounces, error) {
	u, err := url.Parse(generateApiUrl(m, bouncesEndpoint))
	if err != nil {
		return Bounces{}, err
	}

	q := u.Query()
	if limit != -1 {
		q.Set("limit", strconv.Itoa(limit))
	}
	if skip != -1 {
		q.Set("skip", strconv.Itoa(skip))
	}
	u.RawQuery = q.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return Bounces{}, err
	}
	req.SetBasicAuth(basicAuthUser, m.ApiKey())

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return Bounces{}, err
	}
	if resp.StatusCode != http.StatusOK {
		return Bounces{}, errors.New(fmt.Sprintf("Status is not 200. It was %d", resp.StatusCode))
	}

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

	var response Bounces
	err2 := json.Unmarshal(body, &response)
	if err2 != nil {
		return Bounces{}, err2
	}

	return response, nil
}

func (m *mailgunImpl) GetSingleBounce(address string) (BounceItem, error) {
	return BounceItem{}, nil
}

func (m *mailgunImpl) AddBounce(address, code, error string) error {
	return nil
}

func (m *mailgunImpl) DeleteBounce(address string) error {
	return nil
}
<|endoftext|>


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

package xproxyd

import (
	"io"
	"sync"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/flow"
	"v.io/v23/flow/message"
	"v.io/v23/naming"
)

const reconnectDelay = 50 * time.Millisecond

type proxy struct {
	m              flow.Manager
	mu             sync.Mutex
	proxyEndpoints map[string][]naming.Endpoint // keyed by proxy address
}

func New(ctx *context.T) (*proxy, *context.T, error) {
	mgr, err := v23.NewFlowManager(ctx)
	if err != nil {
		return nil, nil, err
	}
	p := &proxy{
		m:              mgr,
		proxyEndpoints: make(map[string][]naming.Endpoint),
	}
	for _, addr := range v23.GetListenSpec(ctx).Addrs {
		if addr.Protocol == "v23" {
			ep, err := v23.NewEndpoint(addr.Address)
			if err != nil {
				return nil, nil, err
			}
			go p.connectToProxy(ctx, addr.Address, ep)
		} else if err := p.m.Listen(ctx, addr.Protocol, addr.Address); err != nil {
			return nil, nil, err
		}
	}
	go p.listenLoop(ctx)
	return p, ctx, nil
}

func (p *proxy) ListeningEndpoints() []naming.Endpoint {
	return p.m.ListeningEndpoints()
}

func (p *proxy) MultipleProxyEndpoints() []naming.Endpoint {
	var eps []naming.Endpoint
	p.mu.Lock()
	for _, v := range p.proxyEndpoints {
		eps = append(eps, v...)
	}
	p.mu.Unlock()
	return eps
}

func (p *proxy) listenLoop(ctx *context.T) {
	for {
		f, err := p.m.Accept(ctx)
		if err != nil {
			ctx.Infof("p.m.Accept failed: %v", err)
			break
		}
		msg, err := readMessage(ctx, f)
		if err != nil {
			ctx.Errorf("reading type byte failed: %v", err)
		}
		switch m := msg.(type) {
		case *message.Setup:
			err = p.startRouting(ctx, f, m)
		case *message.MultiProxyRequest:
			err = p.replyToProxy(ctx, f)
		case *message.ProxyServerRequest:
			err = p.replyToServer(ctx, f)
		default:
			continue
		}
		if err != nil {
			ctx.Errorf("failed to handle incoming connection: %v", err)
		}
	}
}

func (p *proxy) startRouting(ctx *context.T, f flow.Flow, m *message.Setup) error {
	fout, err := p.dialNextHop(ctx, f, m)
	if err != nil {
		f.Close()
		return err
	}
	go p.forwardLoop(ctx, f, fout)
	go p.forwardLoop(ctx, fout, f)
	return nil
}

func (p *proxy) forwardLoop(ctx *context.T, fin, fout flow.Flow) {
	for {
		if _, err := io.Copy(fin, fout); err != nil {
			fin.Close()
			fout.Close()
			ctx.Errorf("f.Read failed: %v", err)
			return
		}
	}
}

func (p *proxy) dialNextHop(ctx *context.T, f flow.Flow, m *message.Setup) (flow.Flow, error) {
	var (
		rid naming.RoutingID
		ep  naming.Endpoint
		err error
	)
	if ep, err = removeNetworkAddress(m.PeerRemoteEndpoint); err != nil {
		return nil, err
	}
	if routes := ep.Routes(); len(routes) > 0 {
		if err := rid.FromString(routes[0]); err != nil {
			return nil, err
		}
		// Make an endpoint with the correct routingID to dial out. All other fields
		// do not matter.
		// TODO(suharshs): Make sure that the routingID from the route belongs to a
		// connection that is stored in the manager's cache. (i.e. a Server has connected
		// with the routingID before)
		if ep, err = setEndpointRoutingID(ep, rid); err != nil {
			return nil, err
		}
		// Remove the read route from the setup message endpoint.
		if m.PeerRemoteEndpoint, err = setEndpointRoutes(m.PeerRemoteEndpoint, routes[1:]); err != nil {
			return nil, err
		}
	}
	fout, err := p.m.Dial(ctx, ep, proxyAuthorizer{})
	if err != nil {
		return nil, err
	}
	// Write the setup message back onto the flow for the next hop to read.
	return fout, writeMessage(ctx, m, fout)
}

func (p *proxy) replyToServer(ctx *context.T, f flow.Flow) error {
	rid := f.Conn().RemoteEndpoint().RoutingID()
	eps, err := p.returnEndpoints(ctx, rid, "")
	if err != nil {
		return err
	}
	return writeMessage(ctx, &message.ProxyResponse{Endpoints: eps}, f)
}

func (p *proxy) replyToProxy(ctx *context.T, f flow.Flow) error {
	// Add the routing id of the incoming proxy to the routes. The routing id of the
	// returned endpoint doesn't matter because it will eventually be replaced
	// by a server's rid by some later proxy.
	// TODO(suharshs): Use a local route instead of this global routingID.
	rid := f.Conn().RemoteEndpoint().RoutingID()
	eps, err := p.returnEndpoints(ctx, naming.NullRoutingID, rid.String())
	if err != nil {
		return err
	}
	return writeMessage(ctx, &message.ProxyResponse{Endpoints: eps}, f)
}

func (p *proxy) returnEndpoints(ctx *context.T, rid naming.RoutingID, route string) ([]naming.Endpoint, error) {
	p.mu.Lock()
	eps := p.m.ListeningEndpoints()
	for _, peps := range p.proxyEndpoints {
		eps = append(eps, peps...)
	}
	p.mu.Unlock()
	if len(eps) == 0 {
		return nil, NewErrNotListening(ctx)
	}
	for idx, ep := range eps {
		var err error
		if rid != naming.NullRoutingID {
			ep, err = setEndpointRoutingID(ep, rid)
			if err != nil {
				return nil, err
			}
		}
		if len(route) > 0 {
			var cp []string
			cp = append(cp, ep.Routes()...)
			cp = append(cp, route)
			ep, err = setEndpointRoutes(ep, cp)
			if err != nil {
				return nil, err
			}
		}
		eps[idx] = ep
	}
	return eps, nil
}

func (p *proxy) connectToProxy(ctx *context.T, address string, ep naming.Endpoint) {
	for delay := reconnectDelay; ; delay *= 2 {
		time.Sleep(delay - reconnectDelay)
		select {
		case <-ctx.Done():
			return
		default:
		}
		f, err := p.m.Dial(ctx, ep, proxyAuthorizer{})
		if err != nil {
			ctx.Error(err)
			continue
		}
		// Send a byte telling the acceptor that we are a proxy.
		if err := writeMessage(ctx, &message.MultiProxyRequest{}, f); err != nil {
			ctx.Error(err)
			continue
		}
		eps, err := readProxyResponse(ctx, f)
		if err != nil {
			ctx.Error(err)
			continue
		}
		p.mu.Lock()
		p.proxyEndpoints[address] = eps
		p.mu.Unlock()
		select {
		case <-ctx.Done():
			return
		case <-f.Closed():
			p.mu.Lock()
			delete(p.proxyEndpoints, address)
			p.mu.Unlock()
			delay = reconnectDelay
		}
	}
}
<commit_msg>services/xproxyd: Fix error message.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xproxyd

import (
	"io"
	"sync"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/flow"
	"v.io/v23/flow/message"
	"v.io/v23/naming"
)

const reconnectDelay = 50 * time.Millisecond

type proxy struct {
	m              flow.Manager
	mu             sync.Mutex
	proxyEndpoints map[string][]naming.Endpoint // keyed by proxy address
}

func New(ctx *context.T) (*proxy, *context.T, error) {
	mgr, err := v23.NewFlowManager(ctx)
	if err != nil {
		return nil, nil, err
	}
	p := &proxy{
		m:              mgr,
		proxyEndpoints: make(map[string][]naming.Endpoint),
	}
	for _, addr := range v23.GetListenSpec(ctx).Addrs {
		if addr.Protocol == "v23" {
			ep, err := v23.NewEndpoint(addr.Address)
			if err != nil {
				return nil, nil, err
			}
			go p.connectToProxy(ctx, addr.Address, ep)
		} else if err := p.m.Listen(ctx, addr.Protocol, addr.Address); err != nil {
			return nil, nil, err
		}
	}
	go p.listenLoop(ctx)
	return p, ctx, nil
}

func (p *proxy) ListeningEndpoints() []naming.Endpoint {
	return p.m.ListeningEndpoints()
}

func (p *proxy) MultipleProxyEndpoints() []naming.Endpoint {
	var eps []naming.Endpoint
	p.mu.Lock()
	for _, v := range p.proxyEndpoints {
		eps = append(eps, v...)
	}
	p.mu.Unlock()
	return eps
}

func (p *proxy) listenLoop(ctx *context.T) {
	for {
		f, err := p.m.Accept(ctx)
		if err != nil {
			ctx.Infof("p.m.Accept failed: %v", err)
			break
		}
		msg, err := readMessage(ctx, f)
		if err != nil {
			ctx.Errorf("reading message failed: %v", err)
		}
		switch m := msg.(type) {
		case *message.Setup:
			err = p.startRouting(ctx, f, m)
		case *message.MultiProxyRequest:
			err = p.replyToProxy(ctx, f)
		case *message.ProxyServerRequest:
			err = p.replyToServer(ctx, f)
		default:
			continue
		}
		if err != nil {
			ctx.Errorf("failed to handle incoming connection: %v", err)
		}
	}
}

func (p *proxy) startRouting(ctx *context.T, f flow.Flow, m *message.Setup) error {
	fout, err := p.dialNextHop(ctx, f, m)
	if err != nil {
		f.Close()
		return err
	}
	go p.forwardLoop(ctx, f, fout)
	go p.forwardLoop(ctx, fout, f)
	return nil
}

func (p *proxy) forwardLoop(ctx *context.T, fin, fout flow.Flow) {
	for {
		if _, err := io.Copy(fin, fout); err != nil {
			fin.Close()
			fout.Close()
			ctx.Errorf("f.Read failed: %v", err)
			return
		}
	}
}

func (p *proxy) dialNextHop(ctx *context.T, f flow.Flow, m *message.Setup) (flow.Flow, error) {
	var (
		rid naming.RoutingID
		ep  naming.Endpoint
		err error
	)
	if ep, err = removeNetworkAddress(m.PeerRemoteEndpoint); err != nil {
		return nil, err
	}
	if routes := ep.Routes(); len(routes) > 0 {
		if err := rid.FromString(routes[0]); err != nil {
			return nil, err
		}
		// Make an endpoint with the correct routingID to dial out. All other fields
		// do not matter.
		// TODO(suharshs): Make sure that the routingID from the route belongs to a
		// connection that is stored in the manager's cache. (i.e. a Server has connected
		// with the routingID before)
		if ep, err = setEndpointRoutingID(ep, rid); err != nil {
			return nil, err
		}
		// Remove the read route from the setup message endpoint.
		if m.PeerRemoteEndpoint, err = setEndpointRoutes(m.PeerRemoteEndpoint, routes[1:]); err != nil {
			return nil, err
		}
	}
	fout, err := p.m.Dial(ctx, ep, proxyAuthorizer{})
	if err != nil {
		return nil, err
	}
	// Write the setup message back onto the flow for the next hop to read.
	return fout, writeMessage(ctx, m, fout)
}

func (p *proxy) replyToServer(ctx *context.T, f flow.Flow) error {
	rid := f.Conn().RemoteEndpoint().RoutingID()
	eps, err := p.returnEndpoints(ctx, rid, "")
	if err != nil {
		return err
	}
	return writeMessage(ctx, &message.ProxyResponse{Endpoints: eps}, f)
}

func (p *proxy) replyToProxy(ctx *context.T, f flow.Flow) error {
	// Add the routing id of the incoming proxy to the routes. The routing id of the
	// returned endpoint doesn't matter because it will eventually be replaced
	// by a server's rid by some later proxy.
	// TODO(suharshs): Use a local route instead of this global routingID.
	rid := f.Conn().RemoteEndpoint().RoutingID()
	eps, err := p.returnEndpoints(ctx, naming.NullRoutingID, rid.String())
	if err != nil {
		return err
	}
	return writeMessage(ctx, &message.ProxyResponse{Endpoints: eps}, f)
}

func (p *proxy) returnEndpoints(ctx *context.T, rid naming.RoutingID, route string) ([]naming.Endpoint, error) {
	p.mu.Lock()
	eps := p.m.ListeningEndpoints()
	for _, peps := range p.proxyEndpoints {
		eps = append(eps, peps...)
	}
	p.mu.Unlock()
	if len(eps) == 0 {
		return nil, NewErrNotListening(ctx)
	}
	for idx, ep := range eps {
		var err error
		if rid != naming.NullRoutingID {
			ep, err = setEndpointRoutingID(ep, rid)
			if err != nil {
				return nil, err
			}
		}
		if len(route) > 0 {
			var cp []string
			cp = append(cp, ep.Routes()...)
			cp = append(cp, route)
			ep, err = setEndpointRoutes(ep, cp)
			if err != nil {
				return nil, err
			}
		}
		eps[idx] = ep
	}
	return eps, nil
}

func (p *proxy) connectToProxy(ctx *context.T, address string, ep naming.Endpoint) {
	for delay := reconnectDelay; ; delay *= 2 {
		time.Sleep(delay - reconnectDelay)
		select {
		case <-ctx.Done():
			return
		default:
		}
		f, err := p.m.Dial(ctx, ep, proxyAuthorizer{})
		if err != nil {
			ctx.Error(err)
			continue
		}
		// Send a byte telling the acceptor that we are a proxy.
		if err := writeMessage(ctx, &message.MultiProxyRequest{}, f); err != nil {
			ctx.Error(err)
			continue
		}
		eps, err := readProxyResponse(ctx, f)
		if err != nil {
			ctx.Error(err)
			continue
		}
		p.mu.Lock()
		p.proxyEndpoints[address] = eps
		p.mu.Unlock()
		select {
		case <-ctx.Done():
			return
		case <-f.Closed():
			p.mu.Lock()
			delete(p.proxyEndpoints, address)
			p.mu.Unlock()
			delay = reconnectDelay
		}
	}
}
<|endoftext|>


<commit_before>package wal

import (
	"bytes"
	"encoding/binary"
	"io"
	"sync/atomic"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/errors"
	"golang.org/x/crypto/blake2b"
)

// Update defines a single update that can be sent to the WAL and saved
// atomically. Updates are sent to the wal in groups of one or more, and upon
// being signaled, will be saved to disk in a high-integrity, all- or-nothing
// fasion that follows ACID principles.
//
// The name and version are optional, however best-practice code will make use
// of these fields.
//
// When using the Update, it recommended that you typecast the Update type to
// another type which has methods on it for creating and applying the Update +
// instructions, including any special handling based on the version.
type Update struct {
	// The name of the update type. When the WAL is loaded after an unclean
	// shutdown, any un-committed changes will be passed as Updates back to the
	// caller instantiating the WAL. The caller should determine what code to
	// run on the the update based on the name and version.
	Name string

	// The version of the update type. Update types and implementations can be
	// tweaked over time, and a version field allows for easy compatibility
	// between releases, even if an upgrade occurs between an unclean shutdown
	// and a reload.
	Version string

	// The marshalled data directing the update. The data is an opaque set of
	// instructions to follow that implement and idempotent change to a set of
	// persistent files. A series of unclean shutdowns in rapid succession could
	// mean that these instructions get followed multiple times, which means
	// idempotent instructions are required.
	Instructions []byte
}

// Transaction defines a series of updates that are to be performed atomically.
// In the event of an unclean shutdown, either all updates will have been saved
// together at full integrity, or none of the updates in the transaction will
// have been saved at all.
//
// While multiple transactions can be safely open at the same time, multiple
// methods should not be called on the transaction at the same time - the WAL
// is thread-safe, but the transactions are not.
//
// A Transaction is created by calling NewTransaction. Afterwards, the
// transactions SignalSetupComplete has to be called which returns a channel
// that is closed once the transaction is committed. Finally
// SignalUpdatesApplied needs to be called after the transaction was committed
// to signal a successfull transaction and free used pages.
type Transaction struct {
	// setupComplete, commitComplete, and releaseComplete signal the progress of
	// the transaction, and should be set to 'true' in order.
	//
	// When setupComplete is set to true, it means that the creater of the
	// transaction is ready for the transaction to be committed.
	//
	// When commitComplete is set to true, it means that the WAL has
	// successfully and fully committed the transaction.
	//
	// releaseComplete is set to true when the caller has fully applied the
	// transaction, meaning the transaction can be over-written safely in the
	// WAL, and the on-disk pages can be reclaimed for future transactions.
	setupComplete   bool
	commitComplete  bool
	releaseComplete bool

	// firstPage is the first page of the transaction. It is the last page that
	// is written when finalizing a commit and when releasing a transaction.
	firstPage *page

	// Updates defines the set of updates that compose the transaction.
	Updates []Update

	// The wal that was used to create the transaction
	wal *WAL
	// An internal channel to signal that the transaction was initialized and
	// can be committed
	initComplete chan error
}

// checksum calculates the checksum of a transaction excluding the checksum
// field of each page
func (t Transaction) checksum() (c checksum) {
	h, _ := blake2b.New256(nil)
	buf := make([]byte, pageSize)
	for page := t.firstPage; page != nil; page = page.nextPage {
		b := page.appendTo(buf[:0])
		h.Write(b[checksumSize:]) // exclude checksum
	}
	copy(c[:], h.Sum(buf[:0]))
	return
}

// commit commits a transaction by setting the correct status and checksum
func (t *Transaction) commit(done chan error) {
	// Signal completion of the commit
	defer close(done)

	// Make sure that the initialization of the transaction finished
	err := <-t.initComplete
	if err != nil {
		done <- err
		return
	}

	// set the status of the first page first
	t.firstPage.pageStatus = pageStatusComitted

	// Set the transaction number of the first page and increase the transactionCounter of the wal
	t.firstPage.transactionNumber = atomic.AddUint64(&t.wal.atomicNextTxnNum, 1) - 1

	// calculate the checksum
	t.firstPage.transactionChecksum = t.checksum()

	// Finalize the commit by writing the first page with the updated status if
	// there have been no errors so far.
	if t.wal.deps.disrupt("CommitFail") {
		// Disk failure causes the commit to fail
		done <- errors.New("Write failed on purpose")
		return
	}
	if _, err := t.wal.logFile.WriteAt(t.firstPage.appendTo(nil), int64(t.firstPage.offset)); err != nil {
		done <- build.ExtendErr("Writing the first page failed", err)
		return
	}

	t.commitComplete = true
	t.wal.fSync()
}

// marshalUpdates marshals the updates of a transaction
func marshalUpdates(updates []Update) ([]byte, error) {
	buffer := new(bytes.Buffer)

	for _, update := range updates {
		// Marshal name
		name := []byte(update.Name)
		err1 := binary.Write(buffer, binary.LittleEndian, uint64(len(name)))
		_, err2 := buffer.Write(name)

		// Marshal version
		version := []byte(update.Version)
		err3 := binary.Write(buffer, binary.LittleEndian, uint64(len(version)))
		_, err4 := buffer.Write(version)

		// Append instructions
		err5 := binary.Write(buffer, binary.LittleEndian, uint64(len(update.Instructions)))
		_, err6 := buffer.Write(update.Instructions)

		if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil {
			return nil, errors.Compose(errors.New("Failed to marshal updates"), err1, err2, err3, err4, err5, err6)
		}
	}

	return buffer.Bytes(), nil
}

// unmarshalUpdates unmarshals the updates of a transaction
func unmarshalUpdates(data []byte) ([]Update, error) {
	buffer := bytes.NewBuffer(data)
	updates := make([]Update, 0)

	for {
		update := Update{}

		// Unmarshal name
		var nameLength uint64
		err1 := binary.Read(buffer, binary.LittleEndian, &nameLength)
		if err1 == io.EOF {
			// End of buffer reached
			break
		}

		name := make([]byte, nameLength)
		_, err2 := buffer.Read(name)

		// Unmarshal version
		var versionLength uint64
		err3 := binary.Read(buffer, binary.LittleEndian, &versionLength)

		version := make([]byte, versionLength)
		_, err4 := buffer.Read(version)

		// Unmarshal instructions
		var instructionsLength uint64
		err5 := binary.Read(buffer, binary.LittleEndian, &instructionsLength)

		instructions := make([]byte, instructionsLength)
		_, err6 := buffer.Read(instructions)

		// Check if any errors occured
		if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil {
			return nil, errors.Compose(errors.New("Failed to unmarshal updates"), err1, err2, err3, err4, err5, err6)
		}

		update.Name = string(name)
		update.Version = string(version)
		update.Instructions = instructions

		updates = append(updates, update)
	}

	return updates, nil
}

// threadedInitTransaction reserves pages of the wal, marshalls the
// transactions's updates into a payload and splits the payload equally among
// the pages. Once finished those pages are written to disk and the transaction
// is committed.
func initTransaction(t *Transaction) {
	defer close(t.initComplete)

	// Marshal all the updates to get their total length on disk
	data, err := marshalUpdates(t.Updates)
	if err != nil {
		t.initComplete <- build.ExtendErr("could not marshal update", err)
		return
	}

	// Get the pages from the wal and set the first page's status
	pages := t.wal.managedReservePages(data)
	pages[0].pageStatus = pageStatusWritten

	// Set the first page of the transaction
	t.firstPage = &pages[0]

	// write the pages to disk
	if err := t.writeToFile(); err != nil {
		t.initComplete <- build.ExtendErr("Couldn't write the page to file", err)
		return
	}
}

// validateChecksum checks if a transaction has been corrupted by computing a hash
// and comparing it to the one in the firstPage of the transaction
func (t Transaction) validateChecksum() error {
	if t.firstPage == nil {
		return errors.New("firstPage is nil")
	} else if t.checksum() != t.firstPage.transactionChecksum {
		return errors.New("checksum not valid")
	}
	return nil
}

// SignalUpdatesApplied  informs the WAL that it is safe to free the used pages to reuse them in a new transaction
func (t *Transaction) SignalUpdatesApplied() error {
	if !t.setupComplete || !t.commitComplete || t.releaseComplete {
		return errors.New("misuse of transaction - call each of the signaling methods exactly once, in serial, in order")
	}
	t.releaseComplete = true

	// Set the page status to applied
	t.firstPage.pageStatus = pageStatusApplied

	// Write the page to disk
	var err error
	if t.wal.deps.disrupt("ReleaseFail") {
		// Disk failure causes the commit to fail
		err = errors.New("Write failed on purpose")
	} else {
		_, err = t.wal.logFile.WriteAt(t.firstPage.appendTo(nil), int64(t.firstPage.offset))
	}
	if err != nil {
		return build.ExtendErr("Couldn't write the page to file", err)
	}
	t.wal.fSync()

	// Update the wal's available pages
	t.wal.mu.Lock()
	for page := t.firstPage; page != nil; page = page.nextPage {
		// Append the index of the freed page
		t.wal.availablePages = append(t.wal.availablePages, page.offset)
	}
	t.wal.mu.Unlock()

	// Decrease the number of active transactions
	if atomic.AddInt64(&t.wal.atomicUnfinishedTxns, -1) < 0 {
		panic("Sanity check failed. atomicUnfinishedTxns should never be negative")
	}

	return nil
}

// append is a helper function to append updates to a transaction on which
// SignalSetupComplete hasn't been called yet
func (t *Transaction) append(updates []Update, done chan error) {
	defer close(done)

	// If there is nothing to append we are done
	if len(updates) == 0 {
		return
	}

	// Make sure that the initialization finished
	err := <-t.initComplete
	if err != nil {
		done <- err
		return
	}

	// Marshal the data
	data, err := marshalUpdates(updates)
	if err != nil {
		done <- errors.Extend(errors.New("failed to marshal new updates"), err)
		return
	}

	// Find last page to which we append and count the pages
	lastPage := t.firstPage
	for lastPage.nextPage != nil {
		lastPage = lastPage.nextPage
	}

	// Write as much data to the last page as possible
	lenDiff := maxPayloadSize - len(lastPage.payload)
	if len(data) <= lenDiff {
		lastPage.payload = append(lastPage.payload, data...)
		data = nil
	} else {
		lastPage.payload = append(lastPage.payload, data[:lenDiff]...)
		data = data[lenDiff:]
	}

	// If there is no more data to write we are done
	if data == nil {
		return
	}

	// Get enough pages for the remaining data
	pages := t.wal.managedReservePages(data)
	lastPage.nextPage = &pages[0]

	// Write the new pages to disk and sync them
	buf := make([]byte, pageSize)
	for _, page := range pages {
		b := page.appendTo(buf[:0])
		if _, err := t.wal.logFile.WriteAt(b, int64(page.offset)); err != nil {
			done <- build.ExtendErr("Writing the page to disk failed", err)
			return
		}
	}
	t.wal.fSync()

	// Link the new pages to the last one and sync the last page
	b := lastPage.appendTo(buf[:0])
	if _, err := t.wal.logFile.WriteAt(b, int64(lastPage.offset)); err != nil {
		done <- build.ExtendErr("Writing the last page to disk failed", err)
		return
	}
	t.wal.fSync()

	// Append the updates to the transaction
	t.Updates = append(t.Updates, updates...)
}

// Append appends additional updates to a transaction
func (t *Transaction) Append(updates []Update) <-chan error {
	done := make(chan error, 1)

	if t.setupComplete || t.commitComplete || t.releaseComplete {
		done <- errors.New("misuse of trnasaction - can't append to transaction once it is committed/released")
		return done
	}

	go t.append(updates, done)
	return done
}

// SignalSetupComplete will signal to the WAL that any required setup has
// completed, and that the WAL can safely commit to the transaction being
// applied atomically.
func (t *Transaction) SignalSetupComplete() <-chan error {
	done := make(chan error, 1)

	if t.setupComplete || t.commitComplete || t.releaseComplete {
		done <- errors.New("misuse of transaction - call each of the signaling methods exactly ones, in serial, in order")
		return done
	}
	t.setupComplete = true

	// Commit the transaction non-blocking
	go t.commit(done)
	return done
}

// NewTransaction creates a transaction from a set of updates
func (w *WAL) NewTransaction(updates []Update) (*Transaction, error) {
	if !w.recoveryComplete {
		return nil, errors.New("can't call NewTransaction before recovery is complete")
	}
	// Check that there are updates for the transaction to process.
	if len(updates) == 0 {
		return nil, errors.New("cannot create a transaction without updates")
	}

	// Create new transaction
	newTransaction := Transaction{
		Updates:      updates,
		wal:          w,
		initComplete: make(chan error),
	}

	// Initialize the transaction by splitting up the payload among free pages
	// and writing them to disk.
	go initTransaction(&newTransaction)

	// Increase the number of active transaction
	atomic.AddInt64(&w.atomicUnfinishedTxns, 1)

	return &newTransaction, nil
}

// writeToFile writes all the pages of the transaction to disk
func (t *Transaction) writeToFile() error {
	buf := make([]byte, pageSize)
	for page := t.firstPage; page != nil; page = page.nextPage {
		b := page.appendTo(buf[:0])
		if _, err := t.wal.logFile.WriteAt(b, int64(page.offset)); err != nil {
			return build.ExtendErr("Writing the page to disk failed", err)
		}
	}
	return nil
}
<commit_msg>add initErr field to transaction to indicate an intitialization error<commit_after>package wal

import (
	"bytes"
	"encoding/binary"
	"io"
	"sync/atomic"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/errors"
	"golang.org/x/crypto/blake2b"
)

// Update defines a single update that can be sent to the WAL and saved
// atomically. Updates are sent to the wal in groups of one or more, and upon
// being signaled, will be saved to disk in a high-integrity, all- or-nothing
// fasion that follows ACID principles.
//
// The name and version are optional, however best-practice code will make use
// of these fields.
//
// When using the Update, it recommended that you typecast the Update type to
// another type which has methods on it for creating and applying the Update +
// instructions, including any special handling based on the version.
type Update struct {
	// The name of the update type. When the WAL is loaded after an unclean
	// shutdown, any un-committed changes will be passed as Updates back to the
	// caller instantiating the WAL. The caller should determine what code to
	// run on the the update based on the name and version.
	Name string

	// The version of the update type. Update types and implementations can be
	// tweaked over time, and a version field allows for easy compatibility
	// between releases, even if an upgrade occurs between an unclean shutdown
	// and a reload.
	Version string

	// The marshalled data directing the update. The data is an opaque set of
	// instructions to follow that implement and idempotent change to a set of
	// persistent files. A series of unclean shutdowns in rapid succession could
	// mean that these instructions get followed multiple times, which means
	// idempotent instructions are required.
	Instructions []byte
}

// Transaction defines a series of updates that are to be performed atomically.
// In the event of an unclean shutdown, either all updates will have been saved
// together at full integrity, or none of the updates in the transaction will
// have been saved at all.
//
// While multiple transactions can be safely open at the same time, multiple
// methods should not be called on the transaction at the same time - the WAL
// is thread-safe, but the transactions are not.
//
// A Transaction is created by calling NewTransaction. Afterwards, the
// transactions SignalSetupComplete has to be called which returns a channel
// that is closed once the transaction is committed. Finally
// SignalUpdatesApplied needs to be called after the transaction was committed
// to signal a successfull transaction and free used pages.
type Transaction struct {
	// setupComplete, commitComplete, and releaseComplete signal the progress of
	// the transaction, and should be set to 'true' in order.
	//
	// When setupComplete is set to true, it means that the creater of the
	// transaction is ready for the transaction to be committed.
	//
	// When commitComplete is set to true, it means that the WAL has
	// successfully and fully committed the transaction.
	//
	// releaseComplete is set to true when the caller has fully applied the
	// transaction, meaning the transaction can be over-written safely in the
	// WAL, and the on-disk pages can be reclaimed for future transactions.
	setupComplete   bool
	commitComplete  bool
	releaseComplete bool

	// firstPage is the first page of the transaction. It is the last page that
	// is written when finalizing a commit and when releasing a transaction.
	firstPage *page

	// Updates defines the set of updates that compose the transaction.
	Updates []Update

	// The wal that was used to create the transaction
	wal *WAL
	// initComplete is used to signal if initializing the transaction is complete
	initComplete chan struct{}
	// initErr stores possible errors that might have occured during
	// initialization
	initErr error
}

// checksum calculates the checksum of a transaction excluding the checksum
// field of each page
func (t Transaction) checksum() (c checksum) {
	h, _ := blake2b.New256(nil)
	buf := make([]byte, pageSize)
	for page := t.firstPage; page != nil; page = page.nextPage {
		b := page.appendTo(buf[:0])
		h.Write(b[checksumSize:]) // exclude checksum
	}
	copy(c[:], h.Sum(buf[:0]))
	return
}

// commit commits a transaction by setting the correct status and checksum
func (t *Transaction) commit(done chan error) {
	// Signal completion of the commit
	defer close(done)

	// Make sure that the initialization of the transaction finished
	<-t.initComplete
	if t.initErr != nil {
		done <- t.initErr
		return
	}

	// set the status of the first page first
	t.firstPage.pageStatus = pageStatusComitted

	// Set the transaction number of the first page and increase the transactionCounter of the wal
	t.firstPage.transactionNumber = atomic.AddUint64(&t.wal.atomicNextTxnNum, 1) - 1

	// calculate the checksum
	t.firstPage.transactionChecksum = t.checksum()

	// Finalize the commit by writing the first page with the updated status if
	// there have been no errors so far.
	if t.wal.deps.disrupt("CommitFail") {
		// Disk failure causes the commit to fail
		done <- errors.New("Write failed on purpose")
		return
	}
	if _, err := t.wal.logFile.WriteAt(t.firstPage.appendTo(nil), int64(t.firstPage.offset)); err != nil {
		done <- build.ExtendErr("Writing the first page failed", err)
		return
	}

	t.commitComplete = true
	t.wal.fSync()
}

// marshalUpdates marshals the updates of a transaction
func marshalUpdates(updates []Update) ([]byte, error) {
	buffer := new(bytes.Buffer)

	for _, update := range updates {
		// Marshal name
		name := []byte(update.Name)
		err1 := binary.Write(buffer, binary.LittleEndian, uint64(len(name)))
		_, err2 := buffer.Write(name)

		// Marshal version
		version := []byte(update.Version)
		err3 := binary.Write(buffer, binary.LittleEndian, uint64(len(version)))
		_, err4 := buffer.Write(version)

		// Append instructions
		err5 := binary.Write(buffer, binary.LittleEndian, uint64(len(update.Instructions)))
		_, err6 := buffer.Write(update.Instructions)

		if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil {
			return nil, errors.Compose(errors.New("Failed to marshal updates"), err1, err2, err3, err4, err5, err6)
		}
	}

	return buffer.Bytes(), nil
}

// unmarshalUpdates unmarshals the updates of a transaction
func unmarshalUpdates(data []byte) ([]Update, error) {
	buffer := bytes.NewBuffer(data)
	updates := make([]Update, 0)

	for {
		update := Update{}

		// Unmarshal name
		var nameLength uint64
		err1 := binary.Read(buffer, binary.LittleEndian, &nameLength)
		if err1 == io.EOF {
			// End of buffer reached
			break
		}

		name := make([]byte, nameLength)
		_, err2 := buffer.Read(name)

		// Unmarshal version
		var versionLength uint64
		err3 := binary.Read(buffer, binary.LittleEndian, &versionLength)

		version := make([]byte, versionLength)
		_, err4 := buffer.Read(version)

		// Unmarshal instructions
		var instructionsLength uint64
		err5 := binary.Read(buffer, binary.LittleEndian, &instructionsLength)

		instructions := make([]byte, instructionsLength)
		_, err6 := buffer.Read(instructions)

		// Check if any errors occured
		if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil {
			return nil, errors.Compose(errors.New("Failed to unmarshal updates"), err1, err2, err3, err4, err5, err6)
		}

		update.Name = string(name)
		update.Version = string(version)
		update.Instructions = instructions

		updates = append(updates, update)
	}

	return updates, nil
}

// threadedInitTransaction reserves pages of the wal, marshalls the
// transactions's updates into a payload and splits the payload equally among
// the pages. Once finished those pages are written to disk and the transaction
// is committed.
func initTransaction(t *Transaction) {
	defer close(t.initComplete)

	// Marshal all the updates to get their total length on disk
	data, err := marshalUpdates(t.Updates)
	if err != nil {
		t.initErr = build.ExtendErr("could not marshal update", err)
		return
	}

	// Get the pages from the wal and set the first page's status
	pages := t.wal.managedReservePages(data)
	pages[0].pageStatus = pageStatusWritten

	// Set the first page of the transaction
	t.firstPage = &pages[0]

	// write the pages to disk
	if err := t.writeToFile(); err != nil {
		t.initErr = build.ExtendErr("Couldn't write the page to file", err)
		return
	}
}

// validateChecksum checks if a transaction has been corrupted by computing a hash
// and comparing it to the one in the firstPage of the transaction
func (t Transaction) validateChecksum() error {
	if t.firstPage == nil {
		return errors.New("firstPage is nil")
	} else if t.checksum() != t.firstPage.transactionChecksum {
		return errors.New("checksum not valid")
	}
	return nil
}

// SignalUpdatesApplied  informs the WAL that it is safe to free the used pages to reuse them in a new transaction
func (t *Transaction) SignalUpdatesApplied() error {
	if !t.setupComplete || !t.commitComplete || t.releaseComplete {
		return errors.New("misuse of transaction - call each of the signaling methods exactly once, in serial, in order")
	}
	t.releaseComplete = true

	// Set the page status to applied
	t.firstPage.pageStatus = pageStatusApplied

	// Write the page to disk
	var err error
	if t.wal.deps.disrupt("ReleaseFail") {
		// Disk failure causes the commit to fail
		err = errors.New("Write failed on purpose")
	} else {
		_, err = t.wal.logFile.WriteAt(t.firstPage.appendTo(nil), int64(t.firstPage.offset))
	}
	if err != nil {
		return build.ExtendErr("Couldn't write the page to file", err)
	}
	t.wal.fSync()

	// Update the wal's available pages
	t.wal.mu.Lock()
	for page := t.firstPage; page != nil; page = page.nextPage {
		// Append the index of the freed page
		t.wal.availablePages = append(t.wal.availablePages, page.offset)
	}
	t.wal.mu.Unlock()

	// Decrease the number of active transactions
	if atomic.AddInt64(&t.wal.atomicUnfinishedTxns, -1) < 0 {
		panic("Sanity check failed. atomicUnfinishedTxns should never be negative")
	}

	return nil
}

// append is a helper function to append updates to a transaction on which
// SignalSetupComplete hasn't been called yet
func (t *Transaction) append(updates []Update, done chan error) {
	defer close(done)

	// If there is nothing to append we are done
	if len(updates) == 0 {
		return
	}

	// Make sure that the initialization finished
	<-t.initComplete
	if t.initErr != nil {
		done <- t.initErr
		return
	}

	// Marshal the data
	data, err := marshalUpdates(updates)
	if err != nil {
		done <- errors.Extend(errors.New("failed to marshal new updates"), err)
		return
	}

	// Find last page to which we append and count the pages
	lastPage := t.firstPage
	for lastPage.nextPage != nil {
		lastPage = lastPage.nextPage
	}

	// Write as much data to the last page as possible
	lenDiff := maxPayloadSize - len(lastPage.payload)
	if len(data) <= lenDiff {
		lastPage.payload = append(lastPage.payload, data...)
		data = nil
	} else {
		lastPage.payload = append(lastPage.payload, data[:lenDiff]...)
		data = data[lenDiff:]
	}

	// If there is no more data to write we are done
	if data == nil {
		return
	}

	// Get enough pages for the remaining data
	pages := t.wal.managedReservePages(data)
	lastPage.nextPage = &pages[0]

	// Write the new pages to disk and sync them
	buf := make([]byte, pageSize)
	for _, page := range pages {
		b := page.appendTo(buf[:0])
		if _, err := t.wal.logFile.WriteAt(b, int64(page.offset)); err != nil {
			done <- build.ExtendErr("Writing the page to disk failed", err)
			return
		}
	}
	t.wal.fSync()

	// Link the new pages to the last one and sync the last page
	b := lastPage.appendTo(buf[:0])
	if _, err := t.wal.logFile.WriteAt(b, int64(lastPage.offset)); err != nil {
		done <- build.ExtendErr("Writing the last page to disk failed", err)
		return
	}
	t.wal.fSync()

	// Append the updates to the transaction
	t.Updates = append(t.Updates, updates...)
}

// Append appends additional updates to a transaction
func (t *Transaction) Append(updates []Update) <-chan error {
	done := make(chan error, 1)

	if t.setupComplete || t.commitComplete || t.releaseComplete {
		done <- errors.New("misuse of trnasaction - can't append to transaction once it is committed/released")
		return done
	}

	go t.append(updates, done)
	return done
}

// SignalSetupComplete will signal to the WAL that any required setup has
// completed, and that the WAL can safely commit to the transaction being
// applied atomically.
func (t *Transaction) SignalSetupComplete() <-chan error {
	done := make(chan error, 1)

	if t.setupComplete || t.commitComplete || t.releaseComplete {
		done <- errors.New("misuse of transaction - call each of the signaling methods exactly ones, in serial, in order")
		return done
	}
	t.setupComplete = true

	// Commit the transaction non-blocking
	go t.commit(done)
	return done
}

// NewTransaction creates a transaction from a set of updates
func (w *WAL) NewTransaction(updates []Update) (*Transaction, error) {
	if !w.recoveryComplete {
		return nil, errors.New("can't call NewTransaction before recovery is complete")
	}
	// Check that there are updates for the transaction to process.
	if len(updates) == 0 {
		return nil, errors.New("cannot create a transaction without updates")
	}

	// Create new transaction
	newTransaction := Transaction{
		Updates:      updates,
		wal:          w,
		initComplete: make(chan struct{}),
	}

	// Initialize the transaction by splitting up the payload among free pages
	// and writing them to disk.
	go initTransaction(&newTransaction)

	// Increase the number of active transaction
	atomic.AddInt64(&w.atomicUnfinishedTxns, 1)

	return &newTransaction, nil
}

// writeToFile writes all the pages of the transaction to disk
func (t *Transaction) writeToFile() error {
	buf := make([]byte, pageSize)
	for page := t.firstPage; page != nil; page = page.nextPage {
		b := page.appendTo(buf[:0])
		if _, err := t.wal.logFile.WriteAt(b, int64(page.offset)); err != nil {
			return build.ExtendErr("Writing the page to disk failed", err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package sfxproto

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestDataPoint(t *testing.T) {
	Convey("Testing DataPoint", t, func() {
		Convey("massage key should work", func() {
			So(massageKey("hello"), ShouldEqual, "hello")
			So(massageKey(".hello:bob1_&"), ShouldEqual, "_hello_bob1__")
		})

		Convey("setting values should work", func() {
		})
	})
}
<commit_msg>remove dead code<commit_after>package sfxproto

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestDataPoint(t *testing.T) {
	Convey("Testing DataPoint", t, func() {
		Convey("massage key should work", func() {
			So(massageKey("hello"), ShouldEqual, "hello")
			So(massageKey(".hello:bob1_&"), ShouldEqual, "_hello_bob1__")
		})
	})
}
<|endoftext|>


<commit_before>package service

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/coreos/go-etcd/etcd"
)

const (
	HEARTBEAT_DURATION = 5
)

func Register(service string, host *Host, stop chan bool) (chan struct{}, error) {
	if len(host.Name) == 0 {
		host.Name = hostname
	}

	registered := make(chan struct{}, 1)
	key := fmt.Sprintf("/services/%s/%s", service, host.Name)
	hostJson, _ := json.Marshal(&host)
	value := string(hostJson)

	go func() {
		ticker := time.NewTicker((HEARTBEAT_DURATION - 1) * time.Second)
		Client().Set(key, value, HEARTBEAT_DURATION)
		registered <- struct{}{}
		for {
			select {
			case <-stop:
				_, err := Client().Delete(key, false)
				if err != nil {
					logger.Println("fail to remove key", key)
				}
				ticker.Stop()
				return
			case <-ticker.C:
				_, err := Client().Set(key, value, HEARTBEAT_DURATION)
				// If for any random reason, there is an error,
				// we retry every second until it's ok.
				for err != nil {
					errEtcd := err.(*etcd.EtcdError)
					logger.Printf("lost registration of '%v': %v (%v)", service, errEtcd.Message, Client().GetCluster())
					time.Sleep(1 * time.Second)
					_, err = Client().Set(key, value, HEARTBEAT_DURATION)
					if err == nil {
						logger.Printf("recover registration of '%v'", service)
					}
				}
			}
		}
	}()

	return registered, nil
}
<commit_msg>chan bool -> chan struct{} to stop<commit_after>package service

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/coreos/go-etcd/etcd"
)

const (
	HEARTBEAT_DURATION = 5
)

func Register(service string, host *Host, stop chan struct{}) (chan struct{}, error) {
	if len(host.Name) == 0 {
		host.Name = hostname
	}

	registered := make(chan struct{}, 1)
	key := fmt.Sprintf("/services/%s/%s", service, host.Name)
	hostJson, _ := json.Marshal(&host)
	value := string(hostJson)

	go func() {
		ticker := time.NewTicker((HEARTBEAT_DURATION - 1) * time.Second)
		Client().Set(key, value, HEARTBEAT_DURATION)
		registered <- struct{}{}
		for {
			select {
			case <-stop:
				_, err := Client().Delete(key, false)
				if err != nil {
					logger.Println("fail to remove key", key)
				}
				ticker.Stop()
				return
			case <-ticker.C:
				_, err := Client().Set(key, value, HEARTBEAT_DURATION)
				// If for any random reason, there is an error,
				// we retry every second until it's ok.
				for err != nil {
					errEtcd := err.(*etcd.EtcdError)
					logger.Printf("lost registration of '%v': %v (%v)", service, errEtcd.Message, Client().GetCluster())
					time.Sleep(1 * time.Second)
					_, err = Client().Set(key, value, HEARTBEAT_DURATION)
					if err == nil {
						logger.Printf("recover registration of '%v'", service)
					}
				}
			}
		}
	}()

	return registered, nil
}
<|endoftext|>


<commit_before>package predicate

import "testing"

func TestTrue(t *testing.T) {
	if !True().P(nil) {
		t.Fail()
	}
}
<commit_msg>Added TestFalse<commit_after>package predicate

import "testing"

func TestTrue(t *testing.T) {
	if !True().P(nil) {
		t.Fail()
	}
}

func TestFalse(t *testing.T) {
	if False().P(nil) {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"testing"
)

func assert(t *testing.T, actual, expected interface{}, msg string) {
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("%s\nactual: %#v\nexpected: %#v", msg, actual, expected)
	}
}

func TestProcessorGet(t *testing.T) {
	in := map[string]interface{}{"foo": "bar"}

	out, err := processor.Get(in, "foo")

	if err != nil {
		t.Fatal(err)
	}

	assert(t, out, "bar", "get")
}

func TestProcessorSelect(t *testing.T) {
	in := []interface{}{
		map[string]interface{}{"key1": "1-1", "key2": "2-1", "key3": "3-1"},
		map[string]interface{}{"key1": "1-2", "key2": "2-2", "key3": "3-2"},
		map[string]interface{}{"key1": "1-3", "key2": "2-3"},
	}

	out, err := processor.Select(in, "key1", "key3")

	if err != nil {
		t.Fatal(err)
	}

	expected := JsonCollection{
		JsonObject{"key1": "1-1", "key3": "3-1"},
		JsonObject{"key1": "1-2", "key3": "3-2"},
		JsonObject{"key1": "1-3"},
	}

	assert(t, out, expected, "select")
}

func TestProcessorReject(t *testing.T) {
	in := []interface{}{
		map[string]interface{}{"key1": "1-1", "key2": "2-1", "key3": "3-1"},
		map[string]interface{}{"key1": "1-2", "key2": "2-2", "key3": "3-2"},
		map[string]interface{}{"key1": "1-3", "key2": "2-3"},
	}

	out, err := processor.Reject(in, "key1", "key3")

	if err != nil {
		t.Fatal(err)
	}

	expected := JsonCollection{
		JsonObject{"key2": "2-1"},
		JsonObject{"key2": "2-2"},
		JsonObject{"key2": "2-3"},
	}

	assert(t, out, expected, "reject")
}

func TestProcessorSlice(t *testing.T) {
	test := func(in []interface{}, start, length int, expected JsonArray, msg string) {
		out, err := processor.Slice(in, start, length)
		if err != nil {
			t.Fatal(err)
		}
		assert(t, out, expected, msg)
	}

	test([]interface{}{1, 2, 3, 4, 5}, 0, 2, JsonArray{1, 2}, "slice-1")
	test([]interface{}{1, 2, 3, 4, 5}, 2, 2, JsonArray{3, 4}, "slice-2")
	test([]interface{}{1, 2, 3, 4, 5}, 3, 10, JsonArray{4, 5}, "slice-3")
	test([]interface{}{1, 2, 3, 4, 5}, 3, 0, JsonArray{}, "slice-3")
	test([]interface{}{1, 2, 3, 4, 5}, 10, 10, JsonArray{}, "slice-4")
}

func TestProcessorhead(t *testing.T) {
	test := func(in []interface{}, length int, expected JsonArray, msg string) {
		out, err := processor.Head(in, length)
		if err != nil {
			t.Fatal(err)
		}
		assert(t, out, expected, msg)
	}

	test([]interface{}{1, 2, 3, 4, 5}, 0, JsonArray{}, "head-1")
	test([]interface{}{1, 2, 3, 4, 5}, 2, JsonArray{1, 2}, "head-2")
	test([]interface{}{1, 2, 3, 4, 5}, 5, JsonArray{1, 2, 3, 4, 5}, "head-3")
	test([]interface{}{1, 2, 3, 4, 5}, 10, JsonArray{1, 2, 3, 4, 5}, "head-4")
}

func TestProcessorTail(t *testing.T) {
	test := func(in []interface{}, length int, expected JsonArray, msg string) {
		out, err := processor.Tail(in, length)
		if err != nil {
			t.Fatal(err)
		}
		assert(t, out, expected, msg)
	}

	test([]interface{}{1, 2, 3, 4, 5}, 0, JsonArray{}, "tail-4")
	test([]interface{}{1, 2, 3, 4, 5}, 2, JsonArray{4, 5}, "tail-1")
	test([]interface{}{1, 2, 3, 4, 5}, 5, JsonArray{1, 2, 3, 4, 5}, "tail-2")
	test([]interface{}{1, 2, 3, 4, 5}, 10, JsonArray{1, 2, 3, 4, 5}, "tail-3")
}
<commit_msg>Change test function name<commit_after>package main

import (
	"reflect"
	"testing"
)

func assert(t *testing.T, actual, expected interface{}, msg string) {
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("%s\nactual: %#v\nexpected: %#v", msg, actual, expected)
	}
}

func TestProcessorGet(t *testing.T) {
	in := map[string]interface{}{"foo": "bar"}

	out, err := processor.Get(in, "foo")

	if err != nil {
		t.Fatal(err)
	}

	assert(t, out, "bar", "get")
}

func TestProcessorSelect(t *testing.T) {
	in := []interface{}{
		map[string]interface{}{"key1": "1-1", "key2": "2-1", "key3": "3-1"},
		map[string]interface{}{"key1": "1-2", "key2": "2-2", "key3": "3-2"},
		map[string]interface{}{"key1": "1-3", "key2": "2-3"},
	}

	out, err := processor.Select(in, "key1", "key3")

	if err != nil {
		t.Fatal(err)
	}

	expected := JsonCollection{
		JsonObject{"key1": "1-1", "key3": "3-1"},
		JsonObject{"key1": "1-2", "key3": "3-2"},
		JsonObject{"key1": "1-3"},
	}

	assert(t, out, expected, "select")
}

func TestProcessorReject(t *testing.T) {
	in := []interface{}{
		map[string]interface{}{"key1": "1-1", "key2": "2-1", "key3": "3-1"},
		map[string]interface{}{"key1": "1-2", "key2": "2-2", "key3": "3-2"},
		map[string]interface{}{"key1": "1-3", "key2": "2-3"},
	}

	out, err := processor.Reject(in, "key1", "key3")

	if err != nil {
		t.Fatal(err)
	}

	expected := JsonCollection{
		JsonObject{"key2": "2-1"},
		JsonObject{"key2": "2-2"},
		JsonObject{"key2": "2-3"},
	}

	assert(t, out, expected, "reject")
}

func TestProcessorSlice(t *testing.T) {
	test := func(in []interface{}, start, length int, expected JsonArray, msg string) {
		out, err := processor.Slice(in, start, length)
		if err != nil {
			t.Fatal(err)
		}
		assert(t, out, expected, msg)
	}

	test([]interface{}{1, 2, 3, 4, 5}, 0, 2, JsonArray{1, 2}, "slice-1")
	test([]interface{}{1, 2, 3, 4, 5}, 2, 2, JsonArray{3, 4}, "slice-2")
	test([]interface{}{1, 2, 3, 4, 5}, 3, 10, JsonArray{4, 5}, "slice-3")
	test([]interface{}{1, 2, 3, 4, 5}, 3, 0, JsonArray{}, "slice-3")
	test([]interface{}{1, 2, 3, 4, 5}, 10, 10, JsonArray{}, "slice-4")
}

func TestProcessorHead(t *testing.T) {
	test := func(in []interface{}, length int, expected JsonArray, msg string) {
		out, err := processor.Head(in, length)
		if err != nil {
			t.Fatal(err)
		}
		assert(t, out, expected, msg)
	}

	test([]interface{}{1, 2, 3, 4, 5}, 0, JsonArray{}, "head-1")
	test([]interface{}{1, 2, 3, 4, 5}, 2, JsonArray{1, 2}, "head-2")
	test([]interface{}{1, 2, 3, 4, 5}, 5, JsonArray{1, 2, 3, 4, 5}, "head-3")
	test([]interface{}{1, 2, 3, 4, 5}, 10, JsonArray{1, 2, 3, 4, 5}, "head-4")
}

func TestProcessorTail(t *testing.T) {
	test := func(in []interface{}, length int, expected JsonArray, msg string) {
		out, err := processor.Tail(in, length)
		if err != nil {
			t.Fatal(err)
		}
		assert(t, out, expected, msg)
	}

	test([]interface{}{1, 2, 3, 4, 5}, 0, JsonArray{}, "tail-4")
	test([]interface{}{1, 2, 3, 4, 5}, 2, JsonArray{4, 5}, "tail-1")
	test([]interface{}{1, 2, 3, 4, 5}, 5, JsonArray{1, 2, 3, 4, 5}, "tail-2")
	test([]interface{}{1, 2, 3, 4, 5}, 10, JsonArray{1, 2, 3, 4, 5}, "tail-3")
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package exch

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"time"

	"github.com/lunixbochs/struc"

	"my/errs"

	"my/itto/verify/exch/sbtcp"
)

type ExchangeSimulator interface {
	Run()
}

func NewExchangeSimulatorServer() ExchangeSimulator {
	return &exchange{
		glimpse: &glimpseServer{laddr: ":16001"},
		replay:  &replayServer{laddr: ":17001"},
		//mcast:   &mcastServer{laddr: "10.1.0.11:0", raddr: "233.54.12.1:18001"},
		mcast: &mcastServer{laddr: "10.2.0.5:0", raddr: "233.54.12.1:18001"},
	}
}

type exchange struct {
	glimpse *glimpseServer
	replay  *replayServer
	mcast   *mcastServer
}

func (e *exchange) Run() {
	go e.glimpse.run()
	go e.replay.run()
	go e.mcast.run()
	go log.Println("started")
	select {}
}

type glimpseServer struct {
	laddr string
}

func (s *glimpseServer) run() {
	l, err := net.Listen("tcp", s.laddr)
	errs.CheckE(err)
	defer l.Close()
	for {
		conn, err := l.Accept()
		errs.CheckE(err)
		log.Printf("accepted %s -> %s \n", conn.RemoteAddr(), conn.LocalAddr())
		go s.handleClient(conn)
	}
}

func (s *glimpseServer) handleClient(conn net.Conn) {
	defer conn.Close()
	m, err := sbtcp.ReadMessage(conn)
	errs.CheckE(err)
	log.Printf("got %#v\n", m)
	lr := m.(*sbtcp.MessageLoginRequest)
	errs.Check(lr != nil)

	la := sbtcp.MessageLoginAccepted{
		Session:        "00TestSess",
		SequenceNumber: 1,
	}
	errs.CheckE(sbtcp.WriteMessage(conn, &la))
	log.Printf("glimpse send: %v\n", la)

	seqNum := 5
	snap := fmt.Sprintf("M%020d", seqNum)
	sd := sbtcp.MessageSequencedData{}
	sd.SetPayload([]byte(snap))
	errs.CheckE(sbtcp.WriteMessage(conn, &sd))
	log.Printf("glimpse send: %v\n", sd)
}

type replayServer struct {
	laddr string
}

func (s *replayServer) run() {
	type moldudp64request struct {
		Session        string
		SequenceNumber uint64
		MessageCount   uint16
	}

	laddr, err := net.ResolveUDPAddr("udp", s.laddr)
	errs.CheckE(err)
	conn, err := net.ListenUDP("udp", laddr)
	errs.CheckE(err)
	defer conn.Close()
	buf := make([]byte, 20, 65536)
	for {
		n, addr, err := conn.ReadFromUDP(buf)
		errs.CheckE(err)
		if n != 20 {
			log.Printf("ignore wrong request from %s: %v\n", addr, buf)
			continue
		}
		req := &moldudp64request{
			Session:        string(buf[0:10]),
			SequenceNumber: binary.BigEndian.Uint64(buf[10:18]),
			MessageCount:   binary.BigEndian.Uint16(buf[18:20]),
		}
		go func() {
			const MAX_MESSAGES = (1500 - 34 - 20) / 28
			log.Printf("got request: %v\n", req)
			//num := int(req.SequenceNumber) - 10
			num := int(req.MessageCount)
			if num <= 0 {
				num = 1
			} else if num > MAX_MESSAGES {
				num = MAX_MESSAGES
			}
			resp := createPacket(int(req.SequenceNumber), num)
			errs.Check(len(resp) < 1500-34)

			const SLEEP_ENABLED = true
			if SLEEP_ENABLED {
				sleep := time.Duration(250+2500/num) * time.Millisecond
				log.Printf("sleeping for %s\n", sleep)
				time.Sleep(sleep)
			}
			log.Printf("send response: %v\n", resp)
			n, err = conn.WriteToUDP(resp, addr)
			errs.CheckE(err)
			errs.Check(n == len(resp), n, len(resp))
		}()
	}
}

type mcastServer struct {
	laddr string
	raddr string
}

func (s *mcastServer) run() {
	const MCAST_PPS = 1
	laddr, err := net.ResolveUDPAddr("udp", s.laddr)
	errs.CheckE(err)
	raddr, err := net.ResolveUDPAddr("udp", s.raddr)
	errs.CheckE(err)
	conn, err := net.DialUDP("udp", laddr, raddr)
	seq := 1000
	for {
		p := createPacket(seq, 1)
		log.Printf("send mcast: %v\n", p)
		n, err := conn.Write(p)
		errs.CheckE(err)
		errs.Check(n == len(p), n, len(p))

		delay := time.Duration(1000/MCAST_PPS) * time.Millisecond
		time.Sleep(delay)
		seq++
		/*
			if seq > 30 {
				seq = 1
			}
		*/
	}
	defer conn.Close()
}

func createPacket(startSeqNum, count int) []byte {
	type moldUDP64 struct {
		Session        string `struc:"[10]byte"`
		SequenceNumber uint64
		MessageCount   uint16
	}
	type ittoMessageOptionsTrade struct {
		Type      byte
		Timestamp uint32
		Side      byte
		OId       uint32
		Cross     uint32
		Match     uint32
		Price     uint32
		Size      uint32
	}
	type moldUDP64MessageBlock struct {
		MessageLength uint16 //`struc:"sizeof=Payload"`
		Payload       ittoMessageOptionsTrade
	}

	errs.Check(startSeqNum >= 0)
	errs.Check(count >= 0 && count < 1000)
	mh := moldUDP64{
		Session:        "00TestSess",
		SequenceNumber: uint64(startSeqNum),
		MessageCount:   uint16(count),
	}
	var bb bytes.Buffer
	errs.CheckE(struc.Pack(&bb, &mh))
	for i := 0; i < count; i++ {
		mb := moldUDP64MessageBlock{
			MessageLength: 26,
			Payload: ittoMessageOptionsTrade{
				Type: 'P',
			},
		}
		errs.CheckE(struc.Pack(&bb, &mb))
	}
	return bb.Bytes()
}
<commit_msg>exch: more realistic behavior<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package exch

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"time"

	"github.com/lunixbochs/struc"

	"my/errs"

	"my/itto/verify/exch/sbtcp"
)

type ExchangeSimulator interface {
	Run()
}

func NewExchangeSimulatorServer() ExchangeSimulator {
	return &exchange{
		glimpse: &glimpseServer{
			laddr:          ":16001",
			snapshotSeqNum: 5,
		},
		replay: &replayServer{
			laddr:        ":17001",
			sleepEnabled: true,
		},
		mcast: &mcastServer{
			laddr: "10.2.0.5:0",
			raddr: "233.54.12.1:18001",
			seq:   1000,
			pps:   1,
		},
	}
}

type exchange struct {
	glimpse *glimpseServer
	replay  *replayServer
	mcast   *mcastServer
}

func (e *exchange) Run() {
	go e.glimpse.run()
	go e.replay.run()
	go e.mcast.run()
	go log.Println("started")
	select {}
}

type glimpseServer struct {
	laddr          string
	snapshotSeqNum int
}

func (s *glimpseServer) run() {
	l, err := net.Listen("tcp", s.laddr)
	errs.CheckE(err)
	defer l.Close()
	for {
		conn, err := l.Accept()
		errs.CheckE(err)
		log.Printf("accepted %s -> %s \n", conn.RemoteAddr(), conn.LocalAddr())
		go s.handleClient(conn)
	}
}
func (s *glimpseServer) handleClient(conn net.Conn) {
	defer conn.Close()
	m, err := sbtcp.ReadMessage(conn)
	errs.CheckE(err)
	log.Printf("got %#v\n", m)
	lr := m.(*sbtcp.MessageLoginRequest)
	errs.Check(lr != nil)

	la := sbtcp.MessageLoginAccepted{
		Session:        "00TestSess",
		SequenceNumber: 1,
	}
	errs.CheckE(sbtcp.WriteMessage(conn, &la))
	log.Printf("glimpse send: %v\n", la)

	for i := 0; i < s.snapshotSeqNum; i++ {
		s.sendSeqData(conn, generateIttoMessage(i))
	}
	snap := fmt.Sprintf("M%020d", s.snapshotSeqNum)
	s.sendSeqData(conn, []byte(snap))
}
func (s *glimpseServer) sendSeqData(conn net.Conn, data []byte) {
	sd := sbtcp.MessageSequencedData{}
	sd.SetPayload(data)
	errs.CheckE(sbtcp.WriteMessage(conn, &sd))
	log.Printf("glimpse send: %v\n", sd)
}

type replayServer struct {
	laddr        string
	sleepEnabled bool
}

func (s *replayServer) run() {
	type moldudp64request struct {
		Session        string
		SequenceNumber uint64
		MessageCount   uint16
	}

	laddr, err := net.ResolveUDPAddr("udp", s.laddr)
	errs.CheckE(err)
	conn, err := net.ListenUDP("udp", laddr)
	errs.CheckE(err)
	defer conn.Close()
	buf := make([]byte, 20, 65536)
	for {
		n, addr, err := conn.ReadFromUDP(buf)
		errs.CheckE(err)
		if n != 20 {
			log.Printf("ignore wrong request from %s: %v\n", addr, buf)
			continue
		}
		req := &moldudp64request{
			Session:        string(buf[0:10]),
			SequenceNumber: binary.BigEndian.Uint64(buf[10:18]),
			MessageCount:   binary.BigEndian.Uint16(buf[18:20]),
		}
		go func() {
			const MAX_MESSAGES = (1500 - 34 - 20) / 40
			log.Printf("got request: %v\n", req)
			//num := int(req.SequenceNumber) - 10
			num := int(req.MessageCount)
			if num <= 0 {
				num = 1
			} else if num > MAX_MESSAGES {
				num = MAX_MESSAGES
			}
			resp := createMoldPacket(int(req.SequenceNumber), num)
			errs.Check(len(resp) < 1500-34)

			if s.sleepEnabled {
				sleep := time.Duration(250+2500/num) * time.Millisecond
				log.Printf("sleeping for %s\n", sleep)
				time.Sleep(sleep)
			}
			log.Printf("send response: %v\n", resp)
			n, err = conn.WriteToUDP(resp, addr)
			errs.CheckE(err)
			errs.Check(n == len(resp), n, len(resp))
		}()
	}
}

type mcastServer struct {
	laddr string
	raddr string
	seq   int
	pps   int
}

func (s *mcastServer) run() {
	errs.Check(s.pps != 0)
	laddr, err := net.ResolveUDPAddr("udp", s.laddr)
	errs.CheckE(err)
	raddr, err := net.ResolveUDPAddr("udp", s.raddr)
	errs.CheckE(err)
	conn, err := net.DialUDP("udp", laddr, raddr)
	for {
		p := createMoldPacket(s.seq, 1)
		log.Printf("send mcast: %v\n", p)
		n, err := conn.Write(p)
		errs.CheckE(err)
		errs.Check(n == len(p), n, len(p))

		delay := time.Duration(1000/s.pps) * time.Millisecond
		time.Sleep(delay)
		s.seq++
	}
	defer conn.Close()
}

func createMoldPacket(startSeqNum, count int) []byte {
	type moldUDP64 struct {
		Session        string `struc:"[10]byte"`
		SequenceNumber uint64
		MessageCount   uint16
	}
	type moldUDP64MessageBlock struct {
		MessageLength int16 `struc:"sizeof=Payload"`
		Payload       []uint8
	}

	errs.Check(startSeqNum >= 0)
	errs.Check(count >= 0 && count < 1000)
	mh := moldUDP64{
		Session:        "00TestSess",
		SequenceNumber: uint64(startSeqNum),
		MessageCount:   uint16(count),
	}
	var bb bytes.Buffer
	errs.CheckE(struc.Pack(&bb, &mh))
	for i := 0; i < count; i++ {
		mb := moldUDP64MessageBlock{
			Payload: generateIttoMessage(startSeqNum + i),
		}
		errs.CheckE(struc.Pack(&bb, &mb))
	}
	return bb.Bytes()
}

func generateIttoMessage(seqNum int) []byte {
	type ittoMessageOptionsTrade struct {
		Type      byte
		Timestamp uint32
		Side      byte
		OId       uint32
		Cross     uint32
		Match     uint32
		Price     uint32
		Size      uint32
	}
	type ittoMessageOptionDirectory struct {
		Type             byte
		Timestamp        uint32
		OId              uint32
		Symbol           [6]byte
		ExpirationYear   byte
		ExpirationMonth  byte
		ExpirationDay    byte
		StrikePrice      uint32
		OType            byte
		Source           uint8
		UnderlyingSymbol [13]byte
		ClosingType      byte
		Tradable         byte
		MPV              byte
	}
	type ittoMessageAddOrder struct {
		Type      byte
		Timestamp uint32
		RefNumD   uint32
		Side      byte
		OId       uint32
		Price     uint32
		Size      uint32
	}

	errs.Check(seqNum >= 0)
	var bb bytes.Buffer
	switch seqNum % 3 {
	case 0:
		m := ittoMessageOptionDirectory{
			Type: 'R',
			OId:  uint32(seqNum / 3),
		}
		errs.CheckE(struc.Pack(&bb, &m))
	case 1:
		m := ittoMessageOptionsTrade{
			Type: 'P',
			OId:  uint32(seqNum / 3),
		}
		errs.CheckE(struc.Pack(&bb, &m))
	case 2:
		m := ittoMessageAddOrder{
			Type:    'A',
			RefNumD: uint32(seqNum),
			Side:    'B',
			OId:     uint32(seqNum/9) + 0x10000,
			Price:   uint32(seqNum % 10 * 1000),
			Size:    uint32(seqNum % 10),
		}
		errs.CheckE(struc.Pack(&bb, &m))
	}
	return bb.Bytes()
}
<|endoftext|>