<commit_before>/*
 * The MIT License
 *
 * Copyright 2016 hutdev.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"flag"
	"io/ioutil"
	"log"
	"math"
	"math/big"
	"os"
	"path"
	"time"
)

const FILENAME_SEP = "."
const KEYFILE_SUFFIX = "key"
const CERTFILE_SUFFIX = "crt"
const DEFAULT_KEYSIZE = 2048
const DEFAULT_CA_AGE = 10
const DEFAULT_CERT_AGE = 3
const DEFAULT_OUTPATH = "."
const DEFAULT_CA_NAME = "ca"
const DEFAULT_CERT_NAME = "server"
const RESTRICTIVE_PERMISSIONS = 0600

var outpath string
var commonName string
var caCommonName string
var certname string
var caname string
var keysize int
var caValid int
var certValid int

func init() {
	const cnUsage = "Value for the common name (CN) field of the certificate"
	const cnFlag = "certcn"
	const caCnUsage = "Value for the common name (CN) field of the certificate authority (CA)"
	const caCnFlag = "cacn"

	flag.StringVar(&outpath, "out", DEFAULT_OUTPATH, "Output directory")
	flag.StringVar(&certname, "certname", DEFAULT_CERT_NAME, "Certificate filename (without suffix)")
	flag.StringVar(&caname, "caname", DEFAULT_CA_NAME, "CA filename (without suffix)")
	flag.IntVar(&keysize, "keysize", DEFAULT_KEYSIZE, "Size of the private keys in bits")
	flag.IntVar(&caValid, "cav", DEFAULT_CA_AGE, "Validity of the CA certificate in years")
	flag.IntVar(&certValid, "certv", DEFAULT_CERT_AGE, "Validity of the certificate in years")

	if hostname, err := os.Hostname(); err == nil {
		flag.StringVar(&commonName, cnFlag, hostname, cnUsage)
		flag.StringVar(&caCommonName, caCnFlag, hostname, caCnUsage)
	} else {
		flag.StringVar(&commonName, cnFlag, "dummy", cnUsage)
		flag.StringVar(&caCommonName, caCnFlag, "dummyCA", caCnUsage)
	}
	flag.Parse()
}

func GenerateKey(path string) (*rsa.PrivateKey, error) {
	if key, err := rsa.GenerateKey(rand.Reader, keysize); err == nil {
		return key, ioutil.WriteFile(path, x509.MarshalPKCS1PrivateKey(key), RESTRICTIVE_PERMISSIONS)
	} else {
		return nil, err
	}
}

func CreateCert(path string, cn string, signerKey *rsa.PrivateKey, ca *x509.Certificate, key *rsa.PublicKey) (*x509.Certificate, error) {
	var signeeKey *rsa.PublicKey
	var signer *x509.Certificate
	var certAge int
	isCa := ca == nil

	if isCa {
		signeeKey = &signerKey.PublicKey
		certAge = caValid
	} else {
		signeeKey = key
		certAge = certValid
	}

	if serial, serialErr := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)); serialErr == nil {
		template := x509.Certificate{
			Subject: pkix.Name{
				CommonName: cn,
			},
			SerialNumber: serial,
			NotBefore:    time.Now(),
		}
		template.NotAfter = template.NotBefore.AddDate(certAge, 0, 0)

		if isCa {
			signer = &template
			template.IsCA = true
			template.KeyUsage = x509.KeyUsageCertSign
		} else {
			signer = ca
			template.KeyUsage = x509.KeyUsageDataEncipherment
			template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
		}

		if cert, err := x509.CreateCertificate(rand.Reader, &template, signer, signeeKey, signerKey); err == nil {
			ioutil.WriteFile(path, cert, RESTRICTIVE_PERMISSIONS)
			return &template, nil
		} else {
			return nil, err
		}
	} else {
		return nil, serialErr
	}
}

func main() {
	caKeyfileName := caname + FILENAME_SEP + KEYFILE_SUFFIX
	caKeyPath := path.Join(outpath, caKeyfileName)
	caCertfileName := caname + FILENAME_SEP + CERTFILE_SUFFIX
	caCertPath := path.Join(outpath, caCertfileName)
	certKeyfileName := certname + FILENAME_SEP + KEYFILE_SUFFIX
	certKeyPath := path.Join(outpath, certKeyfileName)
	certfileName := certname + FILENAME_SEP + CERTFILE_SUFFIX
	certPath := path.Join(outpath, certfileName)
	var caKey, certKey *rsa.PrivateKey
	var caCert *x509.Certificate
	var err error

	//Create a private key for the CA
	if caKey, err = GenerateKey(caKeyPath); err == nil {
		log.Printf("Private key stored at %s.\n", caKeyPath)
	} else {
		log.Fatal(err)
	}

	//Create a private key for the certificate
	if certKey, err = GenerateKey(certKeyPath); err == nil {
		log.Printf("Private key stored at %s.\n", certKeyPath)
	} else {
		log.Fatal(err)
	}

	//Create a self-signed CA certificate
	if caCert, err = CreateCert(caCertPath, caCommonName, caKey, nil, nil); err == nil {
		log.Printf("CA certificate stored at %s.\n", caCertPath)
	} else {
		log.Fatal(err)
	}

	//Create a server certificate
	if _, err = CreateCert(certPath, commonName, caKey, caCert, &certKey.PublicKey); err == nil {
		log.Printf("Server certificate stored at %s.\n", certPath)
	} else {
		log.Fatal(err)
	}
}
<commit_msg>Allow usage of existing CA<commit_after>/*
 * The MIT License
 *
 * Copyright 2016 hutdev.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"flag"
	"io/ioutil"
	"log"
	"math"
	"math/big"
	"os"
	"path"
	"time"
)

const FILENAME_SEP = "."
const KEYFILE_SUFFIX = "key"
const CERTFILE_SUFFIX = "crt"
const DEFAULT_KEYSIZE = 2048
const DEFAULT_CA_AGE = 10
const DEFAULT_CERT_AGE = 3
const CURRENT_DIR = "."
const DEFAULT_CA_NAME = "ca"
const DEFAULT_CERT_NAME = "server"
const RESTRICTIVE_PERMISSIONS = 0600

var outpath string
var commonName string
var caCommonName string
var certname string
var caname string
var keysize int
var caValid int
var certValid int
var capath string

func init() {
	const cnUsage = "Value for the common name (CN) field of the certificate"
	const cnFlag = "certcn"
	const caCnUsage = "Value for the common name (CN) field of the certificate authority (CA)"
	const caCnFlag = "cacn"

	flag.StringVar(&outpath, "out", CURRENT_DIR, "Output directory")
	flag.StringVar(&certname, "certname", DEFAULT_CERT_NAME, "Certificate filename (without suffix)")
	flag.StringVar(&caname, "caname", DEFAULT_CA_NAME, "CA filename (without suffix)")
	flag.StringVar(&capath, "capath", CURRENT_DIR, "Path to location of an existing CA (private key and certificate)")
	flag.IntVar(&keysize, "keysize", DEFAULT_KEYSIZE, "Size of the private keys in bits")
	flag.IntVar(&caValid, "cav", DEFAULT_CA_AGE, "Validity of the CA certificate in years")
	flag.IntVar(&certValid, "certv", DEFAULT_CERT_AGE, "Validity of the certificate in years")

	if hostname, err := os.Hostname(); err == nil {
		flag.StringVar(&commonName, cnFlag, hostname, cnUsage)
		flag.StringVar(&caCommonName, caCnFlag, hostname, caCnUsage)
	} else {
		flag.StringVar(&commonName, cnFlag, "dummy", cnUsage)
		flag.StringVar(&caCommonName, caCnFlag, "dummyCA", caCnUsage)
	}
	flag.Parse()
}

func GenerateKey(path string) (*rsa.PrivateKey, error) {
	if key, err := rsa.GenerateKey(rand.Reader, keysize); err == nil {
		return key, ioutil.WriteFile(path, x509.MarshalPKCS1PrivateKey(key), RESTRICTIVE_PERMISSIONS)
	} else {
		return nil, err
	}
}

func CreateCert(path string, cn string, signerKey *rsa.PrivateKey, ca *x509.Certificate, key *rsa.PublicKey) (*x509.Certificate, error) {
	var signeeKey *rsa.PublicKey
	var signer *x509.Certificate
	var certAge int
	isCa := ca == nil

	if isCa {
		signeeKey = &signerKey.PublicKey
		certAge = caValid
	} else {
		signeeKey = key
		certAge = certValid
	}

	if serial, serialErr := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)); serialErr == nil {
		template := x509.Certificate{
			Subject: pkix.Name{
				CommonName: cn,
			},
			SerialNumber: serial,
			NotBefore:    time.Now(),
		}
		template.NotAfter = template.NotBefore.AddDate(certAge, 0, 0)

		if isCa {
			signer = &template
			template.IsCA = true
			template.KeyUsage = x509.KeyUsageCertSign
		} else {
			signer = ca
			template.KeyUsage = x509.KeyUsageDataEncipherment
			template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
		}

		if cert, err := x509.CreateCertificate(rand.Reader, &template, signer, signeeKey, signerKey); err == nil {
			ioutil.WriteFile(path, cert, RESTRICTIVE_PERMISSIONS)
			return &template, nil
		} else {
			return nil, err
		}
	} else {
		return nil, serialErr
	}
}

func readOrDie(path string) *[]byte {
	if b, err := ioutil.ReadFile(path); err == nil {
		return &b
	} else {
		log.Fatal(err)
		return nil
	}
}

func main() {
	var caKey, certKey *rsa.PrivateKey
	var caCert *x509.Certificate
	var err error

	caKeyfileName := caname + FILENAME_SEP + KEYFILE_SUFFIX
	caKeyPath := path.Join(outpath, caKeyfileName)
	caCertfileName := caname + FILENAME_SEP + CERTFILE_SUFFIX
	caCertPath := path.Join(outpath, caCertfileName)
	certKeyfileName := certname + FILENAME_SEP + KEYFILE_SUFFIX
	certKeyPath := path.Join(outpath, certKeyfileName)
	certfileName := certname + FILENAME_SEP + CERTFILE_SUFFIX
	certPath := path.Join(outpath, certfileName)

	if _, err = os.Stat(caKeyPath); err == nil {
		if _, err = os.Stat(caCertPath); err == nil {
			//Read CA private key from file
			if caKey, err = x509.ParsePKCS1PrivateKey(*readOrDie(caKeyPath)); err != nil {
				log.Fatal(err)
			}
			log.Printf("CA private key loaded from %s\n", caKeyPath)
			//Read CA cert from file
			if caCert, err = x509.ParseCertificate(*readOrDie(caCertPath)); err != nil {
				log.Fatal(err)
			}
			log.Printf("CA certificate loaded from %s\n", caCertPath)
		}
	}

	//Create a private key for the CA
	if caKey == nil {
		if caKey, err = GenerateKey(caKeyPath); err == nil {
			log.Printf("CA private key stored at %s.\n", caKeyPath)
		} else {
			log.Fatal(err)
		}
	}

	//Create a private key for the certificate
	if certKey, err = GenerateKey(certKeyPath); err == nil {
		log.Printf("Certificate private key stored at %s.\n", certKeyPath)
	} else {
		log.Fatal(err)
	}

	//Create a self-signed CA certificate
	if caCert == nil {
		if caCert, err = CreateCert(caCertPath, caCommonName, caKey, nil, nil); err == nil {
			log.Printf("CA certificate stored at %s.\n", caCertPath)
		} else {
			log.Fatal(err)
		}
	}

	//Create a server certificate
	if _, err = CreateCert(certPath, commonName, caKey, caCert, &certKey.PublicKey); err == nil {
		log.Printf("Server certificate stored at %s.\n", certPath)
	} else {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main
// Author: Robert B Frangioso

import (
	"path/filepath"
	"os"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"
	"os/exec"
	"bytes"
	"strconv"
	"strings"
)

type msg_type int

const (
	OUTPUT msg_type = 1 + iota
	ERROR
	CLOSE
)

type output_msg struct {
	mtype	msg_type
	buffer	bytes.Buffer
}

func find(root string, wg *sync.WaitGroup, flags []string, args []string, output chan output_msg) {

	defer wg.Done()
	var cmd_out, cmd_err bytes.Buffer
	var msg output_msg

	findstr := append(append(append([]string{}, flags... ), []string{root}... ), args... )
	cmd := exec.Command("find", findstr... )
	cmd.Stdout = &cmd_out
	cmd.Stderr = &cmd_err
	err := cmd.Run()

	if err == nil {
		msg.mtype = OUTPUT
		msg.buffer = cmd_out
		output <- msg
	} else {
		msg.mtype = ERROR
		msg.buffer = cmd_err
		output <- msg
	}

	return
}

func aggregator(wg *sync.WaitGroup, input chan output_msg) {

	defer wg.Done()
	var msg output_msg

	for true {
		msg = <- input
		switch msg.mtype {
		case CLOSE:
			return
		case OUTPUT:
			if msg.buffer.Len() > 0 {
				fmt.Printf("%s", msg.buffer.String())
			}
		case ERROR:
			if msg.buffer.Len() > 0 {
				fmt.Fprintf(os.Stderr, "%s", msg.buffer.String())
			}
		default:
		}
	}

}

func parseflags() []string {

	osx_find_flags := []string{"L", "H", "P", "E", "X", "d", "s", "x", "f"}
	set_flags := []string{}

	for f := range osx_find_flags {
		flag.Bool(osx_find_flags[f], false, "bool")
	}

	flag.Parse()
	for f := range osx_find_flags {
		flag_p := flag.Lookup(osx_find_flags[f])
		val, err := strconv.ParseBool(flag_p.Value.String())
		if err == nil && val == true {
			set_flags = append(set_flags, "-"+flag_p.Name)
		}
	}

	return set_flags
}

func getrootdirs(args []string) ([]string, []string) {

	rootdirs := []string{}
	options := []string{}
	var i int

	for i = range args {
		if strings.HasPrefix(args[i], "-")  { break }
		rootdirs = append(rootdirs, args[i])
		i++
	}
	options = append(options, args[i:]... )
	return rootdirs, options
}

func main() {

	var wg, wga sync.WaitGroup
	msg_channel := make(chan output_msg)

	set_flags := parseflags()

	argslice := flag.Args()
	basedirs := []string{}
	rootdirs, options := getrootdirs(argslice)
	for r := range rootdirs {
		dirs, direrr := ioutil.ReadDir(rootdirs[r])
		if(direrr != nil) {
			fmt.Printf("ReadDir err %v \n", direrr)
			fmt.Printf("Usage: gofind rootsearchdir <other-find-args> \n")
			return
		}
		for dirindex := range dirs {
			if dirs[dirindex].IsDir() {
				basedirs = append(basedirs, filepath.Join(rootdirs[r], dirs[dirindex].Name()))
			}
		}
		shallowfind := append(append([]string{},[]string{"-maxdepth", "1"}... ), options... )
		wg.Add(1)
		go find(rootdirs[r], &wg, set_flags, shallowfind, msg_channel)
	}

	for  dir := range basedirs {
		wg.Add(1)
		go find(basedirs[dir], &wg, set_flags, options, msg_channel)
	}

	wga.Add(1)
	go aggregator(&wga, msg_channel)
	wg.Wait()

	msg_channel <- output_msg{CLOSE, bytes.Buffer{}}
	wga.Wait()
}

<commit_msg>cleanup<commit_after>package main
// Author: Robert B Frangioso

import (
	"path/filepath"
	"os"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"
	"os/exec"
	"bytes"
	"strconv"
	"strings"
)

type msg_type int

const (
	OUTPUT msg_type = 1 + iota
	ERROR
	CLOSE
)

type output_msg struct {
	mtype	msg_type
	buffer	bytes.Buffer
}

func find(root string, wg *sync.WaitGroup, flags []string, args []string, output chan output_msg) {

	defer wg.Done()
	var cmd_out, cmd_err bytes.Buffer
	var msg output_msg

	findstr := append(append(append([]string{}, flags... ), []string{root}... ), args... )
	cmd := exec.Command("find", findstr... )
	cmd.Stdout = &cmd_out
	cmd.Stderr = &cmd_err
	err := cmd.Run()

	if err == nil {
		msg.mtype = OUTPUT
		msg.buffer = cmd_out
		output <- msg
	} else {
		msg.mtype = ERROR
		msg.buffer = cmd_err
		output <- msg
	}

	return
}

func aggregator(wg *sync.WaitGroup, input chan output_msg) {

	defer wg.Done()
	var msg output_msg

	for true {
		msg = <- input
		switch msg.mtype {
		case CLOSE:
			return
		case OUTPUT:
			if msg.buffer.Len() > 0 {
				fmt.Printf("%s", msg.buffer.String())
			}
		case ERROR:
			if msg.buffer.Len() > 0 {
				fmt.Fprintf(os.Stderr, "%s", msg.buffer.String())
			}
		default:
		}
	}

}

func parseflags() []string {

	osx_find_flags := []string{"L", "H", "P", "E", "X", "d", "s", "x", "f"}
	set_flags := []string{}

	for f := range osx_find_flags {
		flag.Bool(osx_find_flags[f], false, "bool")
	}

	flag.Parse()
	for f := range osx_find_flags {
		flag_p := flag.Lookup(osx_find_flags[f])
		val, err := strconv.ParseBool(flag_p.Value.String())
		if err == nil && val == true {
			set_flags = append(set_flags, "-"+flag_p.Name)
		}
	}

	return set_flags
}

func parseargs(args []string) ([]string, []string) {

	var i int

	for i = range args {
		if strings.HasPrefix(args[i], "-")  { break }
		i++
	}

	rootdirs := append([]string{}, args[:i]... )
	options := append([]string{}, args[i:]... )
	return rootdirs, options
}

func main() {

	var wg, wga sync.WaitGroup
	msg_channel := make(chan output_msg)

	set_flags := parseflags()
	argslice := flag.Args()
	basedirs := []string{}
	rootdirs, options := parseargs(argslice)

	for r := range rootdirs {
		dirs, direrr := ioutil.ReadDir(rootdirs[r])
		if(direrr != nil) {
			fmt.Printf("ReadDir err %v \n", direrr)
			fmt.Printf("Usage: gofind rootsearchdir <other-find-args> \n")
			return
		}
		for dirindex := range dirs {
			if dirs[dirindex].IsDir() {
				basedirs = append(basedirs, filepath.Join(rootdirs[r], dirs[dirindex].Name()))
			}
		}
		shallowfind := append(append([]string{},[]string{"-maxdepth", "1"}... ), options... )
		wg.Add(1)
		go find(rootdirs[r], &wg, set_flags, shallowfind, msg_channel)
	}

	for  dir := range basedirs {
		wg.Add(1)
		go find(basedirs[dir], &wg, set_flags, options, msg_channel)
	}

	wga.Add(1)
	go aggregator(&wga, msg_channel)
	wg.Wait()

	msg_channel <- output_msg{CLOSE, bytes.Buffer{}}
	wga.Wait()
}

<|endoftext|>


<commit_before>package main
// Author: Robert B Frangioso

import (
	"path/filepath"
	"os"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"
	"os/exec"
	"bytes"
)

type msg_type int

const (
	OUTPUT msg_type = 1 + iota
	ERROR
	CLOSE
)

type output_msg struct {
	mtype	msg_type
	buffer	bytes.Buffer
}

func find(root string, wg *sync.WaitGroup, exp []string, output chan output_msg) {

	defer wg.Done()
	var cmd_out, cmd_err bytes.Buffer
	var msg output_msg

	findargs := append([]string{root}, exp... )
	cmd := exec.Command("find", findargs... )
	cmd.Stdout = &cmd_out
	cmd.Stderr = &cmd_err
	err := cmd.Run()

	if err == nil {
		msg.mtype = OUTPUT
		msg.buffer = cmd_out
		output <- msg
	} else {
		msg.mtype = ERROR
		msg.buffer = cmd_err
		output <- msg
	}

	return
}

func aggregate(wg *sync.WaitGroup, input chan output_msg) {

	defer wg.Done()
	var msg output_msg

	for true {
		msg = <- input
		switch msg.mtype {
		case CLOSE:
			return
		case OUTPUT:
			if msg.buffer.Len() > 0 {
				fmt.Printf("%s", msg.buffer.String())
			}
		case ERROR:
			if msg.buffer.Len() > 0 {
				fmt.Fprintf(os.Stderr, "%s", msg.buffer.String())
			}
		default:
		}
	}

}

func main() {

	var wg, wga sync.WaitGroup
	msg_channel := make(chan output_msg)

	flag.Parse()
	root := flag.Arg(0)
	basedirs, direrr := ioutil.ReadDir(root)
	argslice := flag.Args()

	if(direrr != nil) {
		fmt.Printf("ReadDir err %v \n", direrr)
		fmt.Printf("Usage: gofind rootsearchdir <other-find-args> \n")
		return
	}

	shallowfind := append(append([]string{},[]string{"-maxdepth", "1"}... ), argslice[1:]... )
	wg.Add(1)
	go find(root, &wg, shallowfind, msg_channel)

	for  dir := range basedirs {
		if basedirs[dir].IsDir() {
			wg.Add(1)
			go find(filepath.Join(root, basedirs[dir].Name()), &wg, argslice[1:], msg_channel)
		}
	}

	wga.Add(1)
	go aggregate(&wga, msg_channel)
	wg.Wait()

	msg_channel <- output_msg{CLOSE, bytes.Buffer{}}
	wga.Wait()
}

<commit_msg>pedantic<commit_after>package main
// Author: Robert B Frangioso

import (
	"path/filepath"
	"os"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"
	"os/exec"
	"bytes"
)

type msg_type int

const (
	OUTPUT msg_type = 1 + iota
	ERROR
	CLOSE
)

type output_msg struct {
	mtype	msg_type
	buffer	bytes.Buffer
}

func find(root string, wg *sync.WaitGroup, exp []string, output chan output_msg) {

	defer wg.Done()
	var cmd_out, cmd_err bytes.Buffer
	var msg output_msg

	findargs := append([]string{root}, exp... )
	cmd := exec.Command("find", findargs... )
	cmd.Stdout = &cmd_out
	cmd.Stderr = &cmd_err
	err := cmd.Run()

	if err == nil {
		msg.mtype = OUTPUT
		msg.buffer = cmd_out
		output <- msg
	} else {
		msg.mtype = ERROR
		msg.buffer = cmd_err
		output <- msg
	}

	return
}

func aggregator(wg *sync.WaitGroup, input chan output_msg) {

	defer wg.Done()
	var msg output_msg

	for true {
		msg = <- input
		switch msg.mtype {
		case CLOSE:
			return
		case OUTPUT:
			if msg.buffer.Len() > 0 {
				fmt.Printf("%s", msg.buffer.String())
			}
		case ERROR:
			if msg.buffer.Len() > 0 {
				fmt.Fprintf(os.Stderr, "%s", msg.buffer.String())
			}
		default:
		}
	}

}

func main() {

	var wg, wga sync.WaitGroup
	msg_channel := make(chan output_msg)

	flag.Parse()
	root := flag.Arg(0)
	basedirs, direrr := ioutil.ReadDir(root)
	argslice := flag.Args()

	if(direrr != nil) {
		fmt.Printf("ReadDir err %v \n", direrr)
		fmt.Printf("Usage: gofind rootsearchdir <other-find-args> \n")
		return
	}

	shallowfind := append(append([]string{},[]string{"-maxdepth", "1"}... ), argslice[1:]... )
	wg.Add(1)
	go find(root, &wg, shallowfind, msg_channel)

	for  dir := range basedirs {
		if basedirs[dir].IsDir() {
			wg.Add(1)
			go find(filepath.Join(root, basedirs[dir].Name()), &wg, argslice[1:], msg_channel)
		}
	}

	wga.Add(1)
	go aggregator(&wga, msg_channel)
	wg.Wait()

	msg_channel <- output_msg{CLOSE, bytes.Buffer{}}
	wga.Wait()
}

<|endoftext|>


<commit_before>// A simple LLRP-based logical reader mock for RFID Tags using go-llrp
package main

import (
	"encoding/binary"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/gin-gonic/contrib/static"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/iomz/go-llrp"
	"github.com/juju/loggo"
	"golang.org/x/net/websocket"
	"gopkg.in/alecthomas/kingpin.v2"
)

// ManagementAction is a type for TagManager
type ManagementAction int

const (
	// RetrieveTags is a const for retrieving tags
	RetrieveTags ManagementAction = iota
	// AddTags is a const for adding tags
	AddTags
	// DeleteTags is a const for deleting tags
	DeleteTags
)

// TagManager is a struct for tag management channel
type TagManager struct {
	action ManagementAction
	tags   []*Tag
}

// Constant values
const (
	// BufferSize is a general size for a buffer
	BufferSize = 512
)

var (
	// Current Version
	version = "0.1.0"

	// kingpin app
	app = kingpin.New("golemu", "A mock LLRP-based logical reader emulator for RFID Tags.")
	// kingpin debug mode flag
	debug = app.Flag("debug", "Enable debug mode.").Short('v').Default("false").Bool()
	// kingpin initial MessageID
	initialMessageID = app.Flag("initialMessageID", "The initial messageID to start from.").Short('m').Default("1000").Int()
	// kingpin initial KeepaliveID
	initialKeepaliveID = app.Flag("initialKeepaliveID", "The initial keepaliveID to start from.").Short('k').Default("80000").Int()
	// kingpin LLRP listening port
	port = app.Flag("port", "LLRP listening port.").Short('p').Default("5084").Int()
	// kingpin LLRP listening IP address
	ip = app.Flag("ip", "LLRP listening address.").Short('a').Default("0.0.0.0").IP()

	// kingpin server command
	server = app.Command("server", "Run as a tag stream server.")
	// kingpin report interval
	reportInterval = server.Flag("reportInterval", "The interval of ROAccessReport in ms. Pseudo ROReport spec option.").Short('i').Default("1000").Int()
	// kingpin maximum tag to include in ROAccessReport
	maxTag = server.Flag("maxTag", "The maximum number of TagReportData parameters per ROAccessReport. Pseudo ROReport spec option. 0 for no limit.").Short('t').Default("0").Int()
	// kingpin tag list file
	file = server.Flag("file", "The file containing Tag data.").Short('f').Default("tags.csv").String()
	// kingpin web port
	webPort = server.Flag("webPort", "Port listening for web access.").Short('w').Default("3000").Int()

	// kingpin client command
	client = app.Command("client", "Run as a client mode.")

	// loggo
	logger = loggo.GetLogger("")

	// LLRPConn flag
	isLLRPConnAlive = false
	// Current messageID
	messageID = uint32(*initialMessageID)
	// Current KeepaliveID
	keepaliveID = *initialKeepaliveID
	// Current activeClients
	activeClients = make(map[WebsockConn]int) // map containing clients
	// Tag management channel
	tagManager = make(chan *TagManager)
	// notify tag update channel
	notify = make(chan bool)
	// update TagReportDataStack when tag is updated
	tagUpdated = make(chan []*Tag)
)

func init() {
}

// Iterate through the Tags and write ROAccessReport message to the socket
func sendROAccessReport(conn net.Conn, trds *TagReportDataStack) error {
	for _, trd := range trds.Stack {
		// Append TagReportData to ROAccessReport
		roar := llrp.ROAccessReport(trd.Parameter, messageID)
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		logger.Infof("%v\n", len(roar))

		// Send
		_, err := conn.Write(roar)
		if err != nil {
			return err
		}

		// Wait until ACK received
		time.Sleep(time.Millisecond)
	}

	return nil
}

// Handles incoming requests.
func handleRequest(conn net.Conn, tags []*Tag) {
	// Make a buffer to hold incoming data.
	buf := make([]byte, BufferSize)
	trds := buildTagReportDataStack(tags)

	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			logger.Infof("The client is disconnected, closing LLRP connection")
			conn.Close()
			return
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Infof("Closing LLRP connection")
			conn.Close()
			return
		}

		// Respond according to the LLRP packet header
		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.SetReaderConfigHeader || header == llrp.KeepaliveAckHeader {
			if header == llrp.SetReaderConfigHeader {
				// SRC received, start ROAR
				logger.Infof(">>> SET_READER_CONFIG")
				conn.Write(llrp.SetReaderConfigResponse())
			} else if header == llrp.KeepaliveAckHeader {
				// KA receieved, continue ROAR
				logger.Infof(">>> KeepaliveAck")
			}
			// Tick ROAR and Keepalive interval
			roarTicker := time.NewTicker(time.Duration(*reportInterval) * time.Millisecond)
			keepaliveTicker := time.NewTicker(10 * time.Second)
			for { // Infinite loop
				isLLRPConnAlive = true
				logger.Debugf("[LLRP handler select]: %v", trds)
				select {
				// ROAccessReport interval tick
				case <-roarTicker.C:
					logger.Tracef("### roarTicker.C")
					logger.Infof("<<< ROAccessReport (# of Tags: %v, # of TagReportData: %v)", trds.TotalTagCounts(), len(trds.Stack))
					err := sendROAccessReport(conn, trds)
					if err != nil {
						logger.Errorf(err.Error())
						isLLRPConnAlive = false
					}
				// Keepalive interval tick
				case <-keepaliveTicker.C:
					logger.Tracef("### keepaliveTicker.C")
					logger.Infof("<<< Keepalive")
					conn.Write(llrp.Keepalive())
					isLLRPConnAlive = false
				// When the tag queue is updated
				case tags := <-tagUpdated:
					logger.Tracef("### TagUpdated")
					trds = buildTagReportDataStack(tags)
				}
				if !isLLRPConnAlive {
					roarTicker.Stop()
					keepaliveTicker.Stop()
					break
				}
			}
		} else {
			// Unknown LLRP packet received, reset the connection
			logger.Warningf("Unknown header: %v, reqlen: %v", header, reqLen)
			logger.Warningf("Message: %v", buf)
			return
		}
	}
}

// APIPostTag redirects the tag addition request
func APIPostTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqAddTag("add", json); res == "error" {
		c.String(http.StatusAlreadyReported, "The tag already exists!\n")
	} else {
		c.String(http.StatusAccepted, "Post requested!\n")
	}
}

// APIDeleteTag redirects the tag deletion request
func APIDeleteTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqDeleteTag("delete", json); res == "error" {
		c.String(http.StatusNoContent, "The tag doesn't exist!\n")
	} else {
		c.String(http.StatusAccepted, "Delete requested!\n")
	}
}

// server mode
func runServer() int {
	// Read virtual tags from a csv file
	logger.Infof("Loading virtual Tags from \"%v\"", *file)

	if _, err := os.Stat(*file); os.IsNotExist(err) {
		_, err := os.Create(*file)
		check(err)
		logger.Infof("%v created.", *file)
	}

	csvIn, err := ioutil.ReadFile(*file)
	check(err)
	tags := loadTagsFromCSV(string(csvIn))

	// Listen for incoming connections.
	l, err := net.Listen("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	// Close the listener when the application closes.
	defer l.Close()
	logger.Infof("Listening on %v:%v", ip, *port)

	// Channel for communicating virtual tag updates and signals
	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	// Handle websocket and static file hosting with gin
	go func() {
		r := gin.Default()
		r.Use(static.Serve("/", static.LocalFile("./public", true)))
		r.GET("/ws", func(c *gin.Context) {
			handler := websocket.Handler(SockServer)
			handler.ServeHTTP(c.Writer, c.Request)
		})
		v1 := r.Group("api/v1")
		v1.POST("/tags", APIPostTag)
		v1.DELETE("/tags", APIDeleteTag)
		r.Run(":" + strconv.Itoa(*webPort))
	}()

	go func() {
		for {
			select {
			case cmd := <-tagManager:
				// Tag management
				res := []*Tag{}
				switch cmd.action {
				case AddTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i < 0 {
							tags = append(tags, t)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case DeleteTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i >= 0 {
							tags = append(tags[:i], tags[i+1:]...)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case RetrieveTags:
					res = tags
				}
				cmd.tags = res
				tagManager <- cmd
			case signal := <-signals:
				// Handle SIGINT and SIGTERM.
				logger.Infof("%v", signal)
				os.Exit(0)
			}
		}
	}()

	// Handle LLRP connection
	for {
		// Accept an incoming connection.
		logger.Infof("LLRP connection initiated")
		conn, err := l.Accept()
		if err != nil {
			logger.Errorf(err.Error())
			os.Exit(2)
		}

		// Send back READER_EVENT_NOTIFICATION
		currentTime := uint64(time.Now().UTC().Nanosecond() / 1000)
		conn.Write(llrp.ReaderEventNotification(messageID, currentTime))
		logger.Infof("<<< READER_EVENT_NOTIFICATION")
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		time.Sleep(time.Millisecond)

		// Handle connections in a new goroutine.
		go handleRequest(conn, tags)
	}
}

// client mode
func runClient() int {
	// Establish a connection to the llrp client
	conn, err := net.Dial("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	buf := make([]byte, BufferSize)
	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			return 0
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Errorf("reqLen = %v", reqLen)
			conn.Close()
			break
		}

		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.ReaderEventNotificationHeader {
			logger.Infof(">>> READER_EVENT_NOTIFICATION")
			conn.Write(llrp.SetReaderConfig(messageID))
		} else if header == llrp.KeepaliveHeader {
			logger.Infof(">>> KEEP_ALIVE")
			conn.Write(llrp.KeepaliveAck())
		} else if header == llrp.SetReaderConfigResponseHeader {
			logger.Infof(">>> SET_READER_CONFIG_RESPONSE")
		} else if header == llrp.ROAccessReportHeader {
			logger.Infof(">>> RO_ACCESS_REPORT")
			logger.Debugf("Packet size: %v\n", reqLen)
			logger.Debugf("% x\n", buf[:reqLen])
		} else {
			logger.Warningf("Unknown header: %v\n", header)
		}
	}
	return 0
}

func main() {
	app.Version(version)
	parse := kingpin.MustParse(app.Parse(os.Args[1:]))

	if *debug {
		loggo.ConfigureLoggers("TRACE")
		gin.SetMode(gin.DebugMode)
	} else {
		loggo.ConfigureLoggers("INFO")
		gin.SetMode(gin.ReleaseMode)
	}

	switch parse {
	case server.FullCommand():
		os.Exit(runServer())
	case client.FullCommand():
		os.Exit(runClient())
	}
}
<commit_msg>undisplay roar size<commit_after>// A simple LLRP-based logical reader mock for RFID Tags using go-llrp
package main

import (
	"encoding/binary"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/gin-gonic/contrib/static"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/iomz/go-llrp"
	"github.com/juju/loggo"
	"golang.org/x/net/websocket"
	"gopkg.in/alecthomas/kingpin.v2"
)

// ManagementAction is a type for TagManager
type ManagementAction int

const (
	// RetrieveTags is a const for retrieving tags
	RetrieveTags ManagementAction = iota
	// AddTags is a const for adding tags
	AddTags
	// DeleteTags is a const for deleting tags
	DeleteTags
)

// TagManager is a struct for tag management channel
type TagManager struct {
	action ManagementAction
	tags   []*Tag
}

// Constant values
const (
	// BufferSize is a general size for a buffer
	BufferSize = 512
)

var (
	// Current Version
	version = "0.1.0"

	// kingpin app
	app = kingpin.New("golemu", "A mock LLRP-based logical reader emulator for RFID Tags.")
	// kingpin debug mode flag
	debug = app.Flag("debug", "Enable debug mode.").Short('v').Default("false").Bool()
	// kingpin initial MessageID
	initialMessageID = app.Flag("initialMessageID", "The initial messageID to start from.").Short('m').Default("1000").Int()
	// kingpin initial KeepaliveID
	initialKeepaliveID = app.Flag("initialKeepaliveID", "The initial keepaliveID to start from.").Short('k').Default("80000").Int()
	// kingpin LLRP listening port
	port = app.Flag("port", "LLRP listening port.").Short('p').Default("5084").Int()
	// kingpin LLRP listening IP address
	ip = app.Flag("ip", "LLRP listening address.").Short('a').Default("0.0.0.0").IP()

	// kingpin server command
	server = app.Command("server", "Run as a tag stream server.")
	// kingpin report interval
	reportInterval = server.Flag("reportInterval", "The interval of ROAccessReport in ms. Pseudo ROReport spec option.").Short('i').Default("1000").Int()
	// kingpin maximum tag to include in ROAccessReport
	maxTag = server.Flag("maxTag", "The maximum number of TagReportData parameters per ROAccessReport. Pseudo ROReport spec option. 0 for no limit.").Short('t').Default("0").Int()
	// kingpin tag list file
	file = server.Flag("file", "The file containing Tag data.").Short('f').Default("tags.csv").String()
	// kingpin web port
	webPort = server.Flag("webPort", "Port listening for web access.").Short('w').Default("3000").Int()

	// kingpin client command
	client = app.Command("client", "Run as a client mode.")

	// loggo
	logger = loggo.GetLogger("")

	// LLRPConn flag
	isLLRPConnAlive = false
	// Current messageID
	messageID = uint32(*initialMessageID)
	// Current KeepaliveID
	keepaliveID = *initialKeepaliveID
	// Current activeClients
	activeClients = make(map[WebsockConn]int) // map containing clients
	// Tag management channel
	tagManager = make(chan *TagManager)
	// notify tag update channel
	notify = make(chan bool)
	// update TagReportDataStack when tag is updated
	tagUpdated = make(chan []*Tag)
)

func init() {
}

// Iterate through the Tags and write ROAccessReport message to the socket
func sendROAccessReport(conn net.Conn, trds *TagReportDataStack) error {
	for _, trd := range trds.Stack {
		// Append TagReportData to ROAccessReport
		roar := llrp.ROAccessReport(trd.Parameter, messageID)
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		//logger.Infof("%v\n", len(roar))

		// Send
		_, err := conn.Write(roar)
		if err != nil {
			return err
		}

		// Wait until ACK received
		time.Sleep(time.Millisecond)
	}

	return nil
}

// Handles incoming requests.
func handleRequest(conn net.Conn, tags []*Tag) {
	// Make a buffer to hold incoming data.
	buf := make([]byte, BufferSize)
	trds := buildTagReportDataStack(tags)

	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			logger.Infof("The client is disconnected, closing LLRP connection")
			conn.Close()
			return
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Infof("Closing LLRP connection")
			conn.Close()
			return
		}

		// Respond according to the LLRP packet header
		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.SetReaderConfigHeader || header == llrp.KeepaliveAckHeader {
			if header == llrp.SetReaderConfigHeader {
				// SRC received, start ROAR
				logger.Infof(">>> SET_READER_CONFIG")
				conn.Write(llrp.SetReaderConfigResponse())
			} else if header == llrp.KeepaliveAckHeader {
				// KA receieved, continue ROAR
				logger.Infof(">>> KeepaliveAck")
			}
			// Tick ROAR and Keepalive interval
			roarTicker := time.NewTicker(time.Duration(*reportInterval) * time.Millisecond)
			keepaliveTicker := time.NewTicker(10 * time.Second)
			for { // Infinite loop
				isLLRPConnAlive = true
				logger.Debugf("[LLRP handler select]: %v", trds)
				select {
				// ROAccessReport interval tick
				case <-roarTicker.C:
					logger.Tracef("### roarTicker.C")
					logger.Infof("<<< ROAccessReport (# of Tags: %v, # of TagReportData: %v)", trds.TotalTagCounts(), len(trds.Stack))
					err := sendROAccessReport(conn, trds)
					if err != nil {
						logger.Errorf(err.Error())
						isLLRPConnAlive = false
					}
				// Keepalive interval tick
				case <-keepaliveTicker.C:
					logger.Tracef("### keepaliveTicker.C")
					logger.Infof("<<< Keepalive")
					conn.Write(llrp.Keepalive())
					isLLRPConnAlive = false
				// When the tag queue is updated
				case tags := <-tagUpdated:
					logger.Tracef("### TagUpdated")
					trds = buildTagReportDataStack(tags)
				}
				if !isLLRPConnAlive {
					roarTicker.Stop()
					keepaliveTicker.Stop()
					break
				}
			}
		} else {
			// Unknown LLRP packet received, reset the connection
			logger.Warningf("Unknown header: %v, reqlen: %v", header, reqLen)
			logger.Warningf("Message: %v", buf)
			return
		}
	}
}

// APIPostTag redirects the tag addition request
func APIPostTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqAddTag("add", json); res == "error" {
		c.String(http.StatusAlreadyReported, "The tag already exists!\n")
	} else {
		c.String(http.StatusAccepted, "Post requested!\n")
	}
}

// APIDeleteTag redirects the tag deletion request
func APIDeleteTag(c *gin.Context) {
	var json []TagInString
	c.BindWith(&json, binding.JSON)
	if res := ReqDeleteTag("delete", json); res == "error" {
		c.String(http.StatusNoContent, "The tag doesn't exist!\n")
	} else {
		c.String(http.StatusAccepted, "Delete requested!\n")
	}
}

// server mode
func runServer() int {
	// Read virtual tags from a csv file
	logger.Infof("Loading virtual Tags from \"%v\"", *file)

	if _, err := os.Stat(*file); os.IsNotExist(err) {
		_, err := os.Create(*file)
		check(err)
		logger.Infof("%v created.", *file)
	}

	csvIn, err := ioutil.ReadFile(*file)
	check(err)
	tags := loadTagsFromCSV(string(csvIn))

	// Listen for incoming connections.
	l, err := net.Listen("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	// Close the listener when the application closes.
	defer l.Close()
	logger.Infof("Listening on %v:%v", ip, *port)

	// Channel for communicating virtual tag updates and signals
	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	// Handle websocket and static file hosting with gin
	go func() {
		r := gin.Default()
		r.Use(static.Serve("/", static.LocalFile("./public", true)))
		r.GET("/ws", func(c *gin.Context) {
			handler := websocket.Handler(SockServer)
			handler.ServeHTTP(c.Writer, c.Request)
		})
		v1 := r.Group("api/v1")
		v1.POST("/tags", APIPostTag)
		v1.DELETE("/tags", APIDeleteTag)
		r.Run(":" + strconv.Itoa(*webPort))
	}()

	go func() {
		for {
			select {
			case cmd := <-tagManager:
				// Tag management
				res := []*Tag{}
				switch cmd.action {
				case AddTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i < 0 {
							tags = append(tags, t)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case DeleteTags:
					for _, t := range cmd.tags {
						if i := getIndexOfTag(tags, t); i >= 0 {
							tags = append(tags[:i], tags[i+1:]...)
							res = append(res, t)
							writeTagsToCSV(tags, *file)
							if isLLRPConnAlive {
								tagUpdated <- tags
							}
						}
					}
				case RetrieveTags:
					res = tags
				}
				cmd.tags = res
				tagManager <- cmd
			case signal := <-signals:
				// Handle SIGINT and SIGTERM.
				logger.Infof("%v", signal)
				os.Exit(0)
			}
		}
	}()

	// Handle LLRP connection
	for {
		// Accept an incoming connection.
		logger.Infof("LLRP connection initiated")
		conn, err := l.Accept()
		if err != nil {
			logger.Errorf(err.Error())
			os.Exit(2)
		}

		// Send back READER_EVENT_NOTIFICATION
		currentTime := uint64(time.Now().UTC().Nanosecond() / 1000)
		conn.Write(llrp.ReaderEventNotification(messageID, currentTime))
		logger.Infof("<<< READER_EVENT_NOTIFICATION")
		atomic.AddUint32(&messageID, 1)
		runtime.Gosched()
		time.Sleep(time.Millisecond)

		// Handle connections in a new goroutine.
		go handleRequest(conn, tags)
	}
}

// client mode
func runClient() int {
	// Establish a connection to the llrp client
	conn, err := net.Dial("tcp", ip.String()+":"+strconv.Itoa(*port))
	check(err)

	buf := make([]byte, BufferSize)
	for {
		// Read the incoming connection into the buffer.
		reqLen, err := conn.Read(buf)
		if err == io.EOF {
			// Close the connection when you're done with it.
			return 0
		} else if err != nil {
			logger.Errorf(err.Error())
			logger.Errorf("reqLen = %v", reqLen)
			conn.Close()
			break
		}

		header := binary.BigEndian.Uint16(buf[:2])
		if header == llrp.ReaderEventNotificationHeader {
			logger.Infof(">>> READER_EVENT_NOTIFICATION")
			conn.Write(llrp.SetReaderConfig(messageID))
		} else if header == llrp.KeepaliveHeader {
			logger.Infof(">>> KEEP_ALIVE")
			conn.Write(llrp.KeepaliveAck())
		} else if header == llrp.SetReaderConfigResponseHeader {
			logger.Infof(">>> SET_READER_CONFIG_RESPONSE")
		} else if header == llrp.ROAccessReportHeader {
			logger.Infof(">>> RO_ACCESS_REPORT")
			logger.Debugf("Packet size: %v\n", reqLen)
			logger.Debugf("% x\n", buf[:reqLen])
		} else {
			logger.Warningf("Unknown header: %v\n", header)
		}
	}
	return 0
}

func main() {
	app.Version(version)
	parse := kingpin.MustParse(app.Parse(os.Args[1:]))

	if *debug {
		loggo.ConfigureLoggers("TRACE")
		gin.SetMode(gin.DebugMode)
	} else {
		loggo.ConfigureLoggers("INFO")
		gin.SetMode(gin.ReleaseMode)
	}

	switch parse {
	case server.FullCommand():
		os.Exit(runServer())
	case client.FullCommand():
		os.Exit(runClient())
	}
}
<|endoftext|>


<commit_before>package gomega

import "time"

const GOMEGA_VERSION = "1.0"

var globalFailHandler OmegaFailHandler

type OmegaFailHandler func(message string, callerSkip ...int)

func RegisterFailHandler(handler OmegaFailHandler) {
	globalFailHandler = handler
}

func Ω(actual interface{}) Actual {
	return newActual(actual, globalFailHandler)
}

func Expect(actual interface{}) Actual {
	return newActual(actual, globalFailHandler)
}

func Eventually(actual interface{}, intervals ...float64) AsyncActual {
	timeoutInterval := time.Duration(1 * time.Second)
	pollingInterval := time.Duration(10 * time.Millisecond)
	if len(intervals) > 0 {
		timeoutInterval = time.Duration(intervals[0] * float64(time.Second))
	}
	if len(intervals) > 1 {
		pollingInterval = time.Duration(intervals[1] * float64(time.Second))
	}
	return newAsyncActual(actual, globalFailHandler, timeoutInterval, pollingInterval)
}

type AsyncActual interface {
	Should(matcher OmegaMatcher, optionalDescription ...interface{})
	ShouldNot(matcher OmegaMatcher, optionalDescription ...interface{})
}

type Actual interface {
	Should(matcher OmegaMatcher, optionalDescription ...interface{})
	ShouldNot(matcher OmegaMatcher, optionalDescription ...interface{})

	To(matcher OmegaMatcher, optionalDescription ...interface{})
	ToNot(matcher OmegaMatcher, optionalDescription ...interface{})
	NotTo(matcher OmegaMatcher, optionalDescription ...interface{})
}

type OmegaMatcher interface {
	Match(actual interface{}) (success bool, message string, err error)
}
<commit_msg>Version is 0.9<commit_after>package gomega

import "time"

const GOMEGA_VERSION = "0.9"

var globalFailHandler OmegaFailHandler

type OmegaFailHandler func(message string, callerSkip ...int)

func RegisterFailHandler(handler OmegaFailHandler) {
	globalFailHandler = handler
}

func Ω(actual interface{}) Actual {
	return newActual(actual, globalFailHandler)
}

func Expect(actual interface{}) Actual {
	return newActual(actual, globalFailHandler)
}

func Eventually(actual interface{}, intervals ...float64) AsyncActual {
	timeoutInterval := time.Duration(1 * time.Second)
	pollingInterval := time.Duration(10 * time.Millisecond)
	if len(intervals) > 0 {
		timeoutInterval = time.Duration(intervals[0] * float64(time.Second))
	}
	if len(intervals) > 1 {
		pollingInterval = time.Duration(intervals[1] * float64(time.Second))
	}
	return newAsyncActual(actual, globalFailHandler, timeoutInterval, pollingInterval)
}

type AsyncActual interface {
	Should(matcher OmegaMatcher, optionalDescription ...interface{})
	ShouldNot(matcher OmegaMatcher, optionalDescription ...interface{})
}

type Actual interface {
	Should(matcher OmegaMatcher, optionalDescription ...interface{})
	ShouldNot(matcher OmegaMatcher, optionalDescription ...interface{})

	To(matcher OmegaMatcher, optionalDescription ...interface{})
	ToNot(matcher OmegaMatcher, optionalDescription ...interface{})
	NotTo(matcher OmegaMatcher, optionalDescription ...interface{})
}

type OmegaMatcher interface {
	Match(actual interface{}) (success bool, message string, err error)
}
<|endoftext|>


<commit_before>package checks

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net"
	"os"
	"strings"

	"github.com/jonog/redalert/utils"

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

func init() {
	Register("remote-docker", NewDockerRemoteDocker)
}

type RemoteDocker struct {
	User string
	Host string
	Tool string
	log  *log.Logger
}

var NewDockerRemoteDocker = func(config Config, logger *log.Logger) (Checker, error) {

	tool := utils.StringDefault(config.Tool, "nc")
	if !utils.FindStringInArray(tool, []string{"nc", "socat"}) {
		return nil, errors.New("checks: unknown tool in remote docker config")
	}

	return Checker(&RemoteDocker{
		User: config.User,
		Host: config.Host,
		Tool: tool,
		log:  logger,
	}), nil
}

func runCommand(client *ssh.Client, cmd string) (string, error) {
	session, err := client.NewSession()
	if err != nil {
		return "", nil
	}
	defer session.Close()
	var b bytes.Buffer
	session.Stdout = &b
	err = session.Run(cmd)
	if err != nil {
		return "", nil
	}
	output := b.String()
	return output, nil
}

func parseAndUnmarshal(raw string, data interface{}) error {

	httpRawSplit := strings.Split(raw, "\n\r\n")
	if len(httpRawSplit) < 2 {
		return errors.New("invalid format")
	}

	jsonStr := httpRawSplit[1]
	return json.Unmarshal([]byte(jsonStr), data)
}

func (r *RemoteDocker) dockerAPISocketAccess() string {
	if r.Tool == "nc" {
		return "nc -U /var/run/docker.sock"
	}
	if r.Tool == "socat" {
		return "socat - UNIX-CONNECT:/var/run/docker.sock"
	}
	return ""
}

func (r *RemoteDocker) dockerAPIStreamSocketAccess() string {
	if r.Tool == "nc" {
		return "nc -U /var/run/docker.sock"
	}
	if r.Tool == "socat" {
		return "socat -t 2 - UNIX-CONNECT:/var/run/docker.sock"
	}
	return ""
}

func (r *RemoteDocker) Check() (Metrics, error) {

	output := Metrics(make(map[string]*float64))

	// TODO:
	// add SSH auth options involving password / key

	sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		return output, nil
	}
	auth := ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
	defer sshAgent.Close()

	client, err := ssh.Dial("tcp", r.Host+":"+"22", &ssh.ClientConfig{
		User: r.User,
		Auth: []ssh.AuthMethod{auth},
	})
	if err != nil {
		return output, nil
	}

	// TODO:
	// give user choice of nc -U or socat

	sshOutput, err := runCommand(client, `echo -e "GET /containers/json HTTP/1.0\r\n" | `+r.dockerAPISocketAccess())
	if err != nil {
		return output, nil
	}

	if len(sshOutput) == 0 {
		r.log.Println("ERROR: cannot get list of containers from docker remote API")
		return output, nil
	}

	var containers []Container
	err = parseAndUnmarshal(sshOutput, &containers)
	if err != nil {
		return output, nil

	}

	for _, c := range containers {

		cmd := `(timeout 3 <<<'GET /containers/` + c.Id + `/stats HTTP/1.0'$'\r'$'\n' ` + r.dockerAPIStreamSocketAccess() + ` | cat) | tail -2`

		sshOutput, err := runCommand(client, cmd)
		if err != nil {
			r.log.Println("ERROR: ", err)
			continue
		}

		if len(sshOutput) == 0 {
			r.log.Println("ERROR: cannot get container stats from docker remote API")
			continue
		}

		readings := strings.Split(sshOutput, "\n")
		if len(readings) < 2 {
			r.log.Println("ERROR: two readings were not obtained from docker remote API")
			continue
		}

		var containerStats1 ContainerStats
		err = json.Unmarshal([]byte(readings[0]), &containerStats1)
		if err != nil {
			r.log.Println("ERROR: ", err)
			continue
		}
		var containerStats2 ContainerStats
		err = json.Unmarshal([]byte(readings[1]), &containerStats2)
		if err != nil {
			r.log.Println("ERROR: ", err)
			continue
		}

		// TODO: improve logic for picking the container name
		containerName := c.Names[len(c.Names)-1]

		// TODO: collect all the metrics
		containerMemory := float64(containerStats2.MemoryStats.Usage / 1000000.0)
		output[containerName+"_memory"] = &containerMemory

		cpuUsageDelta := float64(containerStats2.CpuStats.CpuUsage.TotalUsage) - float64(containerStats1.CpuStats.CpuUsage.TotalUsage)
		systemCpuUsageDelta := float64(containerStats2.CpuStats.SystemCpuUsage) - float64(containerStats1.CpuStats.SystemCpuUsage)
		cpuUsagePercent := cpuUsageDelta * 100 / systemCpuUsageDelta

		output[containerName+"_cpu"] = &cpuUsagePercent

	}

	containerCount := float64(len(containers))
	output["container_count"] = &containerCount

	return output, nil
}

func (r *RemoteDocker) MetricInfo(metric string) MetricInfo {
	return MetricInfo{Unit: ""}
}

func (r *RemoteDocker) MessageContext() string {
	return "docker host - " + r.Host
}

type Container struct {
	Command string
	Created int
	Id      string
	Image   string
	Names   []string
	Ports   []PortConfig
	Status  string
}

type PortConfig struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type ContainerStats struct {
	Read    string `json:"read"`
	Network struct {
		RxDropped int `json:"rx_dropped"`
		RxBytes   int `json:"rx_bytes"`
		RxErrors  int `json:"rx_errors"`
		TxPackets int `json:"tx_packets"`
		TxDropped int `json:"tx_dropped"`
		RxPackets int `json:"rx_packets"`
		TxErrors  int `json:"tx_errors"`
		TxBytes   int `json:"tx_bytes"`
	} `json:"network"`
	MemoryStats struct {
		Stats struct {
			TotalRss int `json:"total_rss"`
			// TODO: add additional mem stats
		} `json:"stats"`
		MaxUsage int `json:"max_usage"`
		Usage    int `json:"usage"`
		Failcnt  int `json:"failcnt"`
		Limit    int `json:"limit"`
	} `json:"memory_stats"`
	CpuStats struct {
		CpuUsage struct {
			PercpuUsage       []int `json:"percpu_usage"`
			UsageInUsermode   int   `json:"usage_in_usermode"`
			TotalUsage        int   `json:"total_usage"`
			UsageInKernelmode int   `json:"usage_in_kernelmode"`
		} `json:"cpu_usage"`
		SystemCpuUsage int `json:"system_cpu_usage"`
	} `json:"cpu_stats"`
}
<commit_msg>Improve logic of picking container name.<commit_after>package checks

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net"
	"os"
	"strings"

	"github.com/jonog/redalert/utils"

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

func init() {
	Register("remote-docker", NewDockerRemoteDocker)
}

type RemoteDocker struct {
	User string
	Host string
	Tool string
	log  *log.Logger
}

var NewDockerRemoteDocker = func(config Config, logger *log.Logger) (Checker, error) {

	tool := utils.StringDefault(config.Tool, "nc")
	if !utils.FindStringInArray(tool, []string{"nc", "socat"}) {
		return nil, errors.New("checks: unknown tool in remote docker config")
	}

	return Checker(&RemoteDocker{
		User: config.User,
		Host: config.Host,
		Tool: tool,
		log:  logger,
	}), nil
}

func runCommand(client *ssh.Client, cmd string) (string, error) {
	session, err := client.NewSession()
	if err != nil {
		return "", nil
	}
	defer session.Close()
	var b bytes.Buffer
	session.Stdout = &b
	err = session.Run(cmd)
	if err != nil {
		return "", nil
	}
	output := b.String()
	return output, nil
}

func parseAndUnmarshal(raw string, data interface{}) error {

	httpRawSplit := strings.Split(raw, "\n\r\n")
	if len(httpRawSplit) < 2 {
		return errors.New("invalid format")
	}

	jsonStr := httpRawSplit[1]
	return json.Unmarshal([]byte(jsonStr), data)
}

func (r *RemoteDocker) dockerAPISocketAccess() string {
	if r.Tool == "nc" {
		return "nc -U /var/run/docker.sock"
	}
	if r.Tool == "socat" {
		return "socat - UNIX-CONNECT:/var/run/docker.sock"
	}
	return ""
}

func (r *RemoteDocker) dockerAPIStreamSocketAccess() string {
	if r.Tool == "nc" {
		return "nc -U /var/run/docker.sock"
	}
	if r.Tool == "socat" {
		return "socat -t 2 - UNIX-CONNECT:/var/run/docker.sock"
	}
	return ""
}

func (r *RemoteDocker) Check() (Metrics, error) {

	output := Metrics(make(map[string]*float64))

	// TODO:
	// add SSH auth options involving password / key

	sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		return output, nil
	}
	auth := ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
	defer sshAgent.Close()

	client, err := ssh.Dial("tcp", r.Host+":"+"22", &ssh.ClientConfig{
		User: r.User,
		Auth: []ssh.AuthMethod{auth},
	})
	if err != nil {
		return output, nil
	}

	// TODO:
	// give user choice of nc -U or socat

	sshOutput, err := runCommand(client, `echo -e "GET /containers/json HTTP/1.0\r\n" | `+r.dockerAPISocketAccess())
	if err != nil {
		return output, nil
	}

	if len(sshOutput) == 0 {
		r.log.Println("ERROR: cannot get list of containers from docker remote API")
		return output, nil
	}

	var containers []Container
	err = parseAndUnmarshal(sshOutput, &containers)
	if err != nil {
		return output, nil

	}

	for _, c := range containers {

		cmd := `(timeout 3 <<<'GET /containers/` + c.Id + `/stats HTTP/1.0'$'\r'$'\n' ` + r.dockerAPIStreamSocketAccess() + ` | cat) | tail -2`

		sshOutput, err := runCommand(client, cmd)
		if err != nil {
			r.log.Println("ERROR: ", err)
			continue
		}

		if len(sshOutput) == 0 {
			r.log.Println("ERROR: cannot get container stats from docker remote API")
			continue
		}

		readings := strings.Split(sshOutput, "\n")
		if len(readings) < 2 {
			r.log.Println("ERROR: two readings were not obtained from docker remote API")
			continue
		}

		var containerStats1 ContainerStats
		err = json.Unmarshal([]byte(readings[0]), &containerStats1)
		if err != nil {
			r.log.Println("ERROR: ", err)
			continue
		}
		var containerStats2 ContainerStats
		err = json.Unmarshal([]byte(readings[1]), &containerStats2)
		if err != nil {
			r.log.Println("ERROR: ", err)
			continue
		}

		containerName, err := getContainerName(c.Names)
		if err != nil {
			r.log.Println("ERROR: establishing container name", err)
			continue
		}

		// TODO: collect all the metrics
		containerMemory := float64(containerStats2.MemoryStats.Usage / 1000000.0)
		output[containerName+"_memory"] = &containerMemory

		cpuUsageDelta := float64(containerStats2.CpuStats.CpuUsage.TotalUsage) - float64(containerStats1.CpuStats.CpuUsage.TotalUsage)
		systemCpuUsageDelta := float64(containerStats2.CpuStats.SystemCpuUsage) - float64(containerStats1.CpuStats.SystemCpuUsage)
		cpuUsagePercent := cpuUsageDelta * 100 / systemCpuUsageDelta

		output[containerName+"_cpu"] = &cpuUsagePercent

	}

	containerCount := float64(len(containers))
	output["container_count"] = &containerCount

	return output, nil
}

func getContainerName(names []string) string {

	// remove prefix '/'
	for _, name := range names {
		namePrefixRemoved := name[1:]

		// find container without '/' within name
		if len(strings.Split(namePrefixRemoved, "/")) == 1 {
			return namePrefixRemoved
		}
	}
	return ""
}

func (r *RemoteDocker) MetricInfo(metric string) MetricInfo {
	return MetricInfo{Unit: ""}
}

func (r *RemoteDocker) MessageContext() string {
	return "docker host - " + r.Host
}

type Container struct {
	Command string
	Created int
	Id      string
	Image   string
	Names   []string
	Ports   []PortConfig
	Status  string
}

type PortConfig struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type ContainerStats struct {
	Read    string `json:"read"`
	Network struct {
		RxDropped int `json:"rx_dropped"`
		RxBytes   int `json:"rx_bytes"`
		RxErrors  int `json:"rx_errors"`
		TxPackets int `json:"tx_packets"`
		TxDropped int `json:"tx_dropped"`
		RxPackets int `json:"rx_packets"`
		TxErrors  int `json:"tx_errors"`
		TxBytes   int `json:"tx_bytes"`
	} `json:"network"`
	MemoryStats struct {
		Stats struct {
			TotalRss int `json:"total_rss"`
			// TODO: add additional mem stats
		} `json:"stats"`
		MaxUsage int `json:"max_usage"`
		Usage    int `json:"usage"`
		Failcnt  int `json:"failcnt"`
		Limit    int `json:"limit"`
	} `json:"memory_stats"`
	CpuStats struct {
		CpuUsage struct {
			PercpuUsage       []int `json:"percpu_usage"`
			UsageInUsermode   int   `json:"usage_in_usermode"`
			TotalUsage        int   `json:"total_usage"`
			UsageInKernelmode int   `json:"usage_in_kernelmode"`
		} `json:"cpu_usage"`
		SystemCpuUsage int `json:"system_cpu_usage"`
	} `json:"cpu_stats"`
}
<|endoftext|>


<commit_before>package local

import (
	"github.com/hashicorp/terraform/backend"
)

// backend.CLI impl.
func (b *Local) CLIInit(opts *backend.CLIOpts) error {
	b.CLI = opts.CLI
	b.CLIColor = opts.CLIColor
	b.ShowDiagnostics = opts.ShowDiagnostics
	b.ContextOpts = opts.ContextOpts
	b.OpInput = opts.Input
	b.OpValidation = opts.Validation
	b.RunningInAutomation = opts.RunningInAutomation

	// Only configure state paths if we didn't do so via the configure func.
	if b.StatePath == "" {
		b.StatePath = opts.StatePath
		b.StateOutPath = opts.StateOutPath
		b.StateBackupPath = opts.StateBackupPath
	}

	return nil
}
<commit_msg>add backend cli options after configuration<commit_after>package local

import (
	"github.com/hashicorp/terraform/backend"
)

// backend.CLI impl.
func (b *Local) CLIInit(opts *backend.CLIOpts) error {
	b.CLI = opts.CLI
	b.CLIColor = opts.CLIColor
	b.ShowDiagnostics = opts.ShowDiagnostics
	b.ContextOpts = opts.ContextOpts
	b.OpInput = opts.Input
	b.OpValidation = opts.Validation
	b.RunningInAutomation = opts.RunningInAutomation

	// configure any new cli options
	if opts.StatePath != "" {
		b.StatePath = opts.StatePath
	}

	if opts.StateOutPath != "" {
		b.StateOutPath = opts.StateOutPath
	}

	if opts.StateBackupPath != "" {
		b.StateBackupPath = opts.StateBackupPath
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Luke Shumaker
// Copyright 2015 Davis Webb
// Copyright 2015 Guntas Grewal

package backend

import (
	"io"
	"time"

	"github.com/dchest/captcha"
	"github.com/jinzhu/gorm"
)

const (
	// Default number of digits in captcha solution.
	DefaultLen = 6
	// Expiration time of captchas used by default store.
	DefaultExpiration = 20 * time.Minute
	//	Default Captcha Image Width
	DefaultWidth = 640
	//	Default Captcha Image Height
	DefaultHeight = 480
)

type Captcha struct {
	ID         string
	Value      string
	Token      string
	Expiration time.Time
}

func (o Captcha) dbSchema(db *gorm.DB) error {
	return db.CreateTable(&o).Error
}

func NewCaptcha(db *gorm.DB) *Captcha {
	o := Captcha{
		ID:    captcha.New(),
		Value: string(captcha.RandomDigits(DefaultLen)),
	}
	if err := db.Create(&o).Error; err != nil {
		panic(err)
	}
	return &o
}

func UseCaptcha(db *gorm.DB, token string) bool {
	panic("TODO")
}

func CheckCaptcha(db *gorm.DB, userInput string, captchaID string) bool {
	o := GetCaptchaByID(db, captchaID)
	if o == nil {
		return false
	}
	return userInput == o.Value
}

func GetCaptchaByID(db *gorm.DB, id string) *Captcha {
	var o Captcha
	if result := db.First(&o, "id = ?", id); result.Error != nil {
		if result.RecordNotFound() {
			return nil
		}
		panic(result.Error)
	}
	return &o
}

func (o *Captcha) MarshalPNG(w io.Writer) error {
	// TODO: generate PNG and write it to w
	return captcha.WriteImage(w, o.ID, DefaultWidth, DefaultHeight)
}

func (o *Captcha) MarshalWAV(w io.Writer) error {
	// TODO: generate WAV and write it to w
	return captcha.WriteAudio(w, o.ID, "en")
}

func (o *Captcha) Save(db *gorm.DB) {
	if err := db.Save(o).Error; err != nil {
		panic(err)
	}
}
<commit_msg>func UseCaptcha<commit_after>// Copyright 2015 Luke Shumaker
// Copyright 2015 Davis Webb
// Copyright 2015 Guntas Grewal

package backend

import (
	"io"
	"strings"
	"time"

	"github.com/dchest/captcha"
	"github.com/jinzhu/gorm"
)

const (
	// Default number of digits in captcha solution.
	DefaultLen = 6
	// Expiration time of captchas used by default store.
	DefaultExpiration = 20 * time.Minute
	//	Default Captcha Image Width
	DefaultWidth = 640
	//	Default Captcha Image Height
	DefaultHeight = 480
)

type Captcha struct {
	ID         string
	Value      string
	Token      string
	Expiration time.Time
}

func (o Captcha) dbSchema(db *gorm.DB) error {
	return db.CreateTable(&o).Error
}

func NewCaptcha(db *gorm.DB) *Captcha {
	o := Captcha{
		ID:    captcha.New(),
		Value: string(captcha.RandomDigits(DefaultLen)),
	}
	if err := db.Create(&o).Error; err != nil {
		panic(err)
	}
	return &o
}

func UseCaptcha(db *gorm.DB, id, token string) bool {
	o := GetCaptchaByID(db, id)
	if o == nil {
		panic("Captcha " + id + " does not exist.")
	}
	if strings.Compare(token, "true") == 0 {
		// destroy captcha
		db.Delete(&o)
		return true
	}
	// destroy captcha
	db.Delete(&o)
	return false
}

func CheckCaptcha(db *gorm.DB, userInput string, captchaID string) bool {
	o := GetCaptchaByID(db, captchaID)
	if o == nil {
		return false
	}
	return userInput == o.Value
}

func GetCaptchaByID(db *gorm.DB, id string) *Captcha {
	var o Captcha
	if result := db.First(&o, "id = ?", id); result.Error != nil {
		if result.RecordNotFound() {
			return nil
		}
		panic(result.Error)
	}
	return &o
}

func (o *Captcha) MarshalPNG(w io.Writer) error {
	// TODO: generate PNG and write it to w
	return captcha.WriteImage(w, o.ID, DefaultWidth, DefaultHeight)
}

func (o *Captcha) MarshalWAV(w io.Writer) error {
	// TODO: generate WAV and write it to w
	return captcha.WriteAudio(w, o.ID, "en")
}

func (o *Captcha) Save(db *gorm.DB) {
	if err := db.Save(o).Error; err != nil {
		panic(err)
	}
}
<|endoftext|>


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

//go:generate cproto -use-grpc-plugin
//go:generate mockgen -source repo_grpc.pb.go -destination repo_grpc.mock.pb.go -package api

// +build !copybara

// Package api contains CIPD backend API definitions.
package api
<commit_msg>Revert "Do not import cipd/api/cipd/v1/gen.go with copybara"<commit_after>// Copyright 2017 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:generate cproto -use-grpc-plugin
//go:generate mockgen -source repo_grpc.pb.go -destination repo_grpc.mock.pb.go -package api

// Package api contains CIPD backend API definitions.
package api
<|endoftext|>


<commit_before>package dotquotedetect

import (
	"github.com/reiver/go-inquote"

	"io"
)

// DetectQuote looks for a dotquote quote in the dotquote data in a []byte, and returns
// the beginning index and the ending index.
//
// The returned beginning index and ending index are the values one would need
// to take a slice of the []byte, and get just that quote.
//
// For example:
//
//	b, e, err := dotquotedetect.DetectQuote(p)
//	if nil != err {
//		return err
//	}
//
//	quote := p[b:e]
func DetectQuote(b []byte) (int, int, error) {
	if nil == b {
		return -1, -1, errNilBytes
	}

	lenb := len(b)

	if 2 > lenb {
		return -1, -1, errBadRequest
	}

	b0 := b[0]

	if '"' != b0 {
		return -1, -1, newNotQuoteComplainer(string(b))
	}

	const begin = 0
	end := 1 + begin

	p:= b[1:]

	for {
		if 0 >= len(p) {
			return -1, -1, errBadRequest
		}

		p0 := p[0]
		if '"' == p0 {
			end++
			break
		}

		_, n, err := inquote.DecodeRune(p)
		if nil != err {
			if io.EOF == err {
				break
			}
			return -1, -1, err
		}

		end += n

		p = p[n:]
	}

	return begin, end, nil
}
<commit_msg>utf-8<commit_after>package dotquotedetect

import (
	"github.com/reiver/go-inquote"

	"io"
	"unicode/utf8"
)

// DetectQuote looks for a dotquote quote in the dotquote data in a []byte, and returns
// the beginning index and the ending index.
//
// The returned beginning index and ending index are the values one would need
// to take a slice of the []byte, and get just that quote.
//
// For example:
//
//	b, e, err := dotquotedetect.DetectQuote(p)
//	if nil != err {
//		return err
//	}
//
//	quote := p[b:e]
func DetectQuote(b []byte) (int, int, error) {
	if nil == b {
		return -1, -1, errNilBytes
	}

	lenb := len(b)

	if 2 > lenb {
		return -1, -1, errBadRequest
	}

	r0, size := utf8.DecodeRune(b)
	if utf8.RuneError == r0 {
		return -1, -1, errNotUTF8
	}

	if '"' != r0 {
		return -1, -1, newNotQuoteComplainer(string(b))
	}

	const begin = 0
	end := size + begin

	p:= b[size:]

	for {
		if 0 >= len(p) {
			return -1, -1, errBadRequest
		}

		r0, size := utf8.DecodeRune(p)
		if utf8.RuneError == r0 {
			return -1, -1, errNotUTF8
		}

		if '"' == r0 {
			end += size
			break
		}

		_, n, err := inquote.DecodeRune(p)
		if nil != err {
			if io.EOF == err {
				break
			}
			return -1, -1, err
		}

		end += n

		p = p[n:]
	}

	return begin, end, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"io/ioutil"
	"strings"
	"bytes"
	"encoding/json"
	"regexp"
	"errors"
	//"github.com/parnurzeal/gorequest"
)

const CONFIG_FILE string = "../config/client.json"

// A global configuration instance. Must be instantiated properly in main().
var Configuration Config

// Verifies a URL as valid (enough)
const URL_REGEX = "(https?://)?(www\\.)?\\w+\\.\\w+"

// In the case that wait.html cannot be served, we will respond with a
// plain text message to the user.
const PLEASE_WAIT_PLAINTEXT = /* Multi-line strings, yeah! */ `
The page you have requested is being prepared.
Plesae refresh this page in a few seconds to check if it is ready.
`

// Result of a bundle lookup from cache server.
type Result struct {
	Complete bool
	Found    bool
	Bundle   []byte
	// Should add a Created field for the date created
}

// Present the user with a page informing them that something went wrong with
// an action.
func errorPage(errMsg string) []byte {
	return []byte("Error: " + errMsg)
}

// Serve a page to inform the user that a bundle for the site they requested is
// being prepared. It will automatically initiate new requests to retrieve the same
// URL in an interval.
// The second bool return value specifies whether the response is HTML or not
func pleaseWait(url string) ([]byte, bool) {
	content, err := ioutil.ReadFile(Configuration.PleaseWaitPage)
	if err != nil {
		return []byte(PLEASE_WAIT_PLAINTEXT), false
	} else {
		return bytes.Replace(content, []byte("{{REDIRECT}}"), []byte(url), 1), true
	}
}

// Ping the LCS to see if it is available at a given time.
func testLCSAvailability() bool {
	response, err := http.Get(LCSPingURL(Configuration))
	return err == nil && response.StatusCode == 200
}

// Ping the RS to see if it is available at a given time.
func testRSAvailability() bool {
	response, err := http.Get(RSPingURL(Configuration))
	return err == nil && response.StatusCode == 200
}

// Report that an error occured trying to decode the response from the LCS
// The LCS is expected to respond to this request with just the string "okay",
// so we will ignore it for now.
func reportDecodeError(reportURL, errMsg string) (bool, error) {
	mapping := map[string]interface{} {
		"error": errMsg,
	}
	marshalled, _ := json.Marshal(mapping)
	reader := bytes.NewReader(marshalled)
	req, err := http.NewRequest("POST", reportURL, reader)
	if err != nil {
		return false, err
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	response, err := client.Do(req)
	return response.StatusCode == 200, err
}

// Check with the local cache server to find a bundle for a given URL.
func lookup(lookupURL string) (Result, error) {
	response, err := http.Get(BundleLookupURL(Configuration, lookupURL))
	if err != nil || response.StatusCode != 200 {
		fmt.Print("error: ")
		fmt.Println(err)
		return Result{false, false, nil}, errors.New("Unsuccessful request to LCS\n" + err.Error())
	}
	decoder := json.NewDecoder(response.Body)
	var result Result
	if err := decoder.Decode(&result); err != nil {
		fmt.Println("Error decoding response from LCS")
		fmt.Println(err)
		reachedLCS, err2 := reportDecodeError(DecodeErrReportURL(Configuration), err.Error())
		if reachedLCS {
			return Result{false, false, nil}, errors.New("Could not decode LCS response\n" + err.Error())
		} else {
			return Result{false, false, nil}, errors.New("Unsuccessful request to LCS\n" + err2.Error())
		}
	}
	fmt.Println("Result")
	fmt.Println(result)
	return result, nil
}

// POST to the request server to have it start making a new bundle.
func requestNewBundle(lookupURL string) error {
	// We can ignore the content of the response since it is not used.
	response, err := http.Post(
		CreateBundleURL(Configuration, lookupURL),
		"text/plain",
		strings.NewReader(lookupURL))
	fmt.Println("Sent POST request to Request Server")
	if err != nil || response.StatusCode != 200 {
		fmt.Println("Got error POSTing to request server or request did not return status 200")
		fmt.Println(err)
	} else {
		response.Body.Close()
	}
	return err
}

// Handle incoming requests for bundles.
// 1. Initiate bundle lookup process
// 2. Initiate bundle creation process when no bundle exists anywhere
func proxyHandler(w http.ResponseWriter, r *http.Request) {
	URL := r.URL.String()
	matched, err := regexp.MatchString(URL_REGEX, URL)
	if !matched || err != nil {
		fmt.Println("Invalid URL " + URL)
		w.Write(errorPage(URL + " is not a valid URL."))
		return
	}
	result, err := lookup(URL)
	if err != nil {
		w.Write(errorPage(err.Error()))
	} else if result.Complete {
		if result.Found {
			w.Write(result.Bundle)
		} else {
			err = requestNewBundle(URL)
			if err != nil {
				w.Header().Set("Content-Type", "text/plain")
				w.Write(errorPage(err.Error()))
			} else {
				body, isHTML := pleaseWait(URL)
				if isHTML {
					w.Header().Set("Content-Type", "text/html")
				} else {
					w.Header().Set("Content-Type", "text/plain")
				}
				w.Write(body)
			}
		}
	} else {
		body, isHTML := pleaseWait(URL)
		if isHTML {
			w.Header().Set("Content-Type", "text/html")
		} else {
			w.Header().Set("Content-Type", "text/plain")
		}
		w.Write(body)
	}
}

func main() {
	// Read an existing configuration file or have the user supply settings
	conf, err := ReadConfigFile(CONFIG_FILE)
	if err != nil {
		fmt.Print("Could not read configuration file at " + CONFIG_FILE)
		Configuration = GetConfigFromUser()
	} else {
		Configuration = conf
	}
	// Ensure the LCS is available at startup time
	available := testLCSAvailability()
	if !available {
		fmt.Println("Local cache server is not responding to requests.")
		fmt.Println(LCS_RUN_INFO)
		return
	}
	// Ensure the RS is available at startup time
	available = testRSAvailability()
	if !available {
		fmt.Println("Request server is not responding to requests.")
		fmt.Println(RS_RUN_INFO)
		return
	}
	// Create an HTTP proxy server
	http.HandleFunc("/", proxyHandler)
	fmt.Println("CeNo proxy server listening at http://localhost" + Configuration.PortNumber)
	http.ListenAndServe(Configuration.PortNumber, nil)
}<commit_msg>Not using gorequest after all<commit_after>package main

import (
	"fmt"
	"net/http"
	"io/ioutil"
	"strings"
	"bytes"
	"encoding/json"
	"regexp"
	"errors"
)

const CONFIG_FILE string = "../config/client.json"

// A global configuration instance. Must be instantiated properly in main().
var Configuration Config

// Verifies a URL as valid (enough)
const URL_REGEX = "(https?://)?(www\\.)?\\w+\\.\\w+"

// In the case that wait.html cannot be served, we will respond with a
// plain text message to the user.
const PLEASE_WAIT_PLAINTEXT = /* Multi-line strings, yeah! */ `
The page you have requested is being prepared.
Plesae refresh this page in a few seconds to check if it is ready.
`

// Result of a bundle lookup from cache server.
type Result struct {
	Complete bool
	Found    bool
	Bundle   []byte
	// Should add a Created field for the date created
}

// Present the user with a page informing them that something went wrong with
// an action.
func errorPage(errMsg string) []byte {
	return []byte("Error: " + errMsg)
}

// Serve a page to inform the user that a bundle for the site they requested is
// being prepared. It will automatically initiate new requests to retrieve the same
// URL in an interval.
// The second bool return value specifies whether the response is HTML or not
func pleaseWait(url string) ([]byte, bool) {
	content, err := ioutil.ReadFile(Configuration.PleaseWaitPage)
	if err != nil {
		return []byte(PLEASE_WAIT_PLAINTEXT), false
	} else {
		return bytes.Replace(content, []byte("{{REDIRECT}}"), []byte(url), 1), true
	}
}

// Ping the LCS to see if it is available at a given time.
func testLCSAvailability() bool {
	response, err := http.Get(LCSPingURL(Configuration))
	return err == nil && response.StatusCode == 200
}

// Ping the RS to see if it is available at a given time.
func testRSAvailability() bool {
	response, err := http.Get(RSPingURL(Configuration))
	return err == nil && response.StatusCode == 200
}

// Report that an error occured trying to decode the response from the LCS
// The LCS is expected to respond to this request with just the string "okay",
// so we will ignore it for now.
func reportDecodeError(reportURL, errMsg string) (bool, error) {
	mapping := map[string]interface{} {
		"error": errMsg,
	}
	marshalled, _ := json.Marshal(mapping)
	reader := bytes.NewReader(marshalled)
	req, err := http.NewRequest("POST", reportURL, reader)
	if err != nil {
		return false, err
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	response, err := client.Do(req)
	return response.StatusCode == 200, err
}

// Check with the local cache server to find a bundle for a given URL.
func lookup(lookupURL string) (Result, error) {
	response, err := http.Get(BundleLookupURL(Configuration, lookupURL))
	if err != nil || response.StatusCode != 200 {
		fmt.Print("error: ")
		fmt.Println(err)
		return Result{false, false, nil}, errors.New("Unsuccessful request to LCS\n" + err.Error())
	}
	decoder := json.NewDecoder(response.Body)
	var result Result
	if err := decoder.Decode(&result); err != nil {
		fmt.Println("Error decoding response from LCS")
		fmt.Println(err)
		reachedLCS, err2 := reportDecodeError(DecodeErrReportURL(Configuration), err.Error())
		if reachedLCS {
			return Result{false, false, nil}, errors.New("Could not decode LCS response\n" + err.Error())
		} else {
			return Result{false, false, nil}, errors.New("Unsuccessful request to LCS\n" + err2.Error())
		}
	}
	fmt.Println("Result")
	fmt.Println(result)
	return result, nil
}

// POST to the request server to have it start making a new bundle.
func requestNewBundle(lookupURL string) error {
	// We can ignore the content of the response since it is not used.
	response, err := http.Post(
		CreateBundleURL(Configuration, lookupURL),
		"text/plain",
		strings.NewReader(lookupURL))
	fmt.Println("Sent POST request to Request Server")
	if err != nil || response.StatusCode != 200 {
		fmt.Println("Got error POSTing to request server or request did not return status 200")
		fmt.Println(err)
	} else {
		response.Body.Close()
	}
	return err
}

// Handle incoming requests for bundles.
// 1. Initiate bundle lookup process
// 2. Initiate bundle creation process when no bundle exists anywhere
func proxyHandler(w http.ResponseWriter, r *http.Request) {
	URL := r.URL.String()
	matched, err := regexp.MatchString(URL_REGEX, URL)
	if !matched || err != nil {
		fmt.Println("Invalid URL " + URL)
		w.Write(errorPage(URL + " is not a valid URL."))
		return
	}
	result, err := lookup(URL)
	if err != nil {
		w.Write(errorPage(err.Error()))
	} else if result.Complete {
		if result.Found {
			w.Write(result.Bundle)
		} else {
			err = requestNewBundle(URL)
			if err != nil {
				w.Header().Set("Content-Type", "text/plain")
				w.Write(errorPage(err.Error()))
			} else {
				body, isHTML := pleaseWait(URL)
				if isHTML {
					w.Header().Set("Content-Type", "text/html")
				} else {
					w.Header().Set("Content-Type", "text/plain")
				}
				w.Write(body)
			}
		}
	} else {
		body, isHTML := pleaseWait(URL)
		if isHTML {
			w.Header().Set("Content-Type", "text/html")
		} else {
			w.Header().Set("Content-Type", "text/plain")
		}
		w.Write(body)
	}
}

func main() {
	// Read an existing configuration file or have the user supply settings
	conf, err := ReadConfigFile(CONFIG_FILE)
	if err != nil {
		fmt.Print("Could not read configuration file at " + CONFIG_FILE)
		Configuration = GetConfigFromUser()
	} else {
		Configuration = conf
	}
	// Ensure the LCS is available at startup time
	available := testLCSAvailability()
	if !available {
		fmt.Println("Local cache server is not responding to requests.")
		fmt.Println(LCS_RUN_INFO)
		return
	}
	// Ensure the RS is available at startup time
	available = testRSAvailability()
	if !available {
		fmt.Println("Request server is not responding to requests.")
		fmt.Println(RS_RUN_INFO)
		return
	}
	// Create an HTTP proxy server
	http.HandleFunc("/", proxyHandler)
	fmt.Println("CeNo proxy server listening at http://localhost" + Configuration.PortNumber)
	http.ListenAndServe(Configuration.PortNumber, nil)
}<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func getFileName(file string) string {
	tokens := strings.Split(file, string(os.PathSeparator))
	return tokens[len(tokens)-1]
}

func downloadFile(url string, path string) (string, error) {
	tokens := strings.Split(url, "/")
	fileName := tokens[len(tokens)-1]
	// support for twitter https://pbs.twimg.com/media/DdFIBS0VQAMhpmv.png:orig
	if subToken := strings.Split(fileName, ":"); len(subToken) == 2 {
		fileName = subToken[0]
	}
	// support for twitter https://pbs.twimg.com/media/xxxx.mp4?tag=3
	if subToken := strings.Split(fileName, "?"); len(subToken) == 2 {
		fileName = subToken[0]
	}

	fullPath := path + string(os.PathSeparator) + fileName

	if _, err := os.Stat(fullPath); err == nil {
		logger.Noticef("%s exists", fullPath)
		return fullPath, nil
	}

	output, err := os.Create(fullPath)
	if err != nil {
		logger.Errorf("%+v", err)
		return "", err
	}
	defer output.Close()

	logger.Debugf("--> Downloading %s", url)
	response, err := http.Get(url)
	if err != nil {
		logger.Errorf("%+v", err)
		return "", err
	}
	defer response.Body.Close()

	n, err := io.Copy(output, response.Body)
	if err != nil {
		logger.Errorf("%+v", err)
		return "", err
	}
	logger.Debugf("%s: %d bytes", fullPath, n)
	return fullPath, nil
}

func removeFile(url string, path string) error {
	tokens := strings.Split(url, "/")
	fileName := tokens[len(tokens)-1]
	logger.Debugf("--> Deleting %s", fileName)
	fullPath := path + string(os.PathSeparator) + fileName
	err := os.Remove(fullPath)
	if err != nil {
		logger.Errorf("%+v", err)
		return err
	}
	logger.Debugf("--> Deleted %s", fullPath)
	return nil
}

func probate(_type, _id string) error {
	logger.Noticef("probate %s: %s", _type, _id)
	switch _type {
	case "comic":
		fileName := "nhentai.net@" + _id + ".epub"
		return os.Rename(
			filepath.Join(telegramBot.ComicPath, fileName),
			filepath.Join(telegramBot.ComicPath, "probation", fileName),
		)
	case "pic":
		return os.Rename(
			filepath.Join(twitterBot.ImgPath, _id),
			filepath.Join(twitterBot.ImgPath, "probation", _id),
		)
	default:
		return fmt.Errorf("prohibit unkown type")
	}

}
<commit_msg>fix duplicate log<commit_after>package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func getFileName(file string) string {
	tokens := strings.Split(file, string(os.PathSeparator))
	return tokens[len(tokens)-1]
}

func downloadFile(url string, path string) (string, error) {
	tokens := strings.Split(url, "/")
	fileName := tokens[len(tokens)-1]
	// support for twitter https://pbs.twimg.com/media/DdFIBS0VQAMhpmv.png:orig
	if subToken := strings.Split(fileName, ":"); len(subToken) == 2 {
		fileName = subToken[0]
	}
	// support for twitter https://pbs.twimg.com/media/xxxx.mp4?tag=3
	if subToken := strings.Split(fileName, "?"); len(subToken) == 2 {
		fileName = subToken[0]
	}

	fullPath := path + string(os.PathSeparator) + fileName

	if _, err := os.Stat(fullPath); err == nil {
		logger.Noticef("%s exists", fullPath)
		return fullPath, nil
	}

	output, err := os.Create(fullPath)
	if err != nil {
		logger.Errorf("%+v", err)
		return "", err
	}
	defer output.Close()

	logger.Debugf("--> Downloading %s", url)
	response, err := http.Get(url)
	if err != nil {
		logger.Errorf("%+v", err)
		return "", err
	}
	defer response.Body.Close()

	n, err := io.Copy(output, response.Body)
	if err != nil {
		logger.Errorf("%+v", err)
		return "", err
	}
	logger.Debugf("%s: %d bytes", fullPath, n)
	return fullPath, nil
}

func removeFile(url string, path string) error {
	tokens := strings.Split(url, "/")
	fileName := tokens[len(tokens)-1]
	logger.Debugf("--> Deleting %s", fileName)
	fullPath := path + string(os.PathSeparator) + fileName
	err := os.Remove(fullPath)
	if err != nil {
		logger.Errorf("%+v", err)
		return err
	}
	logger.Debugf("--> Deleted %s", fullPath)
	return nil
}

func probate(_type, _id string) error {
	logger.Noticef("%s: %s", _type, _id)
	switch _type {
	case "comic":
		fileName := "nhentai.net@" + _id + ".epub"
		return os.Rename(
			filepath.Join(telegramBot.ComicPath, fileName),
			filepath.Join(telegramBot.ComicPath, "probation", fileName),
		)
	case "pic":
		return os.Rename(
			filepath.Join(twitterBot.ImgPath, _id),
			filepath.Join(twitterBot.ImgPath, "probation", _id),
		)
	default:
		return fmt.Errorf("prohibit unkown type")
	}

}
<|endoftext|>


<commit_before>package cc1100

import (
	"fmt"
	"log"
	"time"
)

const (
	usePolling      = false
	pollInterval    = time.Millisecond
	maxPacketLength = 100

	// Approximate time for one byte to be transmitted, based on
	// the data rate.  It was determined empirically so that few
	// if any iterations are needed in drainTxFifo().
	byteDuration = time.Millisecond
)

func (r *Radio) startRadio() {
	if !r.radioStarted {
		r.radioStarted = true
		go r.radio()
		go r.awaitInterrupts()
	}
}

func (r *Radio) Incoming() <-chan Packet {
	return r.receivedPackets
}

func (r *Radio) Outgoing() chan<- Packet {
	return r.transmittedPackets
}

func (r *Radio) radio() {
	err := r.changeState(SRX, STATE_RX)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case packet := <-r.transmittedPackets:
			err = r.transmit(packet.Data)
		case <-r.interrupt:
			err = r.receive()
		}
		if err != nil {
			log.Fatal(err)
		}
	}
}

func (r *Radio) awaitInterrupts() {
	for {
		if usePolling {
			n, _ := r.ReadNumRxBytes()
			if n == 0 {
				time.Sleep(pollInterval)
				continue
			}
		} else {
			r.interruptPin.Wait()
		}
		r.interrupt <- struct{}{}
	}
}

func (r *Radio) transmit(data []byte) error {
	if len(data) > maxPacketLength {
		return fmt.Errorf("packet too long (%d bytes)", len(data))
	}
	// Terminate packet with zero byte,
	// and pad with another to ensure final bytes
	// are transmitted before leaving TX state.
	err := r.WriteFifo(append(data, []byte{0, 0}...))
	if err != nil {
		return err
	}
	err = r.changeState(STX, STATE_TX)
	if err != nil {
		return err
	}
	return r.drainTxFifo(len(data) + 1)
}

func (r *Radio) drainTxFifo(numBytes int) error {
	time.Sleep(time.Duration(numBytes) * byteDuration)
	for {
		n, err := r.ReadNumTxBytes()
		if err != nil && err != TxFifoUnderflow {
			return err
		}
		if n == 0 || err == TxFifoUnderflow {
			r.PacketsSent++
			return nil
		}
		s, err := r.ReadState()
		if err != nil {
			return err
		}
		if s != STATE_TX && s != STATE_TXFIFO_UNDERFLOW {
			return fmt.Errorf("unexpected %s state during TXFIFO drain", StateName(s))
		}
		if verbose {
			log.Printf("waiting to transmit %d bytes\n", n)
		}
	}
}

func (r *Radio) receive() error {
	err := r.changeState(SRX, STATE_RX)
	if err != nil {
		return err
	}
	waiting := false
	for {
		numBytes, err := r.ReadNumRxBytes()
		if err == RxFifoOverflow {
			r.changeState(SRX, STATE_RX)
			continue
		} else if err != nil {
			return err
		}
		// Don't read last byte of FIFO if packet is still
		// being received. See Section 20 of data sheet.
		if numBytes < 2 {
			if waiting {
				return nil
			}
			waiting = true
			time.Sleep(byteDuration)
			continue
		}
		waiting = false
		c, err := r.ReadRegister(RXFIFO)
		if err != nil {
			return err
		}
		if c != 0 {
			err = r.receiveBuffer.WriteByte(c)
			if err != nil {
				return err
			}
			continue
		}
		// End of packet.
		rssi, err := r.ReadRSSI()
		if err != nil {
			return err
		}
		size := r.receiveBuffer.Len()
		if size != 0 {
			r.PacketsReceived++
			p := make([]byte, size)
			_, err := r.receiveBuffer.Read(p)
			if err != nil {
				return err
			}
			r.receiveBuffer.Reset()
			r.receivedPackets <- Packet{Rssi: rssi, Data: p}
		}
		return nil
	}
}

func (r *Radio) changeState(strobe byte, desired byte) error {
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	if verbose && s != desired {
		log.Printf("change from %s to %s\n", StateName(s), StateName(desired))
	}
	for {
		switch s {
		case desired:
			return nil
		case STATE_RXFIFO_OVERFLOW:
			s, err = r.Strobe(SFRX)
		case STATE_TXFIFO_UNDERFLOW:
			s, err = r.Strobe(SFTX)
		default:
			s, err = r.Strobe(strobe)
		}
		if err != nil {
			return err
		}
		s = (s >> STATE_SHIFT) & STATE_MASK
		if verbose {
			log.Printf("  %s\n", StateName(s))
		}
	}
}
<commit_msg>Change to IDLE state after transmitting<commit_after>package cc1100

import (
	"fmt"
	"log"
	"time"
)

const (
	usePolling      = false
	pollInterval    = time.Millisecond
	maxPacketLength = 100

	// Approximate time for one byte to be transmitted, based on
	// the data rate.  It was determined empirically so that few
	// if any iterations are needed in drainTxFifo().
	byteDuration = time.Millisecond
)

func (r *Radio) startRadio() {
	if !r.radioStarted {
		r.radioStarted = true
		go r.radio()
		go r.awaitInterrupts()
	}
}

func (r *Radio) Incoming() <-chan Packet {
	return r.receivedPackets
}

func (r *Radio) Outgoing() chan<- Packet {
	return r.transmittedPackets
}

func (r *Radio) radio() {
	err := r.changeState(SRX, STATE_RX)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case packet := <-r.transmittedPackets:
			err = r.transmit(packet.Data)
		case <-r.interrupt:
			err = r.receive()
		}
		if err != nil {
			log.Fatal(err)
		}
	}
}

func (r *Radio) awaitInterrupts() {
	for {
		if usePolling {
			n, _ := r.ReadNumRxBytes()
			if n == 0 {
				time.Sleep(pollInterval)
				continue
			}
		} else {
			r.interruptPin.Wait()
		}
		r.interrupt <- struct{}{}
	}
}

func (r *Radio) transmit(data []byte) error {
	if len(data) > maxPacketLength {
		return fmt.Errorf("packet too long (%d bytes)", len(data))
	}
	// Terminate packet with zero byte,
	// and pad with another to ensure final bytes
	// are transmitted before leaving TX state.
	err := r.WriteFifo(append(data, []byte{0, 0}...))
	if err != nil {
		return err
	}
	err = r.changeState(STX, STATE_TX)
	if err != nil {
		return err
	}
	return r.drainTxFifo(len(data) + 1)
}

func (r *Radio) drainTxFifo(numBytes int) error {
	time.Sleep(time.Duration(numBytes) * byteDuration)
	for {
		n, err := r.ReadNumTxBytes()
		if err != nil && err != TxFifoUnderflow {
			return err
		}
		if n == 0 || err == TxFifoUnderflow {
			r.PacketsSent++
			break
		}
		s, err := r.ReadState()
		if err != nil {
			return err
		}
		if s != STATE_TX && s != STATE_TXFIFO_UNDERFLOW {
			return fmt.Errorf("unexpected %s state during TXFIFO drain", StateName(s))
		}
		if verbose {
			log.Printf("waiting to transmit %d bytes\n", n)
		}
	}
	return r.changeState(SIDLE, STATE_IDLE)
}

func (r *Radio) receive() error {
	err := r.changeState(SRX, STATE_RX)
	if err != nil {
		return err
	}
	waiting := false
	for {
		numBytes, err := r.ReadNumRxBytes()
		if err == RxFifoOverflow {
			r.changeState(SRX, STATE_RX)
			continue
		} else if err != nil {
			return err
		}
		// Don't read last byte of FIFO if packet is still
		// being received. See Section 20 of data sheet.
		if numBytes < 2 {
			if waiting {
				return nil
			}
			waiting = true
			time.Sleep(byteDuration)
			continue
		}
		waiting = false
		c, err := r.ReadRegister(RXFIFO)
		if err != nil {
			return err
		}
		if c != 0 {
			err = r.receiveBuffer.WriteByte(c)
			if err != nil {
				return err
			}
			continue
		}
		// End of packet.
		rssi, err := r.ReadRSSI()
		if err != nil {
			return err
		}
		size := r.receiveBuffer.Len()
		if size != 0 {
			r.PacketsReceived++
			p := make([]byte, size)
			_, err := r.receiveBuffer.Read(p)
			if err != nil {
				return err
			}
			r.receiveBuffer.Reset()
			r.receivedPackets <- Packet{Rssi: rssi, Data: p}
		}
		return nil
	}
}

func (r *Radio) changeState(strobe byte, desired byte) error {
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	if verbose && s != desired {
		log.Printf("change from %s to %s\n", StateName(s), StateName(desired))
	}
	for {
		switch s {
		case desired:
			return nil
		case STATE_RXFIFO_OVERFLOW:
			s, err = r.Strobe(SFRX)
		case STATE_TXFIFO_UNDERFLOW:
			s, err = r.Strobe(SFTX)
		default:
			s, err = r.Strobe(strobe)
		}
		if err != nil {
			return err
		}
		s = (s >> STATE_SHIFT) & STATE_MASK
		if verbose {
			log.Printf("  %s\n", StateName(s))
		}
	}
}
<|endoftext|>