<commit_before>/*
Copyright 2018 The Kubernetes 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 value

import (
	"encoding/json"
	"fmt"

	"gopkg.in/yaml.v2"
)

// FromYAML is a helper function for reading a YAML document; it attempts to
// preserve order of keys within maps/structs. This is as a convenience to
// humans keeping YAML documents, not because there is a behavior difference.
//
// Known bug: objects with top-level arrays don't parse correctly.
func FromYAML(input []byte) (Value, error) {
	var decoded interface{}

	if len(input) == 0 || (len(input) == 4 && string(input) == "null") {
		// Special case since the yaml package doesn't accurately
		// preserve this.
		return Value{Null: true}, nil
	}

	// This attempts to enable order sensitivity; note the yaml package is
	// broken for documents that have root-level arrays, hence the two-step
	// approach. TODO: This is a horrific hack. Is it worth it?
	var ms yaml.MapSlice
	if err := yaml.Unmarshal(input, &ms); err == nil {
		decoded = ms
	} else if err := yaml.Unmarshal(input, &decoded); err != nil {
		return Value{}, err
	}

	v, err := FromUnstructured(decoded)
	if err != nil {
		return Value{}, fmt.Errorf("failed to interpret (%v):\n%s", err, input)
	}
	return v, nil
}

// FromJSON is a helper function for reading a JSON document
func FromJSON(input []byte) (Value, error) {
	var decoded interface{}

	if err := yaml.Unmarshal(input, &decoded); err != nil {
		return Value{}, err
	}

	v, err := FromUnstructured(decoded)
	if err != nil {
		return Value{}, fmt.Errorf("failed to interpret (%v):\n%s", err, input)
	}
	return v, nil
}

// FromUnstructured will convert a go interface to a Value.
// It's most commonly expected to be used with map[string]interface{} as the
// input. `in` must not have any structures with cycles in them.
// yaml.MapSlice may be used for order-preservation.
func FromUnstructured(in interface{}) (Value, error) {
	if in == nil {
		return Value{Null: true}, nil
	}
	switch t := in.(type) {
	case map[interface{}]interface{}:
		m := Map{}
		for rawKey, rawVal := range t {
			k, ok := rawKey.(string)
			if !ok {
				return Value{}, fmt.Errorf("key %#v: not a string", k)
			}
			v, err := FromUnstructured(rawVal)
			if err != nil {
				return Value{}, fmt.Errorf("key %v: %v", k, err)
			}
			m.Set(k, v)
		}
		return Value{MapValue: &m}, nil
	case map[string]interface{}:
		m := Map{}
		for k, rawVal := range t {
			v, err := FromUnstructured(rawVal)
			if err != nil {
				return Value{}, fmt.Errorf("key %v: %v", k, err)
			}
			m.Set(k, v)
		}
		return Value{MapValue: &m}, nil
	case yaml.MapSlice:
		m := Map{}
		for _, item := range t {
			k, ok := item.Key.(string)
			if !ok {
				return Value{}, fmt.Errorf("key %#v is not a string", item.Key)
			}
			v, err := FromUnstructured(item.Value)
			if err != nil {
				return Value{}, fmt.Errorf("key %v: %v", k, err)
			}
			m.Set(k, v)
		}
		return Value{MapValue: &m}, nil
	case []interface{}:
		l := List{}
		for i, rawVal := range t {
			v, err := FromUnstructured(rawVal)
			if err != nil {
				return Value{}, fmt.Errorf("index %v: %v", i, err)
			}
			l.Items = append(l.Items, v)
		}
		return Value{ListValue: &l}, nil
	case int:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int8:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int16:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int32:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int64:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint8:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint16:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint32:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case float32:
		f := Float(t)
		return Value{FloatValue: &f}, nil
	case float64:
		f := Float(t)
		return Value{FloatValue: &f}, nil
	case string:
		return StringValue(t), nil
	case bool:
		return BooleanValue(t), nil
	default:
		return Value{}, fmt.Errorf("type unimplemented: %t", in)
	}
}

// ToYAML is a helper function for producing a YAML document; it attempts to
// preserve order of keys within maps/structs. This is as a convenience to
// humans keeping YAML documents, not because there is a behavior difference.
func (v *Value) ToYAML() ([]byte, error) {
	return yaml.Marshal(v.ToUnstructured(true))
}

// ToJSON is a helper function for producing a JSon document.
func (v *Value) ToJSON() ([]byte, error) {
	return json.Marshal(v.ToUnstructured(false))
}

// ToUnstructured will convert the Value into a go-typed object.
// If preserveOrder is true, then maps will be converted to the yaml.MapSlice
// type. Otherwise, map[string]interface{} must be used-- this destroys
// ordering information and is not recommended if the result of this will be
// serialized. Other types:
// * list -> []interface{}
// * others -> corresponding go type, wrapped in an interface{}
//
// Of note, floats and ints will always come out as float64 and int64,
// respectively.
func (v *Value) ToUnstructured(preserveOrder bool) interface{} {
	switch {
	case v.FloatValue != nil:
		f := float64(*v.FloatValue)
		return f
	case v.IntValue != nil:
		i := int64(*v.IntValue)
		return i
	case v.StringValue != nil:
		return string(*v.StringValue)
	case v.BooleanValue != nil:
		return bool(*v.BooleanValue)
	case v.ListValue != nil:
		out := []interface{}{}
		for _, item := range v.ListValue.Items {
			out = append(out, item.ToUnstructured(preserveOrder))
		}
		return out
	case v.MapValue != nil:
		m := v.MapValue
		if preserveOrder {
			ms := make(yaml.MapSlice, len(m.Items))
			for i := range m.Items {
				ms[i] = yaml.MapItem{
					Key:   m.Items[i].Name,
					Value: m.Items[i].Value.ToUnstructured(preserveOrder),
				}
			}
			return ms
		}
		// This case is unavoidably lossy.
		out := map[string]interface{}{}
		for i := range m.Items {
			out[m.Items[i].Name] = m.Items[i].Value.ToUnstructured(preserveOrder)
		}
		return out
	default:
		fallthrough
	case v.Null == true:
		return nil
	}
}
<commit_msg>Use json Unmarshaler rather than yaml<commit_after>/*
Copyright 2018 The Kubernetes 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 value

import (
	"encoding/json"
	"fmt"

	"gopkg.in/yaml.v2"
)

// FromYAML is a helper function for reading a YAML document; it attempts to
// preserve order of keys within maps/structs. This is as a convenience to
// humans keeping YAML documents, not because there is a behavior difference.
//
// Known bug: objects with top-level arrays don't parse correctly.
func FromYAML(input []byte) (Value, error) {
	var decoded interface{}

	if len(input) == 0 || (len(input) == 4 && string(input) == "null") {
		// Special case since the yaml package doesn't accurately
		// preserve this.
		return Value{Null: true}, nil
	}

	// This attempts to enable order sensitivity; note the yaml package is
	// broken for documents that have root-level arrays, hence the two-step
	// approach. TODO: This is a horrific hack. Is it worth it?
	var ms yaml.MapSlice
	if err := yaml.Unmarshal(input, &ms); err == nil {
		decoded = ms
	} else if err := yaml.Unmarshal(input, &decoded); err != nil {
		return Value{}, err
	}

	v, err := FromUnstructured(decoded)
	if err != nil {
		return Value{}, fmt.Errorf("failed to interpret (%v):\n%s", err, input)
	}
	return v, nil
}

// FromJSON is a helper function for reading a JSON document
func FromJSON(input []byte) (Value, error) {
	var decoded interface{}

	if err := json.Unmarshal(input, &decoded); err != nil {
		return Value{}, err
	}

	v, err := FromUnstructured(decoded)
	if err != nil {
		return Value{}, fmt.Errorf("failed to interpret (%v):\n%s", err, input)
	}
	return v, nil
}

// FromUnstructured will convert a go interface to a Value.
// It's most commonly expected to be used with map[string]interface{} as the
// input. `in` must not have any structures with cycles in them.
// yaml.MapSlice may be used for order-preservation.
func FromUnstructured(in interface{}) (Value, error) {
	if in == nil {
		return Value{Null: true}, nil
	}
	switch t := in.(type) {
	case map[interface{}]interface{}:
		m := Map{}
		for rawKey, rawVal := range t {
			k, ok := rawKey.(string)
			if !ok {
				return Value{}, fmt.Errorf("key %#v: not a string", k)
			}
			v, err := FromUnstructured(rawVal)
			if err != nil {
				return Value{}, fmt.Errorf("key %v: %v", k, err)
			}
			m.Set(k, v)
		}
		return Value{MapValue: &m}, nil
	case map[string]interface{}:
		m := Map{}
		for k, rawVal := range t {
			v, err := FromUnstructured(rawVal)
			if err != nil {
				return Value{}, fmt.Errorf("key %v: %v", k, err)
			}
			m.Set(k, v)
		}
		return Value{MapValue: &m}, nil
	case yaml.MapSlice:
		m := Map{}
		for _, item := range t {
			k, ok := item.Key.(string)
			if !ok {
				return Value{}, fmt.Errorf("key %#v is not a string", item.Key)
			}
			v, err := FromUnstructured(item.Value)
			if err != nil {
				return Value{}, fmt.Errorf("key %v: %v", k, err)
			}
			m.Set(k, v)
		}
		return Value{MapValue: &m}, nil
	case []interface{}:
		l := List{}
		for i, rawVal := range t {
			v, err := FromUnstructured(rawVal)
			if err != nil {
				return Value{}, fmt.Errorf("index %v: %v", i, err)
			}
			l.Items = append(l.Items, v)
		}
		return Value{ListValue: &l}, nil
	case int:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int8:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int16:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int32:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case int64:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint8:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint16:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case uint32:
		n := Int(t)
		return Value{IntValue: &n}, nil
	case float32:
		f := Float(t)
		return Value{FloatValue: &f}, nil
	case float64:
		f := Float(t)
		return Value{FloatValue: &f}, nil
	case string:
		return StringValue(t), nil
	case bool:
		return BooleanValue(t), nil
	default:
		return Value{}, fmt.Errorf("type unimplemented: %t", in)
	}
}

// ToYAML is a helper function for producing a YAML document; it attempts to
// preserve order of keys within maps/structs. This is as a convenience to
// humans keeping YAML documents, not because there is a behavior difference.
func (v *Value) ToYAML() ([]byte, error) {
	return yaml.Marshal(v.ToUnstructured(true))
}

// ToJSON is a helper function for producing a JSon document.
func (v *Value) ToJSON() ([]byte, error) {
	return json.Marshal(v.ToUnstructured(false))
}

// ToUnstructured will convert the Value into a go-typed object.
// If preserveOrder is true, then maps will be converted to the yaml.MapSlice
// type. Otherwise, map[string]interface{} must be used-- this destroys
// ordering information and is not recommended if the result of this will be
// serialized. Other types:
// * list -> []interface{}
// * others -> corresponding go type, wrapped in an interface{}
//
// Of note, floats and ints will always come out as float64 and int64,
// respectively.
func (v *Value) ToUnstructured(preserveOrder bool) interface{} {
	switch {
	case v.FloatValue != nil:
		f := float64(*v.FloatValue)
		return f
	case v.IntValue != nil:
		i := int64(*v.IntValue)
		return i
	case v.StringValue != nil:
		return string(*v.StringValue)
	case v.BooleanValue != nil:
		return bool(*v.BooleanValue)
	case v.ListValue != nil:
		out := []interface{}{}
		for _, item := range v.ListValue.Items {
			out = append(out, item.ToUnstructured(preserveOrder))
		}
		return out
	case v.MapValue != nil:
		m := v.MapValue
		if preserveOrder {
			ms := make(yaml.MapSlice, len(m.Items))
			for i := range m.Items {
				ms[i] = yaml.MapItem{
					Key:   m.Items[i].Name,
					Value: m.Items[i].Value.ToUnstructured(preserveOrder),
				}
			}
			return ms
		}
		// This case is unavoidably lossy.
		out := map[string]interface{}{}
		for i := range m.Items {
			out[m.Items[i].Name] = m.Items[i].Value.ToUnstructured(preserveOrder)
		}
		return out
	default:
		fallthrough
	case v.Null == true:
		return nil
	}
}
<|endoftext|>


<commit_before>package core

import (
	"io/ioutil"
	"os"
	"path"

	"github.com/BurntSushi/toml"
)

// Config represents the Goed configuration data.
type Config struct {
	SyntaxHighlighting bool
	Theme              string // ie: theme1.toml
	MaxCmdBufferLines  int    // Max # of lines to keep in buffer when running a command
}

func LoadConfig(file string) *Config {
	conf := LoadDefaultConfig()
	loc := path.Join(Home, file)
	if _, err := toml.DecodeFile(loc, &conf); err != nil {
		panic(err)
	}
	if conf.MaxCmdBufferLines == 0 {
		conf.MaxCmdBufferLines = 10000
	}
	return conf
}

func LoadDefaultConfig() *Config {
	loc := path.Join(Home, "config.toml")
	// If the config does not exist yet(first start ?), create it
	if _, err := os.Stat(loc); os.IsNotExist(err) {
		os.MkdirAll(Home, 0755)
		err := ioutil.WriteFile(loc, []byte(defaultConfig), 0755)
		if err != nil {
			panic(err)
		}
	}
	var conf *Config
	if _, err := toml.DecodeFile(loc, &conf); err != nil {
		panic(err)
	}
	return conf
}

var defaultConfig = `SyntaxHighlighting=true
Theme="default.toml"
MaxCmdBufferLines=10000
`
<commit_msg>Config from bundle<commit_after>package core

import "github.com/BurntSushi/toml"

// Config represents the Goed configuration data.
type Config struct {
	SyntaxHighlighting bool
	Theme              string // ie: theme1.toml
	MaxCmdBufferLines  int    // Max # of lines to keep in buffer when running a command
}

func LoadConfig(file string) *Config {
	conf := &Config{}
	loc := FindResource(file)
	if _, err := toml.DecodeFile(loc, conf); err != nil {
		panic(err)
	}
	if conf.MaxCmdBufferLines == 0 {
		conf.MaxCmdBufferLines = 10000
	}
	return conf
}
<|endoftext|>


<commit_before>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors
 * 	Gustav Simonsson <gustav.simonsson@gmail.com>
 * @date 2015
 *
 */

package crypto

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
)

// TODO: rename to KeyStore when replacing existing KeyStore
type KeyStore2 interface {
	// create new key using io.Reader entropy source and optionally using auth string
	GenerateNewKey(io.Reader, string) (*Key, error)
	GetKey([]byte, string) (*Key, error) // key from addr and auth string
	GetKeyAddresses() ([][]byte, error)  // get all addresses
	StoreKey(*Key, string) error         // store key optionally using auth string
	DeleteKey([]byte, string) error      // delete key by addr and auth string
}

type keyStorePlain struct {
	keysDirPath string
}

func NewKeyStorePlain(path string) KeyStore2 {
	return &keyStorePlain{path}
}

func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
	return GenerateNewKeyDefault(ks, rand, auth)
}

func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("GenerateNewKey error: %v", r)
		}
	}()
	key = NewKey(rand)
	err = ks.StoreKey(key, auth)
	return key, err
}

func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
	fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
	if err != nil {
		return nil, err
	}

	key = new(Key)
	err = json.Unmarshal(fileContent, key)
	return key, err
}

func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) {
	return GetKeyAddresses(ks.keysDirPath)
}

func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
	keyJSON, err := json.Marshal(key)
	if err != nil {
		return err
	}
	err = WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
	return err
}

func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) {
	keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
	err = os.RemoveAll(keyDirPath)
	return err
}

func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
	fileName := hex.EncodeToString(keyAddr)
	return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName))
}

func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
	addrHex := hex.EncodeToString(addr)
	keyDirPath := path.Join(keysDirPath, addrHex)
	keyFilePath := path.Join(keyDirPath, addrHex)
	err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
	if err != nil {
		return err
	}
	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
}

func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
	fileInfos, err := ioutil.ReadDir(keysDirPath)
	if err != nil {
		return nil, err
	}
	addresses = make([][]byte, 0)
	for _, fileInfo := range fileInfos {
		address, err := hex.DecodeString(fileInfo.Name())
		if err != nil {
			continue
		}
		addresses = append(addresses, address)
	}
	return addresses, err
}
<commit_msg>Remove unneeded allocation<commit_after>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors
 * 	Gustav Simonsson <gustav.simonsson@gmail.com>
 * @date 2015
 *
 */

package crypto

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
)

// TODO: rename to KeyStore when replacing existing KeyStore
type KeyStore2 interface {
	// create new key using io.Reader entropy source and optionally using auth string
	GenerateNewKey(io.Reader, string) (*Key, error)
	GetKey([]byte, string) (*Key, error) // key from addr and auth string
	GetKeyAddresses() ([][]byte, error)  // get all addresses
	StoreKey(*Key, string) error         // store key optionally using auth string
	DeleteKey([]byte, string) error      // delete key by addr and auth string
}

type keyStorePlain struct {
	keysDirPath string
}

func NewKeyStorePlain(path string) KeyStore2 {
	return &keyStorePlain{path}
}

func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
	return GenerateNewKeyDefault(ks, rand, auth)
}

func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("GenerateNewKey error: %v", r)
		}
	}()
	key = NewKey(rand)
	err = ks.StoreKey(key, auth)
	return key, err
}

func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
	fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
	if err != nil {
		return nil, err
	}

	key = new(Key)
	err = json.Unmarshal(fileContent, key)
	return key, err
}

func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) {
	return GetKeyAddresses(ks.keysDirPath)
}

func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
	keyJSON, err := json.Marshal(key)
	if err != nil {
		return err
	}
	err = WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
	return err
}

func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) {
	keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
	err = os.RemoveAll(keyDirPath)
	return err
}

func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
	fileName := hex.EncodeToString(keyAddr)
	return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName))
}

func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
	addrHex := hex.EncodeToString(addr)
	keyDirPath := path.Join(keysDirPath, addrHex)
	keyFilePath := path.Join(keyDirPath, addrHex)
	err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
	if err != nil {
		return err
	}
	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
}

func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
	fileInfos, err := ioutil.ReadDir(keysDirPath)
	if err != nil {
		return nil, err
	}
	for _, fileInfo := range fileInfos {
		address, err := hex.DecodeString(fileInfo.Name())
		if err != nil {
			continue
		}
		addresses = append(addresses, address)
	}
	return addresses, err
}
<|endoftext|>


<commit_before>package trdsql

// Convert JSON to a table.
// Supports the following JSON container types.
// * Array ([{c1: 1}, {c1: 2}, {c1: 3}])
// * Multiple JSON ({c1: 1}\n {c1: 2}\n {c1: 3}\n)

// Make a table from json
// or make the result of json filter by jq.
import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"

	"github.com/itchyny/gojq"
)

// JSONReader provides methods of the Reader interface.
type JSONReader struct {
	reader    *json.Decoder
	preRead   []map[string]string
	query     *gojq.Query
	names     []string
	types     []string
	limitRead bool
}

// NewJSONReader returns JSONReader and error.
func NewJSONReader(reader io.Reader, opts *ReadOpts) (*JSONReader, error) {
	r := &JSONReader{}
	r.reader = json.NewDecoder(reader)
	r.reader.UseNumber()
	var top interface{}

	if opts.InJQuery != "" {
		str := trimQuoteAll(opts.InJQuery)
		query, err := gojq.Parse(str)
		if err != nil {
			return nil, fmt.Errorf("gojq: %w (%s)", err, opts.InJQuery)
		}
		r.query = query
	}

	r.limitRead = opts.InLimitRead

	for i := 0; i < opts.InPreRead; i++ {
		err := r.reader.Decode(&top)
		if err != nil {
			if !errors.Is(err, io.EOF) {
				return r, err
			}
			debug.Printf(err.Error())
			return r, nil
		}

		if r.query == nil {
			r, err = r.readAhead(top)
			if err != nil {
				return nil, err
			}
		} else {
			iter := r.query.Run(top)
			for {
				v, ok := iter.Next()
				if !ok {
					break
				}
				if err, ok := v.(error); ok {
					debug.Printf("query %s", err.Error())
					continue
				}
				r, err = r.readAhead(v)
				if err != nil {
					return r, err
				}
			}
		}
	}

	return r, nil
}

// Names returns column names.
func (r *JSONReader) Names() ([]string, error) {
	return r.names, nil
}

// Types returns column types.
// All JSON types return the DefaultDBType.
func (r *JSONReader) Types() ([]string, error) {
	r.types = make([]string, len(r.names))
	for i := 0; i < len(r.names); i++ {
		r.types[i] = DefaultDBType
	}
	return r.types, nil
}

func (r *JSONReader) readAhead(top interface{}) (*JSONReader, error) {
	switch m := top.(type) {
	case []interface{}:
		// []
		r.preRead = make([]map[string]string, 0, len(m))
		if r.reader.More() {
			pre, names, err := etcRow(m)
			if err != nil {
				return nil, err
			}

			r.names = names
			r.preRead = append(r.preRead, pre)
			return r, nil
		}

		already := map[string]bool{}
		for _, v := range m {
			pre, names, err := topLevel(v)
			if err != nil {
				return nil, err
			}

			for k := 0; k < len(names); k++ {
				if !already[names[k]] {
					already[names[k]] = true
					r.names = append(r.names, names[k])
				}
			}

			r.preRead = append(r.preRead, pre)
		}
		return r, nil
	default:
		pre, names, err := topLevel(m)
		if err != nil {
			return nil, err
		}
		r.names = names
		r.preRead = append(r.preRead, pre)
	}
	return r, nil
}

func topLevel(top interface{}) (map[string]string, []string, error) {
	switch obj := top.(type) {
	case map[string]interface{}:
		return objectRow(obj)
	default:
		return etcRow(obj)
	}
}

// PreReadRow is returns only columns that store preread rows.
// One json (not jsonl) returns all rows with preRead.
func (r *JSONReader) PreReadRow() [][]interface{} {
	rows := make([][]interface{}, len(r.preRead))
	for n, v := range r.preRead {
		rows[n] = make([]interface{}, len(r.names))
		for i := range r.names {
			rows[n][i] = v[r.names[i]]
		}
	}
	return rows
}

// ReadRow is read the rest of the row.
// Only jsonl requires ReadRow in json.
func (r *JSONReader) ReadRow(row []interface{}) ([]interface{}, error) {
	if r.limitRead {
		return nil, io.EOF
	}

	var data interface{}
	err := r.reader.Decode(&data)
	if err != nil {
		return nil, err
	}

	if r.query != nil {
		// json query.
		return r.queryRun(row, data)
	}
	return r.rowParse(row, data), nil
}

func (r *JSONReader) queryRun(row []interface{}, jsonRow interface{}) ([]interface{}, error) {
	iter := r.query.Run(jsonRow)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			debug.Printf("query %s", err.Error())
			continue
		}
		row = r.rowParse(row, v)
	}
	return row, nil
}

func (r *JSONReader) rowParse(row []interface{}, jsonRow interface{}) []interface{} {
	switch m := jsonRow.(type) {
	case map[string]interface{}:
		for i := range r.names {
			row[i] = jsonString(m[r.names[i]])
		}
	default:
		for i := range r.names {
			row[i] = nil
		}
		row[0] = jsonString(jsonRow)
	}
	return row
}

func objectRow(obj map[string]interface{}) (map[string]string, []string, error) {
	// {"a":"b"} object
	names := make([]string, 0, len(obj))
	row := make(map[string]string)
	for k, v := range obj {
		names = append(names, k)
		row[k] = jsonString(v)
	}
	return row, names, nil
}

func etcRow(val interface{}) (map[string]string, []string, error) {
	// ex. array array
	// [["a"],
	//  ["b"]]
	var names []string
	k := "c1"
	names = append(names, k)
	row := make(map[string]string)
	row[k] = jsonString(val)
	return row, names, nil
}

func jsonString(val interface{}) string {
	switch val.(type) {
	case map[string]interface{}, []interface{}:
		str, err := json.Marshal(val)
		if err != nil {
			log.Printf("ERROR: jsonString:%s", err)
		}
		return ValString(str)
	default:
		return ValString(val)
	}
}
<commit_msg>Improved getting column names<commit_after>package trdsql

// Convert JSON to a table.
// Supports the following JSON container types.
// * Array ([{c1: 1}, {c1: 2}, {c1: 3}])
// * Multiple JSON ({c1: 1}\n {c1: 2}\n {c1: 3}\n)

// Make a table from json
// or make the result of json filter by jq.
import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"

	"github.com/itchyny/gojq"
)

// JSONReader provides methods of the Reader interface.
type JSONReader struct {
	reader    *json.Decoder
	preRead   []map[string]string
	query     *gojq.Query
	already   map[string]bool
	names     []string
	types     []string
	limitRead bool
}

// NewJSONReader returns JSONReader and error.
func NewJSONReader(reader io.Reader, opts *ReadOpts) (*JSONReader, error) {
	r := &JSONReader{}
	r.reader = json.NewDecoder(reader)
	r.reader.UseNumber()
	r.already = make(map[string]bool)
	var top interface{}

	if opts.InJQuery != "" {
		str := trimQuoteAll(opts.InJQuery)
		query, err := gojq.Parse(str)
		if err != nil {
			return nil, fmt.Errorf("gojq: %w (%s)", err, opts.InJQuery)
		}
		r.query = query
	}

	r.limitRead = opts.InLimitRead

	for i := 0; i < opts.InPreRead; i++ {
		err := r.reader.Decode(&top)
		if err != nil {
			if !errors.Is(err, io.EOF) {
				return r, err
			}
			debug.Printf(err.Error())
			return r, nil
		}
		if r.query == nil {
			r, err = r.readAhead(top)
			if err != nil {
				return nil, err
			}
		} else {
			iter := r.query.Run(top)
			for {
				v, ok := iter.Next()
				if !ok {
					break
				}
				if err, ok := v.(error); ok {
					debug.Printf("query %s", err.Error())
					continue
				}
				r, err = r.readAhead(v)
				if err != nil {
					return r, err
				}
			}
		}
	}

	return r, nil
}

// Names returns column names.
func (r *JSONReader) Names() ([]string, error) {
	return r.names, nil
}

// Types returns column types.
// All JSON types return the DefaultDBType.
func (r *JSONReader) Types() ([]string, error) {
	r.types = make([]string, len(r.names))
	for i := 0; i < len(r.names); i++ {
		r.types[i] = DefaultDBType
	}
	return r.types, nil
}

func (r *JSONReader) readAhead(top interface{}) (*JSONReader, error) {
	switch m := top.(type) {
	case []interface{}:
		// []
		r.preRead = make([]map[string]string, 0, len(m))
		if r.reader.More() {
			pre, names, err := etcRow(m)
			if err != nil {
				return nil, err
			}

			r.appendNames(names)
			r.preRead = append(r.preRead, pre)
			return r, nil
		}

		for _, v := range m {
			pre, names, err := topLevel(v)
			if err != nil {
				return nil, err
			}

			r.appendNames(names)
			r.preRead = append(r.preRead, pre)
		}
		return r, nil
	default:
		pre, names, err := topLevel(m)
		if err != nil {
			return nil, err
		}
		r.appendNames(names)
		r.preRead = append(r.preRead, pre)
	}
	return r, nil
}

// appendNames adds multiple names for the argument to be unique.
func (r *JSONReader) appendNames(names []string) {
	for _, name := range names {
		if !r.already[name] {
			r.already[name] = true
			r.names = append(r.names, name)
		}
	}
}

func topLevel(top interface{}) (map[string]string, []string, error) {
	switch obj := top.(type) {
	case map[string]interface{}:
		return objectRow(obj)
	default:
		return etcRow(obj)
	}
}

// PreReadRow is returns only columns that store preread rows.
// One json (not jsonl) returns all rows with preRead.
func (r *JSONReader) PreReadRow() [][]interface{} {
	rows := make([][]interface{}, len(r.preRead))
	for n, v := range r.preRead {
		rows[n] = make([]interface{}, len(r.names))
		for i := range r.names {
			rows[n][i] = v[r.names[i]]
		}
	}
	return rows
}

// ReadRow is read the rest of the row.
// Only jsonl requires ReadRow in json.
func (r *JSONReader) ReadRow(row []interface{}) ([]interface{}, error) {
	if r.limitRead {
		return nil, io.EOF
	}

	var data interface{}
	err := r.reader.Decode(&data)
	if err != nil {
		return nil, err
	}

	if r.query != nil {
		// json query.
		return r.queryRun(row, data)
	}
	return r.rowParse(row, data), nil
}

func (r *JSONReader) queryRun(row []interface{}, jsonRow interface{}) ([]interface{}, error) {
	iter := r.query.Run(jsonRow)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			debug.Printf("query %s", err.Error())
			continue
		}
		row = r.rowParse(row, v)
	}
	return row, nil
}

func (r *JSONReader) rowParse(row []interface{}, jsonRow interface{}) []interface{} {
	switch m := jsonRow.(type) {
	case map[string]interface{}:
		for i := range r.names {
			row[i] = jsonString(m[r.names[i]])
		}
	default:
		for i := range r.names {
			row[i] = nil
		}
		row[0] = jsonString(jsonRow)
	}
	return row
}

func objectRow(obj map[string]interface{}) (map[string]string, []string, error) {
	// {"a":"b"} object
	names := make([]string, 0, len(obj))
	row := make(map[string]string)
	for k, v := range obj {
		names = append(names, k)
		row[k] = jsonString(v)
	}
	return row, names, nil
}

func etcRow(val interface{}) (map[string]string, []string, error) {
	// ex. array array
	// [["a"],
	//  ["b"]]
	var names []string
	k := "c1"
	names = append(names, k)
	row := make(map[string]string)
	row[k] = jsonString(val)
	return row, names, nil
}

func jsonString(val interface{}) string {
	switch val.(type) {
	case map[string]interface{}, []interface{}:
		str, err := json.Marshal(val)
		if err != nil {
			log.Printf("ERROR: jsonString:%s", err)
		}
		return ValString(str)
	default:
		return ValString(val)
	}
}
<|endoftext|>


<commit_before>package mounttable

import (
	"errors"
	"net"
	"strconv"
	"strings"
	"time"

	"v.io/x/lib/netconfig"
	"v.io/x/ref/lib/glob"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/v23/rpc"
	"v.io/v23/security"
	"v.io/v23/services/mounttable"
	"v.io/v23/services/security/access"
	vdltime "v.io/v23/vdlroot/time"
	"v.io/v23/verror"
	"v.io/x/lib/vlog"

	mdns "github.com/presotto/go-mdns-sd"
)

const addressPrefix = "address:"

// neighborhood defines a set of machines on the same multicast media.
type neighborhood struct {
	mdns   *mdns.MDNS
	nelems int
	nw     netconfig.NetConfigWatcher
}

var _ rpc.Dispatcher = (*neighborhood)(nil)

type neighborhoodService struct {
	name  string
	elems []string
	nh    *neighborhood
}

func getPort(address string) uint16 {
	epAddr, _ := naming.SplitAddressName(address)

	ep, err := v23.NewEndpoint(epAddr)
	if err != nil {
		return 0
	}
	addr := ep.Addr()
	if addr == nil {
		return 0
	}
	switch addr.Network() {
	case "tcp", "tcp4", "tcp6", "ws", "ws4", "ws6", "wsh", "wsh4", "wsh6":
	default:
		return 0
	}
	_, pstr, err := net.SplitHostPort(addr.String())
	if err != nil {
		return 0
	}
	port, err := strconv.ParseUint(pstr, 10, 16)
	if err != nil || port == 0 {
		return 0
	}
	return uint16(port)
}

func newNeighborhood(host string, addresses []string, loopback bool) (*neighborhood, error) {
	// Create the TXT contents with addresses to announce. Also pick up a port number.
	var txt []string
	var port uint16
	for _, addr := range addresses {
		txt = append(txt, addressPrefix+addr)
		if port == 0 {
			port = getPort(addr)
		}
	}
	if txt == nil {
		return nil, errors.New("neighborhood passed no useful addresses")
	}
	if port == 0 {
		return nil, errors.New("neighborhood couldn't determine a port to use")
	}

	// Start up MDNS, subscribe to the vanadium service, and add us as a vanadium service provider.
	mdns, err := mdns.NewMDNS(host, "", "", loopback, false)
	if err != nil {
		vlog.Errorf("mdns startup failed: %s", err)
		return nil, err
	}
	vlog.VI(2).Infof("listening for service vanadium on port %d", port)
	mdns.SubscribeToService("veyron")
	mdns.AddService("veyron", "", port, txt...)

	nh := &neighborhood{
		mdns: mdns,
	}

	// Watch the network configuration so that we can make MDNS reattach to
	// interfaces when the network changes.
	nh.nw, err = netconfig.NewNetConfigWatcher()
	if err != nil {
		vlog.Errorf("nighborhood can't watch network: %s", err)
		return nh, nil
	}
	go func() {
		if _, ok := <-nh.nw.Channel(); !ok {
			return
		}
		if _, err := nh.mdns.ScanInterfaces(); err != nil {
			vlog.Errorf("nighborhood can't scan interfaces: %s", err)
		}
	}()

	return nh, nil
}

// NewLoopbackNeighborhoodDispatcher creates a new instance of a dispatcher for
// a neighborhood service provider on loopback interfaces (meant for testing).
func NewLoopbackNeighborhoodDispatcher(host string, addresses ...string) (rpc.Dispatcher, error) {
	return newNeighborhood(host, addresses, true)
}

// NewNeighborhoodDispatcher creates a new instance of a dispatcher for a
// neighborhood service provider.
func NewNeighborhoodDispatcher(host string, addresses ...string) (rpc.Dispatcher, error) {
	return newNeighborhood(host, addresses, false)
}

// Lookup implements rpc.Dispatcher.Lookup.
func (nh *neighborhood) Lookup(name string) (interface{}, security.Authorizer, error) {
	vlog.VI(1).Infof("*********************LookupServer '%s'\n", name)
	elems := strings.Split(name, "/")[nh.nelems:]
	if name == "" {
		elems = nil
	}
	ns := &neighborhoodService{
		name:  name,
		elems: elems,
		nh:    nh,
	}
	return mounttable.MountTableServer(ns), nh, nil
}

func (nh *neighborhood) Authorize(*context.T) error {
	// TODO(rthellend): Figure out whether it's OK to accept all requests
	// unconditionally.
	return nil
}

// Stop performs cleanup.
func (nh *neighborhood) Stop() {
	if nh.nw != nil {
		nh.nw.Stop()
	}
	nh.mdns.Stop()
}

// neighbor returns the MountedServers for a particular neighbor.
func (nh *neighborhood) neighbor(instance string) []naming.MountedServer {
	now := time.Now()
	var reply []naming.MountedServer
	si := nh.mdns.ResolveInstance(instance, "veyron")

	// Use a map to dedup any addresses seen
	addrMap := make(map[string]vdltime.Deadline)

	// Look for any TXT records with addresses.
	for _, rr := range si.TxtRRs {
		for _, s := range rr.Txt {
			if !strings.HasPrefix(s, addressPrefix) {
				continue
			}
			addr := s[len(addressPrefix):]
			ttl := time.Second * time.Duration(rr.Header().Ttl)
			addrMap[addr] = vdltime.Deadline{now.Add(ttl)}
		}
	}
	for addr, deadline := range addrMap {
		reply = append(reply, naming.MountedServer{addr, nil, deadline})
	}

	if reply != nil {
		return reply
	}

	// If we didn't get any direct endpoints, make some up from the target and port.
	// TODO(rthellend): Do we need the code below? If we haven't received
	// any results at this point, it would seem to indicate a bug somewhere
	// because NeighborhoodServer won't start without at least one address.
	for _, rr := range si.SrvRRs {
		ips, ttl := nh.mdns.ResolveAddress(rr.Target)
		for _, ip := range ips {
			addr := net.JoinHostPort(ip.String(), strconv.Itoa(int(rr.Port)))
			ep := naming.FormatEndpoint("tcp", addr)
			deadline := vdltime.Deadline{now.Add(time.Second * time.Duration(ttl))}
			reply = append(reply, naming.MountedServer{naming.JoinAddressName(ep, ""), nil, deadline})
		}
	}
	return reply
}

// neighbors returns all neighbors and their MountedServer structs.
func (nh *neighborhood) neighbors() map[string][]naming.MountedServer {
	neighbors := make(map[string][]naming.MountedServer, 0)
	members := nh.mdns.ServiceDiscovery("veyron")
	for _, m := range members {
		if neighbor := nh.neighbor(m.Name); neighbor != nil {
			neighbors[m.Name] = neighbor
		}
	}
	vlog.VI(2).Infof("members %v neighbors %v", members, neighbors)
	return neighbors
}

// ResolveStepX implements ResolveStepX
func (ns *neighborhoodService) ResolveStepX(call rpc.ServerCall) (entry naming.MountEntry, err error) {
	return ns.ResolveStep(call)
}

// ResolveStep implements ResolveStep
func (ns *neighborhoodService) ResolveStep(call rpc.ServerCall) (entry naming.MountEntry, err error) {
	nh := ns.nh
	vlog.VI(2).Infof("ResolveStep %v\n", ns.elems)
	if len(ns.elems) == 0 {
		//nothing can be mounted at the root
		err = verror.New(naming.ErrNoSuchNameRoot, call.Context(), ns.elems)
		return
	}

	// We can only resolve the first element and it always refers to a mount table (for now).
	neighbor := nh.neighbor(ns.elems[0])
	if neighbor == nil {
		err = verror.New(naming.ErrNoSuchName, call.Context(), ns.elems)
		entry.Name = ns.name
		return
	}
	entry.ServesMountTable = true
	entry.Name = naming.Join(ns.elems[1:]...)
	entry.Servers = neighbor
	return
}

// Mount not implemented.
func (ns *neighborhoodService) Mount(call rpc.ServerCall, server string, ttlsecs uint32, opts naming.MountFlag) error {
	return ns.MountX(call, server, nil, ttlsecs, opts)
}
func (ns *neighborhoodService) MountX(_ rpc.ServerCall, _ string, _ []security.BlessingPattern, _ uint32, _ naming.MountFlag) error {
	return errors.New("this server does not implement Mount")
}

// Unmount not implemented.
func (*neighborhoodService) Unmount(_ rpc.ServerCall, _ string) error {
	return errors.New("this server does not implement Unmount")
}

// Delete not implemented.
func (*neighborhoodService) Delete(_ rpc.ServerCall, _ bool) error {
	return errors.New("this server does not implement Delete")
}

// Glob__ implements rpc.AllGlobber
func (ns *neighborhoodService) Glob__(call rpc.ServerCall, pattern string) (<-chan naming.GlobReply, error) {
	g, err := glob.Parse(pattern)
	if err != nil {
		return nil, err
	}

	// return all neighbors that match the first element of the pattern.
	nh := ns.nh

	switch len(ns.elems) {
	case 0:
		ch := make(chan naming.GlobReply)
		go func() {
			defer close(ch)
			for k, n := range nh.neighbors() {
				if ok, _, _ := g.MatchInitialSegment(k); !ok {
					continue
				}
				ch <- naming.GlobReplyEntry{naming.MountEntry{Name: k, Servers: n, ServesMountTable: true}}
			}
		}()
		return ch, nil
	case 1:
		neighbor := nh.neighbor(ns.elems[0])
		if neighbor == nil {
			return nil, verror.New(naming.ErrNoSuchName, call.Context(), ns.elems[0])
		}
		ch := make(chan naming.GlobReply, 1)
		ch <- naming.GlobReplyEntry{naming.MountEntry{Name: "", Servers: neighbor, ServesMountTable: true}}
		close(ch)
		return ch, nil
	default:
		return nil, verror.New(naming.ErrNoSuchName, call.Context(), ns.elems)
	}
}

func (*neighborhoodService) SetPermissions(call rpc.ServerCall, acl access.Permissions, etag string) error {
	return errors.New("this server does not implement SetPermissions")
}

func (*neighborhoodService) GetPermissions(call rpc.ServerCall) (acl access.Permissions, etag string, err error) {
	return nil, "", nil
}
<commit_msg>neighborhood:  Remove an obsolete piece of code.  It existed to keep us backward compatible till we started passing endpoints in the neihgborhood announcements.<commit_after>package mounttable

import (
	"errors"
	"net"
	"strconv"
	"strings"
	"time"

	"v.io/x/lib/netconfig"
	"v.io/x/ref/lib/glob"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/v23/rpc"
	"v.io/v23/security"
	"v.io/v23/services/mounttable"
	"v.io/v23/services/security/access"
	vdltime "v.io/v23/vdlroot/time"
	"v.io/v23/verror"
	"v.io/x/lib/vlog"

	mdns "github.com/presotto/go-mdns-sd"
)

const addressPrefix = "address:"

// neighborhood defines a set of machines on the same multicast media.
type neighborhood struct {
	mdns   *mdns.MDNS
	nelems int
	nw     netconfig.NetConfigWatcher
}

var _ rpc.Dispatcher = (*neighborhood)(nil)

type neighborhoodService struct {
	name  string
	elems []string
	nh    *neighborhood
}

func getPort(address string) uint16 {
	epAddr, _ := naming.SplitAddressName(address)

	ep, err := v23.NewEndpoint(epAddr)
	if err != nil {
		return 0
	}
	addr := ep.Addr()
	if addr == nil {
		return 0
	}
	switch addr.Network() {
	case "tcp", "tcp4", "tcp6", "ws", "ws4", "ws6", "wsh", "wsh4", "wsh6":
	default:
		return 0
	}
	_, pstr, err := net.SplitHostPort(addr.String())
	if err != nil {
		return 0
	}
	port, err := strconv.ParseUint(pstr, 10, 16)
	if err != nil || port == 0 {
		return 0
	}
	return uint16(port)
}

func newNeighborhood(host string, addresses []string, loopback bool) (*neighborhood, error) {
	// Create the TXT contents with addresses to announce. Also pick up a port number.
	var txt []string
	var port uint16
	for _, addr := range addresses {
		txt = append(txt, addressPrefix+addr)
		if port == 0 {
			port = getPort(addr)
		}
	}
	if txt == nil {
		return nil, errors.New("neighborhood passed no useful addresses")
	}
	if port == 0 {
		return nil, errors.New("neighborhood couldn't determine a port to use")
	}

	// Start up MDNS, subscribe to the vanadium service, and add us as a vanadium service provider.
	mdns, err := mdns.NewMDNS(host, "", "", loopback, false)
	if err != nil {
		vlog.Errorf("mdns startup failed: %s", err)
		return nil, err
	}
	vlog.VI(2).Infof("listening for service vanadium on port %d", port)
	mdns.SubscribeToService("veyron")
	mdns.AddService("veyron", "", port, txt...)

	nh := &neighborhood{
		mdns: mdns,
	}

	// Watch the network configuration so that we can make MDNS reattach to
	// interfaces when the network changes.
	nh.nw, err = netconfig.NewNetConfigWatcher()
	if err != nil {
		vlog.Errorf("nighborhood can't watch network: %s", err)
		return nh, nil
	}
	go func() {
		if _, ok := <-nh.nw.Channel(); !ok {
			return
		}
		if _, err := nh.mdns.ScanInterfaces(); err != nil {
			vlog.Errorf("nighborhood can't scan interfaces: %s", err)
		}
	}()

	return nh, nil
}

// NewLoopbackNeighborhoodDispatcher creates a new instance of a dispatcher for
// a neighborhood service provider on loopback interfaces (meant for testing).
func NewLoopbackNeighborhoodDispatcher(host string, addresses ...string) (rpc.Dispatcher, error) {
	return newNeighborhood(host, addresses, true)
}

// NewNeighborhoodDispatcher creates a new instance of a dispatcher for a
// neighborhood service provider.
func NewNeighborhoodDispatcher(host string, addresses ...string) (rpc.Dispatcher, error) {
	return newNeighborhood(host, addresses, false)
}

// Lookup implements rpc.Dispatcher.Lookup.
func (nh *neighborhood) Lookup(name string) (interface{}, security.Authorizer, error) {
	vlog.VI(1).Infof("*********************LookupServer '%s'\n", name)
	elems := strings.Split(name, "/")[nh.nelems:]
	if name == "" {
		elems = nil
	}
	ns := &neighborhoodService{
		name:  name,
		elems: elems,
		nh:    nh,
	}
	return mounttable.MountTableServer(ns), nh, nil
}

func (nh *neighborhood) Authorize(*context.T) error {
	// TODO(rthellend): Figure out whether it's OK to accept all requests
	// unconditionally.
	return nil
}

// Stop performs cleanup.
func (nh *neighborhood) Stop() {
	if nh.nw != nil {
		nh.nw.Stop()
	}
	nh.mdns.Stop()
}

// neighbor returns the MountedServers for a particular neighbor.
func (nh *neighborhood) neighbor(instance string) []naming.MountedServer {
	now := time.Now()
	var reply []naming.MountedServer
	si := nh.mdns.ResolveInstance(instance, "veyron")

	// Use a map to dedup any addresses seen
	addrMap := make(map[string]vdltime.Deadline)

	// Look for any TXT records with addresses.
	for _, rr := range si.TxtRRs {
		for _, s := range rr.Txt {
			if !strings.HasPrefix(s, addressPrefix) {
				continue
			}
			addr := s[len(addressPrefix):]
			ttl := time.Second * time.Duration(rr.Header().Ttl)
			addrMap[addr] = vdltime.Deadline{now.Add(ttl)}
		}
	}
	for addr, deadline := range addrMap {
		reply = append(reply, naming.MountedServer{addr, nil, deadline})
	}
	return reply
}

// neighbors returns all neighbors and their MountedServer structs.
func (nh *neighborhood) neighbors() map[string][]naming.MountedServer {
	neighbors := make(map[string][]naming.MountedServer, 0)
	members := nh.mdns.ServiceDiscovery("veyron")
	for _, m := range members {
		if neighbor := nh.neighbor(m.Name); neighbor != nil {
			neighbors[m.Name] = neighbor
		}
	}
	vlog.VI(2).Infof("members %v neighbors %v", members, neighbors)
	return neighbors
}

// ResolveStepX implements ResolveStepX
func (ns *neighborhoodService) ResolveStepX(call rpc.ServerCall) (entry naming.MountEntry, err error) {
	return ns.ResolveStep(call)
}

// ResolveStep implements ResolveStep
func (ns *neighborhoodService) ResolveStep(call rpc.ServerCall) (entry naming.MountEntry, err error) {
	nh := ns.nh
	vlog.VI(2).Infof("ResolveStep %v\n", ns.elems)
	if len(ns.elems) == 0 {
		//nothing can be mounted at the root
		err = verror.New(naming.ErrNoSuchNameRoot, call.Context(), ns.elems)
		return
	}

	// We can only resolve the first element and it always refers to a mount table (for now).
	neighbor := nh.neighbor(ns.elems[0])
	if neighbor == nil {
		err = verror.New(naming.ErrNoSuchName, call.Context(), ns.elems)
		entry.Name = ns.name
		return
	}
	entry.ServesMountTable = true
	entry.Name = naming.Join(ns.elems[1:]...)
	entry.Servers = neighbor
	return
}

// Mount not implemented.
func (ns *neighborhoodService) Mount(call rpc.ServerCall, server string, ttlsecs uint32, opts naming.MountFlag) error {
	return ns.MountX(call, server, nil, ttlsecs, opts)
}
func (ns *neighborhoodService) MountX(_ rpc.ServerCall, _ string, _ []security.BlessingPattern, _ uint32, _ naming.MountFlag) error {
	return errors.New("this server does not implement Mount")
}

// Unmount not implemented.
func (*neighborhoodService) Unmount(_ rpc.ServerCall, _ string) error {
	return errors.New("this server does not implement Unmount")
}

// Delete not implemented.
func (*neighborhoodService) Delete(_ rpc.ServerCall, _ bool) error {
	return errors.New("this server does not implement Delete")
}

// Glob__ implements rpc.AllGlobber
func (ns *neighborhoodService) Glob__(call rpc.ServerCall, pattern string) (<-chan naming.GlobReply, error) {
	g, err := glob.Parse(pattern)
	if err != nil {
		return nil, err
	}

	// return all neighbors that match the first element of the pattern.
	nh := ns.nh

	switch len(ns.elems) {
	case 0:
		ch := make(chan naming.GlobReply)
		go func() {
			defer close(ch)
			for k, n := range nh.neighbors() {
				if ok, _, _ := g.MatchInitialSegment(k); !ok {
					continue
				}
				ch <- naming.GlobReplyEntry{naming.MountEntry{Name: k, Servers: n, ServesMountTable: true}}
			}
		}()
		return ch, nil
	case 1:
		neighbor := nh.neighbor(ns.elems[0])
		if neighbor == nil {
			return nil, verror.New(naming.ErrNoSuchName, call.Context(), ns.elems[0])
		}
		ch := make(chan naming.GlobReply, 1)
		ch <- naming.GlobReplyEntry{naming.MountEntry{Name: "", Servers: neighbor, ServesMountTable: true}}
		close(ch)
		return ch, nil
	default:
		return nil, verror.New(naming.ErrNoSuchName, call.Context(), ns.elems)
	}
}

func (*neighborhoodService) SetPermissions(call rpc.ServerCall, acl access.Permissions, etag string) error {
	return errors.New("this server does not implement SetPermissions")
}

func (*neighborhoodService) GetPermissions(call rpc.ServerCall) (acl access.Permissions, etag string, err error) {
	return nil, "", nil
}
<|endoftext|>


<commit_before>package node

import (
	"github.com/AutoRoute/l2"
)

// The layer two protocol takes a layer two device and returns the hash of the
// Public Key of all neighbors it can find.
type NeighborFinder interface {
	Find(l2.FrameReadWriter) <-chan string
}

// A map of a fixed size representing an interfaces potential
type ReachabilityMap interface{}

// A receipt listing packets which have been succesfully deliver.
type PacketReceipt interface{}

// Layer three interfaces for network control traffic
type MapConnection interface {
	ReadabilityMaps() <-chan ReachabilityMap
}
type ReceiptConnection interface {
	PacketReceipts() <-chan PacketReceipt
}

// While the two connections use different messages, a working ControlConnection has both interfaces
type ControlConnection interface {
	MapConnection
	ReceptConnection
}

// The actual data connection. Should be done at the layer two level in order to be able to send congestion signals
type DataConnection interface {
	SendPacket([]byte)
}
<commit_msg>Made interfaces make more sense, since you can now send items<commit_after>package node

import (
	"github.com/AutoRoute/l2"
)

// The layer two protocol takes a layer two device and returns the hash of the
// Public Key of all neighbors it can find.
type NeighborFinder interface {
	Find(l2.FrameReadWriter) <-chan string
}

// A map of a fixed size representing an interfaces potential
type ReachabilityMap interface{}

// A receipt listing packets which have been succesfully deliver.
type PacketReceipt interface{}

// Layer three interfaces for network control traffic
type MapConnection interface {
	SendMap(ReachabilityMap)
	ReadabilityMaps() <-chan ReachabilityMap
}
type ReceiptConnection interface {
	SendReceipt(PacketReceipt)
	PacketReceipts() <-chan PacketReceipt
}

// While the two connections use different messages, a working ControlConnection has both interfaces
type ControlConnection interface {
	MapConnection
	ReceiptConnection
}

// The actual data connection. Should be done at the layer two level in order to be able to send congestion signals
type DataConnection interface {
	SendPacket([]byte)
	Packets() <-chan []byte
}
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// vespa clone command
// author: bratseth

package cmd

import (
	"archive/zip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
)

func newCloneCmd(cli *CLI) *cobra.Command {
	var (
		listApps   bool
		forceClone bool
	)
	cmd := &cobra.Command{
		Use:   "clone sample-application-path target-directory",
		Short: "Create files and directory structure for a new Vespa application from a sample application",
		Long: `Create files and directory structure for a new Vespa application
from a sample application.

Sample applications are downloaded from
https://github.com/vespa-engine/sample-apps.

By default sample applications are cached in the user's cache directory. This
directory can be overriden by setting the VESPA_CLI_CACHE_DIR environment
variable.`,
		Example:           "$ vespa clone vespa-cloud/album-recommendation my-app",
		DisableAutoGenTag: true,
		SilenceUsage:      true,
		RunE: func(cmd *cobra.Command, args []string) error {
			if listApps {
				apps, err := listSampleApps(cli.httpClient)
				if err != nil {
					return fmt.Errorf("could not list sample applications: %w", err)
				}
				for _, app := range apps {
					log.Print(app)
				}
				return nil
			}
			if len(args) != 2 {
				return fmt.Errorf("expected exactly 2 arguments, got %d", len(args))
			}
			return cloneApplication(cli, args[0], args[1], forceClone)
		},
	}
	cmd.Flags().BoolVarP(&listApps, "list", "l", false, "List available sample applications")
	cmd.Flags().BoolVarP(&forceClone, "force", "f", false, "Ignore cache and force downloading the latest sample application from GitHub")
	return cmd
}

func cloneApplication(cli *CLI, applicationName string, applicationDir string, force bool) error {
	zipFile, err := openSampleAppsZip(force, cli)
	if err != nil {
		return err
	}
	defer zipFile.Close()

	r, err := zip.OpenReader(zipFile.Name())
	if err != nil {
		return fmt.Errorf("could not open sample apps zip '%s': %w", color.CyanString(zipFile.Name()), err)
	}
	defer r.Close()

	found := false
	for _, f := range r.File {
		dirPrefix := "sample-apps-master/" + applicationName + "/"
		if strings.HasPrefix(f.Name, dirPrefix) {
			if !found { // Create destination directory lazily when source is found
				createErr := os.Mkdir(applicationDir, 0755)
				if createErr != nil {
					return fmt.Errorf("could not create directory '%s': %w", color.CyanString(applicationDir), createErr)
				}
			}
			found = true

			if err := copy(f, applicationDir, dirPrefix); err != nil {
				return fmt.Errorf("could not copy zip entry '%s': %w", color.CyanString(f.Name), err)
			}
		}
	}
	if !found {
		return errHint(fmt.Errorf("could not find source application '%s'", color.CyanString(applicationName)), "Use -f to ignore the cache")
	} else {
		log.Print("Created ", color.CyanString(applicationDir))
	}
	return nil
}

func useCache(force bool, stat os.FileInfo) (bool, error) {
	if force {
		return false, nil
	}
	expiry := stat.ModTime().Add(time.Hour * 168) // 1 week
	return stat.Size() > 0 && time.Now().Before(expiry), nil
}

func fetchSampleAppsZip(destination string, cli *CLI) error {
	f, err := ioutil.TempFile(filepath.Dir(destination), "sample-apps")
	if err != nil {
		return fmt.Errorf("could not create temporary file: %w", err)
	}
	defer f.Close()
	return cli.spinner(cli.Stderr, color.YellowString("Downloading sample apps ..."), func() error {
		request, err := http.NewRequest("GET", "https://github.com/vespa-engine/sample-apps/archive/refs/heads/master.zip", nil)
		if err != nil {
			return fmt.Errorf("invalid url: %w", err)
		}
		response, err := cli.httpClient.Do(request, time.Minute*60)
		if err != nil {
			return fmt.Errorf("could not download sample apps: %w", err)
		}
		defer response.Body.Close()
		if response.StatusCode != http.StatusOK {
			return fmt.Errorf("could not download sample apps: github returned status %d", response.StatusCode)
		}
		if _, err := io.Copy(f, response.Body); err != nil {
			return fmt.Errorf("could not write sample apps to file: %s: %w", f.Name(), err)
		}
		f.Close()
		if err := os.Rename(f.Name(), destination); err != nil {
			return fmt.Errorf("could not move sample apps to cache path")
		}
		return nil
	})
}

func openSampleAppsZip(forceClone bool, cli *CLI) (*os.File, error) {
	cacheDir, err := vespaCliCacheDir(cli.Environment)
	if err != nil {
		return nil, err
	}
	path := filepath.Join(cacheDir, "sample-apps-master.zip")
	cacheExists := true
	stat, err := os.Stat(path)
	if errors.Is(err, os.ErrNotExist) {
		cacheExists = false
	} else if err != nil {
		return nil, fmt.Errorf("could not stat existing cache file: %w", err)
	}
	if cacheExists {
		useCache, err := useCache(forceClone, stat)
		if err != nil {
			return nil, errHint(fmt.Errorf("could not determine cache status: %w", err), "Try ignoring the cache with the -f flag")
		}
		if useCache {
			log.Print(color.YellowString("Using cached sample apps ..."))
			return os.Open(path)
		}
	}
	if err := fetchSampleAppsZip(path, cli); err != nil {
		return nil, fmt.Errorf("could not fetch sample apps: %w", err)
	}
	return os.Open(path)
}

func copy(f *zip.File, destinationDir string, zipEntryPrefix string) error {
	destinationPath := filepath.Join(destinationDir, filepath.FromSlash(strings.TrimPrefix(f.Name, zipEntryPrefix)))
	if strings.HasSuffix(f.Name, "/") {
		if f.Name != zipEntryPrefix { // root is already created
			if err := os.Mkdir(destinationPath, 0755); err != nil {
				return err
			}
		}
	} else {
		r, err := f.Open()
		if err != nil {
			return err
		}
		defer r.Close()
		destination, err := os.Create(destinationPath)
		if err != nil {
			return err
		}
		if _, err := io.Copy(destination, r); err != nil {
			return err
		}
		if err := os.Chmod(destinationPath, f.Mode()); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Simplify<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// vespa clone command
// author: bratseth

package cmd

import (
	"archive/zip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
)

func newCloneCmd(cli *CLI) *cobra.Command {
	var (
		listApps   bool
		forceClone bool
	)
	cmd := &cobra.Command{
		Use:   "clone sample-application-path target-directory",
		Short: "Create files and directory structure for a new Vespa application from a sample application",
		Long: `Create files and directory structure for a new Vespa application
from a sample application.

Sample applications are downloaded from
https://github.com/vespa-engine/sample-apps.

By default sample applications are cached in the user's cache directory. This
directory can be overriden by setting the VESPA_CLI_CACHE_DIR environment
variable.`,
		Example:           "$ vespa clone vespa-cloud/album-recommendation my-app",
		DisableAutoGenTag: true,
		SilenceUsage:      true,
		RunE: func(cmd *cobra.Command, args []string) error {
			if listApps {
				apps, err := listSampleApps(cli.httpClient)
				if err != nil {
					return fmt.Errorf("could not list sample applications: %w", err)
				}
				for _, app := range apps {
					log.Print(app)
				}
				return nil
			}
			if len(args) != 2 {
				return fmt.Errorf("expected exactly 2 arguments, got %d", len(args))
			}
			cloner := &cloner{cli: cli, discardCache: forceClone}
			return cloner.Clone(args[0], args[1])
		},
	}
	cmd.Flags().BoolVarP(&listApps, "list", "l", false, "List available sample applications")
	cmd.Flags().BoolVarP(&forceClone, "force", "f", false, "Ignore cache and force downloading the latest sample application from GitHub")
	return cmd
}

type cloner struct {
	cli          *CLI
	discardCache bool
}

// Clone copies the application identified by applicationName into given path. If the cached copy of sample applications
// has expired, it will be downloaded from GitHub automatically.
func (c *cloner) Clone(applicationName, path string) error {
	zipName, err := c.zipName()
	if err != nil {
		return err
	}

	r, err := zip.OpenReader(zipName)
	if err != nil {
		return fmt.Errorf("could not open sample apps zip '%s': %w", color.CyanString(zipName), err)
	}
	defer r.Close()

	found := false
	for _, f := range r.File {
		dirPrefix := "sample-apps-master/" + applicationName + "/"
		if strings.HasPrefix(f.Name, dirPrefix) {
			if !found { // Create destination directory lazily when source is found
				createErr := os.Mkdir(path, 0755)
				if createErr != nil {
					return fmt.Errorf("could not create directory '%s': %w", color.CyanString(path), createErr)
				}
			}
			found = true

			if err := copy(f, path, dirPrefix); err != nil {
				return fmt.Errorf("could not copy zip entry '%s': %w", color.CyanString(f.Name), err)
			}
		}
	}
	if !found {
		return errHint(fmt.Errorf("could not find source application '%s'", color.CyanString(applicationName)), "Use -f to ignore the cache")
	} else {
		log.Print("Created ", color.CyanString(path))
	}
	return nil
}

func (c *cloner) useCache(stat os.FileInfo) (bool, error) {
	if c.discardCache {
		return false, nil
	}
	expiry := stat.ModTime().Add(time.Hour * 168) // 1 week
	return stat.Size() > 0 && time.Now().Before(expiry), nil
}

func (c *cloner) downloadZip(dst string) error {
	f, err := ioutil.TempFile(filepath.Dir(dst), "sample-apps")
	if err != nil {
		return fmt.Errorf("could not create temporary file: %w", err)
	}
	defer f.Close()
	return c.cli.spinner(c.cli.Stderr, color.YellowString("Downloading sample apps ..."), func() error {
		request, err := http.NewRequest("GET", "https://github.com/vespa-engine/sample-apps/archive/refs/heads/master.zip", nil)
		if err != nil {
			return fmt.Errorf("invalid url: %w", err)
		}
		response, err := c.cli.httpClient.Do(request, time.Minute*60)
		if err != nil {
			return fmt.Errorf("could not download sample apps: %w", err)
		}
		defer response.Body.Close()
		if response.StatusCode != http.StatusOK {
			return fmt.Errorf("could not download sample apps: github returned status %d", response.StatusCode)
		}
		if _, err := io.Copy(f, response.Body); err != nil {
			return fmt.Errorf("could not write sample apps to file: %s: %w", f.Name(), err)
		}
		f.Close()
		if err := os.Rename(f.Name(), dst); err != nil {
			return fmt.Errorf("could not move sample apps to cache path")
		}
		return nil
	})
}

func (c *cloner) zipName() (string, error) {
	cacheDir, err := vespaCliCacheDir(c.cli.Environment)
	if err != nil {
		return "", err
	}
	dst := filepath.Join(cacheDir, "sample-apps-master.zip")
	cacheExists := true
	stat, err := os.Stat(dst)
	if errors.Is(err, os.ErrNotExist) {
		cacheExists = false
	} else if err != nil {
		return "", fmt.Errorf("could not stat existing cache file: %w", err)
	}
	if cacheExists {
		useCache, err := c.useCache(stat)
		if err != nil {
			return "", errHint(fmt.Errorf("could not determine cache status: %w", err), "Try ignoring the cache with the -f flag")
		}
		if useCache {
			log.Print(color.YellowString("Using cached sample apps ..."))
			return dst, nil
		}
	}
	if err := c.downloadZip(dst); err != nil {
		return "", fmt.Errorf("could not fetch sample apps: %w", err)
	}
	return dst, nil
}

func copy(f *zip.File, destinationDir string, zipEntryPrefix string) error {
	destinationPath := filepath.Join(destinationDir, filepath.FromSlash(strings.TrimPrefix(f.Name, zipEntryPrefix)))
	if strings.HasSuffix(f.Name, "/") {
		if f.Name != zipEntryPrefix { // root is already created
			if err := os.Mkdir(destinationPath, 0755); err != nil {
				return err
			}
		}
	} else {
		r, err := f.Open()
		if err != nil {
			return err
		}
		defer r.Close()
		destination, err := os.Create(destinationPath)
		if err != nil {
			return err
		}
		if _, err := io.Copy(destination, r); err != nil {
			return err
		}
		if err := os.Chmod(destinationPath, f.Mode()); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package test

import (
	"imperial-splendour-bundler/backend"
	"imperial-splendour-bundler/backend/mocks"

	"github.com/stretchr/testify/mock"
)

func Before() (*backend.API, *mocks.MockBrowser, *mocks.MockWindow, *mocks.MockLogger, *mocks.MockStore, *mocks.MockSystemHandler) {
	mockSh := &mocks.MockSystemHandler{}
	mockB := &mocks.MockBrowser{}
	mockW := &mocks.MockWindow{}
	mockL := &mocks.MockLogger{}
	mockD := &mocks.MockDialog{}
	mockSt := &mocks.MockStore{}

	mockW.On("Close").Return()

	mockL.On("Info", mock.Anything).Return()
	mockL.On("Infof", mock.Anything, mock.Anything).Return()
	mockL.On("Warn", mock.Anything).Return()
	mockL.On("Warnf", mock.Anything, mock.Anything).Return()
	mockL.On("Debug", mock.Anything).Return(nil)
	mockL.On("Debugf", mock.Anything, mock.Anything).Return()

	mockSt.On("Update", mock.Anything).Return()

	api := &backend.API{}

	mockSh.On("StartCommand", "/bin/sh", []string{"-c", "command -v iscc"}).Return(nil)
	if err := api.Init(mockB, mockW, mockL, mockSt, mockD, mockSh); err != nil {
		panic(err)
	}
	return api, mockB, mockW, mockL, mockSt, mockSh
}

func After(api backend.API) {
}
<commit_msg>Fix test helper<commit_after>package test

import (
	"imperial-splendour-bundler/backend"
	"imperial-splendour-bundler/backend/mocks"

	"github.com/stretchr/testify/mock"
)

func Before() (*backend.API, *mocks.MockBrowser, *mocks.MockWindow, *mocks.MockLogger, *mocks.MockStore, *mocks.MockSystemHandler) {
	mockSh := &mocks.MockSystemHandler{}
	mockB := &mocks.MockBrowser{}
	mockW := &mocks.MockWindow{}
	mockL := &mocks.MockLogger{}
	mockD := &mocks.MockDialog{}
	mockSt := &mocks.MockStore{}

	mockW.On("Close").Return()

	mockL.On("Info", mock.Anything).Return()
	mockL.On("Infof", mock.Anything, mock.Anything).Return()
	mockL.On("Warn", mock.Anything).Return()
	mockL.On("Warnf", mock.Anything, mock.Anything).Return()
	mockL.On("Debug", mock.Anything).Return(nil)
	mockL.On("Debugf", mock.Anything, mock.Anything).Return()

	mockSt.On("Update", mock.Anything).Return()

	api := &backend.API{}

	mockSh.On("StartCommand", "iscc /?").Return(nil)
	if err := api.Init(mockB, mockW, mockL, mockSt, mockD, mockSh); err != nil {
		panic(err)
	}
	return api, mockB, mockW, mockL, mockSt, mockSh
}

func After(api backend.API) {
}
<|endoftext|>


<commit_before>package runtime

//go:generate sh -c "go run ./generate > ./helpers.go"

import (
	"fmt"
	"math"
	"reflect"
)

func Fetch(from, i interface{}) interface{} {
	v := reflect.ValueOf(from)
	kind := v.Kind()
	if kind == reflect.Invalid {
		panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
	}

	// Methods can be defined on any type.
	if v.NumMethod() > 0 {
		method := v.MethodByName(i.(string))
		if method.IsValid() {
			return method.Interface()
		}
	}

	// Structs, maps, and slices can be access through a pointer or through
	// a value, when they are accessed through a pointer we don't want to
	// copy them to a value.
	if kind == reflect.Ptr {
		v = reflect.Indirect(v)
		kind = v.Kind()
	}

	switch kind {

	case reflect.Array, reflect.Slice, reflect.String:
		value := v.Index(ToInt(i))
		if value.IsValid() {
			return value.Interface()
		}

	case reflect.Map:
		value := v.MapIndex(reflect.ValueOf(i))
		if value.IsValid() {
			return value.Interface()
		} else {
			elem := reflect.TypeOf(from).Elem()
			return reflect.Zero(elem).Interface()
		}

	case reflect.Struct:
		fieldName := i.(string)
		value := v.FieldByNameFunc(func(name string) bool {
			field, _ := v.Type().FieldByName(name)
			if field.Tag.Get("expr") == fieldName {
				return true
			}
			return name == fieldName
		})
		if value.IsValid() {
			return value.Interface()
		}
	}
	panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
}

type Field struct {
	Index []int
	Path  string
}

func FetchField(from interface{}, field *Field) interface{} {
	v := reflect.ValueOf(from)
	kind := v.Kind()
	if kind != reflect.Invalid {
		if kind == reflect.Ptr {
			v = reflect.Indirect(v)
			kind = v.Kind()
		}
		if kind == reflect.Struct {
			// We can use v.FieldByIndex here, but it will panic if the field
			// is not exists. And we need to recover() to generate a more
			// user-friendly error message.
			// Also, our fieldByIndex() function is slightly faster than the
			// v.FieldByIndex() function as we don't need to verify what a field
			// is a struct as we already did it on compilation step.
			value := fieldByIndex(v, field.Index)
			if value.IsValid() {
				return value.Interface()
			}
		}
	}
	panic(fmt.Sprintf("cannot get %v from %T", field.Path, from))
}

func fieldByIndex(v reflect.Value, index []int) reflect.Value {
	if len(index) == 1 {
		return v.Field(index[0])
	}
	for i, x := range index {
		if i > 0 {
			if v.Kind() == reflect.Ptr {
				if v.IsNil() {
					return reflect.Value{}
				}
				v = v.Elem()
			}
		}
		v = v.Field(x)
	}
	return v
}

type Method struct {
	Index int
	Name  string
}

func FetchMethod(from interface{}, method *Method) interface{} {
	v := reflect.ValueOf(from)
	kind := v.Kind()
	if kind != reflect.Invalid {
		// Methods can be defined on any type, no need to dereference.
		method := v.Method(method.Index)
		if method.IsValid() {
			return method.Interface()
		}
	}
	panic(fmt.Sprintf("cannot fetch %v from %T", method.Name, from))
}

func Deref(i interface{}) interface{} {
	if i == nil {
		return nil
	}

	v := reflect.ValueOf(i)

	if v.Kind() == reflect.Interface {
		if v.IsNil() {
			return i
		}
		v = v.Elem()
	}

	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return i
		}
		indirect := reflect.Indirect(v)
		switch indirect.Kind() {
		case reflect.Struct, reflect.Map, reflect.Array, reflect.Slice:
		default:
			v = v.Elem()
		}
	}

	if v.IsValid() {
		return v.Interface()
	}

	panic(fmt.Sprintf("cannot dereference %v", i))
}

func Slice(array, from, to interface{}) interface{} {
	v := reflect.ValueOf(array)

	switch v.Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		length := v.Len()
		a, b := ToInt(from), ToInt(to)

		if b > length {
			b = length
		}
		if a > b {
			a = b
		}

		value := v.Slice(a, b)
		if value.IsValid() {
			return value.Interface()
		}

	case reflect.Ptr:
		value := v.Elem()
		if value.IsValid() {
			return Slice(value.Interface(), from, to)
		}

	}
	panic(fmt.Sprintf("cannot slice %v", from))
}

func In(needle interface{}, array interface{}) bool {
	if array == nil {
		return false
	}
	v := reflect.ValueOf(array)

	switch v.Kind() {

	case reflect.Array, reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			value := v.Index(i)
			if value.IsValid() {
				if Equal(value.Interface(), needle).(bool) {
					return true
				}
			}
		}
		return false

	case reflect.Map:
		n := reflect.ValueOf(needle)
		if !n.IsValid() {
			panic(fmt.Sprintf("cannot use %T as index to %T", needle, array))
		}
		value := v.MapIndex(n)
		if value.IsValid() {
			return true
		}
		return false

	case reflect.Struct:
		n := reflect.ValueOf(needle)
		if !n.IsValid() || n.Kind() != reflect.String {
			panic(fmt.Sprintf("cannot use %T as field name of %T", needle, array))
		}
		value := v.FieldByName(n.String())
		if value.IsValid() {
			return true
		}
		return false

	case reflect.Ptr:
		value := v.Elem()
		if value.IsValid() {
			return In(needle, value.Interface())
		}
		return false
	}

	panic(fmt.Sprintf(`operator "in"" not defined on %T`, array))
}

func Length(a interface{}) int {
	v := reflect.ValueOf(a)
	switch v.Kind() {
	case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
		return v.Len()
	default:
		panic(fmt.Sprintf("invalid argument for len (type %T)", a))
	}
}

func Negate(i interface{}) interface{} {
	switch v := i.(type) {
	case float32:
		return -v
	case float64:
		return -v

	case int:
		return -v
	case int8:
		return -v
	case int16:
		return -v
	case int32:
		return -v
	case int64:
		return -v

	case uint:
		return -v
	case uint8:
		return -v
	case uint16:
		return -v
	case uint32:
		return -v
	case uint64:
		return -v

	default:
		panic(fmt.Sprintf("invalid operation: - %T", v))
	}
}

func Exponent(a, b interface{}) float64 {
	return math.Pow(ToFloat64(a), ToFloat64(b))
}

func MakeRange(min, max int) []int {
	size := max - min + 1
	if size <= 0 {
		return []int{}
	}
	rng := make([]int, size)
	for i := range rng {
		rng[i] = min + i
	}
	return rng
}

func ToInt(a interface{}) int {
	switch x := a.(type) {
	case float32:
		return int(x)
	case float64:
		return int(x)
	case int:
		return x
	case int8:
		return int(x)
	case int16:
		return int(x)
	case int32:
		return int(x)
	case int64:
		return int(x)
	case uint:
		return int(x)
	case uint8:
		return int(x)
	case uint16:
		return int(x)
	case uint32:
		return int(x)
	case uint64:
		return int(x)
	default:
		panic(fmt.Sprintf("invalid operation: int(%T)", x))
	}
}

func ToInt64(a interface{}) int64 {
	switch x := a.(type) {
	case float32:
		return int64(x)
	case float64:
		return int64(x)
	case int:
		return int64(x)
	case int8:
		return int64(x)
	case int16:
		return int64(x)
	case int32:
		return int64(x)
	case int64:
		return x
	case uint:
		return int64(x)
	case uint8:
		return int64(x)
	case uint16:
		return int64(x)
	case uint32:
		return int64(x)
	case uint64:
		return int64(x)
	default:
		panic(fmt.Sprintf("invalid operation: int64(%T)", x))
	}
}

func ToFloat64(a interface{}) float64 {
	switch x := a.(type) {
	case float32:
		return float64(x)
	case float64:
		return x
	case int:
		return float64(x)
	case int8:
		return float64(x)
	case int16:
		return float64(x)
	case int32:
		return float64(x)
	case int64:
		return float64(x)
	case uint:
		return float64(x)
	case uint8:
		return float64(x)
	case uint16:
		return float64(x)
	case uint32:
		return float64(x)
	case uint64:
		return float64(x)
	default:
		panic(fmt.Sprintf("invalid operation: float64(%T)", x))
	}
}

func IsNil(v interface{}) bool {
	if v == nil {
		return true
	}
	r := reflect.ValueOf(v)
	switch r.Kind() {
	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
		return r.IsNil()
	default:
		return false
	}
}
<commit_msg>Fix code style<commit_after>package runtime

//go:generate sh -c "go run ./generate > ./helpers.go"

import (
	"fmt"
	"math"
	"reflect"
)

func Fetch(from, i interface{}) interface{} {
	v := reflect.ValueOf(from)
	kind := v.Kind()
	if kind == reflect.Invalid {
		panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
	}

	// Methods can be defined on any type.
	if v.NumMethod() > 0 {
		method := v.MethodByName(i.(string))
		if method.IsValid() {
			return method.Interface()
		}
	}

	// Structs, maps, and slices can be access through a pointer or through
	// a value, when they are accessed through a pointer we don't want to
	// copy them to a value.
	if kind == reflect.Ptr {
		v = reflect.Indirect(v)
		kind = v.Kind()
	}

	switch kind {

	case reflect.Array, reflect.Slice, reflect.String:
		value := v.Index(ToInt(i))
		if value.IsValid() {
			return value.Interface()
		}

	case reflect.Map:
		value := v.MapIndex(reflect.ValueOf(i))
		if value.IsValid() {
			return value.Interface()
		} else {
			elem := reflect.TypeOf(from).Elem()
			return reflect.Zero(elem).Interface()
		}

	case reflect.Struct:
		fieldName := i.(string)
		value := v.FieldByNameFunc(func(name string) bool {
			field, _ := v.Type().FieldByName(name)
			if field.Tag.Get("expr") == fieldName {
				return true
			}
			return name == fieldName
		})
		if value.IsValid() {
			return value.Interface()
		}
	}
	panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
}

type Field struct {
	Index []int
	Path  string
}

func FetchField(from interface{}, field *Field) interface{} {
	v := reflect.ValueOf(from)
	kind := v.Kind()
	if kind != reflect.Invalid {
		if kind == reflect.Ptr {
			v = reflect.Indirect(v)
			kind = v.Kind()
		}
		if kind == reflect.Struct {
			// We can use v.FieldByIndex here, but it will panic if the field
			// is not exists. And we need to recover() to generate a more
			// user-friendly error message.
			// Also, our fieldByIndex() function is slightly faster than the
			// v.FieldByIndex() function as we don't need to verify what a field
			// is a struct as we already did it on compilation step.
			value := fieldByIndex(v, field.Index)
			if value.IsValid() {
				return value.Interface()
			}
		}
	}
	panic(fmt.Sprintf("cannot get %v from %T", field.Path, from))
}

func fieldByIndex(v reflect.Value, index []int) reflect.Value {
	if len(index) == 1 {
		return v.Field(index[0])
	}
	for i, x := range index {
		if i > 0 {
			if v.Kind() == reflect.Ptr {
				if v.IsNil() {
					return reflect.Value{}
				}
				v = v.Elem()
			}
		}
		v = v.Field(x)
	}
	return v
}

type Method struct {
	Index int
	Name  string
}

func FetchMethod(from interface{}, method *Method) interface{} {
	v := reflect.ValueOf(from)
	kind := v.Kind()
	if kind != reflect.Invalid {
		// Methods can be defined on any type, no need to dereference.
		method := v.Method(method.Index)
		if method.IsValid() {
			return method.Interface()
		}
	}
	panic(fmt.Sprintf("cannot fetch %v from %T", method.Name, from))
}

func Deref(i interface{}) interface{} {
	if i == nil {
		return nil
	}

	v := reflect.ValueOf(i)

	if v.Kind() == reflect.Interface {
		if v.IsNil() {
			return i
		}
		v = v.Elem()
	}

	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return i
		}
		indirect := reflect.Indirect(v)
		switch indirect.Kind() {
		case reflect.Struct, reflect.Map, reflect.Array, reflect.Slice:
		default:
			v = v.Elem()
		}
	}

	if v.IsValid() {
		return v.Interface()
	}

	panic(fmt.Sprintf("cannot dereference %v", i))
}

func Slice(array, from, to interface{}) interface{} {
	v := reflect.ValueOf(array)

	switch v.Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		length := v.Len()
		a, b := ToInt(from), ToInt(to)

		if b > length {
			b = length
		}
		if a > b {
			a = b
		}

		value := v.Slice(a, b)
		if value.IsValid() {
			return value.Interface()
		}

	case reflect.Ptr:
		value := v.Elem()
		if value.IsValid() {
			return Slice(value.Interface(), from, to)
		}

	}
	panic(fmt.Sprintf("cannot slice %v", from))
}

func In(needle interface{}, array interface{}) bool {
	if array == nil {
		return false
	}
	v := reflect.ValueOf(array)

	switch v.Kind() {

	case reflect.Array, reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			value := v.Index(i)
			if value.IsValid() {
				if Equal(value.Interface(), needle).(bool) {
					return true
				}
			}
		}
		return false

	case reflect.Map:
		n := reflect.ValueOf(needle)
		if !n.IsValid() {
			panic(fmt.Sprintf("cannot use %T as index to %T", needle, array))
		}
		value := v.MapIndex(n)
		if value.IsValid() {
			return true
		}
		return false

	case reflect.Struct:
		n := reflect.ValueOf(needle)
		if !n.IsValid() || n.Kind() != reflect.String {
			panic(fmt.Sprintf("cannot use %T as field name of %T", needle, array))
		}
		value := v.FieldByName(n.String())
		if value.IsValid() {
			return true
		}
		return false

	case reflect.Ptr:
		value := v.Elem()
		if value.IsValid() {
			return In(needle, value.Interface())
		}
		return false
	}

	panic(fmt.Sprintf(`operator "in"" not defined on %T`, array))
}

func Length(a interface{}) int {
	v := reflect.ValueOf(a)
	switch v.Kind() {
	case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
		return v.Len()
	default:
		panic(fmt.Sprintf("invalid argument for len (type %T)", a))
	}
}

func Negate(i interface{}) interface{} {
	switch v := i.(type) {
	case float32:
		return -v
	case float64:
		return -v
	case int:
		return -v
	case int8:
		return -v
	case int16:
		return -v
	case int32:
		return -v
	case int64:
		return -v
	case uint:
		return -v
	case uint8:
		return -v
	case uint16:
		return -v
	case uint32:
		return -v
	case uint64:
		return -v
	default:
		panic(fmt.Sprintf("invalid operation: - %T", v))
	}
}

func Exponent(a, b interface{}) float64 {
	return math.Pow(ToFloat64(a), ToFloat64(b))
}

func MakeRange(min, max int) []int {
	size := max - min + 1
	if size <= 0 {
		return []int{}
	}
	rng := make([]int, size)
	for i := range rng {
		rng[i] = min + i
	}
	return rng
}

func ToInt(a interface{}) int {
	switch x := a.(type) {
	case float32:
		return int(x)
	case float64:
		return int(x)
	case int:
		return x
	case int8:
		return int(x)
	case int16:
		return int(x)
	case int32:
		return int(x)
	case int64:
		return int(x)
	case uint:
		return int(x)
	case uint8:
		return int(x)
	case uint16:
		return int(x)
	case uint32:
		return int(x)
	case uint64:
		return int(x)
	default:
		panic(fmt.Sprintf("invalid operation: int(%T)", x))
	}
}

func ToInt64(a interface{}) int64 {
	switch x := a.(type) {
	case float32:
		return int64(x)
	case float64:
		return int64(x)
	case int:
		return int64(x)
	case int8:
		return int64(x)
	case int16:
		return int64(x)
	case int32:
		return int64(x)
	case int64:
		return x
	case uint:
		return int64(x)
	case uint8:
		return int64(x)
	case uint16:
		return int64(x)
	case uint32:
		return int64(x)
	case uint64:
		return int64(x)
	default:
		panic(fmt.Sprintf("invalid operation: int64(%T)", x))
	}
}

func ToFloat64(a interface{}) float64 {
	switch x := a.(type) {
	case float32:
		return float64(x)
	case float64:
		return x
	case int:
		return float64(x)
	case int8:
		return float64(x)
	case int16:
		return float64(x)
	case int32:
		return float64(x)
	case int64:
		return float64(x)
	case uint:
		return float64(x)
	case uint8:
		return float64(x)
	case uint16:
		return float64(x)
	case uint32:
		return float64(x)
	case uint64:
		return float64(x)
	default:
		panic(fmt.Sprintf("invalid operation: float64(%T)", x))
	}
}

func IsNil(v interface{}) bool {
	if v == nil {
		return true
	}
	r := reflect.ValueOf(v)
	switch r.Kind() {
	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
		return r.IsNil()
	default:
		return false
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Erlend Johannessen.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

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

	"count"
	"utils"
)

var root string

// ------------------------------------------
// init
// ------------------------------------------
func init() {
	flag.Usage = usage
	flag.Parse()

	// Load config and prepare for parsing directory
	count.Initialize()
}

// ------------------------------------------
// usage
// ------------------------------------------
func usage() {
	var executableName = filepath.Base(os.Args[0])
	fmt.Fprintf(os.Stderr, "%s counts sourcecode lines for given directory and sub-directories.\n", executableName)
	fmt.Fprintf(os.Stderr, "Usage: %s [dirname] \n", executableName)
	fmt.Fprintf(os.Stderr, "       dirname: Name of directory with source code to count lines for.\n")
	fmt.Fprintf(os.Stderr, "                Uses current directory if no directory given.\n")
	flag.PrintDefaults()
	os.Exit(0)
}

// ------------------------------------------
// forEachEntry
// ------------------------------------------
func forEachEntry(filename string, f os.FileInfo, err error) error {
	count.CountExtension(filename, f)
	return nil
}

// ------------------------------------------
// main
// ------------------------------------------
func main() {
	root = utils.GetDirectory(flag.Arg(0), os.Args[0])

	// Walking the given directory
	err := filepath.Walk(root, forEachEntry)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(-1)
	}

	// Show result
	count.Print(root)
}
<commit_msg>Closed issue #1, now using current directory as default direcory<commit_after>// Copyright 2014 Erlend Johannessen.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

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

	"count"
	"utils"
)

var root string

// ------------------------------------------
// init
// ------------------------------------------
func init() {
	flag.Usage = usage
	flag.Parse()

	// Load config and prepare for parsing directory
	count.Initialize()
}

// ------------------------------------------
// usage
// ------------------------------------------
func usage() {
	var executableName = filepath.Base(os.Args[0])
	fmt.Fprintf(os.Stderr, "%s counts sourcecode lines for given directory and sub-directories.\n", executableName)
	fmt.Fprintf(os.Stderr, "Usage: %s [dirname] \n", executableName)
	fmt.Fprintf(os.Stderr, "       dirname: Name of directory with source code to count lines for.\n")
	fmt.Fprintf(os.Stderr, "                Uses current directory if no directory given.\n")
	flag.PrintDefaults()
	os.Exit(0)
}

// ------------------------------------------
// forEachEntry
// ------------------------------------------
func forEachEntry(filename string, f os.FileInfo, err error) error {
	count.CountExtension(filename, f)
	return nil
}

// ------------------------------------------
// main
// ------------------------------------------
func main() {
	root = utils.GetDirectory(flag.Arg(0), ".")

	// Walking the given directory
	err := filepath.Walk(root, forEachEntry)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(-1)
	}

	// Show result
	count.Print(root)
}
<|endoftext|>


<commit_before>package irc

import (
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

func IsNickname(nick string) bool {
	return NicknameExpr.MatchString(nick)
}

type HostnameLookup struct {
	client   *Client
	hostname string
}

func NewHostnameLookup(client *Client, ipAddr string) *HostnameLookup {
	return &HostnameLookup{
		client:   client,
		hostname: LookupHostname(ipAddr),
	}
}

type Client struct {
	atime       time.Time
	awayMessage string
	channels    ChannelSet
	ctime       time.Time
	flags       map[UserMode]bool
	hasQuit     bool
	hops        uint
	hostname    string
	idleTimer   *time.Timer
	loginTimer  *time.Timer
	lookups     chan string
	nick        string
	phase       Phase
	quitTimer   *time.Timer
	realname    string
	replies     chan string
	server      *Server
	socket      *Socket
	username    string
}

func NewClient(server *Server, conn net.Conn) *Client {
	now := time.Now()
	client := &Client{
		atime:    now,
		channels: make(ChannelSet),
		ctime:    now,
		flags:    make(map[UserMode]bool),
		lookups:  make(chan string),
		phase:    server.InitPhase(),
		server:   server,
		socket:   NewSocket(conn),
		replies:  make(chan string, 16),
	}

	client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.connectionTimeout)
	go client.LookupHostname(IPString(conn.RemoteAddr()))
	go client.readCommands()
	go client.writeReplies()

	return client
}

//
// socket read gorountine
//

func (client *Client) readCommands() {
	done := false
	for !done {
		select {
		case ipAddr := <-client.lookups:
			client.server.hostnames <- NewHostnameLookup(client, ipAddr)

		case line := <-client.socket.Read():
			if line == EOF {
				done = true
				break
			}
			msg, err := ParseCommand(line)
			if err != nil {
				switch err {
				case NotEnoughArgsError:
					parts := strings.SplitN(line, " ", 2)
					client.ErrNeedMoreParams(parts[0])
				}
				continue
			}

			msg.SetClient(client)
			client.server.commands <- msg
		}
	}

	client.connectionClosed()
}

func (client *Client) LookupHostname(ipAddr string) {
	client.lookups <- ipAddr
}

func (client *Client) connectionClosed() {
	msg := &QuitCommand{
		message: "connection closed",
	}
	msg.SetClient(client)
	client.server.commands <- msg
}

//
// reply writing goroutine
//

func (client *Client) writeReplies() {
	for reply := range client.replies {
		if reply == EOF {
			break
		}
		if client.socket.Write(reply) != nil {
			break
		}
	}
	client.socket.Close()
}

//
// idle timer goroutine
//

func (client *Client) connectionIdle() {
	client.server.idle <- client
}

//
// quit timer goroutine
//

func (client *Client) connectionTimeout() {
	msg := &QuitCommand{
		message: "connection timeout",
	}
	msg.SetClient(client)
	client.server.commands <- msg
}

//
// server goroutine
//

func (client *Client) Active() {
	client.atime = time.Now()
}

func (client *Client) Touch() {
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	if client.idleTimer == nil {
		client.idleTimer = time.AfterFunc(IDLE_TIMEOUT, client.connectionIdle)
	} else {
		client.idleTimer.Reset(IDLE_TIMEOUT)
	}
}

func (client *Client) Idle() {
	client.Reply(RplPing(client))

	if client.quitTimer == nil {
		client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.connectionTimeout)
	} else {
		client.quitTimer.Reset(QUIT_TIMEOUT)
	}
}

func (client *Client) Register() {
	client.phase = Normal
	client.loginTimer.Stop()
	client.Touch()
}

func (client *Client) destroy() {
	// clean up self

	client.loginTimer.Stop()

	if client.idleTimer != nil {
		client.idleTimer.Stop()
	}
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	// clean up channels

	for channel := range client.channels {
		channel.Quit(client)
	}

	// clean up server

	client.server.clients.Remove(client)

	if DEBUG_CLIENT {
		log.Printf("%s: destroyed", client)
	}
}

func (client *Client) IdleTime() time.Duration {
	return time.Since(client.atime)
}

func (client *Client) SignonTime() int64 {
	return client.ctime.Unix()
}

func (client *Client) IdleSeconds() uint64 {
	return uint64(client.IdleTime().Seconds())
}

func (client *Client) HasNick() bool {
	return client.nick != ""
}

func (client *Client) HasUsername() bool {
	return client.username != ""
}

// <mode>
func (c *Client) ModeString() (str string) {
	for flag := range c.flags {
		str += flag.String()
	}

	if len(str) > 0 {
		str = "+" + str
	}
	return
}

func (c *Client) UserHost() string {
	username := "*"
	if c.HasUsername() {
		username = c.username
	}
	return fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname)
}

func (c *Client) Nick() string {
	if c.HasNick() {
		return c.nick
	}
	return "*"
}

func (c *Client) Id() string {
	return c.UserHost()
}

func (c *Client) String() string {
	return c.Id()
}

func (client *Client) Friends() ClientSet {
	friends := make(ClientSet)
	friends.Add(client)
	for channel := range client.channels {
		for member := range channel.members {
			friends.Add(member)
		}
	}
	return friends
}

func (client *Client) SetNickname(nickname string) {
	client.nick = nickname
	client.server.clients.Add(client)
}

func (client *Client) ChangeNickname(nickname string) {
	// Make reply before changing nick to capture original source id.
	reply := RplNick(client, nickname)
	client.server.clients.Remove(client)
	client.nick = nickname
	client.server.clients.Add(client)
	for friend := range client.Friends() {
		friend.Reply(reply)
	}
}

func (client *Client) Reply(reply string) {
	if client.hasQuit {
		return
	}
	client.replies <- reply
}

func (client *Client) Quit(message string) {
	if client.hasQuit {
		return
	}

	client.Reply(RplError("connection closed"))
	client.Reply(EOF)

	client.hasQuit = true
	friends := client.Friends()
	friends.Remove(client)
	client.destroy()

	if len(friends) > 0 {
		reply := RplQuit(client, message)
		for friend := range friends {
			friend.Reply(reply)
		}
	}
}
<commit_msg>aggressively clean up client<commit_after>package irc

import (
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

func IsNickname(nick string) bool {
	return NicknameExpr.MatchString(nick)
}

type HostnameLookup struct {
	client   *Client
	hostname string
}

func NewHostnameLookup(client *Client, ipAddr string) *HostnameLookup {
	return &HostnameLookup{
		client:   client,
		hostname: LookupHostname(ipAddr),
	}
}

type Client struct {
	atime       time.Time
	awayMessage string
	channels    ChannelSet
	ctime       time.Time
	flags       map[UserMode]bool
	hasQuit     bool
	hops        uint
	hostname    string
	idleTimer   *time.Timer
	loginTimer  *time.Timer
	lookups     chan string
	nick        string
	phase       Phase
	quitTimer   *time.Timer
	realname    string
	replies     chan string
	server      *Server
	socket      *Socket
	username    string
}

func NewClient(server *Server, conn net.Conn) *Client {
	now := time.Now()
	client := &Client{
		atime:    now,
		channels: make(ChannelSet),
		ctime:    now,
		flags:    make(map[UserMode]bool),
		lookups:  make(chan string),
		phase:    server.InitPhase(),
		server:   server,
		socket:   NewSocket(conn),
		replies:  make(chan string, 16),
	}

	client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.connectionTimeout)
	go client.LookupHostname(IPString(conn.RemoteAddr()))
	go client.readCommands()
	go client.writeReplies()

	return client
}

//
// socket read gorountine
//

func (client *Client) readCommands() {
	done := false
	for !done {
		select {
		case ipAddr := <-client.lookups:
			client.server.hostnames <- NewHostnameLookup(client, ipAddr)

		case line := <-client.socket.Read():
			if line == EOF {
				done = true
				break
			}
			msg, err := ParseCommand(line)
			if err != nil {
				switch err {
				case NotEnoughArgsError:
					parts := strings.SplitN(line, " ", 2)
					client.ErrNeedMoreParams(parts[0])
				}
				continue
			}

			msg.SetClient(client)
			client.server.commands <- msg
		}
	}

	client.connectionClosed()
}

func (client *Client) LookupHostname(ipAddr string) {
	client.lookups <- ipAddr
}

func (client *Client) connectionClosed() {
	msg := &QuitCommand{
		message: "connection closed",
	}
	msg.SetClient(client)
	client.server.commands <- msg
}

//
// reply writing goroutine
//

func (client *Client) writeReplies() {
	for reply := range client.replies {
		if reply == EOF {
			break
		}
		if client.socket.Write(reply) != nil {
			break
		}
	}
	client.socket.Close()
}

//
// idle timer goroutine
//

func (client *Client) connectionIdle() {
	client.server.idle <- client
}

//
// quit timer goroutine
//

func (client *Client) connectionTimeout() {
	msg := &QuitCommand{
		message: "connection timeout",
	}
	msg.SetClient(client)
	client.server.commands <- msg
}

//
// server goroutine
//

func (client *Client) Active() {
	client.atime = time.Now()
}

func (client *Client) Touch() {
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	if client.idleTimer == nil {
		client.idleTimer = time.AfterFunc(IDLE_TIMEOUT, client.connectionIdle)
	} else {
		client.idleTimer.Reset(IDLE_TIMEOUT)
	}
}

func (client *Client) Idle() {
	client.Reply(RplPing(client))

	if client.quitTimer == nil {
		client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.connectionTimeout)
	} else {
		client.quitTimer.Reset(QUIT_TIMEOUT)
	}
}

func (client *Client) Register() {
	client.phase = Normal
	client.loginTimer.Stop()
	client.loginTimer = nil
	client.Touch()
}

func (client *Client) destroy() {
	// clean up channels

	for channel := range client.channels {
		channel.Quit(client)
	}
	client.channels = nil

	// clean up server

	client.server.clients.Remove(client)

	// clean up self

	if client.loginTimer != nil {
		client.loginTimer.Stop()
		client.loginTimer = nil
	}
	if client.idleTimer != nil {
		client.idleTimer.Stop()
		client.idleTimer = nil
	}
	if client.quitTimer != nil {
		client.quitTimer.Stop()
		client.quitTimer = nil
	}

	client.lookups = nil
	client.replies = nil
	client.server = nil
	client.socket = nil

	if DEBUG_CLIENT {
		log.Printf("%s: destroyed", client)
	}
}

func (client *Client) IdleTime() time.Duration {
	return time.Since(client.atime)
}

func (client *Client) SignonTime() int64 {
	return client.ctime.Unix()
}

func (client *Client) IdleSeconds() uint64 {
	return uint64(client.IdleTime().Seconds())
}

func (client *Client) HasNick() bool {
	return client.nick != ""
}

func (client *Client) HasUsername() bool {
	return client.username != ""
}

// <mode>
func (c *Client) ModeString() (str string) {
	for flag := range c.flags {
		str += flag.String()
	}

	if len(str) > 0 {
		str = "+" + str
	}
	return
}

func (c *Client) UserHost() string {
	username := "*"
	if c.HasUsername() {
		username = c.username
	}
	return fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname)
}

func (c *Client) Nick() string {
	if c.HasNick() {
		return c.nick
	}
	return "*"
}

func (c *Client) Id() string {
	return c.UserHost()
}

func (c *Client) String() string {
	return c.Id()
}

func (client *Client) Friends() ClientSet {
	friends := make(ClientSet)
	friends.Add(client)
	for channel := range client.channels {
		for member := range channel.members {
			friends.Add(member)
		}
	}
	return friends
}

func (client *Client) SetNickname(nickname string) {
	client.nick = nickname
	client.server.clients.Add(client)
}

func (client *Client) ChangeNickname(nickname string) {
	// Make reply before changing nick to capture original source id.
	reply := RplNick(client, nickname)
	client.server.clients.Remove(client)
	client.nick = nickname
	client.server.clients.Add(client)
	for friend := range client.Friends() {
		friend.Reply(reply)
	}
}

func (client *Client) Reply(reply string) {
	if client.hasQuit {
		return
	}
	client.replies <- reply
}

func (client *Client) Quit(message string) {
	if client.hasQuit {
		return
	}

	client.Reply(RplError("connection closed"))
	client.Reply(EOF)

	client.hasQuit = true
	friends := client.Friends()
	friends.Remove(client)
	client.destroy()

	if len(friends) > 0 {
		reply := RplQuit(client, message)
		for friend := range friends {
			friend.Reply(reply)
		}
	}
}
<|endoftext|>