<commit_before>package ot

// extend.go
//
// Extending Oblivious Transfers Efficiently
// Yuval Ishai, Joe Kilian, Kobbi Nissim, Erez Petrank
// CRYPTO 2003
// http://link.springer.com/chapter/10.1007/978-3-540-45146-4_9
//
// Modified with preprocessing step

import (
	"crypto/rand"
	"fmt"
	"io"

	"bitbucket.org/ede/sha3"
	"github.com/tjim/smpcc/runtime/bit"
)

type ExtendSender struct {
	R            Receiver
	z0, z1       [][]byte
	m            int
	k            int
	otExtChan    chan []byte
	otExtSelChan chan Selector
	l            int
	curPair      int
	started      bool
	sendCalls    int
}

type ExtendReceiver struct {
	S            Sender
	r            []byte
	m            int
	k            int
	otExtChan    chan []byte
	otExtSelChan chan Selector
	l            int
	curPair      int
	T            *bit.Matrix8
}

func NewExtendSender(c chan []byte, otExtSelChan chan Selector, R Receiver, k, l, m int) Sender {
	if k%8 != 0 {
		panic("k must be a multiple of 8")
	}
	if l%8 != 0 {
		panic("l must be a multiple of 8")
	}
	if m%8 != 0 {
		panic("m must be a multiple of 8")
	}
	sender := new(ExtendSender)
	sender.otExtSelChan = otExtSelChan
	sender.k = k
	sender.l = l
	sender.R = R
	sender.otExtChan = c
	sender.m = m
	sender.curPair = m
	sender.started = false
	sender.sendCalls = 0
	return sender
}

func NewExtendReceiver(c chan []byte, otExtSelChan chan Selector, S Sender, k, l, m int) Receiver {
	if k%8 != 0 {
		panic("k must be a multiple of 8")
	}
	if l%8 != 0 {
		panic("l must be a multiple of 8")
	}
	if m%8 != 0 {
		panic("m must be a multiple of 8")
	}
	receiver := new(ExtendReceiver)
	receiver.otExtSelChan = otExtSelChan
	receiver.k = k
	receiver.l = l
	receiver.S = S
	receiver.m = m
	receiver.curPair = m
	receiver.otExtChan = c
	return receiver
}

func (self *ExtendSender) preProcessSender(m int) {
	if m%8 != 0 {
		panic("m must be a multiple of 8")
	}
	// fmt.Printf("pre-processing sender: start\n")
	self.started = true
	self.m = m
	//	log.Printf("preProcessSender: m=%d", m)
	self.curPair = 0
	s := make([]byte, self.k/8)
	randomBitVector(s)

	QT := bit.NewMatrix8(self.k, self.m)
	for i := 0; i < QT.NumRows; i++ {
		recvd := self.R.Receive(Selector(bit.GetBit(s, i)))
		//		log.Printf("preProcessSender: len(recvd)=%d", len(recvd))
		if len(recvd) != self.m/8 {
			panic(fmt.Sprintf("Incorrect column length received: %d != %d", len(recvd), self.m/8))
		}
		QT.SetRow(i, recvd)
	}
	Q := QT.Transpose()
	self.z0 = make([][]byte, m)
	// fmt.Printf("pre-processing sender: len(z0)=%d\n", len(self.z0))
	self.z1 = make([][]byte, m)
	temp := make([]byte, self.k/8)
	for j := 0; j < m; j++ {
		self.z0[j] = RO(Q.GetRow(j), self.l)
		xorBytesExact(temp, Q.GetRow(j), s)
		self.z1[j] = RO(temp, self.l)
	}

}

func (self *ExtendReceiver) preProcessReceiver(m int) {
	// fmt.Printf("pre-processing receiver\n")
	self.curPair = 0
	self.m = m
	//	log.Printf("preProcessReceiver: m=%d", m)
	self.r = make([]byte, self.m/8)
	for i := range self.r { // TJIM: Since we randomize isn't this unnecessary?
		self.r[i] = byte(255)
	}
	randomBitVector(self.r)
	//	fmt.Printf("preProcessReceiver: len(self.r)=%d\n", len(self.r))
	T := bit.NewMatrix8(self.m, self.k)
	T.Randomize()
	TT := T.Transpose()
	self.T = T
	in1 := make([][]byte, self.k) // TJIM: no need to keep in[i] around after Send, just compute on demand
	for i := range in1 {
		in1[i] = make([]byte, self.m/8)
		xorBytesExact(in1[i], self.r, TT.GetRow(i))
	}
	for i := 0; i < self.k; i++ {
		self.S.Send(TT.GetRow(i), in1[i])
	}
}

// hash function instantiating a random oracle
func RO(input []byte, outBits int) []byte {
	if outBits <= 0 {
		panic("output size <= 0")
	}
	if outBits%8 != 0 {
		panic("output size must be a multiple of 8")
	}
	h := sha3.NewCipher(input, nil)
	output := make([]byte, outBits/8)
	h.XORKeyStream(output, output)
	return output
}

func (self *ExtendSender) Send(m0, m1 Message) {
	if len(m0)*8 != self.l || len(m1)*8 != self.l {
		panic(fmt.Sprintf("Send: wrong message length. Should be %d, got %d and %d", self.l, len(m0), len(m1)))
	}
	// self.sendCalls++
	if self.curPair == self.m {
		self.preProcessSender(self.m)
	}
	y0 := make([]byte, self.l/8)
	y1 := make([]byte, self.l/8)
	// fmt.Printf("Send: self.l=%d, self.l%%8=%d, len(y0)=%d, len(y1)=%d\n", self.l, self.l/8, len(y0), len(y1))
	smod := <-self.otExtSelChan
	// log.Printf("Send: self.curPair=%d, len(z0)=%d, smod=%d, m=%d, started=%v, sendCalls=%d\n", self.curPair, len(self.z0), smod, self.m,
	// self.started, self.sendCalls)
	if smod == 0 {
		xorBytesExact(y0, m0, self.z0[self.curPair])
		xorBytesExact(y1, m1, self.z1[self.curPair])
	} else if smod == 1 {
		xorBytesExact(y0, m1, self.z0[self.curPair])
		xorBytesExact(y1, m0, self.z1[self.curPair])
	} else {
		panic("Sender: unexpected smod value")
	}
	// fmt.Printf("Send: self.z0[%d]=%v self.z1[%d]=%v\n",self.curPair,self.z0[self.curPair],self.curPair,self.z1[self.curPair])
	// fmt.Printf("Send:    y0=%v y1=%v\n",y0,y1)
	// fmt.Printf("Send:    m0=%v m1=%v\n",m0,m1)
	self.otExtChan <- y0
	self.otExtChan <- y1
	self.curPair++
	return
}

func (self *ExtendReceiver) Receive(s Selector) Message {
	if self.curPair == self.m {
		self.preProcessReceiver(self.m)
	}
	smod := Selector(byte(s) ^ bit.GetBit(self.r, self.curPair))
	//	log.Printf("Receive: self.curPair=%d, len(self.r)=%d\n", self.curPair, len(self.r))
	self.otExtSelChan <- smod
	y0 := <-self.otExtChan
	y1 := <-self.otExtChan
	w := make([]byte, self.l/8)
	// fmt.Printf("Receive: y0=%v y1=%v\n", y0, y1)
	if bit.GetBit(self.r, self.curPair) == 0 {
		xorBytesExact(w, y0, RO(self.T.GetRow(self.curPair), self.l))
	} else if bit.GetBit(self.r, self.curPair) == 1 {
		xorBytesExact(w, y1, RO(self.T.GetRow(self.curPair), self.l))
	}
	self.curPair++
	return w
}

func xorBytesExact(a, b, c []byte) {
	if len(a) != len(b) || len(b) != len(c) {
		panic(fmt.Sprintf("xorBytesExact: wrong lengths (%d,%d,%d)\n", len(a), len(b), len(c)))
	}
	xorBytes(a, b, c)
}

func randomBitVector(pool []byte) {
	n, err := io.ReadFull(rand.Reader, pool)
	if err != nil || n != len(pool) {
		panic("randomness allocation failed")
	}
}
<commit_msg>Working on variable-length messages for otexend<commit_after>package ot

// extend.go
//
// Extending Oblivious Transfers Efficiently
// Yuval Ishai, Joe Kilian, Kobbi Nissim, Erez Petrank
// CRYPTO 2003
// http://link.springer.com/chapter/10.1007/978-3-540-45146-4_9
//
// Modified with preprocessing step

import (
	"crypto/rand"
	"fmt"
	"io"

	"bitbucket.org/ede/sha3"
	"github.com/tjim/smpcc/runtime/bit"
)

type ExtendSender struct {
	R            Receiver
	z0, z1       [][]byte
	m            int
	k            int
	otExtChan    chan []byte
	otExtSelChan chan Selector
	l            int
	curPair      int
	started      bool
	sendCalls    int
}

type ExtendReceiver struct {
	S            Sender
	r            []byte
	m            int
	k            int
	otExtChan    chan []byte
	otExtSelChan chan Selector
	l            int
	curPair      int
	T            *bit.Matrix8
}

func NewExtendSender(c chan []byte, otExtSelChan chan Selector, R Receiver, k, l, m int) Sender {
	if k%8 != 0 {
		panic("k must be a multiple of 8")
	}
	if l%8 != 0 {
		panic("l must be a multiple of 8")
	}
	if m%8 != 0 {
		panic("m must be a multiple of 8")
	}
	sender := new(ExtendSender)
	sender.otExtSelChan = otExtSelChan
	sender.k = k
	sender.l = l
	sender.R = R
	sender.otExtChan = c
	sender.m = m
	sender.curPair = m
	sender.started = false
	sender.sendCalls = 0
	return sender
}

func NewExtendReceiver(c chan []byte, otExtSelChan chan Selector, S Sender, k, l, m int) Receiver {
	if k%8 != 0 {
		panic("k must be a multiple of 8")
	}
	if l%8 != 0 {
		panic("l must be a multiple of 8")
	}
	if m%8 != 0 {
		panic("m must be a multiple of 8")
	}
	receiver := new(ExtendReceiver)
	receiver.otExtSelChan = otExtSelChan
	receiver.k = k
	receiver.l = l
	receiver.S = S
	receiver.m = m
	receiver.curPair = m
	receiver.otExtChan = c
	return receiver
}

func (self *ExtendSender) preProcessSender(m int) {
	if m%8 != 0 {
		panic("m must be a multiple of 8")
	}
	// fmt.Printf("pre-processing sender: start\n")
	self.started = true
	self.m = m
	//	log.Printf("preProcessSender: m=%d", m)
	self.curPair = 0
	s := make([]byte, self.k/8)
	randomBitVector(s)

	QT := bit.NewMatrix8(self.k, self.m)
	for i := 0; i < QT.NumRows; i++ {
		recvd := self.R.Receive(Selector(bit.GetBit(s, i)))
		//		log.Printf("preProcessSender: len(recvd)=%d", len(recvd))
		if len(recvd) != self.m/8 {
			panic(fmt.Sprintf("Incorrect column length received: %d != %d", len(recvd), self.m/8))
		}
		QT.SetRow(i, recvd)
	}
	Q := QT.Transpose()
	self.z0 = make([][]byte, m)
	// fmt.Printf("pre-processing sender: len(z0)=%d\n", len(self.z0))
	self.z1 = make([][]byte, m)
	temp := make([]byte, self.k/8)
	for j := 0; j < m; j++ {
		self.z0[j] = Q.GetRow(j)
		xorBytesExact(temp, Q.GetRow(j), s)
		self.z1[j] = temp
	}

}

func (self *ExtendReceiver) preProcessReceiver(m int) {
	// fmt.Printf("pre-processing receiver\n")
	self.curPair = 0
	self.m = m
	//	log.Printf("preProcessReceiver: m=%d", m)
	self.r = make([]byte, self.m/8)
	for i := range self.r { // TJIM: Since we randomize isn't this unnecessary?
		self.r[i] = byte(255)
	}
	randomBitVector(self.r)
	//	fmt.Printf("preProcessReceiver: len(self.r)=%d\n", len(self.r))
	T := bit.NewMatrix8(self.m, self.k)
	T.Randomize()
	TT := T.Transpose()
	self.T = T
	in1 := make([][]byte, self.k) // TJIM: no need to keep in[i] around after Send, just compute on demand
	for i := range in1 {
		in1[i] = make([]byte, self.m/8)
		xorBytesExact(in1[i], self.r, TT.GetRow(i))
	}
	for i := 0; i < self.k; i++ {
		self.S.Send(TT.GetRow(i), in1[i])
	}
}

// hash function instantiating a random oracle
func RO(input []byte, outBits int) []byte {
	if outBits <= 0 {
		panic("output size <= 0")
	}
	if outBits%8 != 0 {
		panic("output size must be a multiple of 8")
	}
	h := sha3.NewCipher(input, nil)
	output := make([]byte, outBits/8)
	h.XORKeyStream(output, output)
	return output
}

func (self *ExtendSender) Send(m0, m1 Message) {
	// self.sendCalls++
	if self.curPair == self.m {
		self.preProcessSender(self.m)
	}
	if len(m0) != len(m1) {
		panic("(*ot.ExtendSender).Send: messages have different lengths")
	}
	msglen := len(m0)
	y0 := make([]byte, msglen)
	y1 := make([]byte, msglen)
	// fmt.Printf("Send: self.l=%d, self.l%%8=%d, len(y0)=%d, len(y1)=%d\n", self.l, self.l/8, len(y0), len(y1))
	smod := <-self.otExtSelChan
	// log.Printf("Send: self.curPair=%d, len(z0)=%d, smod=%d, m=%d, started=%v, sendCalls=%d\n", self.curPair, len(self.z0), smod, self.m,
	// self.started, self.sendCalls)
	if smod == 0 {
		xorBytesExact(y0, m0, RO(self.z0[self.curPair], 8*msglen))
		xorBytesExact(y1, m1, RO(self.z1[self.curPair], 8*msglen))
	} else if smod == 1 {
		xorBytesExact(y0, m1, RO(self.z0[self.curPair], 8*msglen))
		xorBytesExact(y1, m0, RO(self.z1[self.curPair], 8*msglen))
	} else {
		panic("Sender: unexpected smod value")
	}
	// fmt.Printf("Send: self.z0[%d]=%v self.z1[%d]=%v\n",self.curPair,self.z0[self.curPair],self.curPair,self.z1[self.curPair])
	// fmt.Printf("Send:    y0=%v y1=%v\n",y0,y1)
	// fmt.Printf("Send:    m0=%v m1=%v\n",m0,m1)
	self.otExtChan <- y0
	self.otExtChan <- y1
	self.curPair++
	return
}

func (self *ExtendReceiver) Receive(s Selector) Message {
	if self.curPair == self.m {
		self.preProcessReceiver(self.m)
	}
	smod := Selector(byte(s) ^ bit.GetBit(self.r, self.curPair))
	//	log.Printf("Receive: self.curPair=%d, len(self.r)=%d\n", self.curPair, len(self.r))
	self.otExtSelChan <- smod
	y0 := <-self.otExtChan
	y1 := <-self.otExtChan
	if len(y0) != len(y1) {
		panic("(*ot.ExtendReceiver).Receive: messages have different length")
	}
	msglen := len(y0)
	w := make([]byte, msglen)
	// fmt.Printf("Receive: y0=%v y1=%v\n", y0, y1)
	if bit.GetBit(self.r, self.curPair) == 0 {
		xorBytesExact(w, y0, RO(self.T.GetRow(self.curPair), 8*msglen))
	} else if bit.GetBit(self.r, self.curPair) == 1 {
		xorBytesExact(w, y1, RO(self.T.GetRow(self.curPair), 8*msglen))
	}
	self.curPair++
	return w
}

func xorBytesExact(a, b, c []byte) {
	if len(a) != len(b) || len(b) != len(c) {
		panic(fmt.Sprintf("xorBytesExact: wrong lengths (%d,%d,%d)\n", len(a), len(b), len(c)))
	}
	xorBytes(a, b, c)
}

func randomBitVector(pool []byte) {
	n, err := io.ReadFull(rand.Reader, pool)
	if err != nil || n != len(pool) {
		panic("randomness allocation failed")
	}
}
<|endoftext|>


<commit_before>package runtime

import (
	"context"
	"sync"

	"github.com/containerd/containerd/namespaces"
	"github.com/pkg/errors"
)

var (
	// ErrTaskNotExists is returned when a task does not exist
	ErrTaskNotExists = errors.New("task does not exist")
	// ErrTaskAlreadyExists is returned when a task already exists
	ErrTaskAlreadyExists = errors.New("task already exists")
)

// NewTaskList returns a new TaskList
func NewTaskList() *TaskList {
	return &TaskList{
		tasks: make(map[string]map[string]Task),
	}
}

// TaskList holds and provides locking around tasks
type TaskList struct {
	mu    sync.Mutex
	tasks map[string]map[string]Task
}

// Get a task
func (l *TaskList) Get(ctx context.Context, id string) (Task, error) {
	l.mu.Lock()
	defer l.mu.Unlock()
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}
	tasks, ok := l.tasks[namespace]
	if !ok {
		return nil, ErrTaskNotExists
	}
	t, ok := tasks[id]
	if !ok {
		return nil, ErrTaskNotExists
	}
	return t, nil
}

// GetAll tasks under a namespace
func (l *TaskList) GetAll(ctx context.Context) ([]Task, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}
	var o []Task
	tasks, ok := l.tasks[namespace]
	if !ok {
		return o, nil
	}
	for _, t := range tasks {
		o = append(o, t)
	}
	return o, nil
}

// Add a task
func (l *TaskList) Add(ctx context.Context, t Task) error {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return err
	}
	return l.AddWithNamespace(namespace, t)
}

// AddWithNamespace adds a task with the provided namespace
func (l *TaskList) AddWithNamespace(namespace string, t Task) error {
	l.mu.Lock()
	defer l.mu.Unlock()

	id := t.ID()
	if _, ok := l.tasks[namespace]; !ok {
		l.tasks[namespace] = make(map[string]Task)
	}
	if _, ok := l.tasks[namespace][id]; ok {
		return errors.Wrap(ErrTaskAlreadyExists, id)
	}
	l.tasks[namespace][id] = t
	return nil
}

// Delete a task
func (l *TaskList) Delete(ctx context.Context, t Task) {
	l.mu.Lock()
	defer l.mu.Unlock()
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return
	}
	tasks, ok := l.tasks[namespace]
	if ok {
		delete(tasks, t.ID())
	}
}
<commit_msg>Lock task list properly.<commit_after>package runtime

import (
	"context"
	"sync"

	"github.com/containerd/containerd/namespaces"
	"github.com/pkg/errors"
)

var (
	// ErrTaskNotExists is returned when a task does not exist
	ErrTaskNotExists = errors.New("task does not exist")
	// ErrTaskAlreadyExists is returned when a task already exists
	ErrTaskAlreadyExists = errors.New("task already exists")
)

// NewTaskList returns a new TaskList
func NewTaskList() *TaskList {
	return &TaskList{
		tasks: make(map[string]map[string]Task),
	}
}

// TaskList holds and provides locking around tasks
type TaskList struct {
	mu    sync.Mutex
	tasks map[string]map[string]Task
}

// Get a task
func (l *TaskList) Get(ctx context.Context, id string) (Task, error) {
	l.mu.Lock()
	defer l.mu.Unlock()
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}
	tasks, ok := l.tasks[namespace]
	if !ok {
		return nil, ErrTaskNotExists
	}
	t, ok := tasks[id]
	if !ok {
		return nil, ErrTaskNotExists
	}
	return t, nil
}

// GetAll tasks under a namespace
func (l *TaskList) GetAll(ctx context.Context) ([]Task, error) {
	l.mu.Lock()
	defer l.mu.Unlock()
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}
	var o []Task
	tasks, ok := l.tasks[namespace]
	if !ok {
		return o, nil
	}
	for _, t := range tasks {
		o = append(o, t)
	}
	return o, nil
}

// Add a task
func (l *TaskList) Add(ctx context.Context, t Task) error {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return err
	}
	return l.AddWithNamespace(namespace, t)
}

// AddWithNamespace adds a task with the provided namespace
func (l *TaskList) AddWithNamespace(namespace string, t Task) error {
	l.mu.Lock()
	defer l.mu.Unlock()

	id := t.ID()
	if _, ok := l.tasks[namespace]; !ok {
		l.tasks[namespace] = make(map[string]Task)
	}
	if _, ok := l.tasks[namespace][id]; ok {
		return errors.Wrap(ErrTaskAlreadyExists, id)
	}
	l.tasks[namespace][id] = t
	return nil
}

// Delete a task
func (l *TaskList) Delete(ctx context.Context, t Task) {
	l.mu.Lock()
	defer l.mu.Unlock()
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return
	}
	tasks, ok := l.tasks[namespace]
	if ok {
		delete(tasks, t.ID())
	}
}
<|endoftext|>


<commit_before>package chroot

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"testing"
	"time"

	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/multistep"
)

func TestStepMountDevice_Run(t *testing.T) {
	mountPath, err := ioutil.TempDir("", "stepmountdevicetest")
	if err != nil {
		t.Errorf("Unable to create a temporary directory: %q", err)
	}
	step := &StepMountDevice{
		MountOptions:   []string{"foo"},
		MountPartition: "42",
		MountPath:      mountPath,
	}

	var gotCommand string
	var wrapper common.CommandWrapper
	wrapper = func(ran string) (string, error) {
		gotCommand = ran
		return "", nil
	}

	state := new(multistep.BasicStateBag)
	state.Put("wrappedCommand", wrapper)
	state.Put("device", "/dev/quux")

	ui, getErrs := testUI()
	state.Put("ui", ui)

	var config Config
	state.Put("config", &config)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	got := step.Run(ctx, state)
	if got != multistep.ActionContinue {
		t.Errorf("Expected 'continue', but got '%v'", got)
	}

	var expectedMountDevice string
	switch runtime.GOOS {
	case "freebsd":
		expectedMountDevice = "/dev/quuxp42"
	default: // currently just Linux
		expectedMountDevice = "/dev/quux42"
	}
	expectedCommand := fmt.Sprintf("mount -o foo %s %s", expectedMountDevice, mountPath)
	if gotCommand != expectedCommand {
		t.Errorf("Expected '%v', but got '%v'", expectedCommand, gotCommand)
	}

	os.Remove(mountPath)
	_ = getErrs
}
<commit_msg>Only run on platforms supported by chroot.<commit_after>//+build linux,freebsd

package chroot

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"testing"
	"time"

	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/multistep"
)

func TestStepMountDevice_Run(t *testing.T) {
	mountPath, err := ioutil.TempDir("", "stepmountdevicetest")
	if err != nil {
		t.Errorf("Unable to create a temporary directory: %q", err)
	}
	step := &StepMountDevice{
		MountOptions:   []string{"foo"},
		MountPartition: "42",
		MountPath:      mountPath,
	}

	var gotCommand string
	var wrapper common.CommandWrapper
	wrapper = func(ran string) (string, error) {
		gotCommand = ran
		return "", nil
	}

	state := new(multistep.BasicStateBag)
	state.Put("wrappedCommand", wrapper)
	state.Put("device", "/dev/quux")

	ui, getErrs := testUI()
	state.Put("ui", ui)

	var config Config
	state.Put("config", &config)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	got := step.Run(ctx, state)
	if got != multistep.ActionContinue {
		t.Errorf("Expected 'continue', but got '%v'", got)
	}

	var expectedMountDevice string
	switch runtime.GOOS {
	case "freebsd":
		expectedMountDevice = "/dev/quuxp42"
	default: // currently just Linux
		expectedMountDevice = "/dev/quux42"
	}
	expectedCommand := fmt.Sprintf("mount -o foo %s %s", expectedMountDevice, mountPath)
	if gotCommand != expectedCommand {
		t.Errorf("Expected '%v', but got '%v'", expectedCommand, gotCommand)
	}

	os.Remove(mountPath)
	_ = getErrs
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Spotify AB.
//
//  Licensed to the Apache Software Foundation (ASF) under one
//  or more contributor license agreements.  See the NOTICE file
//  distributed with this work for additional information
//  regarding copyright ownership.  The ASF licenses this file
//  to you under the Apache License, Version 2.0 (the
//  "License"); you may not use this file except in compliance
//  with the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an
//  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//  KIND, either express or implied.  See the License for the
//  specific language governing permissions and limitations
//  under the License.

package main

import (
	"bytes"
	"errors"
	"flag"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
)

type Syslogger struct {
	logger   *Writer
	stream   string
	buffer   *bytes.Buffer
	hostPort string
	priority Priority
	prefix   string
	logFlags int
	protocol string
}

func (s *Syslogger) Write(p []byte) (n int, err error) {
	if s.logger == nil {
		sl, err := Dial(s.protocol, s.hostPort, s.priority, s.prefix)
		if err != nil {
			// while syslog is down, dump the output
			return len(p), nil
		}
		s.logger = sl
	}

	if s.logger == nil { // shouldn't happen
		return len(p), nil // dump output
	}

	for b := range p {
		s.buffer.WriteByte(p[b])
		if p[b] == 10 { // newline
			_, err := s.logger.Write(s.buffer.Bytes())
			if err != nil {
				s.logger = nil
			}
			s.buffer = bytes.NewBuffer([]byte{})
		}
	}
	return len(p), nil
}

func (s *Syslogger) Close() error {
	return nil
}

func NewSysLogger(stream, hostPort, prefix, protocol string) (*Syslogger, error) {
	var priority Priority
	if stream == "stderr" {
		priority = LOG_ERR | LOG_LOCAL0
	} else if stream == "stdout" {
		priority = LOG_INFO | LOG_LOCAL0
	} else {
		return nil, errors.New("cannot create syslogger for stream " + stream)
	}
	logFlags := 0

	return &Syslogger{nil, stream, bytes.NewBuffer([]byte{}), hostPort, priority, prefix, logFlags, protocol}, nil
}

func usage() {
	log.Printf("usage: %s -h syslog_host:port -n name -- executable [arg ...]", os.Args[0])
	flag.PrintDefaults()
	os.Exit(1)
}

func setupSignalHandlers(pid *exec.Cmd) {

	sigc := make(chan os.Signal, 1)

	sigarray := make([]os.Signal, 30)
	for i := 0; i < 30; i++ {
		sigarray[i] = syscall.Signal(i + 1)
	}

	signal.Notify(sigc, sigarray...)

	go func() {
		for {
			if pid.ProcessState != nil {
				break
			}
			s := <-sigc
			var ss syscall.Signal
			ss = s.(syscall.Signal)
			syscall.Kill(pid.Process.Pid, ss)
		}
	}()

}

func main() {
	log.SetFlags(0)

	flHostPort := flag.String("h", "", "Host port of where to connect to the syslog daemon")
	flLogName := flag.String("n", "", "Name to log as")
	flProtocol := flag.Bool("t", false, "use TCP instead of UDP (the default) for syslog communication")
	flTee := flag.Bool("tee", false, "also write to stdout and stderr")
	flag.Parse()

	if *flHostPort == "" {
		log.Printf("Must set the syslog host:port argument")
		usage()
	}

	if *flLogName == "" {
		log.Printf("Must set the syslog log name argument")
		usage()
	}

	protocol := "udp"
	if *flProtocol {
		protocol = "tcp"
	}

	//Example ./syslog-redirector -h 10.0.3.1:6514 -n test-ls-thingy -- \
	//            /bin/bash -c 'while true; do date; echo $SHELL; sleep 1; done'
	if len(os.Args) < 4 {
		log.Printf("at least 3 arguments required")
		usage()
	}
	hostPort := *flHostPort
	name := *flLogName

	if len(flag.Args()) == 0 {
		log.Printf("must supply a command")
		usage()
	}

	cmdName := flag.Args()[0]
	cmdArgs := flag.Args()[1:]

	var err error

	path, err := exec.LookPath(cmdName)
	if err != nil {
		log.Printf("Unable to locate %v", cmdName)
		os.Exit(127)
	}

	cmd := exec.Command(path, cmdArgs...)

	// TODO (dano): tolerate syslog downtime by reconnecting

	cmd.Stdout, err = NewSysLogger("stdout", hostPort, name, protocol)
	if err != nil {
		log.Printf("error creating syslog writer for stdout: %v", err)
	}

	cmd.Stderr, err = NewSysLogger("stderr", hostPort, name, protocol)
	if err != nil {
		log.Printf("error creating syslog writer for stderr: %v", err)
	}

	if *flTee {
		cmd.Stdout = io.MultiWriter(os.Stdout, cmd.Stdout)
		cmd.Stderr = io.MultiWriter(os.Stderr, cmd.Stderr)
	}

	err = cmd.Start()

	if err != nil {
		if msg, ok := err.(*exec.ExitError); ok {
			os.Exit(msg.Sys().(syscall.WaitStatus).ExitStatus())
		} else {
			log.Printf("error running command: %v", err)
			os.Exit(1)
		}
	}

	setupSignalHandlers(cmd)
	err = cmd.Wait()

	os.Exit(0)
}
<commit_msg>use subcommand's ExitStatus as syslog-redirector ExitStatus<commit_after>//  Copyright (c) 2014 Spotify AB.
//
//  Licensed to the Apache Software Foundation (ASF) under one
//  or more contributor license agreements.  See the NOTICE file
//  distributed with this work for additional information
//  regarding copyright ownership.  The ASF licenses this file
//  to you under the Apache License, Version 2.0 (the
//  "License"); you may not use this file except in compliance
//  with the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an
//  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//  KIND, either express or implied.  See the License for the
//  specific language governing permissions and limitations
//  under the License.

package main

import (
	"bytes"
	"errors"
	"flag"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
)

type Syslogger struct {
	logger   *Writer
	stream   string
	buffer   *bytes.Buffer
	hostPort string
	priority Priority
	prefix   string
	logFlags int
	protocol string
}

func (s *Syslogger) Write(p []byte) (n int, err error) {
	if s.logger == nil {
		sl, err := Dial(s.protocol, s.hostPort, s.priority, s.prefix)
		if err != nil {
			// while syslog is down, dump the output
			return len(p), nil
		}
		s.logger = sl
	}

	if s.logger == nil { // shouldn't happen
		return len(p), nil // dump output
	}

	for b := range p {
		s.buffer.WriteByte(p[b])
		if p[b] == 10 { // newline
			_, err := s.logger.Write(s.buffer.Bytes())
			if err != nil {
				s.logger = nil
			}
			s.buffer = bytes.NewBuffer([]byte{})
		}
	}
	return len(p), nil
}

func (s *Syslogger) Close() error {
	return nil
}

func NewSysLogger(stream, hostPort, prefix, protocol string) (*Syslogger, error) {
	var priority Priority
	if stream == "stderr" {
		priority = LOG_ERR | LOG_LOCAL0
	} else if stream == "stdout" {
		priority = LOG_INFO | LOG_LOCAL0
	} else {
		return nil, errors.New("cannot create syslogger for stream " + stream)
	}
	logFlags := 0

	return &Syslogger{nil, stream, bytes.NewBuffer([]byte{}), hostPort, priority, prefix, logFlags, protocol}, nil
}

func usage() {
	log.Printf("usage: %s -h syslog_host:port -n name -- executable [arg ...]", os.Args[0])
	flag.PrintDefaults()
	os.Exit(1)
}

func setupSignalHandlers(pid *exec.Cmd) {

	sigc := make(chan os.Signal, 1)

	sigarray := make([]os.Signal, 30)
	for i := 0; i < 30; i++ {
		sigarray[i] = syscall.Signal(i + 1)
	}

	signal.Notify(sigc, sigarray...)

	go func() {
		for {
			if pid.ProcessState != nil {
				break
			}
			s := <-sigc
			var ss syscall.Signal
			ss = s.(syscall.Signal)
			syscall.Kill(pid.Process.Pid, ss)
		}
	}()

}

func main() {
	log.SetFlags(0)

	flHostPort := flag.String("h", "", "Host port of where to connect to the syslog daemon")
	flLogName := flag.String("n", "", "Name to log as")
	flProtocol := flag.Bool("t", false, "use TCP instead of UDP (the default) for syslog communication")
	flTee := flag.Bool("tee", false, "also write to stdout and stderr")
	flag.Parse()

	if *flHostPort == "" {
		log.Printf("Must set the syslog host:port argument")
		usage()
	}

	if *flLogName == "" {
		log.Printf("Must set the syslog log name argument")
		usage()
	}

	protocol := "udp"
	if *flProtocol {
		protocol = "tcp"
	}

	//Example ./syslog-redirector -h 10.0.3.1:6514 -n test-ls-thingy -- \
	//            /bin/bash -c 'while true; do date; echo $SHELL; sleep 1; done'
	if len(os.Args) < 4 {
		log.Printf("at least 3 arguments required")
		usage()
	}
	hostPort := *flHostPort
	name := *flLogName

	if len(flag.Args()) == 0 {
		log.Printf("must supply a command")
		usage()
	}

	cmdName := flag.Args()[0]
	cmdArgs := flag.Args()[1:]

	var err error

	path, err := exec.LookPath(cmdName)
	if err != nil {
		log.Printf("Unable to locate %v", cmdName)
		os.Exit(127)
	}

	cmd := exec.Command(path, cmdArgs...)

	// TODO (dano): tolerate syslog downtime by reconnecting

	cmd.Stdout, err = NewSysLogger("stdout", hostPort, name, protocol)
	if err != nil {
		log.Printf("error creating syslog writer for stdout: %v", err)
	}

	cmd.Stderr, err = NewSysLogger("stderr", hostPort, name, protocol)
	if err != nil {
		log.Printf("error creating syslog writer for stderr: %v", err)
	}

	if *flTee {
		cmd.Stdout = io.MultiWriter(os.Stdout, cmd.Stdout)
		cmd.Stderr = io.MultiWriter(os.Stderr, cmd.Stderr)
	}

	err = cmd.Start()

	if err != nil {
		if msg, ok := err.(*exec.ExitError); ok {
			os.Exit(msg.Sys().(syscall.WaitStatus).ExitStatus())
		} else {
			log.Printf("error running command: %v", err)
			os.Exit(1)
		}
	}

	setupSignalHandlers(cmd)
	err = cmd.Wait()

	if err != nil {
		// on Linux and Windows get the exit code (ExitStatus())
		if exiterr, ok := err.(*exec.ExitError); ok {
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				os.Exit(status.ExitStatus())
			}
		}

		// there was an error, but we don't know how to get
		// exit code on this platform at the moment, let's
		// return a generic error 1
		os.Exit(1)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package raft

import (
	"reflect"
	"testing"
)

func makeAEWithTerm(term TermNo) *RpcAppendEntries {
	return &RpcAppendEntries{term, 0, 0, nil, 0}
}

func makeAEWithTermAndPrevLogDetails(term TermNo, prevli LogIndex, prevterm TermNo) *RpcAppendEntries {
	return &RpcAppendEntries{term, prevli, prevterm, nil, 0}
}

// 1. Reply false if term < currentTerm (#5.1)
func TestCM_RpcAE_LeaderTermLessThanCurrentTerm(t *testing.T) {
	f := func(
		setup func(t *testing.T) (mcm *managedConsensusModule, mrs *mockRpcSender),
	) (*managedConsensusModule, *mockRpcSender) {
		mcm, mrs := setup(t)
		serverTerm := mcm.pcm.persistentState.GetCurrentTerm()

		appendEntries := makeAEWithTerm(serverTerm - 1)

		reply := mcm.pcm.rpc("s2", appendEntries)

		expectedRpc := &RpcAppendEntriesReply{serverTerm, false}
		if !reflect.DeepEqual(reply, expectedRpc) {
			t.Fatal(reply)
		}

		return mcm, mrs
	}

	// Follower
	f(testSetupMCM_Follower_Figure7LeaderLine)

	// Candidate
	{
		mcm, _ := f(testSetupMCM_Candidate_Figure7LeaderLine)

		// #5.2-p4s1: While waiting for votes, a candidate may receive an AppendEntries
		// RPC from another server claiming to be leader.
		// #5.2-p4s3: If the term in the RPC is smaller than the candidate’s current
		// term, then the candidate rejects the RPC and continues in candidate state.
		if mcm.pcm.getServerState() != CANDIDATE {
			t.Fatal()
		}
	}

	// Leader
	{
		mcm, _ := f(testSetupMCM_Leader_Figure7LeaderLine)

		// Assumed: leader ignores a leader from an older term
		if mcm.pcm.getServerState() != LEADER {
			t.Fatal()
		}
	}
}

// 2. Reply false if log doesn't contain an entry at prevLogIndex whose term
//      matches prevLogTerm (#5.3)
// Note: the above language is slightly ambiguous but I'm assuming that this
// step refers strictly to the follower's log not having any entry at
// prevLogIndex since step 3 covers the alternate conflicting entry case.
// Note: this test based on Figure 7, server (b)
func TestCM_RpcAE_NoMatchingLogEntry(t *testing.T) {
	f := func(
		setup func(*testing.T, []TermNo) (*managedConsensusModule, *mockRpcSender),
		senderTermIsSame bool,
	) (*managedConsensusModule, *mockRpcSender) {
		mcm, mrs := setup(t, []TermNo{1, 1, 1, 4})
		serverTerm := mcm.pcm.persistentState.GetCurrentTerm()

		senderTerm := serverTerm
		if !senderTermIsSame {
			senderTerm += 1
		}

		appendEntries := makeAEWithTermAndPrevLogDetails(senderTerm, 10, 6)

		reply := mcm.pcm.rpc("s3", appendEntries)

		expectedRpc := &RpcAppendEntriesReply{senderTerm, false}
		if !reflect.DeepEqual(reply, expectedRpc) {
			t.Fatal(reply)
		}

		if !senderTermIsSame {
			// #RFS-A2: If RPC request or response contains term T > currentTerm:
			// set currentTerm = T, convert to follower (#5.1)
			// #5.1-p3s4: ...; if one server's current term is smaller than the
			// other's, then it updates its current term to the larger value.
			// #5.1-p3s5: If a candidate or leader discovers that its term is out of
			// date, it immediately reverts to follower state.
			// #5.2-p4s1: While waiting for votes, a candidate may receive an
			// AppendEntries RPC from another server claiming to be leader.
			// #5.2-p4s2: If the leader’s term (included in its RPC) is at least as
			// large as the candidate’s current term, then the candidate recognizes
			// the leader as legitimate and returns to follower state.
			if mcm.pcm.getServerState() != FOLLOWER {
				t.Fatal()
			}
			if mcm.pcm.persistentState.GetCurrentTerm() != senderTerm {
				t.Fatal()
			}
		}

		return mcm, mrs
	}

	// Follower
	f(testSetupMCM_Follower_WithTerms, false)
	f(testSetupMCM_Follower_WithTerms, true)

	// Candidate
	{
		mcm, _ := f(testSetupMCM_Candidate_WithTerms, false)

		// #5.2-p4s1: While waiting for votes, a candidate may receive an
		// AppendEntries RPC from another server claiming to be leader.
		// #5.2-p4s2: If the leader’s term (included in its RPC) is at least as
		// large as the candidate’s current term, then the candidate recognizes the
		// leader as legitimate and returns to follower state.
		if mcm.pcm.getServerState() != FOLLOWER {
			t.Fatal()
		}
		if mcm.pcm.persistentState.GetCurrentTerm() != testCurrentTerm+2 {
			t.Fatal()
		}
	}
	f(testSetupMCM_Candidate_WithTerms, true)

	// Leader
	f(testSetupMCM_Leader_WithTerms, false)
	{
		var mcm *managedConsensusModule

		// Extra: raft violation - two leaders with same term
		test_ExpectPanic(
			t,
			func() {
				mcm, _ = f(testSetupMCM_Leader_WithTerms, true)
			},
			"FATAL: two leaders with same term - got AppendEntries from: s3 with term: 9",
		)
	}
}

// 3. If an existing entry conflicts with a new one (same index
// but different terms), delete the existing entry and all that
// follow it (#5.3)
// 4. Append any new entries not already in the log
// 5. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit,
// index of last new entry)
// Note: this is not specified, but I'm assuming that the RPC reply should
// have success set to true.
// Note: this test case based on Figure 7, case (e) in the Raft paper but adds
// some extra entries to also test step 3
func TestCM_RpcAE_Follower_AppendNewEntries(t *testing.T) {
	mcm, _ := setupManagedConsensusModuleR2(
		t,
		[]TermNo{1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4},
	)
	mcm.pcm.volatileState.commitIndex = 3
	followerTerm := mcm.pcm.persistentState.GetCurrentTerm()

	if mcm.pcm.log.getLogEntryAtIndex(6).Command != "c6" {
		t.Error()
	}

	sentLogEntries := []LogEntry{
		{5, "c6'"},
		{5, "c7'"},
		{6, "c8'"},
	}

	appendEntries := &RpcAppendEntries{testCurrentTerm, 5, 4, sentLogEntries, 7}

	reply := mcm.pcm.rpc("s4", appendEntries)

	expectedRpc := &RpcAppendEntriesReply{followerTerm, true}
	if !reflect.DeepEqual(reply, expectedRpc) {
		t.Fatal(reply)
	}

	if iole := mcm.pcm.log.getIndexOfLastEntry(); iole != 8 {
		t.Fatal(iole)
	}
	addedLogEntry := mcm.pcm.log.getLogEntryAtIndex(6)
	if addedLogEntry.TermNo != 5 {
		t.Error()
	}
	if addedLogEntry.Command != "c6'" {
		t.Error()
	}

	if mcm.pcm.volatileState.commitIndex != 7 {
		t.Error()
	}
}

// Variant of TestRpcAEAppendNewEntries to test alternate path for step 5.
// Note: this test case based on Figure 7, case (b) in the Raft paper
func TestCM_RpcAE_Follower_AppendNewEntriesB(t *testing.T) {
	mcm, _ := setupManagedConsensusModuleR2(
		t,
		[]TermNo{1, 1, 1, 4},
	)
	mcm.pcm.volatileState.commitIndex = 3
	followerTerm := mcm.pcm.persistentState.GetCurrentTerm()

	if mcm.pcm.log.getLogEntryAtIndex(4).Command != "c4" {
		t.Error()
	}

	sentLogEntries := []LogEntry{
		{4, "c5'"},
		{5, "c6'"},
	}

	appendEntries := &RpcAppendEntries{testCurrentTerm, 4, 4, sentLogEntries, 7}

	reply := mcm.pcm.rpc("s4", appendEntries)

	expectedRpc := &RpcAppendEntriesReply{followerTerm, true}
	if !reflect.DeepEqual(reply, expectedRpc) {
		t.Fatal(reply)
	}

	if iole := mcm.pcm.log.getIndexOfLastEntry(); iole != 6 {
		t.Fatal(iole)
	}
	addedLogEntry := mcm.pcm.log.getLogEntryAtIndex(6)
	if addedLogEntry.TermNo != 5 {
		t.Error()
	}
	if addedLogEntry.Command != "c6'" {
		t.Error()
	}

	if mcm.pcm.volatileState.commitIndex != 6 {
		t.Error()
	}
}
<commit_msg>Simplify TestCM_RpcAE_NoMatchingLogEntry<commit_after>package raft

import (
	"reflect"
	"testing"
)

func makeAEWithTerm(term TermNo) *RpcAppendEntries {
	return &RpcAppendEntries{term, 0, 0, nil, 0}
}

func makeAEWithTermAndPrevLogDetails(term TermNo, prevli LogIndex, prevterm TermNo) *RpcAppendEntries {
	return &RpcAppendEntries{term, prevli, prevterm, nil, 0}
}

// 1. Reply false if term < currentTerm (#5.1)
func TestCM_RpcAE_LeaderTermLessThanCurrentTerm(t *testing.T) {
	f := func(
		setup func(t *testing.T) (mcm *managedConsensusModule, mrs *mockRpcSender),
	) (*managedConsensusModule, *mockRpcSender) {
		mcm, mrs := setup(t)
		serverTerm := mcm.pcm.persistentState.GetCurrentTerm()

		appendEntries := makeAEWithTerm(serverTerm - 1)

		reply := mcm.pcm.rpc("s2", appendEntries)

		expectedRpc := &RpcAppendEntriesReply{serverTerm, false}
		if !reflect.DeepEqual(reply, expectedRpc) {
			t.Fatal(reply)
		}

		return mcm, mrs
	}

	// Follower
	f(testSetupMCM_Follower_Figure7LeaderLine)

	// Candidate
	{
		mcm, _ := f(testSetupMCM_Candidate_Figure7LeaderLine)

		// #5.2-p4s1: While waiting for votes, a candidate may receive an AppendEntries
		// RPC from another server claiming to be leader.
		// #5.2-p4s3: If the term in the RPC is smaller than the candidate’s current
		// term, then the candidate rejects the RPC and continues in candidate state.
		if mcm.pcm.getServerState() != CANDIDATE {
			t.Fatal()
		}
	}

	// Leader
	{
		mcm, _ := f(testSetupMCM_Leader_Figure7LeaderLine)

		// Assumed: leader ignores a leader from an older term
		if mcm.pcm.getServerState() != LEADER {
			t.Fatal()
		}
	}
}

// 2. Reply false if log doesn't contain an entry at prevLogIndex whose term
//      matches prevLogTerm (#5.3)
// Note: the above language is slightly ambiguous but I'm assuming that this
// step refers strictly to the follower's log not having any entry at
// prevLogIndex since step 3 covers the alternate conflicting entry case.
// Note: this test based on Figure 7, server (b)
func TestCM_RpcAE_NoMatchingLogEntry(t *testing.T) {
	f := func(
		setup func(*testing.T, []TermNo) (*managedConsensusModule, *mockRpcSender),
		senderTermIsNewer bool,
	) (*managedConsensusModule, *mockRpcSender) {
		mcm, mrs := setup(t, []TermNo{1, 1, 1, 4})
		serverTerm := mcm.pcm.persistentState.GetCurrentTerm()

		senderTerm := serverTerm
		if senderTermIsNewer {
			senderTerm += 1
		}

		appendEntries := makeAEWithTermAndPrevLogDetails(senderTerm, 10, 6)

		reply := mcm.pcm.rpc("s3", appendEntries)

		expectedRpc := &RpcAppendEntriesReply{senderTerm, false}
		if !reflect.DeepEqual(reply, expectedRpc) {
			t.Fatal(reply)
		}

		if senderTermIsNewer {
			// #RFS-A2: If RPC request or response contains term T > currentTerm:
			// set currentTerm = T, convert to follower (#5.1)
			// #5.1-p3s4: ...; if one server's current term is smaller than the
			// other's, then it updates its current term to the larger value.
			// #5.1-p3s5: If a candidate or leader discovers that its term is out of
			// date, it immediately reverts to follower state.
			// #5.2-p4s1: While waiting for votes, a candidate may receive an
			// AppendEntries RPC from another server claiming to be leader.
			// #5.2-p4s2: If the leader’s term (included in its RPC) is at least as
			// large as the candidate’s current term, then the candidate recognizes
			// the leader as legitimate and returns to follower state.
			if mcm.pcm.getServerState() != FOLLOWER {
				t.Fatal()
			}
		}
		if mcm.pcm.persistentState.GetCurrentTerm() != senderTerm {
			t.Fatal()
		}

		return mcm, mrs
	}

	// Follower
	f(testSetupMCM_Follower_WithTerms, true)
	f(testSetupMCM_Follower_WithTerms, false)

	// Candidate
	f(testSetupMCM_Candidate_WithTerms, true)
	f(testSetupMCM_Candidate_WithTerms, false)

	// Leader
	f(testSetupMCM_Leader_WithTerms, true)
	{
		var mcm *managedConsensusModule

		// Extra: raft violation - two leaders with same term
		test_ExpectPanic(
			t,
			func() {
				mcm, _ = f(testSetupMCM_Leader_WithTerms, false)
			},
			"FATAL: two leaders with same term - got AppendEntries from: s3 with term: 9",
		)
	}
}

// 3. If an existing entry conflicts with a new one (same index
// but different terms), delete the existing entry and all that
// follow it (#5.3)
// 4. Append any new entries not already in the log
// 5. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit,
// index of last new entry)
// Note: this is not specified, but I'm assuming that the RPC reply should
// have success set to true.
// Note: this test case based on Figure 7, case (e) in the Raft paper but adds
// some extra entries to also test step 3
func TestCM_RpcAE_Follower_AppendNewEntries(t *testing.T) {
	mcm, _ := setupManagedConsensusModuleR2(
		t,
		[]TermNo{1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4},
	)
	mcm.pcm.volatileState.commitIndex = 3
	followerTerm := mcm.pcm.persistentState.GetCurrentTerm()

	if mcm.pcm.log.getLogEntryAtIndex(6).Command != "c6" {
		t.Error()
	}

	sentLogEntries := []LogEntry{
		{5, "c6'"},
		{5, "c7'"},
		{6, "c8'"},
	}

	appendEntries := &RpcAppendEntries{testCurrentTerm, 5, 4, sentLogEntries, 7}

	reply := mcm.pcm.rpc("s4", appendEntries)

	expectedRpc := &RpcAppendEntriesReply{followerTerm, true}
	if !reflect.DeepEqual(reply, expectedRpc) {
		t.Fatal(reply)
	}

	if iole := mcm.pcm.log.getIndexOfLastEntry(); iole != 8 {
		t.Fatal(iole)
	}
	addedLogEntry := mcm.pcm.log.getLogEntryAtIndex(6)
	if addedLogEntry.TermNo != 5 {
		t.Error()
	}
	if addedLogEntry.Command != "c6'" {
		t.Error()
	}

	if mcm.pcm.volatileState.commitIndex != 7 {
		t.Error()
	}
}

// Variant of TestRpcAEAppendNewEntries to test alternate path for step 5.
// Note: this test case based on Figure 7, case (b) in the Raft paper
func TestCM_RpcAE_Follower_AppendNewEntriesB(t *testing.T) {
	mcm, _ := setupManagedConsensusModuleR2(
		t,
		[]TermNo{1, 1, 1, 4},
	)
	mcm.pcm.volatileState.commitIndex = 3
	followerTerm := mcm.pcm.persistentState.GetCurrentTerm()

	if mcm.pcm.log.getLogEntryAtIndex(4).Command != "c4" {
		t.Error()
	}

	sentLogEntries := []LogEntry{
		{4, "c5'"},
		{5, "c6'"},
	}

	appendEntries := &RpcAppendEntries{testCurrentTerm, 4, 4, sentLogEntries, 7}

	reply := mcm.pcm.rpc("s4", appendEntries)

	expectedRpc := &RpcAppendEntriesReply{followerTerm, true}
	if !reflect.DeepEqual(reply, expectedRpc) {
		t.Fatal(reply)
	}

	if iole := mcm.pcm.log.getIndexOfLastEntry(); iole != 6 {
		t.Fatal(iole)
	}
	addedLogEntry := mcm.pcm.log.getLogEntryAtIndex(6)
	if addedLogEntry.TermNo != 5 {
		t.Error()
	}
	if addedLogEntry.Command != "c6'" {
		t.Error()
	}

	if mcm.pcm.volatileState.commitIndex != 6 {
		t.Error()
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.

package grpc_ctxtags

import (
	"github.com/grpc-ecosystem/go-grpc-middleware"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/peer"
)

// UnaryServerInterceptor returns a new unary server interceptors that sets the values for request tags.
func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
	o := evaluateOptions(opts)
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		newCtx := newTagsForCtx(ctx)
		if o.requestFieldsFunc != nil {
			setRequestFieldTags(newCtx, o.requestFieldsFunc, info.FullMethod, req)
		}
		return handler(newCtx, req)
	}
}

// StreamServerInterceptor returns a new streaming server interceptor that sets the values for request tags.
func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
	o := evaluateOptions(opts)
	return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		newCtx := newTagsForCtx(stream.Context())
		if o.requestFieldsFunc == nil {
			// Short-circuit, don't do the expensive bit of allocating a wrappedStream.
			wrappedStream := grpc_middleware.WrapServerStream(stream)
			wrappedStream.WrappedContext = newCtx
			return handler(srv, wrappedStream)
		}
		wrapped := &wrappedStream{stream, info, o, newCtx, true}
		err := handler(srv, wrapped)
		return err
	}
}

// wrappedStream is a thin wrapper around grpc.ServerStream that allows modifying context and extracts log fields from the initial message.
type wrappedStream struct {
	grpc.ServerStream
	info *grpc.StreamServerInfo
	opts *options
	// WrappedContext is the wrapper's own Context. You can assign it.
	WrappedContext context.Context
	initial        bool
}

// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
func (w *wrappedStream) Context() context.Context {
	return w.WrappedContext
}

func (w *wrappedStream) RecvMsg(m interface{}) error {
	err := w.ServerStream.RecvMsg(m)
	// We only do log fields extraction on the single-request of a server-side stream.
	if !w.info.IsClientStream || w.opts.requestFieldsFromInitial && w.initial {
		w.initial = false

		setRequestFieldTags(w.Context(), w.opts.requestFieldsFunc, w.info.FullMethod, m)
	}
	return err
}

func newTagsForCtx(ctx context.Context) context.Context {
	t := Extract(ctx) // will allocate a new one if it didn't exist.
	if peer, ok := peer.FromContext(ctx); ok {
		t.Set("peer.address", peer.Addr)
	}
	return setInContext(ctx, t)
}

func setRequestFieldTags(ctx context.Context, f RequestFieldExtractorFunc, fullMethodName string, req interface{}) {
	if valMap := f(fullMethodName, req); valMap != nil {
		t := Extract(ctx)
		for k, v := range valMap {
			t.Set("grpc.request."+k, v)
		}
	}
}
<commit_msg>change peer.address logrus representaion. (#118)<commit_after>// Copyright 2017 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.

package grpc_ctxtags

import (
	"github.com/grpc-ecosystem/go-grpc-middleware"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/peer"
)

// UnaryServerInterceptor returns a new unary server interceptors that sets the values for request tags.
func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
	o := evaluateOptions(opts)
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		newCtx := newTagsForCtx(ctx)
		if o.requestFieldsFunc != nil {
			setRequestFieldTags(newCtx, o.requestFieldsFunc, info.FullMethod, req)
		}
		return handler(newCtx, req)
	}
}

// StreamServerInterceptor returns a new streaming server interceptor that sets the values for request tags.
func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
	o := evaluateOptions(opts)
	return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		newCtx := newTagsForCtx(stream.Context())
		if o.requestFieldsFunc == nil {
			// Short-circuit, don't do the expensive bit of allocating a wrappedStream.
			wrappedStream := grpc_middleware.WrapServerStream(stream)
			wrappedStream.WrappedContext = newCtx
			return handler(srv, wrappedStream)
		}
		wrapped := &wrappedStream{stream, info, o, newCtx, true}
		err := handler(srv, wrapped)
		return err
	}
}

// wrappedStream is a thin wrapper around grpc.ServerStream that allows modifying context and extracts log fields from the initial message.
type wrappedStream struct {
	grpc.ServerStream
	info *grpc.StreamServerInfo
	opts *options
	// WrappedContext is the wrapper's own Context. You can assign it.
	WrappedContext context.Context
	initial        bool
}

// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
func (w *wrappedStream) Context() context.Context {
	return w.WrappedContext
}

func (w *wrappedStream) RecvMsg(m interface{}) error {
	err := w.ServerStream.RecvMsg(m)
	// We only do log fields extraction on the single-request of a server-side stream.
	if !w.info.IsClientStream || w.opts.requestFieldsFromInitial && w.initial {
		w.initial = false

		setRequestFieldTags(w.Context(), w.opts.requestFieldsFunc, w.info.FullMethod, m)
	}
	return err
}

func newTagsForCtx(ctx context.Context) context.Context {
	t := Extract(ctx) // will allocate a new one if it didn't exist.
	if peer, ok := peer.FromContext(ctx); ok {
		t.Set("peer.address", peer.Addr.String())
	}
	return setInContext(ctx, t)
}

func setRequestFieldTags(ctx context.Context, f RequestFieldExtractorFunc, fullMethodName string, req interface{}) {
	if valMap := f(fullMethodName, req); valMap != nil {
		t := Extract(ctx)
		for k, v := range valMap {
			t.Set("grpc.request."+k, v)
		}
	}
}
<|endoftext|>


<commit_before>package sensors

import (
	"strings"

	"github.com/md14454/gosensors"

	"github.com/influxdb/telegraf/plugins/inputs"
)

type Sensors struct {
	Sensors []string
}

func (_ *Sensors) Description() string {
	return "Monitor sensors using lm-sensors package"
}

var sensorsSampleConfig = `
  # By default, telegraf gathers stats from all sensors
  # detected by the lm-sensors module.
  #
  # Only collect stats from the selected sensors. Sensors
  # are listed as <chip name>:<feature name>. This
  # information can be found by running the sensors command.
  # e.g. sensors -u
  # A * as the feature name will return all features of the chip
  #
  # sensors = ["coretemp-isa-0000:Core 0", "coretemp-isa-0001:*", ... ]
`

func (_ *Sensors) SampleConfig() string {
	return sensorsSampleConfig
}

func (s *Sensors) Gather(acc inputs.Accumulator) error {
	gosensors.Init()
	defer gosensors.Cleanup()

	for _, chip := range gosensors.GetDetectedChips() {
		for _, feature := range chip.GetFeatures() {
			chipName := chip.String()
			featureLabel := feature.GetLabel()

			if len(s.Sensors) != 0 {
				var found bool

				for _, sensor := range s.Sensors {
					parts := strings.SplitN(":", sensor, 2)

					if parts[0] == chipName {
						if parts[1] == "*" || parts[1] == featureLabel {
							found = true
							break
						}
					}
				}

				if !found {
					continue
				}
			}

			tags := map[string]string{
				"chip":          chipName,
				"adapter":       chip.AdapterName(),
				"feature-name":  feature.Name,
				"feature-label": featureLabel,
			}

			fieldName := chipName + ":" + featureLabel

			fields := map[string]interface{}{
				fieldName: feature.GetValue(),
			}

			acc.AddFields("sensors", fields, tags)
		}
	}

	return nil
}

func init() {
	inputs.Add("sensors", func() inputs.Input {
		return &Sensors{}
	})
}
<commit_msg>Change build configuration to linux only<commit_after>// +build linux

package sensors

import (
	"strings"

	"github.com/md14454/gosensors"

	"github.com/influxdb/telegraf/plugins/inputs"
)

type Sensors struct {
	Sensors []string
}

func (_ *Sensors) Description() string {
	return "Monitor sensors using lm-sensors package"
}

var sensorsSampleConfig = `
  # By default, telegraf gathers stats from all sensors
  # detected by the lm-sensors module.
  #
  # Only collect stats from the selected sensors. Sensors
  # are listed as <chip name>:<feature name>. This
  # information can be found by running the sensors command.
  # e.g. sensors -u
  # A * as the feature name will return all features of the chip
  #
  # sensors = ["coretemp-isa-0000:Core 0", "coretemp-isa-0001:*", ... ]
`

func (_ *Sensors) SampleConfig() string {
	return sensorsSampleConfig
}

func (s *Sensors) Gather(acc inputs.Accumulator) error {
	gosensors.Init()
	defer gosensors.Cleanup()

	for _, chip := range gosensors.GetDetectedChips() {
		for _, feature := range chip.GetFeatures() {
			chipName := chip.String()
			featureLabel := feature.GetLabel()

			if len(s.Sensors) != 0 {
				var found bool

				for _, sensor := range s.Sensors {
					parts := strings.SplitN(":", sensor, 2)

					if parts[0] == chipName {
						if parts[1] == "*" || parts[1] == featureLabel {
							found = true
							break
						}
					}
				}

				if !found {
					continue
				}
			}

			tags := map[string]string{
				"chip":          chipName,
				"adapter":       chip.AdapterName(),
				"feature-name":  feature.Name,
				"feature-label": featureLabel,
			}

			fieldName := chipName + ":" + featureLabel

			fields := map[string]interface{}{
				fieldName: feature.GetValue(),
			}

			acc.AddFields("sensors", fields, tags)
		}
	}

	return nil
}

func init() {
	inputs.Add("sensors", func() inputs.Input {
		return &Sensors{}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"text/template"
)

func main() {
	var application struct {
		ApplicationURIs []string `json:"application_uris"`
	}

	err := json.Unmarshal([]byte(os.Getenv("VCAP_APPLICATION")), &application)
	if err != nil {
		log.Fatalf("failed to parse VCAP_APPLICATION: %s", err)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		var withoutAgentPath bool
		path := req.URL.Path

		uri := application.ApplicationURIs[0]

		if strings.HasPrefix(path, "/without-agent-path") {
			uri = fmt.Sprintf("%s/without-agent-path", uri)
			path = strings.TrimPrefix(path, "/without-agent-path")
			withoutAgentPath = true
		}

		switch path {
		case "/v1/deployment/installer/agent/unix/paas-sh/latest":
			context := struct{ URI string }{URI: uri}
			t := template.Must(template.New("install.sh").ParseFiles("install.sh"))
			err := t.Execute(w, context)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

		case "/dynatrace-env.sh", "/liboneagentproc.so":
			contents, err := ioutil.ReadFile(strings.TrimPrefix(req.URL.Path, "/"))
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			w.Write(contents)

		case "/manifest.json":
			payload := map[string]interface{}{}

			if !withoutAgentPath {
				file, err := os.Open("manifest.json")
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}

				err = json.NewDecoder(file).Decode(&payload)
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}
			}

			json.NewEncoder(w).Encode(payload)

		default:
			w.WriteHeader(http.StatusNotFound)
		}
	})

	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil))
}
<commit_msg>Trying to fix dynatrace api integration spec<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"text/template"
)

func main() {
	var application struct {
		ApplicationURIs []string `json:"application_uris"`
	}

	err := json.Unmarshal([]byte(os.Getenv("VCAP_APPLICATION")), &application)
	if err != nil {
		log.Fatalf("failed to parse VCAP_APPLICATION: %s", err)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		var withoutAgentPath bool
		path := req.URL.Path

		uri := application.ApplicationURIs[0]

		if strings.HasPrefix(path, "/without-agent-path") {
			uri = fmt.Sprintf("%s/without-agent-path", uri)
			path = strings.TrimPrefix(path, "/without-agent-path")
			withoutAgentPath = true
		}

		switch path {
		case "/v1/deployment/installer/agent/unix/paas-sh/latest":
			context := struct{ URI string }{URI: uri}
			t := template.Must(template.New("install.sh").ParseFiles("install.sh"))
			err := t.Execute(w, context)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

		case "/dynatrace-env.sh", "/liboneagentproc.so":
			contents, err := ioutil.ReadFile(strings.TrimPrefix(req.URL.Path, "/"))
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			w.Write(contents)

		case "/manifest.json":
			var payload map[string]interface{}
			file, err := os.Open("manifest.json")
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

			err = json.NewDecoder(file).Decode(&payload)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

			if !withoutAgentPath {
				payload["technologies"] = map[string]interface{}{
					"process": map[string]interface{}{
						"linux-x86-64": []struct{}{},
					},
				}
			}

			json.NewEncoder(w).Encode(payload)

		default:
			w.WriteHeader(http.StatusNotFound)
		}
	})

	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil))
}
<|endoftext|>


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

package video

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/paths"
	"github.com/andreaskoch/allmark2/model"
	"github.com/andreaskoch/allmark2/services/converter/markdowntohtml/pattern"
	"github.com/andreaskoch/allmark2/services/converter/markdowntohtml/util"
	"mime"
	"regexp"
	"strings"
)

var (
	// video: [*description text*](*a link to a youtube video or to a video file*)
	markdownPattern = regexp.MustCompile(`video: \[([^\]]+)\]\(([^)]+)\)`)

	// youtube video link pattern
	youTubeVideoPattern = regexp.MustCompile(`http[s]?://www\.youtube\.com/watch\?v=([^&]+)`)

	// vimeo video link pattern
	vimeoVideoPattern = regexp.MustCompile(`http[s]?://vimeo\.com/([\d]+)`)
)

func New(pathProvider paths.Pather, files []*model.File) *VideoExtension {
	return &VideoExtension{
		pathProvider: pathProvider,
		files:        files,
	}
}

type VideoExtension struct {
	pathProvider paths.Pather
	files        []*model.File
}

func (converter *VideoExtension) Convert(markdown string) (convertedContent string, converterError error) {

	convertedContent = markdown

	for {

		found, matches := pattern.IsMatch(convertedContent, markdownPattern)
		if !found || (found && len(matches) != 3) {
			break
		}

		// parameters
		originalText := strings.TrimSpace(matches[0])
		title := strings.TrimSpace(matches[1])
		path := strings.TrimSpace(matches[2])

		// get the code
		renderedCode := converter.getVideoCode(title, path)

		// replace markdown
		convertedContent = strings.Replace(convertedContent, originalText, renderedCode, 1)

	}

	return convertedContent, nil
}

func (converter *VideoExtension) getMatchingFile(path string) *model.File {
	for _, file := range converter.files {
		if file.Route().IsMatch(path) && util.IsVideoFile(file) {
			return file
		}
	}

	return nil
}

func (converter *VideoExtension) getVideoCode(title, path string) string {

	fallback := util.GetHtmlLinkCode(title, path)

	// internal video file
	if util.IsInternalLink(path) {

		if videoFile := converter.getMatchingFile(path); videoFile != nil {

			if mimeType, err := util.GetMimeType(videoFile); err == nil {
				filepath := converter.pathProvider.Path(videoFile.Route().Value())
				return renderVideoFileLink(title, filepath, mimeType)
			}

		}

	} else {

		// external: youtube
		if isYouTube, videoId := isYouTubeLink(path); isYouTube {
			return renderYouTubeVideo(title, videoId)
		}

		// external: vimeo
		if isVimeo, videoId := isVimeoLink(path); isVimeo {
			return renderVimeoVideo(title, videoId)
		}

		// external: html5 video file
		if isVideoFile, mimeType := isVideoFileLink(path); isVideoFile {
			return renderVideoFileLink(title, path, mimeType)
		}

	}

	// return the fallback handler
	return fallback
}

func isYouTubeLink(link string) (isYouTubeLink bool, videoId string) {
	if found, matches := pattern.IsMatch(link, youTubeVideoPattern); found && len(matches) == 2 {
		return true, matches[1]
	}

	return false, ""
}

func renderYouTubeVideo(title, videoId string) string {
	return fmt.Sprintf(`

		%s

`, videoId, title, title, videoId)
}

func isVimeoLink(link string) (isVimeoLink bool, videoId string) {
	if found, matches := pattern.IsMatch(link, vimeoVideoPattern); found && len(matches) == 2 {
		return true, matches[1]
	}

	return false, ""
}

func renderVimeoVideo(title, videoId string) string {
	return fmt.Sprintf(`

		%s

`, videoId, title, title, videoId)
}

func isVideoFileLink(link string) (isVideoFile bool, mimeType string) {

	// abort if the link does not contain a dot
	if !strings.Contains(link, ".") {
		return false, ""
	}

	normalizedLink := strings.ToLower(link)
	fileExtension := normalizedLink[strings.LastIndex(normalizedLink, "."):]
	mimeType = mime.TypeByExtension(fileExtension)

	switch fileExtension {
	case ".mp4", ".ogg", ".ogv", ".webm", ".3gp":
		return true, mimeType
	default:
		return false, ""
	}

	panic("Unreachable")
}

func renderVideoFileLink(title, link, mimetype string) string {
	return fmt.Sprintf(`

		%s
		<video width="560" height="315" controls>
			<source src="%s" type="%s">
		</video>

`, link, title, title, link, mimetype)
}
<commit_msg>Video Extension: Remove the protocol from the youtube and vimeo links<commit_after>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package video

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/paths"
	"github.com/andreaskoch/allmark2/model"
	"github.com/andreaskoch/allmark2/services/converter/markdowntohtml/pattern"
	"github.com/andreaskoch/allmark2/services/converter/markdowntohtml/util"
	"mime"
	"regexp"
	"strings"
)

var (
	// video: [*description text*](*a link to a youtube video or to a video file*)
	markdownPattern = regexp.MustCompile(`video: \[([^\]]+)\]\(([^)]+)\)`)

	// youtube video link pattern
	youTubeVideoPattern = regexp.MustCompile(`http[s]?://www\.youtube\.com/watch\?v=([^&]+)`)

	// vimeo video link pattern
	vimeoVideoPattern = regexp.MustCompile(`http[s]?://vimeo\.com/([\d]+)`)
)

func New(pathProvider paths.Pather, files []*model.File) *VideoExtension {
	return &VideoExtension{
		pathProvider: pathProvider,
		files:        files,
	}
}

type VideoExtension struct {
	pathProvider paths.Pather
	files        []*model.File
}

func (converter *VideoExtension) Convert(markdown string) (convertedContent string, converterError error) {

	convertedContent = markdown

	for {

		found, matches := pattern.IsMatch(convertedContent, markdownPattern)
		if !found || (found && len(matches) != 3) {
			break
		}

		// parameters
		originalText := strings.TrimSpace(matches[0])
		title := strings.TrimSpace(matches[1])
		path := strings.TrimSpace(matches[2])

		// get the code
		renderedCode := converter.getVideoCode(title, path)

		// replace markdown
		convertedContent = strings.Replace(convertedContent, originalText, renderedCode, 1)

	}

	return convertedContent, nil
}

func (converter *VideoExtension) getMatchingFile(path string) *model.File {
	for _, file := range converter.files {
		if file.Route().IsMatch(path) && util.IsVideoFile(file) {
			return file
		}
	}

	return nil
}

func (converter *VideoExtension) getVideoCode(title, path string) string {

	fallback := util.GetHtmlLinkCode(title, path)

	// internal video file
	if util.IsInternalLink(path) {

		if videoFile := converter.getMatchingFile(path); videoFile != nil {

			if mimeType, err := util.GetMimeType(videoFile); err == nil {
				filepath := converter.pathProvider.Path(videoFile.Route().Value())
				return renderVideoFileLink(title, filepath, mimeType)
			}

		}

	} else {

		// external: youtube
		if isYouTube, videoId := isYouTubeLink(path); isYouTube {
			return renderYouTubeVideo(title, videoId)
		}

		// external: vimeo
		if isVimeo, videoId := isVimeoLink(path); isVimeo {
			return renderVimeoVideo(title, videoId)
		}

		// external: html5 video file
		if isVideoFile, mimeType := isVideoFileLink(path); isVideoFile {
			return renderVideoFileLink(title, path, mimeType)
		}

	}

	// return the fallback handler
	return fallback
}

func isYouTubeLink(link string) (isYouTubeLink bool, videoId string) {
	if found, matches := pattern.IsMatch(link, youTubeVideoPattern); found && len(matches) == 2 {
		return true, matches[1]
	}

	return false, ""
}

func renderYouTubeVideo(title, videoId string) string {
	return fmt.Sprintf(`

		%s

`, videoId, title, title, videoId)
}

func isVimeoLink(link string) (isVimeoLink bool, videoId string) {
	if found, matches := pattern.IsMatch(link, vimeoVideoPattern); found && len(matches) == 2 {
		return true, matches[1]
	}

	return false, ""
}

func renderVimeoVideo(title, videoId string) string {
	return fmt.Sprintf(`

		%s

`, videoId, title, title, videoId)
}

func isVideoFileLink(link string) (isVideoFile bool, mimeType string) {

	// abort if the link does not contain a dot
	if !strings.Contains(link, ".") {
		return false, ""
	}

	normalizedLink := strings.ToLower(link)
	fileExtension := normalizedLink[strings.LastIndex(normalizedLink, "."):]
	mimeType = mime.TypeByExtension(fileExtension)

	switch fileExtension {
	case ".mp4", ".ogg", ".ogv", ".webm", ".3gp":
		return true, mimeType
	default:
		return false, ""
	}

	panic("Unreachable")
}

func renderVideoFileLink(title, link, mimetype string) string {
	return fmt.Sprintf(`

		%s
		<video width="560" height="315" controls>
			<source src="%s" type="%s">
		</video>

`, link, title, title, link, mimetype)
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"io"
	"os"
	"time"

	"strings"

	"github.com/ncodes/cocoon/core/orderer"
	proto "github.com/ncodes/cocoon/core/runtime/golang/proto"
	"github.com/ncodes/cocoon/core/types"
	logging "github.com/op/go-logging"
	cmap "github.com/orcaman/concurrent-map"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
)

var log = logging.MustGetLogger("connector.client")

// txChannels holds the channels to send transaction responses to
var txRespChannels = cmap.New()

// Client represents a cocoon code GRPC client
// that interacts with a cocoon code.
type Client struct {
	ccodeAddr        string
	stub             proto.StubClient
	conCtx           context.Context
	conCancel        context.CancelFunc
	orderDiscoTicker *time.Ticker
	ordererAddrs     []string
	stream           proto.Stub_TransactClient
	cocoonID         string
}

// NewClient creates a new cocoon code client
func NewClient() *Client {
	return &Client{}
}

// SetCocoonID sets the cocoon id
func (c *Client) SetCocoonID(id string) {
	c.cocoonID = id
}

// SetCocoonCodeAddr sets the cocoon code bind address
func (c *Client) SetCocoonCodeAddr(ccAddr string) {
	c.ccodeAddr = ccAddr
}

// getCCAddr returns the cocoon code bind address.
// For development, if DEV_COCOON_ADDR is set, it connects to it.
func (c *Client) getCCAddr() string {
	if devCCodeAddr := os.Getenv("DEV_COCOON_ADDR"); len(devCCodeAddr) > 0 {
		return devCCodeAddr
	}
	return c.ccodeAddr
}

// Close the stream and cancel connections
func (c *Client) Close() {
	if c.stream != nil {
		c.stream.CloseSend()
	}
	if c.conCancel != nil {
		c.conCancel()
	}
}

// GetStream returns the grpc stream connected to the grpc cocoon code server
func (c *Client) GetStream() proto.Stub_TransactClient {
	return c.stream
}

// Connect connects to a cocoon code server
// running on a known port
func (c *Client) Connect() error {

	log.Info("Starting cocoon code client")

	// start a ticker to continously discover orderer addreses
	go func() {
		c.orderDiscoTicker = time.NewTicker(60 * time.Second)
		for _ = range c.orderDiscoTicker.C {
			var ordererAddrs []string
			ordererAddrs, err := orderer.DiscoverOrderers()
			if err != nil {
				log.Error(err.Error())
				continue
			}
			c.ordererAddrs = ordererAddrs
		}
	}()

	var ordererAddrs []string
	ordererAddrs, err := orderer.DiscoverOrderers()
	if err != nil {
		return err
	}
	c.ordererAddrs = ordererAddrs

	if len(c.ordererAddrs) > 0 {
		log.Infof("Orderer address list updated. Contains %d orderer address(es)", len(c.ordererAddrs))
	} else {
		log.Warning("No orderer address was found. We won't be able to reach the orderer. ")
	}

	fmt.Printf(">>>> ", c.getCCAddr())
	return nil
	conn, err := grpc.Dial(c.getCCAddr(), grpc.WithInsecure())
	if err != nil {
		return fmt.Errorf("failed to connect to cocoon code server. %s", err)
	}
	defer conn.Close()

	log.Debugf("Now connected to cocoon code at port=%s", strings.Split(c.getCCAddr(), ":")[1])

	c.stub = proto.NewStubClient(conn)

	if err = c.Do(conn); err != nil {
		return err
	}

	return nil
}

// Do starts a request loop that continously asks the
// server for transactions. When it receives a transaction,
// it processes it and returns the result.
func (c *Client) Do(conn *grpc.ClientConn) error {

	var err error

	// create a context so we have complete controll of the connection
	c.conCtx, c.conCancel = context.WithCancel(context.Background())

	// connect to the cocoon code
	c.stream, err = c.stub.Transact(c.conCtx)
	if err != nil {
		return fmt.Errorf("failed to start transaction stream with cocoon code. %s", err)
	}

	for {

		in, err := c.stream.Recv()
		if err == io.EOF {
			return fmt.Errorf("connection with cocoon code has ended")
		}
		if err != nil {
			if strings.Contains(err.Error(), "context canceled") {
				log.Info("Connection to cocoon code closed")
				return nil
			}
			return fmt.Errorf("failed to read message from cocoon code. %s", err)
		}

		switch in.Invoke {
		case true:
			go func() {
				log.Debugf("New invoke transaction (%s) from cocoon code", in.GetId())
				if err = c.handleInvokeTransaction(in); err != nil {
					log.Error(err.Error())
					c.stream.Send(&proto.Tx{
						Response: true,
						Id:       in.GetId(),
						Status:   500,
						Body:     []byte(err.Error()),
					})
				}
			}()
		case false:
			log.Debugf("New response transaction (%s) from cocoon code", in.GetId())
			go func() {
				if err = c.handleRespTransaction(in); err != nil {
					log.Error(err.Error())
					c.stream.Send(&proto.Tx{
						Response: true,
						Id:       in.GetId(),
						Status:   500,
						Body:     []byte(err.Error()),
					})
				}
			}()
		}
	}
}

// handleInvokeTransaction processes invoke transaction requests
func (c *Client) handleInvokeTransaction(tx *proto.Tx) error {
	switch tx.GetName() {
	case types.TxCreateLedger:
		return c.createLedger(tx)
	case types.TxPut:
		return c.put(tx)
	case types.TxGetLedger:
		return c.getLedger(tx)
	case types.TxGet:
		return c.get(tx, false)
	case types.TxGetByID:
		return c.get(tx, true)
	case types.TxGetBlockByID:
		return c.getBlock(tx)
	case types.TxRangeGet:
		return c.getRange(tx)
	default:
		return c.stream.Send(&proto.Tx{
			Id:       tx.GetId(),
			Response: true,
			Status:   500,
			Body:     []byte(fmt.Sprintf("unsupported transaction name (%s)", tx.GetName())),
		})
	}
}

// handleRespTransaction passes the transaction to a response
// channel with a matching transaction id and deletes the channel afterwards.
func (c *Client) handleRespTransaction(tx *proto.Tx) error {
	if !txRespChannels.Has(tx.GetId()) {
		return fmt.Errorf("response transaction (%s) does not have a corresponding response channel", tx.GetId())
	}

	txRespCh, _ := txRespChannels.Get(tx.GetId())
	txRespCh.(chan *proto.Tx) <- tx
	txRespChannels.Remove(tx.GetId())
	return nil
}

// SendTx sends a transaction to the cocoon code
// and saves the response channel. The response channel will
// be passed a response when it is available in the Transact loop.
func (c *Client) SendTx(tx *proto.Tx, respCh chan *proto.Tx) error {
	txRespChannels.Set(tx.GetId(), respCh)
	if err := c.stream.Send(tx); err != nil {
		txRespChannels.Remove(tx.GetId())
		return err
	}
	log.Debugf("Successfully sent transaction (%s) to cocoon code", tx.GetId())
	return nil
}
<commit_msg>debug<commit_after>package client

import (
	"fmt"
	"io"
	"os"
	"time"

	"strings"

	"github.com/ncodes/cocoon/core/orderer"
	proto "github.com/ncodes/cocoon/core/runtime/golang/proto"
	"github.com/ncodes/cocoon/core/types"
	logging "github.com/op/go-logging"
	cmap "github.com/orcaman/concurrent-map"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
)

var log = logging.MustGetLogger("connector.client")

// txChannels holds the channels to send transaction responses to
var txRespChannels = cmap.New()

// Client represents a cocoon code GRPC client
// that interacts with a cocoon code.
type Client struct {
	ccodeAddr        string
	stub             proto.StubClient
	conCtx           context.Context
	conCancel        context.CancelFunc
	orderDiscoTicker *time.Ticker
	ordererAddrs     []string
	stream           proto.Stub_TransactClient
	cocoonID         string
}

// NewClient creates a new cocoon code client
func NewClient() *Client {
	return &Client{}
}

// SetCocoonID sets the cocoon id
func (c *Client) SetCocoonID(id string) {
	c.cocoonID = id
}

// SetCocoonCodeAddr sets the cocoon code bind address
func (c *Client) SetCocoonCodeAddr(ccAddr string) {
	c.ccodeAddr = ccAddr
}

// getCCAddr returns the cocoon code bind address.
// For development, if DEV_COCOON_ADDR is set, it connects to it.
func (c *Client) getCCAddr() string {
	if devCCodeAddr := os.Getenv("DEV_COCOON_ADDR"); len(devCCodeAddr) > 0 {
		return devCCodeAddr
	}
	return c.ccodeAddr
}

// Close the stream and cancel connections
func (c *Client) Close() {
	if c.stream != nil {
		c.stream.CloseSend()
	}
	if c.conCancel != nil {
		c.conCancel()
	}
}

// GetStream returns the grpc stream connected to the grpc cocoon code server
func (c *Client) GetStream() proto.Stub_TransactClient {
	return c.stream
}

// Connect connects to a cocoon code server
// running on a known port
func (c *Client) Connect() error {

	log.Info("Starting cocoon code client")

	// start a ticker to continously discover orderer addreses
	go func() {
		c.orderDiscoTicker = time.NewTicker(60 * time.Second)
		for _ = range c.orderDiscoTicker.C {
			var ordererAddrs []string
			ordererAddrs, err := orderer.DiscoverOrderers()
			if err != nil {
				log.Error(err.Error())
				continue
			}
			c.ordererAddrs = ordererAddrs
		}
	}()

	var ordererAddrs []string
	ordererAddrs, err := orderer.DiscoverOrderers()
	if err != nil {
		return err
	}
	c.ordererAddrs = ordererAddrs

	if len(c.ordererAddrs) > 0 {
		log.Infof("Orderer address list updated. Contains %d orderer address(es)", len(c.ordererAddrs))
	} else {
		log.Warning("No orderer address was found. We won't be able to reach the orderer. ")
	}

	fmt.Println(">>>> ", c.getCCAddr())

	conn, err := grpc.Dial(c.getCCAddr(), grpc.WithInsecure())
	if err != nil {
		return fmt.Errorf("failed to connect to cocoon code server. %s", err)
	}
	defer conn.Close()

	log.Debugf("Now connected to cocoon code at port=%s", strings.Split(c.getCCAddr(), ":")[1])

	c.stub = proto.NewStubClient(conn)

	if err = c.Do(conn); err != nil {
		log.Info("Connect() ends with error", err)
		return err
	}
	log.Info("Connect() ends")

	return nil
}

// Do starts a request loop that continously asks the
// server for transactions. When it receives a transaction,
// it processes it and returns the result.
func (c *Client) Do(conn *grpc.ClientConn) error {

	var err error

	// create a context so we have complete controll of the connection
	c.conCtx, c.conCancel = context.WithCancel(context.Background())

	// connect to the cocoon code
	c.stream, err = c.stub.Transact(c.conCtx)
	if err != nil {
		return fmt.Errorf("failed to start transaction stream with cocoon code. %s", err)
	}

	for {

		in, err := c.stream.Recv()
		if err == io.EOF {
			return fmt.Errorf("connection with cocoon code has ended")
		}
		if err != nil {
			if strings.Contains(err.Error(), "context canceled") {
				log.Info("Connection to cocoon code closed")
				return nil
			}
			return fmt.Errorf("failed to read message from cocoon code. %s", err)
		}

		switch in.Invoke {
		case true:
			go func() {
				log.Debugf("New invoke transaction (%s) from cocoon code", in.GetId())
				if err = c.handleInvokeTransaction(in); err != nil {
					log.Error(err.Error())
					c.stream.Send(&proto.Tx{
						Response: true,
						Id:       in.GetId(),
						Status:   500,
						Body:     []byte(err.Error()),
					})
				}
			}()
		case false:
			log.Debugf("New response transaction (%s) from cocoon code", in.GetId())
			go func() {
				if err = c.handleRespTransaction(in); err != nil {
					log.Error(err.Error())
					c.stream.Send(&proto.Tx{
						Response: true,
						Id:       in.GetId(),
						Status:   500,
						Body:     []byte(err.Error()),
					})
				}
			}()
		}
	}
}

// handleInvokeTransaction processes invoke transaction requests
func (c *Client) handleInvokeTransaction(tx *proto.Tx) error {
	switch tx.GetName() {
	case types.TxCreateLedger:
		return c.createLedger(tx)
	case types.TxPut:
		return c.put(tx)
	case types.TxGetLedger:
		return c.getLedger(tx)
	case types.TxGet:
		return c.get(tx, false)
	case types.TxGetByID:
		return c.get(tx, true)
	case types.TxGetBlockByID:
		return c.getBlock(tx)
	case types.TxRangeGet:
		return c.getRange(tx)
	default:
		return c.stream.Send(&proto.Tx{
			Id:       tx.GetId(),
			Response: true,
			Status:   500,
			Body:     []byte(fmt.Sprintf("unsupported transaction name (%s)", tx.GetName())),
		})
	}
}

// handleRespTransaction passes the transaction to a response
// channel with a matching transaction id and deletes the channel afterwards.
func (c *Client) handleRespTransaction(tx *proto.Tx) error {
	if !txRespChannels.Has(tx.GetId()) {
		return fmt.Errorf("response transaction (%s) does not have a corresponding response channel", tx.GetId())
	}

	txRespCh, _ := txRespChannels.Get(tx.GetId())
	txRespCh.(chan *proto.Tx) <- tx
	txRespChannels.Remove(tx.GetId())
	return nil
}

// SendTx sends a transaction to the cocoon code
// and saves the response channel. The response channel will
// be passed a response when it is available in the Transact loop.
func (c *Client) SendTx(tx *proto.Tx, respCh chan *proto.Tx) error {
	txRespChannels.Set(tx.GetId(), respCh)
	if err := c.stream.Send(tx); err != nil {
		txRespChannels.Remove(tx.GetId())
		return err
	}
	log.Debugf("Successfully sent transaction (%s) to cocoon code", tx.GetId())
	return nil
}
<|endoftext|>