<commit_before>package main

import (
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/mit-dci/lit/logging"

	"github.com/mit-dci/lit/coinparam"
	consts "github.com/mit-dci/lit/consts"
	"github.com/mit-dci/lit/litrpc"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/qln"

	flags "github.com/jessevdk/go-flags"
)

type litConfig struct { // define a struct for usage with go-flags
	// networks lit can try connecting to
	Tn3host     string `long:"tn3" description:"Connect to bitcoin testnet3."`
	Bc2host     string `long:"bc2" description:"bc2 full node."`
	Lt4host     string `long:"lt4" description:"Connect to litecoin testnet4."`
	Reghost     string `long:"reg" description:"Connect to bitcoin regtest."`
	Litereghost string `long:"litereg" description:"Connect to litecoin regtest."`
	Tvtchost    string `long:"tvtc" description:"Connect to Vertcoin test node."`
	Vtchost     string `long:"vtc" description:"Connect to Vertcoin."`
	// system specific configs
	LitHomeDir string `long:"dir" description:"Specify Home Directory of lit as an absolute path."`
	TrackerURL string `long:"tracker" description:"LN address tracker URL http|https://host:port"`
	ConfigFile string
	UnauthRPC  bool `long:"unauthrpc" description:"Enables unauthenticated Websocket RPC"`

	// proxy
	ProxyURL      string `long:"proxy" description:"SOCKS5 proxy to use for communicating with the network"`
	LitProxyURL   string `long:"litproxy" description:"SOCKS5 proxy to use for Lit's network communications. Overridden by the proxy flag."`
	ChainProxyURL string `long:"chainproxy" description:"SOCKS5 proxy to use for Wallit's network communications. Overridden by the proxy flag."`

	// UPnP port forwarding and NAT Traversal
	Nat string `long:"nat" description:"Toggle upnp or pmp NAT Traversal NAT Punching"`
	// resync and tower config
	ReSync bool `short:"r" long:"reSync" description:"Resync from the given tip."`
	Tower  bool `long:"tower" description:"Watchtower: Run a watching node"`
	Hard   bool `short:"t" long:"hard" description:"Flag to set networks."`

	// logging, bool because that's how the tool works
	LogLevel []bool `short:"v" long:"verbose" description:"Set verbosity level from 0 to 5 (most to least)"`

	// rpc server config
	Rpcport uint16 `short:"p" long:"rpcport" description:"Set RPC port to connect to"`
	Rpchost string `long:"rpchost" description:"Set RPC host to listen to"`
	// auto config
	AutoReconnect                   bool   `long:"autoReconnect" description:"Attempts to automatically reconnect to known peers periodically."`
	AutoReconnectInterval           int64  `long:"autoReconnectInterval" description:"The interval (in seconds) the reconnect logic should be executed"`
	AutoReconnectOnlyConnectedCoins bool   `long:"autoReconnectOnlyConnectedCoins" description:"Only reconnect to peers that we have channels with in a coin whose coin daemon is available"`
	AutoListenPort                  string `long:"autoListenPort" description:"When auto reconnect enabled, starts listening on this port"`
	Params                          *coinparam.Params
}

var (
	defaultLitHomeDirName                  = os.Getenv("HOME") + "/.lit"
	defaultTrackerURL                      = "http://hubris.media.mit.edu:46580"
	defaultKeyFileName                     = "privkey.hex"
	defaultConfigFilename                  = "lit.conf"
	defaultHomeDir                         = os.Getenv("HOME")
	defaultRpcport                         = uint16(8001)
	defaultRpchost                         = "localhost"
	defaultAutoReconnect                   = true
	defaultAutoListenPort                  = ":2448"
	defaultAutoReconnectInterval           = int64(60)
	defaultUpnPFlag                        = false
	defaultLogLevel                        = 3 // reasons
	defaultAutoReconnectOnlyConnectedCoins = false
	defaultUnauthRPC                       = false
)

func fileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// newConfigParser returns a new command line flags parser.
func newConfigParser(conf *litConfig, options flags.Options) *flags.Parser {
	parser := flags.NewParser(conf, options)
	return parser
}
func linkWallets(node *qln.LitNode, key *[32]byte, conf *litConfig) error {
	// for now, wallets are linked to the litnode on startup, and
	// can't appear / disappear while it's running.  Later
	// could support dynamically adding / removing wallets

	// order matters; the first registered wallet becomes the default

	var err error
	// try regtest
	if !lnutil.NopeString(conf.Reghost) {
		p := &coinparam.RegressionNetParams
		logging.Infof("reg: %s\n", conf.Reghost)
		err = node.LinkBaseWallet(key, consts.BitcoinRegtestBHeight, conf.ReSync,
			conf.Tower, conf.Reghost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try testnet3
	if !lnutil.NopeString(conf.Tn3host) {
		p := &coinparam.TestNet3Params
		err = node.LinkBaseWallet(
			key, consts.BitcoinTestnet3BHeight, conf.ReSync, conf.Tower,
			conf.Tn3host, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try litecoin regtest
	if !lnutil.NopeString(conf.Litereghost) {
		p := &coinparam.LiteRegNetParams
		err = node.LinkBaseWallet(key, 120, conf.ReSync,
			conf.Tower, conf.Litereghost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try litecoin testnet4
	if !lnutil.NopeString(conf.Lt4host) {
		p := &coinparam.LiteCoinTestNet4Params
		err = node.LinkBaseWallet(
			key, p.StartHeight, conf.ReSync, conf.Tower,
			conf.Lt4host, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin testnet
	if !lnutil.NopeString(conf.Tvtchost) {
		p := &coinparam.VertcoinTestNetParams
		err = node.LinkBaseWallet(
			key, consts.VertcoinTestnetBHeight, conf.ReSync, conf.Tower,
			conf.Tvtchost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin mainnet
	if !lnutil.NopeString(conf.Vtchost) {
		p := &coinparam.VertcoinParams
		err = node.LinkBaseWallet(
			key, p.StartHeight, conf.ReSync, conf.Tower,
			conf.Vtchost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}

	}
	return nil
}

func main() {

	conf := litConfig{
		LitHomeDir:                      defaultLitHomeDirName,
		Rpcport:                         defaultRpcport,
		Rpchost:                         defaultRpchost,
		TrackerURL:                      defaultTrackerURL,
		AutoReconnect:                   defaultAutoReconnect,
		AutoListenPort:                  defaultAutoListenPort,
		AutoReconnectInterval:           defaultAutoReconnectInterval,
		AutoReconnectOnlyConnectedCoins: defaultAutoReconnectOnlyConnectedCoins,
		LogLevel:                        []bool{}, // reasons
		UnauthRPC:                       defaultUnauthRPC,
	}

	key := litSetup(&conf)
	if conf.ProxyURL != "" {
		conf.LitProxyURL = conf.ProxyURL
		conf.ChainProxyURL = conf.ProxyURL
	}

	// SIGQUIT hander for debugging
	go func() {
		sigs := make(chan os.Signal, 1)
		signal.Notify(sigs, syscall.SIGQUIT)
		buf := make([]byte, 1<<20)
		for {
			<-sigs
			stacklen := runtime.Stack(buf, true)
			logging.Warnf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
		}
	}()

	// Setup LN node.  Activate Tower if in hard mode.
	// give node and below file pathof lit home directory
	node, err := qln.NewLitNode(key, conf.LitHomeDir, conf.TrackerURL, conf.LitProxyURL, conf.Nat)
	if err != nil {
		logging.Fatal(err)
	}

	// node is up; link wallets based on args
	err = linkWallets(node, key, &conf)
	if err != nil {
		logging.Fatal(err)
	}

	rpcl := new(litrpc.LitRPC)
	rpcl.Node = node
	rpcl.OffButton = make(chan bool, 1)
	node.RPC = rpcl

	if conf.UnauthRPC {
		go litrpc.RPCListen(rpcl, conf.Rpchost, conf.Rpcport)
	}

	if conf.AutoReconnect {
		node.AutoReconnect(conf.AutoListenPort, conf.AutoReconnectInterval, conf.AutoReconnectOnlyConnectedCoins)
	}

	<-rpcl.OffButton
	logging.Infof("Got stop request\n")
	time.Sleep(time.Second)

	return
	// New directory being created over at PWD
	// conf file being created at /
}
<commit_msg>Resync from given tip (#347)<commit_after>package main

import (
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/mit-dci/lit/logging"

	"github.com/mit-dci/lit/coinparam"
	consts "github.com/mit-dci/lit/consts"
	"github.com/mit-dci/lit/litrpc"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/qln"

	flags "github.com/jessevdk/go-flags"
)

type litConfig struct { // define a struct for usage with go-flags
	// networks lit can try connecting to
	Tn3host     string `long:"tn3" description:"Connect to bitcoin testnet3."`
	Bc2host     string `long:"bc2" description:"bc2 full node."`
	Lt4host     string `long:"lt4" description:"Connect to litecoin testnet4."`
	Reghost     string `long:"reg" description:"Connect to bitcoin regtest."`
	Litereghost string `long:"litereg" description:"Connect to litecoin regtest."`
	Tvtchost    string `long:"tvtc" description:"Connect to Vertcoin test node."`
	Vtchost     string `long:"vtc" description:"Connect to Vertcoin."`
	// system specific configs
	LitHomeDir string `long:"dir" description:"Specify Home Directory of lit as an absolute path."`
	TrackerURL string `long:"tracker" description:"LN address tracker URL http|https://host:port"`
	ConfigFile string
	UnauthRPC  bool `long:"unauthrpc" description:"Enables unauthenticated Websocket RPC"`

	// proxy
	ProxyURL      string `long:"proxy" description:"SOCKS5 proxy to use for communicating with the network"`
	LitProxyURL   string `long:"litproxy" description:"SOCKS5 proxy to use for Lit's network communications. Overridden by the proxy flag."`
	ChainProxyURL string `long:"chainproxy" description:"SOCKS5 proxy to use for Wallit's network communications. Overridden by the proxy flag."`

	// UPnP port forwarding and NAT Traversal
	Nat string `long:"nat" description:"Toggle upnp or pmp NAT Traversal NAT Punching"`
	//resync and tower config
	Resync string `long:"resync" description:"Resync the given chain from the given tip (requires --tip) or from default params"`
	Tip    int32  `long:"tip" description:"Given tip to resync from"`
	Tower  bool   `long:"tower" description:"Watchtower: Run a watching node"`
	Hard   bool   `short:"t" long:"hard" description:"Flag to set networks."`

	// logging, bool because that's how the tool works
	LogLevel []bool `short:"v" long:"verbose" description:"Set verbosity level from 0 to 5 (most to least)"`

	// rpc server config
	Rpcport uint16 `short:"p" long:"rpcport" description:"Set RPC port to connect to"`
	Rpchost string `long:"rpchost" description:"Set RPC host to listen to"`
	// auto config
	AutoReconnect                   bool   `long:"autoReconnect" description:"Attempts to automatically reconnect to known peers periodically."`
	AutoReconnectInterval           int64  `long:"autoReconnectInterval" description:"The interval (in seconds) the reconnect logic should be executed"`
	AutoReconnectOnlyConnectedCoins bool   `long:"autoReconnectOnlyConnectedCoins" description:"Only reconnect to peers that we have channels with in a coin whose coin daemon is available"`
	AutoListenPort                  string `long:"autoListenPort" description:"When auto reconnect enabled, starts listening on this port"`
	Params                          *coinparam.Params
}

var (
	defaultLitHomeDirName                  = os.Getenv("HOME") + "/.lit"
	defaultTrackerURL                      = "http://hubris.media.mit.edu:46580"
	defaultKeyFileName                     = "privkey.hex"
	defaultConfigFilename                  = "lit.conf"
	defaultHomeDir                         = os.Getenv("HOME")
	defaultRpcport                         = uint16(8001)
	defaultRpchost                         = "localhost"
	defaultAutoReconnect                   = true
	defaultAutoListenPort                  = ":2448"
	defaultAutoReconnectInterval           = int64(60)
	defaultUpnPFlag                        = false
	defaultLogLevel                        = 3 // reasons
	defaultAutoReconnectOnlyConnectedCoins = false
	defaultUnauthRPC                       = false
)

func fileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// newConfigParser returns a new command line flags parser.
func newConfigParser(conf *litConfig, options flags.Options) *flags.Parser {
	parser := flags.NewParser(conf, options)
	return parser
}
func linkWallets(node *qln.LitNode, key *[32]byte, conf *litConfig) error {
	// for now, wallets are linked to the litnode on startup, and
	// can't appear / disappear while it's running.  Later
	// could support dynamically adding / removing wallets

	// order matters; the first registered wallet becomes the default

	var err error
	// try regtest
	if !lnutil.NopeString(conf.Reghost) {
		p := &coinparam.RegressionNetParams
		logging.Infof("reg: %s\n", conf.Reghost)
		resync := false
		if conf.Resync == "reg" {
			if conf.Tip < consts.BitcoinRegtestBHeight {
				conf.Tip = consts.BitcoinRegtestBHeight
			}
			resync = true
		}
		err = node.LinkBaseWallet(key, conf.Tip, resync,
			conf.Tower, conf.Reghost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try testnet3
	if !lnutil.NopeString(conf.Tn3host) {
		p := &coinparam.TestNet3Params
		resync := false
		if conf.Resync == "tn3" {
			if conf.Tip < consts.BitcoinTestnet3BHeight {
				conf.Tip = consts.BitcoinTestnet3BHeight
			}
			resync = true
		}
		err = node.LinkBaseWallet(
			key, conf.Tip, resync, conf.Tower,
			conf.Tn3host, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try litecoin regtest
	if !lnutil.NopeString(conf.Litereghost) {
		p := &coinparam.LiteRegNetParams
		resync := false
		if conf.Resync == "ltcreg" {
			if conf.Tip < consts.BitcoinRegtestBHeight {
				conf.Tip = consts.BitcoinRegtestBHeight // birth heights are the same for btc and ltc regtests
			}
			resync = true
		}
		err = node.LinkBaseWallet(key, conf.Tip, resync,
			conf.Tower, conf.Litereghost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try litecoin testnet4
	if !lnutil.NopeString(conf.Lt4host) {
		p := &coinparam.LiteCoinTestNet4Params
		resync := false
		conf.Tip = p.StartHeight
		if conf.Resync == "ltctn" {
			if conf.Tip < 1 {
				conf.Tip = 1
			}
			resync = true
		}
		err = node.LinkBaseWallet(
			key, p.StartHeight, resync, conf.Tower,
			conf.Lt4host, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin testnet
	if !lnutil.NopeString(conf.Tvtchost) {
		p := &coinparam.VertcoinTestNetParams
		resync := false
		if conf.Resync == "vtctn" {
			resync = true
		}
		err = node.LinkBaseWallet(
			key, consts.VertcoinTestnetBHeight, resync, conf.Tower,
			conf.Tvtchost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}
	// try vertcoin mainnet
	if !lnutil.NopeString(conf.Vtchost) {
		p := &coinparam.VertcoinParams
		resync := false
		conf.Tip = p.StartHeight
		if conf.Resync == "ltctn" {
			if conf.Tip < 1 {
				conf.Tip = 1
			}
			resync = true
		}
		err = node.LinkBaseWallet(
			key, conf.Tip, resync, conf.Tower,
			conf.Vtchost, conf.ChainProxyURL, p)
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {

	conf := litConfig{
		LitHomeDir:                      defaultLitHomeDirName,
		Rpcport:                         defaultRpcport,
		Rpchost:                         defaultRpchost,
		TrackerURL:                      defaultTrackerURL,
		AutoReconnect:                   defaultAutoReconnect,
		AutoListenPort:                  defaultAutoListenPort,
		AutoReconnectInterval:           defaultAutoReconnectInterval,
		AutoReconnectOnlyConnectedCoins: defaultAutoReconnectOnlyConnectedCoins,
		LogLevel:                        []bool{}, // reasons
		UnauthRPC:                       defaultUnauthRPC,
	}

	key := litSetup(&conf)
	if conf.ProxyURL != "" {
		conf.LitProxyURL = conf.ProxyURL
		conf.ChainProxyURL = conf.ProxyURL
	}

	// SIGQUIT hander for debugging
	go func() {
		sigs := make(chan os.Signal, 1)
		signal.Notify(sigs, syscall.SIGQUIT)
		buf := make([]byte, 1<<20)
		for {
			<-sigs
			stacklen := runtime.Stack(buf, true)
			logging.Warnf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
		}
	}()

	// Setup LN node.  Activate Tower if in hard mode.
	// give node and below file pathof lit home directory
	node, err := qln.NewLitNode(key, conf.LitHomeDir, conf.TrackerURL, conf.LitProxyURL, conf.Nat)
	if err != nil {
		logging.Fatal(err)
	}

	// node is up; link wallets based on args
	err = linkWallets(node, key, &conf)
	if err != nil {
		logging.Fatal(err)
	}

	rpcl := new(litrpc.LitRPC)
	rpcl.Node = node
	rpcl.OffButton = make(chan bool, 1)
	node.RPC = rpcl

	if conf.UnauthRPC {
		go litrpc.RPCListen(rpcl, conf.Rpchost, conf.Rpcport)
	}

	if conf.AutoReconnect {
		node.AutoReconnect(conf.AutoListenPort, conf.AutoReconnectInterval, conf.AutoReconnectOnlyConnectedCoins)
	}

	<-rpcl.OffButton
	logging.Infof("Got stop request\n")
	time.Sleep(time.Second)

	return
	// New directory being created over at PWD
	// conf file being created at /
}
<|endoftext|>


<commit_before>// Copyright 2014 Unknwon
//
// 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 log

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

var (
	Prefix     = "[Log]"
	TimeFormat = "06-01-02 15:04:05"

	NonColor    bool
	ShowDepth   bool
	CallerDepth = 2

	LevelFlags = []string{"DEBUG", " INFO", " WARN", "ERROR", "FATAL"}
)

func init() {
	if runtime.GOOS == "windows" {
		NonColor = true
	}
}

type Level int

const (
	DEBUG Level = iota
	INFO
	WARNING
	ERROR
	FATAL
)

func Print(level Level, format string, args ...interface{}) {
	var depthInfo string
	if ShowDepth {
		pc, file, line, ok := runtime.Caller(CallerDepth)
		if ok {
			// Get caller function name.
			fn := runtime.FuncForPC(pc)
			var fnName string
			if fn == nil {
				fnName = "?()"
			} else {
				fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
			}
			depthInfo = fmt.Sprintf("[%s:%d %s] ", filepath.Base(file), line, fnName)
		}
	}
	if NonColor {
		fmt.Printf("%s %s [%s] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
		if level == FATAL {
			os.Exit(1)
		}
		return
	}

	switch level {
	case DEBUG:
		fmt.Printf("%s \033[36m%s\033[0m [\033[34m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case INFO:
		fmt.Printf("%s \033[36m%s\033[0m [\033[32m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case WARNING:
		fmt.Printf("%s \033[36m%s\033[0m [\033[33m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case ERROR:
		fmt.Printf("%s \033[36m%s\033[0m [\033[31m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case FATAL:
		fmt.Printf("%s \033[36m%s\033[0m [\033[35m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
		os.Exit(1)
	default:
		fmt.Printf("%s %s [%s] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	}
}

func Debug(format string, args ...interface{}) {
	Print(DEBUG, format, args...)
}

func Warn(format string, args ...interface{}) {
	Print(WARNING, format, args...)
}

func Info(format string, args ...interface{}) {
	Print(INFO, format, args...)
}

func Error(format string, args ...interface{}) {
	Print(ERROR, format, args...)
}

func Fatal(format string, args ...interface{}) {
	Print(FATAL, format, args...)
}
<commit_msg>able to set depth<commit_after>// Copyright 2014 Unknwon
//
// 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 log

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

var (
	Prefix     = "[Log]"
	TimeFormat = "06-01-02 15:04:05"

	NonColor           bool
	ShowDepth          bool
	DefaultCallerDepth = 2

	LevelFlags = []string{"DEBUG", " INFO", " WARN", "ERROR", "FATAL"}
)

func init() {
	if runtime.GOOS == "windows" {
		NonColor = true
	}
}

type Level int

const (
	DEBUG Level = iota
	INFO
	WARNING
	ERROR
	FATAL
)

func Print(level Level, depth int, format string, args ...interface{}) {
	var depthInfo string
	if ShowDepth {
		if depth == -1 {
			depth = DefaultCallerDepth
		}
		pc, file, line, ok := runtime.Caller(depth)
		if ok {
			// Get caller function name.
			fn := runtime.FuncForPC(pc)
			var fnName string
			if fn == nil {
				fnName = "?()"
			} else {
				fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
			}
			depthInfo = fmt.Sprintf("[%s:%d %s] ", filepath.Base(file), line, fnName)
		}
	}
	if NonColor {
		fmt.Printf("%s %s [%s] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
		if level == FATAL {
			os.Exit(1)
		}
		return
	}

	switch level {
	case DEBUG:
		fmt.Printf("%s \033[36m%s\033[0m [\033[34m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case INFO:
		fmt.Printf("%s \033[36m%s\033[0m [\033[32m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case WARNING:
		fmt.Printf("%s \033[36m%s\033[0m [\033[33m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case ERROR:
		fmt.Printf("%s \033[36m%s\033[0m [\033[31m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	case FATAL:
		fmt.Printf("%s \033[36m%s\033[0m [\033[35m%s\033[0m] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
		os.Exit(1)
	default:
		fmt.Printf("%s %s [%s] %s%s\n",
			Prefix, time.Now().Format(TimeFormat), LevelFlags[level], depthInfo,
			fmt.Sprintf(format, args...))
	}
}

func DebugD(depth int, format string, args ...interface{}) {
	Print(DEBUG, depth, format, args...)
}

func Debug(format string, args ...interface{}) {
	DebugD(-1, format, args...)
}

func WarnD(depth int, format string, args ...interface{}) {
	Print(WARNING, depth, format, args...)
}

func Warn(format string, args ...interface{}) {
	WarnD(-1, format, args...)
}

func InfoD(depth int, format string, args ...interface{}) {
	Print(INFO, depth, format, args...)
}

func Info(format string, args ...interface{}) {
	InfoD(-1, format, args...)
}

func ErrorD(depth int, format string, args ...interface{}) {
	Print(ERROR, depth, format, args...)
}

func Error(format string, args ...interface{}) {
	ErrorD(-1, format, args...)
}

func FatalD(depth int, format string, args ...interface{}) {
	Print(FATAL, depth, format, args...)
}

func Fatal(format string, args ...interface{}) {
	FatalD(-1, format, args...)
}
<|endoftext|>


<commit_before>package gou

import (
	"fmt"
	"log"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

const (
	NOLOGGING = -1
	FATAL     = 0
	ERROR     = 1
	WARN      = 2
	INFO      = 3
	DEBUG     = 4
)

/*
https://github.com/mewkiz/pkg/tree/master/term
RED = '\033[0;1;31m'
GREEN = '\033[0;1;32m'
YELLOW = '\033[0;1;33m'
BLUE = '\033[0;1;34m'
MAGENTA = '\033[0;1;35m'
CYAN = '\033[0;1;36m'
WHITE = '\033[0;1;37m'
DARK_MAGENTA = '\033[0;35m'
ANSI_RESET = '\033[0m'
LogColor         = map[int]string{FATAL: "\033[0m\033[37m",
	ERROR: "\033[0m\033[31m",
	WARN:  "\033[0m\033[33m",
	INFO:  "\033[0m\033[32m",
	DEBUG: "\033[0m\033[34m"}

\e]PFdedede
*/

var (
	LogLevel    int = ERROR
	EMPTY       struct{}
	ErrLogLevel int = ERROR
	logger      *log.Logger
	loggerErr   *log.Logger
	LogColor    = map[int]string{FATAL: "\033[0m\033[37m",
		ERROR: "\033[0m\033[31m",
		WARN:  "\033[0m\033[33m",
		INFO:  "\033[0m\033[35m",
		DEBUG: "\033[0m\033[34m"}
	LogPrefix = map[int]string{
		FATAL: "[FATAL] ",
		ERROR: "[ERROR] ",
		WARN:  "[WARN] ",
		INFO:  "[INFO] ",
		DEBUG: "[DEBUG] ",
	}
	escapeNewlines bool           = true
	postFix                       = "" //\033[0m
	LogLevelWords  map[string]int = map[string]int{"fatal": 0, "error": 1, "warn": 2, "info": 3, "debug": 4, "none": -1}
	logThrottles                  = make(map[string]*Throttler)
	throttleMu     sync.Mutex
)

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile), "debug")
func SetupLogging(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), level)
func SetupLoggingLong(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Llongfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup colorized output if this is a terminal
func SetColorIfTerminal() {
	if IsTerminal() {
		SetColorOutput()
	}
}

// Setup colorized output
func SetColorOutput() {
	for lvl, color := range LogColor {
		LogPrefix[lvl] = color
	}
	postFix = "\033[0m"
}

// Setup default log output to go to a dev/null
//
//	log.SetOutput(new(DevNull))
func DiscardStandardLogger() {
	log.SetOutput(new(DevNull))
}

// you can set a logger, and log level,most common usage is:
//
//	gou.SetLogger(log.New(os.Stdout, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
// Note, that you can also set a seperate Error Log Level
func SetLogger(l *log.Logger, logLevel string) {
	logger = l
	LogLevelSet(logLevel)
}
func GetLogger() *log.Logger {
	return logger
}

// you can set a logger, and log level.  this is for errors, and assumes
// you are logging to Stderr (seperate from stdout above), allowing you to seperate
// debug&info logging from errors
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
func SetErrLogger(l *log.Logger, logLevel string) {
	loggerErr = l
	if lvl, ok := LogLevelWords[logLevel]; ok {
		ErrLogLevel = lvl
	}
}
func GetErrLogger() *log.Logger {
	return logger
}

// sets the log level from a string
func LogLevelSet(levelWord string) {
	if lvl, ok := LogLevelWords[levelWord]; ok {
		LogLevel = lvl
	}
}

// Log at debug level
func Debug(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Debugf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprintf(format, v...))
	}
}

// Log at info level
func Info(v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprint(v...))
	}
}

// info log formatted
func Infof(format string, v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprintf(format, v...))
	}
}

// Log at warn level
func Warn(v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Warnf(format string, v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprintf(format, v...))
	}
}

// Log at error level
func Error(v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprint(v...))
	}
}

// Error log formatted
func Errorf(format string, v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprintf(format, v...))
	}
}

// Log this error, and return error object
func LogErrorf(format string, v ...interface{}) error {
	err := fmt.Errorf(format, v...)
	if LogLevel >= 1 {
		DoLog(3, ERROR, err.Error())
	}
	return err
}

// Log to logger if setup
//    Log(ERROR, "message")
func Log(logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprint(v...))
	}
}

// Log to logger if setup, grab a stack trace and add that as well
//
//    u.LogTracef(u.ERROR, "message %s", varx)
//
func LogTracef(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		// grab a stack trace
		stackBuf := make([]byte, 6000)
		stackBufLen := runtime.Stack(stackBuf, false)
		stackTraceStr := string(stackBuf[0:stackBufLen])
		parts := strings.Split(stackTraceStr, "\n")
		if len(parts) > 1 {
			v = append(v, strings.Join(parts[3:len(parts)], "\n"))
		}
		DoLog(3, logLvl, fmt.Sprintf(format+"\n%v", v...))
	}
}

// Throttle logging based on key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottleKey(u.ERROR, 1,"error_that_happens_a_lot" "message %s", varx)
//
func LogThrottleKey(logLvl, limit int, key, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[key]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[key] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Throttle logging based on @format as a key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottle(u.ERROR, 1, "message %s", varx)
//
func LogThrottle(logLvl, limit int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[format]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[format] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    Logf(ERROR, "message %d", 20)
func Logf(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    LogP(ERROR, "prefix", "message", anyItems, youWant)
func LogP(logLvl int, prefix string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	}
}

// Log to logger if setup with a prefix
//    LogPf(ERROR, "prefix", "formatString %s %v", anyItems, youWant)
func LogPf(logLvl int, prefix string, format string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	}
}

// When you want to use the log short filename flag, and want to use
// the lower level logging functions (say from an *Assert* type function)
// you need to modify the stack depth:
//
//     func init() {}
// 	       SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile|log.Lmicroseconds), lvl)
//     }
//
//     func assert(t *testing.T, myData) {
//         // we want log line to show line that called this assert, not this line
//         LogD(5, DEBUG, v...)
//     }
func LogD(depth int, logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(depth, logLvl, fmt.Sprint(v...))
	}
}

// Low level log with depth , level, message and logger
func DoLog(depth, logLvl int, msg string) {
	if escapeNewlines {
		msg = EscapeNewlines(msg)
	}
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(depth, LogPrefix[logLvl]+msg+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(depth, LogPrefix[logLvl]+msg+postFix)
	}
}

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

const (
	_TIOCGWINSZ = 0x5413 // OSX 1074295912
)

//http://play.golang.org/p/5LIA41Iqfp
// Dummy discard, satisfies io.Writer without importing io or os.
type DevNull struct{}

func (DevNull) Write(p []byte) (int, error) {
	return len(p), nil
}

//Replace standard newline characters with escaped newlines so long msgs will
//remain one line.
func EscapeNewlines(str string) string {
	return strings.Replace(str, "\n", "\\n", -1)
}
<commit_msg>Defaulting to not escaping newlines to not change standard behavior<commit_after>package gou

import (
	"fmt"
	"log"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

const (
	NOLOGGING = -1
	FATAL     = 0
	ERROR     = 1
	WARN      = 2
	INFO      = 3
	DEBUG     = 4
)

/*
https://github.com/mewkiz/pkg/tree/master/term
RED = '\033[0;1;31m'
GREEN = '\033[0;1;32m'
YELLOW = '\033[0;1;33m'
BLUE = '\033[0;1;34m'
MAGENTA = '\033[0;1;35m'
CYAN = '\033[0;1;36m'
WHITE = '\033[0;1;37m'
DARK_MAGENTA = '\033[0;35m'
ANSI_RESET = '\033[0m'
LogColor         = map[int]string{FATAL: "\033[0m\033[37m",
	ERROR: "\033[0m\033[31m",
	WARN:  "\033[0m\033[33m",
	INFO:  "\033[0m\033[32m",
	DEBUG: "\033[0m\033[34m"}

\e]PFdedede
*/

var (
	LogLevel    int = ERROR
	EMPTY       struct{}
	ErrLogLevel int = ERROR
	logger      *log.Logger
	loggerErr   *log.Logger
	LogColor    = map[int]string{FATAL: "\033[0m\033[37m",
		ERROR: "\033[0m\033[31m",
		WARN:  "\033[0m\033[33m",
		INFO:  "\033[0m\033[35m",
		DEBUG: "\033[0m\033[34m"}
	LogPrefix = map[int]string{
		FATAL: "[FATAL] ",
		ERROR: "[ERROR] ",
		WARN:  "[WARN] ",
		INFO:  "[INFO] ",
		DEBUG: "[DEBUG] ",
	}
	escapeNewlines bool           = false
	postFix                       = "" //\033[0m
	LogLevelWords  map[string]int = map[string]int{"fatal": 0, "error": 1, "warn": 2, "info": 3, "debug": 4, "none": -1}
	logThrottles                  = make(map[string]*Throttler)
	throttleMu     sync.Mutex
)

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile), "debug")
func SetupLogging(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), level)
func SetupLoggingLong(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Llongfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup colorized output if this is a terminal
func SetColorIfTerminal() {
	if IsTerminal() {
		SetColorOutput()
	}
}

// Setup colorized output
func SetColorOutput() {
	for lvl, color := range LogColor {
		LogPrefix[lvl] = color
	}
	postFix = "\033[0m"
}

//Set whether to escape newline characters in log messages
func EscapeNewlines(en bool) {
	escapeNewlines = en
}

// Setup default log output to go to a dev/null
//
//	log.SetOutput(new(DevNull))
func DiscardStandardLogger() {
	log.SetOutput(new(DevNull))
}

// you can set a logger, and log level,most common usage is:
//
//	gou.SetLogger(log.New(os.Stdout, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
// Note, that you can also set a seperate Error Log Level
func SetLogger(l *log.Logger, logLevel string) {
	logger = l
	LogLevelSet(logLevel)
}
func GetLogger() *log.Logger {
	return logger
}

// you can set a logger, and log level.  this is for errors, and assumes
// you are logging to Stderr (seperate from stdout above), allowing you to seperate
// debug&info logging from errors
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
func SetErrLogger(l *log.Logger, logLevel string) {
	loggerErr = l
	if lvl, ok := LogLevelWords[logLevel]; ok {
		ErrLogLevel = lvl
	}
}
func GetErrLogger() *log.Logger {
	return logger
}

// sets the log level from a string
func LogLevelSet(levelWord string) {
	if lvl, ok := LogLevelWords[levelWord]; ok {
		LogLevel = lvl
	}
}

// Log at debug level
func Debug(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Debugf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprintf(format, v...))
	}
}

// Log at info level
func Info(v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprint(v...))
	}
}

// info log formatted
func Infof(format string, v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprintf(format, v...))
	}
}

// Log at warn level
func Warn(v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Warnf(format string, v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprintf(format, v...))
	}
}

// Log at error level
func Error(v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprint(v...))
	}
}

// Error log formatted
func Errorf(format string, v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprintf(format, v...))
	}
}

// Log this error, and return error object
func LogErrorf(format string, v ...interface{}) error {
	err := fmt.Errorf(format, v...)
	if LogLevel >= 1 {
		DoLog(3, ERROR, err.Error())
	}
	return err
}

// Log to logger if setup
//    Log(ERROR, "message")
func Log(logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprint(v...))
	}
}

// Log to logger if setup, grab a stack trace and add that as well
//
//    u.LogTracef(u.ERROR, "message %s", varx)
//
func LogTracef(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		// grab a stack trace
		stackBuf := make([]byte, 6000)
		stackBufLen := runtime.Stack(stackBuf, false)
		stackTraceStr := string(stackBuf[0:stackBufLen])
		parts := strings.Split(stackTraceStr, "\n")
		if len(parts) > 1 {
			v = append(v, strings.Join(parts[3:len(parts)], "\n"))
		}
		DoLog(3, logLvl, fmt.Sprintf(format+"\n%v", v...))
	}
}

// Throttle logging based on key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottleKey(u.ERROR, 1,"error_that_happens_a_lot" "message %s", varx)
//
func LogThrottleKey(logLvl, limit int, key, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[key]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[key] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Throttle logging based on @format as a key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottle(u.ERROR, 1, "message %s", varx)
//
func LogThrottle(logLvl, limit int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[format]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[format] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    Logf(ERROR, "message %d", 20)
func Logf(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    LogP(ERROR, "prefix", "message", anyItems, youWant)
func LogP(logLvl int, prefix string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	}
}

// Log to logger if setup with a prefix
//    LogPf(ERROR, "prefix", "formatString %s %v", anyItems, youWant)
func LogPf(logLvl int, prefix string, format string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	}
}

// When you want to use the log short filename flag, and want to use
// the lower level logging functions (say from an *Assert* type function)
// you need to modify the stack depth:
//
//     func init() {}
// 	       SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile|log.Lmicroseconds), lvl)
//     }
//
//     func assert(t *testing.T, myData) {
//         // we want log line to show line that called this assert, not this line
//         LogD(5, DEBUG, v...)
//     }
func LogD(depth int, logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(depth, logLvl, fmt.Sprint(v...))
	}
}

// Low level log with depth , level, message and logger
func DoLog(depth, logLvl int, msg string) {
	if escapeNewlines {
		msg = EscapeNewlines(msg)
	}
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(depth, LogPrefix[logLvl]+msg+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(depth, LogPrefix[logLvl]+msg+postFix)
	}
}

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

const (
	_TIOCGWINSZ = 0x5413 // OSX 1074295912
)

//http://play.golang.org/p/5LIA41Iqfp
// Dummy discard, satisfies io.Writer without importing io or os.
type DevNull struct{}

func (DevNull) Write(p []byte) (int, error) {
	return len(p), nil
}

//Replace standard newline characters with escaped newlines so long msgs will
//remain one line.
func EscapeNewlines(str string) string {
	return strings.Replace(str, "\n", "\\n", -1)
}
<|endoftext|>


<commit_before>package main

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

const (
	debugLevel   = 0
	infoLevel    = 1
	warningLevel = 2
	errorLevel   = 3
	fatalLevel   = 4
)

type logger struct {
	mode int
}

func newLog() *logger {
	return &logger{
		mode: infoLevel,
	}
}

func (l *logger) debug(v ...interface{}) {
	if l.mode <= debugLevel {
		log.Println("[Debug] ", v)
	}
}

func (l *logger) debugf(format string, v ...interface{}) {
	if l.mode <= debugLevel {
		log.Printf("[Debug] "+format, v)
	}
}

func (l *logger) info(v ...interface{}) {
	if l.mode <= infoLevel {
		log.Println("[Info] ", v)
	}
}

func (l *logger) infof(format string, v ...interface{}) {
	if l.mode <= infoLevel {
		log.Printf("[Info] "+format, v)
	}
}

func (l *logger) error(v ...interface{}) {
	if l.mode <= errorLevel {
		log.Println("[Debug] ", v)
	}
}

func (l *logger) errorf(format string, v ...interface{}) {
	if l.mode <= errorLevel {
		log.Printf("[Error] "+format, v)
	}
}

func (l *logger) fatal(v ...interface{}) {
	if l.mode <= fatalLevel {
		log.Fatal(v)
	}
}

func (l *logger) fatalf(format string, v ...interface{}) {
	if l.mode <= fatalLevel {
		log.Fatalf(format, v)
	}
}

func writeAccessLog(connectionString string) {
	url, err := url.Parse(connectionString)
	panicIf(err)
	var conn net.Conn
	if strings.EqualFold(url.Scheme, "tcp") {
		conn, err = net.Dial("tcp", url.Host)
		if err != nil {
			_logger.errorf("access log connection was failed %v", err)
		}
	} else {
		conn, err = net.Dial("udp", url.Host)
		if err != nil {
			_logger.errorf("access log connection was failed %v", err)
		}
	}

	// check connection status every 1 second
	go func() {
		for {
			if conn == nil {
				// TODO: tcp is hard-code at the point, we need to remove that later
				newConn, err := net.Dial("tcp", url.Host)
				if err == nil {
					conn = newConn
					_logger.debug("created new connection")
				}
			} else {
				// check connection is alive
				one := []byte{}
				if _, err := conn.Read(one); err != nil {
					_logger.debugf("connection was closed: %v", err)
					conn.Close()
					conn = nil
				}
			}
			time.Sleep(1 * time.Second)
		}
	}()

	var empty byte
	for {
		select {
		case message := <-_messageChan:
			if conn != nil {
				payload := message.toByte()
				payload = append(payload, empty) // when we use tcp, we need to add null byte in the end.
				wsize, err := conn.Write(payload)
				if err != nil {
					_logger.debugf("failed to write: %v", err)
					conn.Close()
					conn = nil
				} else {
					msg := fmt.Sprintf("[%s]payload size: %d", message.LoggerName, wsize)
					_logger.debug(msg)
				}
			}
		default:
			time.Sleep(3 * time.Second)
		}
	}
}
<commit_msg>remove check connection<commit_after>package main

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

const (
	debugLevel   = 0
	infoLevel    = 1
	warningLevel = 2
	errorLevel   = 3
	fatalLevel   = 4
)

type logger struct {
	mode int
}

func newLog() *logger {
	return &logger{
		mode: infoLevel,
	}
}

func (l *logger) debug(v ...interface{}) {
	if l.mode <= debugLevel {
		log.Println("[Debug] ", v)
	}
}

func (l *logger) debugf(format string, v ...interface{}) {
	if l.mode <= debugLevel {
		log.Printf("[Debug] "+format, v)
	}
}

func (l *logger) info(v ...interface{}) {
	if l.mode <= infoLevel {
		log.Println("[Info] ", v)
	}
}

func (l *logger) infof(format string, v ...interface{}) {
	if l.mode <= infoLevel {
		log.Printf("[Info] "+format, v)
	}
}

func (l *logger) error(v ...interface{}) {
	if l.mode <= errorLevel {
		log.Println("[Debug] ", v)
	}
}

func (l *logger) errorf(format string, v ...interface{}) {
	if l.mode <= errorLevel {
		log.Printf("[Error] "+format, v)
	}
}

func (l *logger) fatal(v ...interface{}) {
	if l.mode <= fatalLevel {
		log.Fatal(v)
	}
}

func (l *logger) fatalf(format string, v ...interface{}) {
	if l.mode <= fatalLevel {
		log.Fatalf(format, v)
	}
}

func writeAccessLog(connectionString string) {
	url, err := url.Parse(connectionString)
	panicIf(err)
	var conn net.Conn
	if strings.EqualFold(url.Scheme, "tcp") {
		conn, err = net.Dial("tcp", url.Host)
		if err != nil {
			_logger.errorf("access log connection was failed %v", err)
		}
	} else {
		conn, err = net.Dial("udp", url.Host)
		if err != nil {
			_logger.errorf("access log connection was failed %v", err)
		}
	}

	// check connection status every 1 second
	go func() {
		for {
			if conn == nil {
				// TODO: tcp is hard-code at the point, we need to remove that later
				newConn, err := net.Dial("tcp", url.Host)
				if err == nil {
					conn = newConn
					_logger.debug("created new connection")
				}
			} else {
				// check connection is alive
				/*
					one := []byte{}
					if _, err := conn.Read(one); err != nil {
						_logger.debugf("connection was closed: %v", err)
						conn.Close()
						conn = nil
					}
				*/
			}
			time.Sleep(1 * time.Second)
		}
	}()

	var empty byte
	for {
		select {
		case message := <-_messageChan:
			if conn != nil {
				payload := message.toByte()
				payload = append(payload, empty) // when we use tcp, we need to add null byte in the end.
				wsize, err := conn.Write(payload)
				if err != nil {
					_logger.debugf("failed to write: %v", err)
					conn.Close()
					conn = nil
				} else {
					msg := fmt.Sprintf("[%s]payload size: %d", message.LoggerName, wsize)
					_logger.debug(msg)
				}
			}
		default:
			time.Sleep(3 * time.Second)
		}
	}
}
<|endoftext|>


<commit_before>package cml

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

func value16(c uint16, exp float64) float64 {
	if c == 0 {
		return 0.0
	}
	return math.Pow(exp, float64(c-1))
}

func fullValue16(c uint16, exp float64) float64 {
	if c <= 1 {
		return value16(c, exp)
	}
	return (1.0 - value16(c+1, exp)) / (1.0 - exp)
}

/*
Sketch is a Count-Min-Log sketch 16-bit registers
*/
type Sketch struct {
	maxSample    bool
	progressive  bool
	conservative bool
	w            uint
	k            uint
	nBits        uint
	totalCount   uint
	exp          float64
	cMax         float64

	store [][]uint16
}

/*
NewSketch returns a new Count-Min-Log sketch with 16-bit registers
*/
func NewSketch(w uint, k uint, conservative bool, exp float64,
	maxSample bool, progressive bool, nBits uint) (*Sketch, error) {
	store := make([][]uint16, k, k)
	for i := uint(0); i < k; i++ {
		store[i] = make([]uint16, w, w)
	}
	cMax := math.Pow(2.0, float64(nBits)) - 1.0
	if cMax > math.MaxUint16 {
		return nil,
			errors.New("using 16 bit registers allows a max nBits value of 16")
	}
	return &Sketch{
		w:            w,
		k:            k,
		conservative: conservative,
		exp:          exp,
		maxSample:    maxSample,
		progressive:  progressive,
		nBits:        nBits,
		store:        store,
		totalCount:   0.0,
		cMax:         cMax,
	}, nil
}

/*
NewSketchForEpsilonDelta ...
*/
func NewSketchForEpsilonDelta(epsilon, delta float64) (*Sketch, error) {
	var (
		width = uint(math.Ceil(math.E / epsilon))
		depth = uint(math.Ceil(math.Log(1 / delta)))
	)
	return NewSketch(width, depth, true, 1.00026, false, true, 16)
}

/*
NewDefaultSketch returns a new Count-Min-Log sketch with 16-bit registers and default settings
*/
func NewDefaultSketch() (*Sketch, error) {
	return NewSketch(1000000, 7, true, 1.00026, false, true, 16)
}

/*
NewForCapacity16 returns a new Count-Min-Log sketch with 16-bit registers optimized for a given max capacity and expected error rate
*/
func NewForCapacity16(capacity uint64, e float64) (*Sketch, error) {
	if !(e >= 0.001 && e < 1.0) {
		return nil, errors.New("e needs to be >= 0.001 and < 1.0")
	}
	if capacity < 1000000 {
		capacity = 1000000
	}
	w := float64(capacity) / 256
	return NewSketch(uint(w), 32, true, 1.00026, false, true, 16)
}

func (sk *Sketch) randomLog(c uint16) bool {
	pIncrease := 1.0 / (fullValue16(c+1, sk.getExp(c+1)) - fullValue16(c, sk.getExp(c)))
	return randFloat() < pIncrease
}

func (sk *Sketch) getExp(c uint16) float64 {
	if sk.progressive == true {
		return 1.0 + ((sk.exp - 1.0) * (float64(c) - 1.0) / sk.cMax)
	}
	return sk.exp
}

/*
GetFillRate ...
*/
func (sk *Sketch) GetFillRate() float64 {
	occs := 0.0
	size := sk.w * sk.k
	for _, row := range sk.store {
		for _, col := range row {
			if col > 0 {
				occs++
			}
		}
	}
	return 100 * occs / float64(size)
}

/*
Reset the Sketch to a fresh state (all counters set to 0)
*/
func (sk *Sketch) Reset() {
	sk.store = make([][]uint16, sk.k, sk.k)
	for i := 0; i < len(sk.store); i++ {
		sk.store[i] = make([]uint16, sk.w, sk.w)
	}
	sk.totalCount = 0
}

/*
IncreaseCount increases the count of `s` by one, return true if added and the current count of `s`
*/
func (sk *Sketch) IncreaseCount(s []byte) bool {
	sk.totalCount++
	v := make([]uint16, sk.k, sk.k)
	vmin := uint16(math.MaxUint16)
	vmax := uint16(0)
	for i := range v {
		v[i] = sk.store[i][hash(s, uint(i), sk.w)]
		if v[i] < vmin {
			vmin = v[i]
		}
		if v[i] > vmax {
			vmax = v[i]
		}
	}

	var c uint16
	if sk.maxSample {
		c = vmax
	} else {
		c = vmin
	}

	if float64(c) > sk.cMax || !sk.randomLog(c) {
		return false
	}

	for i := uint(0); i < sk.k; i++ {
		nc := v[i]
		if !sk.conservative || vmin == nc {
			sk.store[i][hash(s, i, sk.w)] = nc + 1
		}
	}
	return true
}

/*
Frequency returns the count of `s`
*/
func (sk *Sketch) Frequency(s []byte) float64 {
	clmin := uint16(math.MaxUint16)
	for i := uint(0); i < sk.k; i++ {
		cl := sk.store[i][hash(s, i, sk.w)]
		if cl < clmin {
			clmin = cl
		}
	}
	c := clmin
	return fullValue16(c, sk.getExp(c))
}

/*
Probability returns the error probability of `s`
*/
func (sk *Sketch) Probability(s []byte) float64 {
	v := sk.Frequency(s)
	if v > 0 {
		return v / float64(sk.totalCount)
	}
	return 0
}

/*
TotalCount returns total count of samples
*/
func (sk *Sketch) TotalCount() uint {
	return sk.totalCount
}

/*
Marshal returns a serialized byte array representing the structure
*/
func (sk *Sketch) Marshal() ([]byte, error) {
	buf := new(bytes.Buffer)

	maxSample := uint8(0)
	if sk.maxSample {
		maxSample = 1
	}
	progressive := uint8(0)
	if sk.progressive {
		progressive = 1
	}
	conservative := uint8(0)
	if sk.conservative {
		conservative = 1
	}
	if err := binary.Write(buf, binary.LittleEndian, maxSample); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, progressive); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, conservative); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.w)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.k)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.nBits)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.totalCount)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, float64(sk.exp)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, float64(sk.cMax)); err != nil {
		return nil, err
	}

	bytes := make([]byte, sk.k*sk.w*2, sk.k*sk.w*2)
	for i := range sk.store {
		for j, value := range sk.store[i] {
			d := make([]byte, 2)
			pos := uint(i)*sk.w*2 + uint(j)*2
			binary.LittleEndian.PutUint16(d, value)
			bytes[pos] = d[0]
			bytes[pos+1] = d[1]
		}
	}
	data := append(buf.Bytes(), bytes...)
	return data, nil
}

/*
Unmarshal returns a Sketch from an serialized byte array
*/
func Unmarshal(b []byte) (*Sketch, error) {
	imaxSample := uint8(0)
	iprogressive := uint8(0)
	iconservative := uint8(0)
	w := uint64(0)
	k := uint64(0)
	nBits := uint64(0)
	totalCount := uint64(0)
	exp := float64(0)
	cMax := float64(0)
	buf := bytes.NewReader(b[0:1])

	if err := binary.Read(buf, binary.LittleEndian, &imaxSample); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[1:2])
	if err := binary.Read(buf, binary.LittleEndian, &iprogressive); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[2:3])
	if err := binary.Read(buf, binary.LittleEndian, &iconservative); err != nil {
		return nil, err
	}

	maxSample := false
	if imaxSample > 0 {
		maxSample = true
	}
	progressive := false
	if iprogressive > 0 {
		progressive = true
	}
	conservative := false
	if iconservative > 0 {
		conservative = true
	}

	buf = bytes.NewReader(b[3:11])
	if err := binary.Read(buf, binary.LittleEndian, &w); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[11:19])
	if err := binary.Read(buf, binary.LittleEndian, &k); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[19:27])
	if err := binary.Read(buf, binary.LittleEndian, &nBits); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[27:35])
	if err := binary.Read(buf, binary.LittleEndian, &totalCount); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[35:43])
	if err := binary.Read(buf, binary.LittleEndian, &exp); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[43:51])
	if err := binary.Read(buf, binary.LittleEndian, &cMax); err != nil {
		return nil, err
	}

	store := make([][]uint16, k, k)
	for i := range store {
		store[i] = make([]uint16, w, w)
		for j := range store[i] {
			pos := 51 + uint(i)*uint(w)*2 + uint(j)*2
			value := binary.LittleEndian.Uint16(b[pos : pos+2])
			store[i][j] = value
		}
	}

	sketch := &Sketch{maxSample: maxSample, progressive: progressive, conservative: conservative,
		w: uint(w), k: uint(k), nBits: uint(nBits), totalCount: uint(totalCount),
		exp: exp, cMax: cMax, store: store}

	return sketch, nil
}
<commit_msg>Update docs<commit_after>package cml

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

func value16(c uint16, exp float64) float64 {
	if c == 0 {
		return 0.0
	}
	return math.Pow(exp, float64(c-1))
}

func fullValue16(c uint16, exp float64) float64 {
	if c <= 1 {
		return value16(c, exp)
	}
	return (1.0 - value16(c+1, exp)) / (1.0 - exp)
}

/*
Sketch is a Count-Min-Log sketch 16-bit registers
*/
type Sketch struct {
	maxSample    bool
	progressive  bool
	conservative bool
	w            uint
	k            uint
	nBits        uint
	totalCount   uint
	exp          float64
	cMax         float64

	store [][]uint16
}

/*
NewSketch returns a new Count-Min-Log sketch with 16-bit registers
*/
func NewSketch(w uint, k uint, conservative bool, exp float64,
	maxSample bool, progressive bool, nBits uint) (*Sketch, error) {
	store := make([][]uint16, k, k)
	for i := uint(0); i < k; i++ {
		store[i] = make([]uint16, w, w)
	}
	cMax := math.Pow(2.0, float64(nBits)) - 1.0
	if cMax > math.MaxUint16 {
		return nil,
			errors.New("using 16 bit registers allows a max nBits value of 16")
	}
	return &Sketch{
		w:            w,
		k:            k,
		conservative: conservative,
		exp:          exp,
		maxSample:    maxSample,
		progressive:  progressive,
		nBits:        nBits,
		store:        store,
		totalCount:   0.0,
		cMax:         cMax,
	}, nil
}

/*
NewSketchForEpsilonDelta for a given error rate epsiolen with a probability of delta
*/
func NewSketchForEpsilonDelta(epsilon, delta float64) (*Sketch, error) {
	var (
		width = uint(math.Ceil(math.E / epsilon))
		depth = uint(math.Ceil(math.Log(1 / delta)))
	)
	return NewSketch(width, depth, true, 1.00026, false, true, 16)
}

/*
NewDefaultSketch returns a new Count-Min-Log sketch with 16-bit registers and default settings
*/
func NewDefaultSketch() (*Sketch, error) {
	return NewSketch(1000000, 7, true, 1.00026, false, true, 16)
}

/*
NewForCapacity16 returns a new Count-Min-Log sketch with 16-bit registers optimized for a given max capacity and expected error rate
*/
func NewForCapacity16(capacity uint64, e float64) (*Sketch, error) {
	if !(e >= 0.001 && e < 1.0) {
		return nil, errors.New("e needs to be >= 0.001 and < 1.0")
	}
	if capacity < 1000000 {
		capacity = 1000000
	}
	w := float64(capacity) / 256
	return NewSketch(uint(w), 32, true, 1.00026, false, true, 16)
}

func (sk *Sketch) randomLog(c uint16) bool {
	pIncrease := 1.0 / (fullValue16(c+1, sk.getExp(c+1)) - fullValue16(c, sk.getExp(c)))
	return randFloat() < pIncrease
}

func (sk *Sketch) getExp(c uint16) float64 {
	if sk.progressive == true {
		return 1.0 + ((sk.exp - 1.0) * (float64(c) - 1.0) / sk.cMax)
	}
	return sk.exp
}

/*
GetFillRate return a float representing the fill rate 0.0 being empty and 1.0 being full
*/
func (sk *Sketch) GetFillRate() float64 {
	occs := 0.0
	size := sk.w * sk.k
	for _, row := range sk.store {
		for _, col := range row {
			if col > 0 {
				occs++
			}
		}
	}
	return 100 * occs / float64(size)
}

/*
Reset the Sketch to a fresh state (all counters set to 0)
*/
func (sk *Sketch) Reset() {
	sk.store = make([][]uint16, sk.k, sk.k)
	for i := 0; i < len(sk.store); i++ {
		sk.store[i] = make([]uint16, sk.w, sk.w)
	}
	sk.totalCount = 0
}

/*
IncreaseCount increases the count of `s` by one, return true if added and the current count of `s`
*/
func (sk *Sketch) IncreaseCount(s []byte) bool {
	sk.totalCount++
	v := make([]uint16, sk.k, sk.k)
	vmin := uint16(math.MaxUint16)
	vmax := uint16(0)
	for i := range v {
		v[i] = sk.store[i][hash(s, uint(i), sk.w)]
		if v[i] < vmin {
			vmin = v[i]
		}
		if v[i] > vmax {
			vmax = v[i]
		}
	}

	var c uint16
	if sk.maxSample {
		c = vmax
	} else {
		c = vmin
	}

	if float64(c) > sk.cMax || !sk.randomLog(c) {
		return false
	}

	for i := uint(0); i < sk.k; i++ {
		nc := v[i]
		if !sk.conservative || vmin == nc {
			sk.store[i][hash(s, i, sk.w)] = nc + 1
		}
	}
	return true
}

/*
Frequency returns the count of `s`
*/
func (sk *Sketch) Frequency(s []byte) float64 {
	clmin := uint16(math.MaxUint16)
	for i := uint(0); i < sk.k; i++ {
		cl := sk.store[i][hash(s, i, sk.w)]
		if cl < clmin {
			clmin = cl
		}
	}
	c := clmin
	return fullValue16(c, sk.getExp(c))
}

/*
Probability returns the error probability of `s`
*/
func (sk *Sketch) Probability(s []byte) float64 {
	v := sk.Frequency(s)
	if v > 0 {
		return v / float64(sk.totalCount)
	}
	return 0
}

/*
TotalCount returns total count of samples
*/
func (sk *Sketch) TotalCount() uint {
	return sk.totalCount
}

/*
Marshal returns a serialized byte array representing the structure
*/
func (sk *Sketch) Marshal() ([]byte, error) {
	buf := new(bytes.Buffer)

	maxSample := uint8(0)
	if sk.maxSample {
		maxSample = 1
	}
	progressive := uint8(0)
	if sk.progressive {
		progressive = 1
	}
	conservative := uint8(0)
	if sk.conservative {
		conservative = 1
	}
	if err := binary.Write(buf, binary.LittleEndian, maxSample); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, progressive); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, conservative); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.w)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.k)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.nBits)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, uint64(sk.totalCount)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, float64(sk.exp)); err != nil {
		return nil, err
	}
	if err := binary.Write(buf, binary.LittleEndian, float64(sk.cMax)); err != nil {
		return nil, err
	}

	bytes := make([]byte, sk.k*sk.w*2, sk.k*sk.w*2)
	for i := range sk.store {
		for j, value := range sk.store[i] {
			d := make([]byte, 2)
			pos := uint(i)*sk.w*2 + uint(j)*2
			binary.LittleEndian.PutUint16(d, value)
			bytes[pos] = d[0]
			bytes[pos+1] = d[1]
		}
	}
	data := append(buf.Bytes(), bytes...)
	return data, nil
}

/*
Unmarshal returns a Sketch from an serialized byte array
*/
func Unmarshal(b []byte) (*Sketch, error) {
	imaxSample := uint8(0)
	iprogressive := uint8(0)
	iconservative := uint8(0)
	w := uint64(0)
	k := uint64(0)
	nBits := uint64(0)
	totalCount := uint64(0)
	exp := float64(0)
	cMax := float64(0)
	buf := bytes.NewReader(b[0:1])

	if err := binary.Read(buf, binary.LittleEndian, &imaxSample); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[1:2])
	if err := binary.Read(buf, binary.LittleEndian, &iprogressive); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[2:3])
	if err := binary.Read(buf, binary.LittleEndian, &iconservative); err != nil {
		return nil, err
	}

	maxSample := false
	if imaxSample > 0 {
		maxSample = true
	}
	progressive := false
	if iprogressive > 0 {
		progressive = true
	}
	conservative := false
	if iconservative > 0 {
		conservative = true
	}

	buf = bytes.NewReader(b[3:11])
	if err := binary.Read(buf, binary.LittleEndian, &w); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[11:19])
	if err := binary.Read(buf, binary.LittleEndian, &k); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[19:27])
	if err := binary.Read(buf, binary.LittleEndian, &nBits); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[27:35])
	if err := binary.Read(buf, binary.LittleEndian, &totalCount); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[35:43])
	if err := binary.Read(buf, binary.LittleEndian, &exp); err != nil {
		return nil, err
	}
	buf = bytes.NewReader(b[43:51])
	if err := binary.Read(buf, binary.LittleEndian, &cMax); err != nil {
		return nil, err
	}

	store := make([][]uint16, k, k)
	for i := range store {
		store[i] = make([]uint16, w, w)
		for j := range store[i] {
			pos := 51 + uint(i)*uint(w)*2 + uint(j)*2
			value := binary.LittleEndian.Uint16(b[pos : pos+2])
			store[i][j] = value
		}
	}

	sketch := &Sketch{maxSample: maxSample, progressive: progressive, conservative: conservative,
		w: uint(w), k: uint(k), nBits: uint(nBits), totalCount: uint(totalCount),
		exp: exp, cMax: cMax, store: store}

	return sketch, nil
}
<|endoftext|>


<commit_before>package lru

import (
	"bytes"
	"container/list"
	"encoding/base64"
	"fmt"
	"hash/fnv"
	"io"
	"io/ioutil"
	"os"
	"sync"
	"time"
)

type object struct {
	key        string
	size       uint64
	accessTime time.Time
}

type Cache struct {
	sync.Mutex

	list  *list.List
	table map[string]*list.Element
	size  uint64

	maxSize uint64
	path    string

	debug bool
}

type Options struct {
	ClearCacheOnBoot bool
	Debug            bool
}

func hashCacheKey(data string) string {
	hash := fnv.New64a()
	hash.Write([]byte(data))

	return base64.URLEncoding.EncodeToString(hash.Sum(nil))
}

func New(maxSize uint64, path string, options Options) *Cache {
	cache := Cache{
		list:    list.New(),
		table:   make(map[string]*list.Element),
		maxSize: maxSize,
		path:    path,
		debug:   options.Debug,
	}

	cache.Debug(fmt.Sprintf("new cache of size %d", maxSize))

	if options.ClearCacheOnBoot {
		cache.Debug("clearing cache on boot")
		os.RemoveAll(cache.path)
		os.MkdirAll(cache.path, 0755)
	}

	return &cache
}

func (cache *Cache) Debug(msg string) {
	if cache.debug {
		fmt.Println("[lru]", msg)
	}
}

func (cache *Cache) FilePath(key string) string {
	return cache.path + "/" + hashCacheKey(key)
}

func (cache *Cache) Get(key string) ([]byte, bool) {
	cache.Lock()
	defer cache.Unlock()

	element := cache.table[key]

	if element == nil {
		return nil, false
	}

	cache.moveToFront(element)

	value, err := ioutil.ReadFile(cache.FilePath(element.Value.(*object).key))

	if err != nil {
		return nil, false
	}

	return value, true
}

func (cache *Cache) GetBuffer(key string) (data *bytes.Buffer, ok bool) {
	cache.Lock()
	defer cache.Unlock()

	element := cache.table[key]

	if element == nil {
		return nil, false
	}

	cache.moveToFront(element)

	file, err := os.Open(cache.FilePath(element.Value.(*object).key))

	if err != nil {
		return nil, false
	}

	io.Copy(data, file)

	if err != nil {
		return nil, false
	}

	return data, true
}

func (cache *Cache) Set(key string, value []byte) {
	cache.Lock()
	defer cache.Unlock()

	if element := cache.table[key]; element != nil {
		cache.moveToFront(element)
	} else {
		cache.addNew(key, value)
	}
}

func (cache *Cache) Delete(key string) bool {
	cache.Lock()
	defer cache.Unlock()

	element := cache.table[key]

	if element == nil {
		return false
	}

	err := os.Remove(cache.FilePath(key))

	if err != nil {
		return false
	}

	cache.list.Remove(element)
	delete(cache.table, key)

	cache.size -= element.Value.(*object).size

	return true
}

func (cache *Cache) Clear() {
	cache.Lock()
	defer cache.Unlock()

	cache.clearFiles()
	cache.list.Init()
	cache.table = make(map[string]*list.Element)
	cache.size = 0
}

func (cache *Cache) Size() uint64 {
	cache.Lock()
	defer cache.Unlock()

	return cache.size
}

func (cache *Cache) MaxSize() uint64 {
	cache.Lock()
	defer cache.Unlock()

	return cache.maxSize
}

func (cache *Cache) Oldest() (oldest time.Time) {
	cache.Lock()
	defer cache.Unlock()

	if lastElem := cache.list.Back(); lastElem != nil {
		oldest = lastElem.Value.(*object).accessTime
	}

	return
}

func (cache *Cache) keys() []string {
	keys := make([]string, 0, cache.list.Len())

	for element := cache.list.Front(); element != nil; element = element.Next() {
		keys = append(keys, element.Value.(*object).key)
	}

	return keys
}

func (cache *Cache) moveToFront(element *list.Element) {
	cache.list.MoveToFront(element)
	element.Value.(*object).accessTime = time.Now()
}

func (cache *Cache) addNew(key string, value []byte) {
	size := uint64(len(value))

	cache.Debug(fmt.Sprintf("new object of size %d", size))

	if size > cache.maxSize {
		cache.Debug("file is too large")
		return
	}

	newObject := &object{key, size, time.Now()}

	cache.trim(cache.size + newObject.size)

	if _, err := os.Stat(cache.FilePath(key)); os.IsNotExist(err) {
		err := ioutil.WriteFile(cache.FilePath(key), value, 0644)

		if err != nil {
			cache.Debug(err.Error())
			return
		}

		element := cache.list.PushFront(newObject)
		cache.table[key] = element
		cache.size += (*newObject).size
		cache.Debug(fmt.Sprintf("added %d, new size is %d", (*newObject).size, cache.size))
	} else {
		cache.Debug("file already exist")
	}
}

func (cache *Cache) trim(futureSize uint64) {
	for futureSize > cache.maxSize {
		element := cache.list.Back()

		if element == nil {
			cache.Debug("file is too large")
			return
		}

		value := cache.list.Remove(element).(*object)

		cache.Debug(fmt.Sprintf("deleting %s", cache.FilePath(value.key)))

		if err := os.RemoveAll(cache.FilePath(value.key)); err != nil {
			cache.Debug(fmt.Sprintf("couldn't delete %s", cache.FilePath(value.key)))
		}

		delete(cache.table, value.key)

		cache.size -= value.size
		futureSize -= value.size
	}
}

func (cache *Cache) clearFiles() {
	for _, key := range cache.keys() {
		os.RemoveAll(cache.FilePath(key))
	}
}
<commit_msg>Should have thought of that<commit_after>package lru

import (
	"bytes"
	"container/list"
	"encoding/base64"
	"fmt"
	"hash/fnv"
	"io"
	"io/ioutil"
	"os"
	"sync"
	"time"
)

type object struct {
	key        string
	size       uint64
	accessTime time.Time
}

type Cache struct {
	sync.Mutex

	list  *list.List
	table map[string]*list.Element
	size  uint64

	maxSize uint64
	path    string

	debug bool
}

type Options struct {
	ClearCacheOnBoot bool
	Debug            bool
}

func hashCacheKey(data string) string {
	hash := fnv.New64a()
	hash.Write([]byte(data))

	return base64.URLEncoding.EncodeToString(hash.Sum(nil))
}

func New(maxSize uint64, path string, options Options) *Cache {
	cache := Cache{
		list:    list.New(),
		table:   make(map[string]*list.Element),
		maxSize: maxSize,
		path:    path,
		debug:   options.Debug,
	}

	cache.Debug(fmt.Sprintf("new cache of size %d", maxSize))

	if options.ClearCacheOnBoot {
		cache.Debug("clearing cache on boot")
		os.RemoveAll(cache.path)
		os.MkdirAll(cache.path, 0755)
	}

	return &cache
}

func (cache *Cache) Debug(msg string) {
	if cache.debug {
		fmt.Println("[lru]", msg)
	}
}

func (cache *Cache) FilePath(key string) string {
	return cache.path + "/" + hashCacheKey(key)
}

func (cache *Cache) Get(key string) ([]byte, bool) {
	cache.Lock()
	defer cache.Unlock()

	element := cache.table[key]

	if element == nil {
		return nil, false
	}

	cache.moveToFront(element)

	value, err := ioutil.ReadFile(cache.FilePath(element.Value.(*object).key))

	if err != nil {
		return nil, false
	}

	return value, true
}

func (cache *Cache) GetBuffer(key string) (data *bytes.Buffer, ok bool) {
	cache.Lock()
	defer cache.Unlock()

	element := cache.table[key]

	if element == nil {
		return nil, false
	}

	cache.moveToFront(element)

	file, err := os.Open(cache.FilePath(element.Value.(*object).key))

	if err != nil {
		return nil, false
	}

	data = &bytes.Buffer{}

	io.Copy(data, file)

	if err != nil {
		return nil, false
	}

	return data, true
}

func (cache *Cache) Set(key string, value []byte) {
	cache.Lock()
	defer cache.Unlock()

	if element := cache.table[key]; element != nil {
		cache.moveToFront(element)
	} else {
		cache.addNew(key, value)
	}
}

func (cache *Cache) Delete(key string) bool {
	cache.Lock()
	defer cache.Unlock()

	element := cache.table[key]

	if element == nil {
		return false
	}

	err := os.Remove(cache.FilePath(key))

	if err != nil {
		return false
	}

	cache.list.Remove(element)
	delete(cache.table, key)

	cache.size -= element.Value.(*object).size

	return true
}

func (cache *Cache) Clear() {
	cache.Lock()
	defer cache.Unlock()

	cache.clearFiles()
	cache.list.Init()
	cache.table = make(map[string]*list.Element)
	cache.size = 0
}

func (cache *Cache) Size() uint64 {
	cache.Lock()
	defer cache.Unlock()

	return cache.size
}

func (cache *Cache) MaxSize() uint64 {
	cache.Lock()
	defer cache.Unlock()

	return cache.maxSize
}

func (cache *Cache) Oldest() (oldest time.Time) {
	cache.Lock()
	defer cache.Unlock()

	if lastElem := cache.list.Back(); lastElem != nil {
		oldest = lastElem.Value.(*object).accessTime
	}

	return
}

func (cache *Cache) keys() []string {
	keys := make([]string, 0, cache.list.Len())

	for element := cache.list.Front(); element != nil; element = element.Next() {
		keys = append(keys, element.Value.(*object).key)
	}

	return keys
}

func (cache *Cache) moveToFront(element *list.Element) {
	cache.list.MoveToFront(element)
	element.Value.(*object).accessTime = time.Now()
}

func (cache *Cache) addNew(key string, value []byte) {
	size := uint64(len(value))

	cache.Debug(fmt.Sprintf("new object of size %d", size))

	if size > cache.maxSize {
		cache.Debug("file is too large")
		return
	}

	newObject := &object{key, size, time.Now()}

	cache.trim(cache.size + newObject.size)

	if _, err := os.Stat(cache.FilePath(key)); os.IsNotExist(err) {
		err := ioutil.WriteFile(cache.FilePath(key), value, 0644)

		if err != nil {
			cache.Debug(err.Error())
			return
		}

		element := cache.list.PushFront(newObject)
		cache.table[key] = element
		cache.size += (*newObject).size
		cache.Debug(fmt.Sprintf("added %d, new size is %d", (*newObject).size, cache.size))
	} else {
		cache.Debug("file already exist")
	}
}

func (cache *Cache) trim(futureSize uint64) {
	for futureSize > cache.maxSize {
		element := cache.list.Back()

		if element == nil {
			cache.Debug("file is too large")
			return
		}

		value := cache.list.Remove(element).(*object)

		cache.Debug(fmt.Sprintf("deleting %s", cache.FilePath(value.key)))

		if err := os.RemoveAll(cache.FilePath(value.key)); err != nil {
			cache.Debug(fmt.Sprintf("couldn't delete %s", cache.FilePath(value.key)))
		}

		delete(cache.table, value.key)

		cache.size -= value.size
		futureSize -= value.size
	}
}

func (cache *Cache) clearFiles() {
	for _, key := range cache.keys() {
		os.RemoveAll(cache.FilePath(key))
	}
}
<|endoftext|>


<commit_before>package tmsh

import (
	"fmt"
	"strconv"
	"strings"
)

type Node struct {
	Name          string `ltm:"name"`
	Addr          string `ltm:"addr"`
	MonitorRule   string `ltm:"monitor-rule"`
	MonitorStatus string `ltm:"monitor-status"`
	EnabledState  string `ltm:"status.enabled-state"`
}

type Pool struct {
	ActiveMemberCount int          `ltm:"active-member-cnt"`
	Name              string       `ltm:"name"`
	MonitorRule       string       `ltm:"monitor-rule"`
	AvailabilityState string       `ltm:"status.availability-state"`
	EnabledState      string       `ltm:"status.enabled-state"`
	StatusReason      string       `ltm:"status.status-reason"`
	PoolMembers       []PoolMember `ltm:"members"`
}

type PoolMember struct {
	Name              string `ltm:"node-name"`
	Addr              string `ltm:"addr"`
	Port              int    `ltm:"port"`
	MonitorRule       string `ltm:"monitor-rule"`
	MonitorStatus     string `ltm:"monitor-status"`
	EnabledState      string `ltm:"status.enabled-state"`
	AvailabilityState string `ltm:"status.availability-state"`
	StatusReason      string `ltm:"status.status-reason"`
}

type VirtualServer struct {
	Name        string             `ltm:"name"`
	Destination string             `ltm:"destination"`
	IpProtocol  string             `ltm:"ip-protocol"`
	Mask        string             `ltm:"mask"`
	Partition   string             `ltm:"partition"`
	Pool        string             `ltm:"pool"`
	Profiles    map[string]Profile `ltm:"profiles"`
}

type Profile struct {
	Context string `ltm:"context"`
}

func (bigip *BigIP) GetAllNodes() ([]Node, error) {
	return nil, nil
}

func (bigip *BigIP) GetNode(name string) (*Node, error) {
	ret, _ := bigip.ExecuteCommand("show ltm node " + name + " field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}

	var node Node
	if err := Unmarshal(ret, &node); err != nil {
		return nil, err
	}

	return &node, nil
}

func (bigip *BigIP) CreateNode(name, ipaddr string) error {
	ret, _ := bigip.ExecuteCommand("create ltm node " + name + " address " + ipaddr)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteNode(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm node " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-enabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-disabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetAllPools() ([]Pool, error) {
	return nil, nil
}

func (bigip *BigIP) GetPool(name string) (*Pool, error) {
	ret, _ := bigip.ExecuteCommand("show ltm pool " + name + " members field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}

	var pool Pool
	if err := Unmarshal(ret, &pool); err != nil {
		return nil, err
	}

	return &pool, nil
}

func (bigip *BigIP) CreatePool(name string) error {
	ret, _ := bigip.ExecuteCommand("create ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePool(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddMonitorToPool(poolName, monitorName string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm pool " + poolName + " monitor '" + monitorName + "'")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddPoolMember(poolName, nodeName, monitorName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members add { " + member + " } monitor '" + monitorName + "'"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members delete { " + member + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-enabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-disabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetAllVirtualServers() ([]VirtualServer, error) {
	return nil, nil
}

func (bigip *BigIP) GetVirtualServer(name string) (*VirtualServer, error) {
	ret, _ := bigip.ExecuteCommand("list ltm virtual " + name)
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}

	var vs VirtualServer
	if err := Unmarshal(ret, &vs); err != nil {
		return nil, err
	}

	return &vs, nil
}

func (bigip *BigIP) CreateVirtualServer(vsName, poolName, targetVIP, defaultProfileName string, targetPort int) error {
	destination := targetVIP + ":" + strconv.Itoa(targetPort)
	cmd := "create ltm virtual " + vsName + " { destination " + destination + " ip-protocol tcp mask 255.255.255.255 pool " + poolName + " profiles add { " + defaultProfileName + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServer(vsName string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm virtual " + vsName)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles add { " + profileName + " { context " + context + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles delete { " + profileName + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) ApplyPolicyToVirtualServer(vsName, policyName string) error {
	cmd := "modify ltm virtual " + vsName + " fw-enforced-policy " + policyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) RouteAdvertisementEnabled(targetVIP string) error {
	cmd := "modify ltm virtual-address " + targetVIP + " route-advertisement enabled"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) CreateSecurityFWPolicy(firewallPolicyName string) error {
	cmd := "create security firewall policy " + firewallPolicyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddSecurityFWPolicyRule(firewallPolicyName, ruleName, action string, targetPort int) error {
	if action != "accept" && action != "accept-decisively" &&
		action != "drop" && action != "reject" {
		return fmt.Errorf("Invalid action name: " + action)
	}

	cmd := "modify security firewall policy " + firewallPolicyName + " rules add { " + ruleName +
		" { action " + action + " ip-protocol tcp destination { ports add { " + strconv.Itoa(targetPort) + " } } place-after last } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}
<commit_msg>Implement GetAll functions<commit_after>package tmsh

import (
	"fmt"
	"strconv"
	"strings"
)

type Node struct {
	Name          string `ltm:"name"`
	Addr          string `ltm:"addr"`
	MonitorRule   string `ltm:"monitor-rule"`
	MonitorStatus string `ltm:"monitor-status"`
	EnabledState  string `ltm:"status.enabled-state"`
}

type Pool struct {
	ActiveMemberCount int          `ltm:"active-member-cnt"`
	Name              string       `ltm:"name"`
	MonitorRule       string       `ltm:"monitor-rule"`
	AvailabilityState string       `ltm:"status.availability-state"`
	EnabledState      string       `ltm:"status.enabled-state"`
	StatusReason      string       `ltm:"status.status-reason"`
	PoolMembers       []PoolMember `ltm:"members"`
}

type PoolMember struct {
	Name              string `ltm:"node-name"`
	Addr              string `ltm:"addr"`
	Port              int    `ltm:"port"`
	MonitorRule       string `ltm:"monitor-rule"`
	MonitorStatus     string `ltm:"monitor-status"`
	EnabledState      string `ltm:"status.enabled-state"`
	AvailabilityState string `ltm:"status.availability-state"`
	StatusReason      string `ltm:"status.status-reason"`
}

type VirtualServer struct {
	Name        string             `ltm:"name"`
	Destination string             `ltm:"destination"`
	IpProtocol  string             `ltm:"ip-protocol"`
	Mask        string             `ltm:"mask"`
	Partition   string             `ltm:"partition"`
	Pool        string             `ltm:"pool"`
	Profiles    map[string]Profile `ltm:"profiles"`
}

type Profile struct {
	Context string `ltm:"context"`
}

func splitLtmOutput(str string) []string {
	sep := "ltm"
	strs := []string{}
	for _, s := range strings.Split(str, sep) {
		if s == "" {
			continue
		}
		s = sep + s
		strs = append(strs, s)
	}
	return strs
}

func (bigip *BigIP) GetAllNodes() ([]Node, error) {
	ret, err := bigip.ExecuteCommand("show ltm node field-fmt")
	if err != nil {
		return nil, err
	}

	var nodes []Node
	for _, s := range splitLtmOutput(ret) {
		var n Node
		if err := Unmarshal(s, &n); err != nil {
			return nil, err
		}
		nodes = append(nodes, n)
	}

	return nodes, nil
}

func (bigip *BigIP) GetNode(name string) (*Node, error) {
	ret, _ := bigip.ExecuteCommand("show ltm node " + name + " field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}

	var node Node
	if err := Unmarshal(ret, &node); err != nil {
		return nil, err
	}

	return &node, nil
}

func (bigip *BigIP) CreateNode(name, ipaddr string) error {
	ret, _ := bigip.ExecuteCommand("create ltm node " + name + " address " + ipaddr)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteNode(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm node " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-enabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-disabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetAllPools() ([]Pool, error) {
	ret, err := bigip.ExecuteCommand("show ltm pool members field-fmt")
	if err != nil {
		return nil, err
	}

	var pools []Pool
	for _, s := range splitLtmOutput(ret) {
		var p Pool
		if err := Unmarshal(s, &p); err != nil {
			return nil, err
		}
		pools = append(pools, p)
	}

	return pools, nil
}

func (bigip *BigIP) GetPool(name string) (*Pool, error) {
	ret, _ := bigip.ExecuteCommand("show ltm pool " + name + " members field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}

	var pool Pool
	if err := Unmarshal(ret, &pool); err != nil {
		return nil, err
	}

	return &pool, nil
}

func (bigip *BigIP) CreatePool(name string) error {
	ret, _ := bigip.ExecuteCommand("create ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePool(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddMonitorToPool(poolName, monitorName string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm pool " + poolName + " monitor '" + monitorName + "'")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddPoolMember(poolName, nodeName, monitorName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members add { " + member + " } monitor '" + monitorName + "'"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members delete { " + member + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-enabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-disabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetAllVirtualServers() ([]VirtualServer, error) {
	ret, err := bigip.ExecuteCommand("list ltm virtual all-properties")
	if err != nil {
		return nil, err
	}

	var vss []VirtualServer
	for _, s := range splitLtmOutput(ret) {
		var vs VirtualServer
		if err := Unmarshal(s, &vs); err != nil {
			return nil, err
		}
		vss = append(vss, vs)
	}

	return vss, nil
}

func (bigip *BigIP) GetVirtualServer(name string) (*VirtualServer, error) {
	ret, _ := bigip.ExecuteCommand("list ltm virtual " + name)
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}

	var vs VirtualServer
	if err := Unmarshal(ret, &vs); err != nil {
		return nil, err
	}

	return &vs, nil
}

func (bigip *BigIP) CreateVirtualServer(vsName, poolName, targetVIP, defaultProfileName string, targetPort int) error {
	destination := targetVIP + ":" + strconv.Itoa(targetPort)
	cmd := "create ltm virtual " + vsName + " { destination " + destination + " ip-protocol tcp mask 255.255.255.255 pool " + poolName + " profiles add { " + defaultProfileName + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServer(vsName string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm virtual " + vsName)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles add { " + profileName + " { context " + context + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles delete { " + profileName + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) ApplyPolicyToVirtualServer(vsName, policyName string) error {
	cmd := "modify ltm virtual " + vsName + " fw-enforced-policy " + policyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) RouteAdvertisementEnabled(targetVIP string) error {
	cmd := "modify ltm virtual-address " + targetVIP + " route-advertisement enabled"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) CreateSecurityFWPolicy(firewallPolicyName string) error {
	cmd := "create security firewall policy " + firewallPolicyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddSecurityFWPolicyRule(firewallPolicyName, ruleName, action string, targetPort int) error {
	if action != "accept" && action != "accept-decisively" &&
		action != "drop" && action != "reject" {
		return fmt.Errorf("Invalid action name: " + action)
	}

	cmd := "modify security firewall policy " + firewallPolicyName + " rules add { " + ruleName +
		" { action " + action + " ip-protocol tcp destination { ports add { " + strconv.Itoa(targetPort) + " } } place-after last } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"path/filepath"
)

// GitPodsRunner builds, runs, stops and restarts GitPods.
type GitPodsRunner struct {
	name    string
	env     []string
	cmd     *exec.Cmd
	restart chan bool
}

func NewGitPodsRunner(name string, env []string) *GitPodsRunner {
	return &GitPodsRunner{
		name:    name,
		env:     env,
		restart: make(chan bool, 1),
	}
}

func (r *GitPodsRunner) Name() string {
	return r.name
}

func (r *GitPodsRunner) Run() error {
	file := "./dev/" + r.name
	_, err := os.Stat(file)
	if err != nil {
		if err := r.Build(); err == nil {
			r.restart <- true
		}
	}

	//// Enter the first for iteration to start the services
	//r.restart <- true

	var cmd *exec.Cmd
	for {
		//<-r.restart

		if cmd != nil {
			r.Stop()
		}

		r.cmd = exec.Command("./dev/" + r.name)
		r.cmd.Env = r.env
		r.cmd.Stdin = os.Stdin
		r.cmd.Stdout = os.Stdout
		r.cmd.Stderr = os.Stderr
		return r.cmd.Run()
	}

}

func (r *GitPodsRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}

func (r *GitPodsRunner) Build() error {
	cmd := exec.Command("go", "build", "-v", "-i", "-o", "./dev/"+r.name, "./cmd/"+r.name)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (r GitPodsRunner) Restart() {
	r.restart <- true
}

// WebpackRunner runs webpack either ones or watches the files.
type WebpackRunner struct {
	cmd *exec.Cmd
}

func (r *WebpackRunner) Run(watch bool) error {
	file := "./webpack.config.js"
	_, err := os.Stat(file)
	if err != nil {
		// webpack config not found
		return nil
	}

	args := []string{}
	if watch {
		args = []string{"--watch"}
	}

	r.cmd = exec.Command(filepath.Join("node_modules", ".bin", "webpack"), args...)
	r.cmd.Stdin = os.Stdin
	r.cmd.Stdout = os.Stdout
	r.cmd.Stderr = os.Stderr

	return r.cmd.Run()
}

func (r *WebpackRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}

// CaddyRunner runs caddy
type CaddyRunner struct {
	cmd *exec.Cmd
}

func (r *CaddyRunner) Run() error {
	r.cmd = exec.Command(filepath.Join(".", "dev", "caddy"), "-conf", "./dev/Caddyfile")
	r.cmd.Stdin = os.Stdin
	r.cmd.Stdout = os.Stdout
	r.cmd.Stderr = os.Stderr

	return r.cmd.Run()
}

func (r *CaddyRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}
<commit_msg>Always build binaries when running gitpods dev<commit_after>package main

import (
	"os"
	"os/exec"
	"path/filepath"
)

// GitPodsRunner builds, runs, stops and restarts GitPods.
type GitPodsRunner struct {
	name    string
	env     []string
	cmd     *exec.Cmd
	restart chan bool
}

func NewGitPodsRunner(name string, env []string) *GitPodsRunner {
	return &GitPodsRunner{
		name:    name,
		env:     env,
		restart: make(chan bool, 1),
	}
}

func (r *GitPodsRunner) Name() string {
	return r.name
}

func (r *GitPodsRunner) Run() error {
	if err := r.Build(); err == nil {
		r.restart <- true
	}

	//// Enter the first for iteration to start the services
	//r.restart <- true

	var cmd *exec.Cmd
	for {
		//<-r.restart

		if cmd != nil {
			r.Stop()
		}

		r.cmd = exec.Command("./dev/" + r.name)
		r.cmd.Env = r.env
		r.cmd.Stdin = os.Stdin
		r.cmd.Stdout = os.Stdout
		r.cmd.Stderr = os.Stderr
		return r.cmd.Run()
	}

}

func (r *GitPodsRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}

func (r *GitPodsRunner) Build() error {
	cmd := exec.Command("go", "build", "-v", "-i", "-o", "./dev/"+r.name, "./cmd/"+r.name)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (r GitPodsRunner) Restart() {
	r.restart <- true
}

// WebpackRunner runs webpack either ones or watches the files.
type WebpackRunner struct {
	cmd *exec.Cmd
}

func (r *WebpackRunner) Run(watch bool) error {
	file := "./webpack.config.js"
	_, err := os.Stat(file)
	if err != nil {
		// webpack config not found
		return nil
	}

	args := []string{}
	if watch {
		args = []string{"--watch"}
	}

	r.cmd = exec.Command(filepath.Join("node_modules", ".bin", "webpack"), args...)
	r.cmd.Stdin = os.Stdin
	r.cmd.Stdout = os.Stdout
	r.cmd.Stderr = os.Stderr

	return r.cmd.Run()
}

func (r *WebpackRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}

// CaddyRunner runs caddy
type CaddyRunner struct {
	cmd *exec.Cmd
}

func (r *CaddyRunner) Run() error {
	r.cmd = exec.Command(filepath.Join(".", "dev", "caddy"), "-conf", "./dev/Caddyfile")
	r.cmd.Stdin = os.Stdin
	r.cmd.Stdout = os.Stdout
	r.cmd.Stderr = os.Stderr

	return r.cmd.Run()
}

func (r *CaddyRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}
<|endoftext|>