<commit_before>/*
Copyright 2011 Google Inc.

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.
*/

// Usage:
//
// Writes to stdout by default:
//   camget BLOBREF
//
// Like curl, lets you set output file/directory with -o:
//   camget -o dir BLOBREF     (if dir exists and is directory, BLOBREF must be a directory, and -f to overwrite any files)
//   camget -o file  BLOBREF
//
// Should be possible to get a directory JSON blob without recursively
// fetching an entire directory.  Likewise with files.  But default
// should be sensitive on the type of the listed blob.  Maybe --blob
// just to get the blob?  Seems consistent.

package main

import (
	"camli/blobref"
	"camli/client"
	"flag"
	"io"
	"log"
	"os"
	"strings"
)

var flagVerbose *bool = flag.Bool("verbose", false, "be verbose")

var flagCheck *bool = flag.Bool("check", false, "just check for the existence of listed blobs; returning 0 if all our present")
var flagOutput *string = flag.String("o", "-", "Output file/directory to create.  Use -f to overwrite.")
var flagVia *string = flag.String("via", "", "Fetch the blob via the given comma-separated sharerefs (dev only).")

func main() {
	flag.Parse()

	client := client.NewOrFail()
	if *flagCheck {
		// Simply do HEAD requests checking if the blobs exists.
		return
	}

	var w io.Writer = os.Stdout

	for n := 0; n < flag.NArg(); n++ {
		arg := flag.Arg(n)
		br := blobref.Parse(arg)
		if br == nil {
			log.Fatalf("Failed to parse argument \"%s\" as a blobref.", arg)
		}
		if *flagVerbose {
			log.Printf("Need to fetch %s", br.String())
		}
		var (
			r blobref.ReadSeekCloser
			err os.Error
		)

		if len(*flagVia) > 0 {
			vs := strings.Split(*flagVia, ",", -1)
			abr := make([]*blobref.BlobRef, len(vs))
			for i, sbr := range vs {
				abr[i] = blobref.Parse(sbr)
				if abr[i] == nil {
					log.Fatalf("Invalid -via blobref: %q", sbr)
				}
				if *flagVerbose {
					log.Printf("via: %s", sbr)
				}
			}
			r, _, err = client.FetchVia(br, abr)
		} else {
			r, _, err = client.Fetch(br)
		}
		if err != nil {
			log.Fatalf("Failed to fetch %q: %s", br, err)
		}
		_, err = io.Copy(w, r)
		if err != nil {
			log.Fatalf("Failed transferring %q: %s", br, err)
		}
	}

}
<commit_msg>camget: only require a ReadCloser.<commit_after>/*
Copyright 2011 Google Inc.

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.
*/

// Usage:
//
// Writes to stdout by default:
//   camget BLOBREF
//
// Like curl, lets you set output file/directory with -o:
//   camget -o dir BLOBREF     (if dir exists and is directory, BLOBREF must be a directory, and -f to overwrite any files)
//   camget -o file  BLOBREF
//
// Should be possible to get a directory JSON blob without recursively
// fetching an entire directory.  Likewise with files.  But default
// should be sensitive on the type of the listed blob.  Maybe --blob
// just to get the blob?  Seems consistent.

package main

import (
	"camli/blobref"
	"camli/client"
	"flag"
	"io"
	"log"
	"os"
	"strings"
)

var flagVerbose *bool = flag.Bool("verbose", false, "be verbose")

var flagCheck *bool = flag.Bool("check", false, "just check for the existence of listed blobs; returning 0 if all our present")
var flagOutput *string = flag.String("o", "-", "Output file/directory to create.  Use -f to overwrite.")
var flagVia *string = flag.String("via", "", "Fetch the blob via the given comma-separated sharerefs (dev only).")

func main() {
	flag.Parse()

	client := client.NewOrFail()
	if *flagCheck {
		// Simply do HEAD requests checking if the blobs exists.
		return
	}

	var w io.Writer = os.Stdout

	for n := 0; n < flag.NArg(); n++ {
		arg := flag.Arg(n)
		br := blobref.Parse(arg)
		if br == nil {
			log.Fatalf("Failed to parse argument \"%s\" as a blobref.", arg)
		}
		if *flagVerbose {
			log.Printf("Need to fetch %s", br.String())
		}
		var (
			r io.ReadCloser
			err os.Error
		)

		if len(*flagVia) > 0 {
			vs := strings.Split(*flagVia, ",", -1)
			abr := make([]*blobref.BlobRef, len(vs))
			for i, sbr := range vs {
				abr[i] = blobref.Parse(sbr)
				if abr[i] == nil {
					log.Fatalf("Invalid -via blobref: %q", sbr)
				}
				if *flagVerbose {
					log.Printf("via: %s", sbr)
				}
			}
			r, _, err = client.FetchVia(br, abr)
		} else {
			r, _, err = client.FetchStreaming(br)
		}
		if err != nil {
			log.Fatalf("Failed to fetch %q: %s", br, err)
		}
		defer r.Close()
		_, err = io.Copy(w, r)
		if err != nil {
			log.Fatalf("Failed transferring %q: %s", br, err)
		}
	}

}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd 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 concurrency

import (
	v3 "github.com/coreos/etcd/clientv3"
	"golang.org/x/net/context"
)

// STM is an interface for software transactional memory.
type STM interface {
	// Get returns the value for a key and inserts the key in the txn's read set.
	// If Get fails, it aborts the transaction with an error, never returning.
	Get(key string) string
	// Put adds a value for a key to the write set.
	Put(key, val string, opts ...v3.OpOption)
	// Rev returns the revision of a key in the read set.
	Rev(key string) int64
	// Del deletes a key.
	Del(key string)

	// commit attempts to apply the txn's changes to the server.
	commit() *v3.TxnResponse
	reset()
}

// stmError safely passes STM errors through panic to the STM error channel.
type stmError struct{ err error }

// NewSTMRepeatable initiates new repeatable read transaction; reads within
// the same transaction attempt always return the same data.
func NewSTMRepeatable(ctx context.Context, c *v3.Client, apply func(STM) error) (*v3.TxnResponse, error) {
	s := &stm{client: c, ctx: ctx, getOpts: []v3.OpOption{v3.WithSerializable()}}
	return runSTM(s, apply)
}

// NewSTMSerializable initiates a new serialized transaction; reads within the
// same transactiona attempt return data from the revision of the first read.
func NewSTMSerializable(ctx context.Context, c *v3.Client, apply func(STM) error) (*v3.TxnResponse, error) {
	s := &stmSerializable{
		stm:      stm{client: c, ctx: ctx},
		prefetch: make(map[string]*v3.GetResponse),
	}
	return runSTM(s, apply)
}

// NewSTMReadCommitted initiates a new read committed transaction.
func NewSTMReadCommitted(ctx context.Context, c *v3.Client, apply func(STM) error) (*v3.TxnResponse, error) {
	s := &stmReadCommitted{stm{client: c, ctx: ctx, getOpts: []v3.OpOption{v3.WithSerializable()}}}
	return runSTM(s, apply)
}

type stmResponse struct {
	resp *v3.TxnResponse
	err  error
}

func runSTM(s STM, apply func(STM) error) (*v3.TxnResponse, error) {
	outc := make(chan stmResponse, 1)
	go func() {
		defer func() {
			if r := recover(); r != nil {
				e, ok := r.(stmError)
				if !ok {
					// client apply panicked
					panic(r)
				}
				outc <- stmResponse{nil, e.err}
			}
		}()
		var out stmResponse
		for {
			s.reset()
			if out.err = apply(s); out.err != nil {
				break
			}
			if out.resp = s.commit(); out.resp != nil {
				break
			}
		}
		outc <- out
	}()
	r := <-outc
	return r.resp, r.err
}

// stm implements repeatable-read software transactional memory over etcd
type stm struct {
	client *v3.Client
	ctx    context.Context
	// rset holds read key values and revisions
	rset map[string]*v3.GetResponse
	// wset holds overwritten keys and their values
	wset map[string]stmPut
	// getOpts are the opts used for gets
	getOpts []v3.OpOption
}

type stmPut struct {
	val string
	op  v3.Op
}

func (s *stm) Get(key string) string {
	if wv, ok := s.wset[key]; ok {
		return wv.val
	}
	return respToValue(s.fetch(key))
}

func (s *stm) Put(key, val string, opts ...v3.OpOption) {
	s.wset[key] = stmPut{val, v3.OpPut(key, val, opts...)}
}

func (s *stm) Del(key string) { s.wset[key] = stmPut{"", v3.OpDelete(key)} }

func (s *stm) Rev(key string) int64 {
	if resp := s.fetch(key); resp != nil && len(resp.Kvs) != 0 {
		return resp.Kvs[0].ModRevision
	}
	return 0
}

func (s *stm) commit() *v3.TxnResponse {
	txnresp, err := s.client.Txn(s.ctx).If(s.cmps()...).Then(s.puts()...).Commit()
	if err != nil {
		panic(stmError{err})
	}
	if txnresp.Succeeded {
		return txnresp
	}
	return nil
}

// cmps guards the txn from updates to read set
func (s *stm) cmps() []v3.Cmp {
	cmps := make([]v3.Cmp, 0, len(s.rset))
	for k, rk := range s.rset {
		cmps = append(cmps, isKeyCurrent(k, rk))
	}
	return cmps
}

func (s *stm) fetch(key string) *v3.GetResponse {
	if resp, ok := s.rset[key]; ok {
		return resp
	}
	resp, err := s.client.Get(s.ctx, key, s.getOpts...)
	if err != nil {
		panic(stmError{err})
	}
	s.rset[key] = resp
	return resp
}

// puts is the list of ops for all pending writes
func (s *stm) puts() []v3.Op {
	puts := make([]v3.Op, 0, len(s.wset))
	for _, v := range s.wset {
		puts = append(puts, v.op)
	}
	return puts
}

func (s *stm) reset() {
	s.rset = make(map[string]*v3.GetResponse)
	s.wset = make(map[string]stmPut)
}

type stmSerializable struct {
	stm
	prefetch map[string]*v3.GetResponse
}

func (s *stmSerializable) Get(key string) string {
	if wv, ok := s.wset[key]; ok {
		return wv.val
	}
	firstRead := len(s.rset) == 0
	if resp, ok := s.prefetch[key]; ok {
		delete(s.prefetch, key)
		s.rset[key] = resp
	}
	resp := s.stm.fetch(key)
	if firstRead {
		// txn's base revision is defined by the first read
		s.getOpts = []v3.OpOption{
			v3.WithRev(resp.Header.Revision),
			v3.WithSerializable(),
		}
	}
	return respToValue(resp)
}

func (s *stmSerializable) Rev(key string) int64 {
	s.Get(key)
	return s.stm.Rev(key)
}

func (s *stmSerializable) gets() ([]string, []v3.Op) {
	keys := make([]string, 0, len(s.rset))
	ops := make([]v3.Op, 0, len(s.rset))
	for k := range s.rset {
		keys = append(keys, k)
		ops = append(ops, v3.OpGet(k))
	}
	return keys, ops
}

func (s *stmSerializable) commit() *v3.TxnResponse {
	keys, getops := s.gets()
	txn := s.client.Txn(s.ctx).If(s.cmps()...).Then(s.puts()...)
	// use Else to prefetch keys in case of conflict to save a round trip
	txnresp, err := txn.Else(getops...).Commit()
	if err != nil {
		panic(stmError{err})
	}
	if txnresp.Succeeded {
		return txnresp
	}
	// load prefetch with Else data
	for i := range keys {
		resp := txnresp.Responses[i].GetResponseRange()
		s.rset[keys[i]] = (*v3.GetResponse)(resp)
	}
	s.prefetch = s.rset
	s.getOpts = nil
	return nil
}

type stmReadCommitted struct{ stm }

// commit always goes through when read committed
func (s *stmReadCommitted) commit() *v3.TxnResponse {
	s.rset = nil
	return s.stm.commit()
}

func isKeyCurrent(k string, r *v3.GetResponse) v3.Cmp {
	if len(r.Kvs) != 0 {
		return v3.Compare(v3.ModRevision(k), "=", r.Kvs[0].ModRevision)
	}
	return v3.Compare(v3.ModRevision(k), "=", 0)
}

func respToValue(resp *v3.GetResponse) string {
	if len(resp.Kvs) == 0 {
		return ""
	}
	return string(resp.Kvs[0].Value)
}
<commit_msg>concurrency: variadic stm options<commit_after>// Copyright 2016 The etcd 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 concurrency

import (
	v3 "github.com/coreos/etcd/clientv3"
	"golang.org/x/net/context"
)

// STM is an interface for software transactional memory.
type STM interface {
	// Get returns the value for a key and inserts the key in the txn's read set.
	// If Get fails, it aborts the transaction with an error, never returning.
	Get(key string) string
	// Put adds a value for a key to the write set.
	Put(key, val string, opts ...v3.OpOption)
	// Rev returns the revision of a key in the read set.
	Rev(key string) int64
	// Del deletes a key.
	Del(key string)

	// commit attempts to apply the txn's changes to the server.
	commit() *v3.TxnResponse
	reset()
}

// Isolation is an enumeration of transactional isolation levels which
// describes how transactions should interfere and conflict.
type Isolation int

const (
	// Snapshot is serializable but also checks writes for conflicts.
	Snapshot Isolation = iota
	// Serializable reads within the same transactiona attempt return data
	// from the at the revision of the first read.
	Serializable
	// RepeatableReads reads within the same transaction attempt always
	// return the same data.
	RepeatableReads
	// ReadCommitted reads keys from any committed revision.
	ReadCommitted
)

// stmError safely passes STM errors through panic to the STM error channel.
type stmError struct{ err error }

type stmOptions struct {
	iso Isolation
	ctx       context.Context
}

type stmOption func(*stmOptions)

// WithIsolation specifies the transaction isolation level.
func WithIsolation(lvl Isolation) stmOption {
	return func(so *stmOptions) { so.iso = lvl }
}

// WithAbortContext specifies the context for permanently aborting the transaction.
func WithAbortContext(ctx context.Context) stmOption {
	return func(so *stmOptions) { so.ctx = ctx }
}

// NewSTM initiates a new STM instance.
func NewSTM(c *v3.Client, apply func(STM) error, so ...stmOption) (*v3.TxnResponse, error) {
	opts := &stmOptions{ctx: c.Ctx()}
	for _, f := range so {
		f(opts)
	}
	var s STM
	switch opts.iso {
	case Serializable:
		s = &stmSerializable{
			stm:      stm{client: c, ctx: opts.ctx},
			prefetch: make(map[string]*v3.GetResponse),
		}
	case RepeatableReads:
		s = &stm{client: c, ctx: opts.ctx, getOpts: []v3.OpOption{v3.WithSerializable()}}
	case ReadCommitted:
		ss := stm{client: c, ctx: opts.ctx, getOpts: []v3.OpOption{v3.WithSerializable()}}
		s = &stmReadCommitted{ss}
	default:
		panic("unsupported")
	}
	return runSTM(s, apply)
}

type stmResponse struct {
	resp *v3.TxnResponse
	err  error
}

func runSTM(s STM, apply func(STM) error) (*v3.TxnResponse, error) {
	outc := make(chan stmResponse, 1)
	go func() {
		defer func() {
			if r := recover(); r != nil {
				e, ok := r.(stmError)
				if !ok {
					// client apply panicked
					panic(r)
				}
				outc <- stmResponse{nil, e.err}
			}
		}()
		var out stmResponse
		for {
			s.reset()
			if out.err = apply(s); out.err != nil {
				break
			}
			if out.resp = s.commit(); out.resp != nil {
				break
			}
		}
		outc <- out
	}()
	r := <-outc
	return r.resp, r.err
}

// stm implements repeatable-read software transactional memory over etcd
type stm struct {
	client *v3.Client
	ctx    context.Context
	// rset holds read key values and revisions
	rset map[string]*v3.GetResponse
	// wset holds overwritten keys and their values
	wset map[string]stmPut
	// getOpts are the opts used for gets
	getOpts []v3.OpOption
}

type stmPut struct {
	val string
	op  v3.Op
}

func (s *stm) Get(key string) string {
	if wv, ok := s.wset[key]; ok {
		return wv.val
	}
	return respToValue(s.fetch(key))
}

func (s *stm) Put(key, val string, opts ...v3.OpOption) {
	s.wset[key] = stmPut{val, v3.OpPut(key, val, opts...)}
}

func (s *stm) Del(key string) { s.wset[key] = stmPut{"", v3.OpDelete(key)} }

func (s *stm) Rev(key string) int64 {
	if resp := s.fetch(key); resp != nil && len(resp.Kvs) != 0 {
		return resp.Kvs[0].ModRevision
	}
	return 0
}

func (s *stm) commit() *v3.TxnResponse {
	txnresp, err := s.client.Txn(s.ctx).If(s.cmps()...).Then(s.puts()...).Commit()
	if err != nil {
		panic(stmError{err})
	}
	if txnresp.Succeeded {
		return txnresp
	}
	return nil
}

// cmps guards the txn from updates to read set
func (s *stm) cmps() []v3.Cmp {
	cmps := make([]v3.Cmp, 0, len(s.rset))
	for k, rk := range s.rset {
		cmps = append(cmps, isKeyCurrent(k, rk))
	}
	return cmps
}

func (s *stm) fetch(key string) *v3.GetResponse {
	if resp, ok := s.rset[key]; ok {
		return resp
	}
	resp, err := s.client.Get(s.ctx, key, s.getOpts...)
	if err != nil {
		panic(stmError{err})
	}
	s.rset[key] = resp
	return resp
}

// puts is the list of ops for all pending writes
func (s *stm) puts() []v3.Op {
	puts := make([]v3.Op, 0, len(s.wset))
	for _, v := range s.wset {
		puts = append(puts, v.op)
	}
	return puts
}

func (s *stm) reset() {
	s.rset = make(map[string]*v3.GetResponse)
	s.wset = make(map[string]stmPut)
}

type stmSerializable struct {
	stm
	prefetch map[string]*v3.GetResponse
}

func (s *stmSerializable) Get(key string) string {
	if wv, ok := s.wset[key]; ok {
		return wv.val
	}
	firstRead := len(s.rset) == 0
	if resp, ok := s.prefetch[key]; ok {
		delete(s.prefetch, key)
		s.rset[key] = resp
	}
	resp := s.stm.fetch(key)
	if firstRead {
		// txn's base revision is defined by the first read
		s.getOpts = []v3.OpOption{
			v3.WithRev(resp.Header.Revision),
			v3.WithSerializable(),
		}
	}
	return respToValue(resp)
}

func (s *stmSerializable) Rev(key string) int64 {
	s.Get(key)
	return s.stm.Rev(key)
}

func (s *stmSerializable) gets() ([]string, []v3.Op) {
	keys := make([]string, 0, len(s.rset))
	ops := make([]v3.Op, 0, len(s.rset))
	for k := range s.rset {
		keys = append(keys, k)
		ops = append(ops, v3.OpGet(k))
	}
	return keys, ops
}

func (s *stmSerializable) commit() *v3.TxnResponse {
	keys, getops := s.gets()
	txn := s.client.Txn(s.ctx).If(s.cmps()...).Then(s.puts()...)
	// use Else to prefetch keys in case of conflict to save a round trip
	txnresp, err := txn.Else(getops...).Commit()
	if err != nil {
		panic(stmError{err})
	}
	if txnresp.Succeeded {
		return txnresp
	}
	// load prefetch with Else data
	for i := range keys {
		resp := txnresp.Responses[i].GetResponseRange()
		s.rset[keys[i]] = (*v3.GetResponse)(resp)
	}
	s.prefetch = s.rset
	s.getOpts = nil
	return nil
}

type stmReadCommitted struct{ stm }

// commit always goes through when read committed
func (s *stmReadCommitted) commit() *v3.TxnResponse {
	s.rset = nil
	return s.stm.commit()
}

func isKeyCurrent(k string, r *v3.GetResponse) v3.Cmp {
	if len(r.Kvs) != 0 {
		return v3.Compare(v3.ModRevision(k), "=", r.Kvs[0].ModRevision)
	}
	return v3.Compare(v3.ModRevision(k), "=", 0)
}

func respToValue(resp *v3.GetResponse) string {
	if len(resp.Kvs) == 0 {
		return ""
	}
	return string(resp.Kvs[0].Value)
}
<|endoftext|>


<commit_before>package goweb

import (
	"encoding/json"
	"errors"
)

// Interface describing an object responsible for
// handling transformed/formatted response data
type Formatter interface {
	// method to transform response
	Format(context *Context, input interface{}) ([]uint8, error)
	// method that decides if this formatter will be used
	Match(*Context) bool
}

// Internal collection of formatters
var formatters []Formatter

// Adds a formatter decider
func AddFormatter(formatter Formatter) {
	if formatters == nil {
		formatters = make([]Formatter, 0)
	}
	formatters = append([]Formatter{formatter}, formatters...)
}

// Clears all formatters (including default internal ones)
func ClearFormatters() {
	formatters = nil
}

// Gets the relevant formatter for the specified context or
// returns an error if no formatter is found
func GetFormatter(cx *Context) (Formatter, error) {

	// warn if someone cleared them all out
	if formatters == nil {
		return nil, errors.New("There are no formatters set")
	}

	// check each formatter for a match
	for _, formatter := range formatters {
		if formatter.Match(cx) {
			return formatter, nil
		}
	}

	// none found
	return nil, errors.New("No suitable Formatter could be found to deal with that request, consider calling ConfigureDefaultFormatters() or AddFormatter().  See http://code.google.com/p/goweb/wiki/APIDocumentation#Formatters")

}

/*

	Default internal formatters

*/

// Formatter for JSON
type JsonFormatter struct{}

// Readies response and converts input data into JSON
func (f *JsonFormatter) Format(cx *Context, input interface{}) ([]uint8, error) {
	// marshal json
	output, err := json.Marshal(input)
	if err != nil {
		return nil, err
	}

	// if callback param is given format as JSONP
	if callback := cx.GetCallback(); callback != "" {
		// get the context var
		requestContext := cx.GetRequestContext()

		// wrap in js function
		outputString := callback + "(" + string(output)

		// pass the request context as the second param
		if requestContext != "" {
			outputString = outputString + ", \"" + requestContext + "\")"
		} else {
			outputString = outputString + ")"
		}
		// set the new content type
		cx.ResponseWriter.Header().Set("Content-Type", JSONP_CONTENT_TYPE)

		// convert back
		output = []uint8(outputString)

	} else {
		// normal json content type
		cx.ResponseWriter.Header().Set("Content-Type", "application/json")
		cx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*")
	}

	return output, nil
}

// Gets the "application/json" content type
func (f *JsonFormatter) Match(cx *Context) bool {
	return cx.Format == "JSON"
}

// Adds the default formatters to goweb so that
func ConfigureDefaultFormatters() {
	AddFormatter(new(JsonFormatter))
}
<commit_msg>added Access-Control-Allow-Headers: Authorization to default header<commit_after>package goweb

import (
	"encoding/json"
	"errors"
)

// Interface describing an object responsible for
// handling transformed/formatted response data
type Formatter interface {
	// method to transform response
	Format(context *Context, input interface{}) ([]uint8, error)
	// method that decides if this formatter will be used
	Match(*Context) bool
}

// Internal collection of formatters
var formatters []Formatter

// Adds a formatter decider
func AddFormatter(formatter Formatter) {
	if formatters == nil {
		formatters = make([]Formatter, 0)
	}
	formatters = append([]Formatter{formatter}, formatters...)
}

// Clears all formatters (including default internal ones)
func ClearFormatters() {
	formatters = nil
}

// Gets the relevant formatter for the specified context or
// returns an error if no formatter is found
func GetFormatter(cx *Context) (Formatter, error) {

	// warn if someone cleared them all out
	if formatters == nil {
		return nil, errors.New("There are no formatters set")
	}

	// check each formatter for a match
	for _, formatter := range formatters {
		if formatter.Match(cx) {
			return formatter, nil
		}
	}

	// none found
	return nil, errors.New("No suitable Formatter could be found to deal with that request, consider calling ConfigureDefaultFormatters() or AddFormatter().  See http://code.google.com/p/goweb/wiki/APIDocumentation#Formatters")

}

/*

	Default internal formatters

*/

// Formatter for JSON
type JsonFormatter struct{}

// Readies response and converts input data into JSON
func (f *JsonFormatter) Format(cx *Context, input interface{}) ([]uint8, error) {
	// marshal json
	output, err := json.Marshal(input)
	if err != nil {
		return nil, err
	}

	// if callback param is given format as JSONP
	if callback := cx.GetCallback(); callback != "" {
		// get the context var
		requestContext := cx.GetRequestContext()

		// wrap in js function
		outputString := callback + "(" + string(output)

		// pass the request context as the second param
		if requestContext != "" {
			outputString = outputString + ", \"" + requestContext + "\")"
		} else {
			outputString = outputString + ")"
		}
		// set the new content type
		cx.ResponseWriter.Header().Set("Content-Type", JSONP_CONTENT_TYPE)

		// convert back
		output = []uint8(outputString)

	} else {
		// normal json content type
		cx.ResponseWriter.Header().Set("Content-Type", "application/json")
		cx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*")
		cx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Authorization")
	}

	return output, nil
}

// Gets the "application/json" content type
func (f *JsonFormatter) Match(cx *Context) bool {
	return cx.Format == "JSON"
}

// Adds the default formatters to goweb so that
func ConfigureDefaultFormatters() {
	AddFormatter(new(JsonFormatter))
}
<|endoftext|>


<commit_before>package foundation

import (
	"errors"
	"os"

	"github.com/metacoin/flojson"
)

func RPCCall(command string, args ...interface{}) (interface{}, error) {
	// create a new command based on the command string given
	// handle errors, and return results to main function
	id := 1
	var cmd flojson.Cmd
	var err error
	var ret interface{}

	switch command {

	case "getblock":
		cmd, err = flojson.NewGetBlockCmd(id, args[0].(string))
	case "getblockhash":
		cmd, err = flojson.NewGetBlockHashCmd(id, args[0].(int))
	case "getblockcount":
		cmd, err = flojson.NewGetBlockCountCmd(id)
	case "getrawtransaction":
		cmd, err = flojson.NewGetRawTransactionCmd(id, args[0].(string))
	case "decoderawtransaction":
		cmd, err = flojson.NewDecodeRawTransactionCmd(id, args[0].(string))
	case "getconnectioncount":
		cmd, err = flojson.NewGetConnectionCountCmd(id)
	case "getnetworkhashps":
		cmd, err = flojson.NewGetNetworkHashPSCmd(id)
	case "settxfee":
		cmd, err = flojson.NewSetTxFeeCmd(id, args[0].(int64))
	case "sendtoaddress":
		cmd, err = flojson.NewSendToAddressCmd(id, args[0].(string), args[1].(int64), args[2], args[3], args[4])
	case "walletpassphrase":
		cmd, err = flojson.NewWalletPassphraseCmd(id, args[0].(string), args[1].(int))
	case "signmessage":
		cmd, err = flojson.NewSignMessageCmd(id, args[0].(string), args[1].(string))
	case "verifymessage":
		cmd, err = flojson.NewVerifyMessageCmd(id, args[0].(string), args[1].(string), args[2].(string))
	case "validateaddress":
		cmd, err = flojson.NewValidateAddressCmd(id, args[0].(string))
	default:
		err = errors.New("command " + command + " not found")
	}

	if err != nil {
		return ret, err
	}

	if cmd != nil {
		reply, err := SendCommand(cmd)
		if err != nil {
			return ret, err
		} else {
			return reply, nil
		}
	}
	return ret, errors.New("flojson replied with empty NewCmd struct")
}

func SendCommand(cmd flojson.Cmd) (interface{}, error) {

	var ret interface{}
	ftoken := os.Getenv("F_TOKEN")
	if ftoken == "" {
		return ret, errors.New("F_TOKEN environment variable not set")
	}

	// send command to RPC, get a response in reply
	reply, err := flojson.RpcSend("florincoinrpc", ftoken, "127.0.0.1:18322", cmd)
	if err != nil {
		return ret, err
	}

	if reply.Result != nil {
		return reply.Result, nil
	} else {
		// if for some reason the result is nil, but err isn't nil, return a generic warning message
		return ret, errors.New("didn't get a response from the RPC - check auth and permission settings")
	}
}
<commit_msg>added environment variable for Florincoin rpcuser<commit_after>package foundation

import (
	"errors"
	"os"

	"github.com/metacoin/flojson"
)

func RPCCall(command string, args ...interface{}) (interface{}, error) {
	// create a new command based on the command string given
	// handle errors, and return results to main function
	id := 1
	var cmd flojson.Cmd
	var err error
	var ret interface{}

	switch command {

	case "getblock":
		cmd, err = flojson.NewGetBlockCmd(id, args[0].(string))
	case "getblockhash":
		cmd, err = flojson.NewGetBlockHashCmd(id, args[0].(int))
	case "getblockcount":
		cmd, err = flojson.NewGetBlockCountCmd(id)
	case "getrawtransaction":
		cmd, err = flojson.NewGetRawTransactionCmd(id, args[0].(string))
	case "decoderawtransaction":
		cmd, err = flojson.NewDecodeRawTransactionCmd(id, args[0].(string))
	case "getconnectioncount":
		cmd, err = flojson.NewGetConnectionCountCmd(id)
	case "getnetworkhashps":
		cmd, err = flojson.NewGetNetworkHashPSCmd(id)
	case "settxfee":
		cmd, err = flojson.NewSetTxFeeCmd(id, args[0].(int64))
	case "sendtoaddress":
		cmd, err = flojson.NewSendToAddressCmd(id, args[0].(string), args[1].(int64), args[2], args[3], args[4])
	case "walletpassphrase":
		cmd, err = flojson.NewWalletPassphraseCmd(id, args[0].(string), args[1].(int))
	case "signmessage":
		cmd, err = flojson.NewSignMessageCmd(id, args[0].(string), args[1].(string))
	case "verifymessage":
		cmd, err = flojson.NewVerifyMessageCmd(id, args[0].(string), args[1].(string), args[2].(string))
	case "validateaddress":
		cmd, err = flojson.NewValidateAddressCmd(id, args[0].(string))
	default:
		err = errors.New("command " + command + " not found")
	}

	if err != nil {
		return ret, err
	}

	if cmd != nil {
		reply, err := SendCommand(cmd)
		if err != nil {
			return ret, err
		} else {
			return reply, nil
		}
	}
	return ret, errors.New("flojson replied with empty NewCmd struct")
}

func SendCommand(cmd flojson.Cmd) (interface{}, error) {

	var ret interface{}
	ftoken := os.Getenv("F_TOKEN")
	if ftoken == "" {
		return ret, errors.New("F_TOKEN environment variable not set")
	}

	fuser := os.Getenv("F_USER")
	if ftoken == "" {
		return ret, errors.New("F_USER environment variable not set")
	}

	// send command to RPC, get a response in reply
	reply, err := flojson.RpcSend(fuser, ftoken, "127.0.0.1:18322", cmd)
	if err != nil {
		return ret, err
	}

	if reply.Result != nil {
		return reply.Result, nil
	} else {
		// if for some reason the result is nil, but err isn't nil, return a generic warning message
		return ret, errors.New("didn't get a response from the RPC - check auth and permission settings")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"

	"github.com/mlafeldt/chef-runner.go/cookbook"
	"github.com/mlafeldt/chef-runner.go/log"
	"github.com/mlafeldt/chef-runner.go/openssh"
	"github.com/mlafeldt/chef-runner.go/provisioner/chefsolo"
	"github.com/mlafeldt/chef-runner.go/util"
	"github.com/mlafeldt/chef-runner.go/vagrant"
)

type SSHClient interface {
	RunCommand(command string) error
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: chef-runner [flags] [recipe ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func abort(v ...interface{}) {
	log.Error(v...)
	os.Exit(1)
}

func buildRunList(cookbookName string, recipes []string) []string {
	if len(recipes) == 0 {
		return []string{cookbookName + "::default"}
	}

	var runList []string
	for _, r := range recipes {
		var recipeName string
		if strings.Contains(r, "::") {
			recipeName = r
		} else if path.Dir(r) == "recipes" && path.Ext(r) == ".rb" {
			recipeName = cookbookName + "::" + util.BaseName(r, ".rb")
		} else {
			recipeName = cookbookName + "::" + r
		}
		runList = append(runList, recipeName)
	}
	return runList
}

func main() {
	var (
		host     = flag.String("H", "", "Set hostname for direct SSH access")
		machine  = flag.String("M", "", "Set name of Vagrant virtual machine")
		format   = flag.String("F", "", "Set output format")
		logLevel = flag.String("l", "", "Set log level")
		jsonFile = flag.String("j", "", "Load attributes from a JSON file")
	)
	flag.Usage = usage
	flag.Parse()

	if *host != "" && *machine != "" {
		abort("-H and -M cannot be used together")
	}

	cb, err := cookbook.NewCookbook(".")
	if err != nil {
		abort(err)
	}
	if cb.Name == "" {
		abort("unknown cookbook name")
	}
	log.Debug("Cookbook =", cb)

	recipes := flag.Args()
	runList := buildRunList(cb.Name, recipes)
	log.Debug("Run list =", runList)

	var attributes string
	if *jsonFile != "" {
		data, err := ioutil.ReadFile(*jsonFile)
		if err != nil {
			abort(err)
		}
		attributes = string(data)
	}
	log.Debug("Attributes =", attributes)

	provisioner := chefsolo.Provisoner{
		RunList:    runList,
		Attributes: attributes,
		Format:     *format,
		LogLevel:   *logLevel,
	}
	if err := provisioner.CreateSandbox(); err != nil {
		abort(err)
	}

	// TODO: Copy files from p.SandboxPath to p.RootPath in order to get
	// rid of the Vagrant dependency

	cmd := strings.Join(provisioner.Command(), " ")
	log.Debug(cmd)

	var client SSHClient
	if *host != "" {
		client = openssh.NewClient(*host)
	} else {
		client = vagrant.NewClient(*machine)
	}

	if err := client.RunCommand(cmd); err != nil {
		abort(err)
	}
}
<commit_msg>Set log level via CHEF_RUNNER_LOG env var<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"

	"github.com/mlafeldt/chef-runner.go/cookbook"
	"github.com/mlafeldt/chef-runner.go/log"
	"github.com/mlafeldt/chef-runner.go/openssh"
	"github.com/mlafeldt/chef-runner.go/provisioner/chefsolo"
	"github.com/mlafeldt/chef-runner.go/util"
	"github.com/mlafeldt/chef-runner.go/vagrant"
)

type SSHClient interface {
	RunCommand(command string) error
}

func logLevel() int {
	l := log.LevelInfo
	e := os.Getenv("CHEF_RUNNER_LOG")
	if e == "" {
		return l
	}
	m := map[string]int{
		"debug": log.LevelDebug,
		"info":  log.LevelInfo,
		"warn":  log.LevelWarn,
		"error": log.LevelError,
	}
	if v, ok := m[strings.ToLower(e)]; ok {
		l = v
	}
	return l
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: chef-runner [flags] [recipe ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func abort(v ...interface{}) {
	log.Error(v...)
	os.Exit(1)
}

func buildRunList(cookbookName string, recipes []string) []string {
	if len(recipes) == 0 {
		return []string{cookbookName + "::default"}
	}

	var runList []string
	for _, r := range recipes {
		var recipeName string
		if strings.Contains(r, "::") {
			recipeName = r
		} else if path.Dir(r) == "recipes" && path.Ext(r) == ".rb" {
			recipeName = cookbookName + "::" + util.BaseName(r, ".rb")
		} else {
			recipeName = cookbookName + "::" + r
		}
		runList = append(runList, recipeName)
	}
	return runList
}

func main() {
	log.Level = logLevel()

	var (
		host     = flag.String("H", "", "Set hostname for direct SSH access")
		machine  = flag.String("M", "", "Set name of Vagrant virtual machine")
		format   = flag.String("F", "", "Set output format")
		logLevel = flag.String("l", "", "Set log level")
		jsonFile = flag.String("j", "", "Load attributes from a JSON file")
	)
	flag.Usage = usage
	flag.Parse()

	if *host != "" && *machine != "" {
		abort("-H and -M cannot be used together")
	}

	cb, err := cookbook.NewCookbook(".")
	if err != nil {
		abort(err)
	}
	if cb.Name == "" {
		abort("unknown cookbook name")
	}
	log.Debug("Cookbook =", cb)

	recipes := flag.Args()
	runList := buildRunList(cb.Name, recipes)
	log.Debug("Run list =", runList)

	var attributes string
	if *jsonFile != "" {
		data, err := ioutil.ReadFile(*jsonFile)
		if err != nil {
			abort(err)
		}
		attributes = string(data)
	}
	log.Debug("Attributes =", attributes)

	provisioner := chefsolo.Provisoner{
		RunList:    runList,
		Attributes: attributes,
		Format:     *format,
		LogLevel:   *logLevel,
	}
	if err := provisioner.CreateSandbox(); err != nil {
		abort(err)
	}

	// TODO: Copy files from p.SandboxPath to p.RootPath in order to get
	// rid of the Vagrant dependency

	cmd := strings.Join(provisioner.Command(), " ")
	log.Debug(cmd)

	var client SSHClient
	if *host != "" {
		client = openssh.NewClient(*host)
	} else {
		client = vagrant.NewClient(*machine)
	}

	if err := client.RunCommand(cmd); err != nil {
		abort(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/bin/bindata"
	"github.com/concourse/flag"
	concourseWorker "github.com/concourse/worker"
	"github.com/concourse/worker/beacon"
	workerConfig "github.com/concourse/worker/start"
	"github.com/concourse/worker/sweeper"
	"github.com/concourse/worker/tsa"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
)

type WorkerCommand struct {
	Worker workerConfig.Config

	TSA tsa.Config `group:"TSA Configuration" namespace:"tsa"`

	Certs Certs

	WorkDir flag.Dir `long:"work-dir" required:"true" description:"Directory in which to place container data."`

	BindIP   flag.IP `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
	BindPort uint16  `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`
	PeerIP   flag.IP `long:"peer-ip" description:"IP used to reach this worker from the ATC nodes."`

	Garden GardenBackend `group:"Garden Configuration" namespace:"garden"`

	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`

	Logger flag.Lager
}

func (cmd *WorkerCommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
}

func (cmd *WorkerCommand) Runner(args []string) (ifrit.Runner, error) {
	logger, _ := cmd.Logger.Logger("worker")

	hasAssets, err := cmd.setup(logger.Session("setup"))
	if err != nil {
		return nil, err
	}

	worker, gardenRunner, err := cmd.gardenRunner(logger.Session("garden"), hasAssets)
	if err != nil {
		return nil, err
	}

	worker.Version = WorkerVersion

	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"), hasAssets)
	if err != nil {
		return nil, err
	}

	members := grouper.Members{
		{
			Name:   "garden",
			Runner: gardenRunner,
		},
		{
			Name:   "baggageclaim",
			Runner: baggageclaimRunner,
		},
	}

	if cmd.TSA.WorkerPrivateKey.PrivateKey != nil {
		beaconConfig := beacon.Config{
			TSAConfig: cmd.TSA,
		}

		if cmd.PeerIP.IP != nil {
			worker.GardenAddr = fmt.Sprintf("%s:%d", cmd.PeerIP.IP, cmd.BindPort)
			worker.BaggageclaimURL = fmt.Sprintf("http://%s:%d", cmd.PeerIP.IP, cmd.Baggageclaim.BindPort)

			beaconConfig.RegistrationMode = "direct"
		} else {
			beaconConfig.RegistrationMode = "forward"
			beaconConfig.GardenForwardAddr = fmt.Sprintf("%s:%d", cmd.BindIP.IP, cmd.BindPort)
			beaconConfig.BaggageclaimForwardAddr = fmt.Sprintf("%s:%d", cmd.Baggageclaim.BindIP.IP, cmd.Baggageclaim.BindPort)

			worker.GardenAddr = beaconConfig.GardenForwardAddr
			worker.BaggageclaimURL = fmt.Sprintf("http://%s", beaconConfig.BaggageclaimForwardAddr)
		}

		members = append(members, grouper.Member{
			Name: "beacon",
			Runner: concourseWorker.BeaconRunner(
				logger.Session("beacon"),
				worker,
				beaconConfig,
			),
		})

		members = append(members, grouper.Member{
			Name: "sweeper",
			Runner: sweeper.NewSweeperRunner(
				logger,
				worker,
				beaconConfig,
			),
		})
	}

	return grouper.NewParallel(os.Interrupt, members), nil
}

func (cmd *WorkerCommand) assetPath(paths ...string) string {
	return filepath.Join(append([]string{cmd.WorkDir.Path(), Version, "assets"}, paths...)...)
}

func (cmd *WorkerCommand) setup(logger lager.Logger) (bool, error) {
	okMarker := cmd.assetPath("ok")

	_, err := os.Stat(okMarker)
	if err == nil {
		logger.Info("already-done")
		return true, nil
	}

	_, err = bindata.AssetDir("assets")
	if err != nil {
		logger.Info("no-assets")
		return false, nil
	}

	logger.Info("unpacking")

	err = bindata.RestoreAssets(filepath.Split(cmd.assetPath()))
	if err != nil {
		logger.Error("failed-to-unpack", err)
		return false, err
	}

	_, err = os.Stat(cmd.assetPath())
	if os.IsNotExist(err) {
		logger.Info("no-assets")
		return false, nil
	}

	ok, err := os.Create(okMarker)
	if err != nil {
		logger.Error("failed-to-create-ok-marker", err)
		return false, err
	}

	err = ok.Close()
	if err != nil {
		logger.Error("failed-to-close-ok-marker", err)
		return false, err
	}

	logger.Info("done")

	return true, nil
}

func (cmd *WorkerCommand) workerName() (string, error) {
	if cmd.Worker.Name != "" {
		return cmd.Worker.Name, nil
	}

	return os.Hostname()
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger, hasAssets bool) (ifrit.Runner, error) {
	volumesDir := filepath.Join(cmd.WorkDir.Path(), "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	cmd.Baggageclaim.Metrics = cmd.Metrics
	cmd.Baggageclaim.VolumesDir = flag.Dir(volumesDir)

	cmd.Baggageclaim.OverlaysDir = filepath.Join(cmd.WorkDir.Path(), "overlays")

	if hasAssets {
		cmd.Baggageclaim.MkfsBin = cmd.assetPath("btrfs", "mkfs.btrfs")
		cmd.Baggageclaim.BtrfsBin = cmd.assetPath("btrfs", "btrfs")
	}

	return cmd.Baggageclaim.Runner(nil)
}
<commit_msg>clean up unneeded code<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/bin/bindata"
	"github.com/concourse/flag"
	concourseWorker "github.com/concourse/worker"
	"github.com/concourse/worker/beacon"
	workerConfig "github.com/concourse/worker/start"
	"github.com/concourse/worker/sweeper"
	"github.com/concourse/worker/tsa"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
)

type WorkerCommand struct {
	Worker workerConfig.Config

	TSA tsa.Config `group:"TSA Configuration" namespace:"tsa"`

	Certs Certs

	WorkDir flag.Dir `long:"work-dir" required:"true" description:"Directory in which to place container data."`

	BindIP   flag.IP `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
	BindPort uint16  `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`
	PeerIP   flag.IP `long:"peer-ip" description:"IP used to reach this worker from the ATC nodes."`

	Garden GardenBackend `group:"Garden Configuration" namespace:"garden"`

	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`

	Logger flag.Lager
}

func (cmd *WorkerCommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
}

func (cmd *WorkerCommand) Runner(args []string) (ifrit.Runner, error) {
	logger, _ := cmd.Logger.Logger("worker")

	hasAssets, err := cmd.setup(logger.Session("setup"))
	if err != nil {
		return nil, err
	}

	worker, gardenRunner, err := cmd.gardenRunner(logger.Session("garden"), hasAssets)
	if err != nil {
		return nil, err
	}

	worker.Version = WorkerVersion

	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"), hasAssets)
	if err != nil {
		return nil, err
	}

	members := grouper.Members{
		{
			Name:   "garden",
			Runner: gardenRunner,
		},
		{
			Name:   "baggageclaim",
			Runner: baggageclaimRunner,
		},
	}

	if cmd.TSA.WorkerPrivateKey.PrivateKey != nil {
		beaconConfig := beacon.Config{
			TSAConfig: cmd.TSA,
		}

		if cmd.PeerIP.IP != nil {
			worker.GardenAddr = fmt.Sprintf("%s:%d", cmd.PeerIP.IP, cmd.BindPort)
			worker.BaggageclaimURL = fmt.Sprintf("http://%s:%d", cmd.PeerIP.IP, cmd.Baggageclaim.BindPort)

			beaconConfig.RegistrationMode = "direct"
		} else {
			beaconConfig.RegistrationMode = "forward"
			beaconConfig.GardenForwardAddr = fmt.Sprintf("%s:%d", cmd.BindIP.IP, cmd.BindPort)
			beaconConfig.BaggageclaimForwardAddr = fmt.Sprintf("%s:%d", cmd.Baggageclaim.BindIP.IP, cmd.Baggageclaim.BindPort)

			worker.GardenAddr = beaconConfig.GardenForwardAddr
			worker.BaggageclaimURL = fmt.Sprintf("http://%s", beaconConfig.BaggageclaimForwardAddr)
		}

		members = append(members, grouper.Member{
			Name: "beacon",
			Runner: concourseWorker.BeaconRunner(
				logger.Session("beacon"),
				worker,
				beaconConfig,
			),
		})

		members = append(members, grouper.Member{
			Name: "sweeper",
			Runner: sweeper.NewSweeperRunner(
				logger,
				worker,
				beaconConfig,
			),
		})
	}

	return grouper.NewParallel(os.Interrupt, members), nil
}

func (cmd *WorkerCommand) assetPath(paths ...string) string {
	return filepath.Join(append([]string{cmd.WorkDir.Path(), Version, "assets"}, paths...)...)
}

func (cmd *WorkerCommand) setup(logger lager.Logger) (bool, error) {
	okMarker := cmd.assetPath("ok")

	_, err := os.Stat(okMarker)
	if err == nil {
		logger.Info("already-done")
		return true, nil
	}

	_, err = bindata.AssetDir("assets")
	if err != nil {
		logger.Info("no-assets")
		return false, nil
	}

	logger.Info("unpacking")

	err = bindata.RestoreAssets(filepath.Split(cmd.assetPath()))
	if err != nil {
		logger.Error("failed-to-unpack", err)
		return false, err
	}

	_, err = os.Stat(cmd.assetPath())
	if os.IsNotExist(err) {
		logger.Info("no-assets")
		return false, nil
	}

	ok, err := os.Create(okMarker)
	if err != nil {
		logger.Error("failed-to-create-ok-marker", err)
		return false, err
	}

	err = ok.Close()
	if err != nil {
		logger.Error("failed-to-close-ok-marker", err)
		return false, err
	}

	logger.Info("done")

	return true, nil
}

func (cmd *WorkerCommand) workerName() (string, error) {
	if cmd.Worker.Name != "" {
		return cmd.Worker.Name, nil
	}

	return os.Hostname()
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger, hasAssets bool) (ifrit.Runner, error) {
	volumesDir := filepath.Join(cmd.WorkDir.Path(), "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	cmd.Baggageclaim.VolumesDir = flag.Dir(volumesDir)

	cmd.Baggageclaim.OverlaysDir = filepath.Join(cmd.WorkDir.Path(), "overlays")

	if hasAssets {
		cmd.Baggageclaim.MkfsBin = cmd.assetPath("btrfs", "mkfs.btrfs")
		cmd.Baggageclaim.BtrfsBin = cmd.assetPath("btrfs", "btrfs")
	}

	return cmd.Baggageclaim.Runner(nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"time"

	gclient "code.cloudfoundry.org/garden/client"
	gconn "code.cloudfoundry.org/garden/client/connection"
	"code.cloudfoundry.org/lager"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	bclient "github.com/concourse/baggageclaim/client"
	"github.com/concourse/concourse"
	"github.com/concourse/concourse/worker"
	"github.com/concourse/flag"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
)

type WorkerCommand struct {
	Worker WorkerConfig

	TSA worker.TSAConfig `group:"TSA Configuration" namespace:"tsa"`

	Certs Certs

	WorkDir flag.Dir `long:"work-dir" required:"true" description:"Directory in which to place container data."`

	BindIP   flag.IP `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
	BindPort uint16  `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`

	DebugBindIP   flag.IP `long:"debug-bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the pprof debugger endpoints."`
	DebugBindPort uint16  `long:"debug-bind-port" default:"7776"      description:"Port on which to listen for the pprof debugger endpoints."`

	HealthcheckBindIP   flag.IP       `long:"healthcheck-bind-ip"    default:"0.0.0.0"  description:"IP address on which to listen for health checking requests."`
	HealthcheckBindPort uint16        `long:"healthcheck-bind-port"  default:"8888"     description:"Port on which to listen for health checking requests."`
	HealthCheckTimeout  time.Duration `long:"healthcheck-timeout"    default:"5s"       description:"HTTP timeout for the full duration of health checking."`

	SweepInterval               time.Duration `long:"sweep-interval" default:"30s" description:"Interval on which containers and volumes will be garbage collected from the worker."`
	VolumeSweeperMaxInFlight    uint16        `long:"volume-sweeper-max-in-flight" default:"3" description:"Maximum number of volumes which can be swept in parallel."`
	ContainerSweeperMaxInFlight uint16        `long:"container-sweeper-max-in-flight" default:"5" description:"Maximum number of containers which can be swept in parallel."`

	RebalanceInterval time.Duration `long:"rebalance-interval" description:"Duration after which the registration should be swapped to another random SSH gateway."`

	ConnectionDrainTimeout time.Duration `long:"connection-drain-timeout" default:"1h" description:"Duration after which a worker should give up draining forwarded connections on shutdown."`

	Garden GardenBackend `group:"Garden Configuration" namespace:"garden"`

	ExternalGardenAddress flag.URL `long:"external-garden-address" description:"garden server connection address, when specified will not use embedded garden"`

	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`

	ResourceTypes flag.Dir `long:"resource-types" description:"Path to directory containing resource types the worker should advertise."`

	Logger flag.Lager
}

func (cmd *WorkerCommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
}

func (cmd *WorkerCommand) Runner(args []string) (ifrit.Runner, error) {
	if cmd.ResourceTypes == "" {
		cmd.ResourceTypes = flag.Dir(discoverAsset("resource-types"))
	}

	logger, _ := cmd.Logger.Logger("worker")

	atcWorker, gardenRunner, err := cmd.gardenRunner(logger.Session("garden"))
	if err != nil {
		return nil, err
	}

	atcWorker.Version = concourse.WorkerVersion

	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"))
	if err != nil {
		return nil, err
	}

	healthChecker := worker.NewHealthChecker(
		logger.Session("healthchecker"),
		cmd.baggageclaimURL(),
		cmd.gardenURL(),
		cmd.HealthCheckTimeout,
	)

	tsaClient := cmd.TSA.Client(atcWorker)

	beaconRunner := worker.NewBeaconRunner(
		logger.Session("beacon-runner"),
		tsaClient,
		cmd.RebalanceInterval,
		cmd.ConnectionDrainTimeout,
		cmd.gardenAddr(),
		cmd.baggageclaimAddr(),
	)

	gardenClient := gclient.New(
		gconn.NewWithLogger(
			"tcp",
			cmd.gardenAddr(),
			logger.Session("garden-connection"),
		),
	)

	baggageclaimClient := bclient.NewWithHTTPClient(
		cmd.baggageclaimURL(),

		// ensure we don't use baggageclaim's default retryhttp client; all
		// traffic should be local, so any failures are unlikely to be transient.
		// we don't want a retry loop to block up sweeping and prevent the worker
		// from existing.
		&http.Client{
			Transport: &http.Transport{
				// don't let a slow (possibly stuck) baggageclaim server slow down
				// sweeping too much
				ResponseHeaderTimeout: 1 * time.Minute,
			},
		},
	)

	containerSweeper := worker.NewContainerSweeper(
		logger.Session("container-sweeper"),
		cmd.SweepInterval,
		tsaClient,
		gardenClient,
		cmd.ContainerSweeperMaxInFlight,
	)

	volumeSweeper := worker.NewVolumeSweeper(
		logger.Session("volume-sweeper"),
		cmd.SweepInterval,
		tsaClient,
		baggageclaimClient,
		cmd.VolumeSweeperMaxInFlight,
	)

	var members grouper.Members

	if !cmd.gardenIsExternal() {
		members = append(members, grouper.Member{
			Name:   "garden",
			Runner: NewLoggingRunner(logger.Session("garden-runner"), gardenRunner),
		})
	}

	members = append(members, grouper.Members{
		{
			Name:   "baggageclaim",
			Runner: NewLoggingRunner(logger.Session("baggageclaim-runner"), baggageclaimRunner),
		},
		{
			Name: "debug",
			Runner: NewLoggingRunner(
				logger.Session("debug-runner"),
				http_server.New(
					fmt.Sprintf("%s:%d", cmd.DebugBindIP.IP, cmd.DebugBindPort),
					http.DefaultServeMux,
				),
			),
		},
		{
			Name: "healthcheck",
			Runner: NewLoggingRunner(
				logger.Session("healthcheck-runner"),
				http_server.New(
					fmt.Sprintf("%s:%d", cmd.HealthcheckBindIP.IP, cmd.HealthcheckBindPort),
					http.HandlerFunc(healthChecker.CheckHealth),
				),
			),
		},
		{
			Name: "beacon",
			Runner: NewLoggingRunner(
				logger.Session("beacon-runner"),
				beaconRunner,
			),
		},
		{
			Name: "container-sweeper",
			Runner: NewLoggingRunner(
				logger.Session("container-sweeper"),
				containerSweeper,
			),
		},
		{
			Name: "volume-sweeper",
			Runner: NewLoggingRunner(
				logger.Session("volume-sweeper"),
				volumeSweeper,
			),
		},
	}...)

	return grouper.NewParallel(os.Interrupt, members), nil
}

func (cmd *WorkerCommand) gardenIsExternal() bool {
	return cmd.ExternalGardenAddress.URL != nil
}

func (cmd *WorkerCommand) gardenAddr() string {
	if cmd.gardenIsExternal() {
		return cmd.ExternalGardenAddress.URL.Host
	}
	return fmt.Sprintf("%s:%d", cmd.BindIP, cmd.BindPort)
}

func (cmd *WorkerCommand) gardenURL() string {
	return fmt.Sprintf("http://%s", cmd.gardenAddr())
}

func (cmd *WorkerCommand) baggageclaimAddr() string {
	return fmt.Sprintf("%s:%d", cmd.Baggageclaim.BindIP, cmd.Baggageclaim.BindPort)
}

func (cmd *WorkerCommand) baggageclaimURL() string {
	return fmt.Sprintf("http://%s", cmd.baggageclaimAddr())
}

func (cmd *WorkerCommand) workerName() (string, error) {
	if cmd.Worker.Name != "" {
		return cmd.Worker.Name, nil
	}

	return os.Hostname()
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesDir := filepath.Join(cmd.WorkDir.Path(), "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	cmd.Baggageclaim.VolumesDir = flag.Dir(volumesDir)

	cmd.Baggageclaim.OverlaysDir = filepath.Join(cmd.WorkDir.Path(), "overlays")

	return cmd.Baggageclaim.Runner(nil)
}
<commit_msg>--external-garden-address -> --external-garden-url<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"time"

	gclient "code.cloudfoundry.org/garden/client"
	gconn "code.cloudfoundry.org/garden/client/connection"
	"code.cloudfoundry.org/lager"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	bclient "github.com/concourse/baggageclaim/client"
	"github.com/concourse/concourse"
	"github.com/concourse/concourse/worker"
	"github.com/concourse/flag"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
)

type WorkerCommand struct {
	Worker WorkerConfig

	TSA worker.TSAConfig `group:"TSA Configuration" namespace:"tsa"`

	Certs Certs

	WorkDir flag.Dir `long:"work-dir" required:"true" description:"Directory in which to place container data."`

	BindIP   flag.IP `long:"bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the Garden server."`
	BindPort uint16  `long:"bind-port" default:"7777"      description:"Port on which to listen for the Garden server."`

	DebugBindIP   flag.IP `long:"debug-bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the pprof debugger endpoints."`
	DebugBindPort uint16  `long:"debug-bind-port" default:"7776"      description:"Port on which to listen for the pprof debugger endpoints."`

	HealthcheckBindIP   flag.IP       `long:"healthcheck-bind-ip"    default:"0.0.0.0"  description:"IP address on which to listen for health checking requests."`
	HealthcheckBindPort uint16        `long:"healthcheck-bind-port"  default:"8888"     description:"Port on which to listen for health checking requests."`
	HealthCheckTimeout  time.Duration `long:"healthcheck-timeout"    default:"5s"       description:"HTTP timeout for the full duration of health checking."`

	SweepInterval               time.Duration `long:"sweep-interval" default:"30s" description:"Interval on which containers and volumes will be garbage collected from the worker."`
	VolumeSweeperMaxInFlight    uint16        `long:"volume-sweeper-max-in-flight" default:"3" description:"Maximum number of volumes which can be swept in parallel."`
	ContainerSweeperMaxInFlight uint16        `long:"container-sweeper-max-in-flight" default:"5" description:"Maximum number of containers which can be swept in parallel."`

	RebalanceInterval time.Duration `long:"rebalance-interval" description:"Duration after which the registration should be swapped to another random SSH gateway."`

	ConnectionDrainTimeout time.Duration `long:"connection-drain-timeout" default:"1h" description:"Duration after which a worker should give up draining forwarded connections on shutdown."`

	Garden GardenBackend `group:"Garden Configuration" namespace:"garden"`

	ExternalGardenURL flag.URL `long:"external-garden-url" description:"API endpoint of an externally managed Garden server to use instead of running the embedded Garden server."`

	Baggageclaim baggageclaimcmd.BaggageclaimCommand `group:"Baggageclaim Configuration" namespace:"baggageclaim"`

	ResourceTypes flag.Dir `long:"resource-types" description:"Path to directory containing resource types the worker should advertise."`

	Logger flag.Lager
}

func (cmd *WorkerCommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	return <-ifrit.Invoke(sigmon.New(runner)).Wait()
}

func (cmd *WorkerCommand) Runner(args []string) (ifrit.Runner, error) {
	if cmd.ResourceTypes == "" {
		cmd.ResourceTypes = flag.Dir(discoverAsset("resource-types"))
	}

	logger, _ := cmd.Logger.Logger("worker")

	atcWorker, gardenRunner, err := cmd.gardenRunner(logger.Session("garden"))
	if err != nil {
		return nil, err
	}

	atcWorker.Version = concourse.WorkerVersion

	baggageclaimRunner, err := cmd.baggageclaimRunner(logger.Session("baggageclaim"))
	if err != nil {
		return nil, err
	}

	healthChecker := worker.NewHealthChecker(
		logger.Session("healthchecker"),
		cmd.baggageclaimURL(),
		cmd.gardenURL(),
		cmd.HealthCheckTimeout,
	)

	tsaClient := cmd.TSA.Client(atcWorker)

	beaconRunner := worker.NewBeaconRunner(
		logger.Session("beacon-runner"),
		tsaClient,
		cmd.RebalanceInterval,
		cmd.ConnectionDrainTimeout,
		cmd.gardenAddr(),
		cmd.baggageclaimAddr(),
	)

	gardenClient := gclient.New(
		gconn.NewWithLogger(
			"tcp",
			cmd.gardenAddr(),
			logger.Session("garden-connection"),
		),
	)

	baggageclaimClient := bclient.NewWithHTTPClient(
		cmd.baggageclaimURL(),

		// ensure we don't use baggageclaim's default retryhttp client; all
		// traffic should be local, so any failures are unlikely to be transient.
		// we don't want a retry loop to block up sweeping and prevent the worker
		// from existing.
		&http.Client{
			Transport: &http.Transport{
				// don't let a slow (possibly stuck) baggageclaim server slow down
				// sweeping too much
				ResponseHeaderTimeout: 1 * time.Minute,
			},
		},
	)

	containerSweeper := worker.NewContainerSweeper(
		logger.Session("container-sweeper"),
		cmd.SweepInterval,
		tsaClient,
		gardenClient,
		cmd.ContainerSweeperMaxInFlight,
	)

	volumeSweeper := worker.NewVolumeSweeper(
		logger.Session("volume-sweeper"),
		cmd.SweepInterval,
		tsaClient,
		baggageclaimClient,
		cmd.VolumeSweeperMaxInFlight,
	)

	var members grouper.Members

	if !cmd.gardenIsExternal() {
		members = append(members, grouper.Member{
			Name:   "garden",
			Runner: NewLoggingRunner(logger.Session("garden-runner"), gardenRunner),
		})
	}

	members = append(members, grouper.Members{
		{
			Name:   "baggageclaim",
			Runner: NewLoggingRunner(logger.Session("baggageclaim-runner"), baggageclaimRunner),
		},
		{
			Name: "debug",
			Runner: NewLoggingRunner(
				logger.Session("debug-runner"),
				http_server.New(
					fmt.Sprintf("%s:%d", cmd.DebugBindIP.IP, cmd.DebugBindPort),
					http.DefaultServeMux,
				),
			),
		},
		{
			Name: "healthcheck",
			Runner: NewLoggingRunner(
				logger.Session("healthcheck-runner"),
				http_server.New(
					fmt.Sprintf("%s:%d", cmd.HealthcheckBindIP.IP, cmd.HealthcheckBindPort),
					http.HandlerFunc(healthChecker.CheckHealth),
				),
			),
		},
		{
			Name: "beacon",
			Runner: NewLoggingRunner(
				logger.Session("beacon-runner"),
				beaconRunner,
			),
		},
		{
			Name: "container-sweeper",
			Runner: NewLoggingRunner(
				logger.Session("container-sweeper"),
				containerSweeper,
			),
		},
		{
			Name: "volume-sweeper",
			Runner: NewLoggingRunner(
				logger.Session("volume-sweeper"),
				volumeSweeper,
			),
		},
	}...)

	return grouper.NewParallel(os.Interrupt, members), nil
}

func (cmd *WorkerCommand) gardenIsExternal() bool {
	return cmd.ExternalGardenURL.URL != nil
}

func (cmd *WorkerCommand) gardenAddr() string {
	if cmd.gardenIsExternal() {
		return cmd.ExternalGardenURL.URL.Host
	}

	return fmt.Sprintf("%s:%d", cmd.BindIP, cmd.BindPort)
}

func (cmd *WorkerCommand) gardenURL() string {
	return fmt.Sprintf("http://%s", cmd.gardenAddr())
}

func (cmd *WorkerCommand) baggageclaimAddr() string {
	return fmt.Sprintf("%s:%d", cmd.Baggageclaim.BindIP, cmd.Baggageclaim.BindPort)
}

func (cmd *WorkerCommand) baggageclaimURL() string {
	return fmt.Sprintf("http://%s", cmd.baggageclaimAddr())
}

func (cmd *WorkerCommand) workerName() (string, error) {
	if cmd.Worker.Name != "" {
		return cmd.Worker.Name, nil
	}

	return os.Hostname()
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesDir := filepath.Join(cmd.WorkDir.Path(), "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	cmd.Baggageclaim.VolumesDir = flag.Dir(volumesDir)

	cmd.Baggageclaim.OverlaysDir = filepath.Join(cmd.WorkDir.Path(), "overlays")

	return cmd.Baggageclaim.Runner(nil)
}
<|endoftext|>


<commit_before>package cmd

import (
	"os"
	"time"

	"github.com/bpicode/fritzctl/console"
	"github.com/bpicode/fritzctl/fritz"
	"github.com/bpicode/fritzctl/logger"
	"github.com/bpicode/fritzctl/stringutils"
	"github.com/spf13/cobra"
)

var listThermostatsCmd = &cobra.Command{
	Use:     "thermostats",
	Short:   "List the available smart home thermostats",
	Long:    "List the available smart home devices [thermostats] and associated data.",
	Example: "fritzctl list thermostats",
	RunE:    listThermostats,
}

func init() {
	listCmd.AddCommand(listThermostatsCmd)
}

func listThermostats(_ *cobra.Command, _ []string) error {
	c := homeAutoClient()
	devs, err := c.List()
	assertNoErr(err, "cannot obtain thermostats device data")
	logger.Success("Device data:")

	table := thermostatsTable()
	appendThermostats(devs, table)
	table.Print(os.Stdout)
	return nil
}

var errorCodesVsDescriptions = map[string]string{
	"":  "",
	"0": "",
	"1": " Thermostat adjustment not possible. Is the device mounted correctly?",
	"2": " Valve plunger cannot be driven far enough. Possible solutions: Open and close the plunger a couple of times by hand. Check if the battery is too weak.",
	"3": " Valve plunger cannot be moved. Is it blocked?",
	"4": " Preparing installation.",
	"5": " Device in mode 'INSTALLATION'. It can be mounted now.",
	"6": " Device is adjusting to the valve plunger.",
}

func thermostatsTable() *console.Table {
	return console.NewTable(console.Headers(
		"NAME",
		"MANUFACTURER",
		"PRODUCTNAME",
		"PRESENT",
		"LOCK (BOX/DEV)",
		"MEASURED [°C]",
		"OFFSET [°C]",
		"WANT [°C]",
		"SAVING [°C]",
		"COMFORT [°C]",
		"NEXT",
		"STATE",
		"BATTERY",
	))
}

func appendThermostats(devs *fritz.Devicelist, table *console.Table) {
	for _, dev := range devs.Thermostats() {
		table.Append(thermostatColumns(dev))
	}
}

func thermostatColumns(dev fritz.Device) []string {
	var columnValues []string
	columnValues = appendMetadata(columnValues, dev)
	columnValues = appendRuntimeFlags(columnValues, dev)
	columnValues = appendTemperatureValues(columnValues, dev)
	columnValues = appendRuntimeWarnings(columnValues, dev)
	return columnValues
}

func appendMetadata(cols []string, dev fritz.Device) []string {
	return append(cols, dev.Name, dev.Manufacturer, dev.Productname)
}

func appendRuntimeFlags(cols []string, dev fritz.Device) []string {
	return append(cols,
		console.IntToCheckmark(dev.Present),
		console.StringToCheckmark(dev.Thermostat.Lock)+"/"+console.StringToCheckmark(dev.Thermostat.DeviceLock))
}

func appendRuntimeWarnings(cols []string, dev fritz.Device) []string {
	return append(cols, errorCode(dev.Thermostat.ErrorCode),
		console.Stoc(dev.Thermostat.BatteryLow).Inverse().String())
}

func appendTemperatureValues(cols []string, dev fritz.Device) []string {
	return append(cols,
		dev.Thermostat.FmtMeasuredTemperature(),
		dev.Temperature.FmtOffset(),
		dev.Thermostat.FmtGoalTemperature(),
		dev.Thermostat.FmtSavingTemperature(),
		dev.Thermostat.FmtComfortTemperature(),
		fmtNextChange(dev.Thermostat.NextChange))
}
func fmtNextChange(n fritz.NextChange) string {
	return stringutils.DefaultIfEmpty(n.FmtTimestamp(time.Now()), "?") +
		" -> " +
		stringutils.DefaultIfEmpty(n.FmtGoalTemperature(), "?") +
		"°C"
}

func errorCode(ec string) string {
	checkMark := console.Stoc(ec).Inverse()
	return checkMark.String() + errorCodesVsDescriptions[ec]
}
<commit_msg>join MANUFACTURER and PRODUCTNAME to PRODUCT in "list thermostats" table<commit_after>package cmd

import (
	"fmt"
	"os"
	"time"

	"github.com/bpicode/fritzctl/console"
	"github.com/bpicode/fritzctl/fritz"
	"github.com/bpicode/fritzctl/logger"
	"github.com/bpicode/fritzctl/stringutils"
	"github.com/spf13/cobra"
)

var listThermostatsCmd = &cobra.Command{
	Use:     "thermostats",
	Short:   "List the available smart home thermostats",
	Long:    "List the available smart home devices [thermostats] and associated data.",
	Example: "fritzctl list thermostats",
	RunE:    listThermostats,
}

func init() {
	listCmd.AddCommand(listThermostatsCmd)
}

func listThermostats(_ *cobra.Command, _ []string) error {
	c := homeAutoClient()
	devs, err := c.List()
	assertNoErr(err, "cannot obtain thermostats device data")
	logger.Success("Device data:")

	table := thermostatsTable()
	appendThermostats(devs, table)
	table.Print(os.Stdout)
	return nil
}
var errorCodesVsDescriptions = map[string]string{
	"":  "",
	"0": "",
	"1": " Thermostat adjustment not possible. Is the device mounted correctly?",
	"2": " Valve plunger cannot be driven far enough. Possible solutions: Open and close the plunger a couple of times by hand. Check if the battery is too weak.",
	"3": " Valve plunger cannot be moved. Is it blocked?",
	"4": " Preparing installation.",
	"5": " Device in mode 'INSTALLATION'. It can be mounted now.",
	"6": " Device is adjusting to the valve plunger.",
}

func thermostatsTable() *console.Table {
	return console.NewTable(console.Headers(
		"NAME",
		"PRODUCT",
		"PRESENT",
		"LOCK (BOX/DEV)",
		"MEASURED [°C]",
		"OFFSET [°C]",
		"WANT [°C]",
		"SAVING [°C]",
		"COMFORT [°C]",
		"NEXT",
		"STATE",
		"BATTERY",
	))
}

func appendThermostats(devs *fritz.Devicelist, table *console.Table) {
	for _, dev := range devs.Thermostats() {
		table.Append(thermostatColumns(dev))
	}
}

func thermostatColumns(dev fritz.Device) []string {
	var columnValues []string
	columnValues = appendMetadata(columnValues, dev)
	columnValues = appendRuntimeFlags(columnValues, dev)
	columnValues = appendTemperatureValues(columnValues, dev)
	columnValues = appendRuntimeWarnings(columnValues, dev)
	return columnValues
}

func appendMetadata(cols []string, dev fritz.Device) []string {
	return append(cols, dev.Name, fmt.Sprintf("%s %s", dev.Manufacturer, dev.Productname))
}

func appendRuntimeFlags(cols []string, dev fritz.Device) []string {
	return append(cols,
		console.IntToCheckmark(dev.Present),
		console.StringToCheckmark(dev.Thermostat.Lock)+"/"+console.StringToCheckmark(dev.Thermostat.DeviceLock))
}

func appendRuntimeWarnings(cols []string, dev fritz.Device) []string {
	return append(cols, errorCode(dev.Thermostat.ErrorCode),
		console.Stoc(dev.Thermostat.BatteryLow).Inverse().String())
}

func appendTemperatureValues(cols []string, dev fritz.Device) []string {
	return append(cols,
		dev.Thermostat.FmtMeasuredTemperature(),
		dev.Temperature.FmtOffset(),
		dev.Thermostat.FmtGoalTemperature(),
		dev.Thermostat.FmtSavingTemperature(),
		dev.Thermostat.FmtComfortTemperature(),
		fmtNextChange(dev.Thermostat.NextChange))
}
func fmtNextChange(n fritz.NextChange) string {
	return stringutils.DefaultIfEmpty(n.FmtTimestamp(time.Now()), "?") +
		" -> " +
		stringutils.DefaultIfEmpty(n.FmtGoalTemperature(), "?") +
		"°C"
}

func errorCode(ec string) string {
	checkMark := console.Stoc(ec).Inverse()
	return checkMark.String() + errorCodesVsDescriptions[ec]
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/sajari/word2vec"
)

var listen string
var path string

func init() {
	flag.StringVar(&listen, "listen", "localhost:1234", "bind `address` for HTTP server")
	flag.StringVar(&path, "p", "", "path to binary model data")
}

func main() {
	flag.Parse()

	if path == "" {
		fmt.Println("must specify -p; see -h for more details")
		os.Exit(1)
	}

	log.Println("Loading model...")
	f, err := os.Open(path)
	if err != nil {
		fmt.Printf("error opening binary model data file: %v\n", err)
		os.Exit(1)
	}
	defer f.Close()

	m, err := word2vec.FromReader(f)
	if err != nil {
		fmt.Printf("error reading binary model data: %v\n", err)
		os.Exit(1)
	}

	ms := word2vec.NewServer(m)

	log.Printf("Server listening on %v", listen)
	log.Println("Hit Ctrl-C to quit.")

	log.Fatal(http.ListenAndServe(listen, ms))
}
<commit_msg>Updated word-server doc and config variables.<commit_after>/*
word-server creates an HTTP server which exports endpoints for querying a word2vec model.
*/
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/sajari/word2vec"
)

var listen, modelPath string

func init() {
	flag.StringVar(&listen, "listen", "localhost:1234", "bind `address` for HTTP server")
	flag.StringVar(&modelPath, "model", "", "path to binary model data")
}

func main() {
	flag.Parse()

	if modelPath == "" {
		fmt.Println("must specify -p; see -h for more details")
		os.Exit(1)
	}

	log.Println("Loading model...")
	f, err := os.Open(modelPath)
	if err != nil {
		fmt.Printf("error opening binary model data file: %v\n", err)
		os.Exit(1)
	}
	defer f.Close()

	m, err := word2vec.FromReader(f)
	if err != nil {
		fmt.Printf("error reading binary model data: %v\n", err)
		os.Exit(1)
	}

	ms := word2vec.NewServer(m)

	log.Printf("Server listening on %v", listen)
	log.Println("Hit Ctrl-C to quit.")

	log.Fatal(http.ListenAndServe(listen, ms))
}
<|endoftext|>


<commit_before>package gateway

import (
	"fmt"
	"github.com/42wim/matterbridge/bridge"
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/peterhellberg/emojilib"
	//	"github.com/davecgh/go-spew/spew"
	"regexp"
	"strings"
	"time"
)

type Gateway struct {
	*config.Config
	MyConfig        *config.Gateway
	Bridges         map[string]*bridge.Bridge
	Channels        map[string]*config.ChannelInfo
	ChannelOptions  map[string]config.ChannelOptions
	Names           map[string]bool
	Name            string
	Message         chan config.Message
	DestChannelFunc func(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo
}

func New(cfg *config.Config) *Gateway {
	gw := &Gateway{}
	gw.Config = cfg
	gw.Channels = make(map[string]*config.ChannelInfo)
	gw.Message = make(chan config.Message)
	gw.Bridges = make(map[string]*bridge.Bridge)
	gw.Names = make(map[string]bool)
	gw.DestChannelFunc = gw.getDestChannel
	return gw
}

func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
	for _, br := range gw.Bridges {
		if br.Account == cfg.Account {
			gw.mapChannelsToBridge(br)
			err := br.JoinChannels()
			if err != nil {
				return fmt.Errorf("Bridge %s failed to join channel: %v", br.Account, err)
			}
			return nil
		}
	}
	log.Infof("Starting bridge: %s ", cfg.Account)
	br := bridge.New(gw.Config, cfg, gw.Message)
	gw.mapChannelsToBridge(br)
	gw.Bridges[cfg.Account] = br
	err := br.Connect()
	if err != nil {
		return fmt.Errorf("Bridge %s failed to start: %v", br.Account, err)
	}
	err = br.JoinChannels()
	if err != nil {
		return fmt.Errorf("Bridge %s failed to join channel: %v", br.Account, err)
	}
	return nil
}

func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
	if gw.Names[cfg.Name] {
		return fmt.Errorf("Gateway with name %s already exists", cfg.Name)
	}
	if cfg.Name == "" {
		return fmt.Errorf("%s", "Gateway without name found")
	}
	log.Infof("Starting gateway: %s", cfg.Name)
	gw.Names[cfg.Name] = true
	gw.Name = cfg.Name
	gw.MyConfig = cfg
	gw.mapChannels()
	for _, br := range append(gw.MyConfig.In, append(gw.MyConfig.InOut, gw.MyConfig.Out...)...) {
		err := gw.AddBridge(&br)
		if err != nil {
			return err
		}
	}
	return nil
}

func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge) {
	for ID, channel := range gw.Channels {
		if br.Account == channel.Account {
			br.Channels[ID] = *channel
		}
	}
}

func (gw *Gateway) Start() error {
	go gw.handleReceive()
	return nil
}

func (gw *Gateway) handleReceive() {
	for msg := range gw.Message {
		if msg.Event == config.EVENT_FAILURE {
			for _, br := range gw.Bridges {
				if msg.Account == br.Account {
					go gw.reconnectBridge(br)
				}
			}
		}
		if msg.Event == config.EVENT_REJOIN_CHANNELS {
			for _, br := range gw.Bridges {
				if msg.Account == br.Account {
					br.Joined = make(map[string]bool)
					br.JoinChannels()
				}
			}
			continue
		}
		if !gw.ignoreMessage(&msg) {
			msg.Timestamp = time.Now()
			gw.modifyMessage(&msg)
			for _, br := range gw.Bridges {
				gw.handleMessage(msg, br)
			}
		}
	}
}

func (gw *Gateway) reconnectBridge(br *bridge.Bridge) {
	br.Disconnect()
	time.Sleep(time.Second * 5)
RECONNECT:
	log.Infof("Reconnecting %s", br.Account)
	err := br.Connect()
	if err != nil {
		log.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err)
		time.Sleep(time.Second * 60)
		goto RECONNECT
	}
	br.Joined = make(map[string]bool)
	br.JoinChannels()
}

func (gw *Gateway) mapChannels() error {
	for _, br := range append(gw.MyConfig.Out, gw.MyConfig.InOut...) {
		if isApi(br.Account) {
			br.Channel = "api"
		}
		ID := br.Channel + br.Account
		_, ok := gw.Channels[ID]
		if !ok {
			channel := &config.ChannelInfo{Name: br.Channel, Direction: "out", ID: ID, Options: br.Options, Account: br.Account,
				GID: make(map[string]bool), SameChannel: make(map[string]bool)}
			channel.GID[gw.Name] = true
			channel.SameChannel[gw.Name] = br.SameChannel
			gw.Channels[channel.ID] = channel
		}
		gw.Channels[ID].GID[gw.Name] = true
		gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
	}

	for _, br := range append(gw.MyConfig.In, gw.MyConfig.InOut...) {
		if isApi(br.Account) {
			br.Channel = "api"
		}
		ID := br.Channel + br.Account
		_, ok := gw.Channels[ID]
		if !ok {
			channel := &config.ChannelInfo{Name: br.Channel, Direction: "in", ID: ID, Options: br.Options, Account: br.Account,
				GID: make(map[string]bool), SameChannel: make(map[string]bool)}
			channel.GID[gw.Name] = true
			channel.SameChannel[gw.Name] = br.SameChannel
			gw.Channels[channel.ID] = channel
		}
		gw.Channels[ID].GID[gw.Name] = true
		gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
	}
	return nil
}

func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo {
	var channels []config.ChannelInfo
	for _, channel := range gw.Channels {
		if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
			continue
		}
		// add gateway to message
		gw.validGatewayDest(msg, channel)

		// do samechannelgateway logic
		if channel.SameChannel[msg.Gateway] {
			if msg.Channel == channel.Name && msg.Account != dest.Account {
				channels = append(channels, *channel)
			}
			continue
		}

		if channel.Direction == "out" && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
			channels = append(channels, *channel)
		}
	}
	return channels
}

func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
	// only relay join/part when configged
	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
		return
	}
	// broadcast to every out channel (irc QUIT)
	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
		log.Debug("empty channel")
		return
	}
	originchannel := msg.Channel
	origmsg := msg
	for _, channel := range gw.DestChannelFunc(&msg, *dest) {
		// do not send to ourself
		if channel.ID == getChannelID(origmsg) {
			continue
		}
		log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
		msg.Channel = channel.Name
		msg.Avatar = gw.modifyAvatar(origmsg, dest)
		msg.Username = gw.modifyUsername(origmsg, dest)
		// for api we need originchannel as channel
		if dest.Protocol == "api" {
			msg.Channel = originchannel
		}
		err := dest.Send(msg)
		if err != nil {
			fmt.Println(err)
		}
	}
}

func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
	if msg.Text == "" {
		log.Debugf("ignoring empty message %#v from %s", msg, msg.Account)
		return true
	}
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreNicks) {
		if msg.Username == entry {
			log.Debugf("ignoring %s from %s", msg.Username, msg.Account)
			return true
		}
	}
	// TODO do not compile regexps everytime
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreMessages) {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				log.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(msg.Text) {
				log.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account)
				return true
			}
		}
	}
	return false
}

func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string {
	br := gw.Bridges[msg.Account]
	msg.Protocol = br.Protocol
	nick := gw.Config.General.RemoteNickFormat
	if nick == "" {
		nick = dest.Config.RemoteNickFormat
	}
	if len(msg.Username) > 0 {
		// fix utf-8 issue #193
		i := 0
		for index := range msg.Username {
			if i == 1 {
				i = index
				break
			}
			i++
		}
		nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1)
	}
	nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
	nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
	nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
	return nick
}

func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string {
	iconurl := gw.Config.General.IconURL
	if iconurl == "" {
		iconurl = dest.Config.IconURL
	}
	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
	if msg.Avatar == "" {
		msg.Avatar = iconurl
	}
	return msg.Avatar
}

func (gw *Gateway) modifyMessage(msg *config.Message) {
	// replace :emoji: to unicode
	msg.Text = emojilib.Replace(msg.Text)
}

func getChannelID(msg config.Message) string {
	return msg.Channel + msg.Account
}

func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool {
	GIDmap := gw.Channels[getChannelID(*msg)].GID

	// gateway is specified in message (probably from api)
	if msg.Gateway != "" {
		return channel.GID[msg.Gateway]
	}

	// check if we are running a samechannelgateway.
	// if it is and the channel name matches it's ok, otherwise we shouldn't use this channel.
	for k := range GIDmap {
		if channel.SameChannel[k] {
			if msg.Channel == channel.Name {
				// add the gateway to our message
				msg.Gateway = k
				return true
			} else {
				return false
			}
		}
	}
	// check if we are in the correct gateway
	for k := range GIDmap {
		if channel.GID[k] {
			// add the gateway to our message
			msg.Gateway = k
			return true
		}
	}
	return false
}

func isApi(account string) bool {
	return strings.HasPrefix(account, "api.")
}
<commit_msg>Fix in/out logic. Closes #224<commit_after>package gateway

import (
	"fmt"
	"github.com/42wim/matterbridge/bridge"
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/peterhellberg/emojilib"
	//	"github.com/davecgh/go-spew/spew"
	"regexp"
	"strings"
	"time"
)

type Gateway struct {
	*config.Config
	MyConfig        *config.Gateway
	Bridges         map[string]*bridge.Bridge
	Channels        map[string]*config.ChannelInfo
	ChannelOptions  map[string]config.ChannelOptions
	Names           map[string]bool
	Name            string
	Message         chan config.Message
	DestChannelFunc func(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo
}

func New(cfg *config.Config) *Gateway {
	gw := &Gateway{}
	gw.Config = cfg
	gw.Channels = make(map[string]*config.ChannelInfo)
	gw.Message = make(chan config.Message)
	gw.Bridges = make(map[string]*bridge.Bridge)
	gw.Names = make(map[string]bool)
	gw.DestChannelFunc = gw.getDestChannel
	return gw
}

func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
	for _, br := range gw.Bridges {
		if br.Account == cfg.Account {
			gw.mapChannelsToBridge(br)
			err := br.JoinChannels()
			if err != nil {
				return fmt.Errorf("Bridge %s failed to join channel: %v", br.Account, err)
			}
			return nil
		}
	}
	log.Infof("Starting bridge: %s ", cfg.Account)
	br := bridge.New(gw.Config, cfg, gw.Message)
	gw.mapChannelsToBridge(br)
	gw.Bridges[cfg.Account] = br
	err := br.Connect()
	if err != nil {
		return fmt.Errorf("Bridge %s failed to start: %v", br.Account, err)
	}
	err = br.JoinChannels()
	if err != nil {
		return fmt.Errorf("Bridge %s failed to join channel: %v", br.Account, err)
	}
	return nil
}

func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
	if gw.Names[cfg.Name] {
		return fmt.Errorf("Gateway with name %s already exists", cfg.Name)
	}
	if cfg.Name == "" {
		return fmt.Errorf("%s", "Gateway without name found")
	}
	log.Infof("Starting gateway: %s", cfg.Name)
	gw.Names[cfg.Name] = true
	gw.Name = cfg.Name
	gw.MyConfig = cfg
	gw.mapChannels()
	for _, br := range append(gw.MyConfig.In, append(gw.MyConfig.InOut, gw.MyConfig.Out...)...) {
		err := gw.AddBridge(&br)
		if err != nil {
			return err
		}
	}
	return nil
}

func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge) {
	for ID, channel := range gw.Channels {
		if br.Account == channel.Account {
			br.Channels[ID] = *channel
		}
	}
}

func (gw *Gateway) Start() error {
	go gw.handleReceive()
	return nil
}

func (gw *Gateway) handleReceive() {
	for msg := range gw.Message {
		if msg.Event == config.EVENT_FAILURE {
			for _, br := range gw.Bridges {
				if msg.Account == br.Account {
					go gw.reconnectBridge(br)
				}
			}
		}
		if msg.Event == config.EVENT_REJOIN_CHANNELS {
			for _, br := range gw.Bridges {
				if msg.Account == br.Account {
					br.Joined = make(map[string]bool)
					br.JoinChannels()
				}
			}
			continue
		}
		if !gw.ignoreMessage(&msg) {
			msg.Timestamp = time.Now()
			gw.modifyMessage(&msg)
			for _, br := range gw.Bridges {
				gw.handleMessage(msg, br)
			}
		}
	}
}

func (gw *Gateway) reconnectBridge(br *bridge.Bridge) {
	br.Disconnect()
	time.Sleep(time.Second * 5)
RECONNECT:
	log.Infof("Reconnecting %s", br.Account)
	err := br.Connect()
	if err != nil {
		log.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err)
		time.Sleep(time.Second * 60)
		goto RECONNECT
	}
	br.Joined = make(map[string]bool)
	br.JoinChannels()
}

func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) {
	for _, br := range cfg {
		if isApi(br.Account) {
			br.Channel = "api"
		}
		ID := br.Channel + br.Account
		if _, ok := gw.Channels[ID]; !ok {
			channel := &config.ChannelInfo{Name: br.Channel, Direction: direction, ID: ID, Options: br.Options, Account: br.Account,
				GID: make(map[string]bool), SameChannel: make(map[string]bool)}
			channel.GID[gw.Name] = true
			channel.SameChannel[gw.Name] = br.SameChannel
			gw.Channels[channel.ID] = channel
		} else {
			// if we already have a key and it's not our current direction it means we have a bidirectional inout
			if gw.Channels[ID].Direction != direction {
				gw.Channels[ID].Direction = "inout"
			}
		}
		gw.Channels[ID].GID[gw.Name] = true
		gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
	}
}
func (gw *Gateway) mapChannels() error {
	gw.mapChannelConfig(gw.MyConfig.In, "in")
	gw.mapChannelConfig(gw.MyConfig.Out, "out")
	gw.mapChannelConfig(gw.MyConfig.InOut, "inout")
	return nil
}

func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo {
	var channels []config.ChannelInfo
	// if source channel is in only, do nothing
	for _, channel := range gw.Channels {
		// lookup the channel from the message
		if channel.ID == getChannelID(*msg) {
			// we only have destinations if the original message is from an "in" (sending) channel
			if !strings.Contains(channel.Direction, "in") {
				return channels
			}
			continue
		}
	}
	for _, channel := range gw.Channels {
		if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
			continue
		}
		// add gateway to message
		gw.validGatewayDest(msg, channel)

		// do samechannelgateway logic
		if channel.SameChannel[msg.Gateway] {
			if msg.Channel == channel.Name && msg.Account != dest.Account {
				channels = append(channels, *channel)
			}
			continue
		}
		if strings.Contains(channel.Direction, "out") && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
			channels = append(channels, *channel)
		}
	}
	return channels
}

func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
	// only relay join/part when configged
	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
		return
	}
	// broadcast to every out channel (irc QUIT)
	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
		log.Debug("empty channel")
		return
	}
	originchannel := msg.Channel
	origmsg := msg
	for _, channel := range gw.DestChannelFunc(&msg, *dest) {
		// do not send to ourself
		if channel.ID == getChannelID(origmsg) {
			continue
		}
		log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
		msg.Channel = channel.Name
		msg.Avatar = gw.modifyAvatar(origmsg, dest)
		msg.Username = gw.modifyUsername(origmsg, dest)
		// for api we need originchannel as channel
		if dest.Protocol == "api" {
			msg.Channel = originchannel
		}
		err := dest.Send(msg)
		if err != nil {
			fmt.Println(err)
		}
	}
}

func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
	if msg.Text == "" {
		log.Debugf("ignoring empty message %#v from %s", msg, msg.Account)
		return true
	}
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreNicks) {
		if msg.Username == entry {
			log.Debugf("ignoring %s from %s", msg.Username, msg.Account)
			return true
		}
	}
	// TODO do not compile regexps everytime
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreMessages) {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				log.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(msg.Text) {
				log.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account)
				return true
			}
		}
	}
	return false
}

func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string {
	br := gw.Bridges[msg.Account]
	msg.Protocol = br.Protocol
	nick := gw.Config.General.RemoteNickFormat
	if nick == "" {
		nick = dest.Config.RemoteNickFormat
	}
	if len(msg.Username) > 0 {
		// fix utf-8 issue #193
		i := 0
		for index := range msg.Username {
			if i == 1 {
				i = index
				break
			}
			i++
		}
		nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1)
	}
	nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
	nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
	nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
	return nick
}

func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string {
	iconurl := gw.Config.General.IconURL
	if iconurl == "" {
		iconurl = dest.Config.IconURL
	}
	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
	if msg.Avatar == "" {
		msg.Avatar = iconurl
	}
	return msg.Avatar
}

func (gw *Gateway) modifyMessage(msg *config.Message) {
	// replace :emoji: to unicode
	msg.Text = emojilib.Replace(msg.Text)
}

func getChannelID(msg config.Message) string {
	return msg.Channel + msg.Account
}

func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool {
	GIDmap := gw.Channels[getChannelID(*msg)].GID

	// gateway is specified in message (probably from api)
	if msg.Gateway != "" {
		return channel.GID[msg.Gateway]
	}

	// check if we are running a samechannelgateway.
	// if it is and the channel name matches it's ok, otherwise we shouldn't use this channel.
	for k := range GIDmap {
		if channel.SameChannel[k] {
			if msg.Channel == channel.Name {
				// add the gateway to our message
				msg.Gateway = k
				return true
			} else {
				return false
			}
		}
	}
	// check if we are in the correct gateway
	for k := range GIDmap {
		if channel.GID[k] {
			// add the gateway to our message
			msg.Gateway = k
			return true
		}
	}
	return false
}

func isApi(account string) bool {
	return strings.HasPrefix(account, "api.")
}
<|endoftext|>


<commit_before><commit_msg>Fixed import<commit_after><|endoftext|>


<commit_before>// Tests of call chaining f(g()) when g has multiple return values (MRVs).
// See https://code.google.com/p/go/issues/detail?id=4573.

package main

func assert(actual, expected int) {
	if actual != expected {
		panic(actual)
	}
}

func g() (int, int) {
	return 5, 7
}

func g2() (float64, float64) {
	return 5, 7
}

func f1v(x int, v ...int) {
	assert(x, 5)
	assert(v[0], 7)
}

func f2(x, y int) {
	assert(x, 5)
	assert(y, 7)
}

func f2v(x, y int, v ...int) {
	assert(x, 5)
	assert(y, 7)
	assert(len(v), 0)
}

func complexArgs() (float64, float64) {
	return 5, 7
}

func appendArgs() ([]string, string) {
	return []string{"foo"}, "bar"
}

func h() (i interface{}, ok bool) {
	m := map[int]string{1: "hi"}
	i, ok = m[1] // string->interface{} conversion within multi-valued expression
	return
}

func main() {
	f1v(g())
	f2(g())
	f2v(g())
	// TODO(gri): the typechecker still doesn't support these cases correctly.
	// if c := complex(complexArgs()); c != 5+7i {
	// 	panic(c)
	// }
	// if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
	// 	panic(s)
	// }

	i, ok := h()
	if !ok || i.(string) != "hi" {
		panic(i)
	}
}
<commit_msg>go.tools/ssa/interp: enable tests of builtin(f()) where f has multiple results.<commit_after>// Tests of call chaining f(g()) when g has multiple return values (MRVs).
// See https://code.google.com/p/go/issues/detail?id=4573.

package main

func assert(actual, expected int) {
	if actual != expected {
		panic(actual)
	}
}

func g() (int, int) {
	return 5, 7
}

func g2() (float64, float64) {
	return 5, 7
}

func f1v(x int, v ...int) {
	assert(x, 5)
	assert(v[0], 7)
}

func f2(x, y int) {
	assert(x, 5)
	assert(y, 7)
}

func f2v(x, y int, v ...int) {
	assert(x, 5)
	assert(y, 7)
	assert(len(v), 0)
}

func complexArgs() (float64, float64) {
	return 5, 7
}

func appendArgs() ([]string, string) {
	return []string{"foo"}, "bar"
}

func h() (i interface{}, ok bool) {
	m := map[int]string{1: "hi"}
	i, ok = m[1] // string->interface{} conversion within multi-valued expression
	return
}

func main() {
	f1v(g())
	f2(g())
	f2v(g())
	if c := complex(complexArgs()); c != 5+7i {
		panic(c)
	}
	if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
		panic(s)
	}
	i, ok := h()
	if !ok || i.(string) != "hi" {
		panic(i)
	}
}
<|endoftext|>


<commit_before><commit_msg>leveldb: Add TestDb_LeveldbIssue200 testing<commit_after><|endoftext|>