<commit_before>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

const (
	eRaw = iota
	eDoc
	eAry
)

type lazyNode struct {
	raw   *json.RawMessage
	doc   partialDoc
	ary   partialArray
	which int
}

type operation map[string]*json.RawMessage

// Patch is an ordered collection of operations.
type Patch []operation

type partialDoc map[string]*lazyNode
type partialArray []*lazyNode

type container interface {
	get(key string) (*lazyNode, error)
	set(key string, val *lazyNode) error
	remove(key string) error
}

func newLazyNode(raw *json.RawMessage) *lazyNode {
	return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
}

func (n *lazyNode) MarshalJSON() ([]byte, error) {
	switch n.which {
	case eRaw:
		return *n.raw, nil
	case eDoc:
		return json.Marshal(n.doc)
	case eAry:
		return json.Marshal(n.ary)
	default:
		return nil, fmt.Errorf("Unknown type")
	}
}

func (n *lazyNode) UnmarshalJSON(data []byte) error {
	dest := make(json.RawMessage, len(data))
	copy(dest, data)
	n.raw = &dest
	n.which = eRaw
	return nil
}

func (n *lazyNode) intoDoc() (*partialDoc, error) {
	if n.which == eDoc {
		return &n.doc, nil
	}

	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return nil, err
	}

	n.which = eDoc
	return &n.doc, nil
}

func (n *lazyNode) intoAry() (*partialArray, error) {
	if n.which == eAry {
		return &n.ary, nil
	}

	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return nil, err
	}

	n.which = eAry
	return &n.ary, nil
}

func (n *lazyNode) compact() []byte {
	buf := &bytes.Buffer{}

	err := json.Compact(buf, *n.raw)

	if err != nil {
		return *n.raw
	}

	return buf.Bytes()
}

func (n *lazyNode) tryDoc() bool {
	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return false
	}

	n.which = eDoc
	return true
}

func (n *lazyNode) tryAry() bool {
	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return false
	}

	n.which = eAry
	return true
}

func (n *lazyNode) equal(o *lazyNode) bool {
	if n.which == eRaw {
		if !n.tryDoc() && !n.tryAry() {
			if o.which != eRaw {
				return false
			}

			return bytes.Equal(n.compact(), o.compact())
		}
	}

	if n.which == eDoc {
		if o.which == eRaw {
			if !o.tryDoc() {
				return false
			}
		}

		if o.which != eDoc {
			return false
		}

		for k, v := range n.doc {
			ov, ok := o.doc[k]

			if !ok {
				return false
			}

			if v == nil && ov == nil {
				continue
			}

			if !v.equal(ov) {
				return false
			}
		}

		return true
	}

	if o.which != eAry && !o.tryAry() {
		return false
	}

	if len(n.ary) != len(o.ary) {
		return false
	}

	for idx, val := range n.ary {
		if !val.equal(o.ary[idx]) {
			return false
		}
	}

	return true
}

func (o operation) kind() string {
	if obj, ok := o["op"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) path() string {
	if obj, ok := o["path"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) from() string {
	if obj, ok := o["from"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) value() *lazyNode {
	if obj, ok := o["value"]; ok {
		return newLazyNode(obj)
	}

	return nil
}

func isArray(buf []byte) bool {
Loop:
	for _, c := range buf {
		switch c {
		case ' ':
		case '\n':
		case '\t':
			continue
		case '[':
			return true
		default:
			break Loop
		}
	}

	return false
}

func findObject(pd *partialDoc, path string) (container, string) {
	doc := container(pd)

	split := strings.Split(path, "/")

	parts := split[1 : len(split)-1]

	key := split[len(split)-1]

	var err error

	for _, part := range parts {

		next, ok := doc.get(part)

		if next == nil || ok != nil {
			return nil, ""
		}

		if isArray(*next.raw) {
			doc, err = next.intoAry()

			if err != nil {
				return nil, ""
			}
		} else {
			doc, err = next.intoDoc()

			if err != nil {
				return nil, ""
			}
		}
	}

	return doc, key
}

func (d *partialDoc) set(key string, val *lazyNode) error {
	(*d)[key] = val
	return nil
}

func (d *partialDoc) get(key string) (*lazyNode, error) {
	return (*d)[key], nil
}

func (d *partialDoc) remove(key string) error {
	delete(*d, key)
	return nil
}

func (d *partialArray) set(key string, val *lazyNode) error {
	if key == "-" {
		*d = append(*d, val)
		return nil
	}

	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	ary := make([]*lazyNode, len(*d)+1)

	cur := *d

	copy(ary[0:idx], cur[0:idx])
	ary[idx] = val
	copy(ary[idx+1:], cur[idx:])

	*d = ary
	return nil
}

func (d *partialArray) get(key string) (*lazyNode, error) {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return nil, err
	}

	return (*d)[idx], nil
}

func (d *partialArray) remove(key string) error {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	cur := *d

	ary := make([]*lazyNode, len(cur)-1)

	copy(ary[0:idx], cur[0:idx])
	copy(ary[idx:], cur[idx+1:])

	*d = ary
	return nil

}

func (p Patch) add(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	if con == nil {
		return fmt.Errorf("Missing container: %s", path)
	}

	con.set(key, op.value())

	return nil
}

func (p Patch) remove(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	return con.remove(key)
}

func (p Patch) replace(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	con.set(key, op.value())

	return nil
}

func (p Patch) move(doc *partialDoc, op operation) error {
	from := op.from()

	con, key := findObject(doc, from)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	con.remove(key)

	path := op.path()

	con, key = findObject(doc, path)

	con.set(key, val)

	return nil
}

func (p Patch) test(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	if val == nil {
		if op.value().raw == nil {
			return nil
		} else {
			return fmt.Errorf("Testing value %s failed", path)
		}
	}

	if val.equal(op.value()) {
		return nil
	}

	return fmt.Errorf("Testing value %s failed", path)
}

// Equal indicates if 2 JSON documents have the same structural equality.
func Equal(a, b []byte) bool {
	ra := make(json.RawMessage, len(a))
	copy(ra, a)
	la := newLazyNode(&ra)

	rb := make(json.RawMessage, len(b))
	copy(rb, b)
	lb := newLazyNode(&rb)

	return la.equal(lb)
}

// DecodePatch decodes the passed JSON document as an RFC 6902 patch.
func DecodePatch(buf []byte) (Patch, error) {
	var p Patch

	err := json.Unmarshal(buf, &p)

	if err != nil {
		return nil, err
	}

	return p, nil
}

// Apply mutates a JSON document according to the patch, and returns the new
// document.
func (p Patch) Apply(doc []byte) ([]byte, error) {
	res, err := p.ApplyIndent(doc, "")
	return res, err
}

// ApplyIndent mutates a JSON document according to the patch, and returns the new
// document indented.
func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
	pd := &partialDoc{}

	err := json.Unmarshal(doc, pd)

	if err != nil {
		return nil, err
	}

	err = nil

	for _, op := range p {
		switch op.kind() {
		case "add":
			err = p.add(pd, op)
		case "remove":
			err = p.remove(pd, op)
		case "replace":
			err = p.replace(pd, op)
		case "move":
			err = p.move(pd, op)
		case "test":
			err = p.test(pd, op)
		default:
			err = fmt.Errorf("Unexpected kind: %s", op.kind())
		}

		if err != nil {
			return nil, err
		}
	}

	if indent != "" {
		return json.MarshalIndent(pd, "", indent)
	}

	return json.Marshal(pd)
}
<commit_msg>Return values immediately in wrapper func<commit_after>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

const (
	eRaw = iota
	eDoc
	eAry
)

type lazyNode struct {
	raw   *json.RawMessage
	doc   partialDoc
	ary   partialArray
	which int
}

type operation map[string]*json.RawMessage

// Patch is an ordered collection of operations.
type Patch []operation

type partialDoc map[string]*lazyNode
type partialArray []*lazyNode

type container interface {
	get(key string) (*lazyNode, error)
	set(key string, val *lazyNode) error
	remove(key string) error
}

func newLazyNode(raw *json.RawMessage) *lazyNode {
	return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
}

func (n *lazyNode) MarshalJSON() ([]byte, error) {
	switch n.which {
	case eRaw:
		return *n.raw, nil
	case eDoc:
		return json.Marshal(n.doc)
	case eAry:
		return json.Marshal(n.ary)
	default:
		return nil, fmt.Errorf("Unknown type")
	}
}

func (n *lazyNode) UnmarshalJSON(data []byte) error {
	dest := make(json.RawMessage, len(data))
	copy(dest, data)
	n.raw = &dest
	n.which = eRaw
	return nil
}

func (n *lazyNode) intoDoc() (*partialDoc, error) {
	if n.which == eDoc {
		return &n.doc, nil
	}

	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return nil, err
	}

	n.which = eDoc
	return &n.doc, nil
}

func (n *lazyNode) intoAry() (*partialArray, error) {
	if n.which == eAry {
		return &n.ary, nil
	}

	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return nil, err
	}

	n.which = eAry
	return &n.ary, nil
}

func (n *lazyNode) compact() []byte {
	buf := &bytes.Buffer{}

	err := json.Compact(buf, *n.raw)

	if err != nil {
		return *n.raw
	}

	return buf.Bytes()
}

func (n *lazyNode) tryDoc() bool {
	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return false
	}

	n.which = eDoc
	return true
}

func (n *lazyNode) tryAry() bool {
	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return false
	}

	n.which = eAry
	return true
}

func (n *lazyNode) equal(o *lazyNode) bool {
	if n.which == eRaw {
		if !n.tryDoc() && !n.tryAry() {
			if o.which != eRaw {
				return false
			}

			return bytes.Equal(n.compact(), o.compact())
		}
	}

	if n.which == eDoc {
		if o.which == eRaw {
			if !o.tryDoc() {
				return false
			}
		}

		if o.which != eDoc {
			return false
		}

		for k, v := range n.doc {
			ov, ok := o.doc[k]

			if !ok {
				return false
			}

			if v == nil && ov == nil {
				continue
			}

			if !v.equal(ov) {
				return false
			}
		}

		return true
	}

	if o.which != eAry && !o.tryAry() {
		return false
	}

	if len(n.ary) != len(o.ary) {
		return false
	}

	for idx, val := range n.ary {
		if !val.equal(o.ary[idx]) {
			return false
		}
	}

	return true
}

func (o operation) kind() string {
	if obj, ok := o["op"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) path() string {
	if obj, ok := o["path"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) from() string {
	if obj, ok := o["from"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) value() *lazyNode {
	if obj, ok := o["value"]; ok {
		return newLazyNode(obj)
	}

	return nil
}

func isArray(buf []byte) bool {
Loop:
	for _, c := range buf {
		switch c {
		case ' ':
		case '\n':
		case '\t':
			continue
		case '[':
			return true
		default:
			break Loop
		}
	}

	return false
}

func findObject(pd *partialDoc, path string) (container, string) {
	doc := container(pd)

	split := strings.Split(path, "/")

	parts := split[1 : len(split)-1]

	key := split[len(split)-1]

	var err error

	for _, part := range parts {

		next, ok := doc.get(part)

		if next == nil || ok != nil {
			return nil, ""
		}

		if isArray(*next.raw) {
			doc, err = next.intoAry()

			if err != nil {
				return nil, ""
			}
		} else {
			doc, err = next.intoDoc()

			if err != nil {
				return nil, ""
			}
		}
	}

	return doc, key
}

func (d *partialDoc) set(key string, val *lazyNode) error {
	(*d)[key] = val
	return nil
}

func (d *partialDoc) get(key string) (*lazyNode, error) {
	return (*d)[key], nil
}

func (d *partialDoc) remove(key string) error {
	delete(*d, key)
	return nil
}

func (d *partialArray) set(key string, val *lazyNode) error {
	if key == "-" {
		*d = append(*d, val)
		return nil
	}

	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	ary := make([]*lazyNode, len(*d)+1)

	cur := *d

	copy(ary[0:idx], cur[0:idx])
	ary[idx] = val
	copy(ary[idx+1:], cur[idx:])

	*d = ary
	return nil
}

func (d *partialArray) get(key string) (*lazyNode, error) {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return nil, err
	}

	return (*d)[idx], nil
}

func (d *partialArray) remove(key string) error {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	cur := *d

	ary := make([]*lazyNode, len(cur)-1)

	copy(ary[0:idx], cur[0:idx])
	copy(ary[idx:], cur[idx+1:])

	*d = ary
	return nil

}

func (p Patch) add(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	if con == nil {
		return fmt.Errorf("Missing container: %s", path)
	}

	con.set(key, op.value())

	return nil
}

func (p Patch) remove(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	return con.remove(key)
}

func (p Patch) replace(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	con.set(key, op.value())

	return nil
}

func (p Patch) move(doc *partialDoc, op operation) error {
	from := op.from()

	con, key := findObject(doc, from)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	con.remove(key)

	path := op.path()

	con, key = findObject(doc, path)

	con.set(key, val)

	return nil
}

func (p Patch) test(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	if val == nil {
		if op.value().raw == nil {
			return nil
		} else {
			return fmt.Errorf("Testing value %s failed", path)
		}
	}

	if val.equal(op.value()) {
		return nil
	}

	return fmt.Errorf("Testing value %s failed", path)
}

// Equal indicates if 2 JSON documents have the same structural equality.
func Equal(a, b []byte) bool {
	ra := make(json.RawMessage, len(a))
	copy(ra, a)
	la := newLazyNode(&ra)

	rb := make(json.RawMessage, len(b))
	copy(rb, b)
	lb := newLazyNode(&rb)

	return la.equal(lb)
}

// DecodePatch decodes the passed JSON document as an RFC 6902 patch.
func DecodePatch(buf []byte) (Patch, error) {
	var p Patch

	err := json.Unmarshal(buf, &p)

	if err != nil {
		return nil, err
	}

	return p, nil
}

// Apply mutates a JSON document according to the patch, and returns the new
// document.
func (p Patch) Apply(doc []byte) ([]byte, error) {
	return p.ApplyIndent(doc, "")
}

// ApplyIndent mutates a JSON document according to the patch, and returns the new
// document indented.
func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
	pd := &partialDoc{}

	err := json.Unmarshal(doc, pd)

	if err != nil {
		return nil, err
	}

	err = nil

	for _, op := range p {
		switch op.kind() {
		case "add":
			err = p.add(pd, op)
		case "remove":
			err = p.remove(pd, op)
		case "replace":
			err = p.replace(pd, op)
		case "move":
			err = p.move(pd, op)
		case "test":
			err = p.test(pd, op)
		default:
			err = fmt.Errorf("Unexpected kind: %s", op.kind())
		}

		if err != nil {
			return nil, err
		}
	}

	if indent != "" {
		return json.MarshalIndent(pd, "", indent)
	}

	return json.Marshal(pd)
}
<|endoftext|>


<commit_before>package shadowsocks

import (
	"errors"
	"fmt"
	"os"
)

func PrintVersion() {
	const version = "0.5"
	fmt.Println("shadowsocks-go version", version)
}

func IsFileExists(path string) (bool, error) {
	stat, err := os.Stat(path)
	if err == nil {
		if stat.Mode()&os.ModeType == 0 {
			return true, nil
		}
		return false, errors.New(path + " exists but is not regular file")
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func HasPort(s string) bool {
	for i := len(s) - 1; i > 0; i-- {
		if s[i] == ':' {
			return true
		}
	}
	return false
}
<commit_msg>Bump version to 0.6<commit_after>package shadowsocks

import (
	"errors"
	"fmt"
	"os"
)

func PrintVersion() {
	const version = "0.6"
	fmt.Println("shadowsocks-go version", version)
}

func IsFileExists(path string) (bool, error) {
	stat, err := os.Stat(path)
	if err == nil {
		if stat.Mode()&os.ModeType == 0 {
			return true, nil
		}
		return false, errors.New(path + " exists but is not regular file")
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func HasPort(s string) bool {
	for i := len(s) - 1; i > 0; i-- {
		if s[i] == ':' {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package shard

import (
	"bytes"
	"hash/crc32"
	"strconv"
	"testing"
	"time"

	"h12.me/sej"
)

func BenchmarkAppend(b *testing.B) {
	path := newTestPath(b)
	w, err := NewWriter(path, 8, shardFNV)
	if err != nil {
		b.Fatal(err)
	}

	keys := make([][]byte, b.N)
	for i := range keys {
		keys[i] = []byte("key-" + strconv.Itoa(i))
	}
	value := bytes.Repeat([]byte{'a'}, 100)
	now := time.Now()
	msg := sej.Message{Value: value, Timestamp: now}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		msg.Key = keys[i]
		if err := w.Append(&msg); err != nil {
			b.Fatal(err)
		}
	}
	w.Flush()
	b.StopTimer()
	w.Close()
}

func shardCRC(msg *sej.Message) uint32 {
	return crc32.ChecksumIEEE(msg.Key)
}

func shardFNV(msg *sej.Message) uint32 {
	const (
		offset32 = 2166136261
		prime32  = 16777619
	)
	var s uint32 = offset32
	for _, c := range msg.Key {
		s ^= uint32(c)
		s *= prime32
	}
	return s
}
<commit_msg>extract timeAppend<commit_after>package shard

import (
	"bytes"
	"hash/crc32"
	"strconv"
	"testing"
	"time"

	"h12.me/sej"
)

func BenchmarkAppend(b *testing.B) {
	path := newTestPath(b)
	w, err := NewWriter(path, 8, shardFNV)
	if err != nil {
		b.Fatal(err)
	}

	keys := make([][]byte, b.N)
	for i := range keys {
		keys[i] = []byte("key-" + strconv.Itoa(i))
	}
	value := bytes.Repeat([]byte{'a'}, 100)
	now := time.Now()
	msg := sej.Message{Value: value, Timestamp: now}
	timeAppend(b, w, keys, &msg)
	w.Close()
}

func timeAppend(b *testing.B, w *Writer, keys [][]byte, msg *sej.Message) {
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		msg.Key = keys[i]
		if err := w.Append(msg); err != nil {
			b.Fatal(err)
		}
	}
	if err := w.Flush(); err != nil {
		b.Fatal(err)
	}
	b.StopTimer()

}

func shardCRC(msg *sej.Message) uint32 {
	return crc32.ChecksumIEEE(msg.Key)
}

func shardFNV(msg *sej.Message) uint32 {
	const (
		offset32 = 2166136261
		prime32  = 16777619
	)
	var s uint32 = offset32
	for _, c := range msg.Key {
		s ^= uint32(c)
		s *= prime32
	}
	return s
}
<|endoftext|>


<commit_before>package api

import (
	"time"
)

// ImagesPost represents the fields available for a new LXD image
type ImagesPost struct {
	ImagePut `yaml:",inline"`

	Filename string            `json:"filename" yaml:"filename"`
	Source   *ImagesPostSource `json:"source" yaml:"source"`

	// API extension: image_compression_algorithm
	CompressionAlgorithm string `json:"compression_algorithm" yaml:"compression_algorithm"`

	// API extension: image_create_aliases
	Aliases []ImageAlias `json:"aliases" yaml:"aliases"`
}

// ImagesPostSource represents the source of a new LXD image
type ImagesPostSource struct {
	ImageSource `yaml:",inline"`

	Mode string `json:"mode" yaml:"mode"`
	Type string `json:"type" yaml:"type"`

	// For protocol "direct"
	URL string `json:"url" yaml:"url"`

	// For type "container"
	Name string `json:"name" yaml:"name"`

	// For type "image"
	Fingerprint string `json:"fingerprint" yaml:"fingerprint"`
	Secret      string `json:"secret" yaml:"secret"`
}

// ImagePut represents the modifiable fields of a LXD image
type ImagePut struct {
	AutoUpdate bool              `json:"auto_update" yaml:"auto_update"`
	Properties map[string]string `json:"properties" yaml:"properties"`
	Public     bool              `json:"public" yaml:"public"`

	// API extension: images_expiry
	ExpiresAt time.Time `json:"expires_at" yaml:"expires_at"`

	// API extension: image_profiles
	Profiles []string `json:"profiles" yaml:"profiles"`
}

// Image represents a LXD image
type Image struct {
	ImagePut `yaml:",inline"`

	Aliases      []ImageAlias `json:"aliases" yaml:"aliases"`
	Architecture string       `json:"architecture" yaml:"architecture"`
	Cached       bool         `json:"cached" yaml:"cached"`
	Filename     string       `json:"filename" yaml:"filename"`
	Fingerprint  string       `json:"fingerprint" yaml:"fingerprint"`
	Size         int64        `json:"size" yaml:"size"`
	UpdateSource *ImageSource `json:"update_source,omitempty" yaml:"update_source,omitempty"`

	// API extension: image_types
	Type string `json:"type" yaml:"type"`

	CreatedAt  time.Time `json:"created_at" yaml:"created_at"`
	LastUsedAt time.Time `json:"last_used_at" yaml:"last_used_at"`
	UploadedAt time.Time `json:"uploaded_at" yaml:"uploaded_at"`
}

// Writable converts a full Image struct into a ImagePut struct (filters read-only fields)
func (img *Image) Writable() ImagePut {
	return img.ImagePut
}

// ImageAlias represents an alias from the alias list of a LXD image
type ImageAlias struct {
	Name        string `json:"name" yaml:"name"`
	Description string `json:"description" yaml:"description"`
}

// ImageSource represents the source of a LXD image
type ImageSource struct {
	Alias       string `json:"alias" yaml:"alias"`
	Certificate string `json:"certificate" yaml:"certificate"`
	Protocol    string `json:"protocol" yaml:"protocol"`
	Server      string `json:"server" yaml:"server"`

	// API extension: image_types
	ImageType string `json:"image_type" yaml:"image_type"`
}

// ImageAliasesPost represents a new LXD image alias
type ImageAliasesPost struct {
	ImageAliasesEntry `yaml:",inline"`
}

// ImageAliasesEntryPost represents the required fields to rename a LXD image alias
type ImageAliasesEntryPost struct {
	Name string `json:"name" yaml:"name"`
}

// ImageAliasesEntryPut represents the modifiable fields of a LXD image alias
type ImageAliasesEntryPut struct {
	Description string `json:"description" yaml:"description"`
	Target      string `json:"target" yaml:"target"`
}

// ImageAliasesEntry represents a LXD image alias
type ImageAliasesEntry struct {
	ImageAliasesEntryPut `yaml:",inline"`

	Name string `json:"name" yaml:"name"`

	// API extension: image_types
	Type string `json:"type" yaml:"type"`
}

// ImageMetadata represents LXD image metadata
type ImageMetadata struct {
	Architecture string                            `json:"architecture" yaml:"architecture"`
	CreationDate int64                             `json:"creation_date" yaml:"creation_date"`
	ExpiryDate   int64                             `json:"expiry_date" yaml:"expiry_date"`
	Properties   map[string]string                 `json:"properties" yaml:"properties"`
	Templates    map[string]*ImageMetadataTemplate `json:"templates" yaml:"templates"`
}

// ImageMetadataTemplate represents a template entry in image metadata
type ImageMetadataTemplate struct {
	When       []string          `json:"when" yaml:"when"`
	CreateOnly bool              `json:"create_only" yaml:"create_only"`
	Template   string            `json:"template" yaml:"template"`
	Properties map[string]string `json:"properties" yaml:"properties"`
}
<commit_msg>shared/api/image: Add ImageExportPost<commit_after>package api

import (
	"time"
)

// ImageExportPost represents the fields required to export a LXD image
// API extension: images_push_relay
type ImageExportPost struct {
	Target      string       `json:"target" yaml:"target"`
	Secret      string       `json:"secret" yaml:"secret"`
	Certificate string       `json:"certificate" yaml:"certificate"`
	Aliases     []ImageAlias `json:"aliases" yaml:"aliases"`
}

// ImagesPost represents the fields available for a new LXD image
type ImagesPost struct {
	ImagePut `yaml:",inline"`

	Filename string            `json:"filename" yaml:"filename"`
	Source   *ImagesPostSource `json:"source" yaml:"source"`

	// API extension: image_compression_algorithm
	CompressionAlgorithm string `json:"compression_algorithm" yaml:"compression_algorithm"`

	// API extension: image_create_aliases
	Aliases []ImageAlias `json:"aliases" yaml:"aliases"`
}

// ImagesPostSource represents the source of a new LXD image
type ImagesPostSource struct {
	ImageSource `yaml:",inline"`

	Mode string `json:"mode" yaml:"mode"`
	Type string `json:"type" yaml:"type"`

	// For protocol "direct"
	URL string `json:"url" yaml:"url"`

	// For type "container"
	Name string `json:"name" yaml:"name"`

	// For type "image"
	Fingerprint string `json:"fingerprint" yaml:"fingerprint"`
	Secret      string `json:"secret" yaml:"secret"`
}

// ImagePut represents the modifiable fields of a LXD image
type ImagePut struct {
	AutoUpdate bool              `json:"auto_update" yaml:"auto_update"`
	Properties map[string]string `json:"properties" yaml:"properties"`
	Public     bool              `json:"public" yaml:"public"`

	// API extension: images_expiry
	ExpiresAt time.Time `json:"expires_at" yaml:"expires_at"`

	// API extension: image_profiles
	Profiles []string `json:"profiles" yaml:"profiles"`
}

// Image represents a LXD image
type Image struct {
	ImagePut `yaml:",inline"`

	Aliases      []ImageAlias `json:"aliases" yaml:"aliases"`
	Architecture string       `json:"architecture" yaml:"architecture"`
	Cached       bool         `json:"cached" yaml:"cached"`
	Filename     string       `json:"filename" yaml:"filename"`
	Fingerprint  string       `json:"fingerprint" yaml:"fingerprint"`
	Size         int64        `json:"size" yaml:"size"`
	UpdateSource *ImageSource `json:"update_source,omitempty" yaml:"update_source,omitempty"`

	// API extension: image_types
	Type string `json:"type" yaml:"type"`

	CreatedAt  time.Time `json:"created_at" yaml:"created_at"`
	LastUsedAt time.Time `json:"last_used_at" yaml:"last_used_at"`
	UploadedAt time.Time `json:"uploaded_at" yaml:"uploaded_at"`
}

// Writable converts a full Image struct into a ImagePut struct (filters read-only fields)
func (img *Image) Writable() ImagePut {
	return img.ImagePut
}

// ImageAlias represents an alias from the alias list of a LXD image
type ImageAlias struct {
	Name        string `json:"name" yaml:"name"`
	Description string `json:"description" yaml:"description"`
}

// ImageSource represents the source of a LXD image
type ImageSource struct {
	Alias       string `json:"alias" yaml:"alias"`
	Certificate string `json:"certificate" yaml:"certificate"`
	Protocol    string `json:"protocol" yaml:"protocol"`
	Server      string `json:"server" yaml:"server"`

	// API extension: image_types
	ImageType string `json:"image_type" yaml:"image_type"`
}

// ImageAliasesPost represents a new LXD image alias
type ImageAliasesPost struct {
	ImageAliasesEntry `yaml:",inline"`
}

// ImageAliasesEntryPost represents the required fields to rename a LXD image alias
type ImageAliasesEntryPost struct {
	Name string `json:"name" yaml:"name"`
}

// ImageAliasesEntryPut represents the modifiable fields of a LXD image alias
type ImageAliasesEntryPut struct {
	Description string `json:"description" yaml:"description"`
	Target      string `json:"target" yaml:"target"`
}

// ImageAliasesEntry represents a LXD image alias
type ImageAliasesEntry struct {
	ImageAliasesEntryPut `yaml:",inline"`

	Name string `json:"name" yaml:"name"`

	// API extension: image_types
	Type string `json:"type" yaml:"type"`
}

// ImageMetadata represents LXD image metadata
type ImageMetadata struct {
	Architecture string                            `json:"architecture" yaml:"architecture"`
	CreationDate int64                             `json:"creation_date" yaml:"creation_date"`
	ExpiryDate   int64                             `json:"expiry_date" yaml:"expiry_date"`
	Properties   map[string]string                 `json:"properties" yaml:"properties"`
	Templates    map[string]*ImageMetadataTemplate `json:"templates" yaml:"templates"`
}

// ImageMetadataTemplate represents a template entry in image metadata
type ImageMetadataTemplate struct {
	When       []string          `json:"when" yaml:"when"`
	CreateOnly bool              `json:"create_only" yaml:"create_only"`
	Template   string            `json:"template" yaml:"template"`
	Properties map[string]string `json:"properties" yaml:"properties"`
}
<|endoftext|>


<commit_before>package task

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"reflect"

	"github.com/avabot/ava/shared/datatypes"
)

type Task struct {
	Done bool
	Err  error

	typ      string
	resultID sql.NullInt64
	ctx      *dt.Ctx
	resp     *dt.Resp
	respMsg  *dt.RespMsg
}

func New(ctx *dt.Ctx, resp *dt.Resp, respMsg *dt.RespMsg) (*Task, error) {
	if resp.State == nil {
		return &Task{}, errors.New("state nil in *dt.Resp")
	}
	return &Task{
		ctx:     ctx,
		resp:    resp,
		respMsg: respMsg,
	}, nil
}

func (t *Task) getState() float64 {
	tmp := t.resp.State[t.key()]
	if tmp == nil {
		return addressStateNone
	}
	switch tmp.(type) {
	case float64:
		return tmp.(float64)
	case uint64:
		return float64(tmp.(uint64))
	}
	log.Println("err: state was type", reflect.TypeOf(tmp))
	return 0.0
}

func (t *Task) setState(s float64) {
	t.resp.State[t.key()] = s
}

func (t *Task) ResetState() {
	t.resp.State[t.key()] = 0.0
}

func (t *Task) setInterimID(id uint64) {
	t.resp.State[t.key()] = id
}

func (t *Task) key() string {
	return fmt.Sprintf("__task%s_User%dID", t.typ, t.ctx.Msg.User.ID)
}

// getInterimID is useful when you've saved an object, but haven't finished
// modifying it, yet. For example, addresses are saved, but named after the
// fact. If we save the resultID into the task table, the task will cede control
// back to its calling package. As a result, we save the interimID in the resp
// state to keep task control.
func (t *Task) getInterimID() uint64 {
	if len(t.typ) == 0 {
		log.Println("warn: t.typ should be set but was \"\"")
	}
	key := fmt.Sprintf("__task%s_User%dID", t.typ, t.ctx.Msg.User.ID)
	switch t.resp.State[key].(type) {
	case uint64:
		return t.resp.State[key].(uint64)
	case float64:
		return uint64(t.resp.State[key].(float64))
	default:
		log.Println("warn: couldn't get interim ID: invalid type",
			reflect.TypeOf(t.resp.State[key]))
	}
	return uint64(0)
}
<commit_msg>Attempt task state fix<commit_after>package task

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"reflect"

	"github.com/avabot/ava/shared/datatypes"
)

type Task struct {
	Done bool
	Err  error

	typ      string
	resultID sql.NullInt64
	ctx      *dt.Ctx
	resp     *dt.Resp
	respMsg  *dt.RespMsg
}

func New(ctx *dt.Ctx, resp *dt.Resp, respMsg *dt.RespMsg) (*Task, error) {
	if resp.State == nil {
		return &Task{}, errors.New("state nil in *dt.Resp")
	}
	return &Task{
		ctx:     ctx,
		resp:    resp,
		respMsg: respMsg,
	}, nil
}

func (t *Task) getState() float64 {
	tmp := t.resp.State[t.key()]
	if tmp == nil {
		return addressStateNone
	}
	switch tmp.(type) {
	case float64:
		return tmp.(float64)
	case uint64:
		return float64(tmp.(uint64))
	}
	log.Println("err: state was type", reflect.TypeOf(tmp))
	return 0.0
}

func (t *Task) setState(s float64) {
	t.resp.State[t.key()] = s
}

func (t *Task) ResetState() {
	t.resp.State[t.key()] = 0.0
}

func (t *Task) setInterimID(id uint64) {
	t.resp.State[t.key()] = id
}

func (t *Task) key() string {
	return fmt.Sprintf("__task%s_UserID_%d", t.typ, t.ctx.Msg.User.ID)
}

// getInterimID is useful when you've saved an object, but haven't finished
// modifying it, yet. For example, addresses are saved, but named after the
// fact. If we save the resultID into the task table, the task will cede control
// back to its calling package. As a result, we save the interimID in the resp
// state to keep task control.
func (t *Task) getInterimID() uint64 {
	if len(t.typ) == 0 {
		log.Println("warn: t.typ should be set but was \"\"")
	}
	switch t.resp.State[t.key()].(type) {
	case uint64:
		return t.resp.State[t.key()].(uint64)
	case float64:
		return uint64(t.resp.State[t.key()].(float64))
	default:
		log.Println("warn: couldn't get interim ID: invalid type",
			reflect.TypeOf(t.resp.State[t.key()]))
	}
	return uint64(0)
}
<|endoftext|>


<commit_before>/*
copyright 2019 google llc
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 ops

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

	"github.com/google/uuid"
)

//Used for String Splitting Pre and Post Hash
const seperator string = "#!#"

type SUID struct {
	UUID          string    `json:"link"`
	Name          string    `json:"name"`
	TimeStamp     time.Time `json:"timestamp"`
	DisplayName   string    `json:"displayName"`
	DirectoryName string    `json:"directoryName"`
	DownloadId    string    `json:"downloadId"`
	// Private
	longname string
	nameHash string
}

func (s *SUID) name() string {
	return s.Name
}

func (s *SUID) hash() {
	s.nameHash = base64.StdEncoding.EncodeToString([]byte(s.longname))
}

func (s *SUID) Meta() {
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println(s.UUID)
	fmt.Println(s.Name)
	fmt.Println(s.TimeStamp)
	fmt.Println(s.DisplayName)
	fmt.Println(s.longname)
	fmt.Println(s.nameHash)
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println("")
}

func CreateSUID(customName string) SUID {

	// Create SUID Object
	suid := SUID{}
	// Assign Variables for Uniqueness
	suid.UUID = uuid.New().String()
	suid.TimeStamp = time.Now()

	// Ensure We always have a Conversion Name
	if customName == "" {
		// Configure Custom Name
		suid.Name = "Shifter Conversion"
	} else {
		// TODO Clean Name Here
		suid.Name = customName
	}

	// String Format - (Timestamp + UUID + Custom Name)
	suid.longname = fmt.Sprintf("%s%s%s%s%s", suid.TimeStamp.Format(time.RFC1123),
		seperator, suid.UUID, seperator, suid.Name)

	suid.hash()
	suid.DirectoryName = suid.nameHash
	suid.DownloadId = suid.nameHash
	suid.DisplayName = fmt.Sprintf("%s - %s", suid.TimeStamp.Format(time.RFC1123), suid.Name)
	return suid
}

func ResolveSUID(downloadId string) (SUID, error) {
	// Create New SUID Object
	suid := SUID{}
	if downloadId == "" {
		return suid, errors.New("Download ID or Filename Hash must be provided when Resolving SUID")
	}
	suid.nameHash = downloadId
	decoded, err := base64.StdEncoding.DecodeString(suid.nameHash)
	if err != nil {
		return suid, err
	}
	suid.longname = string(decoded)
	items := strings.Split(suid.longname, seperator)
	t, err := time.Parse(time.RFC1123, items[0])
	if err != nil {
		return suid, err
	}
	suid.TimeStamp = t
	suid.UUID = items[1]
	suid.Name = items[2]
	suid.DisplayName = fmt.Sprintf("%s - %s", suid.TimeStamp.Format(time.RFC1123), suid.Name)
	suid.DirectoryName = suid.nameHash
	suid.DownloadId = suid.DirectoryName
	return suid, nil

}
<commit_msg>Landed the encoding of conversion objects metadata into foldername<commit_after>/*
copyright 2019 google llc
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 ops

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

	"github.com/google/uuid"
)

//Used for String Splitting Pre and Post Hash
const seperator string = "#!#"

type SUID struct {
<<<<<<< HEAD
	UUID          string    `json:"link"`
	Name          string    `json:"name"`
	TimeStamp     time.Time `json:"timestamp"`
	DisplayName   string    `json:"displayName"`
	DirectoryName string    `json:"directoryName"`
	DownloadId    string    `json:"downloadId"`
	// Private
	longname string
	nameHash string
=======
	UUID        string    `json:"link"`
	Name        string    `json:"name"`
	TimeStamp   time.Time `json:"timestamp"`
	DisplayName string    `json:"displayName"`
	// Private
	longname    string
	nameHash    string
	OutLongname string
>>>>>>> 85e899b (Landed the encoding of conversion objects metadata into foldername)
}

func (s *SUID) name() string {
	return s.Name
}

func (s *SUID) hash() {
	s.nameHash = base64.StdEncoding.EncodeToString([]byte(s.longname))
}

func (s *SUID) Meta() {
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println(s.UUID)
	fmt.Println(s.Name)
	fmt.Println(s.TimeStamp)
	fmt.Println(s.DisplayName)
	fmt.Println(s.longname)
	fmt.Println(s.nameHash)
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println("_+_+_+_+_+_+_+_+_+_+_+_+_+_")
	fmt.Println("")
}

func CreateSUID(customName string) SUID {

	// Create SUID Object
	suid := SUID{}
	// Assign Variables for Uniqueness
	suid.UUID = uuid.New().String()
	suid.TimeStamp = time.Now()

	// Ensure We always have a Conversion Name
	if customName == "" {
		// Configure Custom Name
		suid.Name = "Shifter Conversion"
	} else {
		// TODO Clean Name Here
		suid.Name = customName
	}

	// String Format - (Timestamp + UUID + Custom Name)
	suid.longname = fmt.Sprintf("%s%s%s%s%s", suid.TimeStamp.Format(time.RFC1123),
		seperator, suid.UUID, seperator, suid.Name)

	suid.hash()
<<<<<<< HEAD
	suid.DirectoryName = suid.nameHash
	suid.DownloadId = suid.nameHash
	suid.DisplayName = fmt.Sprintf("%s - %s", suid.TimeStamp.Format(time.RFC1123), suid.Name)
	return suid
}

func ResolveSUID(downloadId string) (SUID, error) {
	// Create New SUID Object
	suid := SUID{}
	if downloadId == "" {
		return suid, errors.New("Download ID or Filename Hash must be provided when Resolving SUID")
	}
	suid.nameHash = downloadId
	decoded, err := base64.StdEncoding.DecodeString(suid.nameHash)
=======

	suid.OutLongname = suid.nameHash
	return suid
}

func ResolveSUID(hash string) (SUID, error) {
	// Create New SUID Object
	suid := SUID{}
	if hash == "" {
		return suid, errors.New("Filename Hash must be provided when Resolving SUID")
	}
	suid.nameHash = hash
	decoded, err := base64.StdEncoding.DecodeString(hash)
>>>>>>> 85e899b (Landed the encoding of conversion objects metadata into foldername)
	if err != nil {
		return suid, err
	}
	suid.longname = string(decoded)
	items := strings.Split(suid.longname, seperator)
	t, err := time.Parse(time.RFC1123, items[0])
	if err != nil {
		return suid, err
	}
	suid.TimeStamp = t
	suid.UUID = items[1]
	suid.Name = items[2]
<<<<<<< HEAD
	suid.DisplayName = fmt.Sprintf("%s - %s", suid.TimeStamp.Format(time.RFC1123), suid.Name)
	suid.DirectoryName = suid.nameHash
	suid.DownloadId = suid.DirectoryName
=======

>>>>>>> 85e899b (Landed the encoding of conversion objects metadata into foldername)
	return suid, nil

}
<|endoftext|>


<commit_before>package sockjs

import (
	"fmt"
	"net/http"
	"strings"

	"golang.org/x/net/websocket"
)

var (
	wsServer = websocket.Server{Handler: wsHandler, Handshake: WSHandshake}
	handlers = make(map[*http.Request]*handler)
)

func wsHandler(conn *websocket.Conn) {
	req := conn.Request()

	h, ok := handlers[req]
	if ok {
		delete(handlers, req)
	} else {
		conn.Close()
		return
	}

	sessID, _ := h.parseSessionID(req.URL)
	sess := newSession(sessID, h.options.DisconnectDelay, h.options.HeartbeatDelay)

	if h.handlerFunc != nil {
		go h.handlerFunc(sess)
	}

	receiver := newWsReceiver(conn)
	sess.attachReceiver(receiver)
	readCloseCh := make(chan struct{})

	go func() {
		for {
			var d []string
			if err := websocket.JSON.Receive(conn, &d); err != nil {
				close(readCloseCh)
				return
			}

			sess.accept(d...)
		}
	}()

	select {
	case <-readCloseCh:
	case <-receiver.doneNotify():
	}

	conn.Close()
	sess.close()
}

func WSHandshake(config *websocket.Config, req *http.Request) error {
	// accept all connections by default
	return nil
}

func (h *handler) sockjsWebsocket(rw http.ResponseWriter, req *http.Request) {
	handlers[req] = h
	wsServer.ServeHTTP(rw, req)
}

type wsReceiver struct {
	conn    *websocket.Conn
	closeCh chan struct{}
}

func newWsReceiver(conn *websocket.Conn) *wsReceiver {
	return &wsReceiver{
		conn:    conn,
		closeCh: make(chan struct{}),
	}
}

func (w *wsReceiver) sendBulk(messages ...string) {
	if len(messages) > 0 {
		str := fmt.Sprintf("a[%s]", strings.Join(transform(messages, quote), ","))
		w.sendFrame(str)
	}
}

func (w *wsReceiver) sendFrame(frame string) {
	bytes := []byte(frame)
	if _, err := w.conn.Write(bytes); err != nil {
		w.close()
	}
}

func (w *wsReceiver) close() {
	select {
	case <-w.closeCh: // already closed
	default:
		close(w.closeCh)
	}
}

func (w *wsReceiver) canSend() bool {
	select {
	case <-w.closeCh: // already closed
		return false
	default:
		return true
	}
}

func (w *wsReceiver) doneNotify() <-chan struct{} {
	return w.closeCh
}

func (w *wsReceiver) interruptedNotify() <-chan struct{} {
	return nil
}
<commit_msg>Get `WSHandshake` form user<commit_after>package sockjs

import (
	"fmt"
	"net/http"
	"strings"

	"golang.org/x/net/websocket"
)

var (
	WSHandshake func(config *websocket.Config, req *http.Request) error
	wsServer    = websocket.Server{Handler: wsHandler, Handshake: handshake}
	handlers    = make(map[*http.Request]*handler)
)

func wsHandler(conn *websocket.Conn) {
	req := conn.Request()

	h, ok := handlers[req]
	if ok {
		delete(handlers, req)
	} else {
		conn.Close()
		return
	}

	sessID, _ := h.parseSessionID(req.URL)
	sess := newSession(sessID, h.options.DisconnectDelay, h.options.HeartbeatDelay)

	if h.handlerFunc != nil {
		go h.handlerFunc(sess)
	}

	receiver := newWsReceiver(conn)
	sess.attachReceiver(receiver)
	readCloseCh := make(chan struct{})

	go func() {
		for {
			var d []string
			if err := websocket.JSON.Receive(conn, &d); err != nil {
				close(readCloseCh)
				return
			}

			sess.accept(d...)
		}
	}()

	select {
	case <-readCloseCh:
	case <-receiver.doneNotify():
	}

	conn.Close()
	sess.close()
}

func handshake(config *websocket.Config, req *http.Request) error {
	if WSHandshake != nil {
		return WSHandshake(config, req)
	} else {
		// accept all connections by default
		return nil
	}
}

func (h *handler) sockjsWebsocket(rw http.ResponseWriter, req *http.Request) {
	handlers[req] = h
	wsServer.ServeHTTP(rw, req)
}

type wsReceiver struct {
	conn    *websocket.Conn
	closeCh chan struct{}
}

func newWsReceiver(conn *websocket.Conn) *wsReceiver {
	return &wsReceiver{
		conn:    conn,
		closeCh: make(chan struct{}),
	}
}

func (w *wsReceiver) sendBulk(messages ...string) {
	if len(messages) > 0 {
		str := fmt.Sprintf("a[%s]", strings.Join(transform(messages, quote), ","))
		w.sendFrame(str)
	}
}

func (w *wsReceiver) sendFrame(frame string) {
	bytes := []byte(frame)
	if _, err := w.conn.Write(bytes); err != nil {
		w.close()
	}
}

func (w *wsReceiver) close() {
	select {
	case <-w.closeCh: // already closed
	default:
		close(w.closeCh)
	}
}

func (w *wsReceiver) canSend() bool {
	select {
	case <-w.closeCh: // already closed
		return false
	default:
		return true
	}
}

func (w *wsReceiver) doneNotify() <-chan struct{} {
	return w.closeCh
}

func (w *wsReceiver) interruptedNotify() <-chan struct{} {
	return nil
}
<|endoftext|>


<commit_before>package cmd

// Version defines the current Pop version.
const Version = "v4.6.2"
<commit_msg>Bump version<commit_after>package cmd

// Version defines the current Pop version.
const Version = "v4.6.3"
<|endoftext|>


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

package na

import (
	"fmt"
	"testing"
	"time"

	"istio.io/istio/pkg/log"
	"istio.io/istio/security/pkg/caclient"
	"istio.io/istio/security/pkg/caclient/protocol"
	"istio.io/istio/security/pkg/platform"
	mockpc "istio.io/istio/security/pkg/platform/mock"
	"istio.io/istio/security/pkg/util"
	mockutil "istio.io/istio/security/pkg/util/mock"
	pb "istio.io/istio/security/proto"
)

func TestStartWithArgs(t *testing.T) {
	generalConfig := Config{
		CAClientConfig: caclient.Config{
			CAAddress:  "ca_addr",
			Org:        "Google Inc.",
			RSAKeySize: 512,
			Env:        "onprem",
			CSRInitialRetrialInterval: time.Millisecond,
			CSRMaxRetries:             3,
			CSRGracePeriodPercentage:  50,
			RootCertFile:              "ca_file",
			KeyFile:                   "pkey",
			CertChainFile:             "cert_file",
		},
		LoggingOptions: log.DefaultOptions(),
	}
	signedCert := []byte(`TESTCERT`)
	certChain := []byte(`CERTCHAIN`)
	testCases := map[string]struct {
		config      *Config
		pc          platform.Client
		caProtocol  *protocol.FakeProtocol
		certUtil    util.CertUtil
		expectedErr string
		sendTimes   int
		fileContent []byte
	}{
		"Success": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(&pb.CsrResponse{IsApproved: true, SignedCert: signedCert, CertChain: certChain}, ""),
			certUtil:    mockutil.FakeCertUtil{time.Duration(0), nil},
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   12,
			fileContent: append(signedCert, certChain...),
		},
		"Config Nil error": {
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "node Agent configuration is nil",
			sendTimes:   0,
		},
		"Platform error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", false},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "node Agent is not running on the right platform",
			sendTimes:   0,
		},
		"Create CSR error": {
			// 128 is too small for a RSA private key. GenCSR will return error.

			config: &Config{
				CAClientConfig: caclient.Config{
					CAAddress:  "ca_addr",
					Org:        "Google Inc.",
					RSAKeySize: 128,
					Env:        "onprem",
					CSRInitialRetrialInterval: time.Millisecond,
					CSRMaxRetries:             3,
					CSRGracePeriodPercentage:  50,
					RootCertFile:              "ca_file",
					KeyFile:                   "pkey",
					CertChainFile:             "cert_file",
				},
				LoggingOptions: log.DefaultOptions(),
			},
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "CSR creation failed (crypto/rsa: message too long for RSA public key size)",
			sendTimes:   0,
		},
		"Getting agent credential error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", nil, "Err1", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "request creation fails on getting agent credential (Err1)",
			sendTimes:   0,
		},
		"SendCSR empty response error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
		"SendCSR returns error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, "error returned from CA"),
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
		"SendCSR not approved": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(&pb.CsrResponse{IsApproved: false}, ""),
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
		"SendCSR parsing error": {
			config: &generalConfig,
			pc:     mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol: protocol.NewFakeProtocol(&pb.CsrResponse{
				IsApproved: true, SignedCert: signedCert, CertChain: []byte{},
			}, ""),
			certUtil:    mockutil.FakeCertUtil{time.Duration(0), fmt.Errorf("cert parsing error")},
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
	}

	for id, c := range testCases {
		log.Errorf("Start to test %s", id)
		na := nodeAgentInternal{c.config, c.pc, c.caProtocol, "service1", c.certUtil}
		err := na.Start()
		if err.Error() != c.expectedErr {
			t.Errorf("Test case [%s]: incorrect error message: %s VS (expected) %s", id, err.Error(), c.expectedErr)
		}
		if got := c.caProtocol.InvokeTimes(); got != c.sendTimes {
			t.Errorf("Test case [%s]: sendCSR is called incorrect times: %d VS (expected) %d",
				id, got, c.sendTimes)
		}
		// TODO(incfly): add check to compare fileContent equals to the saved secrets after we can read from SecretServer.
	}
}
<commit_msg>Clean up files generated by node agent unit tests. (#4807)<commit_after>// Copyright 2017 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package na

import (
	"fmt"
	"os"
	"testing"
	"time"

	"istio.io/istio/pkg/log"
	"istio.io/istio/security/pkg/caclient"
	"istio.io/istio/security/pkg/caclient/protocol"
	"istio.io/istio/security/pkg/platform"
	mockpc "istio.io/istio/security/pkg/platform/mock"
	"istio.io/istio/security/pkg/util"
	mockutil "istio.io/istio/security/pkg/util/mock"
	pb "istio.io/istio/security/proto"
)

func TestStartWithArgs(t *testing.T) {
	generalConfig := Config{
		CAClientConfig: caclient.Config{
			CAAddress:  "ca_addr",
			Org:        "Google Inc.",
			RSAKeySize: 512,
			Env:        "onprem",
			CSRInitialRetrialInterval: time.Millisecond,
			CSRMaxRetries:             3,
			CSRGracePeriodPercentage:  50,
			RootCertFile:              "ca_file",
			KeyFile:                   "pkey",
			CertChainFile:             "cert_file",
		},
		LoggingOptions: log.DefaultOptions(),
	}
	defer func() {
		_ = os.Remove(generalConfig.CAClientConfig.RootCertFile)
		_ = os.Remove(generalConfig.CAClientConfig.KeyFile)
		_ = os.Remove(generalConfig.CAClientConfig.CertChainFile)
	}()
	signedCert := []byte(`TESTCERT`)
	certChain := []byte(`CERTCHAIN`)
	testCases := map[string]struct {
		config      *Config
		pc          platform.Client
		caProtocol  *protocol.FakeProtocol
		certUtil    util.CertUtil
		expectedErr string
		sendTimes   int
		fileContent []byte
	}{
		"Success": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(&pb.CsrResponse{IsApproved: true, SignedCert: signedCert, CertChain: certChain}, ""),
			certUtil:    mockutil.FakeCertUtil{time.Duration(0), nil},
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   12,
			fileContent: append(signedCert, certChain...),
		},
		"Config Nil error": {
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "node Agent configuration is nil",
			sendTimes:   0,
		},
		"Platform error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", false},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "node Agent is not running on the right platform",
			sendTimes:   0,
		},
		"Create CSR error": {
			// 128 is too small for a RSA private key. GenCSR will return error.

			config: &Config{
				CAClientConfig: caclient.Config{
					CAAddress:  "ca_addr",
					Org:        "Google Inc.",
					RSAKeySize: 128,
					Env:        "onprem",
					CSRInitialRetrialInterval: time.Millisecond,
					CSRMaxRetries:             3,
					CSRGracePeriodPercentage:  50,
					RootCertFile:              "ca_file",
					KeyFile:                   "pkey",
					CertChainFile:             "cert_file",
				},
				LoggingOptions: log.DefaultOptions(),
			},
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "CSR creation failed (crypto/rsa: message too long for RSA public key size)",
			sendTimes:   0,
		},
		"Getting agent credential error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", nil, "Err1", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "request creation fails on getting agent credential (Err1)",
			sendTimes:   0,
		},
		"SendCSR empty response error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, ""),
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
		"SendCSR returns error": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(nil, "error returned from CA"),
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
		"SendCSR not approved": {
			config:      &generalConfig,
			pc:          mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol:  protocol.NewFakeProtocol(&pb.CsrResponse{IsApproved: false}, ""),
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
		"SendCSR parsing error": {
			config: &generalConfig,
			pc:     mockpc.FakeClient{nil, "", "service1", "", []byte{}, "", true},
			caProtocol: protocol.NewFakeProtocol(&pb.CsrResponse{
				IsApproved: true, SignedCert: signedCert, CertChain: []byte{},
			}, ""),
			certUtil:    mockutil.FakeCertUtil{time.Duration(0), fmt.Errorf("cert parsing error")},
			expectedErr: "node agent can't get the CSR approved from Istio CA after max number of retries (3)",
			sendTimes:   4,
		},
	}

	for id, c := range testCases {
		log.Errorf("Start to test %s", id)
		na := nodeAgentInternal{c.config, c.pc, c.caProtocol, "service1", c.certUtil}
		err := na.Start()
		if err.Error() != c.expectedErr {
			t.Errorf("Test case [%s]: incorrect error message: %s VS (expected) %s", id, err.Error(), c.expectedErr)
		}
		if got := c.caProtocol.InvokeTimes(); got != c.sendTimes {
			t.Errorf("Test case [%s]: sendCSR is called incorrect times: %d VS (expected) %d",
				id, got, c.sendTimes)
		}
		// TODO(incfly): add check to compare fileContent equals to the saved secrets after we can read from SecretServer.
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Tigera, 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 ut_test

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path"
	"testing"

	"github.com/projectcalico/felix/idalloc"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	. "github.com/onsi/gomega"

	"github.com/projectcalico/felix/dataplane/linux"
)

func TestCompileTemplateRun(tt *testing.T) {
	t := NewWithT(tt)

	tempDir, err := ioutil.TempDir("", "calico-bpf-")
	t.Expect(err).NotTo(HaveOccurred())

	defer os.RemoveAll(tempDir)

	unique := path.Base(tempDir)
	bpfFsDir := "/sys/fs/bpf/" + unique

	err = os.Mkdir(bpfFsDir, os.ModePerm)
	t.Expect(err).NotTo(HaveOccurred())

	defer os.RemoveAll(bpfFsDir)

	objFname := tempDir + "/redir_tc.o"

	err = intdataplane.CompileTCProgramToFile(nil,
		idalloc.New(),
		intdataplane.CompileWithBpftoolLoader(),
		intdataplane.CompileWithWorkingDir("../xdp"),
		intdataplane.CompileWithSourceName("../xdp/redir_tc.c"),
		intdataplane.CompileWithOutputName(objFname),
		intdataplane.CompileWithFIBEnabled(true),
		intdataplane.CompileWithLogLevel("DEBUG"),
		intdataplane.CompileWithLogPrefix("COMPILE_TEST"),
	)
	t.Expect(err).NotTo(HaveOccurred())

	err = bpftoolProgLoadAll(objFname, bpfFsDir)
	t.Expect(err).NotTo(HaveOccurred())

	dataInFname := tempDir + "/data_in"

	payload := []byte("ABCDEABCDEXXXXXXXXXXXX")
	pkt := gopacket.NewSerializeBuffer()
	err = gopacket.SerializeLayers(pkt, gopacket.SerializeOptions{},
		&layers.Ethernet{
			// zeroed MACs, does not matter
			SrcMAC:       []byte{0, 0, 0, 0, 0, 1},
			DstMAC:       []byte{0, 0, 0, 0, 0, 2},
			EthernetType: layers.EthernetTypeIPv4,
		},
		&layers.IPv4{
			SrcIP:    net.IPv4(1, 1, 1, 1),
			DstIP:    net.IPv4(2, 2, 2, 2),
			Protocol: layers.IPProtocolUDP,
		},
		&layers.UDP{
			SrcPort: 1234,
			DstPort: 5678,
			Length:  uint16(len(payload)),
		},
		gopacket.Payload(payload),
	)
	t.Expect(err).NotTo(HaveOccurred())

	err = ioutil.WriteFile(dataInFname, pkt.Bytes(), 0644)
	t.Expect(err).NotTo(HaveOccurred())

	res, err := bpftoolProgRun(bpfFsDir+"/calico_to_workload_ep", dataInFname)
	t.Expect(err).NotTo(HaveOccurred())

	// Implicitly denied by normal policy: DROP
	t.Expect(res.Retval).To(Equal(2))
}

func bpftool(args ...string) ([]byte, error) {
	args = append([]string{"--json", "--pretty"}, args...)
	cmd := exec.Command("bpftool", args...)
	return cmd.Output()
}

func bpftoolProgLoadAll(fname, bpfFsDir string) error {
	_, err := bpftool("prog", "loadall", fname, bpfFsDir, "type", "classifier")
	return err
}

type runResult struct {
	Retval   int
	Duration int
}

func bpftoolProgRun(progName, dataInFname string) (runResult, error) {
	var res runResult

	out, err := bpftool("prog", "run", "pinned", progName, "data_in", dataInFname)
	if err != nil {
		return res, err
	}

	err = json.Unmarshal(out, &res)

	return res, err
}
<commit_msg>Improve BPF UT diags.<commit_after>// Copyright (c) 2019 Tigera, 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 ut_test

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path"
	"testing"

	"github.com/projectcalico/felix/idalloc"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	. "github.com/onsi/gomega"

	"github.com/projectcalico/felix/dataplane/linux"
)

func TestCompileTemplateRun(tt *testing.T) {
	t := NewWithT(tt)

	tempDir, err := ioutil.TempDir("", "calico-bpf-")
	t.Expect(err).NotTo(HaveOccurred())

	defer os.RemoveAll(tempDir)

	unique := path.Base(tempDir)
	bpfFsDir := "/sys/fs/bpf/" + unique

	err = os.Mkdir(bpfFsDir, os.ModePerm)
	t.Expect(err).NotTo(HaveOccurred())

	defer os.RemoveAll(bpfFsDir)

	objFname := tempDir + "/redir_tc.o"

	err = intdataplane.CompileTCProgramToFile(nil,
		idalloc.New(),
		intdataplane.CompileWithBpftoolLoader(),
		intdataplane.CompileWithWorkingDir("../xdp"),
		intdataplane.CompileWithSourceName("../xdp/redir_tc.c"),
		intdataplane.CompileWithOutputName(objFname),
		intdataplane.CompileWithFIBEnabled(true),
		intdataplane.CompileWithLogLevel("DEBUG"),
		intdataplane.CompileWithLogPrefix("COMPILE_TEST"),
	)
	t.Expect(err).NotTo(HaveOccurred())

	err = bpftoolProgLoadAll(objFname, bpfFsDir)
	if err != nil {
		tt.Log("Error:", string(err.(*exec.ExitError).Stderr))
	}
	t.Expect(err).NotTo(HaveOccurred())

	dataInFname := tempDir + "/data_in"

	payload := []byte("ABCDEABCDEXXXXXXXXXXXX")
	pkt := gopacket.NewSerializeBuffer()
	err = gopacket.SerializeLayers(pkt, gopacket.SerializeOptions{},
		&layers.Ethernet{
			// zeroed MACs, does not matter
			SrcMAC:       []byte{0, 0, 0, 0, 0, 1},
			DstMAC:       []byte{0, 0, 0, 0, 0, 2},
			EthernetType: layers.EthernetTypeIPv4,
		},
		&layers.IPv4{
			SrcIP:    net.IPv4(1, 1, 1, 1),
			DstIP:    net.IPv4(2, 2, 2, 2),
			Protocol: layers.IPProtocolUDP,
		},
		&layers.UDP{
			SrcPort: 1234,
			DstPort: 5678,
			Length:  uint16(len(payload)),
		},
		gopacket.Payload(payload),
	)
	t.Expect(err).NotTo(HaveOccurred())

	err = ioutil.WriteFile(dataInFname, pkt.Bytes(), 0644)
	t.Expect(err).NotTo(HaveOccurred())

	res, err := bpftoolProgRun(bpfFsDir+"/calico_to_workload_ep", dataInFname)
	t.Expect(err).NotTo(HaveOccurred())

	// Implicitly denied by normal policy: DROP
	t.Expect(res.Retval).To(Equal(2))
}

func bpftool(args ...string) ([]byte, error) {
	args = append([]string{"--json", "--pretty"}, args...)
	cmd := exec.Command("bpftool", args...)
	return cmd.Output()
}

func bpftoolProgLoadAll(fname, bpfFsDir string) error {
	_, err := bpftool("prog", "loadall", fname, bpfFsDir, "type", "classifier")
	return err
}

type runResult struct {
	Retval   int
	Duration int
}

func bpftoolProgRun(progName, dataInFname string) (runResult, error) {
	var res runResult

	out, err := bpftool("prog", "run", "pinned", progName, "data_in", dataInFname)
	if err != nil {
		return res, err
	}

	err = json.Unmarshal(out, &res)

	return res, err
}
<|endoftext|>


<commit_before>/*
This is a example to get the actual temperature from the Temperature Bricklet
and print it on the command line.
This is a very simple example.
It should only show the basic structure of a implementation with the bricker api.
You need the bricker api code.
  go get github.com/dirkjabl/bricker
*/
package main

import (
	"flag"
	"fmt"
	"github.com/dirkjabl/bricker"
	"github.com/dirkjabl/bricker/connector/buffered"
	"github.com/dirkjabl/bricker/device/bricklet/temperature"
)

func main() {
	// flag used here to get the needed parameter
	var addr = flag.String("addr", "localhost:4223",
		"address of the brickd, default is localhost:4223")
	var uid = flag.Int("uid", 42362,
		"UId of the Temperature Bricklet, here exists no useful default")

	// Create a bricker object
	brick := bricker.New()
	defer brick.Done() // later for stopping the bricker

	// create a connection to a real brick stack
	conn, err := buffered.NewUnbuffered(*addr)
	if err != nil { // no connection, no temperature
		fmt.Printf("No connection: %s\n", err.Error())
		return
	}
	defer conn.Done() // later for stopping current connection

	// attach the connector to the bricker
	err = brick.Attach(conn, "local") // local is the name for this connection
	if err != nil {                   // no bricker, no fun
		fmt.Printf("Could not attach connection to bricker: %s\n", err.Error())
		return
	}
	defer brick.Release("local") // later to release connection from bricker

	// Call a subscriber for getting the temperature from the bricklet.
	// In this example it is the future version, so it get the temperature or nil
	// and it waits (synchron) for the notify (callback).
	temp := temperature.GetTemperatureFuture(brick, "local", uint32(*uid))
	if temp != nil { // only if a result exists, it is a pointer(!)
		fmt.Printf("Temperature: %02.02f °C\n", temp.Float64())
	}

	// if you defer not like (?)
	// brick.Release("local") // release connection from bricker
	// conn.Done() // close the connection
	// brick.Done() // stop the bricker
	// That's all folks...
}
<commit_msg>more documentation<commit_after>/*
This is a example to get the actual temperature from the Temperature Bricklet
and print it on the command line.
This is a very simple example.
It should only show the basic structure of a implementation with the bricker api.

To run this example, you should have a Temperature Bricklet and a connection to it
(USB, Ethernet, WLAN) with a running brickd.
This example does not test, if the bricklet exists.
When no bricklet exists it waits forever.

You need the bricker api code.
  go get github.com/dirkjabl/bricker
*/
package main

import (
	"flag"
	"fmt"
	"github.com/dirkjabl/bricker"
	"github.com/dirkjabl/bricker/connector/buffered"
	"github.com/dirkjabl/bricker/device/bricklet/temperature"
)

func main() {
	// flag used here to get the needed parameter
	var addr = flag.String("addr", "localhost:4223",
		"address of the brickd, default is localhost:4223")
	var uid = flag.Int("uid", 42362,
		"UId of the Temperature Bricklet, here exists no useful default")

	// Create a bricker object
	brick := bricker.New()
	defer brick.Done() // later for stopping the bricker

	// create a connection to a real brick stack
	conn, err := buffered.NewUnbuffered(*addr)
	if err != nil { // no connection, no temperature
		fmt.Printf("No connection: %s\n", err.Error())
		return
	}
	defer conn.Done() // later for stopping current connection

	// attach the connector to the bricker
	err = brick.Attach(conn, "local") // local is the name for this connection
	if err != nil {                   // no bricker, no fun
		fmt.Printf("Could not attach connection to bricker: %s\n", err.Error())
		return
	}
	defer brick.Release("local") // later to release connection from bricker

	// Call a subscriber for getting the temperature from the bricklet.
	// In this example it is the future version, so it get the temperature or nil
	// and it waits (synchron) for the notify (callback).
	temp := temperature.GetTemperatureFuture(brick, "local", uint32(*uid))
	if temp != nil { // only if a result exists, it is a pointer(!)
		fmt.Printf("Temperature: %02.02f °C\n", temp.Float64())
	}

	// if you defer not like (?)
	// brick.Release("local") // release connection from bricker
	// conn.Done() // close the connection
	// brick.Done() // stop the bricker
	// That's all folks...
}
<|endoftext|>


<commit_before>package helper

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/sirupsen/logrus"
)

func DownloadFile(url string) (*[]byte, error) {
	return DownloadFileAuth(url, "")
}

func DownloadFileAuth(url string, auth string) (*[]byte, error) {
	var buf bytes.Buffer
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	req, err := http.NewRequest("GET", url, nil)
	if auth != "" {
		req.Header.Add("Authorization", auth)
	}
	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	io.Copy(&buf, resp.Body)
	data := buf.Bytes()
	return &data, nil
}

func SplitStringLength(input string, length int) string {
	a := []rune(input)
	str := ""
	for i, r := range a {
		str = str + string(r)
		if i > 0 && (i+1)%length == 0 {
			str += "\n"
		}
	}
	return str
}

// handle all the stuff we put into extra
func HandleExtra(msg *config.Message, general *config.Protocol) []config.Message {
	extra := msg.Extra
	rmsg := []config.Message{}
	if len(extra[config.EVENT_FILE_FAILURE_SIZE]) > 0 {
		for _, f := range extra[config.EVENT_FILE_FAILURE_SIZE] {
			fi := f.(config.FileInfo)
			text := fmt.Sprintf("file %s too big to download (%#v > allowed size: %#v)", fi.Name, fi.Size, general.MediaDownloadSize)
			rmsg = append(rmsg, config.Message{Text: text, Username: "<system> ", Channel: msg.Channel})
		}
		return rmsg
	}
	return rmsg
}

func GetAvatar(av map[string]string, userid string, general *config.Protocol) string {
	if sha, ok := av[userid]; ok {
		return general.MediaServerDownload + "/" + sha + "/" + userid + ".png"
	}
	return ""
}

func HandleDownloadSize(flog *log.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error {
	// check blacklist here
	for _, entry := range general.MediaDownloadBlackList {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(name) {
				return fmt.Errorf("Matching blacklist %s. Not downloading %s", entry, name)
			}
		}
	}
	flog.Debugf("Trying to download %#v with size %#v", name, size)
	if int(size) > general.MediaDownloadSize {
		msg.Event = config.EVENT_FILE_FAILURE_SIZE
		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{Name: name, Comment: msg.Text, Size: size})
		return fmt.Errorf("File %#v to large to download (%#v). MediaDownloadSize is %#v", name, size, general.MediaDownloadSize)
	}
	return nil
}

func HandleDownloadData(flog *log.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
	var avatar bool
	flog.Debugf("Download OK %#v %#v", name, len(*data))
	if msg.Event == config.EVENT_AVATAR_DOWNLOAD {
		avatar = true
	}
	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: name, Data: data, URL: url, Comment: comment, Avatar: avatar})
}

func RemoveEmptyNewLines(msg string) string {
	lines := ""
	for _, line := range strings.Split(msg, "\n") {
		if line != "" {
			lines += line + "\n"
		}
	}
	lines = strings.TrimRight(lines, "\n")
	return lines
}
<commit_msg>Fix possible panic. #448<commit_after>package helper

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/sirupsen/logrus"
)

func DownloadFile(url string) (*[]byte, error) {
	return DownloadFileAuth(url, "")
}

func DownloadFileAuth(url string, auth string) (*[]byte, error) {
	var buf bytes.Buffer
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	req, err := http.NewRequest("GET", url, nil)
	if auth != "" {
		req.Header.Add("Authorization", auth)
	}
	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	io.Copy(&buf, resp.Body)
	data := buf.Bytes()
	return &data, nil
}

func SplitStringLength(input string, length int) string {
	a := []rune(input)
	str := ""
	for i, r := range a {
		str = str + string(r)
		if i > 0 && (i+1)%length == 0 {
			str += "\n"
		}
	}
	return str
}

// handle all the stuff we put into extra
func HandleExtra(msg *config.Message, general *config.Protocol) []config.Message {
	extra := msg.Extra
	rmsg := []config.Message{}
	if len(extra[config.EVENT_FILE_FAILURE_SIZE]) > 0 {
		for _, f := range extra[config.EVENT_FILE_FAILURE_SIZE] {
			fi := f.(config.FileInfo)
			text := fmt.Sprintf("file %s too big to download (%#v > allowed size: %#v)", fi.Name, fi.Size, general.MediaDownloadSize)
			rmsg = append(rmsg, config.Message{Text: text, Username: "<system> ", Channel: msg.Channel, Account: msg.Account})
		}
		return rmsg
	}
	return rmsg
}

func GetAvatar(av map[string]string, userid string, general *config.Protocol) string {
	if sha, ok := av[userid]; ok {
		return general.MediaServerDownload + "/" + sha + "/" + userid + ".png"
	}
	return ""
}

func HandleDownloadSize(flog *log.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error {
	// check blacklist here
	for _, entry := range general.MediaDownloadBlackList {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(name) {
				return fmt.Errorf("Matching blacklist %s. Not downloading %s", entry, name)
			}
		}
	}
	flog.Debugf("Trying to download %#v with size %#v", name, size)
	if int(size) > general.MediaDownloadSize {
		msg.Event = config.EVENT_FILE_FAILURE_SIZE
		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{Name: name, Comment: msg.Text, Size: size})
		return fmt.Errorf("File %#v to large to download (%#v). MediaDownloadSize is %#v", name, size, general.MediaDownloadSize)
	}
	return nil
}

func HandleDownloadData(flog *log.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
	var avatar bool
	flog.Debugf("Download OK %#v %#v", name, len(*data))
	if msg.Event == config.EVENT_AVATAR_DOWNLOAD {
		avatar = true
	}
	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: name, Data: data, URL: url, Comment: comment, Avatar: avatar})
}

func RemoveEmptyNewLines(msg string) string {
	lines := ""
	for _, line := range strings.Split(msg, "\n") {
		if line != "" {
			lines += line + "\n"
		}
	}
	lines = strings.TrimRight(lines, "\n")
	return lines
}
<|endoftext|>


<commit_before>package helper

import (
	"bytes"
	"fmt"
	"image/png"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"
	"unicode/utf8"

	"golang.org/x/image/webp"

	"github.com/42wim/matterbridge/bridge/config"
	"github.com/gomarkdown/markdown"
	"github.com/gomarkdown/markdown/html"
	"github.com/gomarkdown/markdown/parser"
	"github.com/sirupsen/logrus"
)

// DownloadFile downloads the given non-authenticated URL.
func DownloadFile(url string) (*[]byte, error) {
	return DownloadFileAuth(url, "")
}

// DownloadFileAuth downloads the given URL using the specified authentication token.
func DownloadFileAuth(url string, auth string) (*[]byte, error) {
	var buf bytes.Buffer
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	req, err := http.NewRequest("GET", url, nil)
	if auth != "" {
		req.Header.Add("Authorization", auth)
	}
	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	io.Copy(&buf, resp.Body)
	data := buf.Bytes()
	return &data, nil
}

// DownloadFileAuthRocket downloads the given URL using the specified Rocket user ID and authentication token.
func DownloadFileAuthRocket(url, token, userID string) (*[]byte, error) {
	var buf bytes.Buffer
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	req, err := http.NewRequest("GET", url, nil)

	req.Header.Add("X-Auth-Token", token)
	req.Header.Add("X-User-Id", userID)

	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	_, err = io.Copy(&buf, resp.Body)
	data := buf.Bytes()
	return &data, err
}

// GetSubLines splits messages in newline-delimited lines. If maxLineLength is
// specified as non-zero GetSubLines will also clip long lines to the maximum
// length and insert a warning marker that the line was clipped.
//
// TODO: The current implementation has the inconvenient that it disregards
// word boundaries when splitting but this is hard to solve without potentially
// breaking formatting and other stylistic effects.
func GetSubLines(message string, maxLineLength int) []string {
	const clippingMessage = " <clipped message>"

	var lines []string
	for _, line := range strings.Split(strings.TrimSpace(message), "\n") {
		if maxLineLength == 0 || len([]byte(line)) <= maxLineLength {
			lines = append(lines, line)
			continue
		}

		// !!! WARNING !!!
		// Before touching the splitting logic below please ensure that you PROPERLY
		// understand how strings, runes and range loops over strings work in Go.
		// A good place to start is to read https://blog.golang.org/strings. :-)
		var splitStart int
		var startOfPreviousRune int
		for i := range line {
			if i-splitStart > maxLineLength-len([]byte(clippingMessage)) {
				lines = append(lines, line[splitStart:startOfPreviousRune]+clippingMessage)
				splitStart = startOfPreviousRune
			}
			startOfPreviousRune = i
		}
		// This last append is safe to do without looking at the remaining byte-length
		// as we assume that the byte-length of the last rune will never exceed that of
		// the byte-length of the clipping message.
		lines = append(lines, line[splitStart:])
	}
	return lines
}

// HandleExtra manages the supplementary details stored inside a message's 'Extra' field map.
func HandleExtra(msg *config.Message, general *config.Protocol) []config.Message {
	extra := msg.Extra
	rmsg := []config.Message{}
	for _, f := range extra[config.EventFileFailureSize] {
		fi := f.(config.FileInfo)
		text := fmt.Sprintf("file %s too big to download (%#v > allowed size: %#v)", fi.Name, fi.Size, general.MediaDownloadSize)
		rmsg = append(rmsg, config.Message{
			Text:     text,
			Username: "<system> ",
			Channel:  msg.Channel,
			Account:  msg.Account,
		})
	}
	return rmsg
}

// GetAvatar constructs a URL for a given user-avatar if it is available in the cache.
func GetAvatar(av map[string]string, userid string, general *config.Protocol) string {
	if sha, ok := av[userid]; ok {
		return general.MediaServerDownload + "/" + sha + "/" + userid + ".png"
	}
	return ""
}

// HandleDownloadSize checks a specified filename against the configured download blacklist
// and checks a specified file-size against the configure limit.
func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error {
	// check blacklist here
	for _, entry := range general.MediaDownloadBlackList {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				logger.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(name) {
				return fmt.Errorf("Matching blacklist %s. Not downloading %s", entry, name)
			}
		}
	}
	logger.Debugf("Trying to download %#v with size %#v", name, size)
	if int(size) > general.MediaDownloadSize {
		msg.Event = config.EventFileFailureSize
		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{
			Name:    name,
			Comment: msg.Text,
			Size:    size,
		})
		return fmt.Errorf("File %#v to large to download (%#v). MediaDownloadSize is %#v", name, size, general.MediaDownloadSize)
	}
	return nil
}

// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
func HandleDownloadData(logger *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
	var avatar bool
	logger.Debugf("Download OK %#v %#v", name, len(*data))
	if msg.Event == config.EventAvatarDownload {
		avatar = true
	}
	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{
		Name:    name,
		Data:    data,
		URL:     url,
		Comment: comment,
		Avatar:  avatar,
	})
}

var emptyLineMatcher = regexp.MustCompile("\n+")

// RemoveEmptyNewLines collapses consecutive newline characters into a single one and
// trims any preceding or trailing newline characters as well.
func RemoveEmptyNewLines(msg string) string {
	return emptyLineMatcher.ReplaceAllString(strings.Trim(msg, "\n"), "\n")
}

// ClipMessage trims a message to the specified length if it exceeds it and adds a warning
// to the message in case it does so.
func ClipMessage(text string, length int) string {
	const clippingMessage = " <clipped message>"
	if len(text) > length {
		text = text[:length-len(clippingMessage)]
		if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError {
			text = text[:len(text)-size]
		}
		text += clippingMessage
	}
	return text
}

// ParseMarkdown takes in an input string as markdown and parses it to html
func ParseMarkdown(input string) string {
	extensions := parser.HardLineBreak | parser.NoIntraEmphasis | parser.FencedCode
	markdownParser := parser.NewWithExtensions(extensions)
	renderer := html.NewRenderer(html.RendererOptions{
		Flags: 0,
	})
	parsedMarkdown := markdown.ToHTML([]byte(input), markdownParser, renderer)
	res := string(parsedMarkdown)
	res = strings.TrimPrefix(res, "
")
	res = strings.TrimSuffix(res, "
\n")
	return res
}

// ConvertWebPToPNG converts input data (which should be WebP format) to PNG format
func ConvertWebPToPNG(data *[]byte) error {
	r := bytes.NewReader(*data)
	m, err := webp.Decode(r)
	if err != nil {
		return err
	}
	var output []byte
	w := bytes.NewBuffer(output)
	if err := png.Encode(w, m); err != nil {
		return err
	}
	*data = w.Bytes()
	return nil
}

// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
func CanConvertTgsToX() error {
	// We depend on the fact that `lottie_convert.py --help` has exit status 0.
	// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
	// However, there is no alternative like `lottie_convert.py --is-properly-installed`
	cmd := exec.Command("lottie_convert.py", "--help")
	return cmd.Run()
}

// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
// This relies on an external command, which is ugly, but works.
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
	// lottie can't handle input from a pipe, so write to a temporary file:
	tmpFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-*.tgs")
	if err != nil {
		return err
	}
	tmpFileName := tmpFile.Name()
	defer func() {
		if removeErr := os.Remove(tmpFileName); removeErr != nil {
			logger.Errorf("Could not delete temporary file %s: %v", tmpFileName, removeErr)
		}
	}()

	if _, writeErr := tmpFile.Write(*data); writeErr != nil {
		return writeErr
	}
	// Must close before calling lottie to avoid data races:
	if closeErr := tmpFile.Close(); closeErr != nil {
		return closeErr
	}

	// Call lottie to transform:
	cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpFileName, "/dev/stdout")
	cmd.Stderr = nil
	// NB: lottie writes progress into to stderr in all cases.
	stdout, stderr := cmd.Output()
	if stderr != nil {
		// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
		return stderr
	}

	*data = stdout
	return nil
}
<commit_msg>Make lottie_convert work on platforms without /dev/stdout (#1424)<commit_after>package helper

import (
	"bytes"
	"fmt"
	"image/png"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"
	"unicode/utf8"

	"golang.org/x/image/webp"

	"github.com/42wim/matterbridge/bridge/config"
	"github.com/gomarkdown/markdown"
	"github.com/gomarkdown/markdown/html"
	"github.com/gomarkdown/markdown/parser"
	"github.com/sirupsen/logrus"
)

// DownloadFile downloads the given non-authenticated URL.
func DownloadFile(url string) (*[]byte, error) {
	return DownloadFileAuth(url, "")
}

// DownloadFileAuth downloads the given URL using the specified authentication token.
func DownloadFileAuth(url string, auth string) (*[]byte, error) {
	var buf bytes.Buffer
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	req, err := http.NewRequest("GET", url, nil)
	if auth != "" {
		req.Header.Add("Authorization", auth)
	}
	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	io.Copy(&buf, resp.Body)
	data := buf.Bytes()
	return &data, nil
}

// DownloadFileAuthRocket downloads the given URL using the specified Rocket user ID and authentication token.
func DownloadFileAuthRocket(url, token, userID string) (*[]byte, error) {
	var buf bytes.Buffer
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	req, err := http.NewRequest("GET", url, nil)

	req.Header.Add("X-Auth-Token", token)
	req.Header.Add("X-User-Id", userID)

	if err != nil {
		return nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	_, err = io.Copy(&buf, resp.Body)
	data := buf.Bytes()
	return &data, err
}

// GetSubLines splits messages in newline-delimited lines. If maxLineLength is
// specified as non-zero GetSubLines will also clip long lines to the maximum
// length and insert a warning marker that the line was clipped.
//
// TODO: The current implementation has the inconvenient that it disregards
// word boundaries when splitting but this is hard to solve without potentially
// breaking formatting and other stylistic effects.
func GetSubLines(message string, maxLineLength int) []string {
	const clippingMessage = " <clipped message>"

	var lines []string
	for _, line := range strings.Split(strings.TrimSpace(message), "\n") {
		if maxLineLength == 0 || len([]byte(line)) <= maxLineLength {
			lines = append(lines, line)
			continue
		}

		// !!! WARNING !!!
		// Before touching the splitting logic below please ensure that you PROPERLY
		// understand how strings, runes and range loops over strings work in Go.
		// A good place to start is to read https://blog.golang.org/strings. :-)
		var splitStart int
		var startOfPreviousRune int
		for i := range line {
			if i-splitStart > maxLineLength-len([]byte(clippingMessage)) {
				lines = append(lines, line[splitStart:startOfPreviousRune]+clippingMessage)
				splitStart = startOfPreviousRune
			}
			startOfPreviousRune = i
		}
		// This last append is safe to do without looking at the remaining byte-length
		// as we assume that the byte-length of the last rune will never exceed that of
		// the byte-length of the clipping message.
		lines = append(lines, line[splitStart:])
	}
	return lines
}

// HandleExtra manages the supplementary details stored inside a message's 'Extra' field map.
func HandleExtra(msg *config.Message, general *config.Protocol) []config.Message {
	extra := msg.Extra
	rmsg := []config.Message{}
	for _, f := range extra[config.EventFileFailureSize] {
		fi := f.(config.FileInfo)
		text := fmt.Sprintf("file %s too big to download (%#v > allowed size: %#v)", fi.Name, fi.Size, general.MediaDownloadSize)
		rmsg = append(rmsg, config.Message{
			Text:     text,
			Username: "<system> ",
			Channel:  msg.Channel,
			Account:  msg.Account,
		})
	}
	return rmsg
}

// GetAvatar constructs a URL for a given user-avatar if it is available in the cache.
func GetAvatar(av map[string]string, userid string, general *config.Protocol) string {
	if sha, ok := av[userid]; ok {
		return general.MediaServerDownload + "/" + sha + "/" + userid + ".png"
	}
	return ""
}

// HandleDownloadSize checks a specified filename against the configured download blacklist
// and checks a specified file-size against the configure limit.
func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error {
	// check blacklist here
	for _, entry := range general.MediaDownloadBlackList {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				logger.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(name) {
				return fmt.Errorf("Matching blacklist %s. Not downloading %s", entry, name)
			}
		}
	}
	logger.Debugf("Trying to download %#v with size %#v", name, size)
	if int(size) > general.MediaDownloadSize {
		msg.Event = config.EventFileFailureSize
		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{
			Name:    name,
			Comment: msg.Text,
			Size:    size,
		})
		return fmt.Errorf("File %#v to large to download (%#v). MediaDownloadSize is %#v", name, size, general.MediaDownloadSize)
	}
	return nil
}

// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
func HandleDownloadData(logger *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
	var avatar bool
	logger.Debugf("Download OK %#v %#v", name, len(*data))
	if msg.Event == config.EventAvatarDownload {
		avatar = true
	}
	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{
		Name:    name,
		Data:    data,
		URL:     url,
		Comment: comment,
		Avatar:  avatar,
	})
}

var emptyLineMatcher = regexp.MustCompile("\n+")

// RemoveEmptyNewLines collapses consecutive newline characters into a single one and
// trims any preceding or trailing newline characters as well.
func RemoveEmptyNewLines(msg string) string {
	return emptyLineMatcher.ReplaceAllString(strings.Trim(msg, "\n"), "\n")
}

// ClipMessage trims a message to the specified length if it exceeds it and adds a warning
// to the message in case it does so.
func ClipMessage(text string, length int) string {
	const clippingMessage = " <clipped message>"
	if len(text) > length {
		text = text[:length-len(clippingMessage)]
		if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError {
			text = text[:len(text)-size]
		}
		text += clippingMessage
	}
	return text
}

// ParseMarkdown takes in an input string as markdown and parses it to html
func ParseMarkdown(input string) string {
	extensions := parser.HardLineBreak | parser.NoIntraEmphasis | parser.FencedCode
	markdownParser := parser.NewWithExtensions(extensions)
	renderer := html.NewRenderer(html.RendererOptions{
		Flags: 0,
	})
	parsedMarkdown := markdown.ToHTML([]byte(input), markdownParser, renderer)
	res := string(parsedMarkdown)
	res = strings.TrimPrefix(res, "
")
	res = strings.TrimSuffix(res, "
\n")
	return res
}

// ConvertWebPToPNG converts input data (which should be WebP format) to PNG format
func ConvertWebPToPNG(data *[]byte) error {
	r := bytes.NewReader(*data)
	m, err := webp.Decode(r)
	if err != nil {
		return err
	}
	var output []byte
	w := bytes.NewBuffer(output)
	if err := png.Encode(w, m); err != nil {
		return err
	}
	*data = w.Bytes()
	return nil
}

// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
func CanConvertTgsToX() error {
	// We depend on the fact that `lottie_convert.py --help` has exit status 0.
	// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
	// However, there is no alternative like `lottie_convert.py --is-properly-installed`
	cmd := exec.Command("lottie_convert.py", "--help")
	return cmd.Run()
}

// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
// This relies on an external command, which is ugly, but works.
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
	// lottie can't handle input from a pipe, so write to a temporary file:
	tmpInFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-input-*.tgs")
	if err != nil {
		return err
	}
	tmpInFileName := tmpInFile.Name()
	defer func() {
		if removeErr := os.Remove(tmpInFileName); removeErr != nil {
			logger.Errorf("Could not delete temporary (input) file %s: %v", tmpInFileName, removeErr)
		}
	}()
	// lottie can handle writing to a pipe, but there is no way to do that platform-independently.
	// "/dev/stdout" won't work on Windows, and "-" upsets Cairo for some reason. So we need another file:
	tmpOutFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-output-*.data")
	if err != nil {
		return err
	}
	tmpOutFileName := tmpOutFile.Name()
	defer func() {
		if removeErr := os.Remove(tmpOutFileName); removeErr != nil {
			logger.Errorf("Could not delete temporary (output) file %s: %v", tmpOutFileName, removeErr)
		}
	}()

	if _, writeErr := tmpInFile.Write(*data); writeErr != nil {
		return writeErr
	}
	// Must close before calling lottie to avoid data races:
	if closeErr := tmpInFile.Close(); closeErr != nil {
		return closeErr
	}

	// Call lottie to transform:
	cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpInFileName, tmpOutFileName)
	cmd.Stdout = nil
	cmd.Stderr = nil
	// NB: lottie writes progress into to stderr in all cases.
	_, stderr := cmd.Output()
	if stderr != nil {
		// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
		return stderr
	}
	dataContents, err := ioutil.ReadFile(tmpOutFileName)
	if err != nil {
		return err
	}

	*data = dataContents
	return nil
}
<|endoftext|>


<commit_before>package brokers

import (
	"fmt"
	"os"

	"github.com/eddyzags/kafkactl/api/client"

	"github.com/olekukonko/tablewriter"
)

func List(api client.APIClient, all bool) error {
	brokers, err := api.BrokerList()
	if err != nil {
		return err
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetAutoFormatHeaders(false)
	table.SetAutoWrapText(false)
	if all {
		table.SetHeader([]string{"ID", "ACTIVE", "STATE", "CPUS", "MEM", "HEAP", "HOSTNAME", "ENDPOINT"})
		for _, broker := range brokers {
			table.Append([]string{
				broker.ID,
				broker.Active,
				broker.State,
				fmt.Sprintf("%g", broker.Cpus),
				fmt.Sprintf("%g", broker.Mem),
				fmt.Sprintf("%g", broker.Heap),
				broker.Task.Hostname,
				broker.Task.Endpoint,
			})
		}
	} else {
		table.SetHeader([]string{"ID", "STATE", "CPUS", "MEM", "HEAP", "HOSTNAME", "ENDPOINT"})
		for _, broker := range brokers {
			if broker.Active != true {
				continue
			}

			table.Append([]string{
				broker.ID,
				broker.State,
				fmt.Sprintf("%g", broker.Cpus),
				fmt.Sprintf("%g", broker.Mem),
				fmt.Sprintf("%g", broker.Heap),
				broker.Task.Hostname,
				broker.Task.Endpoint,
			})
		}
	}

	table.Render()

	return nil
}
<commit_msg>brokers: List running & stoppted broker handling implemented<commit_after>package brokers

import (
	"fmt"
	"os"

	"github.com/eddyzags/kafkactl/api/client"

	"github.com/olekukonko/tablewriter"
)

func List(api client.APIClient, all bool) error {
	brokers, err := api.BrokerList()
	if err != nil {
		return err
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetAutoFormatHeaders(false)
	table.SetAutoWrapText(false)
	if all {
		table.SetHeader([]string{"ID", "HOSTNAME", "ACTIVE", "STATE", "CPUS", "MEM", "HEAP", "ENDPOINT"})
		for _, broker := range brokers {
			if broker.Active == true {
				table.Append([]string{
					broker.ID,
					broker.Task.Hostname,
					fmt.Sprintf("%t", broker.Active),
					broker.Task.State,
					fmt.Sprintf("%g", broker.Cpus),
					fmt.Sprintf("%g", broker.Mem),
					fmt.Sprintf("%g", broker.Heap),
					broker.Task.Endpoint,
				})
			} else {
				table.Append([]string{
					broker.ID,
					"n/a",
					fmt.Sprintf("%t", broker.Active),
					"stopped",
					fmt.Sprintf("%g", broker.Cpus),
					fmt.Sprintf("%g", broker.Mem),
					fmt.Sprintf("%g", broker.Heap),
					"n/a",
				})
			}
		}
	} else {
		table.SetHeader([]string{"ID", "HOSTNAME", "STATE", "CPUS", "MEM", "HEAP", "ENDPOINT"})
		for _, broker := range brokers {
			if broker.Active != true {
				continue
			}

			table.Append([]string{
				broker.ID,
				broker.Task.Hostname,
				broker.Task.State,
				fmt.Sprintf("%g", broker.Cpus),
				fmt.Sprintf("%g", broker.Mem),
				fmt.Sprintf("%g", broker.Heap),
				broker.Task.Endpoint,
			})
		}
	}

	table.Render()

	return nil
}
<|endoftext|>