<commit_before>package contractor

import (
	"path/filepath"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/consensus"
	"github.com/NebulousLabs/Sia/modules/gateway"
	"github.com/NebulousLabs/Sia/modules/host"
	"github.com/NebulousLabs/Sia/modules/miner"
	"github.com/NebulousLabs/Sia/modules/renter/hostdb"
	"github.com/NebulousLabs/Sia/modules/transactionpool"
	modWallet "github.com/NebulousLabs/Sia/modules/wallet"
	"github.com/NebulousLabs/Sia/types"
)

// newTestingWallet is a helper function that creates a ready-to-use wallet
// and mines some coins into it.
func newTestingWallet(testdir string, cs modules.ConsensusSet, tp modules.TransactionPool) (modules.Wallet, error) {
	w, err := modWallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
	if err != nil {
		return nil, err
	}
	key, err := crypto.GenerateTwofishKey()
	if err != nil {
		return nil, err
	}
	if !w.Encrypted() {
		_, err = w.Encrypt(key)
		if err != nil {
			return nil, err
		}
	}
	err = w.Unlock(key)
	if err != nil {
		return nil, err
	}
	// give it some money
	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
	if err != nil {
		return nil, err
	}
	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
		_, err := m.AddBlock()
		if err != nil {
			return nil, err
		}
	}
	return w, nil
}

// newTestingHost is a helper function that creates a ready-to-use host.
func newTestingHost(testdir string, cs modules.ConsensusSet, tp modules.TransactionPool) (modules.Host, error) {
	w, err := newTestingWallet(testdir, cs, tp)
	if err != nil {
		return nil, err
	}
	return host.New(cs, tp, w, "localhost:0", filepath.Join(testdir, modules.HostDir))
}

// newTestingContractor is a helper function that creates a ready-to-use
// contractor.
func newTestingContractor(testdir string, cs modules.ConsensusSet, tp modules.TransactionPool) (*Contractor, error) {
	w, err := newTestingWallet(testdir, cs, tp)
	if err != nil {
		return nil, err
	}
	hdb, err := hostdb.New(cs, filepath.Join(testdir, "hostdb"))
	if err != nil {
		return nil, err
	}
	return New(cs, w, tp, hdb, filepath.Join(testdir, "contractor"))
}

// newTestingTrio creates a Host, Contractor, and TestMiner that can be used
// for testing host/renter interactions.
func newTestingTrio(name string) (modules.Host, *Contractor, modules.TestMiner, error) {
	testdir := build.TempDir("contractor", name)

	// create miner
	g, err := gateway.New("localhost:0", filepath.Join(testdir, modules.GatewayDir))
	if err != nil {
		return nil, nil, nil, err
	}
	cs, err := consensus.New(g, filepath.Join(testdir, modules.ConsensusDir))
	if err != nil {
		return nil, nil, nil, err
	}
	tp, err := transactionpool.New(cs, g)
	if err != nil {
		return nil, nil, nil, err
	}
	w, err := modWallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
	if err != nil {
		return nil, nil, nil, err
	}
	key, err := crypto.GenerateTwofishKey()
	if err != nil {
		return nil, nil, nil, err
	}
	if !w.Encrypted() {
		_, err = w.Encrypt(key)
		if err != nil {
			return nil, nil, nil, err
		}
	}
	err = w.Unlock(key)
	if err != nil {
		return nil, nil, nil, err
	}
	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
	if err != nil {
		return nil, nil, nil, err
	}

	// create host and contractor, using same consensus set and gateway
	h, err := newTestingHost(filepath.Join(testdir, "Host"), cs, tp)
	if err != nil {
		return nil, nil, nil, err
	}
	c, err := newTestingContractor(filepath.Join(testdir, "Contractor"), cs, tp)
	if err != nil {
		return nil, nil, nil, err
	}

	return h, c, m, nil
}

// TestIntegrationFormContract tests that the contractor can form contracts
// with the host module.
func TestIntegrationFormContract(t *testing.T) {
	// create host+contractor+miner
	h, c, m, err := newTestingTrio("TestIngrationFormContract")
	if err != nil {
		t.Fatal(err)
	}

	// Configure host to accept contracts
	settings := h.InternalSettings()
	settings.AcceptingContracts = true
	err = h.SetInternalSettings(settings)
	if err != nil {
		t.Fatal(err)
	}

	// announce the host
	err = h.Announce()
	if err != nil {
		t.Fatal(err)
	}

	// mine a block, processing the announcement
	m.AddBlock()

	// wait for hostdb to scan host
	for i := 0; i < 500 && len(c.hdb.RandomHosts(1, nil)) == 0; i++ {
		time.Sleep(time.Millisecond)
	}

	// get the host's entry from the db
	hostEntry, ok := c.hdb.Host(h.NetAddress())
	if !ok {
		t.Fatal("no entry for host in db")
	}

	// form a contract with the host
	contract, err := c.newContract(hostEntry, 64000, c.blockHeight+100)
	if err != nil {
		t.Fatal(err)
	}

	if contract.IP != h.NetAddress() {
		t.Fatal("bad contract")
	}
}
<commit_msg>add revision integration test<commit_after>package contractor

import (
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/consensus"
	"github.com/NebulousLabs/Sia/modules/gateway"
	"github.com/NebulousLabs/Sia/modules/host"
	"github.com/NebulousLabs/Sia/modules/miner"
	"github.com/NebulousLabs/Sia/modules/renter/hostdb"
	"github.com/NebulousLabs/Sia/modules/transactionpool"
	modWallet "github.com/NebulousLabs/Sia/modules/wallet"
	"github.com/NebulousLabs/Sia/types"
)

// newTestingWallet is a helper function that creates a ready-to-use wallet
// and mines some coins into it.
func newTestingWallet(testdir string, cs modules.ConsensusSet, tp modules.TransactionPool) (modules.Wallet, error) {
	w, err := modWallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
	if err != nil {
		return nil, err
	}
	key, err := crypto.GenerateTwofishKey()
	if err != nil {
		return nil, err
	}
	if !w.Encrypted() {
		_, err = w.Encrypt(key)
		if err != nil {
			return nil, err
		}
	}
	err = w.Unlock(key)
	if err != nil {
		return nil, err
	}
	// give it some money
	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
	if err != nil {
		return nil, err
	}
	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
		_, err := m.AddBlock()
		if err != nil {
			return nil, err
		}
	}
	return w, nil
}

// newTestingHost is a helper function that creates a ready-to-use host.
func newTestingHost(testdir string, cs modules.ConsensusSet, tp modules.TransactionPool) (modules.Host, error) {
	w, err := newTestingWallet(testdir, cs, tp)
	if err != nil {
		return nil, err
	}
	return host.New(cs, tp, w, "localhost:0", filepath.Join(testdir, modules.HostDir))
}

// newTestingContractor is a helper function that creates a ready-to-use
// contractor.
func newTestingContractor(testdir string, cs modules.ConsensusSet, tp modules.TransactionPool) (*Contractor, error) {
	w, err := newTestingWallet(testdir, cs, tp)
	if err != nil {
		return nil, err
	}
	hdb, err := hostdb.New(cs, filepath.Join(testdir, "hostdb"))
	if err != nil {
		return nil, err
	}
	return New(cs, w, tp, hdb, filepath.Join(testdir, "contractor"))
}

// newTestingTrio creates a Host, Contractor, and TestMiner that can be used
// for testing host/renter interactions.
func newTestingTrio(name string) (modules.Host, *Contractor, modules.TestMiner, error) {
	testdir := build.TempDir("contractor", name)

	// create miner
	g, err := gateway.New("localhost:0", filepath.Join(testdir, modules.GatewayDir))
	if err != nil {
		return nil, nil, nil, err
	}
	cs, err := consensus.New(g, filepath.Join(testdir, modules.ConsensusDir))
	if err != nil {
		return nil, nil, nil, err
	}
	tp, err := transactionpool.New(cs, g)
	if err != nil {
		return nil, nil, nil, err
	}
	w, err := modWallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
	if err != nil {
		return nil, nil, nil, err
	}
	key, err := crypto.GenerateTwofishKey()
	if err != nil {
		return nil, nil, nil, err
	}
	if !w.Encrypted() {
		_, err = w.Encrypt(key)
		if err != nil {
			return nil, nil, nil, err
		}
	}
	err = w.Unlock(key)
	if err != nil {
		return nil, nil, nil, err
	}
	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
	if err != nil {
		return nil, nil, nil, err
	}

	// create host and contractor, using same consensus set and gateway
	h, err := newTestingHost(filepath.Join(testdir, "Host"), cs, tp)
	if err != nil {
		return nil, nil, nil, err
	}
	c, err := newTestingContractor(filepath.Join(testdir, "Contractor"), cs, tp)
	if err != nil {
		return nil, nil, nil, err
	}

	// Configure host to accept contracts
	settings := h.InternalSettings()
	settings.AcceptingContracts = true
	err = h.SetInternalSettings(settings)
	if err != nil {
		return nil, nil, nil, err
	}

	// add storage to host
	storageFolder := filepath.Join(build.SiaTestingDir, "contractor", "TestIntegrationReviseContract", "storage")
	err = os.MkdirAll(storageFolder, 0700)
	if err != nil {
		return nil, nil, nil, err
	}
	err = h.AddStorageFolder(storageFolder, 1e6)
	if err != nil {
		return nil, nil, nil, err
	}

	// announce the host
	err = h.Announce()
	if err != nil {
		return nil, nil, nil, err
	}

	// mine a block, processing the announcement
	m.AddBlock()

	// wait for hostdb to scan host
	for i := 0; i < 500 && len(c.hdb.RandomHosts(1, nil)) == 0; i++ {
		time.Sleep(time.Millisecond)
	}

	return h, c, m, nil
}

// TestIntegrationFormContract tests that the contractor can form contracts
// with the host module.
func TestIntegrationFormContract(t *testing.T) {
	h, c, _, err := newTestingTrio("TestIntegrationFormContract")
	if err != nil {
		t.Fatal(err)
	}

	// get the host's entry from the db
	hostEntry, ok := c.hdb.Host(h.NetAddress())
	if !ok {
		t.Fatal("no entry for host in db")
	}

	// form a contract with the host
	contract, err := c.newContract(hostEntry, 64000, c.blockHeight+100)
	if err != nil {
		t.Fatal(err)
	}

	if contract.IP != h.NetAddress() {
		t.Fatal("bad contract")
	}
}

// TestIntegrationReviseContract tests that the contractor can revise a
// contract previously formed with a host.
func TestIntegrationReviseContract(t *testing.T) {
	// create testing trio
	h, c, _, err := newTestingTrio("TestIntegrationReviseContract")
	if err != nil {
		t.Fatal(err)
	}

	// get the host's entry from the db
	hostEntry, ok := c.hdb.Host(h.NetAddress())
	if !ok {
		t.Fatal("no entry for host in db")
	}

	// form a contract with the host
	contract, err := c.newContract(hostEntry, 64000, c.blockHeight+100)
	if err != nil {
		t.Fatal(err)
	}

	// revise the contract
	editor, err := c.Editor(contract)
	if err != nil {
		t.Fatal(err)
	}
	data, err := crypto.RandBytes(int(modules.SectorSize))
	if err != nil {
		t.Fatal(err)
	}
	_, err = editor.Upload(data)
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "math/big"
    "sort"
    "strings"
    "time"
    "unicode"

    "github.com/tooru/pnbot/prime"
    "github.com/dghubble/go-twitter/twitter"
    "github.com/dghubble/oauth1"
//    "github.com/davecgh/go-spew/spew"
)

// 187 Status is a duplicate.
// 185 User is over daily status update limit.

const (
    maxTweetCharactors = 140
    hellipsis = "\u2026"

    queueSize = 10
    maxRetry = 100
    retryInterval = 10 * time.Minute
    interval = 1 * time.Second
)

func main() {
    log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)

    flags := flag.NewFlagSet("pnbot", flag.ExitOnError)

    mode := flags.String("mode", "normal", "Tweet Mode: 'normal'(default), 'twin', 'primep', 'primeptest'")
    target := flags.String("target", "", "tweet target")

    consumerKey := flags.String("ck", "", "Twitter Consumer Key")
    consumerSecret := flags.String("cs", "", "Twitter Consumer Secret")
    accessToken := flags.String("at", "", "Twitter Access Token")
    accessSecret := flags.String("as", "", "Twitter Access Secret")

    debug := flags.Bool("debug", false, "debug mode")

    flags.Parse(os.Args[1:])

    if *consumerKey == "" || *consumerSecret == "" || *accessToken == "" || *accessSecret == "" {
        log.Fatal("Consumer key/secret and Access token/secret required")
    }

    pnbot := NewPNBot(mode, target, *debug,
        consumerKey, consumerSecret, accessToken, accessSecret)
    pnbot.Start()
}

func NewPNBot(mode *string, target *string, debug bool,
              consumerKey *string, consumerSecret *string,
              accessToken *string, accessSecret *string) *PNBot {
    pnbot := &PNBot{
        mode: mode,
        target: target,
        debug: debug,
        consumerKey: consumerKey,
        consumerSecret: consumerSecret,
        accessToken: accessToken,
        accessSecret: accessSecret,
        prime: prime.NewPrime(),
    }

    return pnbot
}

type PNBot struct {
    mode *string
    target *string
    debug bool

    consumerKey *string
    consumerSecret *string
    accessToken *string
    accessSecret *string

    prime *prime.Prime

    client *twitter.Client

}

type PNTweet struct {
    text string
    params *twitter.StatusUpdateParams
}

func (pnbot *PNBot) Start() error {
    pnbot.client = pnbot.newClient()

    switch *pnbot.mode {
    case "normal":
        return pnbot.startNormal()
    case "twin":
        return pnbot.startTwin()
    case "primep":
        return pnbot.startPrimeP()
    case "primeptest":
        return nil
        //return pnbot.startTestPrimeP()
    default:
        return fmt.Errorf("Start: unknown mode: %v", *pnbot.mode)
    }
}

func (pnbot *PNBot) newClient() *twitter.Client {
    config := oauth1.NewConfig(*pnbot.consumerKey, *pnbot.consumerSecret)
    token := oauth1.NewToken(*pnbot.accessToken, *pnbot.accessSecret)
    httpClient := config.Client(oauth1.NoContext, token)

    return twitter.NewClient(httpClient)
}

func (pnbot *PNBot) tweet(tweets chan *PNTweet, quit chan interface{}) error {
    totalN := 0
    totalStart := time.Now()

    contN := 0
    contStart := totalStart

    for {
        var pnTweet *PNTweet

        select {
        case pnTweet = <- tweets:
        case <- quit:
            log.Fatalf("error occurred.")
        }

        retry := 0
        for {
            var err error
            if pnbot.debug {
                log.Printf("Tweet: %s", pnTweet.text)
            } else {
                _, _, err = pnbot.client.Statuses.Update(pnTweet.text, pnTweet.params)
            }
            if err == nil {
                break
            }
            if retry >= maxRetry {
                return fmt.Errorf("Too many tweet error: %v\n", err)
            }
            log.Printf("Tweet error[%d/%d]:sleep=%s: %v\n", retry+1, maxRetry, retryInterval, err)

            time.Sleep(retryInterval)
            pnbot.client = pnbot.newClient()
            retry++
            continue
        }
        now := time.Now()

        if retry > 0 {
            contN = 0
            contStart = now
        }
        contN++
        totalN++

        log.Printf("tweet:%d:%d:%s:sleep=%s:%.2f tw/h: %.2f tw/h\n",
            totalN, contN,
            pnTweet.text,
            interval,
            float64(totalN)/(float64(now.Sub(totalStart))/float64(time.Hour)),
            float64(contN)/(float64(now.Sub(contStart))/float64(time.Hour)))
        time.Sleep(interval)
    }
}

func (pnbot *PNBot) startNormal() error {
    tweet, err := pnbot.lastTweet()
    if err != nil {
        return err
    }
    log.Printf("last tweet: %v", tweet)

    maxPrime := new(big.Int)
    if tweet != "" {
        maxPrime.SetString(tweet, 10)
    } else {
        maxPrime.SetInt64(0)
    }

    primes := make(chan *PNTweet, 10)
    quit := make(chan interface{})

    go pnbot.makePrimes(maxPrime, primes, quit)

    return pnbot.tweet(primes, quit)
}

func (pnbot *PNBot) startTwin() error {
    tweet, err := pnbot.lastTweet()
    if err != nil {
        return err
    }
    log.Printf("last tweet: %v", tweet)

    maxPrime := new(big.Int)
    if tweet != "" {
        twin := strings.Split(tweet, ",")
        if len(twin) != 2 {
            return fmt.Errorf("invalid tweet len: %v", tweet)
        }
        _, ok := maxPrime.SetString(twin[1], 10)
        if !ok {
            return fmt.Errorf("invalid tweet: %v", tweet)
        }
    } else {
        maxPrime.SetInt64(3)
    }

    primes := make(chan *PNTweet, 10)
    quit := make(chan interface{})

    go pnbot.makeTwinPrimes(maxPrime, primes, quit)

    return pnbot.tweet(primes, quit)
}

func (pnbot *PNBot) lastTweet() (lastTweet string, err error) {
    params := twitter.UserTimelineParams{
        SinceID: 0,
    }

    tweets, _, err := pnbot.client.Timelines.UserTimeline(&params)
    if err != nil {
        log.Printf("lastTweet: %v\n", err)
        return "", err
    }

    if len(tweets) == 0 {
        log.Printf("lastTweet:len=0\n")
        return "", nil
    }

    return tweets[0].Text, nil
}

func (pnbot *PNBot) makePrimes(maxPrime *big.Int, tweets chan *PNTweet, quit chan interface{}) {
    var prime *big.Int
    var err error

    log.Printf("makePrime: %v\n", maxPrime)

    for {
        prime, err = pnbot.prime.Next()
        if err != nil {
            log.Fatalf("makePrimes: %v\n", err)
            quit <- nil
            return
        }

        if prime.Cmp(maxPrime) > 0 {
            break;
        }
        //log.Printf("makePrimes: skip %v\n", prime)
    }

    for {
        log.Printf("makePrimes: found %v\n", prime)
        tweets <- &PNTweet{
            text: prime.Text(10),
        }

        prime, err = pnbot.prime.Next()
        if err != nil {
            log.Fatalf("makePrimes: %v\n", err)
            quit <- nil
            return
        }
    }
}

func (pnbot *PNBot) makeTwinPrimes(maxPrime *big.Int, tweets chan *PNTweet, quit chan interface{}) {
    var prevPrime *big.Int
    var prime *big.Int
    var err error

    big2 := big.NewInt(2)

    log.Printf("makeTwinPrimes: %v\n", maxPrime)

    for {
        prevPrime, err = pnbot.prime.Next()
        if err != nil {
            log.Fatalf("makeTwinPrimes: %v\n", err)
            quit <- nil
            return
        }

        if prevPrime.Cmp(maxPrime) >= 0 {
            break;
        }
    }

    for {
        for {
            prime, err = pnbot.prime.Next()
            if err != nil {
                log.Fatalf("makeTwinPrimes: %v\n", err)
                quit <- nil
                return
            }

            n := new(big.Int)
            if n.Sub(prime, prevPrime).Cmp(big2) == 0 {
                log.Printf("makeTwinPrimes: found %v,%v\n", prevPrime, prime)

                break
            }
            prevPrime = prime
        }

        tweets <- &PNTweet{
            text: fmt.Sprintf("%s,%s", prevPrime.Text(10), prime.Text(10)),
        }
        prevPrime = prime
    }
}

func max(a time.Duration, b time.Duration) time.Duration {
    if a > b {
        return b
    } else {
        return a
    }
}

type Response struct {
    Method string `json:"method"`
    Params interface{} `json:"params"`
    Result interface{} `json:"result"`
}

func (pnbot *PNBot) startPrimeP() error {

    lastReplyID, err := pnbot.lastReplyID()
    if err != nil {
        return err
    }

    tweets := make(chan *PNTweet, 10)
    quit := make(chan interface{})

    go pnbot.reply(tweets, quit, lastReplyID)

    return pnbot.tweet(tweets, quit)
}

func (pnbot *PNBot) lastReplyID() (lastReplyID int64, err error) {
    params := twitter.UserTimelineParams{
        Count: 200,
        SinceID: 0,
    }

    n := 0

    for {
        tweets, _, err := pnbot.client.Timelines.UserTimeline(&params)
        if err != nil {
            log.Printf("lastReplyiD: %v\n", err)
            time.Sleep(time.Minute)
            continue
        }

        if len(tweets) == 0 {
            return -1, nil
        }

        for _, tweet := range tweets {
            params.MaxID = tweet.ID - 1

            if tweet.InReplyToStatusID != 0 {
                return tweet.InReplyToStatusID, nil
            }
        }
        n++
        log.Printf("get next tweets:%d", n)
        time.Sleep(10 * interval)
    }
}

func (pnbot *PNBot) reply(tweets chan *PNTweet, quit chan interface{}, lastReplyID int64) error {
    var prevID int64 = -1
    var id int64 = lastReplyID + 1

    var mentionInterval time.Duration = 10 * time.Second
    var totalCount int = 0;
    var count int = 0;

    var retry int = 0

    for {
        if prevID != id {
            log.Printf("lastReplyID: %d", id)
        }
        params := twitter.MentionTimelineParams{
            SinceID: id,
        }
        mentions := []twitter.Tweet{}
        retry = 0
        for {
            ms, _, err := pnbot.client.Timelines.MentionTimeline(&params)

            if err != nil {
                if retry >= maxRetry {
                    quit <- nil
                    return fmt.Errorf("Too many tweet error: %v\n", err)
                }
                log.Printf("MentionTimeline error[%d/%d]:sleep=%s: %v\n", retry+1, maxRetry, retryInterval, err)

                time.Sleep(retryInterval)
                pnbot.client = pnbot.newClient()
                count = 0
                retry++
                continue
            }
            if len(ms) == 0 {
                break
            }

            mentions = append(mentions, ms...)
            params.MaxID = ms[len(ms)-1].ID - 1
        }

        reverse(mentions)

        for _, mention := range mentions {
            n, ok := parseTweet(mention)

            if !ok {
                continue
            }

            b, err := pnbot.prime.IsPrime(n)
            if err != nil {
                log.Printf("%v", err)

                err := replyPrimeImpl(tweets, n, "timeout", mention)

                if err != nil {
                    quit <- nil
                    return err
                }
                continue
            }

            if b {
                err = replyPrimeImpl(tweets, n, "prime number", mention)
            } else {
                err = replyPrimeImpl(tweets, n, "composite number", mention)
            }
            if err != nil {
                quit <- nil
                return err
            }
        }
        prevID = id
        if len(mentions) > 0 {
            id = mentions[len(mentions)-1].ID + 1
        }
        count++
        totalCount++

        log.Printf("Sleep %v:count=%d:totalCount=%d", mentionInterval, count, totalCount)
        time.Sleep(mentionInterval)
    }
}

func replyPrimeImpl(replies chan *PNTweet, n *big.Int, result string, tweet twitter.Tweet) error {
    var text string

    pnText := n.Text(10)

    for {
        text = fmt.Sprintf("@%s %v: %s", tweet.User.ScreenName, pnText, result)
        log.Printf("%s %d", text, len(text))
        if len(text) <= maxTweetCharactors {
            break
        }
        pnText = pnText[0:(len(pnText)+maxTweetCharactors-len(text)-len(hellipsis))]
        pnText = pnText + hellipsis
    }

    replies <- &PNTweet{
        text: text,
        params: &twitter.StatusUpdateParams{
            InReplyToStatusID: tweet.ID,
        },
    }
    time.Sleep(1 * time.Second)
    return nil
}

func parseTweet(tweet twitter.Tweet) (*big.Int, bool) {
    text := tweet.Text
    i := 0

    log.Printf("'%s' ", text)

    for _, indices := range getEntityIndices(&tweet) {
        if i == indices.Start() {
            i = indices.End()
            continue
        }
        str := text[i:indices.Start()]
        log.Printf("'%s'\n", str)
        if n, ok := parseNumber(str); ok {
            return n, true
        }
        i = indices.End()
    }

    if i < len(text) {
        str := text[i:]
        log.Printf("'%s'\n", str)
        if n, ok := parseNumber(str); ok {
            return n, true
        }
    }

    log.Printf("ignored\n")
    return nil, false
}

func parseNumber(str string) (*big.Int, bool) {
    n := new(big.Int)
    if _, ok := n.SetString(strings.TrimFunc(str, unicode.IsSpace), 10); ok {
        return n, true
    }
    return nil, false

}

type indices []twitter.Indices

func (is indices) Len() int {
    return len(is)
}

func (is indices) Swap(i, j int) {
    is[i], is[j] = is[j], is[i]
}

func (is indices) Less(i, j int) bool {
    return is[i].Start() < is[j].Start()
}

func getEntityIndices(tweet *twitter.Tweet) []twitter.Indices {
    var res indices = make([]twitter.Indices, 0)

    entities := tweet.Entities

    for _, entity := range entities.Hashtags {
        res = append(res, entity.Indices)
    }
    for _, entity := range entities.Media {
        res = append(res, entity.Indices)
    }
    for _, entity := range entities.Urls {
        res = append(res, entity.Indices)
    }
    for _, entity := range entities.UserMentions {
        res = append(res, entity.Indices)
    }

    sort.Sort(res)

    return res
}

func reverse(tweets []twitter.Tweet) {
    for i, j := 0, len(tweets)-1; i < j; i, j = i + 1, j - 1 {
        tweets[i], tweets[j] = tweets[j], tweets[i]
    }
}
<commit_msg>handle API Error code.<commit_after>package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "math/big"
    "sort"
    "strings"
    "time"
    "unicode"

    "github.com/tooru/pnbot/prime"
    "github.com/dghubble/go-twitter/twitter"
    "github.com/dghubble/oauth1"
//    "github.com/davecgh/go-spew/spew"
)

const (
    maxTweetCharactors = 140
    hellipsis = "\u2026"

    queueSize = 10
    maxRetry = 100
    retryInterval = 10 * time.Minute
    interval = 1 * time.Second

    errorUserIsOverDailyStatusUpdateLimit = 185
    errorStatusIsADuplicate = 187
)

func main() {
    log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)

    flags := flag.NewFlagSet("pnbot", flag.ExitOnError)

    mode := flags.String("mode", "normal", "Tweet Mode: 'normal'(default), 'twin', 'primep', 'primeptest'")
    target := flags.String("target", "", "tweet target")

    consumerKey := flags.String("ck", "", "Twitter Consumer Key")
    consumerSecret := flags.String("cs", "", "Twitter Consumer Secret")
    accessToken := flags.String("at", "", "Twitter Access Token")
    accessSecret := flags.String("as", "", "Twitter Access Secret")

    debug := flags.Bool("debug", false, "debug mode")

    flags.Parse(os.Args[1:])

    if *consumerKey == "" || *consumerSecret == "" || *accessToken == "" || *accessSecret == "" {
        log.Fatal("Consumer key/secret and Access token/secret required")
    }

    pnbot := NewPNBot(mode, target, *debug,
        consumerKey, consumerSecret, accessToken, accessSecret)
    pnbot.Start()
}

func NewPNBot(mode *string, target *string, debug bool,
              consumerKey *string, consumerSecret *string,
              accessToken *string, accessSecret *string) *PNBot {
    pnbot := &PNBot{
        mode: mode,
        target: target,
        debug: debug,
        consumerKey: consumerKey,
        consumerSecret: consumerSecret,
        accessToken: accessToken,
        accessSecret: accessSecret,
        prime: prime.NewPrime(),
    }

    return pnbot
}

type PNBot struct {
    mode *string
    target *string
    debug bool

    consumerKey *string
    consumerSecret *string
    accessToken *string
    accessSecret *string

    prime *prime.Prime

    client *twitter.Client

}

type PNTweet struct {
    text string
    params *twitter.StatusUpdateParams
}

func (pnbot *PNBot) Start() error {
    pnbot.client = pnbot.newClient()

    switch *pnbot.mode {
    case "normal":
        return pnbot.startNormal()
    case "twin":
        return pnbot.startTwin()
    case "primep":
        return pnbot.startPrimeP()
    case "primeptest":
        return nil
        //return pnbot.startTestPrimeP()
    default:
        return fmt.Errorf("Start: unknown mode: %v", *pnbot.mode)
    }
}

func (pnbot *PNBot) newClient() *twitter.Client {
    config := oauth1.NewConfig(*pnbot.consumerKey, *pnbot.consumerSecret)
    token := oauth1.NewToken(*pnbot.accessToken, *pnbot.accessSecret)
    httpClient := config.Client(oauth1.NoContext, token)

    return twitter.NewClient(httpClient)
}

func (pnbot *PNBot) tweet(tweets chan *PNTweet, quit chan interface{}) error {
    totalN := 0
    totalStart := time.Now()

    contN := 0
    contStart := totalStart

    for {
        var pnTweet *PNTweet

        select {
        case pnTweet = <- tweets:
        case <- quit:
            log.Fatalf("error occurred.")
        }

        retry := 0
        for {
            var err error
            if pnbot.debug {
                log.Printf("Tweet: %s", pnTweet.text)
            } else {
                _, _, err = pnbot.client.Statuses.Update(pnTweet.text, pnTweet.params)
            }
            if err == nil {
                break
            }
            v, ok := err.(twitter.APIError)
            if ok {
                if len(v.Errors) == 0 {
                    return fmt.Errorf("Unknown Error:len(Errors)=0: %v\n", err)
                }
                errDetail := v.Errors[0]
                if errDetail.Code == errorStatusIsADuplicate {
                    log.Printf(err.Error())
                    break
                } else if errDetail.Code != errorUserIsOverDailyStatusUpdateLimit {
                    return fmt.Errorf("Unknown Error:len(Errors)=0: %v\n", err)
                }
            }

            if retry >= maxRetry {
                return fmt.Errorf("Too many tweet error: %v\n", err)
            }
            log.Printf("Tweet error[%d/%d]:sleep=%s: %v\n", retry+1, maxRetry, retryInterval, err)

            time.Sleep(retryInterval)
            pnbot.client = pnbot.newClient()
            retry++
            continue
        }
        now := time.Now()

        if retry > 0 {
            contN = 0
            contStart = now
        }
        contN++
        totalN++

        log.Printf("tweet:%d:%d:%s:sleep=%s:%.2f tw/h: %.2f tw/h\n",
            totalN, contN,
            pnTweet.text,
            interval,
            float64(totalN)/(float64(now.Sub(totalStart))/float64(time.Hour)),
            float64(contN)/(float64(now.Sub(contStart))/float64(time.Hour)))
        time.Sleep(interval)
    }
}

func (pnbot *PNBot) startNormal() error {
    tweet, err := pnbot.lastTweet()
    if err != nil {
        return err
    }
    log.Printf("last tweet: %v", tweet)

    maxPrime := new(big.Int)
    if tweet != "" {
        maxPrime.SetString(tweet, 10)
    } else {
        maxPrime.SetInt64(0)
    }

    primes := make(chan *PNTweet, 10)
    quit := make(chan interface{})

    go pnbot.makePrimes(maxPrime, primes, quit)

    return pnbot.tweet(primes, quit)
}

func (pnbot *PNBot) startTwin() error {
    tweet, err := pnbot.lastTweet()
    if err != nil {
        return err
    }
    log.Printf("last tweet: %v", tweet)

    maxPrime := new(big.Int)
    if tweet != "" {
        twin := strings.Split(tweet, ",")
        if len(twin) != 2 {
            return fmt.Errorf("invalid tweet len: %v", tweet)
        }
        _, ok := maxPrime.SetString(twin[1], 10)
        if !ok {
            return fmt.Errorf("invalid tweet: %v", tweet)
        }
    } else {
        maxPrime.SetInt64(3)
    }

    primes := make(chan *PNTweet, 10)
    quit := make(chan interface{})

    go pnbot.makeTwinPrimes(maxPrime, primes, quit)

    return pnbot.tweet(primes, quit)
}

func (pnbot *PNBot) lastTweet() (lastTweet string, err error) {
    params := twitter.UserTimelineParams{
        SinceID: 0,
    }

    tweets, _, err := pnbot.client.Timelines.UserTimeline(&params)
    if err != nil {
        log.Printf("lastTweet: %v\n", err)
        return "", err
    }

    if len(tweets) == 0 {
        log.Printf("lastTweet:len=0\n")
        return "", nil
    }

    return tweets[0].Text, nil
}

func (pnbot *PNBot) makePrimes(maxPrime *big.Int, tweets chan *PNTweet, quit chan interface{}) {
    var prime *big.Int
    var err error

    log.Printf("makePrime: %v\n", maxPrime)

    for {
        prime, err = pnbot.prime.Next()
        if err != nil {
            log.Fatalf("makePrimes: %v\n", err)
            quit <- nil
            return
        }

        if prime.Cmp(maxPrime) > 0 {
            break;
        }
        //log.Printf("makePrimes: skip %v\n", prime)
    }

    for {
        log.Printf("makePrimes: found %v\n", prime)
        tweets <- &PNTweet{
            text: prime.Text(10),
        }

        prime, err = pnbot.prime.Next()
        if err != nil {
            log.Fatalf("makePrimes: %v\n", err)
            quit <- nil
            return
        }
    }
}

func (pnbot *PNBot) makeTwinPrimes(maxPrime *big.Int, tweets chan *PNTweet, quit chan interface{}) {
    var prevPrime *big.Int
    var prime *big.Int
    var err error

    big2 := big.NewInt(2)

    log.Printf("makeTwinPrimes: %v\n", maxPrime)

    for {
        prevPrime, err = pnbot.prime.Next()
        if err != nil {
            log.Fatalf("makeTwinPrimes: %v\n", err)
            quit <- nil
            return
        }

        if prevPrime.Cmp(maxPrime) >= 0 {
            break;
        }
    }

    for {
        for {
            prime, err = pnbot.prime.Next()
            if err != nil {
                log.Fatalf("makeTwinPrimes: %v\n", err)
                quit <- nil
                return
            }

            n := new(big.Int)
            if n.Sub(prime, prevPrime).Cmp(big2) == 0 {
                log.Printf("makeTwinPrimes: found %v,%v\n", prevPrime, prime)

                break
            }
            prevPrime = prime
        }

        tweets <- &PNTweet{
            text: fmt.Sprintf("%s,%s", prevPrime.Text(10), prime.Text(10)),
        }
        prevPrime = prime
    }
}

func max(a time.Duration, b time.Duration) time.Duration {
    if a > b {
        return b
    } else {
        return a
    }
}

type Response struct {
    Method string `json:"method"`
    Params interface{} `json:"params"`
    Result interface{} `json:"result"`
}

func (pnbot *PNBot) startPrimeP() error {

    lastReplyID, err := pnbot.lastReplyID()
    if err != nil {
        return err
    }

    tweets := make(chan *PNTweet, 10)
    quit := make(chan interface{})

    go pnbot.reply(tweets, quit, lastReplyID)

    return pnbot.tweet(tweets, quit)
}

func (pnbot *PNBot) lastReplyID() (lastReplyID int64, err error) {
    params := twitter.UserTimelineParams{
        Count: 200,
        SinceID: 0,
    }

    n := 0

    for {
        tweets, _, err := pnbot.client.Timelines.UserTimeline(&params)
        if err != nil {
            log.Printf("lastReplyiD: %v\n", err)
            time.Sleep(time.Minute)
            continue
        }

        if len(tweets) == 0 {
            return -1, nil
        }

        for _, tweet := range tweets {
            params.MaxID = tweet.ID - 1

            if tweet.InReplyToStatusID != 0 {
                return tweet.InReplyToStatusID, nil
            }
        }
        n++
        log.Printf("get next tweets:%d", n)
        time.Sleep(10 * interval)
    }
}

func (pnbot *PNBot) reply(tweets chan *PNTweet, quit chan interface{}, lastReplyID int64) error {
    var prevID int64 = -1
    var id int64 = lastReplyID + 1

    var mentionInterval time.Duration = 10 * time.Second
    var totalCount int = 0;
    var count int = 0;

    var retry int = 0

    for {
        if prevID != id {
            log.Printf("lastReplyID: %d", id)
        }
        params := twitter.MentionTimelineParams{
            SinceID: id,
        }
        mentions := []twitter.Tweet{}
        retry = 0
        for {
            ms, _, err := pnbot.client.Timelines.MentionTimeline(&params)

            if err != nil {
                if retry >= maxRetry {
                    quit <- nil
                    return fmt.Errorf("Too many tweet error: %v\n", err)
                }
                log.Printf("MentionTimeline error[%d/%d]:sleep=%s: %v\n", retry+1, maxRetry, retryInterval, err)

                time.Sleep(retryInterval)
                pnbot.client = pnbot.newClient()
                count = 0
                retry++
                continue
            }
            if len(ms) == 0 {
                break
            }

            mentions = append(mentions, ms...)
            params.MaxID = ms[len(ms)-1].ID - 1
        }

        reverse(mentions)

        for _, mention := range mentions {
            n, ok := parseTweet(mention)

            if !ok {
                continue
            }

            b, err := pnbot.prime.IsPrime(n)
            if err != nil {
                log.Printf("%v", err)

                err := replyPrimeImpl(tweets, n, "timeout", mention)

                if err != nil {
                    quit <- nil
                    return err
                }
                continue
            }

            if b {
                err = replyPrimeImpl(tweets, n, "prime number", mention)
            } else {
                err = replyPrimeImpl(tweets, n, "composite number", mention)
            }
            if err != nil {
                quit <- nil
                return err
            }
        }
        prevID = id
        if len(mentions) > 0 {
            id = mentions[len(mentions)-1].ID + 1
        }
        count++
        totalCount++

        log.Printf("Sleep %v:count=%d:totalCount=%d", mentionInterval, count, totalCount)
        time.Sleep(mentionInterval)
    }
}

func replyPrimeImpl(replies chan *PNTweet, n *big.Int, result string, tweet twitter.Tweet) error {
    var text string

    pnText := n.Text(10)

    for {
        text = fmt.Sprintf("@%s %v: %s", tweet.User.ScreenName, pnText, result)
        log.Printf("%s %d", text, len(text))
        if len(text) <= maxTweetCharactors {
            break
        }
        pnText = pnText[0:(len(pnText)+maxTweetCharactors-len(text)-len(hellipsis))]
        pnText = pnText + hellipsis
    }

    replies <- &PNTweet{
        text: text,
        params: &twitter.StatusUpdateParams{
            InReplyToStatusID: tweet.ID,
        },
    }
    time.Sleep(1 * time.Second)
    return nil
}

func parseTweet(tweet twitter.Tweet) (*big.Int, bool) {
    text := tweet.Text
    i := 0

    log.Printf("'%s' ", text)

    for _, indices := range getEntityIndices(&tweet) {
        if i == indices.Start() {
            i = indices.End()
            continue
        }
        str := text[i:indices.Start()]
        log.Printf("'%s'\n", str)
        if n, ok := parseNumber(str); ok {
            return n, true
        }
        i = indices.End()
    }

    if i < len(text) {
        str := text[i:]
        log.Printf("'%s'\n", str)
        if n, ok := parseNumber(str); ok {
            return n, true
        }
    }

    log.Printf("ignored\n")
    return nil, false
}

func parseNumber(str string) (*big.Int, bool) {
    n := new(big.Int)
    if _, ok := n.SetString(strings.TrimFunc(str, unicode.IsSpace), 10); ok {
        return n, true
    }
    return nil, false

}

type indices []twitter.Indices

func (is indices) Len() int {
    return len(is)
}

func (is indices) Swap(i, j int) {
    is[i], is[j] = is[j], is[i]
}

func (is indices) Less(i, j int) bool {
    return is[i].Start() < is[j].Start()
}

func getEntityIndices(tweet *twitter.Tweet) []twitter.Indices {
    var res indices = make([]twitter.Indices, 0)

    entities := tweet.Entities

    for _, entity := range entities.Hashtags {
        res = append(res, entity.Indices)
    }
    for _, entity := range entities.Media {
        res = append(res, entity.Indices)
    }
    for _, entity := range entities.Urls {
        res = append(res, entity.Indices)
    }
    for _, entity := range entities.UserMentions {
        res = append(res, entity.Indices)
    }

    sort.Sort(res)

    return res
}

func reverse(tweets []twitter.Tweet) {
    for i, j := 0, len(tweets)-1; i < j; i, j = i + 1, j - 1 {
        tweets[i], tweets[j] = tweets[j], tweets[i]
    }
}
<|endoftext|>


<commit_before>package command

import (
	"context"
	"encoding/json"
	"fmt"
	"math/big"
	"net/http"
	"net/url"

	"github.com/spolu/settle/cli"
	"github.com/spolu/settle/lib/client"
	"github.com/spolu/settle/lib/env"
	"github.com/spolu/settle/lib/errors"
	"github.com/spolu/settle/lib/out"
	"github.com/spolu/settle/lib/svc"
	"github.com/spolu/settle/mint"
	"github.com/spolu/settle/register"
)

// MintRegister contains all the required information to register to a mint
// from the cli.
type MintRegister struct {
	Name        string
	Host        string
	Description string
	RegisterURL map[env.Environment]string
}

// PublicMints is a list of proposed public mints that offer registration
// form the cli.
var PublicMints = []MintRegister{
	MintRegister{
		Name:        "Settle",
		Host:        "settle.network",
		Description: "Mint maintained by the Settle developers.",
		RegisterURL: map[env.Environment]string{
			env.Production: "https://register.settle.network/users",
			env.QA:         "https://qa-register.settle.network/users",
		},
	},
}

// RegisterUser registers a user on the provded mint register service.
func RegisterUser(
	ctx context.Context,
	reg MintRegister,
	username string,
	email string,
) (*register.UserResource, error) {
	body := url.Values{}
	body["username"] = []string{username}
	body["email"] = []string{email}

	req, err := http.NewRequest("POST",
		reg.RegisterURL[env.Get(ctx).Environment], nil)
	if err != nil {
		return nil, errors.Trace(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	r, err := client.Default(ctx).Do(req)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer r.Body.Close()

	var raw svc.Resp
	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		return nil, errors.Trace(err)
	}

	if r.StatusCode != http.StatusCreated {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var user register.UserResource
	err = raw.Extract("user", &user)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &user, nil
}

// CreateAsset creates an asset for the currently authenticated user.
func CreateAsset(
	ctx context.Context,
	name string,
) (*mint.AssetResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Creating asset] user=%s@%s asset=%s\n",
		m.Credentials.Username, m.Credentials.Host,
		name)

	a, err := mint.AssetResourceFromName(ctx, name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	status, raw, err := m.Post(ctx,
		"/assets",
		url.Values{},
		url.Values{
			"code":  {a.Code},
			"scale": {fmt.Sprintf("%d", a.Scale)},
		})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusCreated {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var asset mint.AssetResource
	err = raw.Extract("asset", &asset)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &asset, nil
}

// RetrieveAsset retrieves an asset, returnin nil if it does not exist.
func RetrieveAsset(
	ctx context.Context,
	name string,
) (*mint.AssetResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Retrieving asset] user=%s@%s asset=%s\n",
		m.Credentials.Username, m.Credentials.Host,
		name)

	status, raw, err := m.Get(ctx,
		fmt.Sprintf("/assets/%s", name),
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		if e.ErrCode == "asset_not_found" {
			return nil, nil
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var asset mint.AssetResource
	err = raw.Extract("asset", &asset)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &asset, nil
}

// CreateOffer creates an offer for the currently authenticated user.
func CreateOffer(
	ctx context.Context,
	pair string,
	amount big.Int,
	price string,
) (*mint.OfferResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Creating offer] user=%s@%s pair=%s amount=%s price=%s\n",
		m.Credentials.Username, m.Credentials.Host,
		pair, amount.String(), price)

	status, raw, err := m.Post(ctx,
		"/offers",
		url.Values{},
		url.Values{
			"pair":   {pair},
			"amount": {amount.String()},
			"price":  {price},
		})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusCreated {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var offer mint.OfferResource
	err = raw.Extract("offer", &offer)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &offer, nil
}

// ListAssets list assets for the current user.
func ListAssets(
	ctx context.Context,
) ([]mint.AssetResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing assets] user=%s@%s\n",
		m.Credentials.Username, m.Credentials.Host)

	status, raw, err := m.Get(ctx,
		"/assets",
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var assets []mint.AssetResource
	err = raw.Extract("assets", &assets)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return assets, nil
}

// ListBalances list balances of the current user.
func ListBalances(
	ctx context.Context,
) ([]mint.BalanceResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing balances] user=%s@%s\n",
		m.Credentials.Username, m.Credentials.Host)

	status, raw, err := m.Get(ctx,
		"/balances",
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var balances []mint.BalanceResource
	err = raw.Extract("balances", &balances)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return balances, nil
}

// ListAssetBalances list balances for one of the current user's asset.
func ListAssetBalances(
	ctx context.Context,
	asset string,
) ([]mint.BalanceResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing asset balances] user=%s@%s asset=%s\n",
		m.Credentials.Username, m.Credentials.Host, asset)

	status, raw, err := m.Get(ctx,
		fmt.Sprintf("/assets/%s/balances", asset),
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var balances []mint.BalanceResource
	err = raw.Extract("balances", &balances)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return balances, nil
}

// ListAssetOffers list offers for one of the current user's asset.
func ListAssetOffers(
	ctx context.Context,
	asset string,
	propagation mint.PgType,
) ([]mint.OfferResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing asset offers] user=%s@%s asset=%s propagation=%s\n",
		m.Credentials.Username, m.Credentials.Host, asset, propagation)

	status, raw, err := m.Get(ctx,
		fmt.Sprintf("/assets/%s/offers", asset),
		url.Values{
			"propagation": {string(propagation)},
		})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var offers []mint.OfferResource
	err = raw.Extract("offers", &offers)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return offers, nil
}
<commit_msg>Fix QA register<commit_after>package command

import (
	"context"
	"encoding/json"
	"fmt"
	"math/big"
	"net/http"
	"net/url"

	"github.com/spolu/settle/cli"
	"github.com/spolu/settle/lib/client"
	"github.com/spolu/settle/lib/env"
	"github.com/spolu/settle/lib/errors"
	"github.com/spolu/settle/lib/out"
	"github.com/spolu/settle/lib/svc"
	"github.com/spolu/settle/mint"
	"github.com/spolu/settle/register"
)

// MintRegister contains all the required information to register to a mint
// from the cli.
type MintRegister struct {
	Name        string
	Host        string
	Description string
	RegisterURL map[env.Environment]string
}

// PublicMints is a list of proposed public mints that offer registration
// form the cli.
var PublicMints = []MintRegister{
	MintRegister{
		Name:        "Settle",
		Host:        "settle.network",
		Description: "Mint maintained by the Settle developers.",
		RegisterURL: map[env.Environment]string{
			env.Production: "https://register.settle.network/users",
			env.QA:         "https://register.settle.network:444/users",
		},
	},
}

// RegisterUser registers a user on the provded mint register service.
func RegisterUser(
	ctx context.Context,
	reg MintRegister,
	username string,
	email string,
) (*register.UserResource, error) {
	body := url.Values{}
	body["username"] = []string{username}
	body["email"] = []string{email}

	req, err := http.NewRequest("POST",
		reg.RegisterURL[env.Get(ctx).Environment], nil)
	if err != nil {
		return nil, errors.Trace(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	r, err := client.Default(ctx).Do(req)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer r.Body.Close()

	var raw svc.Resp
	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		return nil, errors.Trace(err)
	}

	if r.StatusCode != http.StatusCreated {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var user register.UserResource
	err = raw.Extract("user", &user)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &user, nil
}

// CreateAsset creates an asset for the currently authenticated user.
func CreateAsset(
	ctx context.Context,
	name string,
) (*mint.AssetResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Creating asset] user=%s@%s asset=%s\n",
		m.Credentials.Username, m.Credentials.Host,
		name)

	a, err := mint.AssetResourceFromName(ctx, name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	status, raw, err := m.Post(ctx,
		"/assets",
		url.Values{},
		url.Values{
			"code":  {a.Code},
			"scale": {fmt.Sprintf("%d", a.Scale)},
		})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusCreated {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var asset mint.AssetResource
	err = raw.Extract("asset", &asset)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &asset, nil
}

// RetrieveAsset retrieves an asset, returnin nil if it does not exist.
func RetrieveAsset(
	ctx context.Context,
	name string,
) (*mint.AssetResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Retrieving asset] user=%s@%s asset=%s\n",
		m.Credentials.Username, m.Credentials.Host,
		name)

	status, raw, err := m.Get(ctx,
		fmt.Sprintf("/assets/%s", name),
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		if e.ErrCode == "asset_not_found" {
			return nil, nil
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var asset mint.AssetResource
	err = raw.Extract("asset", &asset)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &asset, nil
}

// CreateOffer creates an offer for the currently authenticated user.
func CreateOffer(
	ctx context.Context,
	pair string,
	amount big.Int,
	price string,
) (*mint.OfferResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Creating offer] user=%s@%s pair=%s amount=%s price=%s\n",
		m.Credentials.Username, m.Credentials.Host,
		pair, amount.String(), price)

	status, raw, err := m.Post(ctx,
		"/offers",
		url.Values{},
		url.Values{
			"pair":   {pair},
			"amount": {amount.String()},
			"price":  {price},
		})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusCreated {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var offer mint.OfferResource
	err = raw.Extract("offer", &offer)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &offer, nil
}

// ListAssets list assets for the current user.
func ListAssets(
	ctx context.Context,
) ([]mint.AssetResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing assets] user=%s@%s\n",
		m.Credentials.Username, m.Credentials.Host)

	status, raw, err := m.Get(ctx,
		"/assets",
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var assets []mint.AssetResource
	err = raw.Extract("assets", &assets)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return assets, nil
}

// ListBalances list balances of the current user.
func ListBalances(
	ctx context.Context,
) ([]mint.BalanceResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing balances] user=%s@%s\n",
		m.Credentials.Username, m.Credentials.Host)

	status, raw, err := m.Get(ctx,
		"/balances",
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var balances []mint.BalanceResource
	err = raw.Extract("balances", &balances)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return balances, nil
}

// ListAssetBalances list balances for one of the current user's asset.
func ListAssetBalances(
	ctx context.Context,
	asset string,
) ([]mint.BalanceResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing asset balances] user=%s@%s asset=%s\n",
		m.Credentials.Username, m.Credentials.Host, asset)

	status, raw, err := m.Get(ctx,
		fmt.Sprintf("/assets/%s/balances", asset),
		url.Values{})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var balances []mint.BalanceResource
	err = raw.Extract("balances", &balances)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return balances, nil
}

// ListAssetOffers list offers for one of the current user's asset.
func ListAssetOffers(
	ctx context.Context,
	asset string,
	propagation mint.PgType,
) ([]mint.OfferResource, error) {
	m, err := cli.MintFromContextCredentials(ctx)
	if err != nil {
		return nil, errors.Trace(err)
	}

	out.Statf("[Listing asset offers] user=%s@%s asset=%s propagation=%s\n",
		m.Credentials.Username, m.Credentials.Host, asset, propagation)

	status, raw, err := m.Get(ctx,
		fmt.Sprintf("/assets/%s/offers", asset),
		url.Values{
			"propagation": {string(propagation)},
		})
	if err != nil {
		return nil, errors.Trace(err)
	}

	if *status != http.StatusOK {
		var e errors.ConcreteUserError
		err = raw.Extract("error", &e)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return nil, errors.Trace(
			errors.Newf("(%s) %s", e.ErrCode, e.ErrMessage))
	}

	var offers []mint.OfferResource
	err = raw.Extract("offers", &offers)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return offers, nil
}
<|endoftext|>


<commit_before>// Producer accepts logs from various sources and sends them to queue.
// The main task of this service - to be up and running 100% of time and run fast.
// Validation and other things should be done by background workers.
package producer

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strings"

	"github.com/firstrow/tcp_server"
	"github.com/logvoyage/logvoyage/shared/config"
	"github.com/streadway/amqp"
)

// RabbitMQ channel to write incoming messages
var channel *amqp.Channel

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

// httpHandler accepts incoming logs data. Each request should contain logs separated by new line.
// tag param is oprional.
// Example:
// POST https://data.logvoyage.com?uuid=projectUUID&tag=nginx
// log line 1
// log line 2
func httpHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		return
	}

	projectUUID := r.URL.Query().Get("uuid")
	if projectUUID == "" {
		return
	}

	tag := r.URL.Query().Get("tag")
	if tag == "" {
		tag = "default"
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println("Error reading request body")
	}

	if len(body) == 0 {
		log.Println("Got empty request")
	}

	log.Println("HTTP Message:", string(body))

	// Send message to queue.
	for _, line := range strings.Split(string(body), "\n") {
		go sendToQueue([]byte(fmt.Sprintf("%s@%s %s", projectUUID, tag, line)))
	}
}

func startHTTPHandler() {
	http.HandleFunc("/", httpHandler)
	err := http.ListenAndServe(":27000", nil)

	if err != nil {
		log.Fatalln("Error starting http server:", err)
	}
}

func startTCPHandler() {
	tcp := tcp_server.New("localhost:28000")

	tcp.OnNewClient(func(c *tcp_server.Client) {
		log.Println("New TCP client connected")
	})
	tcp.OnNewMessage(func(c *tcp_server.Client, message string) {
		log.Println("New message received:", message)
		sendToQueue([]byte(message))
	})
	tcp.OnClientConnectionClosed(func(c *tcp_server.Client, err error) {
		log.Println("Connection to client lost")
	})

	tcp.Listen()
}

func startUDPHandler() {
	updAddr, err := net.ResolveUDPAddr("udp", ":29000")
	failOnError(err, "Error resolving UDP address")

	conn, err := net.ListenUDP("udp", updAddr)
	failOnError(err, "Error listening to UDP")
	defer conn.Close()

	reader := bufio.NewReader(conn)
	for {
		message, err := reader.ReadString('\n')
		log.Println("UDP Message", message)
		if err != nil {
			log.Println("Error reading UDP message:", err)
		}
	}
}

// TODO: If rabbitmq is down - store messages in backlog.
// What type of backlog? memory, hdd, database?
//
// sendToQueue sends data to queue.
// body should be an array of bytes. First N bytes should be project uuid.
func sendToQueue(body []byte) {
	err := channel.Publish(
		"logs", // exchange
		"all",  // routing key
		false,  // mandatory
		false,  // immediate
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})

	if err != nil {
		// TODO: Use logrus package and set proper error level for each log call.
		log.Println("Error publishing message:", string(body))
	}
}

func Start() {
	amqpConn, err := amqp.Dial(config.Get("amqp.url"))
	failOnError(err, "Failed to connect to RabbitMQ")
	defer amqpConn.Close()

	// TODO: Put channel into confirm mode.
	channel, err = amqpConn.Channel()
	failOnError(err, "Failed to open a channel")
	defer channel.Close()

	err = channel.ExchangeDeclare(
		"logs",   // name
		"direct", // type
		true,     // durable
		false,    // auto-deleted
		false,    // internal
		false,    // noWait
		nil,      // arguments
	)
	failOnError(err, "Failed to declare a queue")

	go startHTTPHandler()
	go startTCPHandler()
	go startUDPHandler()

	exit := make(chan int)
	<-exit
}
<commit_msg>Removed hardcoded localhost<commit_after>// Producer accepts logs from various sources and sends them to queue.
// The main task of this service - to be up and running 100% of time and run fast.
// Validation and other things should be done by background workers.
package producer

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strings"

	"github.com/firstrow/tcp_server"
	"github.com/logvoyage/logvoyage/shared/config"
	"github.com/streadway/amqp"
)

// RabbitMQ channel to write incoming messages
var channel *amqp.Channel

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

// httpHandler accepts incoming logs data. Each request should contain logs separated by new line.
// tag param is oprional.
// Example:
// POST https://data.logvoyage.com?uuid=projectUUID&tag=nginx
// log line 1
// log line 2
func httpHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		return
	}

	projectUUID := r.URL.Query().Get("uuid")
	if projectUUID == "" {
		return
	}

	tag := r.URL.Query().Get("tag")
	if tag == "" {
		tag = "default"
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println("Error reading request body")
	}

	if len(body) == 0 {
		log.Println("Got empty request")
	}

	log.Println("HTTP Message:", string(body))

	// Send message to queue.
	for _, line := range strings.Split(string(body), "\n") {
		go sendToQueue([]byte(fmt.Sprintf("%s@%s %s", projectUUID, tag, line)))
	}
}

func startHTTPHandler() {
	http.HandleFunc("/", httpHandler)
	err := http.ListenAndServe(":27000", nil)

	if err != nil {
		log.Fatalln("Error starting http server:", err)
	}
}

func startTCPHandler() {
	tcp := tcp_server.New(":28000")

	tcp.OnNewClient(func(c *tcp_server.Client) {
		log.Println("New TCP client connected")
	})
	tcp.OnNewMessage(func(c *tcp_server.Client, message string) {
		log.Println("New message received:", message)
		sendToQueue([]byte(message))
	})
	tcp.OnClientConnectionClosed(func(c *tcp_server.Client, err error) {
		log.Println("Connection to client lost")
	})

	tcp.Listen()
}

func startUDPHandler() {
	updAddr, err := net.ResolveUDPAddr("udp", ":29000")
	failOnError(err, "Error resolving UDP address")

	conn, err := net.ListenUDP("udp", updAddr)
	failOnError(err, "Error listening to UDP")
	defer conn.Close()

	reader := bufio.NewReader(conn)
	for {
		message, err := reader.ReadString('\n')
		log.Println("UDP Message", message)
		if err != nil {
			log.Println("Error reading UDP message:", err)
		}
	}
}

// TODO: If rabbitmq is down - store messages in backlog.
// What type of backlog? memory, hdd, database?
//
// sendToQueue sends data to queue.
// body should be an array of bytes. First N bytes should be project uuid.
func sendToQueue(body []byte) {
	err := channel.Publish(
		"logs", // exchange
		"all",  // routing key
		false,  // mandatory
		false,  // immediate
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})

	if err != nil {
		// TODO: Use logrus package and set proper error level for each log call.
		log.Println("Error publishing message:", string(body))
	}
}

func Start() {
	amqpConn, err := amqp.Dial(config.Get("amqp.url"))
	failOnError(err, "Failed to connect to RabbitMQ")
	defer amqpConn.Close()

	// TODO: Put channel into confirm mode.
	channel, err = amqpConn.Channel()
	failOnError(err, "Failed to open a channel")
	defer channel.Close()

	err = channel.ExchangeDeclare(
		"logs",   // name
		"direct", // type
		true,     // durable
		false,    // auto-deleted
		false,    // internal
		false,    // noWait
		nil,      // arguments
	)
	failOnError(err, "Failed to declare a queue")

	go startHTTPHandler()
	go startTCPHandler()
	go startUDPHandler()

	exit := make(chan int)
	<-exit
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 - Cloud Instruments Co. Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package seelog

import (
	"io"
	"io/ioutil"
	"fmt"
	"strconv"
	"bufio"
	"bytes"
	"errors"
)

func main() {
	fmt.Println("Hello World!")
}

func countSequencedRowsInFile(filePath string) (int64, error) {
	bts, err := ioutil.ReadFile(filePath)
	if err != nil {
		 return 0, err
	}

	bufReader := bufio.NewReader(bytes.NewBuffer(bts))

	var gotCounter int64
	for ;; {
		line, _, bufErr := bufReader.ReadLine()
		if bufErr != nil && bufErr != io.EOF {
			return 0, bufErr
		}

		lineString := string(line)
		if lineString == "" {
			break
		}

		intVal, atoiErr := strconv.ParseInt(lineString, 10, 64)
		if atoiErr != nil {
			return 0, atoiErr
		}

		if intVal != gotCounter {
			return 0, errors.New(fmt.Sprintf("Wrong order: %d Expected: %d\n", intVal, gotCounter))
		}

		gotCounter++
	}

	return gotCounter, nil
}
<commit_msg>No comments<commit_after>// Copyright (c) 2012 - Cloud Instruments Co. Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package seelog

import (
	"io"
	"io/ioutil"
	"fmt"
	"strconv"
	"bufio"
	"bytes"
	"errors"
)

func countSequencedRowsInFile(filePath string) (int64, error) {
	bts, err := ioutil.ReadFile(filePath)
	if err != nil {
		 return 0, err
	}

	bufReader := bufio.NewReader(bytes.NewBuffer(bts))

	var gotCounter int64
	for ;; {
		line, _, bufErr := bufReader.ReadLine()
		if bufErr != nil && bufErr != io.EOF {
			return 0, bufErr
		}

		lineString := string(line)
		if lineString == "" {
			break
		}

		intVal, atoiErr := strconv.ParseInt(lineString, 10, 64)
		if atoiErr != nil {
			return 0, atoiErr
		}

		if intVal != gotCounter {
			return 0, errors.New(fmt.Sprintf("Wrong order: %d Expected: %d\n", intVal, gotCounter))
		}

		gotCounter++
	}

	return gotCounter, nil
}
<|endoftext|>


<commit_before>package client

import (
	"github.com/stretchr/testify/assert"
  "github.com/heidi-ann/ios/ios/server"
  "github.com/heidi-ann/ios/config"
  "github.com/golang/glog"
	"testing"
  "os"
  "io/ioutil"
)

func TestStartClient(t *testing.T) {
	assert := assert.New(t)
  //Create temp directories
  dirClient, err := ioutil.TempDir("", "IosStartClientTests")
  if err != nil {
    glog.Fatal(err)
  }
  defer os.RemoveAll(dirClient)

  //start 3 node Ios cluster
  serverConfigFile := os.Getenv("GOPATH")+"/src/github.com/heidi-ann/ios/ios/example3.conf"
  for id := 0; id <=2; id++ {
    dirServer, err := ioutil.TempDir("", "IosStartClientTests")
    if err != nil {
      glog.Fatal(err)
    }
    defer os.RemoveAll(dirServer)
    go server.RunIos(id, config.ParseServerConfig(serverConfigFile), dirServer)
  }

  //start client
  clientConfigFile := os.Getenv("GOPATH")+"/src/github.com/heidi-ann/ios/client/example3.conf"

  client := StartClientFromConfigFile(1, dirClient+"/latency.csv", clientConfigFile)

  //submit requests
  success, reply := client.SubmitRequest("update A 1")
  assert.True(success,"Request not successful")
  assert.Equal("OK",reply,"Response not as expected")

  success, reply = client.SubmitRequest("get A")
  assert.True(success,"Request not successful")
  assert.Equal("1",reply,"Response not as expected")

  client2 := StartClientFromConfigFile(2, dirClient+"/latency2.csv", clientConfigFile)

  //submit requests to new client
  success, reply = client2.SubmitRequest("get A")
  assert.True(success,"Request not successful")
  assert.Equal("1",reply,"Response not as expected")

  success, reply = client2.SubmitRequest("update B 2")
  assert.True(success,"Request not successful")
  assert.Equal("OK",reply,"Response not as expected")

  //check original client is still ok
  success, reply = client.SubmitRequest("get B")
  assert.True(success,"Request not successful")
  assert.Equal("2",reply,"Response not as expected")

  //stopping client
  client.StopClient()
  client2.StopClient()

}
<commit_msg>removing client_test.go from test suite for now<commit_after>// +build ignore
package client

import (
	"github.com/stretchr/testify/assert"
  "github.com/heidi-ann/ios/ios/server"
  "github.com/heidi-ann/ios/config"
  "github.com/golang/glog"
	"testing"
  "os"
  "io/ioutil"
)

func TestStartClient(t *testing.T) {
	assert := assert.New(t)
  //Create temp directories
  dirClient, err := ioutil.TempDir("", "IosStartClientTests")
  if err != nil {
    glog.Fatal(err)
  }
  defer os.RemoveAll(dirClient)

  //start 3 node Ios cluster
  serverConfigFile := os.Getenv("GOPATH")+"/src/github.com/heidi-ann/ios/ios/example3.conf"
  for id := 0; id <=2; id++ {
    dirServer, err := ioutil.TempDir("", "IosStartClientTests")
    if err != nil {
      glog.Fatal(err)
    }
    defer os.RemoveAll(dirServer)
    go server.RunIos(id, config.ParseServerConfig(serverConfigFile), dirServer)
  }

  //start client
  clientConfigFile := os.Getenv("GOPATH")+"/src/github.com/heidi-ann/ios/client/example3.conf"

  client := StartClientFromConfigFile(1, dirClient+"/latency.csv", clientConfigFile)

  //submit requests
  success, reply := client.SubmitRequest("update A 1")
  assert.True(success,"Request not successful")
  assert.Equal("OK",reply,"Response not as expected")

  success, reply = client.SubmitRequest("get A")
  assert.True(success,"Request not successful")
  assert.Equal("1",reply,"Response not as expected")

  client2 := StartClientFromConfigFile(2, dirClient+"/latency2.csv", clientConfigFile)

  //submit requests to new client
  success, reply = client2.SubmitRequest("get A")
  assert.True(success,"Request not successful")
  assert.Equal("1",reply,"Response not as expected")

  success, reply = client2.SubmitRequest("update B 2")
  assert.True(success,"Request not successful")
  assert.Equal("OK",reply,"Response not as expected")

  //check original client is still ok
  success, reply = client.SubmitRequest("get B")
  assert.True(success,"Request not successful")
  assert.Equal("2",reply,"Response not as expected")

  //stopping client
  client.StopClient()
  client2.StopClient()

}
<|endoftext|>


<commit_before>package printutil

import (
	"math"
	"strconv"
)

func Stringf64(ks ...float64) string {
	s := ""
	for i, k := range ks {
		if k == math.MaxFloat64*-1 {
			s += "-∞"
		} else if k == math.MaxFloat64 {
			s += "∞"
		} else {
			s += strconv.FormatFloat(k, 'f', -1, 64)
		}
		if i != len(ks)-1 {
			s += ", "
		}
	}
	return s
}
<commit_msg>Floats print an acceptable number of digits after the decimal point<commit_after>package printutil

import (
	"math"
	"strconv"
)

func Stringf64(ks ...float64) string {
	s := ""
	for i, k := range ks {
		if k == math.MaxFloat64*-1 {
			s += "-∞"
		} else if k == math.MaxFloat64 {
			s += "∞"
		} else {
			s += strconv.FormatFloat(k, 'f', 5, 64)
		}
		if i != len(ks)-1 {
			s += ", "
		}
	}
	return s
}
<|endoftext|>


<commit_before>package main

func main() {
  fmt.Println("Hello, world!")
}
<commit_msg>Add Missing Import<commit_after>package main

import "fmt"

func main()  {
  fmt.Println("Hello, world!")
}
<|endoftext|>


<commit_before>//+build linux
package triggers

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/jamesrr39/taskrunner-app/taskrunner"
)

const (
	idVendorKey  = "ATTRS{idVendor}=="
	idProductKey = "ATTRS{idProduct}=="
	runKey       = "RUN+="
)

type UdevRulesDAL struct {
	BaseDir string // /etc/udev/rules.d
}

func NewUdevRulesDAL(baseDir string) *UdevRulesDAL {
	return &UdevRulesDAL{baseDir}
}

type UdevRule struct {
	IdVendor      string
	IdProduct     string
	Run           string
	FileDefinedIn string
}

func NewUdevRule(idVendor, idProduct, run, fileDefinedIn string) *UdevRule {
	return &UdevRule{idVendor, idProduct, run, fileDefinedIn}
}

func (u *UdevRulesDAL) GetRules(job *taskrunner.Job) ([]*UdevRule, error) {
	var rules []*UdevRule

	err := filepath.Walk(u.BaseDir, func(path string, fileInfo os.FileInfo, err error) error {
		if nil != err {
			return err
		}

		if fileInfo.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if nil != err {
			return err
		}
		defer file.Close()
		log.Printf("looking in %s\n", path)
		rules = append(rules, rulesFromFile(file, path, job)...)
		return nil
	})

	if nil != err {
		return nil, err
	}

	return rules, nil
}

func rulesFromFile(file io.Reader, filePath string, job *taskrunner.Job) []*UdevRule {
	var rules []*UdevRule

	fileScanner := bufio.NewScanner(file)
	for fileScanner.Scan() {
		line := strings.TrimSpace(fileScanner.Text())
		if strings.HasPrefix(line, "#") {
			continue
		}

		idVendor := getValueForProperty(line, idVendorKey)
		idProduct := getValueForProperty(line, idProductKey)
		runCommand := getValueForProperty(line, runKey)
		if "" == idVendor || "" == idProduct || !strings.Contains(runCommand, fmt.Sprintf("--run-job='%s'", job.Name)) {
			continue
		}

		rules = append(rules, NewUdevRule(idVendor, idProduct, runCommand, filePath))
	}

	return rules
}

func getValueForProperty(line string, key string) string {
	propertyKeyIndex := strings.Index(line, key)
	if -1 == propertyKeyIndex {
		return ""
	}
	propertyValueIndex := propertyKeyIndex + len(key) + strings.Index(line[propertyKeyIndex+len(key):], "\"") + 1 // chop off leading quotation

	propertyValueEndIndex := propertyValueIndex + strings.Index(line[propertyValueIndex:], "\"")
	if 0 > propertyValueEndIndex {
		return ""
	}

	return line[propertyValueIndex:propertyValueEndIndex]
}
<commit_msg>remove unneeded log<commit_after>//+build linux
package triggers

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/jamesrr39/taskrunner-app/taskrunner"
)

const (
	idVendorKey  = "ATTRS{idVendor}=="
	idProductKey = "ATTRS{idProduct}=="
	runKey       = "RUN+="
)

type UdevRulesDAL struct {
	BaseDir string // /etc/udev/rules.d
}

func NewUdevRulesDAL(baseDir string) *UdevRulesDAL {
	return &UdevRulesDAL{baseDir}
}

type UdevRule struct {
	IdVendor      string
	IdProduct     string
	Run           string
	FileDefinedIn string
}

func NewUdevRule(idVendor, idProduct, run, fileDefinedIn string) *UdevRule {
	return &UdevRule{idVendor, idProduct, run, fileDefinedIn}
}

func (u *UdevRulesDAL) GetRules(job *taskrunner.Job) ([]*UdevRule, error) {
	var rules []*UdevRule

	err := filepath.Walk(u.BaseDir, func(path string, fileInfo os.FileInfo, err error) error {
		if nil != err {
			return err
		}

		if fileInfo.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if nil != err {
			return err
		}
		defer file.Close()

		rules = append(rules, rulesFromFile(file, path, job)...)
		return nil
	})

	if nil != err {
		return nil, err
	}

	return rules, nil
}

func rulesFromFile(file io.Reader, filePath string, job *taskrunner.Job) []*UdevRule {
	var rules []*UdevRule

	fileScanner := bufio.NewScanner(file)
	for fileScanner.Scan() {
		line := strings.TrimSpace(fileScanner.Text())
		if strings.HasPrefix(line, "#") {
			continue
		}

		idVendor := getValueForProperty(line, idVendorKey)
		idProduct := getValueForProperty(line, idProductKey)
		runCommand := getValueForProperty(line, runKey)
		if "" == idVendor || "" == idProduct || !strings.Contains(runCommand, fmt.Sprintf("--run-job='%s'", job.Name)) {
			continue
		}

		rules = append(rules, NewUdevRule(idVendor, idProduct, runCommand, filePath))
	}

	return rules
}

func getValueForProperty(line string, key string) string {
	propertyKeyIndex := strings.Index(line, key)
	if -1 == propertyKeyIndex {
		return ""
	}
	propertyValueIndex := propertyKeyIndex + len(key) + strings.Index(line[propertyKeyIndex+len(key):], "\"") + 1 // chop off leading quotation

	propertyValueEndIndex := propertyValueIndex + strings.Index(line[propertyValueIndex:], "\"")
	if 0 > propertyValueEndIndex {
		return ""
	}

	return line[propertyValueIndex:propertyValueEndIndex]
}
<|endoftext|>


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

package objectserver

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path/filepath"
	"time"

	"go.uber.org/zap"

	"github.com/troubling/hummingbird/common/fs"
	"github.com/troubling/hummingbird/common/ring"
	"github.com/uber-go/tally"
)

const nurseryObjectSleep = 10 * time.Millisecond

type nurseryDevice struct {
	r         *Replicator
	passStart time.Time
	dev       *ring.Device
	policy    int
	oring     ring.Ring
	canchan   chan struct{}
	objEngine NurseryObjectEngine

	stabilizationAttemptsMetric         tally.Counter
	stabilizationSuccessesMetric        tally.Counter
	stabilizationFailuresMetric         tally.Counter
	stabilizationLastPassCountMetric    tally.Gauge
	stabilizationLastPassDurationMetric tally.Timer
}

type PriorityReplicationResult struct {
	ObjectsReplicated int64
	ObjectsErrored    int64
	Success           bool
	ErrorMsg          string
}

func (nrd *nurseryDevice) UpdateStat(stat string, amount int64) {
	nrd.r.updateStat <- statUpdate{nrd.Type(), nrd.Key(), stat, amount}
}

func (nrd *nurseryDevice) Scan() {
	nrd.UpdateStat("startRun", 1)
	if mounted, err := fs.IsMount(filepath.Join(nrd.r.deviceRoot, nrd.dev.Device)); nrd.r.checkMounts && (err != nil || mounted != true) {
		nrd.r.logger.Error("[stabilizeDevice] Drive not mounted", zap.String("Device", nrd.dev.Device), zap.Error(err))
		return
	}
	start := time.Now()
	c := make(chan ObjectStabilizer, 100)
	cancel := make(chan struct{})
	defer close(cancel)
	go nrd.objEngine.GetObjectsToStabilize(nrd.dev.Device, c, cancel)
	count := 0
	for o := range c {
		count++
		nrd.stabilizationAttemptsMetric.Inc(1)
		nrd.UpdateStat("checkin", 1)
		func() {
			nrd.r.nurseryConcurrencySem <- struct{}{}
			defer func() {
				<-nrd.r.nurseryConcurrencySem
			}()
			if err := o.Stabilize(nrd.dev); err == nil {
				nrd.stabilizationSuccessesMetric.Inc(1)
				nrd.UpdateStat("ObjectsStabilizedSuccess", 1)
				nrd.UpdateStat("ObjectsStabilizedBytes", o.ContentLength())
			} else {
				nrd.stabilizationFailuresMetric.Inc(1)
				nrd.r.logger.Debug("[stabilizeDevice] error Stabilize obj", zap.String("Object", o.Repr()), zap.Error(err))
				nrd.UpdateStat("ObjectsStabilizedError", 1)
			}
		}()
		select {
		case <-time.After(nurseryObjectSleep):
		case <-nrd.canchan:
			return
		}
	}
	nrd.stabilizationLastPassCountMetric.Update(float64(count))
	// We don't use Tally's Timer Start().Stop() since we don't want to record canceled passes.
	nrd.stabilizationLastPassDurationMetric.Record(time.Since(start))
	nrd.UpdateStat("PassComplete", 1)
	nrd.r.logger.Info("[stabilizeDevice] Pass complete.")
}

func (nrd *nurseryDevice) ScanLoop() {
	for {
		select {
		case <-nrd.canchan:
			return
		default:
			nrd.Scan()
			time.Sleep(10 * time.Second)
		}
	}
}

func (nrd *nurseryDevice) Cancel() {
	close(nrd.canchan)
}

func (nrd *nurseryDevice) Key() string {
	return deviceKeyId(nrd.dev.Device, nrd.policy)
}

func (nrd *nurseryDevice) Type() string {
	return "object-nursery"
}

func (nrd *nurseryDevice) PriorityReplicate(w http.ResponseWriter, pri PriorityRepJob) {
	objc := make(chan ObjectStabilizer)
	canchan := make(chan struct{})

	go nrd.objEngine.GetObjectsToReplicate(pri, objc, canchan)
	//TODO: add concurrency to this
	w.WriteHeader(http.StatusOK)
	t := time.Now()
	prr := PriorityReplicationResult{}
	for o := range objc {
		if err := o.Replicate(pri); err != nil {
			nrd.r.logger.Error("error prirep Replicate", zap.Error(err))
			prr.ObjectsErrored++
			nrd.UpdateStat("ObjectsReplicatedError", 1)
		} else {
			prr.ObjectsReplicated++
			nrd.UpdateStat("ObjectsReplicatedSuccess", 1)
			nrd.UpdateStat("ObjectsReplicatedBytes", o.ContentLength())
			if time.Since(t) > time.Minute {
				w.Write([]byte(" "))
				t = time.Now()
			}
		}
	}
	prr.Success = prr.ObjectsErrored == 0
	if !prr.Success {
		prr.ErrorMsg = fmt.Sprintf("%d objects failed to replicate", prr.ObjectsErrored)
	}
	b, err := json.Marshal(prr)
	if err != nil {
		nrd.r.logger.Error("error prirep jsoning", zap.Error(err))
		b = []byte("There was an internal server error generating JSON.")
	}
	w.Write(b)
	w.Write([]byte("\n"))
	nrd.UpdateStat("PriorityRepsDone", 1)
}

func GetNurseryDevice(oring ring.Ring, dev *ring.Device, policy int, r *Replicator, f NurseryObjectEngine) (ReplicationDevice, error) {
	nrd := &nurseryDevice{
		r:         r,
		dev:       dev,
		policy:    policy,
		oring:     oring,
		passStart: time.Now(),
		canchan:   make(chan struct{}),
		objEngine: f,
	}
	nrd.stabilizationAttemptsMetric = r.metricsScope.Counter(dev.Device + "_stabilization_attempts")
	nrd.stabilizationSuccessesMetric = r.metricsScope.Counter(dev.Device + "_stabilization_successes")
	nrd.stabilizationFailuresMetric = r.metricsScope.Counter(dev.Device + "_stabilization_failures")
	nrd.stabilizationLastPassCountMetric = r.metricsScope.Gauge(dev.Device + "_stabilization_last_pass_count")
	nrd.stabilizationLastPassDurationMetric = r.metricsScope.Timer(dev.Device + "_stabilization_last_pass_duration")
	return nrd, nil
}
<commit_msg>Updated to include policy in metrics<commit_after>//  Copyright (c) 2015 Rackspace
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//  implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package objectserver

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path/filepath"
	"time"

	"go.uber.org/zap"

	"github.com/troubling/hummingbird/common/fs"
	"github.com/troubling/hummingbird/common/ring"
	"github.com/uber-go/tally"
)

const nurseryObjectSleep = 10 * time.Millisecond

type nurseryDevice struct {
	r         *Replicator
	passStart time.Time
	dev       *ring.Device
	policy    int
	oring     ring.Ring
	canchan   chan struct{}
	objEngine NurseryObjectEngine

	stabilizationAttemptsMetric         tally.Counter
	stabilizationSuccessesMetric        tally.Counter
	stabilizationFailuresMetric         tally.Counter
	stabilizationLastPassCountMetric    tally.Gauge
	stabilizationLastPassDurationMetric tally.Timer
}

type PriorityReplicationResult struct {
	ObjectsReplicated int64
	ObjectsErrored    int64
	Success           bool
	ErrorMsg          string
}

func (nrd *nurseryDevice) UpdateStat(stat string, amount int64) {
	nrd.r.updateStat <- statUpdate{nrd.Type(), nrd.Key(), stat, amount}
}

func (nrd *nurseryDevice) Scan() {
	nrd.UpdateStat("startRun", 1)
	if mounted, err := fs.IsMount(filepath.Join(nrd.r.deviceRoot, nrd.dev.Device)); nrd.r.checkMounts && (err != nil || mounted != true) {
		nrd.r.logger.Error("[stabilizeDevice] Drive not mounted", zap.String("Device", nrd.dev.Device), zap.Error(err))
		return
	}
	start := time.Now()
	c := make(chan ObjectStabilizer, 100)
	cancel := make(chan struct{})
	defer close(cancel)
	go nrd.objEngine.GetObjectsToStabilize(nrd.dev.Device, c, cancel)
	count := 0
	for o := range c {
		count++
		nrd.stabilizationAttemptsMetric.Inc(1)
		nrd.UpdateStat("checkin", 1)
		func() {
			nrd.r.nurseryConcurrencySem <- struct{}{}
			defer func() {
				<-nrd.r.nurseryConcurrencySem
			}()
			if err := o.Stabilize(nrd.dev); err == nil {
				nrd.stabilizationSuccessesMetric.Inc(1)
				nrd.UpdateStat("ObjectsStabilizedSuccess", 1)
				nrd.UpdateStat("ObjectsStabilizedBytes", o.ContentLength())
			} else {
				nrd.stabilizationFailuresMetric.Inc(1)
				nrd.r.logger.Debug("[stabilizeDevice] error Stabilize obj", zap.String("Object", o.Repr()), zap.Error(err))
				nrd.UpdateStat("ObjectsStabilizedError", 1)
			}
		}()
		select {
		case <-time.After(nurseryObjectSleep):
		case <-nrd.canchan:
			return
		}
	}
	nrd.stabilizationLastPassCountMetric.Update(float64(count))
	// We don't use Tally's Timer Start().Stop() since we don't want to record canceled passes.
	nrd.stabilizationLastPassDurationMetric.Record(time.Since(start))
	nrd.UpdateStat("PassComplete", 1)
	nrd.r.logger.Info("[stabilizeDevice] Pass complete.")
}

func (nrd *nurseryDevice) ScanLoop() {
	for {
		select {
		case <-nrd.canchan:
			return
		default:
			nrd.Scan()
			time.Sleep(10 * time.Second)
		}
	}
}

func (nrd *nurseryDevice) Cancel() {
	close(nrd.canchan)
}

func (nrd *nurseryDevice) Key() string {
	return deviceKeyId(nrd.dev.Device, nrd.policy)
}

func (nrd *nurseryDevice) Type() string {
	return "object-nursery"
}

func (nrd *nurseryDevice) PriorityReplicate(w http.ResponseWriter, pri PriorityRepJob) {
	objc := make(chan ObjectStabilizer)
	canchan := make(chan struct{})

	go nrd.objEngine.GetObjectsToReplicate(pri, objc, canchan)
	//TODO: add concurrency to this
	w.WriteHeader(http.StatusOK)
	t := time.Now()
	prr := PriorityReplicationResult{}
	for o := range objc {
		if err := o.Replicate(pri); err != nil {
			nrd.r.logger.Error("error prirep Replicate", zap.Error(err))
			prr.ObjectsErrored++
			nrd.UpdateStat("ObjectsReplicatedError", 1)
		} else {
			prr.ObjectsReplicated++
			nrd.UpdateStat("ObjectsReplicatedSuccess", 1)
			nrd.UpdateStat("ObjectsReplicatedBytes", o.ContentLength())
			if time.Since(t) > time.Minute {
				w.Write([]byte(" "))
				t = time.Now()
			}
		}
	}
	prr.Success = prr.ObjectsErrored == 0
	if !prr.Success {
		prr.ErrorMsg = fmt.Sprintf("%d objects failed to replicate", prr.ObjectsErrored)
	}
	b, err := json.Marshal(prr)
	if err != nil {
		nrd.r.logger.Error("error prirep jsoning", zap.Error(err))
		b = []byte("There was an internal server error generating JSON.")
	}
	w.Write(b)
	w.Write([]byte("\n"))
	nrd.UpdateStat("PriorityRepsDone", 1)
}

func GetNurseryDevice(oring ring.Ring, dev *ring.Device, policy int, r *Replicator, f NurseryObjectEngine) (ReplicationDevice, error) {
	nrd := &nurseryDevice{
		r:         r,
		dev:       dev,
		policy:    policy,
		oring:     oring,
		passStart: time.Now(),
		canchan:   make(chan struct{}),
		objEngine: f,
	}
	nrd.stabilizationAttemptsMetric = r.metricsScope.Counter(fmt.Sprintf("%d_%s_stabilization_attempts", policy, dev.Device))
	nrd.stabilizationSuccessesMetric = r.metricsScope.Counter(fmt.Sprintf("%d_%s_stabilization_successes", policy, dev.Device))
	nrd.stabilizationFailuresMetric = r.metricsScope.Counter(fmt.Sprintf("%d_%s_stabilization_failures", policy, dev.Device))
	nrd.stabilizationLastPassCountMetric = r.metricsScope.Gauge(fmt.Sprintf("%d_%s_stabilization_last_pass_count", policy, dev.Device))
	nrd.stabilizationLastPassDurationMetric = r.metricsScope.Timer(fmt.Sprintf("%d_%s_stabilization_last_pass_duration", policy, dev.Device))
	return nrd, nil
}
<|endoftext|>