<commit_before>// (C) 2016 by Ricardo Branco
//
// MIT License
//
// v0.3.3
//
// TODO:
// + Support HMAC
// + Read filenames from file
// + Support -c option like md5sum(1)
// + Use getopt
// + Use different output formats for display

package main

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	ossl_blake2b "github.com/ricardobranco777/dgst/blake2b"
	ossl_blake2s "github.com/ricardobranco777/dgst/blake2s"
	ossl_md4 "github.com/ricardobranco777/dgst/md4"
	ossl_md5 "github.com/ricardobranco777/dgst/md5"
	ossl_ripemd160 "github.com/ricardobranco777/dgst/ripemd160"
	ossl_sha1 "github.com/ricardobranco777/dgst/sha1"
	ossl_sha256 "github.com/ricardobranco777/dgst/sha256"
	ossl_sha512 "github.com/ricardobranco777/dgst/sha512"
	"golang.org/x/crypto/blake2b"
	"golang.org/x/crypto/blake2s"
	"golang.org/x/crypto/md4"
	"golang.org/x/crypto/ripemd160"
	"golang.org/x/crypto/sha3"
	"hash"
	"io"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"
)

var hashes = map[string]*struct {
	sum string
	hash.Hash
	size int
}{
	"BLAKE2b256": {"", nil, 32},
	"BLAKE2b384": {"", nil, 48},
	"BLAKE2b512": {"", nil, 64},
	"BLAKE2s256": {"", nil, 32},
	"MD4":        {"", nil, 16},
	"MD5":        {"", nil, 16},
	"RIPEMD160":  {"", nil, 20},
	"SHA1":       {"", nil, 20},
	"SHA224":     {"", nil, 28},
	"SHA256":     {"", nil, 32},
	"SHA384":     {"", nil, 48},
	"SHA512":     {"", nil, 64},
	"SHA512-224": {"", nil, 28},
	"SHA512-256": {"", nil, 32},
	"SHA3-224":   {"", nil, 28},
	"SHA3-256":   {"", nil, 32},
	"SHA3-384":   {"", nil, 48},
	"SHA3-512":   {"", nil, 64},
}

// The keys to the above dictionary in sorted order
var keys []string

var progname string

func main() {
	progname = path.Base(os.Args[0])

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] [-s STRING...]|[FILE... DIRECTORY...]\n\n", progname)
		flag.PrintDefaults()
	}

	chosen := make(map[string]*bool)
	for h := range hashes {
		chosen[h] = flag.Bool(strings.ToLower(h), false, fmt.Sprintf("%s algorithm", h))
	}

	var all, ossl, isString *bool
	all = flag.Bool("all", false, "all algorithms")
	ossl = flag.Bool("ossl", false, "use OpenSSL")
	isString = flag.Bool("s", false, "treat arguments as strings")

	sha3_hashes := []string{}
	sha2_hashes := []string{}
	blake2_hashes := []string{}
	var size_hashes = map[int]*struct {
		hashes []string
		set    *bool
	}{
		128: {},
		160: {},
		224: {},
		256: {},
		384: {},
		512: {},
	}

	for h := range hashes {
		if strings.HasPrefix(h, "SHA3-") {
			sha3_hashes = append(sha3_hashes, h)
		} else if strings.HasPrefix(h, "SHA2") || strings.HasPrefix(h, "SHA384") || strings.HasPrefix(h, "SHA512") {
			sha2_hashes = append(sha2_hashes, h)
		} else if strings.HasPrefix(h, "BLAKE2") {
			blake2_hashes = append(blake2_hashes, h)
		}
		size_hashes[hashes[h].size*8].hashes = append(size_hashes[hashes[h].size*8].hashes, h)
	}

	for size := range size_hashes {
		sizeStr := strconv.Itoa(size)
		size_hashes[size].set = flag.Bool(sizeStr, false, "all "+sizeStr+" bits algorithms")
	}
	var sha3Opt, sha2Opt, blake2Opt *bool
	if len(sha3_hashes) > 0 {
		sha3Opt = flag.Bool("sha3", false, "all SHA-3 algorithms")
	}
	if len(sha2_hashes) > 0 {
		sha2Opt = flag.Bool("sha2", false, "all SHA-2 algorithms")
	}
	if len(blake2_hashes) > 0 {
		blake2Opt = flag.Bool("blake2", false, "all BLAKE2 algorithms")
	}

	flag.Parse()

	for size := range size_hashes {
		if !*(size_hashes[size].set) {
			continue
		}
		for _, h := range size_hashes[size].hashes {
			*chosen[h] = true
		}
	}

	if *sha3Opt {
		for _, h := range sha3_hashes {
			*chosen[h] = true
		}
	}
	if *sha2Opt {
		for _, h := range sha2_hashes {
			*chosen[h] = true
		}
	}
	if *blake2Opt {
		for _, h := range blake2_hashes {
			*chosen[h] = true
		}
	}

	if !(*all || choices(chosen)) {
		*all = true
	}

	for h := range chosen {
		if (*all && *chosen[h]) || !(*all || *chosen[h]) {
			delete(hashes, h)
		}
	}

	for k := range hashes {
		keys = append(keys, k)
		switch k {
		case "BLAKE2b256":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New256)
			} else {
				hashes[k].Hash = blake2_(blake2b.New256)
			}
		case "BLAKE2b384":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New384)
			} else {
				hashes[k].Hash = blake2_(blake2b.New384)
			}
		case "BLAKE2b512":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New512)
			} else {
				hashes[k].Hash = blake2_(blake2b.New512)
			}
		case "BLAKE2s256":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2s.New256)
			} else {
				hashes[k].Hash = blake2_(blake2s.New256)
			}
		case "MD4":
			if *ossl {
				hashes[k].Hash = ossl_md4.New()
			} else {
				hashes[k].Hash = md4.New()
			}
		case "MD5":
			if *ossl {
				hashes[k].Hash = ossl_md5.New()
			} else {
				hashes[k].Hash = md5.New()
			}
		case "RIPEMD160":
			if *ossl {
				hashes[k].Hash = ossl_ripemd160.New()
			} else {
				hashes[k].Hash = ripemd160.New()
			}
		case "SHA1":
			if *ossl {
				hashes[k].Hash = ossl_sha1.New()
			} else {
				hashes[k].Hash = sha1.New()
			}
		case "SHA224":
			if *ossl {
				hashes[k].Hash = ossl_sha256.New224()
			} else {
				hashes[k].Hash = sha256.New224()
			}
		case "SHA256":
			if *ossl {
				hashes[k].Hash = ossl_sha256.New()
			} else {
				hashes[k].Hash = sha256.New()
			}
		case "SHA384":
			if *ossl {
				hashes[k].Hash = ossl_sha512.New384()
			} else {
				hashes[k].Hash = sha512.New384()
			}
		case "SHA512":
			if *ossl {
				hashes[k].Hash = ossl_sha512.New()
			} else {
				hashes[k].Hash = sha512.New()
			}
		case "SHA512-224":
			hashes[k].Hash = sha512.New512_224()
		case "SHA512-256":
			hashes[k].Hash = sha512.New512_256()
		case "SHA3-224":
			hashes[k].Hash = sha3.New224()
		case "SHA3-256":
			hashes[k].Hash = sha3.New256()
		case "SHA3-384":
			hashes[k].Hash = sha3.New384()
		case "SHA3-512":
			hashes[k].Hash = sha3.New512()
		}
	}

	sort.Strings(keys)

	if len(hashes) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if flag.NArg() == 0 {
		hash_stdin()
		os.Exit(0)
	}

	var errors bool

	if *isString {
		for _, s := range flag.Args() {
			hash_string(s)
		}
	} else {
		for _, pathname := range flag.Args() {
			info, err := os.Stat(pathname)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
				errors = true
			} else if info.IsDir() {
				errors = hash_dir(pathname)
			} else {
				errors = hash_file(pathname)
			}
		}
	}

	if errors {
		os.Exit(1)
	}
}

// Wrapper for the Blake2 New() methods that needs an optional for MAC
func blake2_(f func([]byte) (hash.Hash, error)) hash.Hash {
	h, _ := f(nil)
	return h
}

// Returns true if at least some algorithm was specified on the command line
func choices(chosen map[string]*bool) bool {
	for h := range chosen {
		if *chosen[h] {
			return true
		}
	}
	return false
}

func display() {
	for _, k := range keys {
		fmt.Println(hashes[k].sum)
	}
}

func hash_string(str string) {
	var wg sync.WaitGroup
	wg.Add(len(hashes))
	for h := range hashes {
		go func(h string) {
			defer wg.Done()
			hashes[h].Write([]byte(str))
			hashes[h].sum = fmt.Sprintf("%s(\"%s\") = %x", h, str, hashes[h].Sum(nil))
			hashes[h].Reset()
		}(h)
	}
	wg.Wait()
	display()
}

func hash_file(filename string) (errors bool) {
	done := make(chan error)
	defer close(done)
	for h := range hashes {
		go func(h string) {
			f, err := os.Open(filename)
			if err != nil {
				done <- err
				return
			}
			defer f.Close()

			if _, err := io.Copy(hashes[h], f); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s(%s) = %x", h, filename, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if (!errors) {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if (!errors) {
		display()
	}
	return
}

func visit(path string, f os.FileInfo, err error) error {
	if err != nil && !os.IsPermission(err) {
		return err
	}
	if f.Mode().IsRegular() {
		hash_file(path)
	}
	return nil
}

func hash_dir(dir string) bool {
	err := filepath.Walk(dir, visit)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
		return false
	}
	return true
}

func hash_stdin() (errors bool) {
	done := make(chan error)
	defer close(done)
	for h := range hashes {
		go func(h string) {
			if _, err := io.Copy(hashes[h], os.Stdin); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s() = %x", h, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if !errors {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if (!errors) {
		display()
	}
	return
}
<commit_msg>Use buffered channel created only once<commit_after>// (C) 2016 by Ricardo Branco
//
// MIT License
//
// v0.3.3
//
// TODO:
// + Support HMAC
// + Read filenames from file
// + Support -c option like md5sum(1)
// + Use getopt
// + Use different output formats for display

package main

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	ossl_blake2b "github.com/ricardobranco777/dgst/blake2b"
	ossl_blake2s "github.com/ricardobranco777/dgst/blake2s"
	ossl_md4 "github.com/ricardobranco777/dgst/md4"
	ossl_md5 "github.com/ricardobranco777/dgst/md5"
	ossl_ripemd160 "github.com/ricardobranco777/dgst/ripemd160"
	ossl_sha1 "github.com/ricardobranco777/dgst/sha1"
	ossl_sha256 "github.com/ricardobranco777/dgst/sha256"
	ossl_sha512 "github.com/ricardobranco777/dgst/sha512"
	"golang.org/x/crypto/blake2b"
	"golang.org/x/crypto/blake2s"
	"golang.org/x/crypto/md4"
	"golang.org/x/crypto/ripemd160"
	"golang.org/x/crypto/sha3"
	"hash"
	"io"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"
)

var hashes = map[string]*struct {
	sum string
	hash.Hash
	size int
}{
	"BLAKE2b256": {"", nil, 32},
	"BLAKE2b384": {"", nil, 48},
	"BLAKE2b512": {"", nil, 64},
	"BLAKE2s256": {"", nil, 32},
	"MD4":        {"", nil, 16},
	"MD5":        {"", nil, 16},
	"RIPEMD160":  {"", nil, 20},
	"SHA1":       {"", nil, 20},
	"SHA224":     {"", nil, 28},
	"SHA256":     {"", nil, 32},
	"SHA384":     {"", nil, 48},
	"SHA512":     {"", nil, 64},
	"SHA512-224": {"", nil, 28},
	"SHA512-256": {"", nil, 32},
	"SHA3-224":   {"", nil, 28},
	"SHA3-256":   {"", nil, 32},
	"SHA3-384":   {"", nil, 48},
	"SHA3-512":   {"", nil, 64},
}

// The keys to the above dictionary in sorted order
var keys []string

var progname string

var done chan error

func main() {
	progname = path.Base(os.Args[0])

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] [-s STRING...]|[FILE... DIRECTORY...]\n\n", progname)
		flag.PrintDefaults()
	}

	chosen := make(map[string]*bool)
	for h := range hashes {
		chosen[h] = flag.Bool(strings.ToLower(h), false, fmt.Sprintf("%s algorithm", h))
	}

	var all, ossl, isString *bool
	all = flag.Bool("all", false, "all algorithms")
	ossl = flag.Bool("ossl", false, "use OpenSSL")
	isString = flag.Bool("s", false, "treat arguments as strings")

	sha3_hashes := []string{}
	sha2_hashes := []string{}
	blake2_hashes := []string{}
	var size_hashes = map[int]*struct {
		hashes []string
		set    *bool
	}{
		128: {},
		160: {},
		224: {},
		256: {},
		384: {},
		512: {},
	}

	for h := range hashes {
		if strings.HasPrefix(h, "SHA3-") {
			sha3_hashes = append(sha3_hashes, h)
		} else if strings.HasPrefix(h, "SHA2") || strings.HasPrefix(h, "SHA384") || strings.HasPrefix(h, "SHA512") {
			sha2_hashes = append(sha2_hashes, h)
		} else if strings.HasPrefix(h, "BLAKE2") {
			blake2_hashes = append(blake2_hashes, h)
		}
		size_hashes[hashes[h].size*8].hashes = append(size_hashes[hashes[h].size*8].hashes, h)
	}

	for size := range size_hashes {
		sizeStr := strconv.Itoa(size)
		size_hashes[size].set = flag.Bool(sizeStr, false, "all "+sizeStr+" bits algorithms")
	}
	var sha3Opt, sha2Opt, blake2Opt *bool
	if len(sha3_hashes) > 0 {
		sha3Opt = flag.Bool("sha3", false, "all SHA-3 algorithms")
	}
	if len(sha2_hashes) > 0 {
		sha2Opt = flag.Bool("sha2", false, "all SHA-2 algorithms")
	}
	if len(blake2_hashes) > 0 {
		blake2Opt = flag.Bool("blake2", false, "all BLAKE2 algorithms")
	}

	flag.Parse()

	for size := range size_hashes {
		if !*(size_hashes[size].set) {
			continue
		}
		for _, h := range size_hashes[size].hashes {
			*chosen[h] = true
		}
	}

	if *sha3Opt {
		for _, h := range sha3_hashes {
			*chosen[h] = true
		}
	}
	if *sha2Opt {
		for _, h := range sha2_hashes {
			*chosen[h] = true
		}
	}
	if *blake2Opt {
		for _, h := range blake2_hashes {
			*chosen[h] = true
		}
	}

	if !(*all || choices(chosen)) {
		*all = true
	}

	for h := range chosen {
		if (*all && *chosen[h]) || !(*all || *chosen[h]) {
			delete(hashes, h)
		}
	}

	for k := range hashes {
		keys = append(keys, k)
		switch k {
		case "BLAKE2b256":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New256)
			} else {
				hashes[k].Hash = blake2_(blake2b.New256)
			}
		case "BLAKE2b384":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New384)
			} else {
				hashes[k].Hash = blake2_(blake2b.New384)
			}
		case "BLAKE2b512":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New512)
			} else {
				hashes[k].Hash = blake2_(blake2b.New512)
			}
		case "BLAKE2s256":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2s.New256)
			} else {
				hashes[k].Hash = blake2_(blake2s.New256)
			}
		case "MD4":
			if *ossl {
				hashes[k].Hash = ossl_md4.New()
			} else {
				hashes[k].Hash = md4.New()
			}
		case "MD5":
			if *ossl {
				hashes[k].Hash = ossl_md5.New()
			} else {
				hashes[k].Hash = md5.New()
			}
		case "RIPEMD160":
			if *ossl {
				hashes[k].Hash = ossl_ripemd160.New()
			} else {
				hashes[k].Hash = ripemd160.New()
			}
		case "SHA1":
			if *ossl {
				hashes[k].Hash = ossl_sha1.New()
			} else {
				hashes[k].Hash = sha1.New()
			}
		case "SHA224":
			if *ossl {
				hashes[k].Hash = ossl_sha256.New224()
			} else {
				hashes[k].Hash = sha256.New224()
			}
		case "SHA256":
			if *ossl {
				hashes[k].Hash = ossl_sha256.New()
			} else {
				hashes[k].Hash = sha256.New()
			}
		case "SHA384":
			if *ossl {
				hashes[k].Hash = ossl_sha512.New384()
			} else {
				hashes[k].Hash = sha512.New384()
			}
		case "SHA512":
			if *ossl {
				hashes[k].Hash = ossl_sha512.New()
			} else {
				hashes[k].Hash = sha512.New()
			}
		case "SHA512-224":
			hashes[k].Hash = sha512.New512_224()
		case "SHA512-256":
			hashes[k].Hash = sha512.New512_256()
		case "SHA3-224":
			hashes[k].Hash = sha3.New224()
		case "SHA3-256":
			hashes[k].Hash = sha3.New256()
		case "SHA3-384":
			hashes[k].Hash = sha3.New384()
		case "SHA3-512":
			hashes[k].Hash = sha3.New512()
		}
	}

	sort.Strings(keys)

	if len(hashes) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if flag.NArg() == 0 {
		hash_stdin()
		os.Exit(0)
	}

	var errors bool

	if *isString {
		for _, s := range flag.Args() {
			hash_string(s)
		}
	} else {
		done = make(chan error, len(hashes))
		defer close(done)

		for _, pathname := range flag.Args() {
			info, err := os.Stat(pathname)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
				errors = true
			} else if info.IsDir() {
				errors = hash_dir(pathname)
			} else {
				errors = hash_file(pathname)
			}
		}
	}

	if errors {
		os.Exit(1)
	}
}

// Wrapper for the Blake2 New() methods that needs an optional for MAC
func blake2_(f func([]byte) (hash.Hash, error)) hash.Hash {
	h, _ := f(nil)
	return h
}

// Returns true if at least some algorithm was specified on the command line
func choices(chosen map[string]*bool) bool {
	for h := range chosen {
		if *chosen[h] {
			return true
		}
	}
	return false
}

func display() {
	for _, k := range keys {
		fmt.Println(hashes[k].sum)
	}
}

func hash_string(str string) {
	var wg sync.WaitGroup
	wg.Add(len(hashes))
	for h := range hashes {
		go func(h string) {
			defer wg.Done()
			hashes[h].Write([]byte(str))
			hashes[h].sum = fmt.Sprintf("%s(\"%s\") = %x", h, str, hashes[h].Sum(nil))
			hashes[h].Reset()
		}(h)
	}
	wg.Wait()
	display()
}

func hash_file(filename string) (errors bool) {
	for h := range hashes {
		go func(h string) {
			f, err := os.Open(filename)
			if err != nil {
				done <- err
				return
			}
			defer f.Close()

			if _, err := io.Copy(hashes[h], f); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s(%s) = %x", h, filename, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if (!errors) {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if (!errors) {
		display()
	}
	return
}

func visit(path string, f os.FileInfo, err error) error {
	if err != nil && !os.IsPermission(err) {
		return err
	}
	if f.Mode().IsRegular() {
		hash_file(path)
	}
	return nil
}

func hash_dir(dir string) bool {
	err := filepath.Walk(dir, visit)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
		return false
	}
	return true
}

func hash_stdin() (errors bool) {
	for h := range hashes {
		go func(h string) {
			if _, err := io.Copy(hashes[h], os.Stdin); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s() = %x", h, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if !errors {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if (!errors) {
		display()
	}
	return
}
<|endoftext|>


<commit_before>package dns

import (
	"fmt"
	"io"
	"strconv"
	"strings"
	"text/scanner"
)

// Only used when debugging the parser itself.
var _DEBUG = false

// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
// * Add ownernames if they are left blank;
// * Suppress sequences of spaces;
// * Make each RR fit on one line (NEWLINE is send as last)
// * Handle comments: ;
// * Handle braces.
const (
	// Zonefile
	_EOF = iota // Don't let it start with zero
	_STRING
	_BLANK
	_NEWLINE
	_RRTYPE
	_OWNER
	_CLASS

	// Privatekey file
	_VALUE
	_KEY

	_EXPECT_OWNER          // Ownername
	_EXPECT_OWNER_BL       // Whitespace after the ownername
	_EXPECT_ANY            // Expect rrtype, ttl or class
	_EXPECT_ANY_NOCLASS    // Expect rrtype or ttl
	_EXPECT_ANY_NOCLASS_BL // The Whitespace after _EXPECT_ANY_NOCLASS
	_EXPECT_ANY_NOTTL      // Expect rrtype or class
	_EXPECT_ANY_NOTTL_BL   // Whitespace after _EXPECT_ANY_NOTTL
	_EXPECT_RRTYPE         // Expect rrtype
	_EXPECT_RRTYPE_BL      // Whitespace BEFORE rrtype
	_EXPECT_RDATA          // The first element of the rdata
)

type ParseError struct {
	err string
	lex lex
}

func (e *ParseError) Error() string {
	va := strconv.Itoa(e.lex.value)
	s := e.err + ": `" + e.lex.token + "' (value: " + va + ") at line: " +
		strconv.Itoa(e.lex.line) + " and column: " +
		strconv.Itoa(e.lex.column)
	return s
}

type lex struct {
	token  string // text of the token
	value  int    // value: _STRING, _BLANK, etc.
	line   int    // line in the file
	column int    // column in the fil
}

type Token struct {
	Rr    RR          // the scanned resource record
	Error *ParseError // when an error occured, this is the specifics
}

// NewRR parses the string s and returns the RR contained in there. If the string
// contains more than one RR, only the first is returned. If an error is detected
// that error error is returned.
// If the class is not specified, the IN class is assumed. If the TTL is not
// specified DefaultTtl is assumed.
func NewRR(s string) (RR, error) {
	t := make(chan Token)
	if s[len(s)-1] != '\n' { // We need a closing newline
		go ParseZone(strings.NewReader(s+"\n"), t)
	} else {
		go ParseZone(strings.NewReader(s), t)
	}
	r := <-t
	if r.Error != nil {
		return nil, r.Error
	}
	return r.Rr, nil
}

// ParseZone reads a RFC 1035 zone from r. It returns each parsed RR or on error
// on the channel t. The channel t is closed by ParseZone when the end of r is reached.
// Basic usage pattern:
// go ParseZone
func ParseZone(r io.Reader, t chan Token) {
	defer close(t)
	var s scanner.Scanner
	c := make(chan lex)
	s.Init(r)
	s.Mode = 0
	s.Whitespace = 0
	// Start the lexer
	go zlexer(s, c)
	// 5 possible beginnings of a line, _ is a space
	// 1. _OWNER _ _RRTYPE                     -> class/ttl omitted
	// 2. _OWNER _ _STRING _ _RRTYPE           -> class omitted
	// 3. _OWNER _ _STRING _ _CLASS  _ _RRTYPE -> ttl/class
	// 4. _OWNER _ _CLASS  _ _RRTYPE           -> ttl omitted
	// 5. _OWNER _ _CLASS  _ _STRING _ _RRTYPE -> class/ttl (reversed)
	// After detecting these, we know the _RRTYPE so we can jump to functions
	// handling the rdata for each of these types.
	st := _EXPECT_OWNER
	var h RR_Header
	var ok bool
	for l := range c {
		if _DEBUG {
			fmt.Printf("[%v]\n", l)
		}
		switch st {
		case _EXPECT_OWNER:
			// Set the defaults here
			h.Ttl = DefaultTtl
			h.Class = ClassINET
			switch l.value {
			case _NEWLINE: // Empty line
				st = _EXPECT_OWNER
			case _OWNER:
				h.Name = l.token
				st = _EXPECT_OWNER_BL
			default:
				t <- Token{Error: &ParseError{"Error at the start", l}}
				return
				//st = _EXPECT_OWNER
			}
		case _EXPECT_OWNER_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank after owner", l}}
				return
			}
			st = _EXPECT_ANY
		case _EXPECT_ANY:
			switch l.value {
			case _RRTYPE:
				h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
				st = _EXPECT_RDATA
			case _CLASS:
				h.Class, ok = Str_class[strings.ToUpper(l.token)]
				if !ok {
					t <- Token{Error: &ParseError{"Unknown class", l}}
					return
				}
				st = _EXPECT_ANY_NOCLASS_BL
			case _STRING: // TTL is this case
				ttl, ok := strconv.Atoi(l.token)
				if ok != nil {
					t <- Token{Error: &ParseError{"Not a TTL", l}}
					return
				} else {
					h.Ttl = uint32(ttl)
				}
				st = _EXPECT_ANY_NOTTL_BL
			default:
				t <- Token{Error: &ParseError{"Expecting RR type, TTL or class, not this...", l}}
				return
			}
		case _EXPECT_ANY_NOCLASS_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank before NOCLASS", l}}
				return
			}
			st = _EXPECT_ANY_NOCLASS
		case _EXPECT_ANY_NOTTL_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank before NOTTL", l}}
				return
			}
			st = _EXPECT_ANY_NOTTL
		case _EXPECT_ANY_NOTTL:
			switch l.value {
			case _CLASS:
				h.Class, ok = Str_class[strings.ToUpper(l.token)]
				if !ok {
					t <- Token{Error: &ParseError{"Unknown class", l}}
					return
				}
				st = _EXPECT_RRTYPE_BL
			case _RRTYPE:
				h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
				st = _EXPECT_RDATA
			}
		case _EXPECT_ANY_NOCLASS:
			switch l.value {
			case _STRING: // TTL
				ttl, ok := strconv.Atoi(l.token)
				if ok != nil {
					t <- Token{Error: &ParseError{"Not a TTL", l}}
					return
				} else {
					h.Ttl = uint32(ttl)
				}
				st = _EXPECT_RRTYPE_BL
			case _RRTYPE:
				h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
				st = _EXPECT_RDATA
			default:
				t <- Token{Error: &ParseError{"Expecting RR type or TTL, not this...", l}}
				return
			}
		case _EXPECT_RRTYPE_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank after", l}}
				return
			}
			st = _EXPECT_RRTYPE
		case _EXPECT_RRTYPE:
			if l.value != _RRTYPE {
				t <- Token{Error: &ParseError{"Unknown RR type", l}}
				return
			}
			h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
			st = _EXPECT_RDATA
		case _EXPECT_RDATA:
			// I could save my token here...? l
			r, e := setRR(h, c)
			if e != nil {
				// If e.lex is nil than we have encounter a unknown RR type
				// in that case we substitute our current lex token
				if e.lex.token == "" && e.lex.value == 0 {
					e.lex = l // Uh, dirty
				}
				t <- Token{Error: e}
				return
			}
			t <- Token{Rr: r}
			st = _EXPECT_OWNER
		}
	}
}

func (l lex) String() string {
	switch l.value {
	case _STRING:
		return l.token
	case _BLANK:
		return " " //"_" // seems to work, make then invisible for now
	case _NEWLINE:
		return "|\n"
	case _RRTYPE:
		return "R:" + l.token
	case _OWNER:
		return "O:" + l.token
	case _CLASS:
		return "C:" + l.token
	}
	return ""
}

// zlexer scans the sourcefile and returns tokens on the channel c.
func zlexer(s scanner.Scanner, c chan lex) {
	var l lex
	str := "" // Hold the current read text
	quote := false
	space := false
	commt := false
	rrtype := false
	owner := true
	brace := 0
	tok := s.Scan()
	defer close(c)
	for tok != scanner.EOF {
		l.column = s.Position.Column
		l.line = s.Position.Line
		switch x := s.TokenText(); x {
		case " ", "\t":
			if commt {
				break
			}
			if str == "" {
				//l.value = _BLANK
				//l.token = " "
			} else if owner {
				// If we have a string and its the first, make it an owner
				l.value = _OWNER
				l.token = str
				c <- l
			} else {
				l.value = _STRING
				l.token = str

				if !rrtype {
					if _, ok := Str_rr[strings.ToUpper(l.token)]; ok {
						l.value = _RRTYPE
						rrtype = true // We've seen one
					}
					if _, ok := Str_class[strings.ToUpper(l.token)]; ok {
						l.value = _CLASS
					}
				}
				c <- l
			}
			str = ""
			if !space && !commt {
				l.value = _BLANK
				l.token = " "
				c <- l
			}
			space = true
			owner = false
		case ";":
			if quote {
				// Inside quoted text we allow ;
				str += ";"
				break
			}
			commt = true
		case "\n":
			if commt {
				// Reset a comment
				commt = false
				rrtype = false
				str = ""
				break
			}
			if str != "" {
				l.value = _STRING
				l.token = str
				c <- l
			}
			if brace > 0 {
				l.value = _BLANK
				l.token = " "
				if !space {
					c <- l
				}
			} else {
				l.value = _NEWLINE
				l.token = "\n"
				c <- l
			}
			if l.value == _BLANK {
				space = true
			}

			str = ""
			commt = false
			rrtype = false
			owner = true
		case "\"":
			if commt {
				break
			}
			// str += "\"" don't add quoted quotes
			quote = !quote
		case "(":
			if commt {
				break
			}
			brace++
		case ")":
			if commt {
				break
			}
			brace--
			if brace < 0 {
				fmt.Printf("%s\n", &ParseError{"Extra closing brace", l})
			}
		default:
			if commt {
				break
			}
			str += x
			space = false
		}
		tok = s.Scan()
	}
}
<commit_msg>Some typos<commit_after>package dns

import (
	"fmt"
	"io"
	"strconv"
	"strings"
	"text/scanner"
)

// Only used when debugging the parser itself.
var _DEBUG = false

// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
// * Add ownernames if they are left blank;
// * Suppress sequences of spaces;
// * Make each RR fit on one line (NEWLINE is send as last)
// * Handle comments: ;
// * Handle braces.
const (
	// Zonefile
	_EOF = iota // Don't let it start with zero
	_STRING
	_BLANK
	_NEWLINE
	_RRTYPE
	_OWNER
	_CLASS

	// Privatekey file
	_VALUE
	_KEY

	_EXPECT_OWNER          // Ownername
	_EXPECT_OWNER_BL       // Whitespace after the ownername
	_EXPECT_ANY            // Expect rrtype, ttl or class
	_EXPECT_ANY_NOCLASS    // Expect rrtype or ttl
	_EXPECT_ANY_NOCLASS_BL // The Whitespace after _EXPECT_ANY_NOCLASS
	_EXPECT_ANY_NOTTL      // Expect rrtype or class
	_EXPECT_ANY_NOTTL_BL   // Whitespace after _EXPECT_ANY_NOTTL
	_EXPECT_RRTYPE         // Expect rrtype
	_EXPECT_RRTYPE_BL      // Whitespace BEFORE rrtype
	_EXPECT_RDATA          // The first element of the rdata
)

// ParseError contains the parse error and the location in the io.Reader
// where the error occured.
type ParseError struct {
	err string
	lex lex
}

func (e *ParseError) Error() string {
	va := strconv.Itoa(e.lex.value)
	s := e.err + ": `" + e.lex.token + "' (value: " + va + ") at line: " +
		strconv.Itoa(e.lex.line) + " and column: " +
		strconv.Itoa(e.lex.column)
	return s
}

type lex struct {
	token  string // text of the token
	value  int    // value: _STRING, _BLANK, etc.
	line   int    // line in the file
	column int    // column in the fil
}

type Token struct {
	Rr    RR          // the scanned resource record
	Error *ParseError // when an error occured, this is the specifics
}

// NewRR parses the string s and returns the RR contained in there. If the string
// contains more than one RR, only the first is returned. If an error is detected
// that error is returned.
// If the class is not specified, the IN class is assumed. If the TTL is not
// specified DefaultTtl is assumed.
func NewRR(s string) (RR, error) {
	t := make(chan Token)
	if s[len(s)-1] != '\n' { // We need a closing newline
		go ParseZone(strings.NewReader(s+"\n"), t)
	} else {
		go ParseZone(strings.NewReader(s), t)
	}
	r := <-t
	if r.Error != nil {
		return nil, r.Error
	}
	return r.Rr, nil
}

// ParseZone reads a RFC 1035 zone from r. It returns each parsed RR or on error
// on the channel t. The channel t is closed by ParseZone when the end of r is reached.
// Basic usage pattern:
// go ParseZone
func ParseZone(r io.Reader, t chan Token) {
	defer close(t)
	var s scanner.Scanner
	c := make(chan lex)
	s.Init(r)
	s.Mode = 0
	s.Whitespace = 0
	// Start the lexer
	go zlexer(s, c)
	// 5 possible beginnings of a line, _ is a space
	// 1. _OWNER _ _RRTYPE                     -> class/ttl omitted
	// 2. _OWNER _ _STRING _ _RRTYPE           -> class omitted
	// 3. _OWNER _ _STRING _ _CLASS  _ _RRTYPE -> ttl/class
	// 4. _OWNER _ _CLASS  _ _RRTYPE           -> ttl omitted
	// 5. _OWNER _ _CLASS  _ _STRING _ _RRTYPE -> class/ttl (reversed)
	// After detecting these, we know the _RRTYPE so we can jump to functions
	// handling the rdata for each of these types.
	st := _EXPECT_OWNER
	var h RR_Header
	var ok bool
	for l := range c {
		if _DEBUG {
			fmt.Printf("[%v]\n", l)
		}
		switch st {
		case _EXPECT_OWNER:
			// Set the defaults here
			h.Ttl = DefaultTtl
			h.Class = ClassINET
			switch l.value {
			case _NEWLINE: // Empty line
				st = _EXPECT_OWNER
			case _OWNER:
				h.Name = l.token
				st = _EXPECT_OWNER_BL
			default:
				t <- Token{Error: &ParseError{"Error at the start", l}}
				return
				//st = _EXPECT_OWNER
			}
		case _EXPECT_OWNER_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank after owner", l}}
				return
			}
			st = _EXPECT_ANY
		case _EXPECT_ANY:
			switch l.value {
			case _RRTYPE:
				h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
				st = _EXPECT_RDATA
			case _CLASS:
				h.Class, ok = Str_class[strings.ToUpper(l.token)]
				if !ok {
					t <- Token{Error: &ParseError{"Unknown class", l}}
					return
				}
				st = _EXPECT_ANY_NOCLASS_BL
			case _STRING: // TTL is this case
				ttl, ok := strconv.Atoi(l.token)
				if ok != nil {
					t <- Token{Error: &ParseError{"Not a TTL", l}}
					return
				} else {
					h.Ttl = uint32(ttl)
				}
				st = _EXPECT_ANY_NOTTL_BL
			default:
				t <- Token{Error: &ParseError{"Expecting RR type, TTL or class, not this...", l}}
				return
			}
		case _EXPECT_ANY_NOCLASS_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank before NOCLASS", l}}
				return
			}
			st = _EXPECT_ANY_NOCLASS
		case _EXPECT_ANY_NOTTL_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank before NOTTL", l}}
				return
			}
			st = _EXPECT_ANY_NOTTL
		case _EXPECT_ANY_NOTTL:
			switch l.value {
			case _CLASS:
				h.Class, ok = Str_class[strings.ToUpper(l.token)]
				if !ok {
					t <- Token{Error: &ParseError{"Unknown class", l}}
					return
				}
				st = _EXPECT_RRTYPE_BL
			case _RRTYPE:
				h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
				st = _EXPECT_RDATA
			}
		case _EXPECT_ANY_NOCLASS:
			switch l.value {
			case _STRING: // TTL
				ttl, ok := strconv.Atoi(l.token)
				if ok != nil {
					t <- Token{Error: &ParseError{"Not a TTL", l}}
					return
				} else {
					h.Ttl = uint32(ttl)
				}
				st = _EXPECT_RRTYPE_BL
			case _RRTYPE:
				h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
				st = _EXPECT_RDATA
			default:
				t <- Token{Error: &ParseError{"Expecting RR type or TTL, not this...", l}}
				return
			}
		case _EXPECT_RRTYPE_BL:
			if l.value != _BLANK {
				t <- Token{Error: &ParseError{"No blank after", l}}
				return
			}
			st = _EXPECT_RRTYPE
		case _EXPECT_RRTYPE:
			if l.value != _RRTYPE {
				t <- Token{Error: &ParseError{"Unknown RR type", l}}
				return
			}
			h.Rrtype, _ = Str_rr[strings.ToUpper(l.token)]
			st = _EXPECT_RDATA
		case _EXPECT_RDATA:
			// I could save my token here...? l
			r, e := setRR(h, c)
			if e != nil {
				// If e.lex is nil than we have encounter a unknown RR type
				// in that case we substitute our current lex token
				if e.lex.token == "" && e.lex.value == 0 {
					e.lex = l // Uh, dirty
				}
				t <- Token{Error: e}
				return
			}
			t <- Token{Rr: r}
			st = _EXPECT_OWNER
		}
	}
}

func (l lex) String() string {
	switch l.value {
	case _STRING:
		return l.token
	case _BLANK:
		return " " //"_" // seems to work, make then invisible for now
	case _NEWLINE:
		return "|\n"
	case _RRTYPE:
		return "R:" + l.token
	case _OWNER:
		return "O:" + l.token
	case _CLASS:
		return "C:" + l.token
	}
	return ""
}

// zlexer scans the sourcefile and returns tokens on the channel c.
func zlexer(s scanner.Scanner, c chan lex) {
	var l lex
	str := "" // Hold the current read text
	quote := false
	space := false
	commt := false
	rrtype := false
	owner := true
	brace := 0
	tok := s.Scan()
	defer close(c)
	for tok != scanner.EOF {
		l.column = s.Position.Column
		l.line = s.Position.Line
		switch x := s.TokenText(); x {
		case " ", "\t":
			if commt {
				break
			}
			if str == "" {
				//l.value = _BLANK
				//l.token = " "
			} else if owner {
				// If we have a string and its the first, make it an owner
				l.value = _OWNER
				l.token = str
				c <- l
			} else {
				l.value = _STRING
				l.token = str

				if !rrtype {
					if _, ok := Str_rr[strings.ToUpper(l.token)]; ok {
						l.value = _RRTYPE
						rrtype = true // We've seen one
					}
					if _, ok := Str_class[strings.ToUpper(l.token)]; ok {
						l.value = _CLASS
					}
				}
				c <- l
			}
			str = ""
			if !space && !commt {
				l.value = _BLANK
				l.token = " "
				c <- l
			}
			space = true
			owner = false
		case ";":
			if quote {
				// Inside quoted text we allow ;
				str += ";"
				break
			}
			commt = true
		case "\n":
			if commt {
				// Reset a comment
				commt = false
				rrtype = false
				str = ""
				break
			}
			if str != "" {
				l.value = _STRING
				l.token = str
				c <- l
			}
			if brace > 0 {
				l.value = _BLANK
				l.token = " "
				if !space {
					c <- l
				}
			} else {
				l.value = _NEWLINE
				l.token = "\n"
				c <- l
			}
			if l.value == _BLANK {
				space = true
			}

			str = ""
			commt = false
			rrtype = false
			owner = true
		case "\"":
			if commt {
				break
			}
			// str += "\"" don't add quoted quotes
			quote = !quote
		case "(":
			if commt {
				break
			}
			brace++
		case ")":
			if commt {
				break
			}
			brace--
			if brace < 0 {
				fmt.Printf("%s\n", &ParseError{"Extra closing brace", l})
			}
		default:
			if commt {
				break
			}
			str += x
			space = false
		}
		tok = s.Scan()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"net/url"
	"time"
)

// 認可コード発行。
func publishCode(w http.ResponseWriter, r *http.Request, sys *system, sess *session) error {

	authReq := sess.request() // commit すると消えるので取っとく。

	consScops, consClms, denyScops, denyClms := sess.commit()

	if !consScops[scopOpId] {
		// openid すら許されなかった。
		return redirectError(w, r, sys, sess, authReq, newIdpError(errAccDeny, "user denied openid", 0, nil))
	}

	codId, err := sys.codCont.newId()
	if err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}
	cod := newCode(
		codId,
		sess.currentAccount(),
		authReq.ta(),
		authReq.redirectUri().String(),
		time.Now().Add(sys.codExpiDur),
		sys.tokExpiDur,
		consScops,
		consClms,
		authReq.nonce(),
		sess.currentAccountDate(),
	)
	log.Debug("Code " + mosaic(cod.id()) + " was generated.")

	if err := sys.codCont.put(cod); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}

	// 認可コードを発行した。
	log.Debug("Code " + mosaic(cod.id()) + " was published")

	if sess.id() == "" {
		id, err := sys.sessCont.newId()
		if err != nil {
			return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
		}
		sess.setId(id)
	}
	sess.setExpirationDate(time.Now().Add(sys.sessExpiDur))
	if err := sys.sessCont.put(sess); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}

	log.Debug("Session " + mosaic(sess.id()) + " was registered")

	if err := sys.consCont.put(sess.currentAccount(), authReq.ta(), consScops, consClms, denyScops, denyClms); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}

	// 認可コードを IdP の ID を含んだ JWS にする。
	jws := util.NewJws()
	jws.SetHeader(jwtAlg, algNone)
	jws.SetClaim(clmJti, cod.id())
	jws.SetClaim(clmIss, sys.selfId)
	if err := jws.Sign(nil); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}
	buff, err := jws.Encode()
	if err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}
	encCod := string(buff)

	rediUri := authReq.redirectUri()
	q := rediUri.Query()
	q.Set(formCod, encCod)
	if stat := authReq.state(); stat != "" {
		q.Set(formStat, stat)
	}
	rediUri.RawQuery = q.Encode()
	http.SetCookie(w, &http.Cookie{
		Name:     cookSess,
		Value:    sess.id(),
		Path:     "/",
		Expires:  sess.expirationDate(),
		Secure:   sys.secCook,
		HttpOnly: true})
	w.Header().Add("Cache-Control", "no-store")
	w.Header().Add("Pragma", "no-cache")
	http.Redirect(w, r, rediUri.String(), http.StatusFound)
	return nil
}

// ユーザー認証・認可開始ページ。
func authPage(w http.ResponseWriter, r *http.Request, sys *system) error {
	req, err := newAuthRequest(r)
	if err != nil {
		return erro.Wrap(err)
	}

	if req.ta() == "" {
		return newIdpError(errInvReq, "no "+formTaId, http.StatusBadRequest, nil)
	}

	// TA が指定されてる。
	log.Debug("TA " + req.ta() + " is declared")

	t, err := sys.taCont.get(req.ta())
	if err != nil {
		return erro.Wrap(err)
	} else if t == nil {
		return newIdpError(errInvReq, "invalid TA "+req.ta(), http.StatusBadRequest, nil)
	}

	// TA は存在する。
	log.Debug("TA " + t.id() + " is exist")
	req.setTaName(t.name())

	if req.rawRedirectUri() == "" {
		return newIdpError(errInvReq, "no "+formRediUri, http.StatusBadRequest, nil)
	} else if !t.redirectUris()[req.rawRedirectUri()] {
		return newIdpError(errInvReq, formRediUri+" "+req.rawRedirectUri()+" is not registered", http.StatusBadRequest, nil)
	}
	rediUri, err := url.Parse(req.rawRedirectUri())
	if err != nil {
		return newIdpError(errInvReq, erro.Unwrap(err).Error(), http.StatusBadRequest, erro.Wrap(err))
	}

	// リダイレクト先には問題無い。
	log.Debug("Redirect URI " + req.rawRedirectUri() + " is OK")
	req.setRedirectUri(rediUri)

	if !req.scopes()[scopOpId] {
		return redirectError(w, r, sys, nil, req, newIdpError(errInvReq, formScop+" has no "+scopOpId, 0, nil))
	}

	// 重複パラメータが無いか検査。
	for k, v := range r.Form {
		if len(v) > 1 {
			return redirectError(w, r, sys, nil, req, newIdpError(errInvReq, k+" is overlapped", 0, nil))
		}
	}

	// scope には問題無い。
	log.Debug("Scope has " + scopOpId)

	if l := len(req.responseType()); l == 0 {
		return redirectError(w, r, sys, nil, req, newIdpError(errInvReq, "no "+formRespType, 0, nil))
	} else if l != 1 || !req.responseType()[respTypeCod] {
		return redirectError(w, r, sys, nil, req, newIdpError(errUnsuppRespType, formRespType+" is not "+respTypeCod, 0, nil))
	}

	// response_type には問題無い。
	log.Debug("Response type is " + respTypeCod)

	var sess *session
	if sessId := newBrowserRequest(r).session(); sessId != "" {
		// セッションが通知された。
		log.Debug("Session " + mosaic(sessId) + " is declared")

		var err error
		sess, err = sys.sessCont.get(sessId)
		if err != nil {
			return redirectError(w, r, sys, nil, req, erro.Wrap(err))
		} else if sess == nil {
			// セッションなんて無かった。
			log.Warn("Session " + mosaic(sessId) + " is not exist")
		} else {
			// セッションがあった。
			log.Debug("Session " + mosaic(sessId) + " is exist")
		}
	}

	if sess == nil {
		sess = newSession()
		log.Debug("New session was generated but not yet registered")
	}
	sess.startRequest(req)

	prmpts := req.prompts()
	if prmpts[prmptSelAcc] {
		if prmpts[prmptNone] {
			return redirectError(w, r, sys, nil, req, newIdpError(errAccSelReq, "cannot select account without UI", 0, nil))
		}

		return redirectSelectUi(w, r, sys, sess, "")
	}

	return afterSelect(w, r, sys, sess)
}
<commit_msg>余計な変数を削除<commit_after>package main

import (
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"net/url"
	"time"
)

// 認可コード発行。
func publishCode(w http.ResponseWriter, r *http.Request, sys *system, sess *session) error {

	authReq := sess.request() // commit すると消えるので取っとく。

	consScops, consClms, denyScops, denyClms := sess.commit()

	if !consScops[scopOpId] {
		// openid すら許されなかった。
		return redirectError(w, r, sys, sess, authReq, newIdpError(errAccDeny, "user denied openid", 0, nil))
	}

	codId, err := sys.codCont.newId()
	if err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}
	cod := newCode(
		codId,
		sess.currentAccount(),
		authReq.ta(),
		authReq.redirectUri().String(),
		time.Now().Add(sys.codExpiDur),
		sys.tokExpiDur,
		consScops,
		consClms,
		authReq.nonce(),
		sess.currentAccountDate(),
	)
	log.Debug("Code " + mosaic(cod.id()) + " was generated.")

	if err := sys.codCont.put(cod); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}

	// 認可コードを発行した。
	log.Debug("Code " + mosaic(cod.id()) + " was published")

	if sess.id() == "" {
		id, err := sys.sessCont.newId()
		if err != nil {
			return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
		}
		sess.setId(id)
	}
	sess.setExpirationDate(time.Now().Add(sys.sessExpiDur))
	if err := sys.sessCont.put(sess); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}

	log.Debug("Session " + mosaic(sess.id()) + " was registered")

	if err := sys.consCont.put(sess.currentAccount(), authReq.ta(), consScops, consClms, denyScops, denyClms); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}

	// 認可コードを IdP の ID を含んだ JWS にする。
	jws := util.NewJws()
	jws.SetHeader(jwtAlg, algNone)
	jws.SetClaim(clmJti, cod.id())
	jws.SetClaim(clmIss, sys.selfId)
	if err := jws.Sign(nil); err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}
	buff, err := jws.Encode()
	if err != nil {
		return redirectError(w, r, sys, sess, authReq, erro.Wrap(err))
	}
	encCod := string(buff)

	q := authReq.redirectUri().Query()
	q.Set(formCod, encCod)
	if stat := authReq.state(); stat != "" {
		q.Set(formStat, stat)
	}
	authReq.redirectUri().RawQuery = q.Encode()
	http.SetCookie(w, &http.Cookie{
		Name:     cookSess,
		Value:    sess.id(),
		Path:     "/",
		Expires:  sess.expirationDate(),
		Secure:   sys.secCook,
		HttpOnly: true})
	w.Header().Add("Cache-Control", "no-store")
	w.Header().Add("Pragma", "no-cache")
	http.Redirect(w, r, authReq.redirectUri().String(), http.StatusFound)
	return nil
}

// ユーザー認証・認可開始ページ。
func authPage(w http.ResponseWriter, r *http.Request, sys *system) error {
	req, err := newAuthRequest(r)
	if err != nil {
		return erro.Wrap(err)
	}

	if req.ta() == "" {
		return newIdpError(errInvReq, "no "+formTaId, http.StatusBadRequest, nil)
	}

	// TA が指定されてる。
	log.Debug("TA " + req.ta() + " is declared")

	t, err := sys.taCont.get(req.ta())
	if err != nil {
		return erro.Wrap(err)
	} else if t == nil {
		return newIdpError(errInvReq, "invalid TA "+req.ta(), http.StatusBadRequest, nil)
	}

	// TA は存在する。
	log.Debug("TA " + t.id() + " is exist")
	req.setTaName(t.name())

	if req.rawRedirectUri() == "" {
		return newIdpError(errInvReq, "no "+formRediUri, http.StatusBadRequest, nil)
	} else if !t.redirectUris()[req.rawRedirectUri()] {
		return newIdpError(errInvReq, formRediUri+" "+req.rawRedirectUri()+" is not registered", http.StatusBadRequest, nil)
	}
	rediUri, err := url.Parse(req.rawRedirectUri())
	if err != nil {
		return newIdpError(errInvReq, erro.Unwrap(err).Error(), http.StatusBadRequest, erro.Wrap(err))
	}

	// リダイレクト先には問題無い。
	log.Debug("Redirect URI " + req.rawRedirectUri() + " is OK")
	req.setRedirectUri(rediUri)

	if !req.scopes()[scopOpId] {
		return redirectError(w, r, sys, nil, req, newIdpError(errInvReq, formScop+" has no "+scopOpId, 0, nil))
	}

	// 重複パラメータが無いか検査。
	for k, v := range r.Form {
		if len(v) > 1 {
			return redirectError(w, r, sys, nil, req, newIdpError(errInvReq, k+" is overlapped", 0, nil))
		}
	}

	// scope には問題無い。
	log.Debug("Scope has " + scopOpId)

	if l := len(req.responseType()); l == 0 {
		return redirectError(w, r, sys, nil, req, newIdpError(errInvReq, "no "+formRespType, 0, nil))
	} else if l != 1 || !req.responseType()[respTypeCod] {
		return redirectError(w, r, sys, nil, req, newIdpError(errUnsuppRespType, formRespType+" is not "+respTypeCod, 0, nil))
	}

	// response_type には問題無い。
	log.Debug("Response type is " + respTypeCod)

	var sess *session
	if sessId := newBrowserRequest(r).session(); sessId != "" {
		// セッションが通知された。
		log.Debug("Session " + mosaic(sessId) + " is declared")

		var err error
		sess, err = sys.sessCont.get(sessId)
		if err != nil {
			return redirectError(w, r, sys, nil, req, erro.Wrap(err))
		} else if sess == nil {
			// セッションなんて無かった。
			log.Warn("Session " + mosaic(sessId) + " is not exist")
		} else {
			// セッションがあった。
			log.Debug("Session " + mosaic(sessId) + " is exist")
		}
	}

	if sess == nil {
		sess = newSession()
		log.Debug("New session was generated but not yet registered")
	}
	sess.startRequest(req)

	prmpts := req.prompts()
	if prmpts[prmptSelAcc] {
		if prmpts[prmptNone] {
			return redirectError(w, r, sys, nil, req, newIdpError(errAccSelReq, "cannot select account without UI", 0, nil))
		}

		return redirectSelectUi(w, r, sys, sess, "")
	}

	return afterSelect(w, r, sys, sess)
}
<|endoftext|>


<commit_before>package cheshire

import (
    "reflect"
    "runtime"
    "strings"
    "github.com/trendrr/cheshire-golang/strest"
    "log"
    // "os"
)

type Bootstrap struct {
    Conf       *strest.ServerConfig
}

// Runs All methods that have prefix of Init
func (this *Bootstrap) RunInitMethods(target interface{}) {
    t := reflect.TypeOf(target)
    for i := 0; i < t.NumMethod(); i++ {
        method := t.Method(i)
        if strings.HasPrefix(method.Name, "Init") {
            reflect.ValueOf(target).Method(i).Call([]reflect.Value{})
        }
    }
}

// func (this *Bootstrap) InitMemcached() {
//     //init our memcached client
//     Memcached().Connect(this.Conf.Get("memcached.servers"))
// }

func (this *Bootstrap) InitProcs() {
    //lets tell our app how to best use the processors
    mp,ok := this.Conf.GetInt64("maxprocs")
    if ok {
        //set the max procs to our config setting
        runtime.GOMAXPROCS(int(mp))
    } else {
        //set the app to utilize all available cpus
        runtime.GOMAXPROCS(runtime.NumCPU())
    }
}

//this needs to be setup correctly to key off of the config yaml
func (this *Bootstrap) InitStaticFiles() {
    if this.Conf.Exists("listeners.http.static_files.route") {

        // http.Handle(
        //         this.Conf.Get("app.static_route"),
        //         http.StripPrefix(this.Conf.Get("app.static_route"),
        //             http.FileServer(http.Dir(this.Conf.Get("app.static_path")))))

    }
}

func (this *Bootstrap) InitWebSockets() {
    if this.Conf.Exists("listeners.http.websockets.route") {
        route, ok := this.Conf.GetString("listeners.http.websockets.route")
        if ok {
            this.Conf.Register(strest.NewWebsocketController(route, this.Conf))
        }
    }

}

// Registers a controller funtion for api calls
func (this *Bootstrap) RegisterApi(route string, methods []string, handler func(*strest.Request,strest.Connection)) {
    this.Conf.Register(strest.NewController(route, methods, handler))
}

// Registers a controller function for html pages
func (this *Bootstrap) RegisterHtml(route string, methods []string, handler func(*strest.Request, *HtmlConnection)) {
    this.Conf.Register(NewHtmlController(route, methods, handler))
}

// Registers a new controller
func (this *Bootstrap) Register(controller strest.Controller) {
    this.Conf.Register(controller)
}

func NewBootstrapFile(configPath string) *Bootstrap {
    conf := NewServerConfigFile(configPath)
    return NewBootstrap(conf)
}

func NewBootstrap(config *strest.ServerConfig) *Bootstrap {
    //create an instance of our application bootstrap
    bs := &Bootstrap{Conf: config}

    //return a pointer to our application
    return bs
}

func NewExtendedBootstrap(configPath string,extentions []func(conf *strest.ServerConfig)) *Bootstrap {
    //create and run the default bootstrap
    bs := NewBootstrapFile(configPath)

    //loop over the bootstrap extentions
    for i := 0; i < len(extentions) ; i++ {
        //execute each extenion method
        extentions[i](bs.Conf)
    }

    //return a pointer to our application
    return bs
}

//starts listening in all the configured listeners
//this method does not return until all listeners exit (i.e. never).
func (this *Bootstrap) Start() {
    this.RunInitMethods(this)
    log.Println("**********")
    log.Println(this.Conf.Map)
    //now start listening.
    if this.Conf.Exists("http.port") {
        port, ok := this.Conf.GetInt("http.port")
        if !ok {
            log.Println("ERROR: Couldn't start http listener ", port)
        } else {
            go strest.HttpListen(port, this.Conf)
        }
    }

    if this.Conf.Exists("json.port") {
        port, ok := this.Conf.GetInt("json.port")
        if !ok {
            log.Println("ERROR: Couldn't start json listener")
        } else {
            go strest.JsonListen(port, this.Conf)
        }
    }

    //this just makes the current thread sleep.  kinda stupid currently.
    //but we should update to get messages from the listeners, like when a listener quites
    channel := make(chan string)
    val := <-channel
    log.Println(val)
}<commit_msg>add a register queue, so that controllers can be registered before bootstraping<commit_after>package cheshire

import (
    "reflect"
    "runtime"
    "strings"
    "github.com/trendrr/cheshire-golang/strest"
    "log"
    "sync"
    // "os"
)

type Bootstrap struct {
    Conf       *strest.ServerConfig
}

// Runs All methods that have prefix of Init
func (this *Bootstrap) RunInitMethods(target interface{}) {
    t := reflect.TypeOf(target)
    for i := 0; i < t.NumMethod(); i++ {
        method := t.Method(i)
        if strings.HasPrefix(method.Name, "Init") {
            reflect.ValueOf(target).Method(i).Call([]reflect.Value{})
        }
    }
}

// func (this *Bootstrap) InitMemcached() {
//     //init our memcached client
//     Memcached().Connect(this.Conf.Get("memcached.servers"))
// }

func (this *Bootstrap) InitProcs() {
    //lets tell our app how to best use the processors
    mp,ok := this.Conf.GetInt64("maxprocs")
    if ok {
        //set the max procs to our config setting
        runtime.GOMAXPROCS(int(mp))
    } else {
        //set the app to utilize all available cpus
        runtime.GOMAXPROCS(runtime.NumCPU())
    }
}

//this needs to be setup correctly to key off of the config yaml
func (this *Bootstrap) InitStaticFiles() {
    if this.Conf.Exists("listeners.http.static_files.route") {

        // http.Handle(
        //         this.Conf.Get("app.static_route"),
        //         http.StripPrefix(this.Conf.Get("app.static_route"),
        //             http.FileServer(http.Dir(this.Conf.Get("app.static_path")))))

    }
}

func (this *Bootstrap) InitWebSockets() {
    if this.Conf.Exists("listeners.http.websockets.route") {
        route, ok := this.Conf.GetString("listeners.http.websockets.route")
        if ok {
            this.Conf.Register(strest.NewWebsocketController(route, this.Conf))
        }
    }

}

func (this *Bootstrap) InitControllers() {
    for _, contr := range registerQueue {
        this.Conf.Register(contr)
    }
}

//
// a queue of controllers so we can register controllers
// before the bootstrap is initialized
var registerQueue []strest.Controller
var registerOnce sync.Once

// Registers a controller funtion for api calls
func RegisterApi(route string, methods []string, handler func(*strest.Request,strest.Connection)) {
    Register(strest.NewController(route, methods, handler))
}

// Registers a controller function for html pages
func RegisterHtml(route string, methods []string, handler func(*strest.Request, *HtmlConnection)) {
    Register(NewHtmlController(route, methods, handler))
}

// Registers a new controller
func Register(controller strest.Controller) {
    registerOnce.Do(func() {
        registerQueue = []strest.Controller{}
    })
    _ = append(registerQueue, controller)
}

func NewBootstrapFile(configPath string) *Bootstrap {
    conf := NewServerConfigFile(configPath)
    return NewBootstrap(conf)
}

func NewBootstrap(config *strest.ServerConfig) *Bootstrap {
    //create an instance of our application bootstrap
    bs := &Bootstrap{Conf: config}

    //return a pointer to our application
    return bs
}

func NewExtendedBootstrap(configPath string,extentions []func(conf *strest.ServerConfig)) *Bootstrap {
    //create and run the default bootstrap
    bs := NewBootstrapFile(configPath)

    //loop over the bootstrap extentions
    for i := 0; i < len(extentions) ; i++ {
        //execute each extenion method
        extentions[i](bs.Conf)
    }

    //return a pointer to our application
    return bs
}

//starts listening in all the configured listeners
//this method does not return until all listeners exit (i.e. never).
func (this *Bootstrap) Start() {
    this.RunInitMethods(this)
    log.Println("**********")
    log.Println(this.Conf.Map)
    //now start listening.
    if this.Conf.Exists("http.port") {
        port, ok := this.Conf.GetInt("http.port")
        if !ok {
            log.Println("ERROR: Couldn't start http listener ", port)
        } else {
            go strest.HttpListen(port, this.Conf)
        }
    }

    if this.Conf.Exists("json.port") {
        port, ok := this.Conf.GetInt("json.port")
        if !ok {
            log.Println("ERROR: Couldn't start json listener")
        } else {
            go strest.JsonListen(port, this.Conf)
        }
    }

    //this just makes the current thread sleep.  kinda stupid currently.
    //but we should update to get messages from the listeners, like when a listener quites
    channel := make(chan string)
    val := <-channel
    log.Println(val)
}<|endoftext|>


<commit_before>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package chk

import (
	"fmt"
	"testing"
)

func Test_IntAssert(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("IntAssert")

	PrintOk("the next error message is")
	IntAssert(2, 1)
}

func Test_DblAssert(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("DblAssert")

	PrintOk("the next error message is")
	DblAssert(2, 1)
}

func Test_IntAssertLessthan(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("IntAssertLessthan")

	PrintOk("the next error message is")
	IntAssertLessThan(1, 1)
}

func Test_IntAssertLessthanOrEqualTo(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("IntAssertLessthanOrEqualTo")

	PrintOk("the next error message is")
	IntAssertLessThanOrEqualTo(2, 1)
}

func Test_StrAssert(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("StrAssert")

	PrintOk("the next error message is")
	StrAssert("rambo", "terminator")
}

func myfunction() {}

func Test_FcnName(tst *testing.T) {

	//Verbose = true
	PrintTitle("FcnName")

	name := GetFunctionName(myfunction)
	if Verbose {
		fmt.Printf("name = %v\n", name)
	}
	if name != "github.com/cpmech/gosl/chk.myfunction" {
		tst.Errorf("function name is incorrect\n")
	}

	fcn := func() {}
	name = GetFunctionName(fcn)
	if Verbose {
		fmt.Printf("name = %v\n", name)
	}
	if name != "github.com/cpmech/gosl/chk.Test_FcnName.func1" {
		tst.Errorf("function name is incorrect\n")
	}
}
<commit_msg>anonymous function name cannot be checked<commit_after>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package chk

import (
	"fmt"
	"testing"
)

func Test_IntAssert(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("IntAssert")

	PrintOk("the next error message is")
	IntAssert(2, 1)
}

func Test_DblAssert(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("DblAssert")

	PrintOk("the next error message is")
	DblAssert(2, 1)
}

func Test_IntAssertLessthan(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("IntAssertLessthan")

	PrintOk("the next error message is")
	IntAssertLessThan(1, 1)
}

func Test_IntAssertLessthanOrEqualTo(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("IntAssertLessthanOrEqualTo")

	PrintOk("the next error message is")
	IntAssertLessThanOrEqualTo(2, 1)
}

func Test_StrAssert(tst *testing.T) {

	//Verbose = true
	defer func() {
		if err := recover(); err != nil {
			if Verbose {
				fmt.Printf("OK, caught the following message:\n\n\t%v\n", err)
			}
		} else {
			tst.Errorf("\n\tTEST FAILED. Assert should have panicked\n")
		}
	}()

	PrintTitle("StrAssert")

	PrintOk("the next error message is")
	StrAssert("rambo", "terminator")
}

func myfunction() {}

func Test_FcnName(tst *testing.T) {

	//Verbose = true
	PrintTitle("FcnName")

	name := GetFunctionName(myfunction)
	if Verbose {
		fmt.Printf("name = %v\n", name)
	}
	if name != "github.com/cpmech/gosl/chk.myfunction" {
		tst.Errorf("function name is incorrect\n")
	}

	fcn := func() {}
	name = GetFunctionName(fcn)
	if Verbose {
		fmt.Printf("name = %v\n", name)
	}
	//if !strings.HasPrefix(name, "github.com/cpmech/gosl/chk.Test_FcnName.func") {
	//tst.Errorf("function name is incorrect\n")
	//}
}
<|endoftext|>


<commit_before>// +build !appengine

package bugsnag

import (
	"github.com/bugsnag/bugsnag-go/errors"
	"github.com/bugsnag/panicwrap"
)

// NOTE: this function does not return when you call it, instead it
// re-exec()s the current process with panic monitoring.
func defaultPanicHandler() {
	defer defaultNotifier.dontPanic()

	err := panicwrap.BasicMonitor(func(output string) {
		toNotify, err := errors.ParsePanic(output)

		if err != nil {
			defaultNotifier.Config.logf("bugsnag.handleUncaughtPanic: %v", err)
		}
		Notify(toNotify, SeverityError, Configuration{Synchronous: true})
	})

	if err != nil {
		defaultNotifier.Config.logf("bugsnag.handleUncaughtPanic: %v", err)
	}
}
<commit_msg>[panicwrap] Clarify documentation for default panic handler<commit_after>// +build !appengine

package bugsnag

import (
	"github.com/bugsnag/bugsnag-go/errors"
	"github.com/bugsnag/panicwrap"
)

// Forks and re-runs your program to add panic monitoring. This function does
// not return on one process, instead listening on stderr of the other process,
// which returns nil.
//
// Related: https://godoc.org/github.com/bugsnag/panicwrap#BasicMonitor
func defaultPanicHandler() {
	defer defaultNotifier.dontPanic()

	err := panicwrap.BasicMonitor(func(output string) {
		toNotify, err := errors.ParsePanic(output)

		if err != nil {
			defaultNotifier.Config.logf("bugsnag.handleUncaughtPanic: %v", err)
		}
		Notify(toNotify, SeverityError, Configuration{Synchronous: true})
	})

	if err != nil {
		defaultNotifier.Config.logf("bugsnag.handleUncaughtPanic: %v", err)
	}
}
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
	"strings"
	"unicode"
	"unicode/utf8"
)

// The line number of an item in the input string
type Line int

func (l Line) LineNumber() Line { return l }

// The begining location of an item in the input.
type StartPosition int

func (s StartPosition) Position() StartPosition { return s }

// itemElement are the types that are emitted by the lexer.
type itemElement int

const (
	itemEOF itemElement = iota
	itemError
	itemTitle
	itemSectionAdornment
	itemParagraph
	itemBlockquote
	itemLiteralBlock
	itemSystemMessage
	itemSpace
	itemBlankLine
)

var elements = [...]string{
	"itemEOF",
	"itemError",
	"itemTitle",
	"itemSectionAdornment",
	"itemParagraph",
	"itemBlockquote",
	"itemLiteralBlock",
	"itemSystemMessage",
	"itemSpace",
	"itemBlankLine",
}

// String implements the Stringer interface for printing itemElement types.
func (t itemElement) String() string { return elements[t] }

// Valid section adornment runes
var sectionAdornments = []rune{'!', '"', '#', '$', '\'', '%', '&', '(', ')', '*',
	'+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\',
	']', '^', '_', '`', '{', '|', '}', '~'}

// Emitted by the lexer on End of File
const eof rune = -1

// Function prototype for scanner functions
type stateFn func(*lexer) stateFn

// Struct for tokens emitted by the scanning process
type item struct {
	ElementName string      `json:"element-name"`
	ElementType itemElement `json:"-"`
	Length      int         `json:"length"`
	Value       interface{} `json:"value"`
	StartPosition           `json:"position"`
	Line			`json:"line"`
}

// The lexer struct tracks the state of the lexer
type lexer struct {
	name     string    // The name of the current lexer
	input    string    // The input text
	state    stateFn   // The current state of the lexer
	index    int       // Position in input
	start    int       // The start of the current token
	width    int       // The width of the current position
	items    chan item // The channel items are emitted to
	lastItem *item     // The last item emitted to the channel
	lastItemPosition  StartPosition
}

// lex is the entry point of the lexer
func lex(name, input string) *lexer {
	log.Debugln("Start")
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	log.Debugln("End")
	return l
}

// run is the engine of the lexing process.
func (l *lexer) run() {
	log.Debugln("Start")
	for l.state = lexStart; l.state != nil; {
		l.state = l.state(l)
	}
	log.Debugln("End")
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemElement) {
	if l.start == l.index && int(l.index) < len(l.input) {
		l.index += 1
	}
	log.Debugf("#### %s: %q start: %d pos: %d line: %d\n", t,
		l.input[l.start:l.index], l.start, l.index, l.lineNumber())
	nItem := item{
		ElementType: t,
		ElementName: fmt.Sprint(t),
		StartPosition:    StartPosition(l.start + 1),
		Line:	     Line(l.lineNumber()),
		Value:       l.input[l.start:l.index],
		Length:      len(l.input[l.start:l.index]),
	}
	l.items <- nItem
	l.lastItem = &nItem
	l.start = l.index
}

// backup backs up the lexer by one position using the width of the last rune retrieved from the
// input.
func (l *lexer) backup() {
	l.index -= l.width
}

// current returns the rune at the current position in the input.
func (l *lexer) current() rune {
	r, _ := utf8.DecodeRuneInString(l.input[l.index:])
	return r
}

// peek looks ahead in the input by one position and returns the rune.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// advance fast forwards the lexer to the next rune in the input specified by "to".
func (l *lexer) advance(to rune) {
	for {
		if l.next() == eof || to == l.current() {
			break
		}
	}
}

// next advances the position of the lexer by one rune and returns that rune.
func (l *lexer) next() rune {
	if int(l.index) >= len(l.input) {
		log.Debugln("Reached eof!")
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.index:])
	l.width = w
	l.index += l.width
	log.Debugf("cur: %q start: %d pos: %d\n", r, l.start, l.index)
	return r
}

// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastItemPosition = item.StartPosition
	return item

}

func (l *lexer) lineNumber() int {
	return 1 + strings.Count(l.input[:l.index-1], "\n")
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t' || r == '\n' || r == '\r'
}

// isEndOfLine reports whether r is an end-of-line character.
func isEndOfLine(r rune) bool {
	return r == '\r' || r == '\n'
}

// isSection compares a number of positions (skipping whitespace) to
// determine if the runes are sectionAdornments and returns a true if the
// positions match each other. Rune comparison begins at the current lexer
// position. isSection returns false if there is a blank line between the
// positions or if there is a rune mismatch between positions.
func isSection(l *lexer) bool {
	log.Debugln("Start")
	var lookPositions = 2
	var lastAdornment rune
	var newLineNum int
	var runePositions []rune
	var matchCount int
	cPos := l.index

	exit := func(value bool) bool {
		l.index = cPos
		log.Debugln("Returning", value)
		return value
	}

	log.Debugln("Looking ahead", lookPositions, "position(s) for sectionAdornments...")

	// Check two runes to see if they are section adornments, if not, we will check the next
	// line (after whitespace).
	if isSectionAdornment(l.current()) && isSectionAdornment(l.peek()) &&
		l.current() == l.peek() {
		return true
	}

	// Advance to the end of the line
	l.advance('\n')
	if l.current() == eof {
		return false
	}

	for j := 0; j < lookPositions; j++ {
		for isSpace(l.current()) {
			if isEndOfLine(l.current()) {
				if newLineNum == 1 {
					log.Debugln("Too many newlines!")
					return exit(false)
				}
				newLineNum += 1
				log.Debugln("newLineNum:", newLineNum)
			}
			l.next()
		}

		if isSectionAdornment(l.current()) {
			log.Debugf("Found adornment: \"%s\" pos: %d\n", string(l.current()), l.index)
			if lastAdornment != 0 && l.current() != lastAdornment {
				log.Debugf("Adornment mismatch, last: %s current: %s\n",
					string(lastAdornment), string(l.current()))
				return exit(false)
			}
			runePositions = append(runePositions, l.current())
			lastAdornment = l.current()
			matchCount += 1
		}
		l.next()
	}

	if len(runePositions) == 0 || matchCount != lookPositions {
		return exit(false)
	}

	return exit(true)
}

// isSectionAdornment returns true if r matches a section adornment.
func isSectionAdornment(r rune) bool {
	for _, a := range sectionAdornments {
		if a == r {
			return true
		}
	}
	return false
}

// lexStart is the first stateFn called by run(). From here other stateFn's are called depending on
// the input. When this function returns nil, the lexing is finished and run() will exit.
func lexStart(l *lexer) stateFn {
	log.Debugln("Start")
	for {
		var tokenLength = l.index - l.start
		switch r := l.current(); {
		case tokenLength == 1:
			log.Debugln("tokenLength == 1; Start of new token")
			if isEndOfLine(r) {
				l.emit(itemBlankLine)
				l.start += 1
			} else if isSpace(r) {
				return lexSpace
			} else if isSection(l) {
				return lexSection
			}
		case isEndOfLine(r):
			log.Debugln("isEndOfLine == true")
			if l.index > l.start {
				l.emit(itemParagraph)
				l.start += 1 // Skip the new line
			} else if l.start == l.index {
				l.emit(itemBlankLine)
			}

		}
		if l.next() == eof {
			break
		}
	}

	// Correctly reached eof.
	if l.index > l.start {
		l.emit(itemParagraph)
	}

	l.emit(itemEOF)
	log.Debugln("End")
	return nil
}

// lexSpace consumes space characters (space and tab) in the input and emits a itemSpace token.
func lexSpace(l *lexer) stateFn {
	log.Debugln("Start")
	for isSpace(l.current()) {
		l.next()
	}
	if l.start < l.index {
		l.emit(itemSpace)
		l.next()
	}
	log.Debugln("End")
	return lexStart
}

// lexSection is used after isSection() has determined that the next runes of input are section.
// From here, the lexTitle() and lexSectionAdornment() are called based on the input.
func lexSection(l *lexer) stateFn {
	log.Debugln("Start")
	// The order of the case statement matter here
	switch r := l.next(); {
	case isSectionAdornment(r):
		if l.lastItem.ElementType != itemTitle {
			return lexSectionAdornment
		}
		lexSectionAdornment(l)
	case isSpace(r):
		return lexSpace
	case r <= unicode.MaxASCII && unicode.IsPrint(r):
		return lexTitle
	case isEndOfLine(r):
		l.start += 1
	}
	log.Debugln("Exit")
	return lexStart
}

// lexTitle consumes input until newline and emits an itemTitle token. Once the token is emitted,
// control is returned to lexSection().
func lexTitle(l *lexer) stateFn {
	log.Debugln("Start")
	for {
		l.next()
		if l.peek() == '\n' {
			l.emit(itemTitle)
			l.start += 1
			l.index += 1
			break
		}
	}
	log.Debugln("End")
	return lexSection
}

// lexSectionAdornment advances the lexer until a newline is encountered and emits a
// itemSectionAdornment token. Control is returned to lexSection() on completion.
func lexSectionAdornment(l *lexer) stateFn {
	log.Debugln("Start")
	for {
		//TODO: Add adornment rune check
		l.next()
		if l.peek() == '\n' {
			l.emit(itemSectionAdornment)
			l.start += 1
			l.index += 1
			break
		}
	}
	log.Debugln("End")
	return lexSection
}
<commit_msg>lex.go: go fmt fixes<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
	"strings"
	"unicode"
	"unicode/utf8"
)

// The line number of an item in the input string
type Line int

func (l Line) LineNumber() Line { return l }

// The begining location of an item in the input.
type StartPosition int

func (s StartPosition) Position() StartPosition { return s }

// itemElement are the types that are emitted by the lexer.
type itemElement int

const (
	itemEOF itemElement = iota
	itemError
	itemTitle
	itemSectionAdornment
	itemParagraph
	itemBlockquote
	itemLiteralBlock
	itemSystemMessage
	itemSpace
	itemBlankLine
)

var elements = [...]string{
	"itemEOF",
	"itemError",
	"itemTitle",
	"itemSectionAdornment",
	"itemParagraph",
	"itemBlockquote",
	"itemLiteralBlock",
	"itemSystemMessage",
	"itemSpace",
	"itemBlankLine",
}

// String implements the Stringer interface for printing itemElement types.
func (t itemElement) String() string { return elements[t] }

// Valid section adornment runes
var sectionAdornments = []rune{'!', '"', '#', '$', '\'', '%', '&', '(', ')', '*',
	'+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\',
	']', '^', '_', '`', '{', '|', '}', '~'}

// Emitted by the lexer on End of File
const eof rune = -1

// Function prototype for scanner functions
type stateFn func(*lexer) stateFn

// Struct for tokens emitted by the scanning process
type item struct {
	ElementName   string      `json:"element-name"`
	ElementType   itemElement `json:"-"`
	Length        int         `json:"length"`
	Value         interface{} `json:"value"`
	StartPosition `json:"position"`
	Line          `json:"line"`
}

// The lexer struct tracks the state of the lexer
type lexer struct {
	name             string    // The name of the current lexer
	input            string    // The input text
	state            stateFn   // The current state of the lexer
	index            int       // Position in input
	start            int       // The start of the current token
	width            int       // The width of the current position
	items            chan item // The channel items are emitted to
	lastItem         *item     // The last item emitted to the channel
	lastItemPosition StartPosition
}

// lex is the entry point of the lexer
func lex(name, input string) *lexer {
	log.Debugln("Start")
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	log.Debugln("End")
	return l
}

// run is the engine of the lexing process.
func (l *lexer) run() {
	log.Debugln("Start")
	for l.state = lexStart; l.state != nil; {
		l.state = l.state(l)
	}
	log.Debugln("End")
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemElement) {
	if l.start == l.index && int(l.index) < len(l.input) {
		l.index += 1
	}
	log.Debugf("#### %s: %q start: %d pos: %d line: %d\n", t,
		l.input[l.start:l.index], l.start, l.index, l.lineNumber())
	nItem := item{
		ElementType:   t,
		ElementName:   fmt.Sprint(t),
		StartPosition: StartPosition(l.start + 1),
		Line:          Line(l.lineNumber()),
		Value:         l.input[l.start:l.index],
		Length:        len(l.input[l.start:l.index]),
	}
	l.items <- nItem
	l.lastItem = &nItem
	l.start = l.index
}

// backup backs up the lexer by one position using the width of the last rune retrieved from the
// input.
func (l *lexer) backup() {
	l.index -= l.width
}

// current returns the rune at the current position in the input.
func (l *lexer) current() rune {
	r, _ := utf8.DecodeRuneInString(l.input[l.index:])
	return r
}

// peek looks ahead in the input by one position and returns the rune.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// advance fast forwards the lexer to the next rune in the input specified by "to".
func (l *lexer) advance(to rune) {
	for {
		if l.next() == eof || to == l.current() {
			break
		}
	}
}

// next advances the position of the lexer by one rune and returns that rune.
func (l *lexer) next() rune {
	if int(l.index) >= len(l.input) {
		log.Debugln("Reached eof!")
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.index:])
	l.width = w
	l.index += l.width
	log.Debugf("cur: %q start: %d pos: %d\n", r, l.start, l.index)
	return r
}

// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastItemPosition = item.StartPosition
	return item

}

func (l *lexer) lineNumber() int {
	return 1 + strings.Count(l.input[:l.index-1], "\n")
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t' || r == '\n' || r == '\r'
}

// isEndOfLine reports whether r is an end-of-line character.
func isEndOfLine(r rune) bool {
	return r == '\r' || r == '\n'
}

// isSection compares a number of positions (skipping whitespace) to
// determine if the runes are sectionAdornments and returns a true if the
// positions match each other. Rune comparison begins at the current lexer
// position. isSection returns false if there is a blank line between the
// positions or if there is a rune mismatch between positions.
func isSection(l *lexer) bool {
	log.Debugln("Start")
	var lookPositions = 2
	var lastAdornment rune
	var newLineNum int
	var runePositions []rune
	var matchCount int
	cPos := l.index

	exit := func(value bool) bool {
		l.index = cPos
		log.Debugln("Returning", value)
		return value
	}

	log.Debugln("Looking ahead", lookPositions, "position(s) for sectionAdornments...")

	// Check two runes to see if they are section adornments, if not, we will check the next
	// line (after whitespace).
	if isSectionAdornment(l.current()) && isSectionAdornment(l.peek()) &&
		l.current() == l.peek() {
		return true
	}

	// Advance to the end of the line
	l.advance('\n')
	if l.current() == eof {
		return false
	}

	for j := 0; j < lookPositions; j++ {
		for isSpace(l.current()) {
			if isEndOfLine(l.current()) {
				if newLineNum == 1 {
					log.Debugln("Too many newlines!")
					return exit(false)
				}
				newLineNum += 1
				log.Debugln("newLineNum:", newLineNum)
			}
			l.next()
		}

		if isSectionAdornment(l.current()) {
			log.Debugf("Found adornment: \"%s\" pos: %d\n", string(l.current()), l.index)
			if lastAdornment != 0 && l.current() != lastAdornment {
				log.Debugf("Adornment mismatch, last: %s current: %s\n",
					string(lastAdornment), string(l.current()))
				return exit(false)
			}
			runePositions = append(runePositions, l.current())
			lastAdornment = l.current()
			matchCount += 1
		}
		l.next()
	}

	if len(runePositions) == 0 || matchCount != lookPositions {
		return exit(false)
	}

	return exit(true)
}

// isSectionAdornment returns true if r matches a section adornment.
func isSectionAdornment(r rune) bool {
	for _, a := range sectionAdornments {
		if a == r {
			return true
		}
	}
	return false
}

// lexStart is the first stateFn called by run(). From here other stateFn's are called depending on
// the input. When this function returns nil, the lexing is finished and run() will exit.
func lexStart(l *lexer) stateFn {
	log.Debugln("Start")
	for {
		var tokenLength = l.index - l.start
		switch r := l.current(); {
		case tokenLength == 1:
			log.Debugln("tokenLength == 1; Start of new token")
			if isEndOfLine(r) {
				l.emit(itemBlankLine)
				l.start += 1
			} else if isSpace(r) {
				return lexSpace
			} else if isSection(l) {
				return lexSection
			}
		case isEndOfLine(r):
			log.Debugln("isEndOfLine == true")
			if l.index > l.start {
				l.emit(itemParagraph)
				l.start += 1 // Skip the new line
			} else if l.start == l.index {
				l.emit(itemBlankLine)
			}

		}
		if l.next() == eof {
			break
		}
	}

	// Correctly reached eof.
	if l.index > l.start {
		l.emit(itemParagraph)
	}

	l.emit(itemEOF)
	log.Debugln("End")
	return nil
}

// lexSpace consumes space characters (space and tab) in the input and emits a itemSpace token.
func lexSpace(l *lexer) stateFn {
	log.Debugln("Start")
	for isSpace(l.current()) {
		l.next()
	}
	if l.start < l.index {
		l.emit(itemSpace)
		l.next()
	}
	log.Debugln("End")
	return lexStart
}

// lexSection is used after isSection() has determined that the next runes of input are section.
// From here, the lexTitle() and lexSectionAdornment() are called based on the input.
func lexSection(l *lexer) stateFn {
	log.Debugln("Start")
	// The order of the case statement matter here
	switch r := l.next(); {
	case isSectionAdornment(r):
		if l.lastItem.ElementType != itemTitle {
			return lexSectionAdornment
		}
		lexSectionAdornment(l)
	case isSpace(r):
		return lexSpace
	case r <= unicode.MaxASCII && unicode.IsPrint(r):
		return lexTitle
	case isEndOfLine(r):
		l.start += 1
	}
	log.Debugln("Exit")
	return lexStart
}

// lexTitle consumes input until newline and emits an itemTitle token. Once the token is emitted,
// control is returned to lexSection().
func lexTitle(l *lexer) stateFn {
	log.Debugln("Start")
	for {
		l.next()
		if l.peek() == '\n' {
			l.emit(itemTitle)
			l.start += 1
			l.index += 1
			break
		}
	}
	log.Debugln("End")
	return lexSection
}

// lexSectionAdornment advances the lexer until a newline is encountered and emits a
// itemSectionAdornment token. Control is returned to lexSection() on completion.
func lexSectionAdornment(l *lexer) stateFn {
	log.Debugln("Start")
	for {
		//TODO: Add adornment rune check
		l.next()
		if l.peek() == '\n' {
			l.emit(itemSectionAdornment)
			l.start += 1
			l.index += 1
			break
		}
	}
	log.Debugln("End")
	return lexSection
}
<|endoftext|>


<commit_before>// Package circonusgometrics provides instrumentation for your applications in the form
// of counters, gauges and histograms and allows you to publish them to
// Circonus
//
// Counters
//
// A counter is a monotonically-increasing, unsigned, 64-bit integer used to
// represent the number of times an event has occurred. By tracking the deltas
// between measurements of a counter over intervals of time, an aggregation
// layer can derive rates, acceleration, etc.
//
// Gauges
//
// A gauge returns instantaneous measurements of something using signed, 64-bit
// integers. This value does not need to be monotonic.
//
// Histograms
//
// A histogram tracks the distribution of a stream of values (e.g. the number of
// seconds it takes to handle requests).  Circonus can calculate complex
// analytics on these.
//
// Reporting
//
// A period push to a Circonus httptrap is confgurable.

package circonusgometrics

import (
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sync"
	"time"
)

const (
	// a few sensible defaults
	defaultApiHost  = "api.circonus.com"
	defaultApiApp   = "circonus-gometrics"
	defaultInterval = 10 * time.Second
)

// a few words about: "BrokerGroupId"
//
// calling it this because the instructions for how to get into the UI and FIND this value are more straight-forward:
//
// log into ui
// navigate to brokers page
// identify which broker you need to use
// click the little down arrow in the circle on the right-hand side of the line for the broker you'd like to use
// use the value from the "GROUP ID:" field under "Broker Details" in the drop-down afetr clicking the down arrow
//
// ... or ...
//
// log into ui
// navigate to brokers page
// identify which broker you need to use
// click the hamburger menu icon (three lines to the left of the broker name)
// click "view API object" from the drop-down menu
// look for "_cid" field, use integer value after "/broker/" e.g. "/broker/35" would be 35
//

type CirconusMetrics struct {
	ApiToken      string
	SubmissionUrl string
	CheckId       int
	ApiApp        string
	ApiHost       string
	InstanceId    string
	SearchTag     string
	BrokerGroupId int
	Tags          []string
	CheckSecret   string

	Interval time.Duration
	Log      *log.Logger
	Debug    bool

	// internals
	ready   bool
	trapUrl string
	trapCN  string
	trapSSL bool
	trapmu  sync.Mutex

	certPool      *x509.CertPool
	cert          []byte
	checkBundle   *CheckBundle
	activeMetrics map[string]bool
	checkType     string

	counters map[string]uint64
	cm       sync.Mutex

	counterFuncs map[string]func() uint64
	cfm          sync.Mutex

	gauges map[string]int64
	gm     sync.Mutex

	gaugeFuncs map[string]func() int64
	gfm        sync.Mutex

	histograms map[string]*Histogram
	hm         sync.Mutex
}

func NewCirconusMetrics() *CirconusMetrics {
	_, an := path.Split(os.Args[0])
	hn, err := os.Hostname()
	if err != nil {
		hn = "unknown"
	}

	return &CirconusMetrics{
		InstanceId:    fmt.Sprintf("%s:%s", hn, an),
		SearchTag:     fmt.Sprintf("service:%s", an),
		ApiHost:       defaultApiHost,
		ApiApp:        defaultApiApp,
		Interval:      defaultInterval,
		Log:           log.New(ioutil.Discard, "", log.LstdFlags),
		Debug:         false,
		ready:         false,
		trapUrl:       "",
		activeMetrics: make(map[string]bool),
		counters:      make(map[string]uint64),
		counterFuncs:  make(map[string]func() uint64),
		gauges:        make(map[string]int64),
		gaugeFuncs:    make(map[string]func() int64),
		histograms:    make(map[string]*Histogram),
		certPool:      x509.NewCertPool(),
		checkType:     "httptrap",
	}

}

// Start starts a perdiodic submission process of all metrics collected
func (m *CirconusMetrics) Start() {
	go func() {
		if m.Debug {
			m.Log = log.New(os.Stderr, "", log.LstdFlags)
		}
		//m.loadCACert()
		if !m.ready {
			m.initializeTrap()
		}
	}()

	go func() {
		for _ = range time.NewTicker(m.Interval).C {
			m.Flush()
		}
	}()
}

func (m *CirconusMetrics) Flush() {
	m.Log.Println("Flushing")
	if !m.ready {
		if err := m.initializeTrap(); err != nil {
			m.Log.Println("Unable to initialize check, NOT flushing metrics.")
			return
		}
	}

	// check for new metrics and enable them automatically
	newMetrics := make(map[string]*CheckBundleMetric)

	counters, gauges, histograms := m.snapshot()
	output := make(map[string]interface{})
	for name, value := range counters {
		output[name] = map[string]interface{}{
			"_type":  "n",
			"_value": value,
		}
		if _, ok := m.activeMetrics[name]; !ok {
			newMetrics[name] = &CheckBundleMetric{
				Name:   name,
				Type:   "numeric",
				Status: "active",
			}
		}
	}

	for name, value := range gauges {
		output[name] = map[string]interface{}{
			"_type":  "n",
			"_value": value,
		}
		if _, ok := m.activeMetrics[name]; !ok {
			newMetrics[name] = &CheckBundleMetric{
				Name:   name,
				Type:   "numeric",
				Status: "active",
			}
		}
	}

	for name, value := range histograms {
		output[name] = map[string]interface{}{
			"_type":  "n",
			"_value": value.DecStrings(),
		}
		if _, ok := m.activeMetrics[name]; !ok {
			newMetrics[name] = &CheckBundleMetric{
				Name:   name,
				Type:   "histogram",
				Status: "active",
			}
		}
	}

	m.submit(output, newMetrics)
}
<commit_msg>make initializeTrap in start not a go func and return error on failure to initialize<commit_after>// Package circonusgometrics provides instrumentation for your applications in the form
// of counters, gauges and histograms and allows you to publish them to
// Circonus
//
// Counters
//
// A counter is a monotonically-increasing, unsigned, 64-bit integer used to
// represent the number of times an event has occurred. By tracking the deltas
// between measurements of a counter over intervals of time, an aggregation
// layer can derive rates, acceleration, etc.
//
// Gauges
//
// A gauge returns instantaneous measurements of something using signed, 64-bit
// integers. This value does not need to be monotonic.
//
// Histograms
//
// A histogram tracks the distribution of a stream of values (e.g. the number of
// seconds it takes to handle requests).  Circonus can calculate complex
// analytics on these.
//
// Reporting
//
// A period push to a Circonus httptrap is confgurable.

package circonusgometrics

import (
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sync"
	"time"
)

const (
	// a few sensible defaults
	defaultApiHost  = "api.circonus.com"
	defaultApiApp   = "circonus-gometrics"
	defaultInterval = 10 * time.Second
)

// a few words about: "BrokerGroupId"
//
// calling it this because the instructions for how to get into the UI and FIND this value are more straight-forward:
//
// log into ui
// navigate to brokers page
// identify which broker you need to use
// click the little down arrow in the circle on the right-hand side of the line for the broker you'd like to use
// use the value from the "GROUP ID:" field under "Broker Details" in the drop-down afetr clicking the down arrow
//
// ... or ...
//
// log into ui
// navigate to brokers page
// identify which broker you need to use
// click the hamburger menu icon (three lines to the left of the broker name)
// click "view API object" from the drop-down menu
// look for "_cid" field, use integer value after "/broker/" e.g. "/broker/35" would be 35
//

type CirconusMetrics struct {
	ApiToken      string
	SubmissionUrl string
	CheckId       int
	ApiApp        string
	ApiHost       string
	InstanceId    string
	SearchTag     string
	BrokerGroupId int
	Tags          []string
	CheckSecret   string

	Interval time.Duration
	Log      *log.Logger
	Debug    bool

	// internals
	ready   bool
	trapUrl string
	trapCN  string
	trapSSL bool
	trapmu  sync.Mutex

	certPool      *x509.CertPool
	cert          []byte
	checkBundle   *CheckBundle
	activeMetrics map[string]bool
	checkType     string

	counters map[string]uint64
	cm       sync.Mutex

	counterFuncs map[string]func() uint64
	cfm          sync.Mutex

	gauges map[string]int64
	gm     sync.Mutex

	gaugeFuncs map[string]func() int64
	gfm        sync.Mutex

	histograms map[string]*Histogram
	hm         sync.Mutex
}

func NewCirconusMetrics() *CirconusMetrics {
	_, an := path.Split(os.Args[0])
	hn, err := os.Hostname()
	if err != nil {
		hn = "unknown"
	}

	return &CirconusMetrics{
		InstanceId:    fmt.Sprintf("%s:%s", hn, an),
		SearchTag:     fmt.Sprintf("service:%s", an),
		ApiHost:       defaultApiHost,
		ApiApp:        defaultApiApp,
		Interval:      defaultInterval,
		Log:           log.New(ioutil.Discard, "", log.LstdFlags),
		Debug:         false,
		ready:         false,
		trapUrl:       "",
		activeMetrics: make(map[string]bool),
		counters:      make(map[string]uint64),
		counterFuncs:  make(map[string]func() uint64),
		gauges:        make(map[string]int64),
		gaugeFuncs:    make(map[string]func() int64),
		histograms:    make(map[string]*Histogram),
		certPool:      x509.NewCertPool(),
		checkType:     "httptrap",
	}

}

// Start starts a perdiodic submission process of all metrics collected
func (m *CirconusMetrics) Start() error {
	if m.Debug {
		m.Log = log.New(os.Stderr, "", log.LstdFlags)
	}
	if !m.ready {
		if err := m.initializeTrap(); err != nil {
			return err
		}
	}

	go func() {
		for _ = range time.NewTicker(m.Interval).C {
			m.Flush()
		}
	}()

	return nil
}

func (m *CirconusMetrics) Flush() {
	m.Log.Println("Flushing")
	if !m.ready {
		if err := m.initializeTrap(); err != nil {
			m.Log.Printf("Unable to initialize check, NOT flushing metrics. %s\n", err)
		}
		return
	}

	// check for new metrics and enable them automatically
	newMetrics := make(map[string]*CheckBundleMetric)

	counters, gauges, histograms := m.snapshot()
	output := make(map[string]interface{})
	for name, value := range counters {
		output[name] = map[string]interface{}{
			"_type":  "n",
			"_value": value,
		}
		if _, ok := m.activeMetrics[name]; !ok {
			newMetrics[name] = &CheckBundleMetric{
				Name:   name,
				Type:   "numeric",
				Status: "active",
			}
		}
	}

	for name, value := range gauges {
		output[name] = map[string]interface{}{
			"_type":  "n",
			"_value": value,
		}
		if _, ok := m.activeMetrics[name]; !ok {
			newMetrics[name] = &CheckBundleMetric{
				Name:   name,
				Type:   "numeric",
				Status: "active",
			}
		}
	}

	for name, value := range histograms {
		output[name] = map[string]interface{}{
			"_type":  "n",
			"_value": value.DecStrings(),
		}
		if _, ok := m.activeMetrics[name]; !ok {
			newMetrics[name] = &CheckBundleMetric{
				Name:   name,
				Type:   "histogram",
				Status: "active",
			}
		}
	}

	m.submit(output, newMetrics)
}
<|endoftext|>