<commit_before>// Copyright 2014-2015 Apptimist, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/apptimistco/asn/debug"
	"github.com/apptimistco/asn/debug/file"
)

const (
	AsnUsage = `Usage:	asn [FLAGS] [COMMAND [ARGS...]]

`
	ExampleUsage = `
Examples:

  $ asn -config example-sf &
  $ asn -config example-adm echo hello world
  $ asn -config example-adm -server 1 echo hello world
  $ asn -config example-adm -server sf echo hello world
  $ asn -config example-adm -server sf			# CLI
  $ asn -config example-adm -server sf - <<-EOF
	echo hello world
  EOF

`
	ExampleConfigs = `
Server CONFIG Format:
  name: STRING
  dir: PATH
  lat: FLOAT
  lon: FLOAT
  listen:
  - unix:///PATH.sock
  - tcp://:PORT
  - ws://[HOST][:PORT]/PATH.ws
  keys:
    admin:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    server:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      sec:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    nonce: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Admin CONFIG Format:
  name: STRING
  dir: PATH
  lat: FLOAT
  lon: FLOAT
  keys:
    admin:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      sec:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    server:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    nonce: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  server:
  - name: local
    url: unix:///PATH.sock
  - name: sf
    url: ws://HOST[:PORT]/PATH.ws
    lat: 37.774929
    lon: -122.419415
  - name: la
    url: ws://HOST[:PORT]/PATH.ws
    lat: 34.052234
    lon: -118.243684
`
	ConfigExt = ".yaml"
	LogExt    = ".log"
	ReposExt  = ".asn"

	DefaultConfigFN = AsnStr + ConfigExt
	DefaultReposDN  = ReposExt
)

var (
	Exit = os.Exit
	FS   *flag.FlagSet
	FN   struct {
		config string
		diag   string
		log    string
	}
	Show struct {
		help    bool
		config  bool
		ids     bool
		errors  bool
		newkeys bool
		sums    bool
	}
	NL    = []byte{'\n'}
	Time0 = time.Time{}
	Debug = debug.Debug(AsnStr)
)

func init() {
	FS = flag.NewFlagSet(AsnStr, flag.ContinueOnError)
	FS.Usage = ShowHelp
	FS.BoolVar(&Show.help, "show-help", false,
		`Print this and exit.`)
	FS.BoolVar(&Show.config, "show-config", false,
		`Print configuration with redacted keys and exit.`)
	FS.BoolVar(&Show.ids, "show-ids", false,
		`Print ASN protocol identifiers and exit.`)
	FS.BoolVar(&Show.errors, "show-errors", false,
		`Print ASN protocol error codes and exit.`)
	FS.BoolVar(&Show.newkeys, "new-keys", false,
		"Print new keys and exit.")
	FS.BoolVar(&Show.sums, "show-sums", false,
		"Print sums of *.go files and exit.")
	FS.StringVar(&FN.config, "config", DefaultConfigFN,
		`Load configuration from named file or builtin string.
	Without this flag asn searches './' and '/etc' for 'asn.yaml'.`)
	FS.StringVar(&FN.log, "log", "",
		`This redirects all log output to the named file instead of
	syslog or 'NAME.log' with the prefix of the config flag.`)
}

func IsBlob(fi os.FileInfo) bool {
	fn := fi.Name()
	return !fi.IsDir() && len(fn) == 2*(SumSz-1) && IsHex(fn)
}

func IsBridge(fn string) bool {
	return filepath.Base(filepath.Dir(fn)) == "bridge"
}

func IsHex(s string) bool {
	if s == "" {
		return false
	}
	for _, c := range s {
		if !('0' <= c && c <= '9' ||
			'a' <= c && c <= 'f' ||
			'A' <= c && c <= 'f') {
			return false
		}
	}
	return true
}

func IsINT(sig os.Signal) bool  { return sig == syscall.SIGINT }
func IsTERM(sig os.Signal) bool { return sig == syscall.SIGTERM }
func IsUSR1(sig os.Signal) bool { return sig == syscall.SIGUSR1 }

func IsTopDir(fi os.FileInfo) bool {
	fn := fi.Name()
	return fi.IsDir() && len(fn) == ReposTopSz && IsHex(fn)
}

func IsUser(fn string) bool {
	return IsHex(fn) && len(fn) == 2*(PubEncrSz-1)
}

func main() {
	syscall.Umask(0007)
	cmd := Command{
		Stdin:  file.File{os.Stdin},
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}
	pid := os.Getpid()
	FS.BoolVar(&cmd.Flag.Admin, "admin", false,
		`Run COMMAND or CLI in admin mode.
	This is the default action if the configuration doesn't have
	any listerners.`)
	FS.BoolVar(&cmd.Flag.NoLogin, "nologin", false,
		`run COMMAND w/o login`)
	FS.StringVar(&cmd.Flag.Server, "server", "0",
		`Connect to the configured server with the matching name,
	URL or at the given index.`)
	err := FS.Parse(os.Args[1:])
	prefix := strings.TrimSuffix(FN.config, ConfigExt)
	cmd.Debug.Set(prefix)
	logfn := ""
	if FN.log != "" {
		logfn = FN.log
	} else if FN.config != DefaultConfigFN {
		logfn = prefix + LogExt
	}
	if logfn != "" {
		var f *os.File
		if f, err = os.Create(logfn); err != nil {
			return
		}
		defer f.Close()
		if err = f.Chmod(0664); err != nil {
			return
		}
		debug.Redirect(f)
		cmd.Log("start", pid)
	}
	defer func() {
		cmd.Log("end", pid)
		if err != nil {
			cmd.Diag(debug.Depth(2), err)
			io.WriteString(cmd.Stderr, err.Error())
			cmd.Stderr.Write(NL)
			Exit(1)
		}
	}()
	switch {
	case err == flag.ErrHelp:
		return
	case err != nil:
		return
	case Show.help:
		showHelp(cmd.Stdout)
		return
	case Show.errors:
		cmd.ShowErrors()
		return
	case Show.ids:
		cmd.ShowIds()
		return
	case Show.newkeys:
		cmd.ShowNewKeys()
		return
	case Show.sums:
		cmd.ShowSums()
		return
	}
	if err = cmd.Cfg.Parse(FN.config); err != nil {
		return
	}
	if Show.config {
		cmd.ShowConfig()
		return
	}
	cmd.Sig = make(Sig, 1)
	cmd.Done = make(Done, 1)
	signal.Notify(cmd.Sig,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGUSR1)
	if cmd.Flag.Admin || len(cmd.Cfg.Listen) == 0 {
		go cmd.Admin(FS.Args()...)
	} else {
		go cmd.Server(FS.Args()...)
	}
	if err = cmd.Wait(); err == io.EOF {
		err = nil
	}
	FlushPDU()
}

func MkdirAll(dn string) error {
	return os.MkdirAll(dn, os.FileMode(0770))
}

func showHelp(out io.Writer) {
	io.WriteString(out, AsnUsage)
	io.WriteString(out, "Flags:\n\n")
	FS.PrintDefaults()
	io.WriteString(out, ExampleUsage)
	io.WriteString(out, ExecUsage)
	io.WriteString(out, ExampleConfigs)
}

func ShowHelp() {
	showHelp(os.Stderr)
}

// UrlPathSearch looks for the given file in this order.
//	path		return
//	/foo.bar	foo.bar
//	/foo/bar	foo/bar if foo/ exists; otherwise
//			/foo/bar
func UrlPathSearch(path string) string {
	dir := filepath.Dir(path)
	if dir == "/" {
		return filepath.Base(path)
	} else {
		if f, err := os.Open(dir[1:]); err == nil {
			f.Close()
			return path[1:]
		}
	}
	return path
}

type Command struct {
	debug.Debug
	Stdin  ReadCloseWriteToer
	Stdout io.WriteCloser
	Stderr io.WriteCloser
	Sig    Sig
	Done   Done
	Cfg    Config
	Flag   struct {
		Admin   bool
		NoLogin bool
		Server  string
	}
}

func (cmd *Command) ShowConfig() {
	c := cmd.Cfg
	c.Keys = nil
	io.WriteString(cmd.Stdout, c.String())
}

func (cmd *Command) ShowIds() {
	fmt.Fprintf(cmd.Stdout, "%25s%s\n", "", "Version")
	fmt.Fprintf(cmd.Stdout, "%25s", "")
	for v := Version(0); v <= Latest; v++ {
		fmt.Fprintf(cmd.Stdout, "%4d", v)
	}
	cmd.Stdout.Write(NL)
	for id := RawId + 1; id < Nids; id++ {
		fmt.Fprintf(cmd.Stdout, "%8d.", id)
		if s := id.String(); len(s) > 0 {
			fmt.Fprintf(cmd.Stdout, "%16s", s+"Id")
			for v := Version(0); v <= Latest; v++ {
				fmt.Fprintf(cmd.Stdout, "%4d", id.Version(v))
			}
		}
		cmd.Stdout.Write(NL)
	}
}

func (cmd *Command) ShowErrors() {
	fmt.Fprintf(cmd.Stdout, "%25s%s\n", "", "Version")
	fmt.Fprintf(cmd.Stdout, "%25s", "")
	for v := Version(0); v <= Latest; v++ {
		fmt.Fprintf(cmd.Stdout, "%4d", v)
	}
	cmd.Stdout.Write(NL)
	for ecode, s := range ErrStrings {
		fmt.Fprintf(cmd.Stdout, "%8d.", ecode)
		fmt.Fprintf(cmd.Stdout, "%16s", s)
		for v := Version(0); v <= Latest; v++ {
			fmt.Fprintf(cmd.Stdout, "%4d", Err(ecode).Version(v))
		}
		cmd.Stdout.Write(NL)
	}
}

func (cmd *Command) ShowNewKeys() {
	if k, err := NewRandomServiceKeys(); err != nil {
		io.WriteString(os.Stderr, err.Error())
	} else {
		io.WriteString(cmd.Stdout, k.String())
	}
}

func (cmd *Command) ShowSums() {
	b := &bytes.Buffer{}
	dot, err := os.Open(".")
	if err != nil {
		io.WriteString(os.Stderr, err.Error())
		return
	}
	dir, _ := dot.Readdir(0)
	dot.Close()
	var in, out Sums
	for _, fi := range dir {
		if strings.HasSuffix(fi.Name(), ".go") {
			if f, err := os.Open(fi.Name()); err != nil {
				io.WriteString(os.Stderr, err.Error())
			} else {
				sum := NewSumOf(f)
				out = append(out, *sum)
				fmt.Fprintf(cmd.Stdout, "%s:\t%s\n",
					fi.Name(), sum.FullString())
				sum = nil
			}
		}
	}
	out.WriteTo(b)
	in.ReadFrom(b)
	if len(out) != len(in) {
		fmt.Fprintf(os.Stderr, "Mismatched lengths %d vs. %d\n",
			len(in), len(out))
	} else {
		for i := range in {
			if in[i] != out[i] {
				fmt.Fprintf(os.Stderr,
					"mismatch @ %d : %s vs. %s\n",
					i, in[i].String()[:8],
					out[i].String()[:8])
			}
		}
	}
}

func (cmd *Command) Wait() error { return cmd.Done.Wait() }

type Done chan error

func (done Done) Wait() error { return <-done }

type Sig chan os.Signal

func (sig Sig) INT()  { sig <- syscall.SIGINT }
func (sig Sig) TERM() { sig <- syscall.SIGTERM }
func (sig Sig) USR1() { sig <- syscall.SIGUSR1 }
<commit_msg>Buffer the signal channel<commit_after>// Copyright 2014-2015 Apptimist, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/apptimistco/asn/debug"
	"github.com/apptimistco/asn/debug/file"
)

const (
	AsnUsage = `Usage:	asn [FLAGS] [COMMAND [ARGS...]]

`
	ExampleUsage = `
Examples:

  $ asn -config example-sf &
  $ asn -config example-adm echo hello world
  $ asn -config example-adm -server 1 echo hello world
  $ asn -config example-adm -server sf echo hello world
  $ asn -config example-adm -server sf			# CLI
  $ asn -config example-adm -server sf - <<-EOF
	echo hello world
  EOF

`
	ExampleConfigs = `
Server CONFIG Format:
  name: STRING
  dir: PATH
  lat: FLOAT
  lon: FLOAT
  listen:
  - unix:///PATH.sock
  - tcp://:PORT
  - ws://[HOST][:PORT]/PATH.ws
  keys:
    admin:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    server:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      sec:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    nonce: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Admin CONFIG Format:
  name: STRING
  dir: PATH
  lat: FLOAT
  lon: FLOAT
  keys:
    admin:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      sec:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    server:
      pub:
        encr: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        auth: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    nonce: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  server:
  - name: local
    url: unix:///PATH.sock
  - name: sf
    url: ws://HOST[:PORT]/PATH.ws
    lat: 37.774929
    lon: -122.419415
  - name: la
    url: ws://HOST[:PORT]/PATH.ws
    lat: 34.052234
    lon: -118.243684
`
	ConfigExt = ".yaml"
	LogExt    = ".log"
	ReposExt  = ".asn"

	DefaultConfigFN = AsnStr + ConfigExt
	DefaultReposDN  = ReposExt
)

var (
	Exit = os.Exit
	FS   *flag.FlagSet
	FN   struct {
		config string
		diag   string
		log    string
	}
	Show struct {
		help    bool
		config  bool
		ids     bool
		errors  bool
		newkeys bool
		sums    bool
	}
	NL    = []byte{'\n'}
	Time0 = time.Time{}
	Debug = debug.Debug(AsnStr)
)

func init() {
	FS = flag.NewFlagSet(AsnStr, flag.ContinueOnError)
	FS.Usage = ShowHelp
	FS.BoolVar(&Show.help, "show-help", false,
		`Print this and exit.`)
	FS.BoolVar(&Show.config, "show-config", false,
		`Print configuration with redacted keys and exit.`)
	FS.BoolVar(&Show.ids, "show-ids", false,
		`Print ASN protocol identifiers and exit.`)
	FS.BoolVar(&Show.errors, "show-errors", false,
		`Print ASN protocol error codes and exit.`)
	FS.BoolVar(&Show.newkeys, "new-keys", false,
		"Print new keys and exit.")
	FS.BoolVar(&Show.sums, "show-sums", false,
		"Print sums of *.go files and exit.")
	FS.StringVar(&FN.config, "config", DefaultConfigFN,
		`Load configuration from named file or builtin string.
	Without this flag asn searches './' and '/etc' for 'asn.yaml'.`)
	FS.StringVar(&FN.log, "log", "",
		`This redirects all log output to the named file instead of
	syslog or 'NAME.log' with the prefix of the config flag.`)
}

func IsBlob(fi os.FileInfo) bool {
	fn := fi.Name()
	return !fi.IsDir() && len(fn) == 2*(SumSz-1) && IsHex(fn)
}

func IsBridge(fn string) bool {
	return filepath.Base(filepath.Dir(fn)) == "bridge"
}

func IsHex(s string) bool {
	if s == "" {
		return false
	}
	for _, c := range s {
		if !('0' <= c && c <= '9' ||
			'a' <= c && c <= 'f' ||
			'A' <= c && c <= 'f') {
			return false
		}
	}
	return true
}

func IsINT(sig os.Signal) bool  { return sig == syscall.SIGINT }
func IsTERM(sig os.Signal) bool { return sig == syscall.SIGTERM }
func IsUSR1(sig os.Signal) bool { return sig == syscall.SIGUSR1 }

func IsTopDir(fi os.FileInfo) bool {
	fn := fi.Name()
	return fi.IsDir() && len(fn) == ReposTopSz && IsHex(fn)
}

func IsUser(fn string) bool {
	return IsHex(fn) && len(fn) == 2*(PubEncrSz-1)
}

func main() {
	syscall.Umask(0007)
	cmd := Command{
		Stdin:  file.File{os.Stdin},
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}
	pid := os.Getpid()
	FS.BoolVar(&cmd.Flag.Admin, "admin", false,
		`Run COMMAND or CLI in admin mode.
	This is the default action if the configuration doesn't have
	any listerners.`)
	FS.BoolVar(&cmd.Flag.NoLogin, "nologin", false,
		`run COMMAND w/o login`)
	FS.StringVar(&cmd.Flag.Server, "server", "0",
		`Connect to the configured server with the matching name,
	URL or at the given index.`)
	err := FS.Parse(os.Args[1:])
	prefix := strings.TrimSuffix(FN.config, ConfigExt)
	cmd.Debug.Set(prefix)
	logfn := ""
	if FN.log != "" {
		logfn = FN.log
	} else if FN.config != DefaultConfigFN {
		logfn = prefix + LogExt
	}
	if logfn != "" {
		var f *os.File
		if f, err = os.Create(logfn); err != nil {
			return
		}
		defer f.Close()
		if err = f.Chmod(0664); err != nil {
			return
		}
		debug.Redirect(f)
	}
	cmd.Log("start", pid)
	defer func() {
		cmd.Log("end", pid)
		if err != nil {
			cmd.Log(debug.Depth(2), err)
			io.WriteString(cmd.Stderr, err.Error())
			cmd.Stderr.Write(NL)
			Exit(1)
		}
	}()
	switch {
	case err == flag.ErrHelp:
		return
	case err != nil:
		return
	case Show.help:
		showHelp(cmd.Stdout)
		return
	case Show.errors:
		cmd.ShowErrors()
		return
	case Show.ids:
		cmd.ShowIds()
		return
	case Show.newkeys:
		cmd.ShowNewKeys()
		return
	case Show.sums:
		cmd.ShowSums()
		return
	}
	if err = cmd.Cfg.Parse(FN.config); err != nil {
		return
	}
	if Show.config {
		cmd.ShowConfig()
		return
	}
	cmd.Sig = make(Sig, 4)
	cmd.Done = make(Done, 1)
	signal.Notify(cmd.Sig,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGUSR1)
	defer signal.Stop(cmd.Sig)
	defer FlushPDU()
	if cmd.Flag.Admin || len(cmd.Cfg.Listen) == 0 {
		go cmd.Admin(FS.Args()...)
	} else {
		go cmd.Server(FS.Args()...)
	}
	if err = cmd.Wait(); err == io.EOF {
		err = nil
	}
}

func MkdirAll(dn string) error {
	return os.MkdirAll(dn, os.FileMode(0770))
}

func showHelp(out io.Writer) {
	io.WriteString(out, AsnUsage)
	io.WriteString(out, "Flags:\n\n")
	FS.PrintDefaults()
	io.WriteString(out, ExampleUsage)
	io.WriteString(out, ExecUsage)
	io.WriteString(out, ExampleConfigs)
}

func ShowHelp() {
	showHelp(os.Stderr)
}

// UrlPathSearch looks for the given file in this order.
//	path		return
//	/foo.bar	foo.bar
//	/foo/bar	foo/bar if foo/ exists; otherwise
//			/foo/bar
func UrlPathSearch(path string) string {
	dir := filepath.Dir(path)
	if dir == "/" {
		return filepath.Base(path)
	} else {
		if f, err := os.Open(dir[1:]); err == nil {
			f.Close()
			return path[1:]
		}
	}
	return path
}

type Command struct {
	debug.Debug
	Stdin  ReadCloseWriteToer
	Stdout io.WriteCloser
	Stderr io.WriteCloser
	Sig    Sig
	Done   Done
	Cfg    Config
	Flag   struct {
		Admin   bool
		NoLogin bool
		Server  string
	}
}

func (cmd *Command) ShowConfig() {
	c := cmd.Cfg
	c.Keys = nil
	io.WriteString(cmd.Stdout, c.String())
}

func (cmd *Command) ShowIds() {
	fmt.Fprintf(cmd.Stdout, "%25s%s\n", "", "Version")
	fmt.Fprintf(cmd.Stdout, "%25s", "")
	for v := Version(0); v <= Latest; v++ {
		fmt.Fprintf(cmd.Stdout, "%4d", v)
	}
	cmd.Stdout.Write(NL)
	for id := RawId + 1; id < Nids; id++ {
		fmt.Fprintf(cmd.Stdout, "%8d.", id)
		if s := id.String(); len(s) > 0 {
			fmt.Fprintf(cmd.Stdout, "%16s", s+"Id")
			for v := Version(0); v <= Latest; v++ {
				fmt.Fprintf(cmd.Stdout, "%4d", id.Version(v))
			}
		}
		cmd.Stdout.Write(NL)
	}
}

func (cmd *Command) ShowErrors() {
	fmt.Fprintf(cmd.Stdout, "%25s%s\n", "", "Version")
	fmt.Fprintf(cmd.Stdout, "%25s", "")
	for v := Version(0); v <= Latest; v++ {
		fmt.Fprintf(cmd.Stdout, "%4d", v)
	}
	cmd.Stdout.Write(NL)
	for ecode, s := range ErrStrings {
		fmt.Fprintf(cmd.Stdout, "%8d.", ecode)
		fmt.Fprintf(cmd.Stdout, "%16s", s)
		for v := Version(0); v <= Latest; v++ {
			fmt.Fprintf(cmd.Stdout, "%4d", Err(ecode).Version(v))
		}
		cmd.Stdout.Write(NL)
	}
}

func (cmd *Command) ShowNewKeys() {
	if k, err := NewRandomServiceKeys(); err != nil {
		io.WriteString(os.Stderr, err.Error())
	} else {
		io.WriteString(cmd.Stdout, k.String())
	}
}

func (cmd *Command) ShowSums() {
	b := &bytes.Buffer{}
	dot, err := os.Open(".")
	if err != nil {
		io.WriteString(os.Stderr, err.Error())
		return
	}
	dir, _ := dot.Readdir(0)
	dot.Close()
	var in, out Sums
	for _, fi := range dir {
		if strings.HasSuffix(fi.Name(), ".go") {
			if f, err := os.Open(fi.Name()); err != nil {
				io.WriteString(os.Stderr, err.Error())
			} else {
				sum := NewSumOf(f)
				out = append(out, *sum)
				fmt.Fprintf(cmd.Stdout, "%s:\t%s\n",
					fi.Name(), sum.FullString())
				sum = nil
			}
		}
	}
	out.WriteTo(b)
	in.ReadFrom(b)
	if len(out) != len(in) {
		fmt.Fprintf(os.Stderr, "Mismatched lengths %d vs. %d\n",
			len(in), len(out))
	} else {
		for i := range in {
			if in[i] != out[i] {
				fmt.Fprintf(os.Stderr,
					"mismatch @ %d : %s vs. %s\n",
					i, in[i].String()[:8],
					out[i].String()[:8])
			}
		}
	}
}

func (cmd *Command) Wait() error { return cmd.Done.Wait() }

type Done chan error

func (done Done) Wait() error { return <-done }

type Sig chan os.Signal

func (sig Sig) INT()  { sig <- syscall.SIGINT }
func (sig Sig) TERM() { sig <- syscall.SIGTERM }
func (sig Sig) USR1() { sig <- syscall.SIGUSR1 }
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

type ConfigType struct {
	CliCmd      string
	PzAddr      string
	SvcName     string
	Url         string
	Port        int
	Description string
	Attributes  map[string]string
}

type OutStruct struct {
	InFiles    map[string]string
	OutFiles   map[string]string
	ProgReturn string
}

func main() {

	if len(os.Args) < 2 {
		fmt.Println("error: Insufficient parameters.  You must specify a config file.")
		return
	}

	// first argument after the base call should be the path to the config file.
	// ReadFile returns the contents of the file as a byte buffer.
	configBuf, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Println("error:", err)
	}

	var configObj ConfigType
	err = json.Unmarshal(configBuf, &configObj)
	if err != nil {
		fmt.Println("error:", err)
	}

	if configObj.Port <= 0 {
		configObj.Port = 8080
	}

	portStr := ":" + strconv.Itoa(configObj.Port)

	if configObj.SvcName != "" && configObj.PzAddr != "" {
		fullUrl := configObj.Url + portStr
fmt.Println("About to manage registration.")
		err = pzsvc.ManageRegistration(configObj.SvcName, configObj.Description, fullUrl, configObj.PzAddr)
		if err != nil {
			fmt.Println("error:", err)
		}
fmt.Println("Registration managed.")

	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		switch r.URL.Path {
		case "/":
			fmt.Fprintf(w, "hello.")
		case "/execute":
			{

				var cmdParam string
				var inFileStr string
				var outTiffStr string
				var outTxtStr string
				var outGeoJStr string
				var usePz string

				// might be time to start looking into that "help" thing.

				if r.Method == "GET" {
					cmdParam = r.URL.Query().Get("cmd")
					inFileStr = r.URL.Query().Get("inFiles")
					outTiffStr = r.URL.Query().Get("outTiffs")
					outTxtStr = r.URL.Query().Get("outTxts")
					outGeoJStr = r.URL.Query().Get("outGeoJson")
					usePz = r.URL.Query().Get("pz")
				} else {
					cmdParam = r.FormValue("cmd")
					inFileStr = r.FormValue("inFiles")
					outTiffStr = r.FormValue("outTiffs")
					outTxtStr = r.FormValue("outTxts")
					outGeoJStr = r.FormValue("outGeoJson")
					usePz = r.FormValue("pz")
				}

				cmdConfigSlice := splitOrNil(configObj.CliCmd, " ")
				cmdParamSlice := splitOrNil(cmdParam, " ")
				cmdSlice := append(cmdConfigSlice, cmdParamSlice...)

				inFileSlice := splitOrNil(inFileStr, ",")
				outTiffSlice := splitOrNil(outTiffStr, ",")
				outTxtSlice := splitOrNil(outTxtStr, ",")
				outGeoJSlice := splitOrNil(outGeoJStr, ",")

				var output OutStruct

				uuid, err := exec.Command("uuidgen").Output()
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}

				runId := string(uuid)

				err = os.Mkdir("./"+runId, 0777)
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}
				defer os.RemoveAll("./" + runId)

				err = os.Chmod("./"+runId, 0777)
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}

				if len(inFileSlice) > 0 {
					output.InFiles = make(map[string]string)
				}
				if len(outTiffSlice)+len(outTxtSlice)+len(outGeoJSlice) > 0 {
					output.OutFiles = make(map[string]string)
				}

				for i, inFile := range inFileSlice {

					fmt.Printf("Downloading file %s - %d of %d.\n", inFile, i, len(inFileSlice))
					fname, err := pzsvc.Download(inFile, runId, configObj.PzAddr)
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Download failed.  %s", err.Error())
					} else {
						output.InFiles[inFile] = fname
						fmt.Printf("Successfully downloaded %s.", fname)
					}
				}

				if len(cmdSlice) == 0 {
					fmt.Fprintf(w, `No cmd specified in config file.  Please provide "cmd" param.`)
					break
				}

				fmt.Printf("Executing \"%s\".\n", configObj.CliCmd+" "+cmdParam)

				clc := exec.Command(cmdSlice[0], cmdSlice[1:]...)
				clc.Dir = runId
				var b bytes.Buffer
				clc.Stdout = &b
				clc.Stderr = os.Stderr

				err = clc.Run()
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}
				fmt.Printf("Program output: %s\n", b.String())
				output.ProgReturn = b.String()

				for i, outTiff := range outTiffSlice {
					fmt.Printf("Uploading Tiff %s - %d of %d.\n", outTiff, i, len(outTiffSlice))
					dataId, err := pzsvc.IngestTiff(outTiff, runId, configObj.PzAddr, cmdSlice[0])
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Upload failed.  %s", err.Error())
					} else {
						output.OutFiles[outTiff] = dataId
					}
				}

				for i, outTxt := range outTxtSlice {
					fmt.Printf("Uploading Txt %s - %d of %d.\n", outTxt, i, len(outTxtSlice))
					dataId, err := pzsvc.IngestTxt(outTxt, runId, configObj.PzAddr, cmdSlice[0])
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Upload failed.  %s", err.Error())
					} else {
						output.OutFiles[outTxt] = dataId
					}
				}

				for i, outGeoJ := range outGeoJSlice {
					fmt.Printf("Uploading GeoJson %s - %d of %d.\n", outGeoJ, i, len(outGeoJSlice))
					dataId, err := pzsvc.IngestGeoJson(outGeoJ, runId, configObj.PzAddr, cmdSlice[0])
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Upload failed.  %s", err.Error())
					} else {
						output.OutFiles[outGeoJ] = dataId
					}
				}

				outBuf, err := json.Marshal(output)
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}

				outStr := string(outBuf)

				if usePz != "" {
					outStr = strconv.QuoteToASCII(outStr)
					// TODO: clean this up a bit, and possibly move it back into
					// the support function.
					// - possibly include metadata to help on results searches?  Talk with Marge on where/how to put it in.
					outStr = fmt.Sprintf(`{ "dataType": { "type": "text", "content": "%s" "mimeType": "text/plain" }, "metadata": {} }`, outStr)
				}

				fmt.Fprintf(w, outStr)

			}
		case "/description":
			if configObj.Description == "" {
				fmt.Fprintf(w, "No description defined")
			} else {
				fmt.Fprintf(w, configObj.Description)
			}
		case "/attributes":
			if configObj.Attributes == nil {
				fmt.Fprintf(w, "{ }")
			} else {
				// convert attributes back into Json
				// this might require specifying the interface a bit better.
				//					fmt.Fprintf(w, configObj.Attributes)
			}
		case "/help":
			fmt.Fprintf(w, "We're sorry, help is not yet implemented.\n")
		default:
			fmt.Fprintf(w, "Command undefined.  Try help?\n")
		}
	})

	log.Fatal(http.ListenAndServe(portStr, nil))
}

func splitOrNil(inString, knife string) []string {
	if inString == "" {
		return nil
	}
	return strings.Split(inString, knife)
}
<commit_msg>further tweaks.  Checked it in wrong last time.<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

type ConfigType struct {
	CliCmd      string
	PzAddr      string
	SvcName     string
	Url         string
	Port        int
	Description string
	Attributes  map[string]string
}

type OutStruct struct {
	InFiles    map[string]string
	OutFiles   map[string]string
	ProgReturn string
}

func main() {

	if len(os.Args) < 2 {
		fmt.Println("error: Insufficient parameters.  You must specify a config file.")
		return
	}

	// first argument after the base call should be the path to the config file.
	// ReadFile returns the contents of the file as a byte buffer.
	configBuf, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Println("error:", err)
	}

	var configObj ConfigType
	err = json.Unmarshal(configBuf, &configObj)
	if err != nil {
		fmt.Println("error:", err)
	}

	if configObj.Port <= 0 {
		configObj.Port = 8080
	}

	portStr := ":" + strconv.Itoa(configObj.Port)

	if configObj.SvcName != "" && configObj.PzAddr != "" {
fmt.Println("About to manage registration.")
		err = pzsvc.ManageRegistration(configObj.SvcName, configObj.Description, configObj.Url, configObj.PzAddr)
		if err != nil {
			fmt.Println("error:", err)
		}
fmt.Println("Registration managed.")

	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		switch r.URL.Path {
		case "/":
			fmt.Fprintf(w, "hello.")
		case "/execute":
			{

				var cmdParam string
				var inFileStr string
				var outTiffStr string
				var outTxtStr string
				var outGeoJStr string
				var usePz string

				// might be time to start looking into that "help" thing.

				if r.Method == "GET" {
					cmdParam = r.URL.Query().Get("cmd")
					inFileStr = r.URL.Query().Get("inFiles")
					outTiffStr = r.URL.Query().Get("outTiffs")
					outTxtStr = r.URL.Query().Get("outTxts")
					outGeoJStr = r.URL.Query().Get("outGeoJson")
					usePz = r.URL.Query().Get("pz")
				} else {
					cmdParam = r.FormValue("cmd")
					inFileStr = r.FormValue("inFiles")
					outTiffStr = r.FormValue("outTiffs")
					outTxtStr = r.FormValue("outTxts")
					outGeoJStr = r.FormValue("outGeoJson")
					usePz = r.FormValue("pz")
				}

				cmdConfigSlice := splitOrNil(configObj.CliCmd, " ")
				cmdParamSlice := splitOrNil(cmdParam, " ")
				cmdSlice := append(cmdConfigSlice, cmdParamSlice...)

				inFileSlice := splitOrNil(inFileStr, ",")
				outTiffSlice := splitOrNil(outTiffStr, ",")
				outTxtSlice := splitOrNil(outTxtStr, ",")
				outGeoJSlice := splitOrNil(outGeoJStr, ",")

				var output OutStruct

				uuid, err := exec.Command("uuidgen").Output()
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}

				runId := string(uuid)

				err = os.Mkdir("./"+runId, 0777)
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}
				defer os.RemoveAll("./" + runId)

				err = os.Chmod("./"+runId, 0777)
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}

				if len(inFileSlice) > 0 {
					output.InFiles = make(map[string]string)
				}
				if len(outTiffSlice)+len(outTxtSlice)+len(outGeoJSlice) > 0 {
					output.OutFiles = make(map[string]string)
				}

				for i, inFile := range inFileSlice {

					fmt.Printf("Downloading file %s - %d of %d.\n", inFile, i, len(inFileSlice))
					fname, err := pzsvc.Download(inFile, runId, configObj.PzAddr)
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Download failed.  %s", err.Error())
					} else {
						output.InFiles[inFile] = fname
						fmt.Printf("Successfully downloaded %s.", fname)
					}
				}

				if len(cmdSlice) == 0 {
					fmt.Fprintf(w, `No cmd specified in config file.  Please provide "cmd" param.`)
					break
				}

				fmt.Printf("Executing \"%s\".\n", configObj.CliCmd+" "+cmdParam)

				clc := exec.Command(cmdSlice[0], cmdSlice[1:]...)
				clc.Dir = runId
				var b bytes.Buffer
				clc.Stdout = &b
				clc.Stderr = os.Stderr

				err = clc.Run()
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}
				fmt.Printf("Program output: %s\n", b.String())
				output.ProgReturn = b.String()

				for i, outTiff := range outTiffSlice {
					fmt.Printf("Uploading Tiff %s - %d of %d.\n", outTiff, i, len(outTiffSlice))
					dataId, err := pzsvc.IngestTiff(outTiff, runId, configObj.PzAddr, cmdSlice[0])
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Upload failed.  %s", err.Error())
					} else {
						output.OutFiles[outTiff] = dataId
					}
				}

				for i, outTxt := range outTxtSlice {
					fmt.Printf("Uploading Txt %s - %d of %d.\n", outTxt, i, len(outTxtSlice))
					dataId, err := pzsvc.IngestTxt(outTxt, runId, configObj.PzAddr, cmdSlice[0])
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Upload failed.  %s", err.Error())
					} else {
						output.OutFiles[outTxt] = dataId
					}
				}

				for i, outGeoJ := range outGeoJSlice {
					fmt.Printf("Uploading GeoJson %s - %d of %d.\n", outGeoJ, i, len(outGeoJSlice))
					dataId, err := pzsvc.IngestGeoJson(outGeoJ, runId, configObj.PzAddr, cmdSlice[0])
					if err != nil {
						fmt.Fprintf(w, err.Error())
						fmt.Printf("Upload failed.  %s", err.Error())
					} else {
						output.OutFiles[outGeoJ] = dataId
					}
				}

				outBuf, err := json.Marshal(output)
				if err != nil {
					fmt.Fprintf(w, err.Error())
				}

				outStr := string(outBuf)

				if usePz != "" {
					outStr = strconv.QuoteToASCII(outStr)
					// TODO: clean this up a bit, and possibly move it back into
					// the support function.
					// - possibly include metadata to help on results searches?  Talk with Marge on where/how to put it in.
					outStr = fmt.Sprintf(`{ "dataType": { "type": "text", "content": "%s" "mimeType": "text/plain" }, "metadata": {} }`, outStr)
				}

				fmt.Fprintf(w, outStr)

			}
		case "/description":
			if configObj.Description == "" {
				fmt.Fprintf(w, "No description defined")
			} else {
				fmt.Fprintf(w, configObj.Description)
			}
		case "/attributes":
			if configObj.Attributes == nil {
				fmt.Fprintf(w, "{ }")
			} else {
				// convert attributes back into Json
				// this might require specifying the interface a bit better.
				//					fmt.Fprintf(w, configObj.Attributes)
			}
		case "/help":
			fmt.Fprintf(w, "We're sorry, help is not yet implemented.\n")
		default:
			fmt.Fprintf(w, "Command undefined.  Try help?\n")
		}
	})

	log.Fatal(http.ListenAndServe(portStr, nil))
}

func splitOrNil(inString, knife string) []string {
	if inString == "" {
		return nil
	}
	return strings.Split(inString, knife)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Nan Deng
 *
 * 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 main

import (
	"github.com/uniqush/uniqush-conn/proto"
	"fmt"
	"net"
	"encoding/pem"
	"crypto/x509"
	"crypto/rsa"
	"io/ioutil"
)

func readPrivateKey(keyFileName string) (priv *rsa.PrivateKey, err error) {
	keyData, err := ioutil.ReadFile(keyFileName)
	if err != nil {
		return
	}

	b, _ := pem.Decode(keyData)
	priv, err := x509.ParsePKCS1PrivateKey(b.Bytes)
	if err != nil {
		return
	}
	return
}

func main() {
	ln, err := net.Listen("tcp", ":8964")
	if err != nil {
		fmt.Printf("Error: %v", err)
		return
	}
}

<commit_msg>compilable version of main<commit_after>/*
 * Copyright 2012 Nan Deng
 *
 * 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 main

import (
	"github.com/uniqush/uniqush-conn/configparser"
	"github.com/uniqush/uniqush-conn/msgcenter"
	"fmt"
	"net"
	"encoding/pem"
	"crypto/x509"
	"crypto/rsa"
	"io/ioutil"
	"flag"
	"os"
	"time"
)

func readPrivateKey(keyFileName string) (priv *rsa.PrivateKey, err error) {
	keyData, err := ioutil.ReadFile(keyFileName)
	if err != nil {
		return
	}

	b, _ := pem.Decode(keyData)
	priv, err = x509.ParsePKCS1PrivateKey(b.Bytes)
	if err != nil {
		return
	}
	return
}

var argvKeyFile = flag.String("key", "key.pem", "private key")
var argvConfigFile = flag.String("config", "config.yaml", "config file path")

// In memory of the blood on the square.
var argvPort = flag.Int("port", 0x2304, "port number")

func main() {
	flag.Parse()
	ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%v", *argvPort))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Network error: %v\n", err)
		return
	}

	privkey, err := readPrivateKey(*argvKeyFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Key error: %v\n", err)
		return
	}
	config, err := configparser.Parse(*argvConfigFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Config error: %v\n", err)
		return
	}

	center := msgcenter.NewMessageCenter(ln, privkey, nil, nil, 3 * time.Second, config.Auth, config)
	center.Start()
}

<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"syscall"

	"github.com/BurntSushi/toml"
	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/zenazn/goji/graceful"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var (
	configPath = flag.String("config-file", "./config.toml", "path to qmd config file")
	config     Config

	producer *nsq.Producer
	consumer *nsq.Consumer
	redisDB  *redis.Pool
)

func main() {
	flag.Parse()
	fmt.Printf("Using config file from: %s\n", *configPath)

	var err error
	_, err = toml.DecodeFile(*configPath, &config)
	if err != nil {
		log.Println(err)
		return
	}

	fmt.Println("Setting up producer")
	producer = nsq.NewProducer(config.QueueAddr, nsq.NewConfig())

	fmt.Println("Creating Redis connection pool")
	redisDB = newPool(config.RedisAddr)

	// Setup and start worker.
	fmt.Println("Creating worker")
	worker, err := NewWorker(config)
	if err != nil {
		log.Println(err)
		return
	}
	go worker.Run()

	// Http server
	w := web.New()
	w.Use(middleware.Logger)

	w.Get("/", ServiceRoot)
	w.Post("/", ServiceRoot)
	w.Get("/scripts", GetAllScripts)
	w.Put("/scripts", ReloadScripts)
	w.Post("/scripts/:name", RunScript)
	w.Get("/scripts/:name/logs", GetAllLogs)
	w.Get("/scripts/:name/logs/:id", GetLog)

	err = graceful.ListenAndServe(config.ListenOnAddr, w)
	if err != nil {
		log.Fatal(err)
	}
	graceful.AddSignal(syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	graceful.Wait()
}

// func ExampleMiddleware(h http.Handler) http.Handler {
// 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 		log.Println("Request yooooooo")
// 		h.ServeHTTP(w, r)
// 	})
// }
<commit_msg>Add graceful prehook fn<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"syscall"

	"github.com/BurntSushi/toml"
	"github.com/bitly/go-nsq"
	"github.com/garyburd/redigo/redis"
	"github.com/zenazn/goji/graceful"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var (
	configPath = flag.String("config-file", "./config.toml", "path to qmd config file")
	config     Config

	producer *nsq.Producer
	consumer *nsq.Consumer
	redisDB  *redis.Pool
)

func main() {
	flag.Parse()
	fmt.Printf("Using config file from: %s\n", *configPath)

	var err error
	_, err = toml.DecodeFile(*configPath, &config)
	if err != nil {
		log.Println(err)
		return
	}

	fmt.Println("Setting up producer")
	producer = nsq.NewProducer(config.QueueAddr, nsq.NewConfig())

	fmt.Println("Creating Redis connection pool")
	redisDB = newPool(config.RedisAddr)

	// Setup and start worker.
	fmt.Println("Creating worker")
	worker, err := NewWorker(config)
	if err != nil {
		log.Println(err)
		return
	}
	go worker.Run()

	// Http server
	w := web.New()
	w.Use(middleware.Logger)

	w.Get("/", ServiceRoot)
	w.Post("/", ServiceRoot)
	w.Get("/scripts", GetAllScripts)
	w.Put("/scripts", ReloadScripts)
	w.Post("/scripts/:name", RunScript)
	w.Get("/scripts/:name/logs", GetAllLogs)
	w.Get("/scripts/:name/logs/:id", GetLog)

	// Spin up the server with graceful hooks
	graceful.PreHook(func() {
		fmt.Println("Shutting down producer")
		producer.Stop()

		fmt.Println("Shutting down worker consumers")
		worker.Stop()

		fmt.Println("Closing Redis connections")
		redisDB.Close()
	})

	graceful.AddSignal(syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	err = graceful.ListenAndServe(config.ListenOnAddr, w)
	if err != nil {
		log.Fatal(err)
	}
	graceful.Wait()
}

// func ExampleMiddleware(h http.Handler) http.Handler {
// 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 		log.Println("Request yooooooo")
// 		h.ServeHTTP(w, r)
// 	})
// }
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/najeira/ltsv"

	"golang.org/x/crypto/ssh/terminal"
)

func main() {
	if terminal.IsTerminal(1) {
		args := os.Args

		reader := ltsv.NewReader(os.Stdin)
		records, err := reader.ReadAll()

		if err != nil {
			panic(err)
		}

		var result float64

		switch args[1] {
		case "sum":
			result = sum(args[2], records)

		case "ave":
			result = ave(args[2], records)
		}

		fmt.Println(result)
	}
}

func sum(key string, ltsv []map[string]string) float64 {
	result := 0.0
	for _, record := range ltsv {
		for k, v := range record {
			if k == key {
				f64, _ := strconv.ParseFloat(v, 64)
				result += f64
			}
		}
	}

	return result
}

func ave(key string, ltsv []map[string]string) float64 {
	return sum(key, ltsv) / float64(len(ltsv))
}
<commit_msg>not accept interactive input<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"
	"syscall"

	"github.com/najeira/ltsv"

	"golang.org/x/crypto/ssh/terminal"
)

func main() {
	if terminal.IsTerminal(syscall.Stdin) {
		fmt.Println("Usage: cat hoge.ltsv | hakari (sum|ave) ${tareget_key}")
	} else {
		args := os.Args

		reader := ltsv.NewReader(os.Stdin)
		records, err := reader.ReadAll()

		if err != nil {
			panic(err)
		}

		var result float64

		switch args[1] {
		case "sum":
			result = sum(args[2], records)

		case "ave":
			result = ave(args[2], records)
		}

		fmt.Println(result)
	}
}

func sum(key string, ltsv []map[string]string) float64 {
	result := 0.0
	for _, record := range ltsv {
		for k, v := range record {
			if k == key {
				f64, _ := strconv.ParseFloat(v, 64)
				result += f64
			}
		}
	}

	return result
}

func ave(key string, ltsv []map[string]string) float64 {
	return sum(key, ltsv) / float64(len(ltsv))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	ui "github.com/gizak/termui"
	"github.com/samalba/dockerclient"
)

var (
	dockersocket          = flag.String("docker", "unix:///var/run/docker.sock", "the socket of the docker daemon")
	allcontainers         []dockerclient.Container
	containerDetailsIndex = 0
	containerDetailsId    = ""
	statsData             = make(map[string][]*dockerclient.Stats)
	columns               = 0
	lock                  sync.Mutex
)

type DockerDrawer func(*dockerclient.DockerClient)

func dockerStats(id string, stats *dockerclient.Stats, errs chan error, data ...interface{}) {
	lock.Lock()
	defer lock.Unlock()
	dat, _ := statsData[id]
	if len(dat) > (columns - 2) {
		dat = dat[1:]
	}
	if len(dat) > 0 && dat[len(dat)-1].Read == stats.Read {
		// same stat twice, ignore
		return
	}
	dat = append(dat, stats)
	statsData[id] = dat
}

func ContainerList() (DockerDrawer, ui.GridBufferer) {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorYellow
	list.Border.Label = "Containers"
	return func(dc *dockerclient.DockerClient) {
		containers, err := dc.ListContainers(false, false, "")
		if err != nil {
			containerDetailsId = ""
			dc.StopAllMonitorStats()
			//log.Printf(err.Error())
		} else {
			var conts []string
			newstats := make(map[string][]*dockerclient.Stats)
			for i, c := range containers {
				conts = append(conts, genContainerListName(i, c, 30))
				if i == containerDetailsIndex {
					containerDetailsId = c.Id
				}
				stat, ok := statsData[c.Id]
				if ok {
					newstats[c.Id] = stat
				} else {
					errs := make(chan error)
					dc.StartMonitorStats(c.Id, dockerStats, errs, &c)
				}
			}
			lock.Lock()
			defer lock.Unlock()
			statsData = newstats
			allcontainers = containers
			if len(allcontainers) == 0 {
				dc.StopAllMonitorStats()
				containerDetailsId = ""
			}
			list.Items = conts
			list.Height = len(conts) + 2
		}
	}, list
}

func genContainerListName(idx int, c dockerclient.Container, maxlen int) string {
	s := fmt.Sprintf("[%d] %s:%s", idx, c.Names[0], c.Id)
	if len(s) > maxlen {
		return s[:maxlen-3] + "..."
	}
	return s
}

func ContainerDetails() (DockerDrawer, ui.GridBufferer) {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorYellow
	list.Border.Label = "Details"
	return func(dc *dockerclient.DockerClient) {
		if containerDetailsId == "" {
			list.Height = 2
			return
		}
		ci, err := dc.InspectContainer(containerDetailsId)
		if err != nil {
			//log.Printf(err.Error())
		} else {
			var lines []string
			lines = append(lines, fmt.Sprintf("Name: %s", ci.Name))
			lines = append(lines, fmt.Sprintf("Image: %s", ci.Image))
			lines = append(lines, fmt.Sprintf("Path: %s", ci.Path))
			lines = append(lines, fmt.Sprintf("Args: %s", ci.Args))
			lines = append(lines, fmt.Sprintf("IP: %s", ci.NetworkSettings.IPAddress))
			lines = append(lines, fmt.Sprintf("Ports: %s", genPortMappings(ci)))
			for vi, v := range genVolumes(ci) {
				if vi == 0 {
					lines = append(lines, fmt.Sprintf("Volumes: %s", v))
				} else {
					lines = append(lines, fmt.Sprintf("         %s", v))
				}
			}
			lines = append(lines, fmt.Sprintf("Hostname: %s", ci.Config.Hostname))
			lines = append(lines, fmt.Sprintf("Memory: %d", ci.Config.Memory))
			lines = append(lines, fmt.Sprintf("Swap: %d", ci.Config.MemorySwap))
			lines = append(lines, fmt.Sprintf("Cpu-Shares: %d", ci.Config.CpuShares))
			lines = append(lines, fmt.Sprintf("Cpu-Set: %s", ci.Config.Cpuset))
			lines = append(lines, fmt.Sprintf("Env: %s", ci.Config.Env))
			list.Items = lines
			list.Height = len(lines) + 2
			list.Border.Label = fmt.Sprintf("Details: %s", ci.Name)
		}
	}, list
}

func genPortMappings(di *dockerclient.ContainerInfo) string {
	var res []string
	var keys []string
	for p, _ := range di.NetworkSettings.Ports {
		keys = append(keys, p)
	}
	sort.Strings(keys)
	for _, k := range keys {
		pc := di.NetworkSettings.Ports[k]
		res = append(res, fmt.Sprintf("%s -> %s ", k, pc))
	}

	return strings.Join(res, ",")
}

func genVolumes(di *dockerclient.ContainerInfo) []string {
	var res []string
	var keys []string
	for v, _ := range di.Volumes {
		keys = append(keys, v)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := di.Volumes[k]
		res = append(res, fmt.Sprintf("%s -> %s ", k, v))
	}
	return res
}

func ContainerCpu() (DockerDrawer, ui.GridBufferer) {
	cpus := ui.NewSparklines()
	cpus.Border.Label = "CPU"
	return func(dc *dockerclient.DockerClient) {
		cpus.Lines = []ui.Sparkline{}
		cpus.Height = 2
		for _, c := range allcontainers {
			dat, _ := statsData[c.Id]
			lastVal := 0
			if len(dat) > 1 {
				lastVal = cpuPercent(dat, len(dat)-1)
			}
			l := ui.NewSparkline()
			l.Title = fmt.Sprintf("[%d %%] %s:%s ", lastVal, c.Names, c.Id)
			l.LineColor = ui.ColorRed
			l.Data = genCPUSystemUsage(dat)
			cpus.Lines = append(cpus.Lines, l)
			cpus.Height = cpus.Height + 2
		}

	}, cpus
}

func ContainerMemory() (DockerDrawer, ui.GridBufferer) {
	mem := ui.NewMBarChart()
	mem.Border.Label = "Memory usage (red=used, green=free)"
	mem.Height = 23
	mem.BarWidth = 5
	mem.BarColor[0] = ui.ColorRed
	mem.BarColor[1] = ui.ColorGreen
	return func(dc *dockerclient.DockerClient) {
		var labels []string
		var used []int
		var free []int
		for i, c := range allcontainers {
			labels = append(labels, fmt.Sprintf("[%d]", i))
			dat, _ := statsData[c.Id]
			if len(dat) > 1 {
				last := dat[len(dat)-1]
				memused := last.MemoryStats.Usage
				memlim := last.MemoryStats.Limit
				memusedP := int(100 * memused / memlim)
				used = append(used, memusedP)
				free = append(free, 100-memusedP)
			}
		}
		mem.DataLabels = labels
		mem.Data[0] = used
		mem.Data[1] = free
	}, mem
}

func genCPUSystemUsage(stats []*dockerclient.Stats) []int {
	var res []int
	for i, _ := range stats {
		if i > 0 {
			res = append(res, cpuPercent(stats, i))
		}
	}
	return res
}

func cpuPercent(stats []*dockerclient.Stats, idx int) int {
	var (
		p        = 0.0
		mystat   = stats[idx]
		prevstat = stats[idx-1]
		cpudelta = float64(mystat.CpuStats.CpuUsage.TotalUsage - prevstat.CpuStats.CpuUsage.TotalUsage)
		sysdelta = float64(mystat.CpuStats.SystemUsage - prevstat.CpuStats.SystemUsage)
	)

	if sysdelta > 0.0 && cpudelta > 0.0 {
		p = (cpudelta / sysdelta) * float64(len(mystat.CpuStats.CpuUsage.PercpuUsage)) * 100.0
	}
	return int(p)
}

func main() {
	flag.Parse()

	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer ui.Close()

	// Init the client
	docker, err := dockerclient.NewDockerClient(*dockersocket, nil)
	if err != nil {
		panic(err)
	}

	var drawers []DockerDrawer
	containerlist, uiCntList := ContainerList()
	containerDetails, uiCntDets := ContainerDetails()
	cpuList, uiCpus := ContainerCpu()
	memUsg, uiMem := ContainerMemory()

	drawers = append(drawers, containerlist, containerDetails, cpuList, memUsg)

	title := ui.NewPar("dockmon (press 'q' to quit)")
	title.Height = 3
	title.HasBorder = true

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(12, 0, title)),
		ui.NewRow(
			ui.NewCol(4, 0, uiCntList),
			ui.NewCol(8, 0, uiCntDets)),
		ui.NewRow(
			ui.NewCol(12, 0, uiCpus)),
		ui.NewRow(
			ui.NewCol(6, 0, uiMem)))

	// calculate layout
	ui.Body.Align()
	columns = ui.Body.Width

	evt := ui.EventCh()

	for {
		select {
		case e := <-evt:
			if e.Type == ui.EventKey && e.Ch == 'q' {
				return
			}
			if e.Type == ui.EventKey && e.Ch >= '0' && e.Ch <= '9' {
				containerDetailsIndex = int(e.Ch - '0')
			}
			if e.Type == ui.EventResize {
				ui.Body.Width = ui.TermWidth()
				ui.Body.Align()
			}
		default:
			for _, d := range drawers {
				d(docker)
			}
			ui.Body.Align()
			columns = ui.Body.Width
			ui.Render(ui.Body)
			time.Sleep(time.Second / 2)
		}
	}
}
<commit_msg>remove old comments<commit_after>package main

import (
	"flag"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	ui "github.com/gizak/termui"
	"github.com/samalba/dockerclient"
)

var (
	dockersocket          = flag.String("docker", "unix:///var/run/docker.sock", "the socket of the docker daemon")
	allcontainers         []dockerclient.Container
	containerDetailsIndex = 0
	containerDetailsId    = ""
	statsData             = make(map[string][]*dockerclient.Stats)
	columns               = 0
	lock                  sync.Mutex
)

type DockerDrawer func(*dockerclient.DockerClient)

func dockerStats(id string, stats *dockerclient.Stats, errs chan error, data ...interface{}) {
	lock.Lock()
	defer lock.Unlock()
	dat, _ := statsData[id]
	if len(dat) > (columns - 2) {
		dat = dat[1:]
	}
	if len(dat) > 0 && dat[len(dat)-1].Read == stats.Read {
		// same stat twice, ignore
		return
	}
	dat = append(dat, stats)
	statsData[id] = dat
}

func ContainerList() (DockerDrawer, ui.GridBufferer) {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorYellow
	list.Border.Label = "Containers"
	return func(dc *dockerclient.DockerClient) {
		containers, err := dc.ListContainers(false, false, "")
		if err != nil {
			containerDetailsId = ""
			dc.StopAllMonitorStats()
		} else {
			var conts []string
			newstats := make(map[string][]*dockerclient.Stats)
			for i, c := range containers {
				conts = append(conts, genContainerListName(i, c, 30))
				if i == containerDetailsIndex {
					containerDetailsId = c.Id
				}
				stat, ok := statsData[c.Id]
				if ok {
					newstats[c.Id] = stat
				} else {
					errs := make(chan error)
					dc.StartMonitorStats(c.Id, dockerStats, errs, &c)
				}
			}
			lock.Lock()
			defer lock.Unlock()
			statsData = newstats
			allcontainers = containers
			if len(allcontainers) == 0 {
				dc.StopAllMonitorStats()
				containerDetailsId = ""
			}
			list.Items = conts
			list.Height = len(conts) + 2
		}
	}, list
}

func genContainerListName(idx int, c dockerclient.Container, maxlen int) string {
	s := fmt.Sprintf("[%d] %s:%s", idx, c.Names[0], c.Id)
	if len(s) > maxlen {
		return s[:maxlen-3] + "..."
	}
	return s
}

func ContainerDetails() (DockerDrawer, ui.GridBufferer) {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorYellow
	list.Border.Label = "Details"
	return func(dc *dockerclient.DockerClient) {
		if containerDetailsId == "" {
			list.Height = 2
			return
		}
		ci, err := dc.InspectContainer(containerDetailsId)
		if err != nil {
			// don't log !
		} else {
			var lines []string
			lines = append(lines, fmt.Sprintf("Name: %s", ci.Name))
			lines = append(lines, fmt.Sprintf("Image: %s", ci.Image))
			lines = append(lines, fmt.Sprintf("Path: %s", ci.Path))
			lines = append(lines, fmt.Sprintf("Args: %s", ci.Args))
			lines = append(lines, fmt.Sprintf("IP: %s", ci.NetworkSettings.IPAddress))
			lines = append(lines, fmt.Sprintf("Ports: %s", genPortMappings(ci)))
			for vi, v := range genVolumes(ci) {
				if vi == 0 {
					lines = append(lines, fmt.Sprintf("Volumes: %s", v))
				} else {
					lines = append(lines, fmt.Sprintf("         %s", v))
				}
			}
			lines = append(lines, fmt.Sprintf("Hostname: %s", ci.Config.Hostname))
			lines = append(lines, fmt.Sprintf("Memory: %d", ci.Config.Memory))
			lines = append(lines, fmt.Sprintf("Swap: %d", ci.Config.MemorySwap))
			lines = append(lines, fmt.Sprintf("Cpu-Shares: %d", ci.Config.CpuShares))
			lines = append(lines, fmt.Sprintf("Cpu-Set: %s", ci.Config.Cpuset))
			lines = append(lines, fmt.Sprintf("Env: %s", ci.Config.Env))
			list.Items = lines
			list.Height = len(lines) + 2
			list.Border.Label = fmt.Sprintf("Details: %s", ci.Name)
		}
	}, list
}

func genPortMappings(di *dockerclient.ContainerInfo) string {
	var res []string
	var keys []string
	for p, _ := range di.NetworkSettings.Ports {
		keys = append(keys, p)
	}
	sort.Strings(keys)
	for _, k := range keys {
		pc := di.NetworkSettings.Ports[k]
		res = append(res, fmt.Sprintf("%s -> %s ", k, pc))
	}

	return strings.Join(res, ",")
}

func genVolumes(di *dockerclient.ContainerInfo) []string {
	var res []string
	var keys []string
	for v, _ := range di.Volumes {
		keys = append(keys, v)
	}
	sort.Strings(keys)
	for _, k := range keys {
		v := di.Volumes[k]
		res = append(res, fmt.Sprintf("%s -> %s ", k, v))
	}
	return res
}

func ContainerCpu() (DockerDrawer, ui.GridBufferer) {
	cpus := ui.NewSparklines()
	cpus.Border.Label = "CPU"
	return func(dc *dockerclient.DockerClient) {
		cpus.Lines = []ui.Sparkline{}
		cpus.Height = 2
		for _, c := range allcontainers {
			dat, _ := statsData[c.Id]
			lastVal := 0
			if len(dat) > 1 {
				lastVal = cpuPercent(dat, len(dat)-1)
			}
			l := ui.NewSparkline()
			l.Title = fmt.Sprintf("[%d %%] %s:%s ", lastVal, c.Names, c.Id)
			l.LineColor = ui.ColorRed
			l.Data = genCPUSystemUsage(dat)
			cpus.Lines = append(cpus.Lines, l)
			cpus.Height = cpus.Height + 2
		}

	}, cpus
}

func ContainerMemory() (DockerDrawer, ui.GridBufferer) {
	mem := ui.NewMBarChart()
	mem.Border.Label = "Memory usage (red=used, green=free)"
	mem.Height = 23
	mem.BarWidth = 5
	mem.BarColor[0] = ui.ColorRed
	mem.BarColor[1] = ui.ColorGreen
	return func(dc *dockerclient.DockerClient) {
		var labels []string
		var used []int
		var free []int
		for i, c := range allcontainers {
			labels = append(labels, fmt.Sprintf("[%d]", i))
			dat, _ := statsData[c.Id]
			if len(dat) > 1 {
				last := dat[len(dat)-1]
				memused := last.MemoryStats.Usage
				memlim := last.MemoryStats.Limit
				memusedP := int(100 * memused / memlim)
				used = append(used, memusedP)
				free = append(free, 100-memusedP)
			}
		}
		mem.DataLabels = labels
		mem.Data[0] = used
		mem.Data[1] = free
	}, mem
}

func genCPUSystemUsage(stats []*dockerclient.Stats) []int {
	var res []int
	for i, _ := range stats {
		if i > 0 {
			res = append(res, cpuPercent(stats, i))
		}
	}
	return res
}

func cpuPercent(stats []*dockerclient.Stats, idx int) int {
	var (
		p        = 0.0
		mystat   = stats[idx]
		prevstat = stats[idx-1]
		cpudelta = float64(mystat.CpuStats.CpuUsage.TotalUsage - prevstat.CpuStats.CpuUsage.TotalUsage)
		sysdelta = float64(mystat.CpuStats.SystemUsage - prevstat.CpuStats.SystemUsage)
	)

	if sysdelta > 0.0 && cpudelta > 0.0 {
		p = (cpudelta / sysdelta) * float64(len(mystat.CpuStats.CpuUsage.PercpuUsage)) * 100.0
	}
	return int(p)
}

func main() {
	flag.Parse()

	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer ui.Close()

	// Init the client
	docker, err := dockerclient.NewDockerClient(*dockersocket, nil)
	if err != nil {
		panic(err)
	}

	var drawers []DockerDrawer
	containerlist, uiCntList := ContainerList()
	containerDetails, uiCntDets := ContainerDetails()
	cpuList, uiCpus := ContainerCpu()
	memUsg, uiMem := ContainerMemory()

	drawers = append(drawers, containerlist, containerDetails, cpuList, memUsg)

	title := ui.NewPar("dockmon (press 'q' to quit)")
	title.Height = 3
	title.HasBorder = true

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(12, 0, title)),
		ui.NewRow(
			ui.NewCol(4, 0, uiCntList),
			ui.NewCol(8, 0, uiCntDets)),
		ui.NewRow(
			ui.NewCol(12, 0, uiCpus)),
		ui.NewRow(
			ui.NewCol(6, 0, uiMem)))

	// calculate layout
	ui.Body.Align()
	columns = ui.Body.Width

	evt := ui.EventCh()

	for {
		select {
		case e := <-evt:
			if e.Type == ui.EventKey && e.Ch == 'q' {
				return
			}
			if e.Type == ui.EventKey && e.Ch >= '0' && e.Ch <= '9' {
				containerDetailsIndex = int(e.Ch - '0')
			}
			if e.Type == ui.EventResize {
				ui.Body.Width = ui.TermWidth()
				ui.Body.Align()
			}
		default:
			for _, d := range drawers {
				d(docker)
			}
			ui.Body.Align()
			columns = ui.Body.Width
			ui.Render(ui.Body)
			time.Sleep(time.Second / 2)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/joho/godotenv"
	"github.com/urfave/cli"
)

var build = "0" // build number set at compile-time

func main() {
	app := cli.NewApp()
	app.Name = "helm plugin"
	app.Usage = "helm plugin"
	app.Action = run
	app.Version = fmt.Sprintf("1.0.%s", build)
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "helm_command",
			Usage:  "add the command Helm has to execute",
			EnvVar: "PLUGIN_HELM_COMMAND,HELM_COMMAND",
		},
		cli.StringFlag{
			Name:   "kube-config",
			Usage:  "Kubernetes configuration file path",
			EnvVar: "PLUGIN_KUBE_CONFIG,KUBE_CONFIG",
			Value:  "/root/.kube/config",
		},
		cli.StringFlag{
			Name:   "namespace",
			Usage:  "Kubernetes namespace",
			EnvVar: "PLUGIN_NAMESPACE,NAMESPACE",
		},
		cli.StringFlag{
			Name:   "release",
			Usage:  "Kubernetes helm release",
			EnvVar: "PLUGIN_RELEASE,RELEASE",
		},
		cli.StringSliceFlag{
			Name:   "helm_repos",
			Usage:  "Repos helm should add",
			EnvVar: "PLUGIN_HELM_REPOS,HELM_REPOS",
		},
		cli.StringFlag{
			Name:   "chart",
			Usage:  "Kubernetes helm chart name",
			EnvVar: "PLUGIN_CHART,CHART",
		},
		cli.StringFlag{
			Name:   "chart-version",
			Usage:  "specify the exact chart version to use. If this is not specified, the latest version is used",
			EnvVar: "PLUGIN_CHART_VERSION,CHART_VERSION",
		},
		cli.StringFlag{
			Name:   "values",
			Usage:  "Kubernetes helm release",
			EnvVar: "PLUGIN_VALUES,VALUES",
		},
		cli.StringFlag{
			Name:   "values_files",
			Usage:  "Helm values override files",
			EnvVar: "PLUGIN_VALUES_FILES,VALUES_FILES",
		},
		cli.BoolFlag{
			Name:   "skip_tls_verify",
			Usage:  "Skip TLS verification",
			EnvVar: "PLUGIN_SKIP_TLS_VERIFY,SKIP_TLS_VERIFY",
		},
		cli.BoolFlag{
			Name:   "debug",
			Usage:  "Debug",
			EnvVar: "PLUGIN_DEBUG,DEBUG",
		},
		cli.BoolFlag{
			Name:   "dry-run",
			Usage:  "Helm dry-run",
			EnvVar: "PLUGIN_DRY_RUN,DRY_RUN",
		},
		cli.StringFlag{
			Name:   "prefix",
			Usage:  "Prefix for all the secrets",
			EnvVar: "PLUGIN_PREFIX,PREFIX",
		},
		cli.StringFlag{
			Name:   "tiller-ns",
			Usage:  "Namespace to install Tiller",
			EnvVar: "PLUGIN_TILLER_NS,TILLER_NS",
		},
		cli.BoolFlag{
			Name:   "wait",
			Usage:  "if set, will wait until all Pods, PVCs, and Services are in a ready state before marking the release as successful.",
			EnvVar: "PLUGIN_WAIT,WAIT",
		},
		cli.BoolFlag{
			Name:   "recreate-pods",
			Usage:  "performs pods restart for the resource if applicable",
			EnvVar: "PLUGIN_RECREATE_PODS,RECREATE_PODS",
		},
		cli.BoolFlag{
			Name:   "upgrade",
			Usage:  "if set, will upgrade tiller to the latest version",
			EnvVar: "PLUGIN_UPGRADE,UPGRADE",
		},
		cli.BoolFlag{
			Name:   "canary-image",
			Usage:  "if set, Helm will use the canary tiller image",
			EnvVar: "PLUGIN_CANARY_IMAGE,CANARY_IMAGE",
		},
		cli.BoolFlag{
			Name:   "client-only",
			Usage:  "if set, it will initilises helm in the client side only",
			EnvVar: "PLUGIN_CLIENT_ONLY,CLIENT_ONLY",
		},
		cli.BoolFlag{
			Name:   "reuse-values",
			Usage:  "when upgrading, reuse the last release's values, and merge in any new values",
			EnvVar: "PLUGIN_REUSE_VALUES,REUSE_VALUES",
		},
		cli.StringFlag{
			Name:   "timeout",
			Usage:  "time in seconds to wait for any individual kubernetes operation (like Jobs for hooks) (default 300)",
			EnvVar: "PLUGIN_TIMEOUT,TIMEOUT",
		},
		cli.BoolFlag{
			Name:   "force",
			Usage:  "force resource update through delete/recreate if needed",
			EnvVar: "PLUGIN_FORCE,FORCE",
		},
		cli.BoolFlag{
			Name:   "purge",
			Usage:  "purge on delete",
			EnvVar: "PLUGIN_PURGE,PURGE",
		},
		cli.BoolFlag{
			Name:   "update-dependencies",
			Usage:  "update dependency charts based on the contents of requirements.yaml file of the local chart",
			EnvVar: "PLUGIN_UPDATE_DEPENDENCIES,UPDATE_DEPENDENCIES",
		},
	}
	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}
	plugin := Plugin{
		Config: Config{
			APIServer:      	c.String("api_server"),
			Token:          	c.String("token"),
			Certificate:    	c.String("certificate"),
			ServiceAccount: 	c.String("service-account"),
			KubeConfig:     	c.String("kube-config"),
			HelmCommand:    	c.String("helm_command"),
			Namespace:      	c.String("namespace"),
			SkipTLSVerify:  	c.Bool("skip_tls_verify"),
			Values:         	c.String("values"),
			ValuesFiles:    	c.String("values_files"),
			Release:        	c.String("release"),
			HelmRepos:      	c.StringSlice("helm_repos"),
			Chart:          	c.String("chart"),
			Version:        	c.String("chart-version"),
			Debug:          	c.Bool("debug"),
			DryRun:         	c.Bool("dry-run"),
			Secrets:        	c.StringSlice("secrets"),
			Prefix:        		c.String("prefix"),
			TillerNs:      		c.String("tiller-ns"),
			Wait:          		c.Bool("wait"),
			RecreatePods:   	c.Bool("recreate-pods"),
			ClientOnly:     	c.Bool("client-only"),
			CanaryImage:    	c.Bool("canary-image"),
			Upgrade:    	    c.Bool("upgrade"),
			ReuseValues:   		c.Bool("reuse-values"),
			Timeout:        	c.String("timeout"),
			Force:          	c.Bool("force"),
			UpdateDependencies:	c.Bool("update-dependencies"),
		},
	}
	return plugin.Exec()
}
<commit_msg>Fix indent<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/joho/godotenv"
	"github.com/urfave/cli"
)

var build = "0" // build number set at compile-time

func main() {
	app := cli.NewApp()
	app.Name = "helm plugin"
	app.Usage = "helm plugin"
	app.Action = run
	app.Version = fmt.Sprintf("1.0.%s", build)
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "helm_command",
			Usage:  "add the command Helm has to execute",
			EnvVar: "PLUGIN_HELM_COMMAND,HELM_COMMAND",
		},
		cli.StringFlag{
			Name:   "kube-config",
			Usage:  "Kubernetes configuration file path",
			EnvVar: "PLUGIN_KUBE_CONFIG,KUBE_CONFIG",
			Value:  "/root/.kube/config",
		},
		cli.StringFlag{
			Name:   "namespace",
			Usage:  "Kubernetes namespace",
			EnvVar: "PLUGIN_NAMESPACE,NAMESPACE",
		},
		cli.StringFlag{
			Name:   "release",
			Usage:  "Kubernetes helm release",
			EnvVar: "PLUGIN_RELEASE,RELEASE",
		},
		cli.StringSliceFlag{
			Name:   "helm_repos",
			Usage:  "Repos helm should add",
			EnvVar: "PLUGIN_HELM_REPOS,HELM_REPOS",
		},
		cli.StringFlag{
			Name:   "chart",
			Usage:  "Kubernetes helm chart name",
			EnvVar: "PLUGIN_CHART,CHART",
		},
		cli.StringFlag{
			Name:   "chart-version",
			Usage:  "specify the exact chart version to use. If this is not specified, the latest version is used",
			EnvVar: "PLUGIN_CHART_VERSION,CHART_VERSION",
		},
		cli.StringFlag{
			Name:   "values",
			Usage:  "Kubernetes helm release",
			EnvVar: "PLUGIN_VALUES,VALUES",
		},
		cli.StringFlag{
			Name:   "values_files",
			Usage:  "Helm values override files",
			EnvVar: "PLUGIN_VALUES_FILES,VALUES_FILES",
		},
		cli.BoolFlag{
			Name:   "skip_tls_verify",
			Usage:  "Skip TLS verification",
			EnvVar: "PLUGIN_SKIP_TLS_VERIFY,SKIP_TLS_VERIFY",
		},
		cli.BoolFlag{
			Name:   "debug",
			Usage:  "Debug",
			EnvVar: "PLUGIN_DEBUG,DEBUG",
		},
		cli.BoolFlag{
			Name:   "dry-run",
			Usage:  "Helm dry-run",
			EnvVar: "PLUGIN_DRY_RUN,DRY_RUN",
		},
		cli.StringFlag{
			Name:   "prefix",
			Usage:  "Prefix for all the secrets",
			EnvVar: "PLUGIN_PREFIX,PREFIX",
		},
		cli.StringFlag{
			Name:   "tiller-ns",
			Usage:  "Namespace to install Tiller",
			EnvVar: "PLUGIN_TILLER_NS,TILLER_NS",
		},
		cli.BoolFlag{
			Name:   "wait",
			Usage:  "if set, will wait until all Pods, PVCs, and Services are in a ready state before marking the release as successful.",
			EnvVar: "PLUGIN_WAIT,WAIT",
		},
		cli.BoolFlag{
			Name:   "recreate-pods",
			Usage:  "performs pods restart for the resource if applicable",
			EnvVar: "PLUGIN_RECREATE_PODS,RECREATE_PODS",
		},
		cli.BoolFlag{
			Name:   "upgrade",
			Usage:  "if set, will upgrade tiller to the latest version",
			EnvVar: "PLUGIN_UPGRADE,UPGRADE",
		},
		cli.BoolFlag{
			Name:   "canary-image",
			Usage:  "if set, Helm will use the canary tiller image",
			EnvVar: "PLUGIN_CANARY_IMAGE,CANARY_IMAGE",
		},
		cli.BoolFlag{
			Name:   "client-only",
			Usage:  "if set, it will initilises helm in the client side only",
			EnvVar: "PLUGIN_CLIENT_ONLY,CLIENT_ONLY",
		},
		cli.BoolFlag{
			Name:   "reuse-values",
			Usage:  "when upgrading, reuse the last release's values, and merge in any new values",
			EnvVar: "PLUGIN_REUSE_VALUES,REUSE_VALUES",
		},
		cli.StringFlag{
			Name:   "timeout",
			Usage:  "time in seconds to wait for any individual kubernetes operation (like Jobs for hooks) (default 300)",
			EnvVar: "PLUGIN_TIMEOUT,TIMEOUT",
		},
		cli.BoolFlag{
			Name:   "force",
			Usage:  "force resource update through delete/recreate if needed",
			EnvVar: "PLUGIN_FORCE,FORCE",
		},
		cli.BoolFlag{
			Name:   "purge",
			Usage:  "purge on delete",
			EnvVar: "PLUGIN_PURGE,PURGE",
		},
		cli.BoolFlag{
			Name:   "update-dependencies",
			Usage:  "update dependency charts based on the contents of requirements.yaml file of the local chart",
			EnvVar: "PLUGIN_UPDATE_DEPENDENCIES,UPDATE_DEPENDENCIES",
		},
	}
	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}
	plugin := Plugin{
		Config: Config{
			APIServer:      	c.String("api_server"),
			Token:          	c.String("token"),
			Certificate:    	c.String("certificate"),
			ServiceAccount: 	c.String("service-account"),
			KubeConfig:     	c.String("kube-config"),
			HelmCommand:    	c.String("helm_command"),
			Namespace:      	c.String("namespace"),
			SkipTLSVerify:  	c.Bool("skip_tls_verify"),
			Values:         	c.String("values"),
			ValuesFiles:    	c.String("values_files"),
			Release:        	c.String("release"),
			HelmRepos:      	c.StringSlice("helm_repos"),
			Chart:          	c.String("chart"),
			Version:        	c.String("chart-version"),
			Debug:          	c.Bool("debug"),
			DryRun:         	c.Bool("dry-run"),
			Secrets:        	c.StringSlice("secrets"),
			Prefix:        		c.String("prefix"),
			TillerNs:      		c.String("tiller-ns"),
			Wait:          		c.Bool("wait"),
			RecreatePods:   	c.Bool("recreate-pods"),
			ClientOnly:     	c.Bool("client-only"),
			CanaryImage:    	c.Bool("canary-image"),
			Upgrade:			c.Bool("upgrade"),
			ReuseValues:   		c.Bool("reuse-values"),
			Timeout:        	c.String("timeout"),
			Force:          	c.Bool("force"),
			UpdateDependencies:	c.Bool("update-dependencies"),
		},
	}
	return plugin.Exec()
}
<|endoftext|>


<commit_before>package main

import (
	_ "expvar"
	"net/http"
	"os"

	"github.com/bmizerany/pat"
	"github.com/codegangsta/negroni"
	"github.com/meatballhat/negroni-logrus"
	"github.com/unrolled/render"
)

func main() {
	Run()
}

func Run() {
	m := pat.New()
	n := negroni.New(negroni.NewRecovery(), negroni.NewStatic(http.Dir("assets")))
	l := negronilogrus.NewMiddleware()
	o := render.New(render.Options{
		Layout: "layout",
	})

	n.Use(l)
	n.UseHandler(m)

	m.Get("/debug/vars", http.DefaultServeMux)

	m.Get("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		o.HTML(w, http.StatusOK, "index", "world")
	}))

	var addr string
	if len(os.Getenv("PORT")) > 0 {
		addr = ":" + os.Getenv("PORT")
	} else {
		addr = ":3000"
	}

	l.Logger.Infof("Listening on %s", addr)
	l.Logger.Fatal(http.ListenAndServe(addr, n))
}
<commit_msg>Use `r` for `*http.Request`<commit_after>package main

import (
	_ "expvar"
	"net/http"
	"os"

	"github.com/bmizerany/pat"
	"github.com/codegangsta/negroni"
	"github.com/meatballhat/negroni-logrus"
	"github.com/unrolled/render"
)

func main() {
	Run()
}

func Run() {
	m := pat.New()
	n := negroni.New(negroni.NewRecovery(), negroni.NewStatic(http.Dir("assets")))
	l := negronilogrus.NewMiddleware()
	o := render.New(render.Options{
		Layout: "layout",
	})

	n.Use(l)
	n.UseHandler(m)

	m.Get("/debug/vars", http.DefaultServeMux)

	m.Get("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		o.HTML(w, http.StatusOK, "index", "world")
	}))

	var addr string
	if len(os.Getenv("PORT")) > 0 {
		addr = ":" + os.Getenv("PORT")
	} else {
		addr = ":3000"
	}

	l.Logger.Infof("Listening on %s", addr)
	l.Logger.Fatal(http.ListenAndServe(addr, n))
}
<|endoftext|>


<commit_before>package main

import (
  "flag"
  "fmt"
  "log"
  "sync"
  "time"

  "github.com/hatstand/cc1101/config"
  "github.com/kidoman/embd"
  _ "github.com/kidoman/embd/host/rpi"
)

const (
  // Read/write flags.
  WRITE_SINGLE_BYTE = 0x00
  WRITE_BURST = 0x40
  READ_SINGLE_BYTE = 0x80
  READ_BURST = 0xc0

  BYTES_IN_RXFIFO = 0x7f
  RXFIFO = 0x3f
  TXFIFO = 0x3f
  OVERFLOW = 0x80

  CRC_OK = 0x80
  RSSI = 0
  LQI = 1
  RSSI_OFFSET = 74

  // Strobes
  SRES = 0x30  // Reset
  SRX = 0x34   // Set receive mode
  STX = 0x35   // Set transmit mode
  SIDLE = 0x36
  SFRX = 0x3a  // Flush RX FIFO buffer
  SFTX = 0x3b  // Flush TX FIFO buffer

  // Status Registers
  PARTNUM = 0xf0
  VERSION = 0xf1
  RXBYTES = 0x3b

  // Config Registers
  IOCFG2 = 0x00
  IOCFG1 = 0x01
  IOCFG0 = 0x02

  FIFOTHR = 0x03

  SYNC1 = 0x04
  SYNC0 = 0x05

  PKTLEN = 0x06
  PKTCTRL1 = 0x07
  PKTCTRL0 = 0x08

  ADDR = 0x09

  CHANNR = 0x0a
  FSCTRL1 = 0x0b
  FSCTRL0 = 0x0c

  FREQ2 = 0x0d
  FREQ1 = 0x0e
  FREQ0 = 0x0f

  MDMCFG4 = 0x10
  MDMCFG3 = 0x11
  MDMCFG2 = 0x12
  MDMCFG1 = 0x13
  MDMCFG0 = 0x14

  DEVIATN = 0x15

  MCSM2 = 0x16
  MCSM1 = 0x17
  MCSM0 = 0x18

  FOCCFG = 0x19
  BSCFG = 0x1a

  AGCCTRL2 = 0x1b
  AGCCTRL1 = 0x1c
  AGCCTRL0 = 0x1d

  WOREVT1 = 0x1e
  WOREVT0 = 0x1f
  WORCTRL = 0x20

  FREND1 = 0x21
  FREND0 = 0x22

  FSCAL3 = 0x23
  FSCAL2 = 0x24
  FSCAL1 = 0x25
  FSCAL0 = 0x26

  RCCTRL1 = 0x27
  RCCTRL0 = 0x28

  FSTEST = 0x29
  PTEST = 0x2a
  AGCTEST = 0x2b
  TEST2 = 0x2c
  TEST1 = 0x2d
  TEST0 = 0x2e
)

func convertRSSI(rssi int) int {
  if rssi >= 128 {
    return (rssi - 256) / 2 - RSSI_OFFSET
  } else {
    return rssi / 2 - RSSI_OFFSET
  }
}

type CC1101 struct {
  bus  embd.SPIBus
  gdo0 embd.DigitalPin
  gdo2 embd.DigitalPin
  lock sync.Mutex
}

func NewCC1101(packetCh chan<- []byte) CC1101 {
  err := embd.InitSPI()
  if err != nil {
    panic(err)
  }

  err = embd.InitGPIO()
  if err != nil {
    panic(err)
  }

  gdo0, err := embd.NewDigitalPin(24)
  if err != nil {
    panic(err)
  }
  gdo0.SetDirection(embd.In)

  gdo2, err := embd.NewDigitalPin(25)
  if err != nil {
    panic(err)
  }
  gdo2.SetDirection(embd.In)

  bus := embd.NewSPIBus(embd.SPIMode0, 0, 50000, 8, 0)

  cc1101 := CC1101{
    bus:  bus,
    gdo0: gdo0,
    gdo2: gdo2,
  }
  cc1101.Reset()
  cc1101.SelfTest()
  cc1101.Init()

  cc1101.SetIdle()
  cc1101.SetRx()

  log.Print("Waiting for packets...")
  gdo0.Watch(embd.EdgeRising, func(pin embd.DigitalPin) {
    defer cc1101.SetRx()
    defer cc1101.SetIdle()

    log.Print("Received something!")
    time.Sleep(time.Microsecond * 50)
    recv, err := cc1101.Receive()
    if err != nil {
      log.Println("Failed to receive: ", err)
    } else {
      packetCh <- recv
    }
  })

  return cc1101
}

func (c *CC1101) Close() {
  c.bus.Close()
  c.gdo0.Close()
  c.gdo2.Close()
  embd.CloseGPIO()
  embd.CloseSPI()
}

func (cc1101 *CC1101) Strobe(address byte) error {
  data := []byte{address, 0x00}
  return cc1101.bus.TransferAndReceiveData(data)
}

func (cc1101 *CC1101) ReadSingleByte(address byte) (byte, error) {
  data := []byte{address | READ_SINGLE_BYTE, 0x00}
  err := cc1101.bus.TransferAndReceiveData(data)
  if err != nil {
    return 0x00, err
  }
  return data[1], nil
}

func (c *CC1101) ReadBurst(address byte, num byte) ([]byte, error) {
  var buf []byte

  for i:=byte(0); i < num + 1; i++ {
    addr := (address + i * 8) | READ_BURST
    buf = append(buf, addr)
  }

  err := c.bus.TransferAndReceiveData(buf)
  if err != nil {
    return nil, err
  }
  return buf[1:], nil
}

func (cc1101 *CC1101) WriteSingleByte(address byte, in byte) error {
  data := []byte{address | WRITE_SINGLE_BYTE, in}
  return cc1101.bus.TransferAndReceiveData(data)
}

func (c *CC1101) WriteBurst(address byte, data []byte) error {
  var buf []byte
  buf = append(buf, address | WRITE_BURST)
  buf = append(buf, data...)
  err := c.bus.TransferAndReceiveData(buf)
  if err != nil {
    return err
  }
  return nil
}

func (cc1101 *CC1101) Reset() error {
  return cc1101.Strobe(SRES)
}

func (c *CC1101) Init() error {
  c.WriteSingleByte(FSCTRL1, config.FSCTRL1)
  c.WriteSingleByte(FSCTRL0, config.FSCTRL0)

  c.WriteSingleByte(FREQ2, config.FREQ2)
  c.WriteSingleByte(FREQ1, config.FREQ1)
  c.WriteSingleByte(FREQ0, config.FREQ0)

  c.WriteSingleByte(MDMCFG4, config.MDMCFG4)
  c.WriteSingleByte(MDMCFG3, config.MDMCFG3)
  c.WriteSingleByte(MDMCFG2, config.MDMCFG2)
  c.WriteSingleByte(MDMCFG1, config.MDMCFG1)
  c.WriteSingleByte(MDMCFG0, config.MDMCFG0)

  c.WriteSingleByte(CHANNR, config.CHANNR)
  c.WriteSingleByte(DEVIATN, config.DEVIATN)
  c.WriteSingleByte(FREND1, config.FREND1)
  c.WriteSingleByte(FREND0, config.FREND0)
  c.WriteSingleByte(MCSM0, config.MCSM0)
  c.WriteSingleByte(FOCCFG, config.FOCCFG)
  c.WriteSingleByte(BSCFG, config.BSCFG)

  c.WriteSingleByte(AGCCTRL2, config.AGCCTRL2)
  c.WriteSingleByte(AGCCTRL1, config.AGCCTRL1)
  c.WriteSingleByte(AGCCTRL0, config.AGCCTRL0)

  c.WriteSingleByte(FSCAL3, config.FSCAL3)
  c.WriteSingleByte(FSCAL2, config.FSCAL2)
  c.WriteSingleByte(FSCAL1, config.FSCAL1)
  c.WriteSingleByte(FSCAL0, config.FSCAL0)

  c.WriteSingleByte(FSTEST, config.FSTEST)
  c.WriteSingleByte(TEST2, config.TEST2)
  c.WriteSingleByte(TEST1, config.TEST1)
  c.WriteSingleByte(TEST0, config.TEST0)

  c.WriteSingleByte(IOCFG2, config.IOCFG2)
  c.WriteSingleByte(IOCFG1, config.IOCFG1)
  c.WriteSingleByte(IOCFG0, config.IOCFG0)

  // Two status bytes appended to payload: RSSI LQI and CRC OK.
  c.WriteSingleByte(PKTCTRL1, config.PKTCTRL1)
  // No address check, data whitening off, CRC enable, variable length packets.
  c.WriteSingleByte(PKTCTRL0, config.PKTCTRL0)

  c.WriteSingleByte(ADDR, config.ADDR)
  // Max packet length 61 bytes.
  c.WriteSingleByte(PKTLEN, config.PKTLEN)
  return nil
}

func (cc1101 *CC1101) SelfTest() error {
  version, err := cc1101.ReadSingleByte(VERSION)
  if err != nil {
    return err
  }
  log.Printf("Version: 0x%x", version)
  partnum, err := cc1101.ReadSingleByte(PARTNUM)
  if err != nil {
    return err
  }
  log.Printf("Partnum: 0x%x", partnum)

  if version != 0x14 || partnum != 0x00 {
    return fmt.Errorf("Self test failed.\nGot Version: 0x%x Partnum: 0x%x", version, partnum)
  }
  return nil
}

func (cc1101 *CC1101) SetCarrierFrequency(freq int) error {
  if (freq == 868) {
    err := cc1101.WriteSingleByte(FREQ2, 0x21)
    if err != nil {
      return err
    }
    err = cc1101.WriteSingleByte(FREQ1, 0x62)
    if err != nil {
      return err
    }
    err = cc1101.WriteSingleByte(FREQ0, 0x76)
    if err != nil {
      return err
    }
    return nil
  } else {
    return fmt.Errorf("Frequency %dMHz not supported.", freq)
  }
}

func (cc1101 *CC1101) SetRx() error {
  return cc1101.Strobe(SRX)
}

func (c *CC1101) SetTx() error {
  return c.Strobe(STX)
}

func (c *CC1101) SetIdle() error {
  return c.Strobe(SIDLE)
}

func (c *CC1101) FlushRx() {
  c.Strobe(SIDLE)
  time.Sleep(50 * time.Microsecond)
  c.Strobe(SFRX)
}

func (c *CC1101) Receive() ([]byte, error) {
  c.lock.Lock()
  defer c.lock.Unlock()

  rxbytes, err := c.ReadSingleByte(RXBYTES)
  if err != nil {
    return nil, err
  }
  log.Printf("RXBYTES: 0x%x\n", rxbytes)
  // Flush RX buffer.
  defer c.FlushRx()

  if rxbytes & OVERFLOW > 0 {
    return nil, fmt.Errorf("FIFO Overflow")
  }

  if rxbytes & BYTES_IN_RXFIFO > 0 {
    log.Printf("Bytes in buffer: %d", rxbytes & BYTES_IN_RXFIFO)
    numBytes, err := c.ReadSingleByte(RXFIFO)
    if err != nil {
      return nil, err
    }
    log.Printf("Receiving %d bytes", numBytes)
    var recv []byte
    if numBytes > 0 {
      recv, err = c.ReadBurst(RXFIFO, numBytes)
      if err != nil {
        return nil, err
      }
    }
    status, err := c.ReadBurst(RXFIFO, 2)
    if err != nil {
      return nil, err
    }

    log.Printf("Status RSSI:   %ddBm\n", convertRSSI(int(status[RSSI])))
    log.Printf("Status LQI:    %d\n", status[LQI] & 0x7f)
    log.Printf("Status CRC OK: %d\n", (status[LQI] & CRC_OK) >> 7)
    return recv, nil
  } else {
    return []byte{}, nil
  }
}

func (c *CC1101) Send(packet []byte) error {
  c.lock.Lock()
  defer c.lock.Unlock()

  defer c.SetRx()

  log.Printf("Sending packet: %v\n", packet)

  if len(packet) > 60 {
    return fmt.Errorf("Packet too long: %d", len(packet))
  }
  log.Printf("Writing packet length: %d\n", len(packet))
  err := c.WriteSingleByte(TXFIFO, byte(len(packet)))
  if err != nil {
    return err
  }
  log.Println("Writing packet to FIFO")
  err = c.WriteBurst(TXFIFO, packet)
  if err != nil {
    return err
  }

  log.Println("Enabling TX mode")
  c.SetTx()
  defer c.Strobe(SFTX)
  defer c.Strobe(SIDLE)

  log.Println("Waiting for sync to transmit")
  for {
    sync, err := c.gdo2.Read()
    if err != nil {
      return err
    }
    if sync > 0 {
      break
    }
  }

  log.Println("Waiting for end of packet")
  for {
    sync, err := c.gdo2.Read()
    if err != nil {
      return err
    }
    if sync == 0 {
      break
    }
  }
  return nil
}

func main() {
  flag.Parse()

  packetCh := make(chan []byte, 10)
  cc1101 := NewCC1101(packetCh)
  defer cc1101.Close()

  /*
  time.Sleep(5 * time.Second)
  cc1101.Send([]byte{0x57, 0x16, 0x0a, 0x2b, 0x7e, 0x60, 0x3b, 0x26, 0x14})
  cc1101.Send([]byte{0x57, 0x16, 0x0a, 0x2b, 0x7e, 0x60, 0x3b, 0x26, 0x14})
  cc1101.Send([]byte{0x57, 0x16, 0x0a, 0x2b, 0x7e, 0x60, 0x3b, 0x26, 0x14})
  */

  for {
    select{
      case p := <-packetCh:
        log.Printf("Received packet: %v\n", p)
    }
  }
}

<commit_msg>Re-enable sending<commit_after>package main

import (
  "flag"
  "fmt"
  "log"
  "sync"
  "time"

  "github.com/hatstand/cc1101/config"
  "github.com/kidoman/embd"
  _ "github.com/kidoman/embd/host/rpi"
)

const (
  // Read/write flags.
  WRITE_SINGLE_BYTE = 0x00
  WRITE_BURST = 0x40
  READ_SINGLE_BYTE = 0x80
  READ_BURST = 0xc0

  BYTES_IN_RXFIFO = 0x7f
  RXFIFO = 0x3f
  TXFIFO = 0x3f
  OVERFLOW = 0x80

  CRC_OK = 0x80
  RSSI = 0
  LQI = 1
  RSSI_OFFSET = 74

  // Strobes
  SRES = 0x30  // Reset
  SRX = 0x34   // Set receive mode
  STX = 0x35   // Set transmit mode
  SIDLE = 0x36
  SFRX = 0x3a  // Flush RX FIFO buffer
  SFTX = 0x3b  // Flush TX FIFO buffer

  // Status Registers
  PARTNUM = 0xf0
  VERSION = 0xf1
  RXBYTES = 0x3b

  // Config Registers
  IOCFG2 = 0x00
  IOCFG1 = 0x01
  IOCFG0 = 0x02

  FIFOTHR = 0x03

  SYNC1 = 0x04
  SYNC0 = 0x05

  PKTLEN = 0x06
  PKTCTRL1 = 0x07
  PKTCTRL0 = 0x08

  ADDR = 0x09

  CHANNR = 0x0a
  FSCTRL1 = 0x0b
  FSCTRL0 = 0x0c

  FREQ2 = 0x0d
  FREQ1 = 0x0e
  FREQ0 = 0x0f

  MDMCFG4 = 0x10
  MDMCFG3 = 0x11
  MDMCFG2 = 0x12
  MDMCFG1 = 0x13
  MDMCFG0 = 0x14

  DEVIATN = 0x15

  MCSM2 = 0x16
  MCSM1 = 0x17
  MCSM0 = 0x18

  FOCCFG = 0x19
  BSCFG = 0x1a

  AGCCTRL2 = 0x1b
  AGCCTRL1 = 0x1c
  AGCCTRL0 = 0x1d

  WOREVT1 = 0x1e
  WOREVT0 = 0x1f
  WORCTRL = 0x20

  FREND1 = 0x21
  FREND0 = 0x22

  FSCAL3 = 0x23
  FSCAL2 = 0x24
  FSCAL1 = 0x25
  FSCAL0 = 0x26

  RCCTRL1 = 0x27
  RCCTRL0 = 0x28

  FSTEST = 0x29
  PTEST = 0x2a
  AGCTEST = 0x2b
  TEST2 = 0x2c
  TEST1 = 0x2d
  TEST0 = 0x2e
)

func convertRSSI(rssi int) int {
  if rssi >= 128 {
    return (rssi - 256) / 2 - RSSI_OFFSET
  } else {
    return rssi / 2 - RSSI_OFFSET
  }
}

type CC1101 struct {
  bus  embd.SPIBus
  gdo0 embd.DigitalPin
  gdo2 embd.DigitalPin
  lock sync.Mutex
}

func NewCC1101(packetCh chan<- []byte) CC1101 {
  err := embd.InitSPI()
  if err != nil {
    panic(err)
  }

  err = embd.InitGPIO()
  if err != nil {
    panic(err)
  }

  gdo0, err := embd.NewDigitalPin(24)
  if err != nil {
    panic(err)
  }
  gdo0.SetDirection(embd.In)

  gdo2, err := embd.NewDigitalPin(25)
  if err != nil {
    panic(err)
  }
  gdo2.SetDirection(embd.In)

  bus := embd.NewSPIBus(embd.SPIMode0, 0, 50000, 8, 0)

  cc1101 := CC1101{
    bus:  bus,
    gdo0: gdo0,
    gdo2: gdo2,
  }
  cc1101.Reset()
  cc1101.SelfTest()
  cc1101.Init()

  cc1101.SetIdle()
  cc1101.SetRx()

  log.Print("Waiting for packets...")
  gdo0.Watch(embd.EdgeRising, func(pin embd.DigitalPin) {
    defer cc1101.SetRx()
    defer cc1101.SetIdle()

    log.Print("Received something!")
    time.Sleep(time.Microsecond * 50)
    recv, err := cc1101.Receive()
    if err != nil {
      log.Println("Failed to receive: ", err)
    } else {
      packetCh <- recv
    }
  })

  return cc1101
}

func (c *CC1101) Close() {
  c.bus.Close()
  c.gdo0.Close()
  c.gdo2.Close()
  embd.CloseGPIO()
  embd.CloseSPI()
}

func (cc1101 *CC1101) Strobe(address byte) error {
  data := []byte{address, 0x00}
  return cc1101.bus.TransferAndReceiveData(data)
}

func (cc1101 *CC1101) ReadSingleByte(address byte) (byte, error) {
  data := []byte{address | READ_SINGLE_BYTE, 0x00}
  err := cc1101.bus.TransferAndReceiveData(data)
  if err != nil {
    return 0x00, err
  }
  return data[1], nil
}

func (c *CC1101) ReadBurst(address byte, num byte) ([]byte, error) {
  var buf []byte

  for i:=byte(0); i < num + 1; i++ {
    addr := (address + i * 8) | READ_BURST
    buf = append(buf, addr)
  }

  err := c.bus.TransferAndReceiveData(buf)
  if err != nil {
    return nil, err
  }
  return buf[1:], nil
}

func (cc1101 *CC1101) WriteSingleByte(address byte, in byte) error {
  data := []byte{address | WRITE_SINGLE_BYTE, in}
  return cc1101.bus.TransferAndReceiveData(data)
}

func (c *CC1101) WriteBurst(address byte, data []byte) error {
  var buf []byte
  buf = append(buf, address | WRITE_BURST)
  buf = append(buf, data...)
  err := c.bus.TransferAndReceiveData(buf)
  if err != nil {
    return err
  }
  return nil
}

func (cc1101 *CC1101) Reset() error {
  return cc1101.Strobe(SRES)
}

func (c *CC1101) Init() error {
  c.WriteSingleByte(FSCTRL1, config.FSCTRL1)
  c.WriteSingleByte(FSCTRL0, config.FSCTRL0)

  c.WriteSingleByte(FREQ2, config.FREQ2)
  c.WriteSingleByte(FREQ1, config.FREQ1)
  c.WriteSingleByte(FREQ0, config.FREQ0)

  c.WriteSingleByte(MDMCFG4, config.MDMCFG4)
  c.WriteSingleByte(MDMCFG3, config.MDMCFG3)
  c.WriteSingleByte(MDMCFG2, config.MDMCFG2)
  c.WriteSingleByte(MDMCFG1, config.MDMCFG1)
  c.WriteSingleByte(MDMCFG0, config.MDMCFG0)

  c.WriteSingleByte(CHANNR, config.CHANNR)
  c.WriteSingleByte(DEVIATN, config.DEVIATN)
  c.WriteSingleByte(FREND1, config.FREND1)
  c.WriteSingleByte(FREND0, config.FREND0)
  c.WriteSingleByte(MCSM0, config.MCSM0)
  c.WriteSingleByte(FOCCFG, config.FOCCFG)
  c.WriteSingleByte(BSCFG, config.BSCFG)

  c.WriteSingleByte(AGCCTRL2, config.AGCCTRL2)
  c.WriteSingleByte(AGCCTRL1, config.AGCCTRL1)
  c.WriteSingleByte(AGCCTRL0, config.AGCCTRL0)

  c.WriteSingleByte(FSCAL3, config.FSCAL3)
  c.WriteSingleByte(FSCAL2, config.FSCAL2)
  c.WriteSingleByte(FSCAL1, config.FSCAL1)
  c.WriteSingleByte(FSCAL0, config.FSCAL0)

  c.WriteSingleByte(FSTEST, config.FSTEST)
  c.WriteSingleByte(TEST2, config.TEST2)
  c.WriteSingleByte(TEST1, config.TEST1)
  c.WriteSingleByte(TEST0, config.TEST0)

  c.WriteSingleByte(IOCFG2, config.IOCFG2)
  c.WriteSingleByte(IOCFG1, config.IOCFG1)
  c.WriteSingleByte(IOCFG0, config.IOCFG0)

  // Two status bytes appended to payload: RSSI LQI and CRC OK.
  c.WriteSingleByte(PKTCTRL1, config.PKTCTRL1)
  // No address check, data whitening off, CRC enable, variable length packets.
  c.WriteSingleByte(PKTCTRL0, config.PKTCTRL0)

  c.WriteSingleByte(ADDR, config.ADDR)
  // Max packet length 61 bytes.
  c.WriteSingleByte(PKTLEN, config.PKTLEN)
  return nil
}

func (cc1101 *CC1101) SelfTest() error {
  version, err := cc1101.ReadSingleByte(VERSION)
  if err != nil {
    return err
  }
  log.Printf("Version: 0x%x", version)
  partnum, err := cc1101.ReadSingleByte(PARTNUM)
  if err != nil {
    return err
  }
  log.Printf("Partnum: 0x%x", partnum)

  if version != 0x14 || partnum != 0x00 {
    return fmt.Errorf("Self test failed.\nGot Version: 0x%x Partnum: 0x%x", version, partnum)
  }
  return nil
}

func (cc1101 *CC1101) SetCarrierFrequency(freq int) error {
  if (freq == 868) {
    err := cc1101.WriteSingleByte(FREQ2, 0x21)
    if err != nil {
      return err
    }
    err = cc1101.WriteSingleByte(FREQ1, 0x62)
    if err != nil {
      return err
    }
    err = cc1101.WriteSingleByte(FREQ0, 0x76)
    if err != nil {
      return err
    }
    return nil
  } else {
    return fmt.Errorf("Frequency %dMHz not supported.", freq)
  }
}

func (cc1101 *CC1101) SetRx() error {
  return cc1101.Strobe(SRX)
}

func (c *CC1101) SetTx() error {
  return c.Strobe(STX)
}

func (c *CC1101) SetIdle() error {
  return c.Strobe(SIDLE)
}

func (c *CC1101) FlushRx() {
  c.Strobe(SIDLE)
  time.Sleep(50 * time.Microsecond)
  c.Strobe(SFRX)
}

func (c *CC1101) Receive() ([]byte, error) {
  c.lock.Lock()
  defer c.lock.Unlock()

  rxbytes, err := c.ReadSingleByte(RXBYTES)
  if err != nil {
    return nil, err
  }
  log.Printf("RXBYTES: 0x%x\n", rxbytes)
  // Flush RX buffer.
  defer c.FlushRx()

  if rxbytes & OVERFLOW > 0 {
    return nil, fmt.Errorf("FIFO Overflow")
  }

  if rxbytes & BYTES_IN_RXFIFO > 0 {
    log.Printf("Bytes in buffer: %d", rxbytes & BYTES_IN_RXFIFO)
    numBytes, err := c.ReadSingleByte(RXFIFO)
    if err != nil {
      return nil, err
    }
    log.Printf("Receiving %d bytes", numBytes)
    var recv []byte
    if numBytes > 0 {
      recv, err = c.ReadBurst(RXFIFO, numBytes)
      if err != nil {
        return nil, err
      }
    }
    status, err := c.ReadBurst(RXFIFO, 2)
    if err != nil {
      return nil, err
    }

    log.Printf("Status RSSI:   %ddBm\n", convertRSSI(int(status[RSSI])))
    log.Printf("Status LQI:    %d\n", status[LQI] & 0x7f)
    log.Printf("Status CRC OK: %d\n", (status[LQI] & CRC_OK) >> 7)
    return recv, nil
  } else {
    return []byte{}, nil
  }
}

func (c *CC1101) Send(packet []byte) error {
  c.lock.Lock()
  defer c.lock.Unlock()

  defer c.SetRx()

  log.Printf("Sending packet: %v\n", packet)

  if len(packet) > 60 {
    return fmt.Errorf("Packet too long: %d", len(packet))
  }
  log.Printf("Writing packet length: %d\n", len(packet))
  err := c.WriteSingleByte(TXFIFO, byte(len(packet)))
  if err != nil {
    return err
  }
  log.Println("Writing packet to FIFO")
  err = c.WriteBurst(TXFIFO, packet)
  if err != nil {
    return err
  }

  log.Println("Enabling TX mode")
  c.SetTx()
  defer c.Strobe(SFTX)
  defer c.Strobe(SIDLE)

  log.Println("Waiting for sync to transmit")
  for {
    sync, err := c.gdo2.Read()
    if err != nil {
      return err
    }
    if sync > 0 {
      break
    }
  }

  log.Println("Waiting for end of packet")
  for {
    sync, err := c.gdo2.Read()
    if err != nil {
      return err
    }
    if sync == 0 {
      break
    }
  }
  return nil
}

func main() {
  flag.Parse()

  packetCh := make(chan []byte, 10)
  cc1101 := NewCC1101(packetCh)
  defer cc1101.Close()

  time.Sleep(5 * time.Second)
  cc1101.Send([]byte{0x57, 0x16, 0x0a, 0x2b, 0x7e, 0x60, 0x3b, 0x26, 0x14})
  cc1101.Send([]byte{0x57, 0x16, 0x0a, 0x2b, 0x7e, 0x60, 0x3b, 0x26, 0x14})
  cc1101.Send([]byte{0x57, 0x16, 0x0a, 0x2b, 0x7e, 0x60, 0x3b, 0x26, 0x14})

  for {
    select{
      case p := <-packetCh:
        log.Printf("Received packet: %v\n", p)
    }
  }
}

<|endoftext|>