<commit_before>package editor

import (
	"github.com/elpinal/coco3/editor/register"
	"github.com/elpinal/coco3/screen"
)

type visual struct {
	nvCommon

	start int
}

func newVisual(s streamSet, e *editor) *visual {
	return &visual{
		nvCommon: nvCommon{
			streamSet: s,
			editor:    e,
		},

		start: e.pos,
	}
}

func (v *visual) Mode() mode {
	return modeVisual
}

func (v *visual) Runes() []rune {
	return v.buf
}

func (v *visual) Position() int {
	return v.pos
}

func (v *visual) Message() []rune {
	return []rune("-- VISUAL --")
}

func (v *visual) Highlight() *screen.Hi {
	return &screen.Hi{
		Left:  min(v.start, v.pos),
		Right: constrain(max(v.start, v.pos)+1, 0, len(v.buf)),
	}
}

func (v *visual) Run() (end continuity, next modeChanger, err error) {
	r, _, err := v.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	for ('1' <= r && r <= '9') || (v.count != 0 && r == '0') {
		v.count = v.count*10 + int(r-'0')
		r1, _, err := v.streamSet.in.ReadRune()
		if err != nil {
			return end, next, err
		}
		r = r1
	}
	if v.count == 0 {
		v.count = 1
	}
	cmd, ok := visualCommands[r]
	if !ok {
		return
	}
	if m := cmd(v); m != nil {
		next = m
	}
	if v.pos == len(v.buf) {
		v.move(v.pos - 1)
	}
	v.count = 0
	return
}

type visualCommand = func(*visual) modeChanger

var visualCommands = map[rune]visualCommand{
	CharEscape: (*visual).escape,
	CharCtrlC:  (*visual).escape,
	'$':        (*visual).endline,
	'0':        (*visual).beginline,
	'B':        (*visual).wordBack,
	'E':        (*visual).wordEndNonBlank,
	'F':        (*visual).searchCharacterBackward,
	'U':        (*visual).toUpper,
	'W':        (*visual).wordNonBlank,
	'b':        (*visual).wordBack,
	'c':        (*visual).change,
	'd':        (*visual).delete,
	'e':        (*visual).wordEnd,
	'f':        (*visual).searchCharacter,
	'h':        (*visual).left,
	'l':        (*visual).right,
	'r':        (*visual).replace,
	'o':        (*visual).swap,
	'u':        (*visual).toLower,
	'v':        (*visual).escape,
	'w':        (*visual).word,
	'y':        (*visual).yank,
}

func (v *visual) escape() modeChanger {
	return norm()
}

func (v *visual) delete() modeChanger {
	hi := v.Highlight()
	v.nvCommon.delete(hi.Left, hi.Right)
	return norm()
}

func (v *visual) change() modeChanger {
	_ = v.delete()
	return ins(v.pos == len(v.buf))
}

func (v *visual) swap() (_ modeChanger) {
	v.start, v.pos = v.pos, v.start
	return
}

func (v *visual) yank() modeChanger {
	hi := v.Highlight()
	v.nvCommon.yank(register.Unnamed, hi.Left, hi.Right)
	v.move(hi.Left)
	return norm()
}

func (v *visual) replace() modeChanger {
	r, _, _ := v.in.ReadRune()
	hi := v.Highlight()
	rs := make([]rune, hi.Right-hi.Left)
	for i := range rs {
		rs[i] = r
	}
	v.nvCommon.replace(rs, hi.Left)
	return norm()
}

func (v *visual) toUpper() modeChanger {
	hi := v.Highlight()
	v.nvCommon.toUpper(hi.Left, hi.Right)
	return norm()
}

func (v *visual) toLower() modeChanger {
	hi := v.Highlight()
	v.nvCommon.toLower(hi.Left, hi.Right)
	return norm()
}

func (v *visual) wordEnd() (_ modeChanger) {
	for i := 0; i < v.count; i++ {
		v.nvCommon.wordEnd()
	}
	return
}

func (v *visual) wordEndNonBlank() (_ modeChanger) {
	for i := 0; i < v.count; i++ {
		v.nvCommon.wordEndNonBlank()
	}
	return
}
<commit_msg>Support v_I<commit_after>package editor

import (
	"github.com/elpinal/coco3/editor/register"
	"github.com/elpinal/coco3/screen"
)

type visual struct {
	nvCommon

	start int
}

func newVisual(s streamSet, e *editor) *visual {
	return &visual{
		nvCommon: nvCommon{
			streamSet: s,
			editor:    e,
		},

		start: e.pos,
	}
}

func (v *visual) Mode() mode {
	return modeVisual
}

func (v *visual) Runes() []rune {
	return v.buf
}

func (v *visual) Position() int {
	return v.pos
}

func (v *visual) Message() []rune {
	return []rune("-- VISUAL --")
}

func (v *visual) Highlight() *screen.Hi {
	return &screen.Hi{
		Left:  min(v.start, v.pos),
		Right: constrain(max(v.start, v.pos)+1, 0, len(v.buf)),
	}
}

func (v *visual) Run() (end continuity, next modeChanger, err error) {
	r, _, err := v.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	for ('1' <= r && r <= '9') || (v.count != 0 && r == '0') {
		v.count = v.count*10 + int(r-'0')
		r1, _, err := v.streamSet.in.ReadRune()
		if err != nil {
			return end, next, err
		}
		r = r1
	}
	if v.count == 0 {
		v.count = 1
	}
	cmd, ok := visualCommands[r]
	if !ok {
		return
	}
	if m := cmd(v); m != nil {
		next = m
	}
	if v.pos == len(v.buf) {
		v.move(v.pos - 1)
	}
	v.count = 0
	return
}

type visualCommand = func(*visual) modeChanger

var visualCommands = map[rune]visualCommand{
	CharEscape: (*visual).escape,
	CharCtrlC:  (*visual).escape,
	'$':        (*visual).endline,
	'0':        (*visual).beginline,
	'B':        (*visual).wordBack,
	'E':        (*visual).wordEndNonBlank,
	'F':        (*visual).searchCharacterBackward,
	'I':        (*visual).insertBefore,
	'U':        (*visual).toUpper,
	'W':        (*visual).wordNonBlank,
	'b':        (*visual).wordBack,
	'c':        (*visual).change,
	'd':        (*visual).delete,
	'e':        (*visual).wordEnd,
	'f':        (*visual).searchCharacter,
	'h':        (*visual).left,
	'l':        (*visual).right,
	'r':        (*visual).replace,
	'o':        (*visual).swap,
	'u':        (*visual).toLower,
	'v':        (*visual).escape,
	'w':        (*visual).word,
	'y':        (*visual).yank,
}

func (v *visual) escape() modeChanger {
	return norm()
}

func (v *visual) delete() modeChanger {
	hi := v.Highlight()
	v.nvCommon.delete(hi.Left, hi.Right)
	return norm()
}

func (v *visual) change() modeChanger {
	_ = v.delete()
	return ins(v.pos == len(v.buf))
}

func (v *visual) swap() (_ modeChanger) {
	v.start, v.pos = v.pos, v.start
	return
}

func (v *visual) yank() modeChanger {
	hi := v.Highlight()
	v.nvCommon.yank(register.Unnamed, hi.Left, hi.Right)
	v.move(hi.Left)
	return norm()
}

func (v *visual) replace() modeChanger {
	r, _, _ := v.in.ReadRune()
	hi := v.Highlight()
	rs := make([]rune, hi.Right-hi.Left)
	for i := range rs {
		rs[i] = r
	}
	v.nvCommon.replace(rs, hi.Left)
	return norm()
}

func (v *visual) toUpper() modeChanger {
	hi := v.Highlight()
	v.nvCommon.toUpper(hi.Left, hi.Right)
	return norm()
}

func (v *visual) toLower() modeChanger {
	hi := v.Highlight()
	v.nvCommon.toLower(hi.Left, hi.Right)
	return norm()
}

func (v *visual) wordEnd() (_ modeChanger) {
	for i := 0; i < v.count; i++ {
		v.nvCommon.wordEnd()
	}
	return
}

func (v *visual) wordEndNonBlank() (_ modeChanger) {
	for i := 0; i < v.count; i++ {
		v.nvCommon.wordEndNonBlank()
	}
	return
}

func (v *visual) insertBefore() modeChanger {
	v.move(v.Highlight().Left)
	return ins(v.pos == len(v.buf))
}
<|endoftext|>


<commit_before>package metadata

/*****************************************
 * This file was generated by SalsaFlow. *
 * Please do not modify it manually.     *
 *****************************************/

const Version = "0.5.0"
<commit_msg>Bump version to 0.6.0<commit_after>package metadata

/*****************************************
 * This file was generated by SalsaFlow. *
 * Please do not modify it manually.     *
 *****************************************/

const Version = "0.6.0"
<|endoftext|>


<commit_before>package operations

import (
	"hash/crc32"

	"github.com/rameshvarun/ups/common"
)

// Diff takes in a base buffer, a modified buffer, and returns a PatchData object
// that can be used to write to a UPS file.
func Diff(base []byte, modified []byte) *common.PatchData {
	// Cumulative list of blocks that we construct as we scan through the buffers.
	var blocks []common.PatchBlock

	// The end position of the last patch block that we saw.
	lastBlock := uint64(0)
	// The current block that we are constructing. `nil` if there is no current block.
	var currentBlock *struct {
		Data  []byte
		Start uint64
	}

	for pointer := 0; pointer < len(modified); pointer++ {
		// Determine if the byte has been 'modified'
		var different bool
		if pointer >= len(base) {
			// If the output file is larger than the input, and the byte in this extended
			// region is non-zero, then it is 'modified'
			different = modified[pointer] != 0
		} else {
			// Otherwise, simply check if the byte is different.
			different = modified[pointer] != base[pointer]
		}

		if different {
			// If the current byte is modified, but we are not constructing a block,
			// we need to create an in-progress block, then add in the data.
			if currentBlock == nil {
				currentBlock = &struct {
					Data  []byte
					Start uint64
				}{
					Data:  []byte{},
					Start: uint64(pointer),
				}
			}

			// If we are constructing an in-progress block, just add in the data.
			if currentBlock != nil {
				if pointer >= len(base) {
					currentBlock.Data = append(currentBlock.Data, modified[pointer])
				} else {
					currentBlock.Data = append(currentBlock.Data, base[pointer]^modified[pointer])
				}
			}
		} else {
			if currentBlock != nil {
				// This block has ended.
				blocks = append(blocks, common.PatchBlock{
					Data:           currentBlock.Data,
					RelativeOffset: currentBlock.Start - lastBlock,
				})
				currentBlock = nil

				// lastBlock needs to point to the byte after the unmodified byte that ended
				// the block.
				lastBlock = uint64(pointer) + 1
			}
		}
	}

	// Return the full patch data structure.
	return &common.PatchData{
		InputFileSize:  uint64(len(base)),
		OutputFileSize: uint64(len(modified)),
		PatchBlocks:    blocks,
		InputChecksum:  crc32.ChecksumIEEE(base),
		OutputChecksum: crc32.ChecksumIEEE(modified),
	}
}
<commit_msg>Fixes an edge case when creating a diff.<commit_after>package operations

import (
	"hash/crc32"

	"github.com/rameshvarun/ups/common"
)

// Diff takes in a base buffer, a modified buffer, and returns a PatchData object
// that can be used to write to a UPS file.
func Diff(base []byte, modified []byte) *common.PatchData {
	// Cumulative list of blocks that we construct as we scan through the buffers.
	var blocks []common.PatchBlock

	// The end position of the last patch block that we saw.
	lastBlock := uint64(0)
	// The current block that we are constructing. `nil` if there is no current block.
	var currentBlock *struct {
		Data  []byte
		Start uint64
	}

	for pointer := 0; pointer < len(modified); pointer++ {
		// Determine if the byte has been 'modified'
		var different bool
		if pointer >= len(base) {
			// If the output file is larger than the input, and the byte in this extended
			// region is non-zero, then it is 'modified'
			different = modified[pointer] != 0
		} else {
			// Otherwise, simply check if the byte is different.
			different = modified[pointer] != base[pointer]
		}

		if different {
			// If the current byte is modified, but we are not constructing a block,
			// we need to create an in-progress block, then add in the data.
			if currentBlock == nil {
				currentBlock = &struct {
					Data  []byte
					Start uint64
				}{
					Data:  []byte{},
					Start: uint64(pointer),
				}
			}

			// If we are constructing an in-progress block, just add in the data.
			if currentBlock != nil {
				if pointer >= len(base) {
					currentBlock.Data = append(currentBlock.Data, modified[pointer])
				} else {
					currentBlock.Data = append(currentBlock.Data, base[pointer]^modified[pointer])
				}
			}
		} else {
			if currentBlock != nil {
				// This block has ended.
				blocks = append(blocks, common.PatchBlock{
					Data:           currentBlock.Data,
					RelativeOffset: currentBlock.Start - lastBlock,
				})
				currentBlock = nil

				// lastBlock needs to point to the byte after the unmodified byte that ended
				// the block.
				lastBlock = uint64(pointer) + 1
			}
		}
	}

	// If we ended the loop on a block, then we need to end that block.
	if currentBlock != nil {
		blocks = append(blocks, common.PatchBlock{
			Data:           currentBlock.Data,
			RelativeOffset: currentBlock.Start - lastBlock,
		})
	}

	// Return the full patch data structure.
	return &common.PatchData{
		InputFileSize:  uint64(len(base)),
		OutputFileSize: uint64(len(modified)),
		PatchBlocks:    blocks,
		InputChecksum:  crc32.ChecksumIEEE(base),
		OutputChecksum: crc32.ChecksumIEEE(modified),
	}
}
<|endoftext|>


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

// MerkleAudit runs a merkle tree audit in the background once in a while.
// It verifies the skips of a randomly chosen merkle tree root, making
// sure that the server is not tampering with the merkle trees.

package engine

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"sync"
	"time"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

var MerkleAuditSettings = BackgroundTaskSettings{
	Start:        5 * time.Minute,
	StartStagger: 1 * time.Hour,
	Interval:     6 * time.Hour,
	Limit:        1 * time.Minute,
}

// MerkleAudit is an engine.
type MerkleAudit struct {
	libkb.Contextified
	sync.Mutex

	args *MerkleAuditArgs
	task *BackgroundTask
}

type MerkleAuditArgs struct {
	// Channels used for testing. Normally nil.
	testingMetaCh     chan<- string
	testingRoundResCh chan<- error
}

// NewMerkleAudit creates a new MerkleAudit engine.
func NewMerkleAudit(g *libkb.GlobalContext, args *MerkleAuditArgs) *MerkleAudit {
	task := NewBackgroundTask(g, &BackgroundTaskArgs{
		Name:     "MerkleAudit",
		F:        MerkleAuditRound,
		Settings: MerkleAuditSettings,

		testingMetaCh:     args.testingMetaCh,
		testingRoundResCh: args.testingRoundResCh,
	})
	return &MerkleAudit{
		Contextified: libkb.NewContextified(g),
		args:         args,
		task:         task,
	}
}

// Name is the unique engine name.
func (e *MerkleAudit) Name() string {
	return "MerkleAudit"
}

// GetPrereqs returns the engine prereqs.
func (e *MerkleAudit) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *MerkleAudit) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *MerkleAudit) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{}
}

// Run starts the engine.
// Returns immediately, kicks off a background goroutine.
func (e *MerkleAudit) Run(m libkb.MetaContext) (err error) {
	return RunEngine2(m, e.task)
}

func (e *MerkleAudit) Shutdown() {
	e.task.Shutdown()
}

// randSeqno picks a random number between [low, high).
func randSeqno(lo keybase1.Seqno, hi keybase1.Seqno) (keybase1.Seqno, error) {
	rangeBig := big.NewInt(int64(hi - lo))
	n, err := rand.Int(rand.Reader, rangeBig)
	if err != nil {
		return keybase1.Seqno(0), err
	}
	return keybase1.Seqno(n.Int64()) + lo, nil
}

func MerkleAuditRound(m libkb.MetaContext) error {
	if m.G().ConnectivityMonitor.IsConnected(m.Ctx()) == libkb.ConnectivityMonitorNo {
		m.CDebugf("MerkleAudit giving up offline")
		return nil
	}

	// Figure out the first merkle root seqno with skips, fall back to 1
	firstSeqno := m.G().MerkleClient.FirstSeqnoWithSkips(m)
	if firstSeqno == nil {
		val := keybase1.Seqno(1)
		firstSeqno = &val
	}

	// Acquire the most recent merkle tree root
	lastRoot := m.G().MerkleClient.LastRoot()
	if lastRoot == nil {
		m.CDebugf("MerkleAudit unable to retrieve the last root")
		return nil
	}

	// We can copy the pointer's value as it can only return nil if root == nil.
	lastSeqno := *lastRoot.Seqno()

	// Generate a random seqno for the starting root in the audit.
	startSeqno, err := randSeqno(*firstSeqno, lastSeqno)
	if err != nil {
		return err
	}

	// Acquire the first root and calculate its hash
	startRoot, err := m.G().MerkleClient.LookupRootAtSeqno(m, startSeqno)
	if err != nil {
		return err
	}
	startHash := startRoot.ShortHash()

	// Traverse the merkle tree seqnos
	currentSeqno := startSeqno + 1
	step := 1
	for {
		// Proceed until the last known root
		if currentSeqno > lastSeqno {
			break
		}

		currentRoot, err := m.G().MerkleClient.LookupRootAtSeqno(m, currentSeqno)
		if err != nil {
			return err
		}
		currentHash := currentRoot.SkipToSeqno(startSeqno)

		if !startHash.Eq(currentHash) {
			// Warn the user about the possibility of the server tampering with the roots.
			return fmt.Errorf("Skip of %d to %d broken", currentSeqno, startSeqno)
		}

		// We're doing this exponentially to make use of the skips.
		currentSeqno += keybase1.Seqno(step)
		step *= 2
	}

	return nil
}
<commit_msg>Custom error type for merkle root audit failure path<commit_after>// Copyright 2019 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// MerkleAudit runs a merkle tree audit in the background once in a while.
// It verifies the skips of a randomly chosen merkle tree root, making
// sure that the server is not tampering with the merkle trees.

package engine

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"sync"
	"time"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

var MerkleAuditSettings = BackgroundTaskSettings{
	Start:        5 * time.Minute,
	StartStagger: 1 * time.Hour,
	Interval:     6 * time.Hour,
	Limit:        1 * time.Minute,
}

// MerkleAudit is an engine.
type MerkleAudit struct {
	libkb.Contextified
	sync.Mutex

	args *MerkleAuditArgs
	task *BackgroundTask
}

type MerkleAuditArgs struct {
	// Channels used for testing. Normally nil.
	testingMetaCh     chan<- string
	testingRoundResCh chan<- error
}

type merkleAuditError struct {
	from keybase1.Seqno
	to   keybase1.Seqno
}

func (m merkleAuditError) Error() string {
	return fmt.Sprintf("Skip of %d to %d might have been tampered with", m.from, m.to)
}

// NewMerkleAudit creates a new MerkleAudit engine.
func NewMerkleAudit(g *libkb.GlobalContext, args *MerkleAuditArgs) *MerkleAudit {
	task := NewBackgroundTask(g, &BackgroundTaskArgs{
		Name:     "MerkleAudit",
		F:        MerkleAuditRound,
		Settings: MerkleAuditSettings,

		testingMetaCh:     args.testingMetaCh,
		testingRoundResCh: args.testingRoundResCh,
	})
	return &MerkleAudit{
		Contextified: libkb.NewContextified(g),
		args:         args,
		task:         task,
	}
}

// Name is the unique engine name.
func (e *MerkleAudit) Name() string {
	return "MerkleAudit"
}

// GetPrereqs returns the engine prereqs.
func (e *MerkleAudit) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *MerkleAudit) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *MerkleAudit) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{}
}

// Run starts the engine.
// Returns immediately, kicks off a background goroutine.
func (e *MerkleAudit) Run(m libkb.MetaContext) (err error) {
	return RunEngine2(m, e.task)
}

func (e *MerkleAudit) Shutdown() {
	e.task.Shutdown()
}

// randSeqno picks a random number between [low, high).
func randSeqno(lo keybase1.Seqno, hi keybase1.Seqno) (keybase1.Seqno, error) {
	rangeBig := big.NewInt(int64(hi - lo))
	n, err := rand.Int(rand.Reader, rangeBig)
	if err != nil {
		return keybase1.Seqno(0), err
	}
	return keybase1.Seqno(n.Int64()) + lo, nil
}

func MerkleAuditRound(m libkb.MetaContext) error {
	if m.G().ConnectivityMonitor.IsConnected(m.Ctx()) == libkb.ConnectivityMonitorNo {
		m.CDebugf("MerkleAudit giving up offline")
		return nil
	}

	// Figure out the first merkle root seqno with skips, fall back to 1
	firstSeqno := m.G().MerkleClient.FirstSeqnoWithSkips(m)
	if firstSeqno == nil {
		val := keybase1.Seqno(1)
		firstSeqno = &val
	}

	// Acquire the most recent merkle tree root
	lastRoot := m.G().MerkleClient.LastRoot()
	if lastRoot == nil {
		m.CDebugf("MerkleAudit unable to retrieve the last root")
		return nil
	}

	// We can copy the pointer's value as it can only return nil if root == nil.
	lastSeqno := *lastRoot.Seqno()

	// Generate a random seqno for the starting root in the audit.
	startSeqno, err := randSeqno(*firstSeqno, lastSeqno)
	if err != nil {
		return err
	}

	// Acquire the first root and calculate its hash
	startRoot, err := m.G().MerkleClient.LookupRootAtSeqno(m, startSeqno)
	if err != nil {
		return err
	}
	startHash := startRoot.ShortHash()

	// Traverse the merkle tree seqnos
	currentSeqno := startSeqno + 1
	step := 1
	for {
		// Proceed until the last known root
		if currentSeqno > lastSeqno {
			break
		}

		currentRoot, err := m.G().MerkleClient.LookupRootAtSeqno(m, currentSeqno)
		if err != nil {
			return err
		}
		currentHash := currentRoot.SkipToSeqno(startSeqno)

		if !startHash.Eq(currentHash) {
			// Warn the user about the possibility of the server tampering with the roots.
			return merkleAuditError{
				from: currentSeqno,
				to:   startSeqno,
			}
		}

		// We're doing this exponentially to make use of the skips.
		currentSeqno += keybase1.Seqno(step)
		step *= 2
	}

	return nil
}
<|endoftext|>


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

package otlpexporter

import (
	"context"
	"errors"
	"sync"
	"time"

	"github.com/cenkalti/backoff"
	"google.golang.org/genproto/googleapis/rpc/errdetails"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	otlpmetriccol "go.opentelemetry.io/collector/internal/data/opentelemetry-proto-gen/collector/metrics/v1"
	otlptracecol "go.opentelemetry.io/collector/internal/data/opentelemetry-proto-gen/collector/trace/v1"
	otlplogcol "go.opentelemetry.io/collector/internal/data/opentelemetry-proto-gen/logs/v1"
)

type exporterImp struct {
	// Input configuration.
	config *Config

	stopOnce sync.Once
	w        sender
}

type sender interface {
	exportTrace(ctx context.Context, request *otlptracecol.ExportTraceServiceRequest) error
	exportMetrics(ctx context.Context, request *otlpmetriccol.ExportMetricsServiceRequest) error
	exportLogs(ctx context.Context, request *otlplogcol.ExportLogServiceRequest) error
	stop() error
}

var (
	errTimeout    = errors.New("timeout")
	errFatalError = errors.New("fatal error sending to server")
)

// Crete new exporter and start it. The exporter will begin connecting but
// this function may return before the connection is established.
func newExporter(config *Config) (*exporterImp, error) {
	e := &exporterImp{}
	e.config = config
	w, err := newGrpcSender(config)
	if err != nil {
		return nil, err
	}
	e.w = w
	return e, nil
}

func (e *exporterImp) stop() error {
	var err error
	e.stopOnce.Do(func() {
		// Close the connection.
		err = e.w.stop()
	})
	return err
}

func (e *exporterImp) exportTrace(ctx context.Context, request *otlptracecol.ExportTraceServiceRequest) error {
	return e.w.exportTrace(ctx, request)
}

func (e *exporterImp) exportMetrics(ctx context.Context, request *otlpmetriccol.ExportMetricsServiceRequest) error {
	return e.w.exportMetrics(ctx, request)
}

func (e *exporterImp) exportLogs(ctx context.Context, request *otlplogcol.ExportLogServiceRequest) error {
	return e.w.exportLogs(ctx, request)
}

type grpcSender struct {
	// gRPC clients and connection.
	traceExporter  otlptracecol.TraceServiceClient
	metricExporter otlpmetriccol.MetricsServiceClient
	logExporter    otlplogcol.LogServiceClient
	grpcClientConn *grpc.ClientConn
	metadata       metadata.MD
	waitForReady   bool
}

func newGrpcSender(config *Config) (sender, error) {
	gs := &grpcSender{}
	dialOpts, err := config.GRPCClientSettings.ToDialOptions()
	if err != nil {
		return nil, err
	}

	if gs.grpcClientConn, err = grpc.Dial(config.GRPCClientSettings.Endpoint, dialOpts...); err != nil {
		return nil, err
	}
	gs.traceExporter = otlptracecol.NewTraceServiceClient(gs.grpcClientConn)
	gs.metricExporter = otlpmetriccol.NewMetricsServiceClient(gs.grpcClientConn)
	gs.logExporter = otlplogcol.NewLogServiceClient(gs.grpcClientConn)
	gs.metadata = metadata.New(config.GRPCClientSettings.Headers)
	return gs, nil
}

func (gs *grpcSender) stop() error {
	return gs.grpcClientConn.Close()
}

func (gs *grpcSender) exportTrace(ctx context.Context, request *otlptracecol.ExportTraceServiceRequest) error {
	return exportRequest(gs.enhanceContext(ctx), func(ctx context.Context) error {
		_, err := gs.traceExporter.Export(ctx, request, grpc.WaitForReady(gs.waitForReady))
		return err
	})
}

func (gs *grpcSender) exportMetrics(ctx context.Context, request *otlpmetriccol.ExportMetricsServiceRequest) error {
	return exportRequest(gs.enhanceContext(ctx), func(ctx context.Context) error {
		_, err := gs.metricExporter.Export(ctx, request, grpc.WaitForReady(gs.waitForReady))
		return err
	})
}

func (gs *grpcSender) exportLogs(ctx context.Context, request *otlplogcol.ExportLogServiceRequest) error {
	return exportRequest(gs.enhanceContext(ctx), func(ctx context.Context) error {
		_, err := gs.logExporter.Export(ctx, request, grpc.WaitForReady(gs.waitForReady))
		return err
	})
}

func (gs *grpcSender) enhanceContext(ctx context.Context) context.Context {
	if gs.metadata.Len() > 0 {
		return metadata.NewOutgoingContext(ctx, gs.metadata)
	}
	return ctx
}

// Send a trace or metrics request to the server. "perform" function is expected to make
// the actual gRPC unary call that sends the request. This function implements the
// common OTLP logic around request handling such as retries and throttling.
func exportRequest(ctx context.Context, perform func(ctx context.Context) error) error {

	expBackoff := backoff.NewExponentialBackOff()

	// Spend max 15 mins on this operation. This is just a reasonable number that
	// gives plenty of time for typical quick transient errors to resolve.
	expBackoff.MaxElapsedTime = time.Minute * 15

	for {
		// Send to server.
		err := perform(ctx)

		if err == nil {
			// Request is successful, we are done.
			return nil
		}

		// We have an error, check gRPC status code.

		status := status.Convert(err)

		statusCode := status.Code()
		if statusCode == codes.OK {
			// Not really an error, still success.
			return nil
		}

		// Now, this is this a real error.

		if !shouldRetry(statusCode) {
			// It is not a retryable error, we should not retry.
			return errFatalError
		}

		// Need to retry.

		// Check if server returned throttling information.
		waitDuration := getThrottleDuration(status)
		if waitDuration == 0 {
			// No explicit throttle duration. Use exponential backoff strategy.
			waitDuration = expBackoff.NextBackOff()
			if waitDuration == backoff.Stop {
				// We run out of max time allocated to this operation.
				return errTimeout
			}
		}

		// Wait until one of the conditions below triggers.
		select {
		case <-ctx.Done():
			// This request is cancelled or timed out.
			return errTimeout

		case <-time.After(waitDuration):
			// Time to try again.
		}
	}
}

func shouldRetry(code codes.Code) bool {
	switch code {
	case codes.OK:
		// Success. This function should not be called for this code, the best we
		// can do is tell the caller not to retry.
		return false

	case codes.Canceled,
		codes.DeadlineExceeded,
		codes.PermissionDenied,
		codes.Unauthenticated,
		codes.ResourceExhausted,
		codes.Aborted,
		codes.OutOfRange,
		codes.Unavailable,
		codes.DataLoss:
		// These are retryable errors.
		return true

	case codes.Unknown,
		codes.InvalidArgument,
		codes.NotFound,
		codes.AlreadyExists,
		codes.FailedPrecondition,
		codes.Unimplemented,
		codes.Internal:
		// These are fatal errors, don't retry.
		return false

	default:
		// Don't retry on unknown codes.
		return false
	}
}

func getThrottleDuration(status *status.Status) time.Duration {
	// See if throttling information is available.
	for _, detail := range status.Details() {
		switch t := detail.(type) {
		case *errdetails.RetryInfo:
			if t.RetryDelay.Seconds > 0 || t.RetryDelay.Nanos > 0 {
				// We are throttled. Wait before retrying as requested by the server.
				return time.Duration(t.RetryDelay.Seconds)*time.Second + time.Duration(t.RetryDelay.Nanos)*time.Nanosecond
			}
			return 0
		}
	}
	return 0
}
<commit_msg>Fix OTLP waitForReady, not set from config (#1254)<commit_after>// Copyright  OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package otlpexporter

import (
	"context"
	"errors"
	"sync"
	"time"

	"github.com/cenkalti/backoff"
	"google.golang.org/genproto/googleapis/rpc/errdetails"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	otlpmetriccol "go.opentelemetry.io/collector/internal/data/opentelemetry-proto-gen/collector/metrics/v1"
	otlptracecol "go.opentelemetry.io/collector/internal/data/opentelemetry-proto-gen/collector/trace/v1"
	otlplogcol "go.opentelemetry.io/collector/internal/data/opentelemetry-proto-gen/logs/v1"
)

type exporterImp struct {
	// Input configuration.
	config *Config

	stopOnce sync.Once
	w        sender
}

type sender interface {
	exportTrace(ctx context.Context, request *otlptracecol.ExportTraceServiceRequest) error
	exportMetrics(ctx context.Context, request *otlpmetriccol.ExportMetricsServiceRequest) error
	exportLogs(ctx context.Context, request *otlplogcol.ExportLogServiceRequest) error
	stop() error
}

var (
	errTimeout    = errors.New("timeout")
	errFatalError = errors.New("fatal error sending to server")
)

// Crete new exporter and start it. The exporter will begin connecting but
// this function may return before the connection is established.
func newExporter(config *Config) (*exporterImp, error) {
	e := &exporterImp{}
	e.config = config
	w, err := newGrpcSender(config)
	if err != nil {
		return nil, err
	}
	e.w = w
	return e, nil
}

func (e *exporterImp) stop() error {
	var err error
	e.stopOnce.Do(func() {
		// Close the connection.
		err = e.w.stop()
	})
	return err
}

func (e *exporterImp) exportTrace(ctx context.Context, request *otlptracecol.ExportTraceServiceRequest) error {
	return e.w.exportTrace(ctx, request)
}

func (e *exporterImp) exportMetrics(ctx context.Context, request *otlpmetriccol.ExportMetricsServiceRequest) error {
	return e.w.exportMetrics(ctx, request)
}

func (e *exporterImp) exportLogs(ctx context.Context, request *otlplogcol.ExportLogServiceRequest) error {
	return e.w.exportLogs(ctx, request)
}

type grpcSender struct {
	// gRPC clients and connection.
	traceExporter  otlptracecol.TraceServiceClient
	metricExporter otlpmetriccol.MetricsServiceClient
	logExporter    otlplogcol.LogServiceClient
	grpcClientConn *grpc.ClientConn
	metadata       metadata.MD
	waitForReady   bool
}

func newGrpcSender(config *Config) (sender, error) {
	dialOpts, err := config.GRPCClientSettings.ToDialOptions()
	if err != nil {
		return nil, err
	}

	var clientConn *grpc.ClientConn
	if clientConn, err = grpc.Dial(config.GRPCClientSettings.Endpoint, dialOpts...); err != nil {
		return nil, err
	}

	gs := &grpcSender{
		traceExporter:  otlptracecol.NewTraceServiceClient(clientConn),
		metricExporter: otlpmetriccol.NewMetricsServiceClient(clientConn),
		logExporter:    otlplogcol.NewLogServiceClient(clientConn),
		grpcClientConn: clientConn,
		metadata:       metadata.New(config.GRPCClientSettings.Headers),
		waitForReady:   config.GRPCClientSettings.WaitForReady,
	}
	return gs, nil
}

func (gs *grpcSender) stop() error {
	return gs.grpcClientConn.Close()
}

func (gs *grpcSender) exportTrace(ctx context.Context, request *otlptracecol.ExportTraceServiceRequest) error {
	return exportRequest(gs.enhanceContext(ctx), func(ctx context.Context) error {
		_, err := gs.traceExporter.Export(ctx, request, grpc.WaitForReady(gs.waitForReady))
		return err
	})
}

func (gs *grpcSender) exportMetrics(ctx context.Context, request *otlpmetriccol.ExportMetricsServiceRequest) error {
	return exportRequest(gs.enhanceContext(ctx), func(ctx context.Context) error {
		_, err := gs.metricExporter.Export(ctx, request, grpc.WaitForReady(gs.waitForReady))
		return err
	})
}

func (gs *grpcSender) exportLogs(ctx context.Context, request *otlplogcol.ExportLogServiceRequest) error {
	return exportRequest(gs.enhanceContext(ctx), func(ctx context.Context) error {
		_, err := gs.logExporter.Export(ctx, request, grpc.WaitForReady(gs.waitForReady))
		return err
	})
}

func (gs *grpcSender) enhanceContext(ctx context.Context) context.Context {
	if gs.metadata.Len() > 0 {
		return metadata.NewOutgoingContext(ctx, gs.metadata)
	}
	return ctx
}

// Send a trace or metrics request to the server. "perform" function is expected to make
// the actual gRPC unary call that sends the request. This function implements the
// common OTLP logic around request handling such as retries and throttling.
func exportRequest(ctx context.Context, perform func(ctx context.Context) error) error {

	expBackoff := backoff.NewExponentialBackOff()

	// Spend max 15 mins on this operation. This is just a reasonable number that
	// gives plenty of time for typical quick transient errors to resolve.
	expBackoff.MaxElapsedTime = time.Minute * 15

	for {
		// Send to server.
		err := perform(ctx)

		if err == nil {
			// Request is successful, we are done.
			return nil
		}

		// We have an error, check gRPC status code.

		status := status.Convert(err)

		statusCode := status.Code()
		if statusCode == codes.OK {
			// Not really an error, still success.
			return nil
		}

		// Now, this is this a real error.

		if !shouldRetry(statusCode) {
			// It is not a retryable error, we should not retry.
			return errFatalError
		}

		// Need to retry.

		// Check if server returned throttling information.
		waitDuration := getThrottleDuration(status)
		if waitDuration == 0 {
			// No explicit throttle duration. Use exponential backoff strategy.
			waitDuration = expBackoff.NextBackOff()
			if waitDuration == backoff.Stop {
				// We run out of max time allocated to this operation.
				return errTimeout
			}
		}

		// Wait until one of the conditions below triggers.
		select {
		case <-ctx.Done():
			// This request is cancelled or timed out.
			return errTimeout

		case <-time.After(waitDuration):
			// Time to try again.
		}
	}
}

func shouldRetry(code codes.Code) bool {
	switch code {
	case codes.OK:
		// Success. This function should not be called for this code, the best we
		// can do is tell the caller not to retry.
		return false

	case codes.Canceled,
		codes.DeadlineExceeded,
		codes.PermissionDenied,
		codes.Unauthenticated,
		codes.ResourceExhausted,
		codes.Aborted,
		codes.OutOfRange,
		codes.Unavailable,
		codes.DataLoss:
		// These are retryable errors.
		return true

	case codes.Unknown,
		codes.InvalidArgument,
		codes.NotFound,
		codes.AlreadyExists,
		codes.FailedPrecondition,
		codes.Unimplemented,
		codes.Internal:
		// These are fatal errors, don't retry.
		return false

	default:
		// Don't retry on unknown codes.
		return false
	}
}

func getThrottleDuration(status *status.Status) time.Duration {
	// See if throttling information is available.
	for _, detail := range status.Details() {
		switch t := detail.(type) {
		case *errdetails.RetryInfo:
			if t.RetryDelay.Seconds > 0 || t.RetryDelay.Nanos > 0 {
				// We are throttled. Wait before retrying as requested by the server.
				return time.Duration(t.RetryDelay.Seconds)*time.Second + time.Duration(t.RetryDelay.Nanos)*time.Nanosecond
			}
			return 0
		}
	}
	return 0
}
<|endoftext|>


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

package libkb

import (
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"time"

	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

const LoginSessionMemoryTimeout time.Duration = time.Minute * 5

var ErrLoginSessionNotLoaded = errors.New("LoginSession not loaded")
var ErrLoginSessionCleared = errors.New("LoginSession already cleared")

type LoginSession struct {
	sessionFor      string // set by constructor
	salt            []byte // retrieved from server, or set by WithSalt constructor
	loginSessionB64 string
	loginSession    []byte    // decoded from above parameter
	loaded          bool      // load state
	cleared         bool      // clear state
	createTime      time.Time // load time
	Contextified
}

func NewLoginSession(emailOrUsername string, g *GlobalContext) *LoginSession {
	return &LoginSession{
		sessionFor:   emailOrUsername,
		Contextified: NewContextified(g),
	}
}

// Upon signup, a login session is created with a generated salt.
func NewLoginSessionWithSalt(emailOrUsername string, salt []byte, g *GlobalContext) *LoginSession {
	ls := NewLoginSession(emailOrUsername, g)
	ls.salt = salt
	// XXX are these right?  is this just so the salt can be retrieved?
	ls.loaded = true
	ls.cleared = true
	return ls
}

func (s *LoginSession) Status() *keybase1.SessionStatus {
	return &keybase1.SessionStatus{
		SessionFor: s.sessionFor,
		Loaded:     s.loaded,
		Cleared:    s.cleared,
		Expired:    !s.NotExpired(),
		SaltOnly:   s.loaded && s.loginSession == nil && s.salt != nil,
	}
}

func (s *LoginSession) Session() ([]byte, error) {
	if s == nil {
		return nil, ErrLoginSessionNotLoaded
	}
	if !s.loaded {
		return nil, ErrLoginSessionNotLoaded
	}
	if s.cleared {
		return nil, ErrLoginSessionCleared
	}
	return s.loginSession, nil
}

func (s *LoginSession) SessionEncoded() (string, error) {
	if s == nil {
		return "", ErrLoginSessionNotLoaded
	}
	if !s.loaded {
		return "", ErrLoginSessionNotLoaded
	}
	if s.cleared {
		return "", ErrLoginSessionCleared
	}
	return s.loginSessionB64, nil
}

func (s *LoginSession) ExistsFor(emailOrUsername string) bool {
	if s == nil {
		return false
	}
	if s.sessionFor != emailOrUsername {
		return false
	}
	if s.cleared {
		return false
	}
	if s.loginSession == nil {
		return false
	}
	return true
}

func (s *LoginSession) NotExpired() bool {
	now := s.G().Clock().Now()

	if now.Sub(s.createTime) < LoginSessionMemoryTimeout {
		return true
	}
	s.G().Log.Debug("login_session expired")
	return false
}

// Clear removes the loginSession value from s. It does not
// clear the salt. Unclear how this is useful.
func (s *LoginSession) Clear() error {
	if s == nil {
		return nil
	}
	if !s.loaded {
		return ErrLoginSessionNotLoaded
	}
	s.loginSession = nil
	s.loginSessionB64 = ""
	s.cleared = true
	return nil
}

func (s *LoginSession) Salt() ([]byte, error) {
	if s == nil {
		return nil, ErrLoginSessionNotLoaded
	}
	if !s.loaded {
		return nil, ErrLoginSessionNotLoaded
	}
	return s.salt, nil
}

func (s *LoginSession) Dump() {
	if s == nil {
		fmt.Printf("LoginSession Dump: nil\n")
		return
	}
	fmt.Printf("sessionFor: %q\n", s.sessionFor)
	fmt.Printf("loaded: %v\n", s.loaded)
	fmt.Printf("cleared: %v\n", s.cleared)
	fmt.Printf("salt: %x\n", s.salt)
	fmt.Printf("loginSessionB64: %s\n", s.loginSessionB64)
	fmt.Printf("\n")
}

func (s *LoginSession) Load() error {
	if s.loaded && !s.cleared {
		return fmt.Errorf("LoginSession already loaded for %s", s.sessionFor)
	}

	res, err := s.G().API.Get(APIArg{
		Endpoint:    "getsalt",
		NeedSession: false,
		Args: HTTPArgs{
			"email_or_username": S{Val: s.sessionFor},
		},
	})
	if err != nil {
		return err
	}

	shex, err := res.Body.AtKey("salt").GetString()
	if err != nil {
		return err
	}

	salt, err := hex.DecodeString(shex)
	if err != nil {
		return err
	}

	b64, err := res.Body.AtKey("login_session").GetString()
	if err != nil {
		return err
	}

	ls, err := base64.StdEncoding.DecodeString(b64)
	if err != nil {
		return err
	}

	s.salt = salt
	s.loginSessionB64 = b64
	s.loginSession = ls
	s.loaded = true
	s.cleared = false
	s.createTime = s.G().Clock().Now()

	return nil
}
<commit_msg>new getsalt behavior<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"time"

	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

const LoginSessionMemoryTimeout time.Duration = time.Minute * 5

var ErrLoginSessionNotLoaded = errors.New("LoginSession not loaded")
var ErrLoginSessionCleared = errors.New("LoginSession already cleared")

type LoginSession struct {
	sessionFor      string // set by constructor
	salt            []byte // retrieved from server, or set by WithSalt constructor
	loginSessionB64 string
	loginSession    []byte    // decoded from above parameter
	loaded          bool      // load state
	cleared         bool      // clear state
	createTime      time.Time // load time
	Contextified
}

func NewLoginSession(emailOrUsername string, g *GlobalContext) *LoginSession {
	return &LoginSession{
		sessionFor:   emailOrUsername,
		Contextified: NewContextified(g),
	}
}

// Upon signup, a login session is created with a generated salt.
func NewLoginSessionWithSalt(emailOrUsername string, salt []byte, g *GlobalContext) *LoginSession {
	ls := NewLoginSession(emailOrUsername, g)
	ls.salt = salt
	// XXX are these right?  is this just so the salt can be retrieved?
	ls.loaded = true
	ls.cleared = true
	return ls
}

func (s *LoginSession) Status() *keybase1.SessionStatus {
	return &keybase1.SessionStatus{
		SessionFor: s.sessionFor,
		Loaded:     s.loaded,
		Cleared:    s.cleared,
		Expired:    !s.NotExpired(),
		SaltOnly:   s.loaded && s.loginSession == nil && s.salt != nil,
	}
}

func (s *LoginSession) Session() ([]byte, error) {
	if s == nil {
		return nil, ErrLoginSessionNotLoaded
	}
	if !s.loaded {
		return nil, ErrLoginSessionNotLoaded
	}
	if s.cleared {
		return nil, ErrLoginSessionCleared
	}
	return s.loginSession, nil
}

func (s *LoginSession) SessionEncoded() (string, error) {
	if s == nil {
		return "", ErrLoginSessionNotLoaded
	}
	if !s.loaded {
		return "", ErrLoginSessionNotLoaded
	}
	if s.cleared {
		return "", ErrLoginSessionCleared
	}
	return s.loginSessionB64, nil
}

func (s *LoginSession) ExistsFor(emailOrUsername string) bool {
	if s == nil {
		return false
	}
	if s.sessionFor != emailOrUsername {
		return false
	}
	if s.cleared {
		return false
	}
	if s.loginSession == nil {
		return false
	}
	return true
}

func (s *LoginSession) NotExpired() bool {
	now := s.G().Clock().Now()

	if now.Sub(s.createTime) < LoginSessionMemoryTimeout {
		return true
	}
	s.G().Log.Debug("login_session expired")
	return false
}

// Clear removes the loginSession value from s. It does not
// clear the salt. Unclear how this is useful.
func (s *LoginSession) Clear() error {
	if s == nil {
		return nil
	}
	if !s.loaded {
		return ErrLoginSessionNotLoaded
	}
	s.loginSession = nil
	s.loginSessionB64 = ""
	s.cleared = true
	return nil
}

func (s *LoginSession) Salt() ([]byte, error) {
	if s == nil {
		return nil, ErrLoginSessionNotLoaded
	}
	if !s.loaded {
		return nil, ErrLoginSessionNotLoaded
	}
	return s.salt, nil
}

func (s *LoginSession) Dump() {
	if s == nil {
		fmt.Printf("LoginSession Dump: nil\n")
		return
	}
	fmt.Printf("sessionFor: %q\n", s.sessionFor)
	fmt.Printf("loaded: %v\n", s.loaded)
	fmt.Printf("cleared: %v\n", s.cleared)
	fmt.Printf("salt: %x\n", s.salt)
	fmt.Printf("loginSessionB64: %s\n", s.loginSessionB64)
	fmt.Printf("\n")
}

func (s *LoginSession) Load() error {
	if s.loaded && !s.cleared {
		return fmt.Errorf("LoginSession already loaded for %s", s.sessionFor)
	}

	res, err := s.G().API.Get(APIArg{
		Endpoint:    "getsalt",
		NeedSession: false,
		Args: HTTPArgs{
			"email_or_username": S{Val: s.sessionFor},
			"pdpka_login":       B{Val: true},
		},
	})
	if err != nil {
		return err
	}

	shex, err := res.Body.AtKey("salt").GetString()
	if err != nil {
		return err
	}

	salt, err := hex.DecodeString(shex)
	if err != nil {
		return err
	}

	b64, err := res.Body.AtKey("login_session").GetString()
	if err != nil {
		return err
	}

	ls, err := base64.StdEncoding.DecodeString(b64)
	if err != nil {
		return err
	}

	s.salt = salt
	s.loginSessionB64 = b64
	s.loginSession = ls
	s.loaded = true
	s.cleared = false
	s.createTime = s.G().Clock().Now()

	return nil
}
<|endoftext|>


<commit_before>package teams

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/kbtest"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"

	"github.com/stretchr/testify/require"
)

func TestShowcaseTeam(t *testing.T) {
	tc := SetupTest(t, "team", 1)
	defer tc.Cleanup()

	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	name := createTeam(tc)
	t.Logf("Created team %q", name)

	isShowcased := true
	err = SetTeamShowcase(context.TODO(), tc.G, name, &isShowcased, nil)
	require.NoError(t, err)

	showcase, err := GetTeamShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.Nil(t, nil, showcase.Description)

	description := "Hello world"
	err = SetTeamShowcase(context.TODO(), tc.G, name, nil, &description)
	require.NoError(t, err)

	showcase, err = GetTeamShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.NotNil(t, showcase.Description)
	require.Equal(t, "Hello world", *showcase.Description)

	isShowcased = false
	err = SetTeamShowcase(context.TODO(), tc.G, name, &isShowcased, nil)
	require.NoError(t, err)

	showcase, err = GetTeamShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)

	require.Equal(t, false, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.NotNil(t, showcase.Description)
	require.Equal(t, "Hello world", *showcase.Description)

	tmShowcase, err := GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, showcase, tmShowcase.TeamShowcase)
	require.Equal(t, false, tmShowcase.IsMemberShowcased)
}

func TestShowcaseMember(t *testing.T) {
	tc := SetupTest(t, "team", 1)
	defer tc.Cleanup()

	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	name := createTeam(tc)
	t.Logf("Created team %q", name)

	var nilTeamShowcase = keybase1.TeamShowcase{IsShowcased: false, Description: nil, SetByUID: nil}

	tmShowcase, err := GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, false, tmShowcase.IsMemberShowcased)
	require.Equal(t, nilTeamShowcase, tmShowcase.TeamShowcase)

	err = SetTeamMemberShowcase(context.TODO(), tc.G, name, true)
	require.NoError(t, err)

	tmShowcase, err = GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, tmShowcase.IsMemberShowcased)
	require.Equal(t, nilTeamShowcase, tmShowcase.TeamShowcase)

	isShowcased := true
	description := "Hello Team!"
	err = SetTeamShowcase(context.TODO(), tc.G, name, &isShowcased, &description)
	require.NoError(t, err)

	tmShowcase, err = GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, tmShowcase.IsMemberShowcased)

	showcase := tmShowcase.TeamShowcase
	require.Equal(t, true, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.NotNil(t, showcase.Description)
	require.Equal(t, "Hello Team!", *showcase.Description)
}

func TestShowcasePermissions(t *testing.T) {
	tc := SetupTest(t, "team", 1)
	defer tc.Cleanup()

	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	_, err = kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	team := createTeam(tc)
	t.Logf("Created team %q", team)

	isShowcased := true
	description := "This team is showcased"
	err = SetTeamShowcase(context.TODO(), tc.G, team, &isShowcased, &description)
	require.NoError(t, err)

	err = SetTeamMemberShowcase(context.TODO(), tc.G, team, true)
	require.NoError(t, err)

	_, err = AddMember(context.TODO(), tc.G, team, user.Username, keybase1.TeamRole_WRITER)
	require.NoError(t, err)

	tc.G.Logout()
	err = user.Login(tc.G)
	require.NoError(t, err)

	// Set- functions should check membership and not issue request
	// when user is not an admin or higher.
	isShowcased = false
	err = SetTeamShowcase(context.TODO(), tc.G, team, &isShowcased, nil)
	require.Error(t, err)

	// AppStatusErrors means we bounced off server instead of being
	// stopped by API helper code.
	_, ok := err.(libkb.AppStatusError)
	require.False(t, ok)

	err = SetTeamMemberShowcase(context.TODO(), tc.G, team, true)
	require.Error(t, err)
	_, ok = err.(libkb.AppStatusError)
	require.False(t, ok)

	// Get- functions should still work.
	ret, err := GetTeamAndMemberShowcase(context.TODO(), tc.G, team)
	require.NoError(t, err)
	require.False(t, ret.IsMemberShowcased) // always false if user is not an admin
	require.NotNil(t, ret.TeamShowcase.Description)
	require.Equal(t, description, *ret.TeamShowcase.Description)
	require.True(t, ret.TeamShowcase.IsShowcased)

	ret2, err := GetTeamShowcase(context.TODO(), tc.G, team)
	require.NoError(t, err)
	require.Equal(t, ret.TeamShowcase, ret2)
}
<commit_msg>Fix test<commit_after>package teams

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/kbtest"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"

	"github.com/stretchr/testify/require"
)

func TestShowcaseTeam(t *testing.T) {
	tc := SetupTest(t, "team", 1)
	defer tc.Cleanup()

	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	name := createTeam(tc)
	t.Logf("Created team %q", name)

	isShowcased := true
	err = SetTeamShowcase(context.TODO(), tc.G, name, &isShowcased, nil, nil)
	require.NoError(t, err)

	showcase, err := GetTeamShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.Nil(t, nil, showcase.Description)

	description := "Hello world"
	err = SetTeamShowcase(context.TODO(), tc.G, name, nil, &description, nil)
	require.NoError(t, err)

	showcase, err = GetTeamShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.NotNil(t, showcase.Description)
	require.Equal(t, "Hello world", *showcase.Description)

	isShowcased = false
	err = SetTeamShowcase(context.TODO(), tc.G, name, &isShowcased, nil, nil)
	require.NoError(t, err)

	showcase, err = GetTeamShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)

	require.Equal(t, false, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.NotNil(t, showcase.Description)
	require.Equal(t, "Hello world", *showcase.Description)

	tmShowcase, err := GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, showcase, tmShowcase.TeamShowcase)
	require.Equal(t, false, tmShowcase.IsMemberShowcased)
}

func TestShowcaseMember(t *testing.T) {
	tc := SetupTest(t, "team", 1)
	defer tc.Cleanup()

	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	name := createTeam(tc)
	t.Logf("Created team %q", name)

	var defaultTeamShowcase = keybase1.TeamShowcase{IsShowcased: false, Description: nil, SetByUID: nil, AnyMemberShowcase: true}

	tmShowcase, err := GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, false, tmShowcase.IsMemberShowcased)
	require.Equal(t, defaultTeamShowcase, tmShowcase.TeamShowcase)

	err = SetTeamMemberShowcase(context.TODO(), tc.G, name, true)
	require.NoError(t, err)

	tmShowcase, err = GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, tmShowcase.IsMemberShowcased)
	require.Equal(t, defaultTeamShowcase, tmShowcase.TeamShowcase)

	isShowcased := true
	description := "Hello Team!"
	err = SetTeamShowcase(context.TODO(), tc.G, name, &isShowcased, &description, nil)
	require.NoError(t, err)

	tmShowcase, err = GetTeamAndMemberShowcase(context.TODO(), tc.G, name)
	require.NoError(t, err)
	require.Equal(t, true, tmShowcase.IsMemberShowcased)

	showcase := tmShowcase.TeamShowcase
	require.Equal(t, true, showcase.IsShowcased)
	require.NotNil(t, showcase.SetByUID)
	require.Equal(t, user.User.GetUID(), *showcase.SetByUID)
	require.NotNil(t, showcase.Description)
	require.Equal(t, "Hello Team!", *showcase.Description)
}

func TestShowcasePermissions(t *testing.T) {
	tc := SetupTest(t, "team", 1)
	defer tc.Cleanup()

	user, err := kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	_, err = kbtest.CreateAndSignupFakeUser("team", tc.G)
	require.NoError(t, err)

	team := createTeam(tc)
	t.Logf("Created team %q", team)

	isShowcased := true
	description := "This team is showcased"
	anyMemberShowcase := false
	err = SetTeamShowcase(context.TODO(), tc.G, team, &isShowcased, &description, &anyMemberShowcase)
	require.NoError(t, err)

	err = SetTeamMemberShowcase(context.TODO(), tc.G, team, true)
	require.NoError(t, err)

	_, err = AddMember(context.TODO(), tc.G, team, user.Username, keybase1.TeamRole_WRITER)
	require.NoError(t, err)

	tc.G.Logout()
	err = user.Login(tc.G)
	require.NoError(t, err)

	// Set- functions should check membership and not issue request
	// when user is not an admin or higher.
	isShowcased = false
	err = SetTeamShowcase(context.TODO(), tc.G, team, &isShowcased, nil, nil)
	require.Error(t, err)

	// AppStatusErrors means we bounced off server instead of being
	// stopped by API helper code.
	_, ok := err.(libkb.AppStatusError)
	require.False(t, ok)

	// But we expect to hit server error here: because server checks
	// anyMemberShowcase, not us.
	err = SetTeamMemberShowcase(context.TODO(), tc.G, team, true)
	require.Error(t, err)
	_, ok = err.(libkb.AppStatusError)
	require.True(t, ok)

	// Get- functions should still work.
	ret, err := GetTeamAndMemberShowcase(context.TODO(), tc.G, team)
	require.NoError(t, err)
	require.False(t, ret.IsMemberShowcased) // always false if user is not an admin
	require.NotNil(t, ret.TeamShowcase.Description)
	require.Equal(t, description, *ret.TeamShowcase.Description)
	require.True(t, ret.TeamShowcase.IsShowcased)

	ret2, err := GetTeamShowcase(context.TODO(), tc.G, team)
	require.NoError(t, err)
	require.Equal(t, ret.TeamShowcase, ret2)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"os"
	"runtime"

	"github.com/gorilla/websocket"
	sm "github.com/tchap/go-statemachine"
)

type ErrMsg struct {
	Err string `json:"error"`
}

type DeskMsg struct {
	Desk [][]string `json:"desk"`
}

type PlayerMsg struct {
	Cmd  sm.EventType `json:"command"`
	Card string       `json:"card"`
}

//

const (
	cmdStart sm.EventType = iota
	cmdMove

	cmdCount
)

const (
	stateCollection sm.State = iota
	stateDistribution
	stateGame

	stateCount
)

func stateToString(s sm.State) string {
	return [...]string{
		stateCollection:   "COLLECTION",
		stateDistribution: "DISTRIBUTION",
		stateGame:         "GAME",

		//stateClosed:  "CLOSED",
	}[s]
}

func cmdToString(t sm.EventType) string {
	return [...]string{
		cmdStart: "START",
		cmdMove:  "MOVE",

		//cmdClose: "CLOSE",
	}[t]
}

//

type gameState struct {
	// player that should make the current move
	p *websocket.Conn

	trump string

	sm *sm.StateMachine
}

func NewGameState() *gameState {
	gst := new(gameState)

	// wtf
	gst.sm = sm.New(stateGame, uint(stateCount), uint(cmdCount))

	gst.sm.On(cmdMove,
		[]sm.State{stateGame},
		gst.handleMove)

	return gst
}

func (self *gameState) handleMove(s sm.State, e *sm.Event) (next sm.State) {
	log.Println(e.Data)
	return stateGame
}

var GSt *gameState = NewGameState()

//

type durakSrv struct {
	conn *websocket.Conn
	gst  *gameState
}

func (self *durakSrv) read() {
	var m PlayerMsg

	for {
		err := self.conn.ReadJSON(&m)
		if err != nil {
			log.Println(err)
			return
		}

		switch m.Cmd {
		case cmdStart:
		case cmdMove:
			err = self.gst.sm.Emit(&sm.Event{cmdMove, m.Card})
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

//

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func durakHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close() //dbg

	d := durakSrv{conn, GSt}

	d.read()
}

func main() {
	http.HandleFunc("/", durakHandler)

	log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), nil))
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
<commit_msg>minor changes<commit_after>package main

import (
	"log"
	"net/http"
	"os"
	"runtime"

	"github.com/gorilla/websocket"
	sm "github.com/tchap/go-statemachine"
)

type ErrMsg struct {
	Err string `json:"error"`
}

type DeskMsg struct {
	Desk [][]string `json:"desk"`
}

type PlayerMsg struct {
	Cmd  sm.EventType `json:"command"`
	Card string       `json:"card"`
}

//

const (
	cmdStart sm.EventType = iota
	cmdMove

	cmdCount
)

const (
	stateCollection sm.State = iota
	stateDistribution
	stateGame

	stateCount
)

func stateToString(s sm.State) string {
	return [...]string{
		stateCollection:   "COLLECTION",
		stateDistribution: "DISTRIBUTION",
		stateGame:         "GAME",

		//stateClosed:  "CLOSED",
	}[s]
}

func cmdToString(t sm.EventType) string {
	return [...]string{
		cmdStart: "START",
		cmdMove:  "MOVE",

		//cmdClose: "CLOSE",
	}[t]
}

//

type cmdArgs struct {
	conn *websocket.Conn
	card string
}

//

type gameState struct {
	// player that should make the move now
	p *websocket.Conn

	// card that should be beaten
	card string

	trump string

	sm *sm.StateMachine
}

func NewGameState() *gameState {
	gst := new(gameState)

	// wtf
	gst.sm = sm.New(stateGame, uint(stateCount), uint(cmdCount))

	gst.sm.On(cmdMove,
		[]sm.State{stateGame},
		gst.handleMove)

	return gst
}

func (self *gameState) handleMove(s sm.State, e *sm.Event) (next sm.State) {
	conn := e.Data.(cmdArgs).conn
	//card := e.Data.(cmdArgs).card

	if conn != self.p {
		log.Printf("it's %v's turn to make a move", self.p)
		return s
	}

	return s
}

var GSt *gameState = NewGameState()

//

type durakSrv struct {
	conn *websocket.Conn
	gst  *gameState
}

func (self *durakSrv) read() {
	var m PlayerMsg

	for {
		err := self.conn.ReadJSON(&m)
		if err != nil {
			log.Println(err)
			return
		}

		switch m.Cmd {
		case cmdStart:
		case cmdMove:
			event := &sm.Event{cmdMove, cmdArgs{self.conn, m.Card}}

			err = self.gst.sm.Emit(event)
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

//

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func durakHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close() //dbg

	d := durakSrv{conn, GSt}

	d.read()
}

func main() {
	http.HandleFunc("/", durakHandler)

	log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), nil))
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
<|endoftext|>


<commit_before>package sia

import (
	"errors"
	"math/big"
)

// Used to keep track of how many signatures an input has been signed by.
type InputSignatures struct {
	RemainingSignatures uint8
	PossibleKeys        []PublicKey
	UsedKeys            map[uint8]struct{}
}

// Add a block to the state struct.
func (s *State) AcceptBlock(b *Block) (err error) {
	bid := b.ID() // Function is not implemented.

	_, exists := s.BadBlocks[bid]
	if exists {
		err = errors.New("Block is in bad list")
		return
	}

	if b.Version != 1 {
		s.BadBlocks[bid] = struct{}{}
		err = errors.New("Block is not version 1")
		return
	}

	_, exists = s.BlockMap[bid]
	if exists {
		err = errors.New("Block exists in block map.")
		return
	}

	/*_, exists = s.OrphanBlocks[bid]
	if exists {
		err = errors.New("Block exists in orphan list")
		return
	} */

	parentBlockNode, exists := s.BlockMap[b.ParentBlock]
	if !exists {
		// OrphanBlocks[bid] = b
		err = errors.New("Block is an orphan")
		return
	}

	// If timestamp is in the future, store in future blocks list.
	// If timestamp is too far in the past, reject and put in bad blocks.

	// Check the amount of work done by the block.
	if !ValidHeader(parentBlockNode.Difficulty, b) {
		err = errors.New("Block does not meet difficulty requirement")
		s.BadBlocks[bid] = struct{}{}
		return
	}

	// Add the block to the block tree.
	newBlockNode := new(BlockNode)
	newBlockNode.Block = b
	parentBlockNode.Children = append(parentBlockNode.Children, newBlockNode)
	// newBlockNode.Verified = false // implicit value, stated explicity for prosperity.
	newBlockNode.Height = parentBlockNode.Height + 1
	copy(newBlockNode.RecentTimestamps[:], parentBlockNode.RecentTimestamps[1:])
	newBlockNode.RecentTimestamps[10] = b.Timestamp

	var timePassed Timestamp
	var expectedTimePassed Timestamp
	var blockWindow BlockHeight
	if newBlockNode.Height < 5000 {
		// Calculate new difficulty, using block 0 timestamp.
		timePassed = b.Timestamp - s.BlockRoot.Block.Timestamp
		expectedTimePassed = TargetSecondsPerBlock * Timestamp(newBlockNode.Height)
		blockWindow = newBlockNode.Height
	} else {
		// Calculate new difficulty, using block Height-5000 timestamp.
		timePassed := b.Timestamp - s.BlockMap[s.CurrentPath[newBlockNode.Height-5000]].Block.Timestamp
		expectedTimePassed := TargetSecondsPerBlock * 5000
		blockWindow = 5000
	}

	// Adjustment as a float = timePassed / expectedTimePassed / blockWindow.
	difficultyAdjustment := big.NewRat(int64(timePassed), int64(expectedTimePassed)*int64(blockWindow))

	// Enforce a maximum difficultyAdjustment
	if difficultyAdjustment.Cmp(MaxAdjustmentUp) == 1 {
		difficultyAdjustment = MaxAdjustmentUp
	} else if difficultyAdjustment.Cmp(MaxAdjustmentDown) == -1 {
		difficultyAdjustment = MaxAdjustmentDown
	}

	// Take the difficulty adjustment and apply it to the difficulty slice,
	// using rational numbers. Truncate the result.
	oldTarget := big.NewInt(0).SetBytes(parentBlockNode.Difficulty[:])
	ratOldTarget := big.NewRat(0, 1).SetInt(oldTarget)
	ratNewTarget := ratOldTarget.Mul(difficultyAdjustment, ratOldTarget)
	newTargetNumerator := ratNewTarget.Num()
	newTargetDenominator := ratNewTarget.Denom()
	intNewTarget := big.NewInt(0).Div(newTargetNumerator, newTargetDenominator)
	newTargetBytes := intNewTarget.Bytes()
	offset := len(newBlockNode.Difficulty[:]) - len(newTargetBytes)
	copy(newBlockNode.Difficulty[offset:], newTargetBytes)

	// If block adds to the current fork, validate it and advance fork.
	// Note: current implementation will only ever accept the first block
	// it sees, instead of picking longest chain.
	if b.ParentBlock == s.CurrentBlock {
		err = s.ValidateBlock(b)
		if err != nil {
			s.BadBlocks[bid] = struct{}{}
			parentBlockNode.Children = parentBlockNode.Children[:len(parentBlockNode.Children)-1]
			return
		}

		s.CurrentBlock = bid
		s.CurrentPath[newBlockNode.Height] = bid
	}

	// Do anything necessary to the transaction pool.

	return
}

// ValidateBlock will both verify the block AND update the consensus state.
// Calling integrate block is not needed.
func (s *State) ValidateBlock(b *Block) (err error) {
	// Check the hash on the merkle tree of transactions.

	var appliedTransactions []Transaction
	minerSubsidy := Currency(0)
	for _, txn := range b.Transactions {
		err = s.ValidateTxn(txn, s.BlockMap[b.ID()].Height)
		if err != nil {
			s.BadBlocks[b.ID()] = struct{}{}
			break
		}

		// Apply the transaction to the ConsensusState, adding it to the list of applied transactions.
		s.ApplyTransaction(txn)
		appliedTransactions = append(appliedTransactions, txn)

		minerSubsidy += txn.MinerFee
	}

	if err != nil {
		// Rewind transactions added to ConsensusState.
		for i := len(appliedTransactions) - 1; i >= 0; i-- {
			s.ReverseTransaction(appliedTransactions[i])
		}
		return
	}

	// Add outputs for all of the missed proofs in the open transactions.

	// Add coin inflation to the miner subsidy.

	// Add output contianing miner fees + block subsidy.
	bid := b.ID()
	minerSubsidyID := OutputID(HashBytes(append(bid[:], []byte("blockReward")...)))
	minerSubsidyOutput := Output{
		Value:     minerSubsidy,
		SpendHash: b.MinerAddress,
	}
	s.ConsensusState.UnspentOutputs[minerSubsidyID] = minerSubsidyOutput

	// s.BlockMap[b.ID()].Verified = true

	return
}

// Add a function that integrates a block without verifying it.

func (s *State) ValidateTxn(t Transaction, currentHeight BlockHeight) (err error) {
	if t.Version != 1 {
		err = errors.New("Transaction version is not recognized.")
		return
	}

	inputSum := Currency(0)
	outputSum := t.MinerFee
	var inputSignaturesMap map[OutputID]InputSignatures
	for _, input := range t.Inputs {
		utxo, exists := s.ConsensusState.UnspentOutputs[input.OutputID]
		if !exists {
			err = errors.New("Transaction spends a nonexisting output")
			return
		}

		inputSum += utxo.Value

		// Check that the spend conditions match the hash listed in the output.

		// Check the timelock on the spend conditions is expired.
		if input.SpendConditions.TimeLock < currentHeight {
			err = errors.New("Output spent before timelock expiry.")
			return
		}

		// Create the condition for the input signatures and add it to the input signatures map.
		_, exists = inputSignaturesMap[input.OutputID]
		if exists {
			err = errors.New("Output spent twice in same transaction")
			return
		}
		var newInputSignatures InputSignatures
		newInputSignatures.RemainingSignatures = input.SpendConditions.NumSignatures
		newInputSignatures.PossibleKeys = input.SpendConditions.PublicKeys
		inputSignaturesMap[input.OutputID] = newInputSignatures
	}

	for _, output := range t.Outputs {
		outputSum += output.Value
	}

	for _, contract := range t.FileContracts {
		if contract.Start < currentHeight {
			err = errors.New("Contract starts in the future.")
			return
		}
		if contract.End <= contract.Start {
			err = errors.New("Contract duration must be at least one block.")
			return
		}
	}

	/*
		for _, proof := range t.StorageProofs {
			// Check that the proof passes.
			// Check that the proof has not already been submitted.
		}
	*/

	if inputSum != outputSum {
		err = errors.New("Inputs do not equal outputs for transaction.")
		return
	}

	for _, sig := range t.Signatures {
		// Check that each signature signs a unique pubkey where
		// RemainingSignatures > 0.
		if inputSignaturesMap[sig.InputID].RemainingSignatures == 0 {
			err = errors.New("Friviolous Signature detected.")
			return
		}
		_, exists := inputSignaturesMap[sig.InputID].UsedKeys[sig.PublicKeyIndex]
		if exists {
			err = errors.New("public key used twice while signing")
			return
		}

		// Check the timelock on the signature.
		if sig.TimeLock < currentHeight {
			err = errors.New("signature timelock has not expired")
			return
		}

		// Check that the actual signature is valid, following the covered fields struct.
	}

	return
}

func (s *State) ApplyTransaction(t Transaction) {
	// Remove all inputs from the unspent outputs list
	for _, input := range t.Inputs {
		s.ConsensusState.SpentOutputs[input.OutputID] = s.ConsensusState.UnspentOutputs[input.OutputID]
		delete(s.ConsensusState.UnspentOutputs, input.OutputID)
	}

	// Add all outputs to the unspent outputs list
	for i, output := range t.Outputs {
		newOutputID := OutputID(HashBytes(append((t.Inputs[0].OutputID)[:], EncUint64(uint64(i))...)))
		s.ConsensusState.UnspentOutputs[newOutputID] = output
	}

	// Add all outputs created by storage proofs.
	/*
		for _, sp := range t.StorageProofs {
			// Need to check that the contract fund has sufficient funds remaining.

			newOutputID := HashBytes(append(ContractID), []byte(n))
			output := Output {
				Value: s.ConsensusState.OpenContracts[sp.ContractID].ValidProofPayout,
				SpendHash: s.ConsensusState.OpenContracts[sp.ContractID].ValidProofAddress,
			}
			s.ConsensusState.UnspentOutputs[newOutputID] = output

			// need a counter or some way to determine what the index of
			// the window is.
		}
	*/
}

func (s *State) ReverseTransaction(t Transaction) {
	// Remove all outputs created by storage proofs.

	// Remove all outputs created by outputs.
	for i := range t.Outputs {
		outputID := OutputID(HashBytes(append((t.Inputs[0].OutputID)[:], EncUint64(uint64(i))...)))
		delete(s.ConsensusState.UnspentOutputs, outputID)
	}

	// Add all outputs spent by inputs.
	for _, input := range t.Inputs {
		s.ConsensusState.UnspentOutputs[input.OutputID] = s.ConsensusState.SpentOutputs[input.OutputID]
		delete(s.ConsensusState.SpentOutputs, input.OutputID)
	}
}
<commit_msg>further fix up difficulty adjustment code<commit_after>package sia

import (
	"errors"
	"math/big"
)

// Used to keep track of how many signatures an input has been signed by.
type InputSignatures struct {
	RemainingSignatures uint8
	PossibleKeys        []PublicKey
	UsedKeys            map[uint8]struct{}
}

// Add a block to the state struct.
func (s *State) AcceptBlock(b *Block) (err error) {
	bid := b.ID() // Function is not implemented.

	_, exists := s.BadBlocks[bid]
	if exists {
		err = errors.New("Block is in bad list")
		return
	}

	if b.Version != 1 {
		s.BadBlocks[bid] = struct{}{}
		err = errors.New("Block is not version 1")
		return
	}

	_, exists = s.BlockMap[bid]
	if exists {
		err = errors.New("Block exists in block map.")
		return
	}

	/*_, exists = s.OrphanBlocks[bid]
	if exists {
		err = errors.New("Block exists in orphan list")
		return
	} */

	parentBlockNode, exists := s.BlockMap[b.ParentBlock]
	if !exists {
		// OrphanBlocks[bid] = b
		err = errors.New("Block is an orphan")
		return
	}

	// If timestamp is in the future, store in future blocks list.
	// If timestamp is too far in the past, reject and put in bad blocks.

	// Check the amount of work done by the block.
	if !ValidHeader(parentBlockNode.Difficulty, b) {
		err = errors.New("Block does not meet difficulty requirement")
		s.BadBlocks[bid] = struct{}{}
		return
	}

	// Add the block to the block tree.
	newBlockNode := new(BlockNode)
	newBlockNode.Block = b
	parentBlockNode.Children = append(parentBlockNode.Children, newBlockNode)
	// newBlockNode.Verified = false // implicit value, stated explicity for prosperity.
	newBlockNode.Height = parentBlockNode.Height + 1
	copy(newBlockNode.RecentTimestamps[:], parentBlockNode.RecentTimestamps[1:])
	newBlockNode.RecentTimestamps[10] = b.Timestamp

	var timePassed Timestamp
	var expectedTimePassed Timestamp
	var blockWindow BlockHeight
	if newBlockNode.Height < 5000 {
		// Calculate new difficulty, using block 0 timestamp.
		timePassed = b.Timestamp - s.BlockRoot.Block.Timestamp
		expectedTimePassed = TargetSecondsPerBlock * Timestamp(newBlockNode.Height)
		blockWindow = newBlockNode.Height
	} else {
		// Calculate new difficulty, using block Height-5000 timestamp.
		timePassed := b.Timestamp - s.BlockMap[s.CurrentPath[newBlockNode.Height-5000]].Block.Timestamp
		expectedTimePassed := TargetSecondsPerBlock * 5000
		blockWindow = 5000
	}

	// Adjustment as a float = timePassed / expectedTimePassed / blockWindow.
	difficultyAdjustment := big.NewRat(int64(timePassed), int64(expectedTimePassed)*int64(blockWindow))

	// Enforce a maximum difficultyAdjustment
	if difficultyAdjustment.Cmp(MaxAdjustmentUp) == 1 {
		difficultyAdjustment = MaxAdjustmentUp
	} else if difficultyAdjustment.Cmp(MaxAdjustmentDown) == -1 {
		difficultyAdjustment = MaxAdjustmentDown
	}

	// Take the difficulty adjustment and apply it to the difficulty slice,
	// using rational numbers. Truncate the result.
	oldTarget := new(big.Int).SetBytes(parentBlockNode.Difficulty[:])
	ratOldTarget := new(big.Rat).SetInt(oldTarget)
	ratNewTarget := ratOldTarget.Mul(difficultyAdjustment, ratOldTarget)
	intNewTarget := new(big.Int).Div(ratNewTarget.Num(), ratNewTarget.Denom())
	newTargetBytes := intNewTarget.Bytes()
	offset := len(newBlockNode.Difficulty[:]) - len(newTargetBytes)
	copy(newBlockNode.Difficulty[offset:], newTargetBytes)

	// If block adds to the current fork, validate it and advance fork.
	// Note: current implementation will only ever accept the first block
	// it sees, instead of picking longest chain.
	if b.ParentBlock == s.CurrentBlock {
		err = s.ValidateBlock(b)
		if err != nil {
			s.BadBlocks[bid] = struct{}{}
			parentBlockNode.Children = parentBlockNode.Children[:len(parentBlockNode.Children)-1]
			return
		}

		s.CurrentBlock = bid
		s.CurrentPath[newBlockNode.Height] = bid
	}

	// Do anything necessary to the transaction pool.

	return
}

// ValidateBlock will both verify the block AND update the consensus state.
// Calling integrate block is not needed.
func (s *State) ValidateBlock(b *Block) (err error) {
	// Check the hash on the merkle tree of transactions.

	var appliedTransactions []Transaction
	minerSubsidy := Currency(0)
	for _, txn := range b.Transactions {
		err = s.ValidateTxn(txn, s.BlockMap[b.ID()].Height)
		if err != nil {
			s.BadBlocks[b.ID()] = struct{}{}
			break
		}

		// Apply the transaction to the ConsensusState, adding it to the list of applied transactions.
		s.ApplyTransaction(txn)
		appliedTransactions = append(appliedTransactions, txn)

		minerSubsidy += txn.MinerFee
	}

	if err != nil {
		// Rewind transactions added to ConsensusState.
		for i := len(appliedTransactions) - 1; i >= 0; i-- {
			s.ReverseTransaction(appliedTransactions[i])
		}
		return
	}

	// Add outputs for all of the missed proofs in the open transactions.

	// Add coin inflation to the miner subsidy.

	// Add output contianing miner fees + block subsidy.
	bid := b.ID()
	minerSubsidyID := OutputID(HashBytes(append(bid[:], []byte("blockReward")...)))
	minerSubsidyOutput := Output{
		Value:     minerSubsidy,
		SpendHash: b.MinerAddress,
	}
	s.ConsensusState.UnspentOutputs[minerSubsidyID] = minerSubsidyOutput

	// s.BlockMap[b.ID()].Verified = true

	return
}

// Add a function that integrates a block without verifying it.

func (s *State) ValidateTxn(t Transaction, currentHeight BlockHeight) (err error) {
	if t.Version != 1 {
		err = errors.New("Transaction version is not recognized.")
		return
	}

	inputSum := Currency(0)
	outputSum := t.MinerFee
	var inputSignaturesMap map[OutputID]InputSignatures
	for _, input := range t.Inputs {
		utxo, exists := s.ConsensusState.UnspentOutputs[input.OutputID]
		if !exists {
			err = errors.New("Transaction spends a nonexisting output")
			return
		}

		inputSum += utxo.Value

		// Check that the spend conditions match the hash listed in the output.

		// Check the timelock on the spend conditions is expired.
		if input.SpendConditions.TimeLock < currentHeight {
			err = errors.New("Output spent before timelock expiry.")
			return
		}

		// Create the condition for the input signatures and add it to the input signatures map.
		_, exists = inputSignaturesMap[input.OutputID]
		if exists {
			err = errors.New("Output spent twice in same transaction")
			return
		}
		var newInputSignatures InputSignatures
		newInputSignatures.RemainingSignatures = input.SpendConditions.NumSignatures
		newInputSignatures.PossibleKeys = input.SpendConditions.PublicKeys
		inputSignaturesMap[input.OutputID] = newInputSignatures
	}

	for _, output := range t.Outputs {
		outputSum += output.Value
	}

	for _, contract := range t.FileContracts {
		if contract.Start < currentHeight {
			err = errors.New("Contract starts in the future.")
			return
		}
		if contract.End <= contract.Start {
			err = errors.New("Contract duration must be at least one block.")
			return
		}
	}

	/*
		for _, proof := range t.StorageProofs {
			// Check that the proof passes.
			// Check that the proof has not already been submitted.
		}
	*/

	if inputSum != outputSum {
		err = errors.New("Inputs do not equal outputs for transaction.")
		return
	}

	for _, sig := range t.Signatures {
		// Check that each signature signs a unique pubkey where
		// RemainingSignatures > 0.
		if inputSignaturesMap[sig.InputID].RemainingSignatures == 0 {
			err = errors.New("Friviolous Signature detected.")
			return
		}
		_, exists := inputSignaturesMap[sig.InputID].UsedKeys[sig.PublicKeyIndex]
		if exists {
			err = errors.New("public key used twice while signing")
			return
		}

		// Check the timelock on the signature.
		if sig.TimeLock < currentHeight {
			err = errors.New("signature timelock has not expired")
			return
		}

		// Check that the actual signature is valid, following the covered fields struct.
	}

	return
}

func (s *State) ApplyTransaction(t Transaction) {
	// Remove all inputs from the unspent outputs list
	for _, input := range t.Inputs {
		s.ConsensusState.SpentOutputs[input.OutputID] = s.ConsensusState.UnspentOutputs[input.OutputID]
		delete(s.ConsensusState.UnspentOutputs, input.OutputID)
	}

	// Add all outputs to the unspent outputs list
	for i, output := range t.Outputs {
		newOutputID := OutputID(HashBytes(append((t.Inputs[0].OutputID)[:], EncUint64(uint64(i))...)))
		s.ConsensusState.UnspentOutputs[newOutputID] = output
	}

	// Add all outputs created by storage proofs.
	/*
		for _, sp := range t.StorageProofs {
			// Need to check that the contract fund has sufficient funds remaining.

			newOutputID := HashBytes(append(ContractID), []byte(n))
			output := Output {
				Value: s.ConsensusState.OpenContracts[sp.ContractID].ValidProofPayout,
				SpendHash: s.ConsensusState.OpenContracts[sp.ContractID].ValidProofAddress,
			}
			s.ConsensusState.UnspentOutputs[newOutputID] = output

			// need a counter or some way to determine what the index of
			// the window is.
		}
	*/
}

func (s *State) ReverseTransaction(t Transaction) {
	// Remove all outputs created by storage proofs.

	// Remove all outputs created by outputs.
	for i := range t.Outputs {
		outputID := OutputID(HashBytes(append((t.Inputs[0].OutputID)[:], EncUint64(uint64(i))...)))
		delete(s.ConsensusState.UnspentOutputs, outputID)
	}

	// Add all outputs spent by inputs.
	for _, input := range t.Inputs {
		s.ConsensusState.UnspentOutputs[input.OutputID] = s.ConsensusState.SpentOutputs[input.OutputID]
		delete(s.ConsensusState.SpentOutputs, input.OutputID)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/ujanssen/emil"
	"time"
)

func main() {
	emil.IN_TEST = !true
	emil.DEBUG = true

	db := emil.NewPositionDB()
	start := time.Now()
	//	err := emil.SaveEndGameDb("AnalysisMap.json", db.AnalysisStr)
	end := time.Now()
	db.Positions()
	fmt.Printf("db.Positions() %d\n\n", db.Positions())
	fmt.Printf("\n\n\nsave duration %v\n\n", end.Sub(start))
}
<commit_msg>create 447888 krk positions in 10s<commit_after>package main

import (
	"fmt"
	"github.com/ujanssen/emil"
	"time"
)

func main() {
	emil.IN_TEST = !true
	emil.DEBUG = true

	db := emil.NewPositionDB()
	start := time.Now()
	db.FillWithKRKPositions()
	//	err := emil.SaveEndGameDb("AnalysisMap.json", db.AnalysisStr)
	end := time.Now()
	db.Positions()
	fmt.Printf("db.Positions() %d\n\n", db.Positions())
	fmt.Printf("\n\n\nsave duration %v\n\n", end.Sub(start))
}
<|endoftext|>


<commit_before>package nfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"syscall"
	"testing"
)

func TestMntArgs(t *testing.T) {
	name, args := mntArgs("/opt/serviced/var", "/exports/serviced_var", "", "bind")
	if syscall.Getuid() == 0 {
		if name != "mount" {
			t.Fatalf("as root, expected name to be 'mount' got '%s'", name)
		}
		expectedArgs := []string{"-o", "bind", "/opt/serviced/var", "/exports/serviced_var"}
		if !reflect.DeepEqual(args, expectedArgs) {
			t.Fatalf("got %+v expected %+v", args, expectedArgs)
		}
	} else {
		if name != "sudo" {
			t.Fatalf("as non-root, expected name to be 'sudo' got '%s'", name)
		}
		expectedArgs := []string{"mount", "-o", "bind", "/opt/serviced/var", "/exports/serviced_var"}
		if !reflect.DeepEqual(args, expectedArgs) {
			t.Fatalf("got %+v expected %+v", args, expectedArgs)
		}
	}
}

func dirExists(path string) (bool, error) {
	s, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return s.IsDir(), err
}

var expectedExports = "%s\t192.168.1.0/24(rw,fsid=0,insecure,no_subtree_check,async)\n%s/foo\t192.168.1.0/24(rw,nohide,insecure,no_subtree_check,async)\n"

func TestNewServer(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "nfs_unit_tests_")
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	//defer os.RemoveAll(tempDir)
	t.Logf("created temp dir: %s", tempDir)

	baseDir := path.Join(tempDir, "baseDir")

	// mock out the exports directory, use stack to hold old values
	defer func(e, hostsDeny, hostsAllow, exports, exportsd string) {
		// restore to original values
		exportsPath = e
		etcHostsDeny = hostsDeny
		etcHostsAllow = hostsAllow
		etcExports = exports
		exportsDir = exportsd
	}(exportsPath, etcHostsDeny, etcHostsAllow, etcExports, exportsDir)
	exportsPath = path.Join(tempDir, "exports")
	etcHostsDeny = path.Join(tempDir, "etc/hosts.deny")
	etcHostsAllow = path.Join(tempDir, "etc/hosts.allow")
	etcExports = path.Join(tempDir, "etc/exports")
	exportsDir = path.Join(tempDir, "exports")

	// neuter bindmount during tests
	bindMount = func(string, string) error {
		return nil
	}

	// create our test server
	s, err := NewServer(baseDir, "foo", "192.168.1.0/24")
	if err != nil {
		t.Fatalf("unexpected error : %s ", err)
	}

	// check that the required directories were created
	if exists, err := dirExists(baseDir); err != nil || !exists {
		t.Fatalf("baseDir dir does not exist: %s, %s", baseDir, err)
	}
	exportDir := path.Join(exportsPath, "foo")
	if exists, err := dirExists(exportDir); err != nil || !exists {
		t.Fatalf("export dir does not exist: %s, %s", exportDir, err)
	}

	defer func(f func() error) {
		reload = f
	}(reload)
	reload = func() error {
		return nil
	}
	defer func(f func() error) {
		start = f
	}(start)
	start = reload

	// we call .Sync() repeatedly, lets make a shortcut
	sync := func() {
		if err := s.Sync(); err != nil {
			t.Fatalf("unexpected error synching server: %s", err)
		}
	}
	sync()

	// assert that the defaults get written out
	assertFileContents(t, etcHostsDeny, []byte(hostDenyDefaults))
	assertFileContents(t, etcHostsAllow, []byte(hostAllowDefaults+"\n"))

	s.SetClients("192.168.1.21")
	sync()

	assertFileContents(t, etcHostsDeny, []byte(hostDenyDefaults))
	assertFileContents(t, etcHostsAllow, []byte(hostAllowDefaults+" 192.168.1.21\n"))

	s.SetClients("192.168.1.21", "192.168.1.20")
	sync()

	assertFileContents(t, etcHostsDeny, []byte(hostDenyDefaults))
	assertFileContents(t, etcHostsAllow, []byte(hostAllowDefaults+" 192.168.1.20 192.168.1.21\n"))

	assertFileContents(t, etcExports, []byte(fmt.Sprintf(expectedExports, exportsPath, exportsPath)))

}

func assertFileContents(t *testing.T, filename string, contents []byte) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Fatalf("unexpected failure reading %s: %s", filename, err)
	}
	if string(bytes) != string(contents) {
		t.Fatalf("got [%d]:\n '%+v'' \n\n expected [%d]:\n '%+v'", len(bytes), string(bytes), len(contents), string(contents))
	}
}
<commit_msg>reorder mocking of nfs commands<commit_after>package nfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"syscall"
	"testing"
)

func TestMntArgs(t *testing.T) {
	name, args := mntArgs("/opt/serviced/var", "/exports/serviced_var", "", "bind")
	if syscall.Getuid() == 0 {
		if name != "mount" {
			t.Fatalf("as root, expected name to be 'mount' got '%s'", name)
		}
		expectedArgs := []string{"-o", "bind", "/opt/serviced/var", "/exports/serviced_var"}
		if !reflect.DeepEqual(args, expectedArgs) {
			t.Fatalf("got %+v expected %+v", args, expectedArgs)
		}
	} else {
		if name != "sudo" {
			t.Fatalf("as non-root, expected name to be 'sudo' got '%s'", name)
		}
		expectedArgs := []string{"mount", "-o", "bind", "/opt/serviced/var", "/exports/serviced_var"}
		if !reflect.DeepEqual(args, expectedArgs) {
			t.Fatalf("got %+v expected %+v", args, expectedArgs)
		}
	}
}

func dirExists(path string) (bool, error) {
	s, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return s.IsDir(), err
}

var expectedExports = "%s\t192.168.1.0/24(rw,fsid=0,insecure,no_subtree_check,async)\n%s/foo\t192.168.1.0/24(rw,nohide,insecure,no_subtree_check,async)\n"

func TestNewServer(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "nfs_unit_tests_")
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	//defer os.RemoveAll(tempDir)
	t.Logf("created temp dir: %s", tempDir)

	baseDir := path.Join(tempDir, "baseDir")

	// mock out the exports directory, use stack to hold old values
	defer func(e, hostsDeny, hostsAllow, exports, exportsd string) {
		// restore to original values
		exportsPath = e
		etcHostsDeny = hostsDeny
		etcHostsAllow = hostsAllow
		etcExports = exports
		exportsDir = exportsd
	}(exportsPath, etcHostsDeny, etcHostsAllow, etcExports, exportsDir)
	exportsPath = path.Join(tempDir, "exports")
	etcHostsDeny = path.Join(tempDir, "etc/hosts.deny")
	etcHostsAllow = path.Join(tempDir, "etc/hosts.allow")
	etcExports = path.Join(tempDir, "etc/exports")
	exportsDir = path.Join(tempDir, "exports")

	// neuter bindmount during tests
	bindMount = func(string, string) error {
		return nil
	}

	defer func(f func() error) {
		reload = f
	}(reload)
	reload = func() error {
		return nil
	}
	defer func(f func() error) {
		start = f
	}(start)
	start = reload

	// create our test server
	s, err := NewServer(baseDir, "foo", "192.168.1.0/24")
	if err != nil {
		t.Fatalf("unexpected error : %s ", err)
	}

	// check that the required directories were created
	if exists, err := dirExists(baseDir); err != nil || !exists {
		t.Fatalf("baseDir dir does not exist: %s, %s", baseDir, err)
	}
	exportDir := path.Join(exportsPath, "foo")
	if exists, err := dirExists(exportDir); err != nil || !exists {
		t.Fatalf("export dir does not exist: %s, %s", exportDir, err)
	}

	// we call .Sync() repeatedly, lets make a shortcut
	sync := func() {
		if err := s.Sync(); err != nil {
			t.Fatalf("unexpected error synching server: %s", err)
		}
	}
	sync()

	// assert that the defaults get written out
	assertFileContents(t, etcHostsDeny, []byte(hostDenyDefaults))
	assertFileContents(t, etcHostsAllow, []byte(hostAllowDefaults+"\n"))

	s.SetClients("192.168.1.21")
	sync()

	assertFileContents(t, etcHostsDeny, []byte(hostDenyDefaults))
	assertFileContents(t, etcHostsAllow, []byte(hostAllowDefaults+" 192.168.1.21\n"))

	s.SetClients("192.168.1.21", "192.168.1.20")
	sync()

	assertFileContents(t, etcHostsDeny, []byte(hostDenyDefaults))
	assertFileContents(t, etcHostsAllow, []byte(hostAllowDefaults+" 192.168.1.20 192.168.1.21\n"))

	assertFileContents(t, etcExports, []byte(fmt.Sprintf(expectedExports, exportsPath, exportsPath)))

}

func assertFileContents(t *testing.T, filename string, contents []byte) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Fatalf("unexpected failure reading %s: %s", filename, err)
	}
	if string(bytes) != string(contents) {
		t.Fatalf("got [%d]:\n '%+v'' \n\n expected [%d]:\n '%+v'", len(bytes), string(bytes), len(contents), string(contents))
	}
}
<|endoftext|>


<commit_before>package gateway

import (
	"io"
	"sync"

	pb "github.com/TheThingsNetwork/ttn/api/gateway"
	pb_monitor "github.com/TheThingsNetwork/ttn/api/monitor"
	pb_router "github.com/TheThingsNetwork/ttn/api/router"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/apex/log"
	context "golang.org/x/net/context"
	"google.golang.org/grpc/metadata"
)

func (g *Gateway) monitorContext() (ctx context.Context) {
	return metadata.NewContext(context.Background(), metadata.Pairs(
		"id", g.ID,
		"token", g.Token,
	))
}

type monitorConn struct {
	clients map[string]pb_monitor.MonitorClient

	status struct {
		streams map[string]pb_monitor.Monitor_GatewayStatusClient
		sync.RWMutex
	}

	uplink struct {
		streams map[string]pb_monitor.Monitor_GatewayUplinkClient
		sync.RWMutex
	}

	downlink struct {
		streams map[string]pb_monitor.Monitor_GatewayDownlinkClient
		sync.RWMutex
	}
}

func (g *Gateway) SetMonitors(clients map[string]pb_monitor.MonitorClient) {
	g.monitor = NewMonitorConn(clients)
}

func NewMonitorConn(clients map[string]pb_monitor.MonitorClient) (conn *monitorConn) {
	conn = &monitorConn{clients: clients}
	conn.uplink.streams = make(map[string]pb_monitor.Monitor_GatewayUplinkClient)
	conn.downlink.streams = make(map[string]pb_monitor.Monitor_GatewayDownlinkClient)
	conn.status.streams = make(map[string]pb_monitor.Monitor_GatewayStatusClient)
	return conn
}

func (g *Gateway) pushStatusToMonitor(ctx log.Interface, name string, status *pb.Status) (err error) {
	defer func() {
		switch err {
		case nil:
			ctx.Debug("Pushed status to monitor")

		case io.EOF:
			ctx.Warn("Stream closed, retrying")
			g.monitor.status.Lock()
			delete(g.monitor.status.streams, name)
			g.monitor.status.Unlock()
			err = g.pushStatusToMonitor(ctx, name, status)

		default:
			ctx.WithError(errors.FromGRPCError(err)).Warn("Monitor status push failed")
		}
	}()

	g.monitor.status.RLock()
	stream, ok := g.monitor.status.streams[name]
	g.monitor.status.RUnlock()

	if !ok {
		g.monitor.status.Lock()
		if _, ok := g.monitor.status.streams[name]; !ok {
			cl, ok := g.monitor.clients[name]
			if !ok {
				// Should not happen
				return errors.New("Monitor not found")
			}

			stream, err = cl.GatewayStatus(g.monitorContext())
			if err != nil {
				// TODO check if err returned is GRPC error
				err = errors.FromGRPCError(err)
				ctx.WithError(err).Warn("Failed to open new status stream")
				return err
			}
			ctx.Debug("Opened new status stream")

			g.monitor.status.streams[name] = stream
		}
		g.monitor.status.Unlock()
	}

	return stream.Send(status)
}

func (g *Gateway) pushUplinkToMonitor(ctx log.Interface, name string, uplink *pb_router.UplinkMessage) (err error) {
	defer func() {
		switch err {
		case nil:
			ctx.Debug("Pushed uplink to monitor")

		case io.EOF:
			ctx.Warn("Stream closed, retrying")
			g.monitor.uplink.Lock()
			delete(g.monitor.uplink.streams, name)
			g.monitor.uplink.Unlock()
			err = g.pushUplinkToMonitor(ctx, name, uplink)

		default:
			ctx.WithError(errors.FromGRPCError(err)).Warn("Monitor uplink push failed")
		}
	}()

	g.monitor.uplink.RLock()
	stream, ok := g.monitor.uplink.streams[name]
	g.monitor.uplink.RUnlock()

	if !ok {
		g.monitor.uplink.Lock()
		if _, ok := g.monitor.uplink.streams[name]; !ok {
			cl, ok := g.monitor.clients[name]
			if !ok {
				// Should not happen
				return errors.New("Monitor not found")
			}

			stream, err = cl.GatewayUplink(g.monitorContext())
			if err != nil {
				// TODO check if err returned is GRPC error
				err = errors.FromGRPCError(err)
				ctx.WithError(err).Warn("Failed to open new uplink stream")
				return err
			}
			ctx.Debug("Opened new uplink stream")

			g.monitor.uplink.streams[name] = stream
		}
		g.monitor.uplink.Unlock()
	}

	return stream.Send(uplink)
}

func (g *Gateway) pushDownlinkToMonitor(ctx log.Interface, name string, downlink *pb_router.DownlinkMessage) (err error) {
	defer func() {
		switch err {
		case nil:
			ctx.Debug("Pushed downlink to monitor")

		case io.EOF:
			ctx.Warn("Stream closed, retrying")
			g.monitor.downlink.Lock()
			delete(g.monitor.downlink.streams, name)
			g.monitor.downlink.Unlock()
			err = g.pushDownlinkToMonitor(ctx, name, downlink)

		default:
			ctx.WithError(errors.FromGRPCError(err)).Warn("Monitor downlink push failed")
		}
	}()

	g.monitor.downlink.RLock()
	stream, ok := g.monitor.downlink.streams[name]
	g.monitor.downlink.RUnlock()

	if !ok {
		g.monitor.downlink.Lock()
		if _, ok := g.monitor.downlink.streams[name]; !ok {
			cl, ok := g.monitor.clients[name]
			if !ok {
				// Should not happen
				return errors.New("Monitor not found")
			}

			stream, err = cl.GatewayDownlink(g.monitorContext())
			if err != nil {
				// TODO check if err returned is GRPC error
				err = errors.FromGRPCError(err)
				ctx.WithError(err).Warn("Failed to open new downlink stream")
				return err
			}
			ctx.Debug("Opened new downlink stream")

			g.monitor.downlink.streams[name] = stream
		}
		g.monitor.downlink.Unlock()
	}

	return stream.Send(downlink)
}
<commit_msg>gateway monitor: `stream closed` refactor<commit_after>package gateway

import (
	"io"
	"sync"

	pb "github.com/TheThingsNetwork/ttn/api/gateway"
	pb_monitor "github.com/TheThingsNetwork/ttn/api/monitor"
	pb_router "github.com/TheThingsNetwork/ttn/api/router"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/apex/log"
	context "golang.org/x/net/context"
	"google.golang.org/grpc/metadata"
)

func (g *Gateway) monitorContext() (ctx context.Context) {
	return metadata.NewContext(context.Background(), metadata.Pairs(
		"id", g.ID,
		"token", g.Token,
	))
}

type monitorConn struct {
	clients map[string]pb_monitor.MonitorClient

	status struct {
		streams map[string]pb_monitor.Monitor_GatewayStatusClient
		sync.RWMutex
	}

	uplink struct {
		streams map[string]pb_monitor.Monitor_GatewayUplinkClient
		sync.RWMutex
	}

	downlink struct {
		streams map[string]pb_monitor.Monitor_GatewayDownlinkClient
		sync.RWMutex
	}
}

func (g *Gateway) SetMonitors(clients map[string]pb_monitor.MonitorClient) {
	g.monitor = NewMonitorConn(clients)
}

func NewMonitorConn(clients map[string]pb_monitor.MonitorClient) (conn *monitorConn) {
	conn = &monitorConn{clients: clients}
	conn.uplink.streams = make(map[string]pb_monitor.Monitor_GatewayUplinkClient)
	conn.downlink.streams = make(map[string]pb_monitor.Monitor_GatewayDownlinkClient)
	conn.status.streams = make(map[string]pb_monitor.Monitor_GatewayStatusClient)
	return conn
}

func (g *Gateway) pushStatusToMonitor(ctx log.Interface, name string, status *pb.Status) (err error) {
	defer func() {
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Warn("Monitor status push failed")
		} else {
			ctx.Debug("Pushed status to monitor")
		}
	}()

	g.monitor.status.RLock()
	stream, ok := g.monitor.status.streams[name]
	g.monitor.status.RUnlock()

	if !ok {
		g.monitor.status.Lock()
		if _, ok := g.monitor.status.streams[name]; !ok {
			cl, ok := g.monitor.clients[name]
			if !ok {
				// Should not happen
				return errors.New("Monitor not found")
			}

			stream, err = cl.GatewayStatus(g.monitorContext())
			if err != nil {
				// TODO check if err returned is GRPC error
				err = errors.FromGRPCError(err)
				ctx.WithError(err).Warn("Failed to open new status stream")
				return err
			}
			ctx.Debug("Opened new status stream")

			g.monitor.status.streams[name] = stream
		}
		g.monitor.status.Unlock()
	}

	if err = stream.Send(status); err == io.EOF {
		ctx.Warn("Status stream closed")
		g.monitor.status.Lock()
		if g.monitor.status.streams[name] == stream {
			delete(g.monitor.status.streams, name)
		}
		g.monitor.status.Unlock()
	}
	return err
}

func (g *Gateway) pushUplinkToMonitor(ctx log.Interface, name string, uplink *pb_router.UplinkMessage) (err error) {
	defer func() {
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Warn("Monitor uplink push failed")
		} else {
			ctx.Debug("Pushed uplink to monitor")
		}
	}()

	g.monitor.uplink.RLock()
	stream, ok := g.monitor.uplink.streams[name]
	g.monitor.uplink.RUnlock()

	if !ok {
		g.monitor.uplink.Lock()
		if _, ok := g.monitor.uplink.streams[name]; !ok {
			cl, ok := g.monitor.clients[name]
			if !ok {
				// Should not happen
				return errors.New("Monitor not found")
			}

			stream, err = cl.GatewayUplink(g.monitorContext())
			if err != nil {
				// TODO check if err returned is GRPC error
				err = errors.FromGRPCError(err)
				ctx.WithError(err).Warn("Failed to open new uplink stream")
				return err
			}
			ctx.Debug("Opened new uplink stream")

			g.monitor.uplink.streams[name] = stream
		}
		g.monitor.uplink.Unlock()
	}

	if err = stream.Send(uplink); err == io.EOF {
		ctx.Warn("Uplink stream closed")
		g.monitor.uplink.Lock()
		if g.monitor.uplink.streams[name] == stream {
			delete(g.monitor.uplink.streams, name)
		}
		g.monitor.uplink.Unlock()
	}
	return err
}

func (g *Gateway) pushDownlinkToMonitor(ctx log.Interface, name string, downlink *pb_router.DownlinkMessage) (err error) {
	defer func() {
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Warn("Monitor downlink push failed")
		} else {
			ctx.Debug("Pushed downlink to monitor")
		}
	}()

	g.monitor.downlink.RLock()
	stream, ok := g.monitor.downlink.streams[name]
	g.monitor.downlink.RUnlock()

	if !ok {
		g.monitor.downlink.Lock()
		if _, ok := g.monitor.downlink.streams[name]; !ok {
			cl, ok := g.monitor.clients[name]
			if !ok {
				// Should not happen
				return errors.New("Monitor not found")
			}

			stream, err = cl.GatewayDownlink(g.monitorContext())
			if err != nil {
				// TODO check if err returned is GRPC error
				err = errors.FromGRPCError(err)
				ctx.WithError(err).Warn("Failed to open new downlink stream")
				return err
			}
			ctx.Debug("Opened new downlink stream")

			g.monitor.downlink.streams[name] = stream
		}
		g.monitor.downlink.Unlock()
	}

	if err = stream.Send(downlink); err == io.EOF {
		ctx.Warn("Downlink stream closed")
		g.monitor.downlink.Lock()
		if g.monitor.downlink.streams[name] == stream {
			delete(g.monitor.downlink.streams, name)
		}
		g.monitor.downlink.Unlock()
	}
	return err
}
<|endoftext|>