<commit_before>package dht

import (
	"context"
	"sort"
	"sync"

	"github.com/google/uuid"
	log "github.com/sirupsen/logrus"
)

const numPeersNear int = 3

type searchEntry struct {
	id              ID
	nonce           string
	closestPeer     Peer
	responseChannel chan Peer
}

type DHTNode struct {
	// bps are the Bootstrap Peers
	// lp is the local Peer info
	lpeer *Peer
	// rt is the routing table used
	rt RoutingTable
	// net is the network interface used for comms
	net Net
	// lc stores the nonces and the response channels
	searchStore map[string]*searchEntry
	mt          sync.RWMutex
}

func NewDHTNode(bps []*Peer, localPeer *Peer, rt RoutingTable, net *UDPNet, addr string) *DHTNode {
	dhtNode := &DHTNode{
		lpeer:       localPeer,
		rt:          rt,
		net:         net,
		searchStore: make(map[string]*searchEntry),
	}
	log.WithField("address", addr).Info("Server starting...")
	for _, peer := range bps {
		err := dhtNode.rt.Add(*peer)
		if err != nil {
			log.WithField("error", err).Error("Failed to add peer to routing table")
		}
		ctx := context.Background()
		go dhtNode.Find(ctx, peer.ID)
	}
	go net.StartServer(addr, dhtNode.ReceiveMessage)

	// Refresh all peers in the routing table
	return dhtNode
}

// TODO: Switch to return channel
func (nd *DHTNode) Find(ctx context.Context, id ID) (Peer, error) {
	// Search local Routing Table for node
	peer, err := nd.rt.Get(id)
	log.Info("Searching for peer with id: ", id)
	// If node is not found locally send a message to nodes
	if err == ErrPeerNotFound {
		nc, err := uuid.NewUUID()
		if err != nil {
			log.WithError(err).Error("Failed to generate uuid")
			return Peer{}, err
		}

		msg := &Message{
			Type:        FIND_NODE,
			Nonce:       nc.String(),
			OriginPeer:  *nd.lpeer,
			QueryPeerID: id,
		}

		// Check peers in local store for distance
		// send message to the X closest peers
		lookupPeers, err := nd.findPeersNear(id, numPeersNear)
		if err != nil {
			log.WithError(err).Error("Failed find peers near")
		}

		for _, p := range lookupPeers {
			err := nd.sendMsgPeer(msg, &p)
			if err != nil {
				log.WithError(err).WithField(
					"peer",
					p.ID,
				).Error("Failed to send message to peer")
			}
		}

		nonce := nc.String()
		responseChannel := make(chan Peer)
		se := &searchEntry{
			id:              id,
			nonce:           nonce,
			responseChannel: responseChannel,
		}
		nd.mt.Lock()
		nd.searchStore[nonce] = se
		nd.mt.Unlock()
		resPeer := <-responseChannel
		// Store result to routing table
		// if it exists update it
		err = nd.rt.Add(resPeer)
		if err == ErrPeerAlreadyExists {
			err = nd.rt.Update(resPeer)
			if err != nil {
				log.Error("Failed to update result peer")
			}
		}
		// TODO: Add timeout to wait for response and send not found
		// timeout in config
		log.Info("Waiting for response")
		return resPeer, nil
	}
	if err != nil {
		log.WithError(err).Error("Failed to find peer")
		return Peer{}, err
	}
	return peer, nil
}

func (nd *DHTNode) ReceiveMessage(msg Message) {
	switch msg.Type {
	case PING:
		log.WithField("Type", "PING").Info(msg.OriginPeer.ID)
	case FIND_NODE:
		log.WithField("Type", "FIND_NODE").Info(msg.OriginPeer.ID)
		go nd.findHandler(&msg)
	default:
		log.Info("Call type not implemented")
	}

}

func (nd *DHTNode) sendMsgPeer(msg *Message, peer *Peer) error {
	for _, addr := range peer.Address {
		i, err := nd.net.SendMessage(*msg, addr)
		if err != nil {
			log.WithError(err).Error("Failed to send message")
			break
		}
		log.Info("Sent message: ", i)
	}
	return nil
}

func (nd *DHTNode) findHandler(msg *Message) {
	var peers []Peer
	rPeers := []Peer{}
	// Check if local peer is the origin peer in the message
	if msg.OriginPeer.ID == nd.lpeer.ID {
		nd.mt.Lock()
		defer nd.mt.Unlock()
		if searchEntry, ok := nd.searchStore[msg.Nonce]; ok {
			// Add peers to local routing table
			for _, p := range msg.Peers {
				nd.rt.Add(p)
			}

			// Check if the requested peer is in the results
			for _, p := range msg.Peers {
				if msg.QueryPeerID == p.ID {
					searchEntry.responseChannel <- p
					// Delete response channel entry
					delete(nd.searchStore, msg.Nonce)
					return
				}
			}

			// Send the request to returned closest peers
			peers := msg.Peers
			msg.Peers = []Peer{}
			for _, p := range peers {
				err := nd.sendMsgPeer(msg, &p)
				if err != nil {
					if err != nil {
						log.WithError(err).WithField(
							"peer",
							p.ID,
						).Error("Failed to send message to peer")
					}
				}
			}
			return
		}
	}

	peer, err := nd.rt.Get(msg.QueryPeerID)
	if err != nil {
		log.Error("Failed to find node")
	}

	peers, err = nd.findPeersNear(msg.QueryPeerID, numPeersNear)
	if err != nil {
		log.WithField("Msg", msg).Error("Failed to find nodes near")
	}
	if peer.ID != "" && peer.Address[0] != "" {
		rPeers = append(rPeers, peer)
	} else {
		rPeers = peers
	}
	nd.net.SendMessage(
		Message{
			Type:        FIND_NODE,
			Nonce:       msg.Nonce,
			OriginPeer:  msg.OriginPeer,
			QueryPeerID: msg.QueryPeerID,
			Peers:       rPeers,
		},
		msg.OriginPeer.Address[0],
	)
}

// Xor gets to byte arrays and returns and array of integers with the xor
// for between the two equivalent bytes
func xor(a, b []byte) []int {
	var compA, compB []byte
	var res = []int{}

	lenA := len(a)
	lenB := len(b)

	// Make both byte arrays have the same size
	if lenA > lenB {
		compA = a
		compB = make([]byte, lenA)
		// Need to leave leftmost bytes empty in order compare
		// the equivalent bytes
		copy(compB[lenA-lenB:], b)
	} else {
		compB = b
		compA = make([]byte, lenB)
		copy(compA[lenB-lenA:], a)
	}

	for i := range compA {
		res = append(res, int(compA[i]^compB[i]))
	}

	return res
}

// distEntry is used to hold the distance between nodes
type distEntry struct {
	id   ID
	dist []int
}

// lessIntArr compares two int array return true if a less than b
func lessIntArr(a, b []int) bool {
	for i := range a {
		if a[i] > b[i] {
			return false
		}
		if a[i] < b[i] {
			return true
		}
	}

	return true
}

// findPeersNear accepts an ID and n and finds the n closest nodes to this id
// in the routing table
func (nd *DHTNode) findPeersNear(id ID, n int) ([]Peer, error) {
	peers := []Peer{}

	ids, err := nd.rt.GetPeerIDs()
	if err != nil {
		log.WithError(err).Error("Failed to get peer ids from the routing table")
		return peers, err
	}

	// slice to hold the distances
	dists := []distEntry{}
	for _, pid := range ids {
		entry := distEntry{
			id:   pid,
			dist: xor([]byte(id), []byte(pid)),
		}
		dists = append(dists, entry)
	}
	// Sort the distances
	sort.Slice(dists, func(i, j int) bool {
		return lessIntArr(dists[i].dist, dists[j].dist)
	})

	if n > len(dists) {
		n = len(dists)
	}
	// Append n the first n number of peers from the ids
	for _, de := range dists[:n] {
		p, err := nd.rt.Get(de.id)
		if err != nil {
			log.WithError(err).WithField("ID", de.id).Error("Peer not found")
		}
		peers = append(peers, p)
	}
	return peers, nil
}
<commit_msg>Add minor fixes and store closest peer on start<commit_after>package dht

import (
	"context"
	"sort"
	"sync"

	"github.com/google/uuid"
	log "github.com/sirupsen/logrus"
)

const numPeersNear int = 3

type searchEntry struct {
	id              ID
	nonce           string
	closestPeer     Peer
	responseChannel chan Peer
}

type DHTNode struct {
	// bps are the Bootstrap Peers
	// lp is the local Peer info
	lpeer *Peer
	// rt is the routing table used
	rt RoutingTable
	// net is the network interface used for comms
	net Net
	// lc stores the nonces and the response channels
	searchStore map[string]*searchEntry
	mt          sync.RWMutex
}

func NewDHTNode(bps []*Peer, localPeer *Peer, rt RoutingTable, net *UDPNet, addr string) *DHTNode {
	dhtNode := &DHTNode{
		lpeer:       localPeer,
		rt:          rt,
		net:         net,
		searchStore: make(map[string]*searchEntry),
	}
	log.WithField("address", addr).Info("Server starting...")
	// Add bootstrap peers to routing table
	for _, peer := range bps {
		err := dhtNode.rt.Add(*peer)
		if err != nil {
			log.WithField("error", err).Error("Failed to add peer to routing table")
		}
		ctx := context.Background()
		go dhtNode.Find(ctx, peer.ID)
	}
	go net.StartServer(addr, dhtNode.ReceiveMessage)

	// Refresh all peers in the routing table
	return dhtNode
}

// TODO: Switch to return channel
func (nd *DHTNode) Find(ctx context.Context, id ID) (Peer, error) {
	// Search local Routing Table for node
	peer, err := nd.rt.Get(id)
	log.Info("Searching for peer with id: ", id)
	// If node is not found locally send a message to nodes
	if err == ErrPeerNotFound {
		// Create the nonce id
		nc, err := uuid.NewUUID()
		if err != nil {
			log.WithError(err).Error("Failed to generate uuid")
			return Peer{}, err
		}

		msg := &Message{
			Type:        FIND_NODE,
			Nonce:       nc.String(),
			OriginPeer:  *nd.lpeer,
			QueryPeerID: id,
		}

		// Check peers in local store for distance
		// send message to the X closest peers
		lookupPeers, err := nd.findPeersNear(id, numPeersNear)
		if err != nil {
			log.WithError(err).Error("Failed find peers near")
		}

		se := &searchEntry{
			id:              id,
			nonce:           nc.String(),
			responseChannel: make(chan Peer),
			closestPeer:     lookupPeers[0],
		}

		for _, p := range lookupPeers {
			err := nd.sendMsgPeer(msg, &p)
			if err != nil {
				log.WithError(err).WithField(
					"peer",
					p.ID,
				).Error("Failed to send message to peer")
			}
		}

		nd.mt.Lock()
		nd.searchStore[nc.String()] = se
		nd.mt.Unlock()

		// TODO: If peer does not response in x amount of time remove it from the
		// shortlist lookup peers. Create a goroutine to handle timeouts.

		resPeer := <-se.responseChannel
		// Store result to routing table
		// if it exists update it
		err = nd.rt.Add(resPeer)
		if err == ErrPeerAlreadyExists {
			err = nd.rt.Update(resPeer)
			if err != nil {
				log.Error("Failed to update result peer")
			}
		}
		// TODO: Add timeout to wait for response and send not found
		// timeout in config
		log.Info("Waiting for response")
		return resPeer, nil
	}
	if err != nil {
		log.WithError(err).Error("Failed to find peer")
		return Peer{}, err
	}
	return peer, nil
}

func (nd *DHTNode) ReceiveMessage(msg Message) {
	switch msg.Type {
	case PING:
		log.WithField("Type", "PING").Info(msg.OriginPeer.ID)
	case FIND_NODE:
		log.WithField("Type", "FIND_NODE").Info(msg.OriginPeer.ID)
		go nd.findHandler(&msg)
	default:
		log.Info("Call type not implemented")
	}

}

func (nd *DHTNode) sendMsgPeer(msg *Message, peer *Peer) error {
	for _, addr := range peer.Address {
		i, err := nd.net.SendMessage(*msg, addr)
		if err != nil {
			log.WithError(err).Error("Failed to send message")
			break
		}
		log.Info("Sent message: ", i)
	}
	return nil
}

func (nd *DHTNode) findHandler(msg *Message) {
	peers := []Peer{}
	rPeers := []Peer{}
	// Check if local peer is the origin peer in the message
	if msg.OriginPeer.ID == nd.lpeer.ID {
		nd.mt.Lock()
		defer nd.mt.Unlock()
		if searchEntry, ok := nd.searchStore[msg.Nonce]; ok {
			// Add peers to local routing table
			for _, p := range msg.Peers {
				nd.rt.Add(p)
			}

			// Check if the requested peer is in the results
			for _, p := range msg.Peers {
				if msg.QueryPeerID == p.ID {
					searchEntry.responseChannel <- p
					// Delete response channel entry
					delete(nd.searchStore, msg.Nonce)
					return
				}
			}

			// Send the request to returned closest peers
			peers := msg.Peers
			msg.Peers = []Peer{}
			for _, p := range peers {
				err := nd.sendMsgPeer(msg, &p)
				if err != nil {
					if err != nil {
						log.WithError(err).WithField(
							"peer",
							p.ID,
						).Error("Failed to send message to peer")
					}
				}
			}
			return
		}
	}

	peer, err := nd.rt.Get(msg.QueryPeerID)
	if err != nil {
		log.Error("Failed to find node")
	}

	peers, err = nd.findPeersNear(msg.QueryPeerID, numPeersNear)
	if err != nil {
		log.WithField("Msg", msg).Error("Failed to find nodes near")
	}
	if peer.ID != "" && peer.Address[0] != "" {
		rPeers = append(rPeers, peer)
	} else {
		rPeers = peers
	}
	nd.net.SendMessage(
		Message{
			Type:        FIND_NODE,
			Nonce:       msg.Nonce,
			OriginPeer:  msg.OriginPeer,
			QueryPeerID: msg.QueryPeerID,
			Peers:       rPeers,
		},
		msg.OriginPeer.Address[0],
	)
}

// Xor gets to byte arrays and returns and array of integers with the xor
// for between the two equivalent bytes
func xor(a, b []byte) []int {
	compA := []byte{}
	compB := []byte{}
	res := []int{}

	lenA := len(a)
	lenB := len(b)

	// Make both byte arrays have the same size
	if lenA > lenB {
		compA = a
		compB = make([]byte, lenA)
		// Need to leave leftmost bytes empty in order compare
		// the equivalent bytes
		copy(compB[lenA-lenB:], b)
	} else {
		compB = b
		compA = make([]byte, lenB)
		copy(compA[lenB-lenA:], a)
	}

	for i := range compA {
		res = append(res, int(compA[i]^compB[i]))
	}

	return res
}

// distEntry is used to hold the distance between nodes
type distEntry struct {
	id   ID
	dist []int
}

// lessIntArr compares two int array return true if a less than b
func lessIntArr(a, b []int) bool {
	for i := range a {
		if a[i] > b[i] {
			return false
		}
		if a[i] < b[i] {
			return true
		}
	}

	return true
}

// findPeersNear accepts an ID and n and finds the n closest nodes to this id
// in the routing table
func (nd *DHTNode) findPeersNear(id ID, n int) ([]Peer, error) {
	peers := []Peer{}

	ids, err := nd.rt.GetPeerIDs()
	if err != nil {
		log.WithError(err).Error("Failed to get peer ids from the routing table")
		return peers, err
	}

	// slice to hold the distances
	dists := []distEntry{}
	for _, pid := range ids {
		entry := distEntry{
			id:   pid,
			dist: xor([]byte(id), []byte(pid)),
		}
		dists = append(dists, entry)
	}
	// Sort the distances
	sort.Slice(dists, func(i, j int) bool {
		return lessIntArr(dists[i].dist, dists[j].dist)
	})

	if n > len(dists) {
		n = len(dists)
	}
	// Append n the first n number of peers from the ids
	for _, de := range dists[:n] {
		p, err := nd.rt.Get(de.id)
		if err != nil {
			log.WithError(err).WithField("ID", de.id).Error("Peer not found")
		}
		peers = append(peers, p)
	}
	return peers, nil
}
<|endoftext|>


<commit_before>package deploy

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"bytes"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/ieee0824/getenv"
	"github.com/jobtalk/pnzr/api"
	"github.com/jobtalk/pnzr/lib"
	"github.com/jobtalk/pnzr/lib/setting"
)

type DeployCommand struct {
	sess           *session.Session
	file           *string
	profile        *string
	kmsKeyID       *string
	region         *string
	externalPath   *string
	outerVals      *string
	awsAccessKeyID *string
	awsSecretKeyID *string
	tagOverride    *string
}

var re = regexp.MustCompile(`.*\.json$`)

func parseDockerImage(image string) (url, tag string) {
	r := strings.Split(image, ":")
	if len(r) == 2 {
		return r[0], r[1]
	}
	return r[0], ""
}

func fileList(root string) ([]string, error) {
	if root == "" {
		return nil, nil
	}
	ret := []string{}
	err := filepath.Walk(root,
		func(path string, info os.FileInfo, err error) error {
			if info == nil {
				return errors.New("file info is nil")
			}
			if info.IsDir() {
				return nil
			}

			rel, err := filepath.Rel(root, path)
			if re.MatchString(rel) {
				ret = append(ret, rel)
			}

			return nil
		})

	if err != nil {
		return nil, err
	}

	return ret, nil
}

type deployConfigure struct {
	*setting.Setting
}

func isEncrypted(data []byte) bool {
	var buffer = map[string]interface{}{}
	if err := json.Unmarshal(data, &buffer); err != nil {
		return false
	}
	elem, ok := buffer["cipher"]
	if !ok {
		return false
	}
	str, ok := elem.(string)
	if !ok {
		return false
	}

	return len(str) != 0
}

func (d *DeployCommand) decrypt(bin []byte) ([]byte, error) {
	kms := lib.NewKMSFromBinary(bin, d.sess)
	if kms == nil {
		return nil, errors.New(fmt.Sprintf("%v format is illegal", string(bin)))
	}
	plainText, err := kms.SetKeyID(*d.kmsKeyID).Decrypt()
	if err != nil {
		return nil, err
	}
	return plainText, nil
}

func (d *DeployCommand) readConf(base []byte, externalPathList []string) (*deployConfigure, error) {
	var root = *d.externalPath
	var ret = &deployConfigure{}
	baseStr := string(base)

	root = strings.TrimSuffix(root, "/")
	for _, externalPath := range externalPathList {
		external, err := ioutil.ReadFile(root + "/" + externalPath)
		if err != nil {
			return nil, err
		}
		if isEncrypted(external) {
			plain, err := d.decrypt(external)
			if err != nil {
				return nil, err
			}
			external = plain
		}
		baseStr, err = lib.Embedde(baseStr, string(external))
		if err != nil {
			return nil, err
		}
	}
	if err := json.Unmarshal([]byte(baseStr), ret); err != nil {
		return nil, err
	}
	return ret, nil
}

func (d *DeployCommand) parseArgs(args []string) (helpString string) {
	flagSet := new(flag.FlagSet)
	var f *string

	buffer := new(bytes.Buffer)
	flagSet.SetOutput(buffer)

	d.kmsKeyID = flagSet.String("key_id", getenv.String("KMS_KEY_ID"), "Amazon KMS key ID")
	d.file = flagSet.String("file", "", "target file")
	f = flagSet.String("f", "", "target file")
	d.profile = flagSet.String("profile", getenv.String("AWS_PROFILE_NAME", "default"), "aws credentials profile name")
	d.region = flagSet.String("region", getenv.String("AWS_REGION", "ap-northeast-1"), "aws region")
	d.externalPath = flagSet.String("vars_path", getenv.String("PNZR_VARS_PATH"), "external conf path")
	d.outerVals = flagSet.String("V", "", "outer values")
	d.tagOverride = flagSet.String("t", getenv.String("DOCKER_DEFAULT_DEPLOY_TAG", "latest"), "tag override param")
	d.awsAccessKeyID = flagSet.String("aws-access-key-id", getenv.String("AWS_ACCESS_KEY_ID"), "aws access key id")
	d.awsSecretKeyID = flagSet.String("aws-secret-key-id", getenv.String("AWS_SECRET_KEY_ID"), "aws secret key id")

	if err := flagSet.Parse(args); err != nil {
		if err == flag.ErrHelp {
			return buffer.String()
		}
		panic(err)
	}

	if *f == "" && *d.file == "" && len(flagSet.Args()) != 0 {
		targetName := flagSet.Args()[0]
		d.file = &targetName
	}

	if *d.file == "" {
		d.file = f
	}

	var awsConfig = aws.Config{}

	if *d.awsAccessKeyID != "" && *d.awsSecretKeyID != "" && *d.profile == "" {
		awsConfig.Credentials = credentials.NewStaticCredentials(*d.awsAccessKeyID, *d.awsSecretKeyID, "")
		awsConfig.Region = d.region
	}

	d.sess = session.Must(session.NewSessionWithOptions(session.Options{
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
		SharedConfigState:       session.SharedConfigEnable,
		Profile:                 *d.profile,
		Config:                  awsConfig,
	}))

	return
}

func (d *DeployCommand) Run(args []string) int {
	d.parseArgs(args)
	var config = &deployConfigure{}

	externalList, err := fileList(*d.externalPath)
	if err != nil {
		log.Fatalln(err)
	}
	baseConfBinary, err := ioutil.ReadFile(*d.file)
	if err != nil {
		log.Fatal(err)
	}

	if *d.outerVals != "" {
		baseStr, err := lib.Embedde(string(baseConfBinary), *d.outerVals)
		if err == nil {
			baseConfBinary = []byte(baseStr)
		}
	}

	if externalList != nil {
		c, err := d.readConf(baseConfBinary, externalList)
		if err != nil {
			log.Fatalln(err)
		}
		config = c
	} else {
		bin, err := ioutil.ReadFile(*d.file)
		if err != nil {
			log.Fatalln(err)
		}
		if err := json.Unmarshal(bin, config); err != nil {
			log.Fatalln(err)
		}
	}

	for i, containerDefinition := range config.ECS.TaskDefinition.ContainerDefinitions {
		imageName, tag := parseDockerImage(*containerDefinition.Image)
		if tag == "$tag" {
			image := imageName + ":" + *d.tagOverride
			config.ECS.TaskDefinition.ContainerDefinitions[i].Image = &image
		} else if tag == "" {
			image := imageName + ":" + "latest"
			config.ECS.TaskDefinition.ContainerDefinitions[i].Image = &image
		}
	}

	result, err := api.Deploy(d.sess, config.Setting)
	if err != nil {
		log.Fatalln(err)
	}
	resultJSON, err := json.MarshalIndent(result, "", "    ")
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(string(resultJSON))
	return 0
}

func (c *DeployCommand) Synopsis() string {
	return "Deploy docker on ecs."
}

func (c *DeployCommand) Help() string {
	return c.parseArgs([]string{"-h"})
}
<commit_msg>dry run の追加<commit_after>package deploy

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"bytes"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/ieee0824/getenv"
	"github.com/jobtalk/pnzr/api"
	"github.com/jobtalk/pnzr/lib"
	"github.com/jobtalk/pnzr/lib/setting"
)

type DeployCommand struct {
	sess           *session.Session
	file           *string
	profile        *string
	kmsKeyID       *string
	region         *string
	externalPath   *string
	outerVals      *string
	awsAccessKeyID *string
	awsSecretKeyID *string
	tagOverride    *string
	dryRun         *bool
}

var re = regexp.MustCompile(`.*\.json$`)

func parseDockerImage(image string) (url, tag string) {
	r := strings.Split(image, ":")
	if len(r) == 2 {
		return r[0], r[1]
	}
	return r[0], ""
}

func fileList(root string) ([]string, error) {
	if root == "" {
		return nil, nil
	}
	ret := []string{}
	err := filepath.Walk(root,
		func(path string, info os.FileInfo, err error) error {
			if info == nil {
				return errors.New("file info is nil")
			}
			if info.IsDir() {
				return nil
			}

			rel, err := filepath.Rel(root, path)
			if re.MatchString(rel) {
				ret = append(ret, rel)
			}

			return nil
		})

	if err != nil {
		return nil, err
	}

	return ret, nil
}

type deployConfigure struct {
	*setting.Setting
}

func isEncrypted(data []byte) bool {
	var buffer = map[string]interface{}{}
	if err := json.Unmarshal(data, &buffer); err != nil {
		return false
	}
	elem, ok := buffer["cipher"]
	if !ok {
		return false
	}
	str, ok := elem.(string)
	if !ok {
		return false
	}

	return len(str) != 0
}

func (d *DeployCommand) decrypt(bin []byte) ([]byte, error) {
	kms := lib.NewKMSFromBinary(bin, d.sess)
	if kms == nil {
		return nil, errors.New(fmt.Sprintf("%v format is illegal", string(bin)))
	}
	plainText, err := kms.SetKeyID(*d.kmsKeyID).Decrypt()
	if err != nil {
		return nil, err
	}
	return plainText, nil
}

func (d *DeployCommand) readConf(base []byte, externalPathList []string) (*deployConfigure, error) {
	var root = *d.externalPath
	var ret = &deployConfigure{}
	baseStr := string(base)

	root = strings.TrimSuffix(root, "/")
	for _, externalPath := range externalPathList {
		external, err := ioutil.ReadFile(root + "/" + externalPath)
		if err != nil {
			return nil, err
		}
		if isEncrypted(external) {
			plain, err := d.decrypt(external)
			if err != nil {
				return nil, err
			}
			external = plain
		}
		baseStr, err = lib.Embedde(baseStr, string(external))
		if err != nil {
			return nil, err
		}
	}
	if err := json.Unmarshal([]byte(baseStr), ret); err != nil {
		return nil, err
	}
	return ret, nil
}

func (d *DeployCommand) parseArgs(args []string) (helpString string) {
	flagSet := new(flag.FlagSet)
	var f *string

	buffer := new(bytes.Buffer)
	flagSet.SetOutput(buffer)

	d.kmsKeyID = flagSet.String("key_id", getenv.String("KMS_KEY_ID"), "Amazon KMS key ID")
	d.file = flagSet.String("file", "", "target file")
	f = flagSet.String("f", "", "target file")
	d.profile = flagSet.String("profile", getenv.String("AWS_PROFILE_NAME", "default"), "aws credentials profile name")
	d.region = flagSet.String("region", getenv.String("AWS_REGION", "ap-northeast-1"), "aws region")
	d.externalPath = flagSet.String("vars_path", getenv.String("PNZR_VARS_PATH"), "external conf path")
	d.outerVals = flagSet.String("V", "", "outer values")
	d.tagOverride = flagSet.String("t", getenv.String("DOCKER_DEFAULT_DEPLOY_TAG", "latest"), "tag override param")
	d.awsAccessKeyID = flagSet.String("aws-access-key-id", getenv.String("AWS_ACCESS_KEY_ID"), "aws access key id")
	d.awsSecretKeyID = flagSet.String("aws-secret-key-id", getenv.String("AWS_SECRET_KEY_ID"), "aws secret key id")
	d.dryRun = flagSet.Bool("dry-run", false, "dry run")

	if err := flagSet.Parse(args); err != nil {
		if err == flag.ErrHelp {
			return buffer.String()
		}
		panic(err)
	}

	if *f == "" && *d.file == "" && len(flagSet.Args()) != 0 {
		targetName := flagSet.Args()[0]
		d.file = &targetName
	}

	if *d.file == "" {
		d.file = f
	}

	var awsConfig = aws.Config{}

	if *d.awsAccessKeyID != "" && *d.awsSecretKeyID != "" && *d.profile == "" {
		awsConfig.Credentials = credentials.NewStaticCredentials(*d.awsAccessKeyID, *d.awsSecretKeyID, "")
		awsConfig.Region = d.region
	}

	d.sess = session.Must(session.NewSessionWithOptions(session.Options{
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
		SharedConfigState:       session.SharedConfigEnable,
		Profile:                 *d.profile,
		Config:                  awsConfig,
	}))

	return
}

func (d *DeployCommand) Run(args []string) int {
	d.parseArgs(args)
	var config = &deployConfigure{}

	externalList, err := fileList(*d.externalPath)
	if err != nil {
		log.Fatalln(err)
	}
	baseConfBinary, err := ioutil.ReadFile(*d.file)
	if err != nil {
		log.Fatal(err)
	}

	if *d.outerVals != "" {
		baseStr, err := lib.Embedde(string(baseConfBinary), *d.outerVals)
		if err == nil {
			baseConfBinary = []byte(baseStr)
		}
	}

	if externalList != nil {
		c, err := d.readConf(baseConfBinary, externalList)
		if err != nil {
			log.Fatalln(err)
		}
		config = c
	} else {
		bin, err := ioutil.ReadFile(*d.file)
		if err != nil {
			log.Fatalln(err)
		}
		if err := json.Unmarshal(bin, config); err != nil {
			log.Fatalln(err)
		}
	}

	for i, containerDefinition := range config.ECS.TaskDefinition.ContainerDefinitions {
		imageName, tag := parseDockerImage(*containerDefinition.Image)
		if tag == "$tag" {
			image := imageName + ":" + *d.tagOverride
			config.ECS.TaskDefinition.ContainerDefinitions[i].Image = &image
		} else if tag == "" {
			image := imageName + ":" + "latest"
			config.ECS.TaskDefinition.ContainerDefinitions[i].Image = &image
		}
	}

	f, err := os.Open("/dev/stderr")
	if err != nil {
		panic(err)
	}
	if *d.dryRun {
		fmt.Fprintf(f, "******** DRY RUN ********\n%s\n", config.Setting.ECS)
		return 0
	}

	result, err := api.Deploy(d.sess, config.Setting)
	if err != nil {
		log.Fatalln(err)
	}
	resultJSON, err := json.MarshalIndent(result, "", "    ")
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(string(resultJSON))
	return 0
}

func (c *DeployCommand) Synopsis() string {
	return "Deploy docker on ecs."
}

func (c *DeployCommand) Help() string {
	return c.parseArgs([]string{"-h"})
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/der-antikeks/go-webdav"
)
<commit_msg>davd enabled read access to raw file and metadata (stat)<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
)

type Mount struct {
	baseDir string
}

func (m *Mount) realPath(u *url.URL) string {
	return filepath.Join(m.baseDir, filepath.FromSlash(u.Path))
}

func (m *Mount) InfoFromURL(u *url.URL) (os.FileInfo, error) {
	return os.Stat(m.realPath(u))
}

func (m *Mount) OpenReadFile(u *url.URL) (*os.File, error) {
	return os.Open(m.realPath(u))
}

func (m *Mount) ReadDir(u *url.URL) ([]os.FileInfo, error) {
	f, err := os.Open(m.realPath(u))
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return f.Readdir(-1)
}

type RawFS struct {
	mount    *Mount
	metaBase string
}

func (r *RawFS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	info, err := r.mount.InfoFromURL(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if info.IsDir() {
		r.serveDir(w, req, info)
	} else {
		r.serveFile(w, req, info)
	}
}

func (r *RawFS) serveDir(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	childs, err := r.mount.ReadDir(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w,
		`<!doctype html>

	<title>Listing directory: %v</title>

Listing directory: %v

`,
		info.Name(),
		info.Name())

	for _, child := range childs {
		fmt.Fprintf(w, `<li><a href="%v">%v</a> <a href="%v">Stat</a></li>`,
			"./"+child.Name(), child.Name(), r.metaForChild(child.Name(), req.URL))
	}

	fmt.Fprintf(w,
		`

`)
}

func (r *RawFS) metaForChild(name string, parent *url.URL) *url.URL {
	u := parent.ResolveReference(&url.URL{})
	u.Path = path.Join(r.metaBase, u.Path, name)
	return u
}

func (r *RawFS) serveFile(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	if req.Method != "GET" {
		http.Error(w, "Only GET at this moment", http.StatusMethodNotAllowed)
		return
	}
	rw, err := r.mount.OpenReadFile(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer rw.Close()

	http.ServeContent(w, req, info.Name(), info.ModTime(), rw)
}

type MetaFS struct {
	mount   *Mount
	rawBase string
}

func (m *MetaFS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	info, err := m.mount.InfoFromURL(req.URL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	m.printAsHtml(w, req, info)
}

// Return the raw url representing this file
func (m *MetaFS) rawURLFor(meta *url.URL) *url.URL {
	u := meta.ResolveReference(&url.URL{})
	u.Path = path.Join(m.rawBase, meta.Path)
	return u
}

func (m *MetaFS) printAsHtml(w http.ResponseWriter, req *http.Request, info os.FileInfo) {
	rawUrl := m.rawURLFor(req.URL)

	fmt.Fprintf(w,
		`<!doctype html>

	<title>Info about: %v</title>

Name

%v

Directory?

%v

Size

%d

Mod time

%v

Raw url
%v</href>

`,
		req.URL.Path,
		info.Name(),
		info.IsDir(),
		info.Size(),
		info.ModTime(),
		rawUrl,
		info.Name())
}

var (
	addr    = flag.String("addr", "0.0.0.0:9091", "Address to listen for clients")
	baseDir = flag.String("baseDir", ".", "Base dir to serve the content")
)

func index(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w,
		`<!doctype html>

	<title>Root dir</title>

Meta

./meta/

Raw

./raw/

`)
}

func main() {

	m := &Mount{baseDir: *baseDir}
	metafs := &MetaFS{mount: m, rawBase: "/raw"}
	rawfs := &RawFS{mount: m, metaBase: "/meta"}

	http.HandleFunc("/", index)
	http.Handle("/meta/", http.StripPrefix("/meta/", metafs))
	http.Handle("/raw/", http.StripPrefix("/raw/", rawfs))

	log.Printf("Starting davd server at %v", *addr)
	err := http.ListenAndServe(*addr, nil)
	http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Printf("Error opening server: %v", err)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Marcus Fritzsch
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Implement channel-centric communication with a Denon AVR
package davr

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"strings"
)

type pipeStep func(input, output chan []byte)

func eventAssembler(rawIn, eventOut chan []byte) {
	scratch := make([]byte, 0)
	sep := []byte{0xd}

	for {
		input, ok := <-rawIn

		if !ok {
			close(eventOut)
			break
		}

		scratch = append(scratch, input...)

		for {
			evRest := bytes.SplitN(scratch, sep, 2)

			if len(evRest) != 2 {
				break
			}

			eventOut <- evRest[0]

			if len(evRest) == 2 {
				scratch = evRest[1]
			} else {
				// no remaining bytes, clear scratch
				scratch = scratch[0:0]
			}
		}
	}
}

func producer(f func(out chan []byte)) chan []byte {
	out := make(chan []byte)
	go f(out)
	return out
}

// create a pipe-segment using func f
func pipe(f pipeStep, in chan []byte) chan []byte {
	out := make(chan []byte)
	go f(in, out)
	return out
}

func readerToChan(r io.Reader, out chan []byte) {
	var n int
	var err error
	var buf []byte

	for {
		if buf == nil {
			buf = make([]byte, 1024)
		}

		n, err = r.Read(buf)
		if err != nil {
			close(out)
			return
		}

		if n == 0 {
			continue
		}

		out <- buf[:n]
		buf = nil
	}
}

// Represents a Denon AVR connection
type DAVR struct {
	conn      net.Conn
	eventIn   chan []byte /// events from avr can be read from here
	commandIn chan []byte /// commands to the avr can be written here
}

func run(davr *DAVR) {
	for {
		select {
		case cmd, ok := <-davr.commandIn:
			if !ok {
				return
			}
			davr.conn.Write(cmd)
		}
	}
}

// Connect to an AVR
func Connect(hostPort string) (*DAVR, error) {
	var conn string

	if strings.Contains(hostPort, ":") {
		conn = hostPort
	} else {
		conn = fmt.Sprintf("%s:23", hostPort)
	}

	c, e := net.Dial("tcp", conn)
	if e != nil {
		return nil, e
	}

	commandIn := make(chan []byte)

	// setup event pipe
	eventIn := pipe(eventAssembler,
		producer(func(out chan []byte) {
			readerToChan(c, out)
		}))

	davr := &DAVR{c, eventIn, commandIn}

	go run(davr)

	return davr, nil
}

// GetCommandChannel returns the write only command-channel to the AVR
func (avr *DAVR) GetCommandChannel() chan<- []byte {
	return avr.commandIn
}

// GetEventChannel seturns the read-only event channel from the AVR
// Events returned through this channel are already assembled
// and guarantieed to be bounded and complete
// When reading from this channel, check the ok-flag in
// in order to determine if the connection is still alive.
func (avr *DAVR) GetEventChannel() <-chan []byte {
	return avr.eventIn
}

// Close a Denon AVR connection
func (avr *DAVR) Close() {
	avr.conn.Close()
	close(avr.commandIn)
}
<commit_msg>Fixed package header comment<commit_after>// Copyright (c) 2015 Marcus Fritzsch
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package davr implements channel-centric communication with a Denon AVR
package davr

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"strings"
)

type pipeStep func(input, output chan []byte)

func eventAssembler(rawIn, eventOut chan []byte) {
	scratch := make([]byte, 0)
	sep := []byte{0xd}

	for {
		input, ok := <-rawIn

		if !ok {
			close(eventOut)
			break
		}

		scratch = append(scratch, input...)

		for {
			evRest := bytes.SplitN(scratch, sep, 2)

			if len(evRest) != 2 {
				break
			}

			eventOut <- evRest[0]

			if len(evRest) == 2 {
				scratch = evRest[1]
			} else {
				// no remaining bytes, clear scratch
				scratch = scratch[0:0]
			}
		}
	}
}

func producer(f func(out chan []byte)) chan []byte {
	out := make(chan []byte)
	go f(out)
	return out
}

// create a pipe-segment using func f
func pipe(f pipeStep, in chan []byte) chan []byte {
	out := make(chan []byte)
	go f(in, out)
	return out
}

func readerToChan(r io.Reader, out chan []byte) {
	var n int
	var err error
	var buf []byte

	for {
		if buf == nil {
			buf = make([]byte, 1024)
		}

		n, err = r.Read(buf)
		if err != nil {
			close(out)
			return
		}

		if n == 0 {
			continue
		}

		out <- buf[:n]
		buf = nil
	}
}

// Represents a Denon AVR connection
type DAVR struct {
	conn      net.Conn
	eventIn   chan []byte /// events from avr can be read from here
	commandIn chan []byte /// commands to the avr can be written here
}

func run(davr *DAVR) {
	for {
		select {
		case cmd, ok := <-davr.commandIn:
			if !ok {
				return
			}
			davr.conn.Write(cmd)
		}
	}
}

// Connect to an AVR
func Connect(hostPort string) (*DAVR, error) {
	var conn string

	if strings.Contains(hostPort, ":") {
		conn = hostPort
	} else {
		conn = fmt.Sprintf("%s:23", hostPort)
	}

	c, e := net.Dial("tcp", conn)
	if e != nil {
		return nil, e
	}

	commandIn := make(chan []byte)

	// setup event pipe
	eventIn := pipe(eventAssembler,
		producer(func(out chan []byte) {
			readerToChan(c, out)
		}))

	davr := &DAVR{c, eventIn, commandIn}

	go run(davr)

	return davr, nil
}

// GetCommandChannel returns the write only command-channel to the AVR
func (avr *DAVR) GetCommandChannel() chan<- []byte {
	return avr.commandIn
}

// GetEventChannel seturns the read-only event channel from the AVR
// Events returned through this channel are already assembled
// and guarantieed to be bounded and complete
// When reading from this channel, check the ok-flag in
// in order to determine if the connection is still alive.
func (avr *DAVR) GetEventChannel() <-chan []byte {
	return avr.eventIn
}

// Close a Denon AVR connection
func (avr *DAVR) Close() {
	avr.conn.Close()
	close(avr.commandIn)
}
<|endoftext|>


<commit_before><commit_msg>add compressed schema test for leafref validation (#297)<commit_after><|endoftext|>


<commit_before>package kommentator

import (
	"database/sql"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/kenota/kommentator/migrations"
	"github.com/mattes/migrate"
	"github.com/mattes/migrate/database/sqlite3"
	"github.com/mattes/migrate/source"
	"github.com/mattes/migrate/source/go-bindata"

	_ "github.com/mattn/go-sqlite3"
)

// Storage handles storing/retrieving of comments and does not do any access-related checks
type Storage interface {
	// Adds new comment and returns new comment with all storage-related fields populated
	AddComment(thread *Thread, parent *Comment, comment *Comment) (*Comment, error)
	// Delete comment
	DeleteComment(*Comment) (bool, error)
	// Retrieve comment by id
	GetComment(IDType) (*Comment, error)
	// Retrieve thread by uri
	GetThread(string) (*Thread, error)

	// Creates thread
	CreateThread(uri, title string) (*Thread, error)

	// Retrieve comments for thread at specific URI
	GetThreadedComments(uri *string) (*ThreadedComments, error)

	LikeComment(idType IDType) error
	DislikeComment(idType IDType) error
}

// Encodes specified path array to represent materialized path following following following format:
// [X][Y]{1, ...}
// Where:
// x - single character, represents string representation of length of next id as ase base 36 number
// Y - X characters string, which is base 36 representation of id of next node in path
// this structure repeated for required nesting levels

// Panics if length of string representation of any path element is more than 35 characters
func EncodePath(path []IDType) string {
	var (
		result string
		id     IDType
	)

	for _, id = range path {
		result += EncodePathComponent(id)
	}

	return result
}

func EncodePathComponent(id IDType) string {
	var (
		result, encId, encLen string
		encLenSize            int
	)

	encId = strconv.FormatInt(int64(id), 36)
	encLen = strconv.FormatInt(int64(len(encId)), 36)
	encLenSize = len(encLen)
	if encLenSize > 1 {
		panic(fmt.Sprintf("Too long id: %d. EncodedId: %s Length: %d ", id, encId, encLen))
	}

	result += encLen
	result += encId

	return result
}

type sqliteStorage struct {
	Db *sqlx.DB
}

func copyString(s *string) *string {
	var temp string
	if s == nil {
		return nil
	}

	temp = *s
	return &temp
}

func (s *sqliteStorage) changeLikes(commentId IDType, delta int) error {
	var field string
	if delta > 0 {
		field = "likes"
	} else {
		field = "dislikes"
		delta = -delta
	}

	res, err := s.Db.Exec(fmt.Sprintf("UPDATE comment SET %s = %s + $1 WHERE id = $2", field, field), delta, commentId)
	if err != nil {
		return err
	}
	affected, err := res.RowsAffected()
	if err != nil {
		return err
	}
	switch affected {
	case 0:
		return errors.New("comment does not exist")
	case 1:
		return nil
	default:
		panic(fmt.Sprintf("Unexpected number of rows updated on limited update: %d", affected))
	}
}

func (s *sqliteStorage) LikeComment(id IDType) error {
	return s.changeLikes(id, 1)
}

func (s *sqliteStorage) DislikeComment(id IDType) error {
	return s.changeLikes(id, -1)
}

func (s *sqliteStorage) DeleteComment(*Comment) (bool, error) {
	panic("not implemented yet")
}

func (s *sqliteStorage) GetComment(id IDType) (*Comment, error) {
	var (
		err error
		res Comment
	)

	err = s.Db.Get(&res, "SELECT * FROM comment WHERE id = $1", id)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &res, nil
}

func (s *sqliteStorage) GetThread(uri string) (*Thread, error) {
	var (
		err    error
		thread Thread
	)

	err = s.Db.Get(&thread, "SELECT * FROM thread WHERE uri = $1", uri)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &thread, nil
}

func (s *sqliteStorage) CreateThread(uri, title string) (*Thread, error) {
	var (
		id        int64
		err       error
		newThread = &Thread{
			URI:   uri,
			Title: title,
		}
		res sql.Result
	)

	res, err = s.Db.NamedExec(`
		INSERT INTO thread (uri, title) VALUES (:uri, :title)
	`, newThread)
	if err != nil {
		return nil, err
	}

	id, err = res.LastInsertId()
	if err != nil {
		return nil, err
	}

	newThread.ID = IDType(id)

	return newThread, nil
}

func (s *sqliteStorage) GetThreadedComments(uri *string) (*ThreadedComments, error) {
	var (
		err    error
		th     Thread
		result ThreadedComments
	)

	err = s.Db.Get(&th, "SELECT * FROM thread WHERE uri = $1", uri)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	result.Comments = []Comment{}

	err = s.Db.Select(&result.Comments, "SELECT * FROM comment WHERE tid = $1 ORDER BY path, created", th.ID)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

func (s *sqliteStorage) AddComment(thread *Thread, parent *Comment, comment *Comment) (*Comment, error) {
	var (
		id         int64
		err        error
		tx         *sqlx.Tx
		res        sql.Result
		newComment = Comment{
			ID:         comment.ID,
			Author:     comment.Author,
			Body:       comment.Body,
			Email:      copyString(comment.Email),
			Website:    copyString(comment.Website),
			RemoteAddr: comment.RemoteAddr,
			ThreadID:   thread.ID,
		}
		now          = time.Now()
		loadedParent = &Comment{}
	)

	newComment.Created = &now
	newComment.Modified = &now

	if comment == nil {
		return nil, errors.New("comment is not passed")
	}

	tx, err = s.Db.Beginx()
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	if parent != nil {
		err = tx.Get(loadedParent, "SELECT * FROM comment WHERE id = $1", parent.ID)
		if err != nil {
			return nil, err
		}
		newComment.Path = parent.Path + EncodePathComponent(parent.ID)
		newComment.Depth = loadedParent.Depth + 1
		newComment.Parent = &parent.ID
	} else {
		newComment.Path = EncodePathComponent(thread.ID)
	}

	res, err = tx.NamedExec(`
		INSERT INTO comment
			(tid, path, body, remote_addr, created, modified, author, email, website, depth, parent)
		VALUES (:tid,:path, :body, :remote_addr, :created, :modified, :author, :email, :website, :depth, :parent)
	`, &newComment)
	if err != nil {
		return nil, err
	}

	id, err = res.LastInsertId()
	if err != nil {
		return nil, err
	}

	newComment.ID = IDType(id)
	return &newComment, nil
}

func openSqliteStorage(dbUrl string) (*sqliteStorage, error) {
	var (
		res = &sqliteStorage{}
		err error
	)

	res.Db, err = sqlx.Open("sqlite3", dbUrl)

	if err != nil {
		return nil, err
	}

	err = res.runMigrations()
	if err != nil {
		if err == migrate.ErrNoChange {
			return res, nil
		}
		return nil, err
	}

	return res, nil
}

func (s *sqliteStorage) runMigrations() error {
	var (
		err    error
		assets *bindata.AssetSource
		src    source.Driver
		m      *migrate.Migrate
	)

	assets = bindata.Resource(migrations.AssetNames(), func(name string) ([]byte, error) {
		return migrations.Asset(name)
	})
	src, err = bindata.WithInstance(assets)
	if err != nil {
		return err
	}

	d, err := sqlite3.WithInstance(s.Db.DB, &sqlite3.Config{})
	if err != nil {
		return err
	}

	m, err = migrate.NewWithInstance("go-bindata", src, "sqlite3", d)
	if err != nil {
		return err
	}

	return m.Up()
}

//
func MustOpenSqliteStorage(path string) Storage {
	res, err := openSqliteStorage(fmt.Sprintf("%s?parseTime=true", path))
	if err != nil {
		panic(err)
	}

	return res
}
<commit_msg>Adding locks to writing to database #1<commit_after>package kommentator

import (
	"database/sql"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/kenota/kommentator/migrations"
	"github.com/mattes/migrate"
	"github.com/mattes/migrate/database/sqlite3"
	"github.com/mattes/migrate/source"
	"github.com/mattes/migrate/source/go-bindata"

	_ "github.com/mattn/go-sqlite3"
	"sync"
)

// Storage handles storing/retrieving of comments and does not do any access-related checks
type Storage interface {
	// Adds new comment and returns new comment with all storage-related fields populated
	AddComment(thread *Thread, parent *Comment, comment *Comment) (*Comment, error)
	// Delete comment
	DeleteComment(*Comment) (bool, error)
	// Retrieve comment by id
	GetComment(IDType) (*Comment, error)
	// Retrieve thread by uri
	GetThread(string) (*Thread, error)

	// Creates thread
	CreateThread(uri, title string) (*Thread, error)

	// Retrieve comments for thread at specific URI
	GetThreadedComments(uri *string) (*ThreadedComments, error)

	LikeComment(idType IDType) error
	DislikeComment(idType IDType) error
}

// Encodes specified path array to represent materialized path following following following format:
// [X][Y]{1, ...}
// Where:
// x - single character, represents string representation of length of next id as ase base 36 number
// Y - X characters string, which is base 36 representation of id of next node in path
// this structure repeated for required nesting levels

// Panics if length of string representation of any path element is more than 35 characters
func EncodePath(path []IDType) string {
	var (
		result string
		id     IDType
	)

	for _, id = range path {
		result += EncodePathComponent(id)
	}

	return result
}

func EncodePathComponent(id IDType) string {
	var (
		result, encId, encLen string
		encLenSize            int
	)

	encId = strconv.FormatInt(int64(id), 36)
	encLen = strconv.FormatInt(int64(len(encId)), 36)
	encLenSize = len(encLen)
	if encLenSize > 1 {
		panic(fmt.Sprintf("Too long id: %d. EncodedId: %s Length: %d ", id, encId, encLen))
	}

	result += encLen
	result += encId

	return result
}

// sqlWriteFunc is defining a callback which will is allowed to modify sqlite database. Since go-sqlite3 (and sqlite)
// supports only one writer, we need to have a dedicated goroutine doing all updates
type sqlWriteCallback func(func() sqlWriteRes, chan sqlWriteRes)

type sqlWriteRes struct {
	Res interface{}
	Err error
}

type sqliteStorage struct {
	Db *sqlx.DB
	WriteLck *sync.Mutex
}

func copyString(s *string) *string {
	var temp string
	if s == nil {
		return nil
	}

	temp = *s
	return &temp
}

func (s *sqliteStorage) changeLikes(commentId IDType, delta int) error {
	var field string

	s.WriteLck.Lock()
	defer s.WriteLck.Unlock()

	if delta > 0 {
		field = "likes"
	} else {
		field = "dislikes"
		delta = -delta
	}

	res, err := s.Db.Exec(fmt.Sprintf("UPDATE comment SET %s = %s + $1 WHERE id = $2", field, field), delta, commentId)
	if err != nil {
		return err
	}
	affected, err := res.RowsAffected()
	if err != nil {
		return err
	}
	switch affected {
	case 0:
		return errors.New("comment does not exist")
	case 1:
		return nil
	default:
		panic(fmt.Sprintf("Unexpected number of rows updated on limited update: %d", affected))
	}
}

func (s *sqliteStorage) LikeComment(id IDType) error {
	return s.changeLikes(id, 1)
}

func (s *sqliteStorage) DislikeComment(id IDType) error {
	return s.changeLikes(id, -1)
}

func (s *sqliteStorage) DeleteComment(*Comment) (bool, error) {
	panic("not implemented yet")
}

func (s *sqliteStorage) GetComment(id IDType) (*Comment, error) {
	var (
		err error
		res Comment
	)

	err = s.Db.Get(&res, "SELECT * FROM comment WHERE id = $1", id)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &res, nil
}

func (s *sqliteStorage) GetThread(uri string) (*Thread, error) {
	var (
		err    error
		thread Thread
	)

	err = s.Db.Get(&thread, "SELECT * FROM thread WHERE uri = $1", uri)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &thread, nil
}

func (s *sqliteStorage) CreateThread(uri, title string) (*Thread, error) {
	var (
		id        int64
		err       error
		newThread = &Thread{
			URI:   uri,
			Title: title,
		}
		res sql.Result
	)

	s.WriteLck.Lock()
	defer s.WriteLck.Unlock()

	res, err = s.Db.NamedExec(`
		INSERT INTO thread (uri, title) VALUES (:uri, :title)
	`, newThread)
	if err != nil {
		return nil, err
	}

	id, err = res.LastInsertId()
	if err != nil {
		return nil, err
	}

	newThread.ID = IDType(id)

	return newThread, nil
}

func (s *sqliteStorage) GetThreadedComments(uri *string) (*ThreadedComments, error) {
	var (
		err    error
		th     Thread
		result ThreadedComments
	)

	err = s.Db.Get(&th, "SELECT * FROM thread WHERE uri = $1", uri)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	result.Comments = []Comment{}

	err = s.Db.Select(&result.Comments, "SELECT * FROM comment WHERE tid = $1 ORDER BY path, created", th.ID)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

func (s *sqliteStorage) AddComment(thread *Thread, parent *Comment, comment *Comment) (*Comment, error) {
	var (
		id         int64
		err        error
		tx         *sqlx.Tx
		res        sql.Result
		newComment = Comment{
			ID:         comment.ID,
			Author:     comment.Author,
			Body:       comment.Body,
			Email:      copyString(comment.Email),
			Website:    copyString(comment.Website),
			RemoteAddr: comment.RemoteAddr,
			ThreadID:   thread.ID,
		}
		now          = time.Now()
		loadedParent = &Comment{}
	)

	s.WriteLck.Lock()
	defer s.WriteLck.Unlock()

	newComment.Created = &now
	newComment.Modified = &now

	if comment == nil {
		return nil, errors.New("comment is not passed")
	}

	tx, err = s.Db.Beginx()
	if err != nil {
		return nil, err
	}

	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	if parent != nil {
		err = tx.Get(loadedParent, "SELECT * FROM comment WHERE id = $1", parent.ID)
		if err != nil {
			return nil, err
		}
		newComment.Path = parent.Path + EncodePathComponent(parent.ID)
		newComment.Depth = loadedParent.Depth + 1
		newComment.Parent = &parent.ID
	} else {
		newComment.Path = EncodePathComponent(thread.ID)
	}

	res, err = tx.NamedExec(`
		INSERT INTO comment
			(tid, path, body, remote_addr, created, modified, author, email, website, depth, parent)
		VALUES (:tid,:path, :body, :remote_addr, :created, :modified, :author, :email, :website, :depth, :parent)
	`, &newComment)
	if err != nil {
		return nil, err
	}

	id, err = res.LastInsertId()
	if err != nil {
		return nil, err
	}

	newComment.ID = IDType(id)
	return &newComment, nil
}

func openSqliteStorage(dbUrl string) (*sqliteStorage, error) {
	var (
		res = &sqliteStorage{
			WriteLck: &sync.Mutex{},
		}
		err error
	)

	res.Db, err = sqlx.Open("sqlite3", dbUrl)

	if err != nil {
		return nil, err
	}

	err = res.runMigrations()
	if err != nil {
		if err == migrate.ErrNoChange {
			return res, nil
		}
		return nil, err
	}

	return res, nil
}

func (s *sqliteStorage) runMigrations() error {
	var (
		err    error
		assets *bindata.AssetSource
		src    source.Driver
		m      *migrate.Migrate
	)

	assets = bindata.Resource(migrations.AssetNames(), func(name string) ([]byte, error) {
		return migrations.Asset(name)
	})
	src, err = bindata.WithInstance(assets)
	if err != nil {
		return err
	}

	d, err := sqlite3.WithInstance(s.Db.DB, &sqlite3.Config{})
	if err != nil {
		return err
	}

	m, err = migrate.NewWithInstance("go-bindata", src, "sqlite3", d)
	if err != nil {
		return err
	}

	return m.Up()
}

//
func MustOpenSqliteStorage(path string) Storage {
	res, err := openSqliteStorage(fmt.Sprintf("%s?parseTime=true", path))
	if err != nil {
		panic(err)
	}

	return res
}
<|endoftext|>


<commit_before>package ofsserver

import (
	"errors"
	"fmt"
)

var (
	// ErrAuthRequired occurs after a client connection if the first 4 bytes received is not 0xFFFFFFnn
	// and the server requires authorization
	ErrAuthRequired = errors.New("Client authentication is required")
	// ErrInvalidAuth occurs when the client authentication is incorrect
	ErrInvalidAuth = errors.New("Invalid Credentials")
	// ErrInvalidReauthentication occurs when the client sends a authentication header after
	// the client has already authenticated
	ErrInvalidReauthentication = errors.New("Client is attempting unexpected re-authentication")
	// ErrShortWrite occurs when the server writes less bytes than it expected to write and it is
	// considered an error
	ErrShortWrite = errors.New("Expecting to write more bytes than were actually written")
)

// CreateArgumentNilError creates a custom form ErrArgumentNil with the argument
// name included in the error message
func CreateArgumentNilError(paramName string) error {
	return fmt.Errorf("The argument '%s' cannot be nil", paramName)
}

// CreateBadArgumentError creates a custom form ErrArgumentNil with the argument
// name included in the error message
func CreateBadArgumentError(paramName, message string, args ...interface{}) error {
	return fmt.Errorf("The value of the argument '%s' is invalid: %s", paramName, fmt.Sprintf(message, args))
}
<commit_msg>fix lint complaint<commit_after>package ofsserver

import (
	"errors"
	"fmt"
)

var (
	// ErrAuthRequired occurs after a client connection if the first 4 bytes received is not 0xFFFFFFnn
	// and the server requires authorization
	ErrAuthRequired = errors.New("Client authentication is required")
	// ErrInvalidAuth occurs when the client authentication is incorrect
	ErrInvalidAuth = errors.New("Invalid Credentials")
	// ErrInvalidReauthentication occurs when the client sends a authentication header after
	// the client has already authenticated
	ErrInvalidReauthentication = errors.New("Client is attempting unexpected re-authentication")
	// ErrShortWrite occurs when the server writes less bytes than it expected to write and it is
	// considered an error
	ErrShortWrite = errors.New("Expecting to write more bytes than were actually written")
)

// CreateArgumentNilError creates a custom form ErrArgumentNil with the argument
// name included in the error message
func CreateArgumentNilError(paramName string) error {
	return fmt.Errorf("The argument '%s' cannot be nil", paramName)
}

// CreateBadArgumentError creates a custom form ErrArgumentNil with the argument
// name included in the error message
func CreateBadArgumentError(paramName, message string, args ...interface{}) error {
	return fmt.Errorf("The value of the argument '%s' is invalid: %s", paramName, fmt.Sprintf(message, args...))
}
<|endoftext|>


<commit_before>package main

// Serves the scope's main page.

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

func rootHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, page)
}

func eventHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		dataLock.Lock()
		defer dataLock.Unlock()
		fmt.Println("GET:", state)
		json.NewEncoder(w).Encode(&state)
	case "PUT":
		state := make(map[string]interface{})
		check(json.NewDecoder(r.Body).Decode(&state))
		fmt.Println("POST:", state)
		s := NewState(state)
		s.WriteTo(serial)
	}
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

const page = `
<!DOCTYPE html>

	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>SoftScope</title>

	<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.4.2/pure-min.css">

SoftScope

  Samples  	 <input id=Samples  type=number min=1 value=256          onchange="upload();">

  TrigLev  	 <input id=TrigLev  type=number min=1 value=510 max=1023 onchange="upload();">

  TimeBase 	 <input id=TimeBase type=number min=1 value=200          onchange="upload();">

`
<commit_msg>webinterface: prototype parameter setting<commit_after>package main

// Serves the scope's main page.

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

func rootHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, page)
}

func eventHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		dataLock.Lock()
		defer dataLock.Unlock()
		fmt.Println("GET:", state)
		json.NewEncoder(w).Encode(&state)
	case "PUT":
		state := make(map[string]interface{})
		check(json.NewDecoder(r.Body).Decode(&state))
		fmt.Println("POST:", state)
		s := NewState(state)
		s.WriteTo(serial)
	}
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

const page = `
<!DOCTYPE html>

	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>SoftScope</title>

	<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.4.2/pure-min.css">

SoftScope

  Samples  	 <input id=Samples  type=number min=1 value=256          onchange="upload();">

  TrigLev  	 <input id=TrigLev  type=number min=1 value=510 max=1023 onchange="upload();">

  TimeBase 	 <input id=TimeBase type=number min=1 value=200          onchange="upload();">

`
<|endoftext|>


<commit_before>// Copyright 2015 Peter Goetz
//
// 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 pegomock

import (
	"reflect"
	"testing"

	"github.com/petergtz/pegomock/pegomock/internal/testingtsupport"
	"github.com/petergtz/pegomock/pegomock/types"
)

var GlobalFailHandler types.FailHandler

func RegisterMockFailHandler(handler types.FailHandler) {
	GlobalFailHandler = handler
}
func RegisterMockTestingT(t *testing.T) {
	RegisterMockFailHandler(testingtsupport.BuildTestingTGomegaFailHandler(t))
}

type Mock interface{}
type Param interface{}
type ReturnValue interface{}
type ReturnValues []ReturnValue

var lastInvocation *invocation
var argMatchers Matchers

type invocation struct {
	genericMock *GenericMock
	MethodName  string
	Params      []Param
}

type GenericMock struct {
	mockedMethods map[string]*mockedMethod
}

func (genericMock *GenericMock) Invoke(methodName string, params ...Param) ReturnValues {
	lastInvocation = &invocation{genericMock: genericMock, MethodName: methodName, Params: params}

	if _, ok := genericMock.mockedMethods[methodName]; !ok {
		genericMock.mockedMethods[methodName] = &mockedMethod{name: methodName}
	}
	return genericMock.mockedMethods[methodName].Invoke(params)
}

func (genericMock *GenericMock) stub(methodName string, paramMatchers []Matcher, returnValues ReturnValues) {
	if _, ok := genericMock.mockedMethods[methodName]; !ok {
		genericMock.mockedMethods[methodName] = &mockedMethod{name: methodName}
	}
	genericMock.mockedMethods[methodName].stub(paramMatchers, returnValues)
}

func (genericMock *GenericMock) Reset(methodName string, params []Matcher) {
	// TODO: should be called from When
}

func (genericMock *GenericMock) NumMethodInvocations(methodName string, params ...Param) int {
	if len(argMatchers) != 0 {
		checkArgument(len(argMatchers) == len(params), "If you use matchers, you must use matchers for all parameters. Example: TODO")
		result := genericMock.NumMethodInvocationsUsingMatchers(methodName, argMatchers)
		argMatchers = nil
		return result
	}

	count := 0
	for _, invocation := range genericMock.mockedMethods[methodName].invocations {
		if reflect.DeepEqual(params, invocation) {
			count++
		}
	}
	return count
}

func (genericMock *GenericMock) NumMethodInvocationsUsingMatchers(methodName string, paramMatchers Matchers) int {
	count := 0
	for _, invocation := range genericMock.mockedMethods[methodName].invocations {
		if paramMatchers.matches(invocation) {
			count++
		}
	}
	return count
}

type mockedMethod struct {
	name        string
	invocations [][]Param
	stubbings   Stubbings
}

func (method *mockedMethod) Invoke(params []Param) ReturnValues {
	method.invocations = append(method.invocations, params)
	stubbing := method.stubbings.find(params)
	if stubbing == nil {
		return ReturnValues{}
	}
	return stubbing.Invoke(params)
}

func (method *mockedMethod) stub(paramMatchers Matchers, returnValues ReturnValues) {
	stubbing := method.stubbings.findByMatchers(paramMatchers)
	if stubbing != nil {
		stubbing.returnValuesSequence = append(stubbing.returnValuesSequence, returnValues)
	} else {
		method.stubbings = append(method.stubbings, &Stubbing{paramMatchers: paramMatchers, returnValuesSequence: []ReturnValues{returnValues}})
	}
}

func (method *mockedMethod) removeLastInvocation() {
	method.invocations = method.invocations[:len(method.invocations)-1]
}

type Stubbings []*Stubbing

func (stubbings Stubbings) find(params []Param) *Stubbing {
	for _, stubbing := range stubbings {
		if stubbing.paramMatchers.matches(params) {
			return stubbing
		}
	}
	return nil
}

func (stubbings Stubbings) findByMatchers(paramMatchers Matchers) *Stubbing {
	for _, stubbing := range stubbings {
		if reflect.DeepEqual(stubbing.paramMatchers, paramMatchers) {
			return stubbing
		}
	}
	return nil
}

type Stubbing struct {
	paramMatchers        Matchers
	returnValuesSequence []ReturnValues
	sequencePointer      int
}

func (stubbing *Stubbing) Invoke(params []Param) ReturnValues {
	result := stubbing.returnValuesSequence[stubbing.sequencePointer]
	if stubbing.sequencePointer < len(stubbing.returnValuesSequence)-1 {
		stubbing.sequencePointer++
	}
	return result
}

type Matchers []Matcher

func (matchers Matchers) matches(params []Param) bool {
	checkArgument(len(matchers) == len(params), "Number of params and matchers different: params: %v, matchers: %v", params, matchers)
	for i := range params {
		if !matchers[i].matches(params[i]) {
			return false
		}
	}
	return true
}

func (matchers *Matchers) append(matcher Matcher) {
	*matchers = append(*matchers, matcher)
}

type ongoingStubbing struct {
	genericMock   *GenericMock
	MethodName    string
	ParamMatchers []Matcher
	returnValues  []interface{}
}

func When(invocation ...interface{}) *ongoingStubbing {
	checkNotNil(lastInvocation,
		"when() requires an argument which has to be 'a method call on a mock'.")
	defer func() {
		lastInvocation = nil
		argMatchers = nil
	}()

	var paramMatchers []Matcher
	if len(argMatchers) == 0 {
		paramMatchers = make([]Matcher, 0)
		for param := range lastInvocation.Params {
			paramMatchers = append(paramMatchers, &EqMatcher{param})
		}
	} else {
		checkArgument(len(argMatchers) == len(lastInvocation.Params),
			"You must use the same number of matchers as arguments")
		paramMatchers = argMatchers
	}
	lastInvocation.genericMock.mockedMethods[lastInvocation.MethodName].removeLastInvocation()
	return &ongoingStubbing{
		genericMock:   lastInvocation.genericMock,
		MethodName:    lastInvocation.MethodName,
		ParamMatchers: paramMatchers,
		returnValues:  invocation,
	}
}

var genericMocks = make(map[Mock]*GenericMock)

func GetGenericMockFrom(mock Mock) *GenericMock {
	if genericMocks[mock] == nil {
		genericMocks[mock] = &GenericMock{mockedMethods: make(map[string]*mockedMethod)}
	}
	return genericMocks[mock]
}

func (stubbing *ongoingStubbing) ThenReturn(values ...ReturnValue) *ongoingStubbing {
	checkArgument(len(values) == len(stubbing.returnValues),
		"Different number of return values")
	for i := range values {
		checkArgument(reflect.TypeOf(values[i]) == reflect.TypeOf(stubbing.returnValues[i]),
			"Return type doesn't match")
	}
	stubbing.genericMock.stub(stubbing.MethodName, stubbing.ParamMatchers, values)
	return stubbing
}

type Stubber struct {
	returnValue interface{}
}

func DoPanic(value interface{}) *Stubber {
	return &Stubber{returnValue: value}
}

func (stubber *Stubber) When(mock interface{}) {

}
<commit_msg>More small refactorings<commit_after>// Copyright 2015 Peter Goetz
//
// 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 pegomock

import (
	"reflect"
	"testing"

	"github.com/petergtz/pegomock/pegomock/internal/testingtsupport"
	"github.com/petergtz/pegomock/pegomock/types"
)

var GlobalFailHandler types.FailHandler

func RegisterMockFailHandler(handler types.FailHandler) {
	GlobalFailHandler = handler
}
func RegisterMockTestingT(t *testing.T) {
	RegisterMockFailHandler(testingtsupport.BuildTestingTGomegaFailHandler(t))
}

type Mock interface{}
type Param interface{}
type ReturnValue interface{}
type ReturnValues []ReturnValue

var lastInvocation *invocation
var argMatchers Matchers

type invocation struct {
	genericMock *GenericMock
	MethodName  string
	Params      []Param
}

type GenericMock struct {
	mockedMethods map[string]*mockedMethod
}

func (genericMock *GenericMock) Invoke(methodName string, params ...Param) ReturnValues {
	lastInvocation = &invocation{
		genericMock: genericMock,
		MethodName:  methodName,
		Params:      params,
	}
	return genericMock.getMockedMethod(methodName).Invoke(params)
}

func (genericMock *GenericMock) stub(methodName string, paramMatchers []Matcher, returnValues ReturnValues) {
	genericMock.getMockedMethod(methodName).stub(paramMatchers, returnValues)
}

func (genericMock *GenericMock) getMockedMethod(methodName string) *mockedMethod {
	if _, ok := genericMock.mockedMethods[methodName]; !ok {
		genericMock.mockedMethods[methodName] = &mockedMethod{name: methodName}
	}
	return genericMock.mockedMethods[methodName]
}

func (genericMock *GenericMock) Reset(methodName string, params []Matcher) {
	// TODO: should be called from When
}

func (genericMock *GenericMock) NumMethodInvocations(methodName string, params ...Param) int {
	if len(argMatchers) != 0 {
		checkArgument(len(argMatchers) == len(params),
			"If you use matchers, you must use matchers for all parameters. Example: TODO")
		result := genericMock.numMethodInvocationsUsingMatchers(methodName, argMatchers)
		argMatchers = nil
		return result
	}

	count := 0
	for _, invocation := range genericMock.mockedMethods[methodName].invocations {
		if reflect.DeepEqual(params, invocation) {
			count++
		}
	}
	return count
}

func (genericMock *GenericMock) numMethodInvocationsUsingMatchers(methodName string, paramMatchers Matchers) int {
	count := 0
	for _, invocation := range genericMock.mockedMethods[methodName].invocations {
		if paramMatchers.matches(invocation) {
			count++
		}
	}
	return count
}

type mockedMethod struct {
	name        string
	invocations [][]Param
	stubbings   Stubbings
}

func (method *mockedMethod) Invoke(params []Param) ReturnValues {
	method.invocations = append(method.invocations, params)
	stubbing := method.stubbings.find(params)
	if stubbing == nil {
		return ReturnValues{}
	}
	return stubbing.Invoke(params)
}

func (method *mockedMethod) stub(paramMatchers Matchers, returnValues ReturnValues) {
	stubbing := method.stubbings.findByMatchers(paramMatchers)
	if stubbing != nil {
		stubbing.returnValuesSequence = append(stubbing.returnValuesSequence, returnValues)
	} else {
		method.stubbings = append(method.stubbings, &Stubbing{
			paramMatchers:        paramMatchers,
			returnValuesSequence: []ReturnValues{returnValues},
		})
	}
}

func (method *mockedMethod) removeLastInvocation() {
	method.invocations = method.invocations[:len(method.invocations)-1]
}

type Stubbings []*Stubbing

func (stubbings Stubbings) find(params []Param) *Stubbing {
	for _, stubbing := range stubbings {
		if stubbing.paramMatchers.matches(params) {
			return stubbing
		}
	}
	return nil
}

func (stubbings Stubbings) findByMatchers(paramMatchers Matchers) *Stubbing {
	for _, stubbing := range stubbings {
		if reflect.DeepEqual(stubbing.paramMatchers, paramMatchers) {
			return stubbing
		}
	}
	return nil
}

type Stubbing struct {
	paramMatchers        Matchers
	returnValuesSequence []ReturnValues
	sequencePointer      int
}

func (stubbing *Stubbing) Invoke(params []Param) ReturnValues {
	result := stubbing.returnValuesSequence[stubbing.sequencePointer]
	if stubbing.sequencePointer < len(stubbing.returnValuesSequence)-1 {
		stubbing.sequencePointer++
	}
	return result
}

type Matchers []Matcher

func (matchers Matchers) matches(params []Param) bool {
	checkArgument(len(matchers) == len(params),
		"Number of params and matchers different: params: %v, matchers: %v",
		params, matchers)
	for i := range params {
		if !matchers[i].matches(params[i]) {
			return false
		}
	}
	return true
}

func (matchers *Matchers) append(matcher Matcher) {
	*matchers = append(*matchers, matcher)
}

type ongoingStubbing struct {
	genericMock   *GenericMock
	MethodName    string
	ParamMatchers []Matcher
	returnValues  []interface{}
}

func When(invocation ...interface{}) *ongoingStubbing {
	checkNotNil(lastInvocation,
		"when() requires an argument which has to be 'a method call on a mock'.")
	defer func() {
		lastInvocation = nil
		argMatchers = nil
	}()
	lastInvocation.genericMock.mockedMethods[lastInvocation.MethodName].removeLastInvocation()
	return &ongoingStubbing{
		genericMock:   lastInvocation.genericMock,
		MethodName:    lastInvocation.MethodName,
		ParamMatchers: paramMatchersFromArgMatchersOrParams(argMatchers, lastInvocation.Params),
		returnValues:  invocation,
	}
}

func paramMatchersFromArgMatchersOrParams(argMatchers []Matcher, params []Param) []Matcher {
	if len(argMatchers) == 0 {
		return transformParamsIntoEqMatchers(params)
	} else {
		checkArgument(len(argMatchers) == len(lastInvocation.Params),
			"You must use the same number of matchers as arguments. Example: TODO")
		return argMatchers
	}
}

func transformParamsIntoEqMatchers(params []Param) []Matcher {
	paramMatchers := make([]Matcher, len(params))
	for param := range params {
		paramMatchers = append(paramMatchers, &EqMatcher{param})
	}
	return paramMatchers
}

var genericMocks = make(map[Mock]*GenericMock)

func GetGenericMockFrom(mock Mock) *GenericMock {
	if genericMocks[mock] == nil {
		genericMocks[mock] = &GenericMock{mockedMethods: make(map[string]*mockedMethod)}
	}
	return genericMocks[mock]
}

func (stubbing *ongoingStubbing) ThenReturn(values ...ReturnValue) *ongoingStubbing {
	checkArguments(values, stubbing.returnValues)
	stubbing.genericMock.stub(stubbing.MethodName, stubbing.ParamMatchers, values)
	return stubbing
}

func checkArguments(stubbedReturnValues []ReturnValue, pseudoReturnValues []interface{}) {
	checkArgument(len(stubbedReturnValues) == len(pseudoReturnValues),
		"Different number of return values")
	for i := range stubbedReturnValues {
		checkArgument(reflect.TypeOf(stubbedReturnValues[i]) == reflect.TypeOf(pseudoReturnValues[i]),
			"Return type doesn't match")
	}
}

type Stubber struct {
	returnValue interface{}
}

func DoPanic(value interface{}) *Stubber {
	return &Stubber{returnValue: value}
}

func (stubber *Stubber) When(mock interface{}) {

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	ggio "github.com/gogo/protobuf/io"
	p2p_host "github.com/libp2p/go-libp2p-host"
	p2p_net "github.com/libp2p/go-libp2p-net"
	p2p_peer "github.com/libp2p/go-libp2p-peer"
	p2p_pstore "github.com/libp2p/go-libp2p-peerstore"
	mc "github.com/mediachain/concat/mc"
	pb "github.com/mediachain/concat/proto"
	"log"
	"os"
	"sync"
)

type Directory struct {
	mc.PeerIdentity
	host  p2p_host.Host
	peers map[p2p_peer.ID]p2p_pstore.PeerInfo
	mx    sync.Mutex
}

func (dir *Directory) registerHandler(s p2p_net.Stream) {
	defer s.Close()

	pid := s.Conn().RemotePeer()
	log.Printf("directory/register: new stream from %s\n", pid.Pretty())

	r := ggio.NewDelimitedReader(s, mc.MaxMessageSize)
	req := new(pb.RegisterPeer)

	for {
		err := r.ReadMsg(req)
		if err != nil {
			break
		}

		if req.Info == nil {
			log.Printf("directory/register: empty peer info from %s\n", pid.Pretty())
			break
		}

		pinfo, err := mc.PBToPeerInfo(req.Info)
		if err != nil {
			log.Printf("directory/register: bad peer info from %s\n", pid.Pretty())
			break
		}

		if pinfo.ID != pid {
			log.Printf("directory/register: bogus peer info from %s\n", pid.Pretty())
			break
		}

		dir.registerPeer(pinfo)

		req.Reset()
	}

	dir.unregisterPeer(pid)
}

func (dir *Directory) lookupHandler(s p2p_net.Stream) {
	defer s.Close()

	pid := s.Conn().RemotePeer()
	log.Printf("directory/lookup: new stream from %s\n", pid.Pretty())

	r := ggio.NewDelimitedReader(s, mc.MaxMessageSize)
	w := ggio.NewDelimitedWriter(s)
	req := new(pb.LookupPeerRequest)
	resp := new(pb.LookupPeerResponse)

	for {
		err := r.ReadMsg(req)
		if err != nil {
			break
		}

		xid, err := p2p_peer.IDB58Decode(req.Id)
		if err != nil {
			log.Printf("directory/lookup: bad request from %s\n", pid.Pretty())
			break
		}

		pinfo, ok := dir.lookupPeer(xid)
		if ok {
			var pbpi pb.PeerInfo
			mc.PBFromPeerInfo(&pbpi, pinfo)
			resp.Peer = &pbpi
		}

		err = w.WriteMsg(resp)
		if err != nil {
			break
		}

		req.Reset()
		resp.Reset()
	}
}

func (dir *Directory) listHandler(s p2p_net.Stream) {
	// Implement Me!
	s.Close()
}

func (dir *Directory) registerPeer(info p2p_pstore.PeerInfo) {
	log.Printf("directory: register %s\n", info.ID.Pretty())
	dir.mx.Lock()
	dir.peers[info.ID] = info
	dir.mx.Unlock()
}

func (dir *Directory) unregisterPeer(pid p2p_peer.ID) {
	log.Printf("directory: unregister %s\n", pid.Pretty())
	dir.mx.Lock()
	delete(dir.peers, pid)
	dir.mx.Unlock()
}

func (dir *Directory) lookupPeer(pid p2p_peer.ID) (p2p_pstore.PeerInfo, bool) {
	dir.mx.Lock()
	pinfo, ok := dir.peers[pid]
	dir.mx.Unlock()
	return pinfo, ok
}

func main() {
	port := flag.Int("l", 9000, "Listen port")
	home := flag.String("d", "/tmp/mcdir", "Directory home")
	flag.Parse()

	err := os.MkdirAll(*home, 0755)
	if err != nil {
		log.Fatal(err)
	}

	id, err := mc.MakePeerIdentity(*home)
	if err != nil {
		log.Fatal(err)
	}

	addr, err := mc.ParseAddress(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *port))
	if err != nil {
		log.Fatal(err)
	}

	host, err := mc.NewHost(id, addr)
	if err != nil {
		log.Fatal(err)
	}

	dir := &Directory{PeerIdentity: id, host: host, peers: make(map[p2p_peer.ID]p2p_pstore.PeerInfo)}
	host.SetStreamHandler("/mediachain/dir/register", dir.registerHandler)
	host.SetStreamHandler("/mediachain/dir/lookup", dir.lookupHandler)
	host.SetStreamHandler("/mediachain/dir/list", dir.listHandler)

	addrs, err := host.Network().InterfaceListenAddresses()
	if err != nil {
		log.Fatal(err)
	}

	for _, addr := range addrs {
		log.Printf("I am %s/%s", addr, id.Pretty())
	}
	select {}
}
<commit_msg>mcdir: use Host.Addrs() for address enumeration<commit_after>package main

import (
	"flag"
	"fmt"
	ggio "github.com/gogo/protobuf/io"
	p2p_host "github.com/libp2p/go-libp2p-host"
	p2p_net "github.com/libp2p/go-libp2p-net"
	p2p_peer "github.com/libp2p/go-libp2p-peer"
	p2p_pstore "github.com/libp2p/go-libp2p-peerstore"
	mc "github.com/mediachain/concat/mc"
	pb "github.com/mediachain/concat/proto"
	"log"
	"os"
	"sync"
)

type Directory struct {
	mc.PeerIdentity
	host  p2p_host.Host
	peers map[p2p_peer.ID]p2p_pstore.PeerInfo
	mx    sync.Mutex
}

func (dir *Directory) registerHandler(s p2p_net.Stream) {
	defer s.Close()

	pid := s.Conn().RemotePeer()
	log.Printf("directory/register: new stream from %s\n", pid.Pretty())

	r := ggio.NewDelimitedReader(s, mc.MaxMessageSize)
	req := new(pb.RegisterPeer)

	for {
		err := r.ReadMsg(req)
		if err != nil {
			break
		}

		if req.Info == nil {
			log.Printf("directory/register: empty peer info from %s\n", pid.Pretty())
			break
		}

		pinfo, err := mc.PBToPeerInfo(req.Info)
		if err != nil {
			log.Printf("directory/register: bad peer info from %s\n", pid.Pretty())
			break
		}

		if pinfo.ID != pid {
			log.Printf("directory/register: bogus peer info from %s\n", pid.Pretty())
			break
		}

		dir.registerPeer(pinfo)

		req.Reset()
	}

	dir.unregisterPeer(pid)
}

func (dir *Directory) lookupHandler(s p2p_net.Stream) {
	defer s.Close()

	pid := s.Conn().RemotePeer()
	log.Printf("directory/lookup: new stream from %s\n", pid.Pretty())

	r := ggio.NewDelimitedReader(s, mc.MaxMessageSize)
	w := ggio.NewDelimitedWriter(s)
	req := new(pb.LookupPeerRequest)
	resp := new(pb.LookupPeerResponse)

	for {
		err := r.ReadMsg(req)
		if err != nil {
			break
		}

		xid, err := p2p_peer.IDB58Decode(req.Id)
		if err != nil {
			log.Printf("directory/lookup: bad request from %s\n", pid.Pretty())
			break
		}

		pinfo, ok := dir.lookupPeer(xid)
		if ok {
			var pbpi pb.PeerInfo
			mc.PBFromPeerInfo(&pbpi, pinfo)
			resp.Peer = &pbpi
		}

		err = w.WriteMsg(resp)
		if err != nil {
			break
		}

		req.Reset()
		resp.Reset()
	}
}

func (dir *Directory) listHandler(s p2p_net.Stream) {
	// Implement Me!
	s.Close()
}

func (dir *Directory) registerPeer(info p2p_pstore.PeerInfo) {
	log.Printf("directory: register %s\n", info.ID.Pretty())
	dir.mx.Lock()
	dir.peers[info.ID] = info
	dir.mx.Unlock()
}

func (dir *Directory) unregisterPeer(pid p2p_peer.ID) {
	log.Printf("directory: unregister %s\n", pid.Pretty())
	dir.mx.Lock()
	delete(dir.peers, pid)
	dir.mx.Unlock()
}

func (dir *Directory) lookupPeer(pid p2p_peer.ID) (p2p_pstore.PeerInfo, bool) {
	dir.mx.Lock()
	pinfo, ok := dir.peers[pid]
	dir.mx.Unlock()
	return pinfo, ok
}

func main() {
	port := flag.Int("l", 9000, "Listen port")
	home := flag.String("d", "/tmp/mcdir", "Directory home")
	flag.Parse()

	err := os.MkdirAll(*home, 0755)
	if err != nil {
		log.Fatal(err)
	}

	id, err := mc.MakePeerIdentity(*home)
	if err != nil {
		log.Fatal(err)
	}

	addr, err := mc.ParseAddress(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *port))
	if err != nil {
		log.Fatal(err)
	}

	host, err := mc.NewHost(id, addr)
	if err != nil {
		log.Fatal(err)
	}

	dir := &Directory{PeerIdentity: id, host: host, peers: make(map[p2p_peer.ID]p2p_pstore.PeerInfo)}
	host.SetStreamHandler("/mediachain/dir/register", dir.registerHandler)
	host.SetStreamHandler("/mediachain/dir/lookup", dir.lookupHandler)
	host.SetStreamHandler("/mediachain/dir/list", dir.listHandler)

	for _, addr := range host.Addrs() {
		log.Printf("I am %s/%s", addr, id.Pretty())
	}
	select {}
}
<|endoftext|>


<commit_before>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
import "C"

// MediaList represents a collection of media files.
type MediaList struct {
	list *C.libvlc_media_list_t
}

// NewMediaList creates an empty media list.
func NewMediaList() (*MediaList, error) {
	if inst == nil {
		return nil, ErrModuleNotInitialized
	}

	var list *C.libvlc_media_list_t
	if list = C.libvlc_media_list_new(inst.handle); list == nil {
		return nil, getError()
	}

	return &MediaList{list: list}, nil
}

// Release destroys the media list instance.
func (ml *MediaList) Release() error {
	if ml.list == nil {
		return nil
	}

	C.libvlc_media_list_release(ml.list)
	ml.list = nil

	return getError()
}

// AddMedia adds a Media instance to the media list.
func (ml *MediaList) AddMedia(m *Media) error {
	if m == nil || m.media == nil {
		return ErrMediaNotInitialized
	}
	if err := ml.Lock(); err != nil {
		return err
	}
	defer ml.Unlock()

	C.libvlc_media_list_add_media(ml.list, m.media)
	return getError()
}

// AddMediaFromPath loads a media file from path and adds it
// to the the media list.
func (ml *MediaList) AddMediaFromPath(path string) error {
	media, err := NewMediaFromPath(path)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// AddMediaFromURL loads a media file from url and adds it
// to the the media list.
func (ml *MediaList) AddMediaFromURL(url string) error {
	media, err := NewMediaFromURL(url)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// Lock makes the caller the current owner of the media list.
func (ml *MediaList) Lock() error {
	if ml.list == nil {
		return ErrMediaListNotInitialized
	}

	C.libvlc_media_list_lock(ml.list)
	return getError()
}

// Unlock releases ownership of the media list.
func (ml *MediaList) Unlock() error {
	if ml.list == nil {
		return ErrMediaListNotInitialized
	}

	C.libvlc_media_list_unlock(ml.list)
	return getError()
}

// EventManager returns the event manager responsible for the media list.
func (ml *MediaList) EventManager() (*EventManager, error) {
	if ml.list == nil {
		return nil, ErrMediaListNotInitialized
	}

	manager := C.libvlc_media_list_event_manager(ml.list)
	if manager == nil {
		return nil, ErrMissingEventManager
	}

	return newEventManager(manager), nil
}
<commit_msg>Implement additional bindings for media lists<commit_after>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
import "C"

// MediaList represents a collection of media files.
type MediaList struct {
	list *C.libvlc_media_list_t
}

// NewMediaList creates an empty media list.
func NewMediaList() (*MediaList, error) {
	if inst == nil {
		return nil, ErrModuleNotInitialized
	}

	var list *C.libvlc_media_list_t
	if list = C.libvlc_media_list_new(inst.handle); list == nil {
		return nil, getError()
	}

	return &MediaList{list: list}, nil
}

// Release destroys the media list instance.
func (ml *MediaList) Release() error {
	if ml.list == nil {
		return nil
	}

	C.libvlc_media_list_release(ml.list)
	ml.list = nil

	return getError()
}

// AddMedia adds the provided Media instance at the end of the media list.
func (ml *MediaList) AddMedia(m *Media) error {
	if m == nil || m.media == nil {
		return ErrMediaNotInitialized
	}
	if err := ml.Lock(); err != nil {
		return err
	}
	defer ml.Unlock()

	C.libvlc_media_list_add_media(ml.list, m.media)
	return getError()
}

// AddMediaFromPath loads the media file at the specified path and adds it at
// the end of the media list.
func (ml *MediaList) AddMediaFromPath(path string) error {
	media, err := NewMediaFromPath(path)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// AddMediaFromURL loads the media file at the specified URL and adds it at the
// end of the the media list.
func (ml *MediaList) AddMediaFromURL(url string) error {
	media, err := NewMediaFromURL(url)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// InsertMedia inserts the provided Media instance in the list,
// at the specified index.
func (ml *MediaList) InsertMedia(m *Media, index uint) error {
	if m == nil || m.media == nil {
		return ErrMediaNotInitialized
	}
	if err := ml.Lock(); err != nil {
		return err
	}
	defer ml.Unlock()

	C.libvlc_media_list_insert_media(ml.list, m.media, C.int(index))
	return getError()
}

// InsertMediaFromPath loads the media file at the provided path and inserts
// it in the list, at the specified index.
func (ml *MediaList) InsertMediaFromPath(path string, index uint) error {
	media, err := NewMediaFromPath(path)
	if err != nil {
		return err
	}

	return ml.InsertMedia(media, index)
}

// InsertMediaFromURL loads the media file at the provided URL and inserts
// it in the list, at the specified index.
func (ml *MediaList) InsertMediaFromURL(url string, index uint) error {
	media, err := NewMediaFromURL(url)
	if err != nil {
		return err
	}

	return ml.InsertMedia(media, index)
}

// RemoveMediaAtIndex removes the media item at the specified index
// from the list.
func (ml *MediaList) RemoveMediaAtIndex(index uint) error {
	if err := ml.Lock(); err != nil {
		return err
	}
	defer ml.Unlock()

	C.libvlc_media_list_remove_index(ml.list, C.int(index))
	return getError()
}

// MediaAtIndex returns the media item at the specified index from the list.
func (ml *MediaList) MediaAtIndex(index uint) (*Media, error) {
	if err := ml.Lock(); err != nil {
		return nil, err
	}
	defer ml.Unlock()

	media := C.libvlc_media_list_item_at_index(ml.list, C.int(index))
	if media == nil {
		return nil, getError()
	}

	// This call will not release the media. Instead, it will decrement
	// the reference count increased by libvlc_media_list_item_at_index.
	C.libvlc_media_release(media)

	return &Media{media}, nil
}

// Count returns the number of media items in the list.
func (ml *MediaList) Count() (int, error) {
	if err := ml.Lock(); err != nil {
		return 0, err
	}
	defer ml.Unlock()

	return int(C.libvlc_media_list_count(ml.list)), getError()
}

// IsReadOnly specifies if the media list can be modified.
func (ml *MediaList) IsReadOnly() (bool, error) {
	if ml.list == nil {
		return false, ErrMediaListNotInitialized
	}

	return (C.libvlc_media_list_is_readonly(ml.list) != C.int(0)), getError()
}

// Lock makes the caller the current owner of the media list.
func (ml *MediaList) Lock() error {
	if ml.list == nil {
		return ErrMediaListNotInitialized
	}

	C.libvlc_media_list_lock(ml.list)
	return getError()
}

// Unlock releases ownership of the media list.
func (ml *MediaList) Unlock() error {
	if ml.list == nil {
		return ErrMediaListNotInitialized
	}

	C.libvlc_media_list_unlock(ml.list)
	return getError()
}

// EventManager returns the event manager responsible for the media list.
func (ml *MediaList) EventManager() (*EventManager, error) {
	if ml.list == nil {
		return nil, ErrMediaListNotInitialized
	}

	manager := C.libvlc_media_list_event_manager(ml.list)
	if manager == nil {
		return nil, ErrMissingEventManager
	}

	return newEventManager(manager), nil
}
<|endoftext|>


<commit_before>// Copyright © 2019 Oxford Nanopore Technologies.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"bufio"
	"fmt"
	"io"
	"os"
	//"runtime"

	"github.com/spf13/cobra"
	"gopkg.in/cheggaaa/pb.v2"
)

// concateCmd represents the concatenate command
var catCmd = &cobra.Command{
	Use:   "cat",
	Short: "stream file to stdout and report progress on stderr",
	Long:  "stream file to stdout and report progress on stderr",

	Run: func(cmd *cobra.Command, args []string) {
		config := getConfigs(cmd)
		outFile := config.OutFile
		files := getFileList(args)
		flagLines := getFlagBool(cmd, "lines")
		flagBuff := getFlagInt(cmd, "buffsize")
		flagFreq := getFlagInt(cmd, "print-freq")
		flagTotal := getFlagInt(cmd, "total")

		of := os.Stdout
		defer of.Close()
		if outFile != "-" {
			var err error
			of, err = os.Create(outFile)
			checkError(err)
		}
		writer := bufio.NewWriterSize(of, flagBuff)
		defer writer.Flush()

		for _, file := range files {
			fmt.Fprintf(os.Stderr, "Streaming file: %s\n", file)
			fh := os.Stdin
			if file != "-" {
				var err error
				fh, err = os.Open(file)
				checkError(err)
			}
			reader := bufio.NewReaderSize(fh, flagBuff)
			var bar *pb.ProgressBar

			if flagLines {
				if flagTotal < 0 {
					panic("help")
				}
				bar = pb.StartNew(flagTotal)
				var line []byte
				var err error
				var count int
				for {
					line, err = reader.ReadBytes('\n')
					if err == io.EOF {
						break
					}
					checkError(err)
					count++
					if count%flagFreq == 0 {
						bar.Add(1)
					}
					_, err := writer.Write(line)
					checkError(err)
				}

			} else {
				var err error
				if flagTotal < 0 {
					if file == "-" {
						panic("help")
					}
					inputStat, err := os.Stat(file)
					checkError(err)
					flagTotal = int(inputStat.Size())

				}
				bar = pb.StartNew(flagTotal)
				byteBuff := make([]byte, flagBuff)
				var count int
				var bytesSince int
				var readSize int
				for {
					readSize, err = reader.Read(byteBuff)
					if err == io.EOF {
						break
					}
					checkError(err)
					count++
					bytesSince += readSize
					if count%flagFreq == 0 {
						bar.Add(bytesSince)
						bytesSince = 0
					}
					_, err = writer.Write(byteBuff[:readSize])
					checkError(err)
				}

			}

			bar.Finish()

			fh.Close()

		}

	},
}

func init() {
	RootCmd.AddCommand(catCmd)
	catCmd.Flags().IntP("print-freq", "p", 1, "print frequency (-1 for print after parsing)")
	catCmd.Flags().IntP("buffsize", "b", 4096*2, "buffer size")
	catCmd.Flags().BoolP("lines", "L", false, "count lines instead of bytes")
	catCmd.Flags().IntP("total", "s", -1, "expected total bytes/lines")
}
<commit_msg>cat: more informative error messages.<commit_after>// Copyright © 2019 Oxford Nanopore Technologies.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"bufio"
	"fmt"
	"io"
	"os"
	//"runtime"

	"github.com/spf13/cobra"
	"gopkg.in/cheggaaa/pb.v2"
)

// concateCmd represents the concatenate command
var catCmd = &cobra.Command{
	Use:   "cat",
	Short: "stream file to stdout and report progress on stderr",
	Long:  "stream file to stdout and report progress on stderr",

	Run: func(cmd *cobra.Command, args []string) {
		config := getConfigs(cmd)
		outFile := config.OutFile
		files := getFileList(args)
		flagLines := getFlagBool(cmd, "lines")
		flagBuff := getFlagInt(cmd, "buffsize")
		flagFreq := getFlagInt(cmd, "print-freq")
		flagTotal := getFlagInt(cmd, "total")

		of := os.Stdout
		defer of.Close()
		if outFile != "-" {
			var err error
			of, err = os.Create(outFile)
			checkError(err)
		}
		writer := bufio.NewWriterSize(of, flagBuff)
		defer writer.Flush()

		for _, file := range files {
			fmt.Fprintf(os.Stderr, "Streaming file: %s\n", file)
			fh := os.Stdin
			if file != "-" {
				var err error
				fh, err = os.Open(file)
				checkError(err)
			}
			reader := bufio.NewReaderSize(fh, flagBuff)
			var bar *pb.ProgressBar

			if flagLines {
				if flagTotal < 0 {
					fmt.Fprintf(os.Stderr, "Cannot read lines unless the of expected number of lines is specified via -s!\n")
					os.Exit(1)
				}
				bar = pb.StartNew(flagTotal)
				var line []byte
				var err error
				var count int
				for {
					line, err = reader.ReadBytes('\n')
					if err == io.EOF {
						break
					}
					checkError(err)
					count++
					if count%flagFreq == 0 {
						bar.Add(1)
					}
					_, err := writer.Write(line)
					checkError(err)
				}

			} else {
				var err error
				if flagTotal < 0 {
					if file == "-" {
						fmt.Fprintf(os.Stderr, "Cannot read from stdin unless the number of expected bytes is specified via -s!\n")
						os.Exit(1)
					}
					inputStat, err := os.Stat(file)
					checkError(err)
					flagTotal = int(inputStat.Size())

				}
				bar = pb.StartNew(flagTotal)
				byteBuff := make([]byte, flagBuff)
				var count int
				var bytesSince int
				var readSize int
				for {
					readSize, err = reader.Read(byteBuff)
					if err == io.EOF {
						break
					}
					checkError(err)
					count++
					bytesSince += readSize
					if count%flagFreq == 0 {
						bar.Add(bytesSince)
						bytesSince = 0
					}
					_, err = writer.Write(byteBuff[:readSize])
					checkError(err)
				}

			}

			bar.Finish()

			fh.Close()

		}

	},
}

func init() {
	RootCmd.AddCommand(catCmd)
	catCmd.Flags().IntP("print-freq", "p", 1, "print frequency (-1 for print after parsing)")
	catCmd.Flags().IntP("buffsize", "b", 4096*2, "buffer size")
	catCmd.Flags().BoolP("lines", "L", false, "count lines instead of bytes")
	catCmd.Flags().IntP("total", "s", -1, "expected total bytes/lines")
}
<|endoftext|>