<commit_before>// Random odds and ends.

package fuse

import (
	"bytes"
	"encoding/binary"
	"os"
	"fmt"
	"log"
	"math"
	"regexp"
	"syscall"
	"unsafe"
	"io/ioutil"
)

// Make a temporary directory securely.
func MakeTempDir() string {
	nm, err := ioutil.TempDir("", "go-fuse");
	if err != nil {
		panic("TempDir() failed: " + err.String())
	}
	return nm
}

// Convert os.Error back to Errno based errors.
func OsErrorToFuseError(err os.Error) Status {
	if err != nil {
		asErrno, ok := err.(os.Errno)
		if ok {
			return Status(asErrno)
		}

		asSyscallErr, ok := err.(*os.SyscallError)
		if ok {
			return Status(asSyscallErr.Errno)
		}

		asPathErr, ok := err.(*os.PathError)
		if ok {
			return OsErrorToFuseError(asPathErr.Error)
		}

		asLinkErr, ok := err.(*os.LinkError)
		if ok {
			return OsErrorToFuseError(asLinkErr.Error)
		}

		// Should not happen.  Should we log an error somewhere?
		log.Println("can't convert error type:", err)
		return ENOSYS
	}
	return OK
}

func operationName(opcode uint32) string {
	switch opcode {
	case FUSE_LOOKUP:
		return "FUSE_LOOKUP"
	case FUSE_FORGET:
		return "FUSE_FORGET"
	case FUSE_GETATTR:
		return "FUSE_GETATTR"
	case FUSE_SETATTR:
		return "FUSE_SETATTR"
	case FUSE_READLINK:
		return "FUSE_READLINK"
	case FUSE_SYMLINK:
		return "FUSE_SYMLINK"
	case FUSE_MKNOD:
		return "FUSE_MKNOD"
	case FUSE_MKDIR:
		return "FUSE_MKDIR"
	case FUSE_UNLINK:
		return "FUSE_UNLINK"
	case FUSE_RMDIR:
		return "FUSE_RMDIR"
	case FUSE_RENAME:
		return "FUSE_RENAME"
	case FUSE_LINK:
		return "FUSE_LINK"
	case FUSE_OPEN:
		return "FUSE_OPEN"
	case FUSE_READ:
		return "FUSE_READ"
	case FUSE_WRITE:
		return "FUSE_WRITE"
	case FUSE_STATFS:
		return "FUSE_STATFS"
	case FUSE_RELEASE:
		return "FUSE_RELEASE"
	case FUSE_FSYNC:
		return "FUSE_FSYNC"
	case FUSE_SETXATTR:
		return "FUSE_SETXATTR"
	case FUSE_GETXATTR:
		return "FUSE_GETXATTR"
	case FUSE_LISTXATTR:
		return "FUSE_LISTXATTR"
	case FUSE_REMOVEXATTR:
		return "FUSE_REMOVEXATTR"
	case FUSE_FLUSH:
		return "FUSE_FLUSH"
	case FUSE_INIT:
		return "FUSE_INIT"
	case FUSE_OPENDIR:
		return "FUSE_OPENDIR"
	case FUSE_READDIR:
		return "FUSE_READDIR"
	case FUSE_RELEASEDIR:
		return "FUSE_RELEASEDIR"
	case FUSE_FSYNCDIR:
		return "FUSE_FSYNCDIR"
	case FUSE_GETLK:
		return "FUSE_GETLK"
	case FUSE_SETLK:
		return "FUSE_SETLK"
	case FUSE_SETLKW:
		return "FUSE_SETLKW"
	case FUSE_ACCESS:
		return "FUSE_ACCESS"
	case FUSE_CREATE:
		return "FUSE_CREATE"
	case FUSE_INTERRUPT:
		return "FUSE_INTERRUPT"
	case FUSE_BMAP:
		return "FUSE_BMAP"
	case FUSE_DESTROY:
		return "FUSE_DESTROY"
	case FUSE_IOCTL:
		return "FUSE_IOCTL"
	case FUSE_POLL:
		return "FUSE_POLL"
	}
	return "UNKNOWN"
}

func (code Status) String() string {
	if code == OK {
		return "OK"
	}
	return fmt.Sprintf("%d=%v", int(code), os.Errno(code))
}

func newInput(opcode uint32) Empty {
	switch opcode {
	case FUSE_FORGET:
		return new(ForgetIn)
	case FUSE_GETATTR:
		return new(GetAttrIn)
	case FUSE_MKNOD:
		return new(MknodIn)
	case FUSE_MKDIR:
		return new(MkdirIn)
	case FUSE_RENAME:
		return new(RenameIn)
	case FUSE_LINK:
		return new(LinkIn)
	case FUSE_SETATTR:
		return new(SetAttrIn)
	case FUSE_OPEN:
		return new(OpenIn)
	case FUSE_CREATE:
		return new(CreateIn)
	case FUSE_FLUSH:
		return new(FlushIn)
	case FUSE_RELEASE:
		return new(ReleaseIn)
	case FUSE_READ:
		return new(ReadIn)
	case FUSE_WRITE:
		return new(WriteIn)
	case FUSE_FSYNC:
		return new(FsyncIn)
	// case FUSE_GET/SETLK(W)
	case FUSE_ACCESS:
		return new(AccessIn)
	case FUSE_INIT:
		return new(InitIn)
	case FUSE_BMAP:
		return new(BmapIn)
	case FUSE_INTERRUPT:
		return new(InterruptIn)
	case FUSE_IOCTL:
		return new(IoctlIn)
	case FUSE_POLL:
		return new(PollIn)
	case FUSE_SETXATTR:
		return new(SetXAttrIn)
	case FUSE_GETXATTR:
		return new(GetXAttrIn)
	case FUSE_OPENDIR:
		return new(OpenIn)
	case FUSE_FSYNCDIR:
		return new(FsyncIn)
	case FUSE_READDIR:
		return new(ReadIn)
	case FUSE_RELEASEDIR:
		return new(ReleaseIn)

	}
	return nil
}

func parseLittleEndian(b *bytes.Buffer, data interface{}) bool {
	err := binary.Read(b, binary.LittleEndian, data)
	if err == nil {
		return true
	}
	if err == os.EOF {
		return false
	}
	panic(fmt.Sprintf("Cannot parse %v", data))
}

func SplitNs(time float64, secs *uint64, nsecs *uint32) {
	*nsecs = uint32(1e9 * (time - math.Trunc(time)))
	*secs = uint64(math.Trunc(time))
}

func CopyFileInfo(fi *os.FileInfo, attr *Attr) {
	attr.Ino = uint64(fi.Ino)
	attr.Size = uint64(fi.Size)
	attr.Blocks = uint64(fi.Blocks)

	attr.Atime = uint64(fi.Atime_ns / 1e9)
	attr.Atimensec = uint32(fi.Atime_ns % 1e9)

	attr.Mtime = uint64(fi.Mtime_ns / 1e9)
	attr.Mtimensec = uint32(fi.Mtime_ns % 1e9)

	attr.Ctime = uint64(fi.Ctime_ns / 1e9)
	attr.Ctimensec = uint32(fi.Ctime_ns % 1e9)

	attr.Mode = fi.Mode
	attr.Nlink = uint32(fi.Nlink)
	attr.Uid = uint32(fi.Uid)
	attr.Gid = uint32(fi.Gid)
	attr.Rdev = uint32(fi.Rdev)
	attr.Blksize = uint32(fi.Blksize)
}

func writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, errno int) {
	n1, _, e1 := syscall.Syscall(
		syscall.SYS_WRITEV,
		uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
	return int(n1), int(e1)
}

func Writev(fd int, packet [][]byte) (n int, err os.Error) {
	iovecs := make([]syscall.Iovec, 0, len(packet))

	for _, v := range packet {
		if v == nil || len(v) == 0 {
			continue
		}
		vec := syscall.Iovec{
		Base: &v[0],
		}
		vec.SetLen(len(v))
		iovecs = append(iovecs, vec)
	}

	if len(iovecs) == 0 {
		return 0, nil
	}

	n, errno := writev(fd, &iovecs[0], len(iovecs))
	if errno != 0 {
		err = os.NewSyscallError("writev", errno)
	}
	return n, err
}

func CountCpus() int {
	var contents [10240]byte

	f, err := os.Open("/proc/stat", os.O_RDONLY, 0)
	defer f.Close()
	if err != nil {
		return 1
	}
	n, _ := f.Read(contents[:])
	re, _ := regexp.Compile("\ncpu[0-9]")

	return len(re.FindAllString(string(contents[:n]), 100))
}

// Creates a return entry for a non-existent path.
func NegativeEntry(time float64) *EntryOut {
	out := new(EntryOut)
	out.NodeId = 0
	SplitNs(time, &out.EntryValid, &out.EntryValidNsec)
	return out
}

func ModeToType(mode uint32) uint32 {
	return (mode & 0170000) >> 12
}

func CheckSuccess(e os.Error) {
	if e != nil {
		panic(fmt.Sprintf("Unexpected error: %v", e))
	}
}

<commit_msg>Implement PrintMap() centrally.<commit_after>// Random odds and ends.

package fuse

import (
	"bytes"
	"encoding/binary"
	"os"
	"fmt"
	"log"
	"math"
	"regexp"
	"sort"
	"syscall"
	"unsafe"
	"io/ioutil"
)

// Make a temporary directory securely.
func MakeTempDir() string {
	nm, err := ioutil.TempDir("", "go-fuse");
	if err != nil {
		panic("TempDir() failed: " + err.String())
	}
	return nm
}

// Convert os.Error back to Errno based errors.
func OsErrorToFuseError(err os.Error) Status {
	if err != nil {
		asErrno, ok := err.(os.Errno)
		if ok {
			return Status(asErrno)
		}

		asSyscallErr, ok := err.(*os.SyscallError)
		if ok {
			return Status(asSyscallErr.Errno)
		}

		asPathErr, ok := err.(*os.PathError)
		if ok {
			return OsErrorToFuseError(asPathErr.Error)
		}

		asLinkErr, ok := err.(*os.LinkError)
		if ok {
			return OsErrorToFuseError(asLinkErr.Error)
		}

		// Should not happen.  Should we log an error somewhere?
		log.Println("can't convert error type:", err)
		return ENOSYS
	}
	return OK
}

func operationName(opcode uint32) string {
	switch opcode {
	case FUSE_LOOKUP:
		return "FUSE_LOOKUP"
	case FUSE_FORGET:
		return "FUSE_FORGET"
	case FUSE_GETATTR:
		return "FUSE_GETATTR"
	case FUSE_SETATTR:
		return "FUSE_SETATTR"
	case FUSE_READLINK:
		return "FUSE_READLINK"
	case FUSE_SYMLINK:
		return "FUSE_SYMLINK"
	case FUSE_MKNOD:
		return "FUSE_MKNOD"
	case FUSE_MKDIR:
		return "FUSE_MKDIR"
	case FUSE_UNLINK:
		return "FUSE_UNLINK"
	case FUSE_RMDIR:
		return "FUSE_RMDIR"
	case FUSE_RENAME:
		return "FUSE_RENAME"
	case FUSE_LINK:
		return "FUSE_LINK"
	case FUSE_OPEN:
		return "FUSE_OPEN"
	case FUSE_READ:
		return "FUSE_READ"
	case FUSE_WRITE:
		return "FUSE_WRITE"
	case FUSE_STATFS:
		return "FUSE_STATFS"
	case FUSE_RELEASE:
		return "FUSE_RELEASE"
	case FUSE_FSYNC:
		return "FUSE_FSYNC"
	case FUSE_SETXATTR:
		return "FUSE_SETXATTR"
	case FUSE_GETXATTR:
		return "FUSE_GETXATTR"
	case FUSE_LISTXATTR:
		return "FUSE_LISTXATTR"
	case FUSE_REMOVEXATTR:
		return "FUSE_REMOVEXATTR"
	case FUSE_FLUSH:
		return "FUSE_FLUSH"
	case FUSE_INIT:
		return "FUSE_INIT"
	case FUSE_OPENDIR:
		return "FUSE_OPENDIR"
	case FUSE_READDIR:
		return "FUSE_READDIR"
	case FUSE_RELEASEDIR:
		return "FUSE_RELEASEDIR"
	case FUSE_FSYNCDIR:
		return "FUSE_FSYNCDIR"
	case FUSE_GETLK:
		return "FUSE_GETLK"
	case FUSE_SETLK:
		return "FUSE_SETLK"
	case FUSE_SETLKW:
		return "FUSE_SETLKW"
	case FUSE_ACCESS:
		return "FUSE_ACCESS"
	case FUSE_CREATE:
		return "FUSE_CREATE"
	case FUSE_INTERRUPT:
		return "FUSE_INTERRUPT"
	case FUSE_BMAP:
		return "FUSE_BMAP"
	case FUSE_DESTROY:
		return "FUSE_DESTROY"
	case FUSE_IOCTL:
		return "FUSE_IOCTL"
	case FUSE_POLL:
		return "FUSE_POLL"
	}
	return "UNKNOWN"
}

func (code Status) String() string {
	if code == OK {
		return "OK"
	}
	return fmt.Sprintf("%d=%v", int(code), os.Errno(code))
}

func newInput(opcode uint32) Empty {
	switch opcode {
	case FUSE_FORGET:
		return new(ForgetIn)
	case FUSE_GETATTR:
		return new(GetAttrIn)
	case FUSE_MKNOD:
		return new(MknodIn)
	case FUSE_MKDIR:
		return new(MkdirIn)
	case FUSE_RENAME:
		return new(RenameIn)
	case FUSE_LINK:
		return new(LinkIn)
	case FUSE_SETATTR:
		return new(SetAttrIn)
	case FUSE_OPEN:
		return new(OpenIn)
	case FUSE_CREATE:
		return new(CreateIn)
	case FUSE_FLUSH:
		return new(FlushIn)
	case FUSE_RELEASE:
		return new(ReleaseIn)
	case FUSE_READ:
		return new(ReadIn)
	case FUSE_WRITE:
		return new(WriteIn)
	case FUSE_FSYNC:
		return new(FsyncIn)
	// case FUSE_GET/SETLK(W)
	case FUSE_ACCESS:
		return new(AccessIn)
	case FUSE_INIT:
		return new(InitIn)
	case FUSE_BMAP:
		return new(BmapIn)
	case FUSE_INTERRUPT:
		return new(InterruptIn)
	case FUSE_IOCTL:
		return new(IoctlIn)
	case FUSE_POLL:
		return new(PollIn)
	case FUSE_SETXATTR:
		return new(SetXAttrIn)
	case FUSE_GETXATTR:
		return new(GetXAttrIn)
	case FUSE_OPENDIR:
		return new(OpenIn)
	case FUSE_FSYNCDIR:
		return new(FsyncIn)
	case FUSE_READDIR:
		return new(ReadIn)
	case FUSE_RELEASEDIR:
		return new(ReleaseIn)

	}
	return nil
}

func parseLittleEndian(b *bytes.Buffer, data interface{}) bool {
	err := binary.Read(b, binary.LittleEndian, data)
	if err == nil {
		return true
	}
	if err == os.EOF {
		return false
	}
	panic(fmt.Sprintf("Cannot parse %v", data))
}

func SplitNs(time float64, secs *uint64, nsecs *uint32) {
	*nsecs = uint32(1e9 * (time - math.Trunc(time)))
	*secs = uint64(math.Trunc(time))
}

func CopyFileInfo(fi *os.FileInfo, attr *Attr) {
	attr.Ino = uint64(fi.Ino)
	attr.Size = uint64(fi.Size)
	attr.Blocks = uint64(fi.Blocks)

	attr.Atime = uint64(fi.Atime_ns / 1e9)
	attr.Atimensec = uint32(fi.Atime_ns % 1e9)

	attr.Mtime = uint64(fi.Mtime_ns / 1e9)
	attr.Mtimensec = uint32(fi.Mtime_ns % 1e9)

	attr.Ctime = uint64(fi.Ctime_ns / 1e9)
	attr.Ctimensec = uint32(fi.Ctime_ns % 1e9)

	attr.Mode = fi.Mode
	attr.Nlink = uint32(fi.Nlink)
	attr.Uid = uint32(fi.Uid)
	attr.Gid = uint32(fi.Gid)
	attr.Rdev = uint32(fi.Rdev)
	attr.Blksize = uint32(fi.Blksize)
}

func writev(fd int, iovecs *syscall.Iovec, cnt int) (n int, errno int) {
	n1, _, e1 := syscall.Syscall(
		syscall.SYS_WRITEV,
		uintptr(fd), uintptr(unsafe.Pointer(iovecs)), uintptr(cnt))
	return int(n1), int(e1)
}

func Writev(fd int, packet [][]byte) (n int, err os.Error) {
	iovecs := make([]syscall.Iovec, 0, len(packet))

	for _, v := range packet {
		if v == nil || len(v) == 0 {
			continue
		}
		vec := syscall.Iovec{
		Base: &v[0],
		}
		vec.SetLen(len(v))
		iovecs = append(iovecs, vec)
	}

	if len(iovecs) == 0 {
		return 0, nil
	}

	n, errno := writev(fd, &iovecs[0], len(iovecs))
	if errno != 0 {
		err = os.NewSyscallError("writev", errno)
	}
	return n, err
}

func CountCpus() int {
	var contents [10240]byte

	f, err := os.Open("/proc/stat", os.O_RDONLY, 0)
	defer f.Close()
	if err != nil {
		return 1
	}
	n, _ := f.Read(contents[:])
	re, _ := regexp.Compile("\ncpu[0-9]")

	return len(re.FindAllString(string(contents[:n]), 100))
}

// Creates a return entry for a non-existent path.
func NegativeEntry(time float64) *EntryOut {
	out := new(EntryOut)
	out.NodeId = 0
	SplitNs(time, &out.EntryValid, &out.EntryValidNsec)
	return out
}

func ModeToType(mode uint32) uint32 {
	return (mode & 0170000) >> 12
}

func CheckSuccess(e os.Error) {
	if e != nil {
		panic(fmt.Sprintf("Unexpected error: %v", e))
	}
}

// For printing latency data.
func PrintMap(m map[string]float64)  {
	keys := make([]string, len(m))
	for k, _ := range m {
		keys = append(keys, k)
	}

	sort.SortStrings(keys)
	for _, k := range keys {
		if m[k] > 0 {
			fmt.Println(k, m[k])
		}
	}
}

func MyPID() string {
	v, _ := os.Readlink("/proc/self")
	return v
}
<|endoftext|>


<commit_before>// Copyright 2017 Stratumn SAS. All rights reserved.
//
// 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 blockcypher defines primitives to work with the BlockCypher API.
package blockcypher

import (
	"context"
	"encoding/hex"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/blockcypher/gobcy"
	"github.com/btcsuite/btcutil/base58"
	"github.com/stratumn/go-core/blockchain/btc"
	"github.com/stratumn/go-core/types"
)

const (
	// DefaultLimiterInterval is the default BlockCypher API limiter
	// interval.
	DefaultLimiterInterval = time.Minute

	// DefaultLimiterSize is the default BlockCypher API limiter size.
	DefaultLimiterSize = 2
)

// Config contains configuration options for the client.
type Config struct {
	// Network is the Bitcoin network.
	Network btc.Network

	// APIKey is an optional BlockCypher API key.
	APIKey string

	// LimiterInterval is the BlockCypher API limiter interval.
	LimiterInterval time.Duration

	// LimiterSize is the BlockCypher API limiter size.
	LimiterSize int
}

// Client is a BlockCypher API client.
type Client struct {
	config    *Config
	api       *gobcy.API
	limiter   chan struct{}
	timer     *time.Timer
	waitGroup sync.WaitGroup
}

// New creates a client for a Bitcoin network, using an optional BlockCypher API
// key.
func New(c *Config) *Client {
	parts := strings.Split(c.Network.String(), ":")
	size := c.LimiterSize
	if size == 0 {
		size = DefaultLimiterSize
	}
	limiter := make(chan struct{}, size)

	return &Client{
		config:  c,
		api:     &gobcy.API{Token: c.APIKey, Coin: "btc", Chain: parts[1]},
		limiter: limiter,
	}
}

// FindUnspent implements
// github.com/stratumn/go-core/blockchain/btc.UnspentFinder.FindUnspent.
func (c *Client) FindUnspent(address *types.ReversedBytes20, amount int64) (res btc.UnspentResult, err error) {
	for range c.limiter {
		break
	}
	c.waitGroup.Add(1)
	defer c.waitGroup.Done()

	addr := base58.CheckEncode(address[:], c.config.Network.ID())
	addrInfo, err := c.api.GetAddr(addr, map[string]string{
		"unspentOnly":   "true",
		"includeScript": "true",
		"limit":         "50",
	})
	if err != nil {
		return
	}

	for _, TXRef := range addrInfo.TXRefs {
		output := btc.Output{Index: TXRef.TXOutputN}

		if err = output.TXHash.Unstring(TXRef.TXHash); err != nil {
			return
		}

		output.PKScript, err = hex.DecodeString(TXRef.Script)
		if err != nil {
			return
		}

		res.Total += int64(TXRef.Value)

		if res.Sum < amount {
			res.Outputs = append(res.Outputs, output)
			res.Sum += int64(TXRef.Value)

		}
	}

	if res.Sum < amount {
		err = fmt.Errorf(
			"not enough Bitcoins available on %s, expected at least %d satoshis got %d",
			addr,
			amount,
			res.Sum,
		)
	}

	return
}

// Broadcast implements
// github.com/stratumn/go-core/blockchain/btc.Broadcaster.Broadcast.
func (c *Client) Broadcast(raw []byte) error {
	for range c.limiter {
		break
	}
	c.waitGroup.Add(1)
	defer c.waitGroup.Done()

	_, err := c.api.PushTX(hex.EncodeToString(raw))
	return err
}

// Start starts the client.
func (c *Client) Start(ctx context.Context) {
	size := c.config.LimiterSize
	if size == 0 {
		size = DefaultLimiterSize
	}
	for i := 0; i < size; i++ {
		c.limiter <- struct{}{}
	}

	interval := c.config.LimiterInterval
	if interval == 0 {
		interval = DefaultLimiterInterval
	}

	c.timer = time.NewTimer(interval)

	for {
		select {
		case <-c.timer.C:
			c.timer = time.NewTimer(interval)
			c.limiter <- struct{}{}
		case <-ctx.Done():
			c.stop()
			return
		}

	}
}

// stop stops the client.
func (c *Client) stop() {
	if !c.timer.Stop() {
		<-c.timer.C
	}

	c.waitGroup.Wait()
	<-c.limiter
	close(c.limiter)
}
<commit_msg>btc: simplify balance calculation<commit_after>// Copyright 2017 Stratumn SAS. All rights reserved.
//
// 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 blockcypher defines primitives to work with the BlockCypher API.
package blockcypher

import (
	"context"
	"encoding/hex"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/blockcypher/gobcy"
	"github.com/btcsuite/btcutil/base58"
	"github.com/stratumn/go-core/blockchain/btc"
	"github.com/stratumn/go-core/types"
)

const (
	// DefaultLimiterInterval is the default BlockCypher API limiter
	// interval.
	DefaultLimiterInterval = time.Minute

	// DefaultLimiterSize is the default BlockCypher API limiter size.
	DefaultLimiterSize = 2
)

// Config contains configuration options for the client.
type Config struct {
	// Network is the Bitcoin network.
	Network btc.Network

	// APIKey is an optional BlockCypher API key.
	APIKey string

	// LimiterInterval is the BlockCypher API limiter interval.
	LimiterInterval time.Duration

	// LimiterSize is the BlockCypher API limiter size.
	LimiterSize int
}

// Client is a BlockCypher API client.
type Client struct {
	config    *Config
	api       *gobcy.API
	limiter   chan struct{}
	timer     *time.Timer
	waitGroup sync.WaitGroup
}

// New creates a client for a Bitcoin network, using an optional BlockCypher API
// key.
func New(c *Config) *Client {
	parts := strings.Split(c.Network.String(), ":")
	size := c.LimiterSize
	if size == 0 {
		size = DefaultLimiterSize
	}
	limiter := make(chan struct{}, size)

	return &Client{
		config:  c,
		api:     &gobcy.API{Token: c.APIKey, Coin: "btc", Chain: parts[1]},
		limiter: limiter,
	}
}

// FindUnspent implements
// github.com/stratumn/go-core/blockchain/btc.UnspentFinder.FindUnspent.
func (c *Client) FindUnspent(address *types.ReversedBytes20, amount int64) (res btc.UnspentResult, err error) {
	for range c.limiter {
		break
	}
	c.waitGroup.Add(1)
	defer c.waitGroup.Done()

	addr := base58.CheckEncode(address[:], c.config.Network.ID())
	addrInfo, err := c.api.GetAddr(addr, map[string]string{
		"unspentOnly":   "true",
		"includeScript": "true",
		"limit":         "50",
	})
	if err != nil {
		return
	}

	res.Total = int64(addrInfo.Balance)

	for _, TXRef := range addrInfo.TXRefs {
		output := btc.Output{Index: TXRef.TXOutputN}

		if err = output.TXHash.Unstring(TXRef.TXHash); err != nil {
			return
		}

		output.PKScript, err = hex.DecodeString(TXRef.Script)
		if err != nil {
			return
		}

		res.Outputs = append(res.Outputs, output)
		res.Sum += int64(TXRef.Value)

		if res.Sum >= amount {
			return
		}
	}

	err = fmt.Errorf(
		"not enough Bitcoins available on %s, expected at least %d satoshis got %d",
		addr,
		amount,
		res.Sum,
	)

	return
}

// Broadcast implements
// github.com/stratumn/go-core/blockchain/btc.Broadcaster.Broadcast.
func (c *Client) Broadcast(raw []byte) error {
	for range c.limiter {
		break
	}
	c.waitGroup.Add(1)
	defer c.waitGroup.Done()

	_, err := c.api.PushTX(hex.EncodeToString(raw))
	return err
}

// Start starts the client.
func (c *Client) Start(ctx context.Context) {
	size := c.config.LimiterSize
	if size == 0 {
		size = DefaultLimiterSize
	}
	for i := 0; i < size; i++ {
		c.limiter <- struct{}{}
	}

	interval := c.config.LimiterInterval
	if interval == 0 {
		interval = DefaultLimiterInterval
	}

	c.timer = time.NewTimer(interval)

	for {
		select {
		case <-c.timer.C:
			c.timer = time.NewTimer(interval)
			c.limiter <- struct{}{}
		case <-ctx.Done():
			c.stop()
			return
		}

	}
}

// stop stops the client.
func (c *Client) stop() {
	if !c.timer.Stop() {
		<-c.timer.C
	}

	c.waitGroup.Wait()
	<-c.limiter
	close(c.limiter)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 fuse

import (
	"fmt"
	"io/ioutil"
	"log"
	"runtime"

	"github.com/jacobsa/bazilfuse"
	"golang.org/x/net/context"
)

// A type that knows how to serve ops read from a connection.
type Server interface {
	// Read and serve ops from the supplied connection until EOF. Do not return
	// until all operations have been responded to. Must not be called more than
	// once.
	ServeOps(*Connection)
}

// A struct representing the status of a mount operation, with a method that
// waits for unmounting.
type MountedFileSystem struct {
	dir string

	// The result to return from Join. Not valid until the channel is closed.
	joinStatus          error
	joinStatusAvailable chan struct{}
}

// Return the directory on which the file system is mounted (or where we
// attempted to mount it.)
func (mfs *MountedFileSystem) Dir() string {
	return mfs.dir
}

// Block until a mounted file system has been unmounted. Do not return
// successfully until all ops read from the connection have been responded to
// (i.e. the file system server has finished processing all in-flight ops).
//
// The return value will be non-nil if anything unexpected happened while
// serving. May be called multiple times.
func (mfs *MountedFileSystem) Join(ctx context.Context) error {
	select {
	case <-mfs.joinStatusAvailable:
		return mfs.joinStatus
	case <-ctx.Done():
		return ctx.Err()
	}
}

// Optional configuration accepted by Mount.
type MountConfig struct {
	// The context from which every op read from the connetion by the sever
	// should inherit. If nil, context.Background() will be used.
	OpContext context.Context

	// If non-empty, the name of the file system as displayed by e.g. `mount`.
	// This is important because the `umount` command requires root privileges if
	// it doesn't agree with /etc/fstab.
	FSName string

	// Mount the file system in read-only mode. File modes will appear as normal,
	// but opening a file for writing and metadata operations like chmod,
	// chtimes, etc. will fail.
	ReadOnly bool

	// A logger to use for logging errors. All errors are logged, with the
	// exception of a few blacklisted errors that are expected. If nil, no error
	// logging is performed.
	ErrorLogger *log.Logger

	// OS X only.
	//
	// Normally on OS X we mount with the novncache option
	// (cf. http://goo.gl/1pTjuk), which disables entry caching in the kernel.
	// This is because osxfuse does not honor the entry expiration values we
	// return to it, instead caching potentially forever (cf.
	// http://goo.gl/8yR0Ie), and it is probably better to fail to cache than to
	// cache for too long, since the latter is more likely to hide consistency
	// bugs that are difficult to detect and diagnose.
	//
	// This field disables the use of novncache, restoring entry caching. Beware:
	// the value of ChildInodeEntry.EntryExpiration is ignored by the kernel, and
	// entries will be cached for an arbitrarily long time.
	EnableVnodeCaching bool

	// Additional key=value options to pass unadulterated to the underlying mount
	// command. See `man 8 mount`, the fuse documentation, etc. for
	// system-specific information.
	//
	// For expert use only! May invalidate other guarantees made in the
	// documentation for this package.
	Options map[string]string
}

// Convert to mount options to be passed to package bazilfuse.
func (c *MountConfig) bazilfuseOptions() (opts []bazilfuse.MountOption) {
	isDarwin := runtime.GOOS == "darwin"

	// Enable permissions checking in the kernel. See the comments on
	// InodeAttributes.Mode.
	opts = append(opts, bazilfuse.SetOption("default_permissions", ""))

	// HACK(jacobsa): Work around what appears to be a bug in systemd v219, as
	// shipped in Ubuntu 15.04, where it automatically unmounts any file system
	// that doesn't set an explicit name.
	//
	// When Ubuntu contains systemd v220, this workaround should be removed and
	// the systemd bug reopened if the problem persists.
	//
	// Cf. https://github.com/bazil/fuse/issues/89
	// Cf. https://bugs.freedesktop.org/show_bug.cgi?id=90907
	fsname := c.FSName
	if runtime.GOOS == "linux" && fsname == "" {
		fsname = "some_fuse_file_system"
	}

	// Special file system name?
	if fsname != "" {
		opts = append(opts, bazilfuse.FSName(fsname))
	}

	// Read only?
	if c.ReadOnly {
		opts = append(opts, bazilfuse.ReadOnly())
	}

	// OS X: set novncache when appropriate.
	if isDarwin && !c.EnableVnodeCaching {
		opts = append(opts, bazilfuse.SetOption("novncache", ""))
	}

	// OS X: disable the use of "Apple Double" (._foo and .DS_Store) files, which
	// just add noise to debug output and can have significant cost on
	// network-based file systems.
	//
	// Cf. https://github.com/osxfuse/osxfuse/wiki/Mount-options
	if isDarwin {
		opts = append(opts, bazilfuse.SetOption("noappledouble", ""))
	}

	// Last but not least: other user-supplied options.
	for k, v := range c.Options {
		opts = append(opts, bazilfuse.SetOption(k, v))
	}

	return
}

// Attempt to mount a file system on the given directory, using the supplied
// Server to serve connection requests. This function blocks until the file
// system is successfully mounted. On some systems, this requires the supplied
// Server to make forward progress (in particular, to respond to
// fuseops.InitOp).
func Mount(
	dir string,
	server Server,
	config *MountConfig) (mfs *MountedFileSystem, err error) {
	debugLogger := getDebugLogger()

	// Initialize the struct.
	mfs = &MountedFileSystem{
		dir:                 dir,
		joinStatusAvailable: make(chan struct{}),
	}

	// Open a bazilfuse connection.
	debugLogger.Println("Opening a bazilfuse connection.")
	bfConn, err := bazilfuse.Mount(mfs.dir, config.bazilfuseOptions()...)
	if err != nil {
		err = fmt.Errorf("bazilfuse.Mount: %v", err)
		return
	}

	// Choose a parent context for ops.
	opContext := config.OpContext
	if opContext == nil {
		opContext = context.Background()
	}

	// Create a /dev/null error logger if necessary.
	errorLogger := config.ErrorLogger
	if errorLogger == nil {
		errorLogger = log.New(ioutil.Discard, "", 0)
	}

	// Create our own Connection object wrapping it.
	connection, err := newConnection(
		opContext,
		debugLogger,
		errorLogger,
		bfConn)

	if err != nil {
		bfConn.Close()
		err = fmt.Errorf("newConnection: %v", err)
		return
	}

	// Serve the connection in the background. When done, set the join status.
	go func() {
		server.ServeOps(connection)
		mfs.joinStatus = connection.close()
		close(mfs.joinStatusAvailable)
	}()

	// Wait for the connection to say it is ready.
	if err = connection.waitForReady(); err != nil {
		err = fmt.Errorf("WaitForReady: %v", err)
		return
	}

	return
}
<commit_msg>Set max readahead to a large value when mounting.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 fuse

import (
	"fmt"
	"io/ioutil"
	"log"
	"runtime"

	"github.com/jacobsa/bazilfuse"
	"golang.org/x/net/context"
)

// A type that knows how to serve ops read from a connection.
type Server interface {
	// Read and serve ops from the supplied connection until EOF. Do not return
	// until all operations have been responded to. Must not be called more than
	// once.
	ServeOps(*Connection)
}

// A struct representing the status of a mount operation, with a method that
// waits for unmounting.
type MountedFileSystem struct {
	dir string

	// The result to return from Join. Not valid until the channel is closed.
	joinStatus          error
	joinStatusAvailable chan struct{}
}

// Return the directory on which the file system is mounted (or where we
// attempted to mount it.)
func (mfs *MountedFileSystem) Dir() string {
	return mfs.dir
}

// Block until a mounted file system has been unmounted. Do not return
// successfully until all ops read from the connection have been responded to
// (i.e. the file system server has finished processing all in-flight ops).
//
// The return value will be non-nil if anything unexpected happened while
// serving. May be called multiple times.
func (mfs *MountedFileSystem) Join(ctx context.Context) error {
	select {
	case <-mfs.joinStatusAvailable:
		return mfs.joinStatus
	case <-ctx.Done():
		return ctx.Err()
	}
}

// Optional configuration accepted by Mount.
type MountConfig struct {
	// The context from which every op read from the connetion by the sever
	// should inherit. If nil, context.Background() will be used.
	OpContext context.Context

	// If non-empty, the name of the file system as displayed by e.g. `mount`.
	// This is important because the `umount` command requires root privileges if
	// it doesn't agree with /etc/fstab.
	FSName string

	// Mount the file system in read-only mode. File modes will appear as normal,
	// but opening a file for writing and metadata operations like chmod,
	// chtimes, etc. will fail.
	ReadOnly bool

	// A logger to use for logging errors. All errors are logged, with the
	// exception of a few blacklisted errors that are expected. If nil, no error
	// logging is performed.
	ErrorLogger *log.Logger

	// OS X only.
	//
	// Normally on OS X we mount with the novncache option
	// (cf. http://goo.gl/1pTjuk), which disables entry caching in the kernel.
	// This is because osxfuse does not honor the entry expiration values we
	// return to it, instead caching potentially forever (cf.
	// http://goo.gl/8yR0Ie), and it is probably better to fail to cache than to
	// cache for too long, since the latter is more likely to hide consistency
	// bugs that are difficult to detect and diagnose.
	//
	// This field disables the use of novncache, restoring entry caching. Beware:
	// the value of ChildInodeEntry.EntryExpiration is ignored by the kernel, and
	// entries will be cached for an arbitrarily long time.
	EnableVnodeCaching bool

	// Additional key=value options to pass unadulterated to the underlying mount
	// command. See `man 8 mount`, the fuse documentation, etc. for
	// system-specific information.
	//
	// For expert use only! May invalidate other guarantees made in the
	// documentation for this package.
	Options map[string]string
}

// Convert to mount options to be passed to package bazilfuse.
func (c *MountConfig) bazilfuseOptions() (opts []bazilfuse.MountOption) {
	isDarwin := runtime.GOOS == "darwin"

	// Enable permissions checking in the kernel. See the comments on
	// InodeAttributes.Mode.
	opts = append(opts, bazilfuse.SetOption("default_permissions", ""))

	// HACK(jacobsa): Work around what appears to be a bug in systemd v219, as
	// shipped in Ubuntu 15.04, where it automatically unmounts any file system
	// that doesn't set an explicit name.
	//
	// When Ubuntu contains systemd v220, this workaround should be removed and
	// the systemd bug reopened if the problem persists.
	//
	// Cf. https://github.com/bazil/fuse/issues/89
	// Cf. https://bugs.freedesktop.org/show_bug.cgi?id=90907
	fsname := c.FSName
	if runtime.GOOS == "linux" && fsname == "" {
		fsname = "some_fuse_file_system"
	}

	// Special file system name?
	if fsname != "" {
		opts = append(opts, bazilfuse.FSName(fsname))
	}

	// Read only?
	if c.ReadOnly {
		opts = append(opts, bazilfuse.ReadOnly())
	}

	// OS X: set novncache when appropriate.
	if isDarwin && !c.EnableVnodeCaching {
		opts = append(opts, bazilfuse.SetOption("novncache", ""))
	}

	// OS X: disable the use of "Apple Double" (._foo and .DS_Store) files, which
	// just add noise to debug output and can have significant cost on
	// network-based file systems.
	//
	// Cf. https://github.com/osxfuse/osxfuse/wiki/Mount-options
	if isDarwin {
		opts = append(opts, bazilfuse.SetOption("noappledouble", ""))
	}

	// Ask the Linux kernel for larger read requests.
	//
	// As of 2015-03-26, the behavior in the kernel is:
	//
	//  *  (http://goo.gl/bQ1f1i, http://goo.gl/HwBrR6) Set the local variable
	//     ra_pages to be init_response->max_readahead divided by the page size.
	//
	//  *  (http://goo.gl/gcIsSh, http://goo.gl/LKV2vA) Set
	//     backing_dev_info::ra_pages to the min of that value and what was sent
	//     in the request's max_readahead field.
	//
	//  *  (http://goo.gl/u2SqzH) Use backing_dev_info::ra_pages when deciding
	//     how much to read ahead.
	//
	//  *  (http://goo.gl/JnhbdL) Don't read ahead at all if that field is zero.
	//
	// Reading a page at a time is a drag. Ask for a larger size.
	const maxReadahead = 1 << 20
	opts = append(opts, bazilfuse.MaxReadahead(maxReadahead))

	// Last but not least: other user-supplied options.
	for k, v := range c.Options {
		opts = append(opts, bazilfuse.SetOption(k, v))
	}

	return
}

// Attempt to mount a file system on the given directory, using the supplied
// Server to serve connection requests. This function blocks until the file
// system is successfully mounted. On some systems, this requires the supplied
// Server to make forward progress (in particular, to respond to
// fuseops.InitOp).
func Mount(
	dir string,
	server Server,
	config *MountConfig) (mfs *MountedFileSystem, err error) {
	debugLogger := getDebugLogger()

	// Initialize the struct.
	mfs = &MountedFileSystem{
		dir:                 dir,
		joinStatusAvailable: make(chan struct{}),
	}

	// Open a bazilfuse connection.
	debugLogger.Println("Opening a bazilfuse connection.")
	bfConn, err := bazilfuse.Mount(mfs.dir, config.bazilfuseOptions()...)
	if err != nil {
		err = fmt.Errorf("bazilfuse.Mount: %v", err)
		return
	}

	// Choose a parent context for ops.
	opContext := config.OpContext
	if opContext == nil {
		opContext = context.Background()
	}

	// Create a /dev/null error logger if necessary.
	errorLogger := config.ErrorLogger
	if errorLogger == nil {
		errorLogger = log.New(ioutil.Discard, "", 0)
	}

	// Create our own Connection object wrapping it.
	connection, err := newConnection(
		opContext,
		debugLogger,
		errorLogger,
		bfConn)

	if err != nil {
		bfConn.Close()
		err = fmt.Errorf("newConnection: %v", err)
		return
	}

	// Serve the connection in the background. When done, set the join status.
	go func() {
		server.ServeOps(connection)
		mfs.joinStatus = connection.close()
		close(mfs.joinStatusAvailable)
	}()

	// Wait for the connection to say it is ready.
	if err = connection.waitForReady(); err != nil {
		err = fmt.Errorf("WaitForReady: %v", err)
		return
	}

	return
}
<|endoftext|>


<commit_before>package moxxiConf

import (
	"errors"
	"github.com/stretchr/testify/assert"
	"testing"
)

func Err_Error_test(t *testing.T) {
	fakeError := errors.New("fake error")
	var testData = []struct {
		in  Err
		out string
	}{
		{
			Err{ErrCloseFile, "/tmp/testfile", fakeError},
			"failed to close the file [/tmp/testfile] - fake error",
		}, {
			Err{ErrRemoveFile, "/tmp/testfile", fakeError},
			"failed to remove file [/tmp/testfile] - fake error",
		}, {
			Err{ErrFilePerm, "/tmp/testfile", fakeError},
			"permission denied to create file [/tmp/testfile] - fake error",
		}, {
			Err{ErrFileUnexpect, "/tmp/testfile", fakeError},
			"unknown error with file [/tmp/testfile] - fake error",
		}, {
			Err{ErrBadHost, "/tmp/testfile", nil},
			"bad hostname provided [/tmp/testfile]",
		}, {
			Err{ErrFileUnexpect, "/tmp/testfile", nil},
			"bad IP provided [/tmp/testfile]",
		}, {
			Err{ErrFileUnexpect, "", nil},
			"was not given a new random domain - shutting down",
		},
	}
	for _, test := range testData{
		assert.Equal(t, test.out, test.in.Error(), "errors should match")
	}
}
<commit_msg>added a test for HandlerLocFlag<commit_after>package moxxiConf

import (
	"errors"
	"github.com/stretchr/testify/assert"
	"testing"
)

func Err_Error_test(t *testing.T) {
	fakeError := errors.New("fake error")
	var testData = []struct {
		in  Err
		out string
	}{
		{
			Err{ErrCloseFile, "/tmp/testfile", fakeError},
			"failed to close the file [/tmp/testfile] - fake error",
		}, {
			Err{ErrRemoveFile, "/tmp/testfile", fakeError},
			"failed to remove file [/tmp/testfile] - fake error",
		}, {
			Err{ErrFilePerm, "/tmp/testfile", fakeError},
			"permission denied to create file [/tmp/testfile] - fake error",
		}, {
			Err{ErrFileUnexpect, "/tmp/testfile", fakeError},
			"unknown error with file [/tmp/testfile] - fake error",
		}, {
			Err{ErrBadHost, "/tmp/testfile", nil},
			"bad hostname provided [/tmp/testfile]",
		}, {
			Err{ErrFileUnexpect, "/tmp/testfile", nil},
			"bad IP provided [/tmp/testfile]",
		}, {
			Err{ErrFileUnexpect, "", nil},
			"was not given a new random domain - shutting down",
		},
	}
	for _, test := range testData {
		assert.Equal(t, test.out, test.in.Error(), "errors should match")
	}
}

func HandlerLocFlag_test(t *testing.T) {
	var testData = []string{
		"one",
		"two",
		"three",
		"four",
	}

	var testWork HandlerLocFlag

	for _, each := range testData {
		assert.NoError(t, testWork.Set(each), "there should not have been a problem adding an item")
	}

	assert.Equal(t, testData, []string(testWork), "the test input and current value of the test should be equal")

	for i := 0; i < len(testData); i++ {
		assert.Equal(t, testData[i], testWork.GetOne(i), "the test input and current value of the test should be equal")
	}

}
<|endoftext|>


<commit_before>package zwave

import (
	"bytes"
	"encoding/binary"
	"errors"
)

type FrameHeader uint8
type FrameType uint8

const (
	FrameHeaderData   uint8 = 0x01
	FrameHeaderAck    uint8 = 0x06
	FrameHeaderNak    uint8 = 0x15
	FrameHeaderCancel uint8 = 0x18
)

const (
	FrameTypeReq uint8 = 0x00
	FrameTypeRes uint8 = 0x01
)

type ZFrame struct {

	// Header is one of FrameHeader*
	Header uint8

	// Length = byte length of all fields, excluding Header and Checksum
	Length uint8

	// Type is one of FrameType*
	Type uint8

	// Payload is the command id and command payload
	Payload []byte

	// Checksum = 0xff XOR Type XOR Length XOR payload[0] XOR [...payload[n]]
	Checksum uint8
}

func NewRequestFrame(payload []byte) *ZFrame {
	frame := ZFrame{
		Header:  FrameHeaderData,
		Type:    FrameTypeReq,
		Length:  uint8(len(payload) + 2), // payload length plus Type and Length
		Payload: payload,
	}

	frame.SetChecksum()

	return &frame
}

func NewNakFrame() *ZFrame {
	return &ZFrame{
		Header: FrameHeaderNak,
	}
}

func NewAckFrame() *ZFrame {
	return &ZFrame{
		Header: FrameHeaderAck,
	}
}

func NewCanFrame() *ZFrame {
	return &ZFrame{
		Header: FrameHeaderCancel,
	}
}

func (z *ZFrame) IsRequest() bool {
	return z.Type == FrameTypeReq
}

func (z *ZFrame) IsResponse() bool {
	return z.Type == FrameTypeRes
}

func (z *ZFrame) IsAck() bool {
	return z.Header == FrameHeaderAck
}

// CalcChecksum calculates the checksum for this frame, given the current data.
// The Z-Wave checksum is calculated by taking 0xFF XOR Length XOR Type XOR Payload[0:n]
func (z *ZFrame) CalcChecksum() uint8 {
	var csum uint8 = 0xff
	csum ^= z.Length
	csum ^= z.Type

	for i := 0; i < len(z.Payload); i++ {
		csum ^= z.Payload[i]
	}

	return csum
}

// SetChecksum calculates the frame checksum and saves it into the frame
func (z *ZFrame) SetChecksum() {
	z.Checksum = z.CalcChecksum()
}

// VerifyChecksum calculates a checksum for the frame and compares it to the
// frame's checksum, returning an error if they do not agree
func (z *ZFrame) VerifyChecksum() error {
	if z.Checksum != z.CalcChecksum() {
		return errors.New("Invalid checksum")
	}

	return nil
}

// Marshal this frame into a byte slice
func (z *ZFrame) Marshal() []byte {
	buf := new(bytes.Buffer)

	switch z.Header {
	case FrameHeaderData:
		// Data frames have the whole kit and caboodle
		binary.Write(buf, binary.BigEndian, uint8(z.Header))
		binary.Write(buf, binary.BigEndian, uint8(z.Length))
		binary.Write(buf, binary.BigEndian, uint8(z.Type))
		buf.Write(z.Payload)
		binary.Write(buf, binary.BigEndian, uint8(z.Checksum))
	default:
		// Non-data frames are just a single byte
		binary.Write(buf, binary.BigEndian, uint8(z.Header))
	}

	return buf.Bytes()
}

// UnmarshalFrame turns a byte slice into a ZFrame
func UnmarshalFrame(frame []byte) *ZFrame {
	if frame[0] != FrameHeaderData {
		return &ZFrame{
			Header: frame[0],
		}
	}

	return &ZFrame{
		Header:   frame[0],
		Length:   frame[1],
		Type:     frame[2],
		Payload:  frame[3 : len(frame)-2],
		Checksum: frame[len(frame)-1],
	}
}
<commit_msg>if not a data frame, do not validate checksum<commit_after>package zwave

import (
	"bytes"
	"encoding/binary"
	"errors"
)

type FrameHeader uint8
type FrameType uint8

const (
	FrameHeaderData   uint8 = 0x01
	FrameHeaderAck    uint8 = 0x06
	FrameHeaderNak    uint8 = 0x15
	FrameHeaderCancel uint8 = 0x18
)

const (
	FrameTypeReq uint8 = 0x00
	FrameTypeRes uint8 = 0x01
)

type ZFrame struct {

	// Header is one of FrameHeader*
	Header uint8

	// Length = byte length of all fields, excluding Header and Checksum
	Length uint8

	// Type is one of FrameType*
	Type uint8

	// Payload is the command id and command payload
	Payload []byte

	// Checksum = 0xff XOR Type XOR Length XOR payload[0] XOR [...payload[n]]
	Checksum uint8
}

func NewRequestFrame(payload []byte) *ZFrame {
	frame := ZFrame{
		Header:  FrameHeaderData,
		Type:    FrameTypeReq,
		Length:  uint8(len(payload) + 2), // payload length plus Type and Length
		Payload: payload,
	}

	frame.SetChecksum()

	return &frame
}

func NewNakFrame() *ZFrame {
	return &ZFrame{
		Header: FrameHeaderNak,
	}
}

func NewAckFrame() *ZFrame {
	return &ZFrame{
		Header: FrameHeaderAck,
	}
}

func NewCanFrame() *ZFrame {
	return &ZFrame{
		Header: FrameHeaderCancel,
	}
}

func (z *ZFrame) IsRequest() bool {
	return z.Type == FrameTypeReq
}

func (z *ZFrame) IsResponse() bool {
	return z.Type == FrameTypeRes
}

func (z *ZFrame) IsAck() bool {
	return z.Header == FrameHeaderAck
}

// CalcChecksum calculates the checksum for this frame, given the current data.
// The Z-Wave checksum is calculated by taking 0xFF XOR Length XOR Type XOR Payload[0:n]
func (z *ZFrame) CalcChecksum() uint8 {
	var csum uint8 = 0xff
	csum ^= z.Length
	csum ^= z.Type

	for i := 0; i < len(z.Payload); i++ {
		csum ^= z.Payload[i]
	}

	return csum
}

// SetChecksum calculates the frame checksum and saves it into the frame
func (z *ZFrame) SetChecksum() {
	z.Checksum = z.CalcChecksum()
}

// VerifyChecksum calculates a checksum for the frame and compares it to the
// frame's checksum, returning an error if they do not agree
func (z *ZFrame) VerifyChecksum() error {
	if z.Header != FrameHeaderData {
		return nil
	}

	if z.Checksum != z.CalcChecksum() {
		return errors.New("Invalid checksum")
	}

	return nil
}

// Marshal this frame into a byte slice
func (z *ZFrame) Marshal() []byte {
	buf := new(bytes.Buffer)

	switch z.Header {
	case FrameHeaderData:
		// Data frames have the whole kit and caboodle
		binary.Write(buf, binary.BigEndian, uint8(z.Header))
		binary.Write(buf, binary.BigEndian, uint8(z.Length))
		binary.Write(buf, binary.BigEndian, uint8(z.Type))
		buf.Write(z.Payload)
		binary.Write(buf, binary.BigEndian, uint8(z.Checksum))
	default:
		// Non-data frames are just a single byte
		binary.Write(buf, binary.BigEndian, uint8(z.Header))
	}

	return buf.Bytes()
}

// UnmarshalFrame turns a byte slice into a ZFrame
func UnmarshalFrame(frame []byte) *ZFrame {
	if frame[0] != FrameHeaderData {
		return &ZFrame{
			Header: frame[0],
		}
	}

	return &ZFrame{
		Header:   frame[0],
		Length:   frame[1],
		Type:     frame[2],
		Payload:  frame[3 : len(frame)-2],
		Checksum: frame[len(frame)-1],
	}
}
<|endoftext|>


<commit_before>package postgis

import (
	"encoding/json"
	"fmt"

	"github.com/geodan/gost/src/sensorthings/entities"

	"database/sql"
	"errors"

	gostErrors "github.com/geodan/gost/src/errors"
	"github.com/geodan/gost/src/sensorthings/odata"
)

var totalThings int

// GetTotalThings returns the total things count in the database
func (gdb *GostDatabase) GetTotalThings() int {
	return totalThings
}

// InitThings Initialises the datastream repository, setting totalThings on startup
func (gdb *GostDatabase) InitThings() {
	sql := fmt.Sprintf("SELECT Count(*) from %s.thing", gdb.Schema)
	gdb.Db.QueryRow(sql).Scan(&totalThings)
}

// GetThing returns a thing entity based on id and query
func (gdb *GostDatabase) GetThing(id interface{}, qo *odata.QueryOptions) (*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("Thing does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "", "", nil)+" from %s.thing where id = %v", gdb.Schema, intID)
	datastream, err := processThing(gdb.Db, sql, qo)
	if err != nil {
		return nil, err
	}

	return datastream, nil
}

//GetThingByDatastream retrieves the thing linked to a datastream
func (gdb *GostDatabase) GetThingByDatastream(id interface{}, qo *odata.QueryOptions) (*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("Datastream does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "thing.", "", nil)+" from %s.thing INNER JOIN %s.datastream ON datastream.thing_id = thing.id WHERE datastream.id = %v;", gdb.Schema, gdb.Schema, intID)
	return processThing(gdb.Db, sql, qo)
}

//GetThingsByLocation retrieves the thing linked to a location
func (gdb *GostDatabase) GetThingsByLocation(id interface{}, qo *odata.QueryOptions) ([]*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("Location does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "thing.", "", nil)+" from %s.thing INNER JOIN %s.thing_to_location ON thing.id = thing_to_location.thing_id INNER JOIN %s.location ON thing_to_location.location_id = location.id WHERE location.id = %v order by id desc "+CreateTopSkipQueryString(qo), gdb.Schema, gdb.Schema, gdb.Schema, intID)
	return processThings(gdb.Db, sql, qo)
}

//GetThingByHistoricalLocation retrieves the thing linked to a HistoricalLocation
func (gdb *GostDatabase) GetThingByHistoricalLocation(id interface{}, qo *odata.QueryOptions) (*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("HistoricalLocation does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "thing.", "", nil)+" from %s.thing INNER JOIN %s.historicallocation ON historicallocation.thing_id = thing.id WHERE historicallocation.id = %v;", gdb.Schema, gdb.Schema, intID)
	return processThing(gdb.Db, sql, qo)
}

// GetThings returns an array of things
func (gdb *GostDatabase) GetThings(qo *odata.QueryOptions) ([]*entities.Thing, error) {
	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "", "", nil)+" FROM %s.thing order by id desc "+CreateTopSkipQueryString(qo), gdb.Schema)
	return processThings(gdb.Db, sql, qo)
}

func processThing(db *sql.DB, sql string, qo *odata.QueryOptions) (*entities.Thing, error) {
	observations, err := processThings(db, sql, qo)
	if err != nil {
		return nil, err
	}

	if len(observations) == 0 {
		return nil, gostErrors.NewRequestNotFound(errors.New("Thing not found"))
	}

	return observations[0], nil
}

func processThings(db *sql.DB, sql string, qo *odata.QueryOptions) ([]*entities.Thing, error) {
	rows, err := db.Query(sql)
	defer rows.Close()

	if err != nil {
		return nil, err
	}

	var things = []*entities.Thing{}
	for rows.Next() {
		var thingID interface{}
		var description string
		var properties *string

		var params []interface{}
		var qp []string
		if qo == nil || qo.QuerySelect == nil || len(qo.QuerySelect.Params) == 0 {
			t := &entities.Thing{}
			qp = t.GetPropertyNames()
		} else {
			qp = qo.QuerySelect.Params
		}

		for _, p := range qp {
			if p == "id" {
				params = append(params, &thingID)
			}
			if p == "description" {
				params = append(params, &description)
			}
			if p == "properties" {
				params = append(params, &properties)
			}
		}

		err = rows.Scan(params...)
		if err != nil {
			return nil, err
		}

		propMap, err := JSONToMap(properties)
		if err != nil {
			return nil, err
		}

		thing := entities.Thing{}
		thing.ID = thingID
		thing.Description = description
		thing.Properties = propMap

		things = append(things, &thing)
	}

	return things, nil
}

// PostThing receives a posted thing entity and adds it to the database
// returns the created Thing including the generated id
func (gdb *GostDatabase) PostThing(thing *entities.Thing) (*entities.Thing, error) {
	jsonProperties, _ := json.Marshal(thing.Properties)
	var thingID int
	sql := fmt.Sprintf("INSERT INTO %s.thing (description, properties) VALUES ($1, $2) RETURNING id", gdb.Schema)
	err := gdb.Db.QueryRow(sql, thing.Description, jsonProperties).Scan(&thingID)
	if err != nil {
		return nil, err
	}

	thing.ID = thingID
	totalThings++
	return thing, nil
}

// PatchThing receives a to be patched Thing entity and changes it in the database
// returns the patched Thing
func (gdb *GostDatabase) PatchThing(id interface{}, thing *entities.Thing) (*entities.Thing, error) {
	intID, _ := ToIntID(id)

	if len(thing.Description) > 0 {
		// update field description for now, todo add other fields
		sql := fmt.Sprintf("update %s.thing set description = $1 where id= $2", gdb.Schema)
		_, err := gdb.Db.Exec(sql, thing.Description, intID)
		if err != nil {
			return nil, err
		}
	}

	jsonProperties, _ := json.Marshal(thing.Properties)
	if jsonProperties != nil {
		sql := fmt.Sprintf("update %s.thing set properties  = $1 where id= $2", gdb.Schema)
		_, err := gdb.Db.Exec(sql, jsonProperties, intID)
		if err != nil {
			return nil, err
		}
	}

	if thing.Locations != nil {
		if len(thing.Locations) > 0 {
			for _, l := range thing.Locations {
				// locationId := l.ID
				location, _ := gdb.GetLocation(l.ID, nil)

				// todo: check if location exist
				if location != nil {
					sql := fmt.Sprintf("update %s.thing_to_location set location_id  = $1 where thing_id= $2", gdb.Schema)
					_, err := gdb.Db.Exec(sql, location.ID, intID)
					if err != nil {
						return nil, err
					}
				}
			}
		}
	}

	// do something with location if needed

	// get the thing and return
	var t *entities.Thing
	t, _ = gdb.GetThing(id, nil)
	return t, nil
}

// ThingExists checks if a thing is present in the database based on a given id
func (gdb *GostDatabase) ThingExists(thingID interface{}) bool {
	var result bool
	sql := fmt.Sprintf("SELECT exists (SELECT 1 FROM %s.thing WHERE id = $1 LIMIT 1)", gdb.Schema)
	err := gdb.Db.QueryRow(sql, thingID).Scan(&result)
	if err != nil {
		return false
	}

	return result
}

// DeleteThing tries to delete a Thing by the given id
func (gdb *GostDatabase) DeleteThing(id interface{}) error {
	intID, ok := ToIntID(id)
	if !ok {
		return gostErrors.NewRequestNotFound(errors.New("Thing does not exist"))
	}

	r, err := gdb.Db.Exec(fmt.Sprintf("DELETE FROM %s.thing WHERE id = $1", gdb.Schema), intID)
	if err != nil {
		return err
	}

	if c, _ := r.RowsAffected(); c == 0 {
		return gostErrors.NewRequestNotFound(errors.New("Thing not found"))
	}

	totalThings--
	return nil
}
<commit_msg>make thing patch upsert not update only<commit_after>package postgis

import (
	"encoding/json"
	"fmt"

	"github.com/geodan/gost/src/sensorthings/entities"

	"database/sql"
	"errors"

	gostErrors "github.com/geodan/gost/src/errors"
	"github.com/geodan/gost/src/sensorthings/odata"
)

var totalThings int

// GetTotalThings returns the total things count in the database
func (gdb *GostDatabase) GetTotalThings() int {
	return totalThings
}

// InitThings Initialises the datastream repository, setting totalThings on startup
func (gdb *GostDatabase) InitThings() {
	sql := fmt.Sprintf("SELECT Count(*) from %s.thing", gdb.Schema)
	gdb.Db.QueryRow(sql).Scan(&totalThings)
}

// GetThing returns a thing entity based on id and query
func (gdb *GostDatabase) GetThing(id interface{}, qo *odata.QueryOptions) (*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("Thing does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "", "", nil)+" from %s.thing where id = %v", gdb.Schema, intID)
	datastream, err := processThing(gdb.Db, sql, qo)
	if err != nil {
		return nil, err
	}

	return datastream, nil
}

//GetThingByDatastream retrieves the thing linked to a datastream
func (gdb *GostDatabase) GetThingByDatastream(id interface{}, qo *odata.QueryOptions) (*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("Datastream does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "thing.", "", nil)+" from %s.thing INNER JOIN %s.datastream ON datastream.thing_id = thing.id WHERE datastream.id = %v;", gdb.Schema, gdb.Schema, intID)
	return processThing(gdb.Db, sql, qo)
}

//GetThingsByLocation retrieves the thing linked to a location
func (gdb *GostDatabase) GetThingsByLocation(id interface{}, qo *odata.QueryOptions) ([]*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("Location does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "thing.", "", nil)+" from %s.thing INNER JOIN %s.thing_to_location ON thing.id = thing_to_location.thing_id INNER JOIN %s.location ON thing_to_location.location_id = location.id WHERE location.id = %v order by id desc "+CreateTopSkipQueryString(qo), gdb.Schema, gdb.Schema, gdb.Schema, intID)
	return processThings(gdb.Db, sql, qo)
}

//GetThingByHistoricalLocation retrieves the thing linked to a HistoricalLocation
func (gdb *GostDatabase) GetThingByHistoricalLocation(id interface{}, qo *odata.QueryOptions) (*entities.Thing, error) {
	intID, ok := ToIntID(id)
	if !ok {
		return nil, gostErrors.NewRequestNotFound(errors.New("HistoricalLocation does not exist"))
	}

	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "thing.", "", nil)+" from %s.thing INNER JOIN %s.historicallocation ON historicallocation.thing_id = thing.id WHERE historicallocation.id = %v;", gdb.Schema, gdb.Schema, intID)
	return processThing(gdb.Db, sql, qo)
}

// GetThings returns an array of things
func (gdb *GostDatabase) GetThings(qo *odata.QueryOptions) ([]*entities.Thing, error) {
	sql := fmt.Sprintf("select "+CreateSelectString(&entities.Thing{}, qo, "", "", nil)+" FROM %s.thing order by id desc "+CreateTopSkipQueryString(qo), gdb.Schema)
	return processThings(gdb.Db, sql, qo)
}

func processThing(db *sql.DB, sql string, qo *odata.QueryOptions) (*entities.Thing, error) {
	observations, err := processThings(db, sql, qo)
	if err != nil {
		return nil, err
	}

	if len(observations) == 0 {
		return nil, gostErrors.NewRequestNotFound(errors.New("Thing not found"))
	}

	return observations[0], nil
}

func processThings(db *sql.DB, sql string, qo *odata.QueryOptions) ([]*entities.Thing, error) {
	rows, err := db.Query(sql)
	defer rows.Close()

	if err != nil {
		return nil, err
	}

	var things = []*entities.Thing{}
	for rows.Next() {
		var thingID interface{}
		var description string
		var properties *string

		var params []interface{}
		var qp []string
		if qo == nil || qo.QuerySelect == nil || len(qo.QuerySelect.Params) == 0 {
			t := &entities.Thing{}
			qp = t.GetPropertyNames()
		} else {
			qp = qo.QuerySelect.Params
		}

		for _, p := range qp {
			if p == "id" {
				params = append(params, &thingID)
			}
			if p == "description" {
				params = append(params, &description)
			}
			if p == "properties" {
				params = append(params, &properties)
			}
		}

		err = rows.Scan(params...)
		if err != nil {
			return nil, err
		}

		propMap, err := JSONToMap(properties)
		if err != nil {
			return nil, err
		}

		thing := entities.Thing{}
		thing.ID = thingID
		thing.Description = description
		thing.Properties = propMap

		things = append(things, &thing)
	}

	return things, nil
}

// PostThing receives a posted thing entity and adds it to the database
// returns the created Thing including the generated id
func (gdb *GostDatabase) PostThing(thing *entities.Thing) (*entities.Thing, error) {
	jsonProperties, _ := json.Marshal(thing.Properties)
	var thingID int
	sql := fmt.Sprintf("INSERT INTO %s.thing (description, properties) VALUES ($1, $2) RETURNING id", gdb.Schema)
	err := gdb.Db.QueryRow(sql, thing.Description, jsonProperties).Scan(&thingID)
	if err != nil {
		return nil, err
	}

	thing.ID = thingID
	totalThings++
	return thing, nil
}

// PatchThing receives a to be patched Thing entity and changes it in the database
// returns the patched Thing
func (gdb *GostDatabase) PatchThing(id interface{}, thing *entities.Thing) (*entities.Thing, error) {
	intID, _ := ToIntID(id)

	if len(thing.Description) > 0 {
		// update field description for now, todo add other fields
		sql := fmt.Sprintf("update %s.thing set description = $1 where id= $2", gdb.Schema)
		_, err := gdb.Db.Exec(sql, thing.Description, intID)
		if err != nil {
			return nil, err
		}
	}

	jsonProperties, _ := json.Marshal(thing.Properties)
	if jsonProperties != nil {
		sql := fmt.Sprintf("update %s.thing set properties  = $1 where id= $2", gdb.Schema)
		_, err := gdb.Db.Exec(sql, jsonProperties, intID)
		if err != nil {
			return nil, err
		}
	}

	if thing.Locations != nil {
		if len(thing.Locations) > 0 {
			for _, l := range thing.Locations {
				// locationId := l.ID
				location, _ := gdb.GetLocation(l.ID, nil)

				// todo: check if location exist
				if location != nil {
					sql := fmt.Sprintf("update %s.thing_to_location set location_id  = $1 where thing_id= $2", gdb.Schema)
					res, err := gdb.Db.Exec(sql, location.ID, intID)
					if err != nil {
						return nil, err
					}
					if c, _ := res.RowsAffected(); c == 0 {
						sqlInsert := fmt.Sprintf("insert into %s.thing_to_location (location_id,thing_id) values ($1, $2)", gdb.Schema)
						_, err := gdb.Db.Exec(sqlInsert, location.ID, intID)
						if err != nil {
							return nil, err
						}
					}
				}
			}
		}
	}

	// do something with location if needed

	// get the thing and return
	var t *entities.Thing
	t, _ = gdb.GetThing(id, nil)
	return t, nil
}

// ThingExists checks if a thing is present in the database based on a given id
func (gdb *GostDatabase) ThingExists(thingID interface{}) bool {
	var result bool
	sql := fmt.Sprintf("SELECT exists (SELECT 1 FROM %s.thing WHERE id = $1 LIMIT 1)", gdb.Schema)
	err := gdb.Db.QueryRow(sql, thingID).Scan(&result)
	if err != nil {
		return false
	}

	return result
}

// DeleteThing tries to delete a Thing by the given id
func (gdb *GostDatabase) DeleteThing(id interface{}) error {
	intID, ok := ToIntID(id)
	if !ok {
		return gostErrors.NewRequestNotFound(errors.New("Thing does not exist"))
	}

	r, err := gdb.Db.Exec(fmt.Sprintf("DELETE FROM %s.thing WHERE id = $1", gdb.Schema), intID)
	if err != nil {
		return err
	}

	if c, _ := r.RowsAffected(); c == 0 {
		return gostErrors.NewRequestNotFound(errors.New("Thing not found"))
	}

	totalThings--
	return nil
}
<|endoftext|>


<commit_before>// Host detection.

package embd

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"strconv"
	"strings"
)

// The Host type represents all the supported host types.
type Host string

const (
	// HostNull reprents a null host.
	HostNull Host = ""

	// HostRPi represents the RaspberryPi.
	HostRPi = "Raspberry Pi"

	// HostBBB represents the BeagleBone Black.
	HostBBB = "BeagleBone Black"

	// HostGalileo represents the Intel Galileo board.
	HostGalileo = "Intel Galileo"

	// HostCubieTruck represents the Cubie Truck.
	HostCubieTruck = "CubieTruck"

	// HostRadxa represents the Radxa board.
	HostRadxa = "Radxa"
)

func execOutput(name string, arg ...string) (output string, err error) {
	var out []byte
	if out, err = exec.Command(name, arg...).Output(); err != nil {
		return
	}
	output = strings.TrimSpace(string(out))
	return
}

func parseVersion(str string) (major, minor, patch int, err error) {
	versionNumber := strings.Split(str, "-")
	parts := strings.Split(versionNumber[0], ".")
	len := len(parts)

	if major, err = strconv.Atoi(parts[0]); err != nil {
		return 0, 0, 0, err
	}
	if minor, err = strconv.Atoi(parts[1]); err != nil {
		return 0, 0, 0, err
	}
	if len > 2 {
		part := parts[2]
		part = strings.TrimSuffix(part, "+")
		if patch, err = strconv.Atoi(part); err != nil {
			return 0, 0, 0, err
		}
	}

	return major, minor, patch, err
}

func kernelVersion() (major, minor, patch int, err error) {
	output, err := execOutput("uname", "-r")
	if err != nil {
		return 0, 0, 0, err
	}

	return parseVersion(output)
}

func cpuInfo() (model, hardware string, revision int, err error) {
	output, err := ioutil.ReadFile("/proc/cpuinfo")
	if err != nil {
		return "", "", 0, err
	}
	for _, line := range strings.Split(string(output), "\n") {
		fields := strings.Split(line, ":")
		if len(fields) < 1 {
			continue
		}
		if strings.HasPrefix(fields[0], "Revision") {
			rev, err := strconv.ParseInt(fields[1], 16, 8)
			if err != nil {
				continue
			}
			revision = int(rev)
		} else if strings.HasPrefix(fields[0], "Hardware") {
			hardware = fields[1]
		} else if strings.HasPrefix(fields[0], "model name") {
			model = fields[1]
		}
	}
	return model, hardware, revision, nil
}

// DetectHost returns the detected host and its revision number.
func DetectHost() (host Host, rev int, err error) {
	major, minor, patch, err := kernelVersion()
	if err != nil {
		return HostNull, 0, err
	}

	if major < 3 || (major == 3 && minor < 8) {
		return HostNull, 0, fmt.Errorf("embd: linux kernel versions lower than 3.8 are not supported. you have %v.%v.%v", major, minor, patch)
	}

	model, hardware, rev, err := cpuInfo()
	if err != nil {
		return HostNull, 0, err
	}

	switch {
	case strings.Contains(model, "ARMv7") && (strings.Contains(hardware, "AM33XX") || strings.Contains(hardware, "AM335X")):
		return HostBBB, rev, nil
	case strings.Contains(hardware, "BCM2708"):
		return HostRPi, rev, nil
	default:
		return HostNull, 0, fmt.Errorf("embd: your host \"%v:%v\" is not supported at this moment. request support at https://github.com/kidoman/embd/issues", host, model)
	}
}
<commit_msg>support detection on rpi b+<commit_after>// Host detection.

package embd

import (
	"fmt"
	"io/ioutil"
	"os/exec"
	"strconv"
	"strings"
)

// The Host type represents all the supported host types.
type Host string

const (
	// HostNull reprents a null host.
	HostNull Host = ""

	// HostRPi represents the RaspberryPi.
	HostRPi = "Raspberry Pi"

	// HostBBB represents the BeagleBone Black.
	HostBBB = "BeagleBone Black"

	// HostGalileo represents the Intel Galileo board.
	HostGalileo = "Intel Galileo"

	// HostCubieTruck represents the Cubie Truck.
	HostCubieTruck = "CubieTruck"

	// HostRadxa represents the Radxa board.
	HostRadxa = "Radxa"
)

func execOutput(name string, arg ...string) (output string, err error) {
	var out []byte
	if out, err = exec.Command(name, arg...).Output(); err != nil {
		return
	}
	output = strings.TrimSpace(string(out))
	return
}

func parseVersion(str string) (major, minor, patch int, err error) {
	versionNumber := strings.Split(str, "-")
	parts := strings.Split(versionNumber[0], ".")
	len := len(parts)

	if major, err = strconv.Atoi(parts[0]); err != nil {
		return 0, 0, 0, err
	}
	if minor, err = strconv.Atoi(parts[1]); err != nil {
		return 0, 0, 0, err
	}
	if len > 2 {
		part := parts[2]
		part = strings.TrimSuffix(part, "+")
		if patch, err = strconv.Atoi(part); err != nil {
			return 0, 0, 0, err
		}
	}

	return major, minor, patch, err
}

func kernelVersion() (major, minor, patch int, err error) {
	output, err := execOutput("uname", "-r")
	if err != nil {
		return 0, 0, 0, err
	}

	return parseVersion(output)
}

func cpuInfo() (model, hardware string, revision int, err error) {
	output, err := ioutil.ReadFile("/proc/cpuinfo")
	if err != nil {
		return "", "", 0, err
	}
	for _, line := range strings.Split(string(output), "\n") {
		fields := strings.Split(line, ":")
		if len(fields) < 1 {
			continue
		}
		switch {
		case strings.HasPrefix(fields[0], "Revision"):
			revs := strings.TrimSpace(fields[1])
			rev, err := strconv.ParseInt(revs, 16, 8)
			if err != nil {
				continue
			}
			revision = int(rev)
		case strings.HasPrefix(fields[0], "Hardware"):
			hardware = fields[1]
		case strings.HasPrefix(fields[0], "model name"):
			model = fields[1]
		}
	}
	return model, hardware, revision, nil
}

// DetectHost returns the detected host and its revision number.
func DetectHost() (host Host, rev int, err error) {
	major, minor, patch, err := kernelVersion()
	if err != nil {
		return HostNull, 0, err
	}

	if major < 3 || (major == 3 && minor < 8) {
		return HostNull, 0, fmt.Errorf("embd: linux kernel versions lower than 3.8 are not supported. you have %v.%v.%v", major, minor, patch)
	}

	model, hardware, rev, err := cpuInfo()
	if err != nil {
		return HostNull, 0, err
	}

	switch {
	case strings.Contains(model, "ARMv7") && (strings.Contains(hardware, "AM33XX") || strings.Contains(hardware, "AM335X")):
		return HostBBB, rev, nil
	case strings.Contains(hardware, "BCM2708"):
		return HostRPi, rev, nil
	default:
		return HostNull, 0, fmt.Errorf("embd: your host \"%v:%v\" is not supported at this moment. request support at https://github.com/kidoman/embd/issues", host, model)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// 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 xretry

import (
	"errors"
	"math"
	"math/rand"
	"time"

	"github.com/m3db/m3x/errors"

	"github.com/uber-go/tally"
)

var (
	// ErrWhileConditionFalse is raised when the while condition to a while retry method evaluates false
	ErrWhileConditionFalse = errors.New("retry while condition evaluated to false")
)

type retrier struct {
	initialBackoff time.Duration
	backoffFactor  float64
	max            int
	jitter         bool
	sleepFn        func(t time.Duration)
	metrics        retrierMetrics
}

type retrierMetrics struct {
	success            tally.Counter
	successLatency     tally.Timer
	errors             tally.Counter
	errorsNotRetryable tally.Counter
	errorsFinal        tally.Counter
	errorsLatency      tally.Timer
	retries            tally.Counter
}

// NewRetrier creates a new retrier
func NewRetrier(opts Options) Retrier {
	scope := opts.GetMetricsScope()
	errorTags := struct {
		retryable    map[string]string
		notRetryable map[string]string
	}{
		map[string]string{
			"type": "retryable",
		},
		map[string]string{
			"type": "not-retryable",
		},
	}
	return &retrier{
		initialBackoff: opts.GetInitialBackoff(),
		backoffFactor:  opts.GetBackoffFactor(),
		max:            opts.GetMax(),
		jitter:         opts.GetJitter(),
		sleepFn:        time.Sleep,
		metrics: retrierMetrics{
			success:            scope.Counter("success"),
			successLatency:     scope.Timer("success-latency"),
			errors:             scope.Tagged(errorTags.retryable).Counter("errors"),
			errorsNotRetryable: scope.Tagged(errorTags.notRetryable).Counter("errors"),
			errorsFinal:        scope.Counter("errors-final"),
			errorsLatency:      scope.Timer("errors-latency"),
			retries:            scope.Counter("retries"),
		},
	}
}

func (r *retrier) Attempt(fn Fn) error {
	return r.attempt(nil, fn)
}

func (r *retrier) AttemptWhile(continueFn ContinueFn, fn Fn) error {
	return r.attempt(continueFn, fn)
}

func (r *retrier) attempt(continueFn ContinueFn, fn Fn) error {
	attempt := 0

	if continueFn != nil && !continueFn(attempt) {
		return ErrWhileConditionFalse
	}

	err := fn()
	attempt++
	if err == nil {
		r.metrics.success.Inc(1)
		return nil
	}
	if xerrors.IsNonRetryableError(err) {
		r.metrics.errorsNotRetryable.Inc(1)
		return err
	}
	r.metrics.errors.Inc(1)

	for i := 0; i < r.max; i++ {
		curr := r.initialBackoff.Nanoseconds() * int64(math.Pow(r.backoffFactor, float64(i)))
		if r.jitter {
			half := curr / 2
			curr = half + int64(rand.Float64()*float64(half))
		}
		r.sleepFn(time.Duration(curr))

		if continueFn != nil && !continueFn(attempt) {
			return ErrWhileConditionFalse
		}

		r.metrics.retries.Inc(1)
		err = fn()
		attempt++
		if err == nil {
			r.metrics.success.Inc(1)
			return nil
		}
		if xerrors.IsNonRetryableError(err) {
			r.metrics.errorsNotRetryable.Inc(1)
			return err
		}
		r.metrics.errors.Inc(1)
	}
	r.metrics.errorsFinal.Inc(1)

	return err
}
<commit_msg>Emit latency metrics for xretry/Retrier (#19)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// 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 xretry

import (
	"errors"
	"math"
	"math/rand"
	"time"

	"github.com/m3db/m3x/errors"

	"github.com/uber-go/tally"
)

var (
	// ErrWhileConditionFalse is raised when the while condition to a while retry method evaluates false
	ErrWhileConditionFalse = errors.New("retry while condition evaluated to false")
)

type retrier struct {
	initialBackoff time.Duration
	backoffFactor  float64
	max            int
	jitter         bool
	sleepFn        func(t time.Duration)
	metrics        retrierMetrics
}

type retrierMetrics struct {
	success            tally.Counter
	successLatency     tally.Timer
	errors             tally.Counter
	errorsNotRetryable tally.Counter
	errorsFinal        tally.Counter
	errorsLatency      tally.Timer
	retries            tally.Counter
}

// NewRetrier creates a new retrier
func NewRetrier(opts Options) Retrier {
	scope := opts.GetMetricsScope()
	errorTags := struct {
		retryable    map[string]string
		notRetryable map[string]string
	}{
		map[string]string{
			"type": "retryable",
		},
		map[string]string{
			"type": "not-retryable",
		},
	}
	return &retrier{
		initialBackoff: opts.GetInitialBackoff(),
		backoffFactor:  opts.GetBackoffFactor(),
		max:            opts.GetMax(),
		jitter:         opts.GetJitter(),
		sleepFn:        time.Sleep,
		metrics: retrierMetrics{
			success:            scope.Counter("success"),
			successLatency:     scope.Timer("success-latency"),
			errors:             scope.Tagged(errorTags.retryable).Counter("errors"),
			errorsNotRetryable: scope.Tagged(errorTags.notRetryable).Counter("errors"),
			errorsFinal:        scope.Counter("errors-final"),
			errorsLatency:      scope.Timer("errors-latency"),
			retries:            scope.Counter("retries"),
		},
	}
}

func (r *retrier) Attempt(fn Fn) error {
	return r.attempt(nil, fn)
}

func (r *retrier) AttemptWhile(continueFn ContinueFn, fn Fn) error {
	return r.attempt(continueFn, fn)
}

func (r *retrier) attempt(continueFn ContinueFn, fn Fn) error {
	attempt := 0

	if continueFn != nil && !continueFn(attempt) {
		return ErrWhileConditionFalse
	}

	start := time.Now()
	err := fn()
	duration := time.Now().Sub(start)
	attempt++
	if err == nil {
		r.metrics.successLatency.Record(duration)
		r.metrics.success.Inc(1)
		return nil
	}
	r.metrics.errorsLatency.Record(duration)
	if xerrors.IsNonRetryableError(err) {
		r.metrics.errorsNotRetryable.Inc(1)
		return err
	}
	r.metrics.errors.Inc(1)

	for i := 0; i < r.max; i++ {
		curr := r.initialBackoff.Nanoseconds() * int64(math.Pow(r.backoffFactor, float64(i)))
		if r.jitter {
			half := curr / 2
			curr = half + int64(rand.Float64()*float64(half))
		}
		r.sleepFn(time.Duration(curr))

		if continueFn != nil && !continueFn(attempt) {
			return ErrWhileConditionFalse
		}

		r.metrics.retries.Inc(1)
		start := time.Now()
		err = fn()
		duration := time.Now().Sub(start)
		attempt++
		if err == nil {
			r.metrics.successLatency.Record(duration)
			r.metrics.success.Inc(1)
			return nil
		}
		r.metrics.errorsLatency.Record(duration)
		if xerrors.IsNonRetryableError(err) {
			r.metrics.errorsNotRetryable.Inc(1)
			return err
		}
		r.metrics.errors.Inc(1)
	}
	r.metrics.errorsFinal.Inc(1)

	return err
}
<|endoftext|>


<commit_before>package pull

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestPing(t *testing.T) {

	ts := httptest.NewServer(pingHandler(http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}
	req, _ := http.NewRequest("GET", ts.URL, nil)
	req.Header.Set("X-GitHub-Event", "ping")
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusAccepted {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusNotImplemented, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	expected := "Received ping"
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestImplements(t *testing.T) {

	ts := httptest.NewServer(implementsHandler(http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}
	req, _ := http.NewRequest("GET", ts.URL, nil)
	req.Header.Set("X-GitHub-Event", "unsupported")
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusNotImplemented {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusNotImplemented, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	expected := "Unsupported event"
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestSecret(t *testing.T) {

	secret := "test"
	reqbody := []byte(`{"test":"test"}`)
	hash := "sha1=7c7429c26f63ae28d74597e825c20e1796c167e3"

	expected := "Success"
	ts := httptest.NewServer(secretHandler(secret, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusTeapot)
		fmt.Fprint(w, expected)
	})))
	defer ts.Close()

	client := &http.Client{}

	req, _ := http.NewRequest("GET", ts.URL, bytes.NewBuffer(reqbody))
	req.Header.Set("X-Hub-Signature", hash)
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusTeapot {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusTeapot, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestSecretNoHeader(t *testing.T) {

	expected := "X-Hub-Signature required for HMAC verification"

	ts := httptest.NewServer(secretHandler("secret", http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}

	req, _ := http.NewRequest("GET", ts.URL, nil)
	//req.Header.Set("X-Hub-Signature", hash)
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusForbidden, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestSecretFailed(t *testing.T) {

	secret := "test"
	reqbody := []byte(`{"test":"test"}`)
	hash := "sha1=mismatchgibberish"

	ts := httptest.NewServer(secretHandler(secret, http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}

	req, _ := http.NewRequest("GET", ts.URL, bytes.NewBuffer(reqbody))
	req.Header.Set("X-Hub-Signature", hash)
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusForbidden, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	actual := string(body)
	expected := "HMAC verification failed"

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}
<commit_msg>Change formatting.<commit_after>package pull

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestPing(t *testing.T) {

	ts := httptest.NewServer(pingHandler(http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}
	req, _ := http.NewRequest("GET", ts.URL, nil)
	req.Header.Set("X-GitHub-Event", "ping")
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusAccepted {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusNotImplemented, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	expected := "Received ping"
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestImplements(t *testing.T) {

	ts := httptest.NewServer(implementsHandler(http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}
	req, _ := http.NewRequest("GET", ts.URL, nil)
	req.Header.Set("X-GitHub-Event", "unsupported")
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusNotImplemented {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusNotImplemented, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	expected := "Unsupported event"
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestSecret(t *testing.T) {

	secret := "test"
	reqbody := []byte(`{"test":"test"}`)
	hash := "sha1=7c7429c26f63ae28d74597e825c20e1796c167e3"

	expected := "Success"
	ts := httptest.NewServer(secretHandler(secret, http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusTeapot)
			fmt.Fprint(w, expected)
		})))
	defer ts.Close()

	client := &http.Client{}

	req, _ := http.NewRequest("GET", ts.URL, bytes.NewBuffer(reqbody))
	req.Header.Set("X-Hub-Signature", hash)
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusTeapot {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusTeapot, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestSecretNoHeader(t *testing.T) {

	expected := "X-Hub-Signature required for HMAC verification"

	ts := httptest.NewServer(secretHandler("secret", http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}

	req, _ := http.NewRequest("GET", ts.URL, nil)
	//req.Header.Set("X-Hub-Signature", hash)
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusForbidden, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	actual := string(body)

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}

func TestSecretFailed(t *testing.T) {

	secret := "test"
	reqbody := []byte(`{"test":"test"}`)
	hash := "sha1=mismatchgibberish"

	ts := httptest.NewServer(secretHandler(secret, http.NotFoundHandler()))
	defer ts.Close()

	client := &http.Client{}

	req, _ := http.NewRequest("GET", ts.URL, bytes.NewBuffer(reqbody))
	req.Header.Set("X-Hub-Signature", hash)
	resp, err := client.Do(req)

	if err != nil {
		t.Fatalf("HTTP Request failed: %s", err)
	}

	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("Expected HTTP %d, got HTTP %d", http.StatusForbidden, resp.StatusCode)
	}

	body, _ := ioutil.ReadAll(resp.Body)
	actual := string(body)
	expected := "HMAC verification failed"

	if actual != expected {
		t.Errorf("Expected %s got %s", expected, actual)
	}
}
<|endoftext|>


<commit_before>package controller

import (
	"github.com/algolia/algoliasearch-client-go/algoliasearch"

	mongomodels "koding/db/models"
	"koding/db/mongodb/modelhelper"
	"koding/helpers"
	"socialapi/config"
	"socialapi/models"
	"socialapi/workers/algoliaconnector/algoliaconnector"
)

func (mwc *Controller) migrateAllAccountsToAlgolia() {
	mwc.log.Notice("Account migration to Algolia started")
	successCount := 0

	s := modelhelper.Selector{
		"type": "registered",
	}

	c := config.MustGet()

	algolia := algoliasearch.NewClient(c.Algolia.AppId, c.Algolia.ApiSecretKey)
	// create message handler
	handler := algoliaconnector.New(mwc.log, algolia, c.Algolia.IndexSuffix)

	migrateAccount := func(account interface{}) error {
		oldAccount := account.(*mongomodels.Account)

		return handler.AccountSaved(&models.Account{
			OldId: oldAccount.Id.Hex(),
			Nick:  oldAccount.Profile.Nickname,
		})
	}

	iterOptions := helpers.NewIterOptions()
	iterOptions.CollectionName = "jAccounts"
	iterOptions.F = migrateAccount
	iterOptions.Filter = s
	iterOptions.Result = &mongomodels.Account{}
	iterOptions.Limit = 10000000
	iterOptions.Skip = 0
	iterOptions.Sort = []string{"-_id"}

	helpers.Iter(modelhelper.Mongo, iterOptions)

	mwc.log.Notice("Account migration completed for %d account with %d errors", successCount, errAccountCount)
}
<commit_msg>algolia-migrator: use extant expando to filter unmigrated accounts<commit_after>package controller

import (
	"github.com/algolia/algoliasearch-client-go/algoliasearch"

	mongomodels "koding/db/models"
	"koding/db/mongodb/modelhelper"
	"koding/helpers"
	"socialapi/config"
	"socialapi/models"
	"socialapi/workers/algoliaconnector/algoliaconnector"
)

func (mwc *Controller) migrateAllAccountsToAlgolia() {
	mwc.log.Notice("Account migration to Algolia started")
	successCount := 0

	s := modelhelper.Selector{
		"migration": modelhelper.Selector{"$exists": false},
		"type":      "registered",
	}

	c := config.MustGet()

	algolia := algoliasearch.NewClient(c.Algolia.AppId, c.Algolia.ApiSecretKey)
	// create message handler
	handler := algoliaconnector.New(mwc.log, algolia, c.Algolia.IndexSuffix)

	migrateAccount := func(account interface{}) error {
		oldAccount := account.(*mongomodels.Account)

		return handler.AccountSaved(&models.Account{
			OldId: oldAccount.Id.Hex(),
			Nick:  oldAccount.Profile.Nickname,
		})
	}

	iterOptions := helpers.NewIterOptions()
	iterOptions.CollectionName = "jAccounts"
	iterOptions.F = migrateAccount
	iterOptions.Filter = s
	iterOptions.Result = &mongomodels.Account{}
	iterOptions.Limit = 10000000
	iterOptions.Skip = 0
	iterOptions.Sort = []string{"-_id"}

	helpers.Iter(modelhelper.Mongo, iterOptions)

	mwc.log.Notice("Account migration completed for %d account with %d errors", successCount, errAccountCount)
}
<|endoftext|>


<commit_before>package push

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"
	"sync"

	"github.com/koichirokamoto/webpush"
	"github.com/sideshow/apns2"
	"golang.org/x/net/context"
	"google.golang.org/api/gensupport"
)

const (
	fcmURL = "https://fcm.googleapis.com/fcm/send"
	gcmURL = "https://android.googleapis.com/gcm/send"
)

var (
	// ServerKey is fcm server key.
	ServerKey string
	// Cert is apns notification certificate.
	Cert tls.Certificate
	// Backoff is backoff strategy.
	Backoff gensupport.BackoffStrategy
	// DevEnv is flag whether environment is development.
	DevEnv bool
)

type worker interface {
	work() error
}

func runWorker(wrk <-chan worker) {
	if Backoff == nil {
		Backoff = gensupport.DefaultBackoffStrategy()
	}
	var wg sync.WaitGroup
	for w := range wrk {
		wg.Add(1)
		go func(w worker) {
			defer wg.Done()
			retry(w.work, Backoff)
		}(w)
	}
	wg.Wait()
}

// FcmSubscription is fcm subscription.
type FcmSubscription struct {
	Endpoint string
	Key      string
	Auth     string
}

type fcmWorker struct {
	ctx     context.Context
	sub     *FcmSubscription
	payload []byte
}

// SendFcmNotification push fcm notification to user.
func SendFcmNotification(ctx context.Context, subs []*FcmSubscription, payload []byte) {
	in := make(chan worker)
	go func() {
		for _, sub := range subs {
			in <- &fcmWorker{ctx, sub, payload}
		}
		close(in)
	}()

	runWorker(in)
}

func (f *fcmWorker) work() error {
	encryption, err := webpush.Encryption(f.sub.Key, f.sub.Auth, f.payload, 0)
	if err != nil {
		return err
	}

	endpoint := strings.Replace(f.sub.Endpoint, gcmURL, fcmURL, 1)
	req, err := http.NewRequest("POST", endpoint, bytes.NewReader(encryption.Payload))
	if err != nil {
		return err
	}
	defer req.Body.Close()
	req.Header.Set("Authorization", "key="+ServerKey)
	req.Header.Set("Encryption", "salt="+base64.URLEncoding.EncodeToString(encryption.Salt))
	req.Header.Set("Crypto-Key", "dh="+base64.URLEncoding.EncodeToString(encryption.PublickKey))
	req.Header.Set("Content-Encoding", "aesgcm")
	req.ContentLength = int64(len(encryption.Payload))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	res.Body.Close()
	return nil
}

type apnsWorker struct {
	ctx         context.Context
	deviceToken string
	payload     []byte
}

// SendApnsNotification send apns2 notification.
func SendApnsNotification(ctx context.Context, deviceTokens []string, payload []byte) {
	in := make(chan worker)

	go func() {
		for _, d := range deviceTokens {
			in <- &apnsWorker{ctx, d, payload}
		}
		close(in)
	}()

	runWorker(in)
}

func (a *apnsWorker) work() error {
	var client *apns2.Client
	if DevEnv {
		client = apns2.NewClient(Cert).Development()
	} else {
		client = apns2.NewClient(Cert).Production()
	}

	notification := &apns2.Notification{}
	notification.DeviceToken = a.deviceToken
	notification.Payload = a.payload

	res, err := client.Push(notification)
	if err != nil {
		return err
	}

	if !res.Sent() {
		return fmt.Errorf("not sent: %v %v %v", res.StatusCode, res.ApnsID, res.Reason)
	}

	return nil
}
<commit_msg>push: pass argument instead define global variable<commit_after>package push

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"
	"sync"

	"github.com/koichirokamoto/gko/log"
	"github.com/koichirokamoto/webpush"
	"github.com/sideshow/apns2"
	"google.golang.org/api/gensupport"
)

const (
	fcmURL = "https://fcm.googleapis.com/fcm/send"
	gcmURL = "https://android.googleapis.com/gcm/send"
)

type worker interface {
	work() error
}

func runWorker(wrk <-chan worker) {
	var wg sync.WaitGroup
	for w := range wrk {
		wg.Add(1)
		go func(w worker) {
			defer wg.Done()
			err := retry(w.work, gensupport.DefaultBackoffStrategy())
			if err != nil {
				log.DefaultLogger.Log(log.Error, err.Error())
			}
		}(w)
	}
	wg.Wait()
}

// FcmSubscription is fcm subscription.
type FcmSubscription struct {
	Endpoint string
	Key      string
	Auth     string
}

type fcmWorker struct {
	c       *http.Client
	key     string
	sub     *FcmSubscription
	payload []byte
}

// SendFcmNotification push fcm notification to user.
func SendFcmNotification(c *http.Client, key string, subs []*FcmSubscription, payload []byte) {
	in := make(chan worker)
	go func() {
		for _, sub := range subs {
			in <- &fcmWorker{c, key, sub, payload}
		}
		close(in)
	}()

	runWorker(in)
}

func (f *fcmWorker) work() error {
	encryption, err := webpush.Encryption(f.sub.Key, f.sub.Auth, f.payload, 0)
	if err != nil {
		log.DefaultLogger.Log(log.Error, err.Error())
		return err
	}

	endpoint := strings.Replace(f.sub.Endpoint, gcmURL, fcmURL, 1)
	req, err := http.NewRequest("POST", endpoint, bytes.NewReader(encryption.Payload))
	if err != nil {
		log.DefaultLogger.Log(log.Error, err.Error())
		return err
	}
	defer req.Body.Close()
	req.Header.Set("Authorization", "key="+f.key)
	req.Header.Set("Encryption", "salt="+base64.URLEncoding.EncodeToString(encryption.Salt))
	req.Header.Set("Crypto-Key", "dh="+base64.URLEncoding.EncodeToString(encryption.PublickKey))
	req.Header.Set("Content-Encoding", "aesgcm")
	req.ContentLength = int64(len(encryption.Payload))
	res, err := f.c.Do(req)
	if err != nil {
		log.DefaultLogger.Log(log.Error, err.Error())
		return err
	}
	res.Body.Close()
	return nil
}

type apnsWorker struct {
	c           *apns2.Client
	deviceToken string
	payload     []byte
}

// SendApns2Notification send apns2 notification.
func SendApns2Notification(cert tls.Certificate, deviceTokens []string, payload []byte) {
	in := make(chan worker)

	go func() {
		c := apns2.NewClient(cert)
		for _, d := range deviceTokens {
			in <- &apnsWorker{c, d, payload}
		}
		close(in)
	}()

	runWorker(in)
}

func (a *apnsWorker) work() error {
	notification := &apns2.Notification{}
	notification.DeviceToken = a.deviceToken
	notification.Payload = a.payload

	res, err := a.c.Push(notification)
	if err != nil {
		log.DefaultLogger.Log(log.Error, err.Error())
		return err
	}

	if !res.Sent() {
		errMsg := fmt.Sprintf("not sent: %d %s %s", res.StatusCode, res.ApnsID, res.Reason)
		log.DefaultLogger.Log(log.Error, errMsg)
		return fmt.Errorf(errMsg)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/stianeikeland/go-rpio"
	"net/http"
	"os"
)

var (
	pin = rpio.Pin(23)
)

func main() {
	// Open and map memory to access gpio, check for errors
	if err := rpio.Open(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Pull up pin
	pin.PullUp()

	// Unmap gpio memory when done
	defer rpio.Close()

	http.HandleFunc("/", handler)
	http.ListenAndServe(":80", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	doorStatus := pin.Read()
	var doorString string
	if doorStatus == 0 {
		doorString = "closed"
	} else {
		doorString = "open"
	}

	fmt.Fprintln(w, "Garage door is:", doorString)
}
<commit_msg>Put door monitoring in a function, use channels.<commit_after>package main

import (
	"fmt"
	"github.com/stianeikeland/go-rpio"
	"net/http"
)

type DoorStatus int

const (
	OPEN DoorStatus = iota
	CLOSED
)

type StatusRequest struct {
	resultChan chan DoorStatus
}

func main() {
	statusChan := make(chan *StatusRequest)
	go doorMonitor(statusChan)

	http.Handle("/", &StatusPage{statusChan})
	http.ListenAndServe(":80", nil)
}

func doorMonitor(queue chan *StatusRequest) {
	// Open and map memory to access gpio, check for errors
	if err := rpio.Open(); err != nil {
		panic(err)
	}

	pin := rpio.Pin(23)

	// Pull up pin
	pin.PullUp()

	for req := range queue {
		doorStatus := pin.Read()
		if doorStatus == 0 {
			req.resultChan <- CLOSED
		} else {
			req.resultChan <- OPEN
		}
	}

	// Unmap gpio memory when done
	defer rpio.Close()
}

type StatusPage struct {
	statusChan chan *StatusRequest
}

func (s *StatusPage) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	req := &StatusRequest{make(chan DoorStatus)}
	s.statusChan <- req
	doorStatus := <-req.resultChan
	var doorString string
	if doorStatus == CLOSED {
		doorString = "closed"
	} else {
		doorString = "open"
	}

	fmt.Fprintln(w, "Garage door is:", doorString)
}
<|endoftext|>