<commit_before>/*-
Copyright (c) 2016, Jörg Pernfuß <code.jpe@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package auth

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"net"
	"net/http"
	"time"

	"github.com/mjolnir42/scrypth64"
)

// Token is the data passed between client and server to
// authenticate the client and issue a token for it that can be used
// as HTTP Basic Auth password.
type Token struct {
	UserName  string `json:"username"`
	Password  string `json:"password,omitempty"`
	Token     string `json:"token,omitempty"`
	ValidFrom string `json:"validFrom,omitempty"`
	ExpiresAt string `json:"expiresAt,omitempty"`
	Salt      string `json:"-"`
	SourceIP  net.IP `json:"-"`
}

// NewToken returns an empty Token
func NewToken() *Token {
	return &Token{}
}

// Generate verifies a the embedded credentials in Token and
// issues a new token to be returned to the user. Calling
// GenerateToken consumes the embedded password regardless of outcome.
// Returns ErrAuth if the password is incorrect.
func (t *Token) Generate(mcf scrypth64.Mcf, key, seed []byte) error {
	var (
		err                 error
		ok                  bool
		stuntSeed, stuntKey []byte
	)
	// do not generate Tokens with an incorrectly configured seed or
	// key
	if seed == nil || key == nil || len(seed) == 0 || len(key) == 0 {
		err = ErrInput
		goto fail
	}

	// net.IP is a bit of a pain since an unset net.IP does not equal
	// nil, and .String() prints `<nil>`
	if t.SourceIP.Equal(net.IP{}) {
		err = ErrInput
		goto fail
	}

	// Username and password have to be set
	if t.UserName == "" || t.Password == "" {
		err = ErrInput
		goto fail
	}

	// stunt data
	stuntSeed = bytes.Repeat([]byte{0x0F}, len(seed))
	stuntKey = bytes.Repeat([]byte{0xAB}, len(key))

	// start of timing critical path
	if ok, err = t.comparePassword(mcf); !ok || err != nil {
		// spend some quality time computing garbage
		t.mixToken(stuntKey, stuntSeed)
		goto fail
	}

	if err = t.mixToken(key, seed); err != nil {
		goto fail
	}

	t.zeroPassword()
	return nil

fail:
	t.zeroPassword()
	if err != nil {
		return err
	}
	return ErrAuth
}

// zeroPassword ensures the Password field is set to the zero value
func (t *Token) zeroPassword() {
	t.Password = ""
}

// comparePassword is used to verify the user supplied password
// against a scrypth64.Mcf
func (t *Token) comparePassword(mcf scrypth64.Mcf) (bool, error) {
	return scrypth64.Verify(t.Password, mcf)
}

// mixToken generates a new password token
func (t *Token) mixToken(key, seed []byte) error {
	var (
		salt, bin, btime []byte
		err              error
		valid, expires   time.Time
	)
	// expiry time
	valid = time.Now().UTC()
	expires = valid.Add(
		time.Duration(TokenExpirySeconds) * time.Second,
	).UTC()
	if btime, err = expires.MarshalBinary(); err != nil {
		goto fail
	}
	t.ValidFrom = valid.Format(rfc3339Milli)
	t.ExpiresAt = expires.Format(rfc3339Milli)

	// add random salt
	salt = make([]byte, 16)
	if _, err = rand.Read(salt); err != nil {
		goto fail
	}
	t.Salt = hex.EncodeToString(salt)

	// compute the token
	bin = computeToken(
		[]byte(t.UserName),
		key,
		seed,
		btime,
		salt,
		[]byte(t.SourceIP.String()),
	)
	t.Token = hex.EncodeToString(bin)

	return nil

fail:
	return err
}

// SetIPAddress records the client's IP address
func (t *Token) SetIPAddress(r *http.Request) {
	t.SourceIP = net.ParseIP(extractAddress(r.RemoteAddr))
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Add Token.SetIPAddressString()<commit_after>/*-
Copyright (c) 2016, Jörg Pernfuß <code.jpe@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package auth

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"net"
	"net/http"
	"time"

	"github.com/mjolnir42/scrypth64"
)

// Token is the data passed between client and server to
// authenticate the client and issue a token for it that can be used
// as HTTP Basic Auth password.
type Token struct {
	UserName  string `json:"username"`
	Password  string `json:"password,omitempty"`
	Token     string `json:"token,omitempty"`
	ValidFrom string `json:"validFrom,omitempty"`
	ExpiresAt string `json:"expiresAt,omitempty"`
	Salt      string `json:"-"`
	SourceIP  net.IP `json:"-"`
}

// NewToken returns an empty Token
func NewToken() *Token {
	return &Token{}
}

// Generate verifies a the embedded credentials in Token and
// issues a new token to be returned to the user. Calling
// GenerateToken consumes the embedded password regardless of outcome.
// Returns ErrAuth if the password is incorrect.
func (t *Token) Generate(mcf scrypth64.Mcf, key, seed []byte) error {
	var (
		err                 error
		ok                  bool
		stuntSeed, stuntKey []byte
	)
	// do not generate Tokens with an incorrectly configured seed or
	// key
	if seed == nil || key == nil || len(seed) == 0 || len(key) == 0 {
		err = ErrInput
		goto fail
	}

	// net.IP is a bit of a pain since an unset net.IP does not equal
	// nil, and .String() prints `<nil>`
	if t.SourceIP.Equal(net.IP{}) {
		err = ErrInput
		goto fail
	}

	// Username and password have to be set
	if t.UserName == "" || t.Password == "" {
		err = ErrInput
		goto fail
	}

	// stunt data
	stuntSeed = bytes.Repeat([]byte{0x0F}, len(seed))
	stuntKey = bytes.Repeat([]byte{0xAB}, len(key))

	// start of timing critical path
	if ok, err = t.comparePassword(mcf); !ok || err != nil {
		// spend some quality time computing garbage
		t.mixToken(stuntKey, stuntSeed)
		goto fail
	}

	if err = t.mixToken(key, seed); err != nil {
		goto fail
	}

	t.zeroPassword()
	return nil

fail:
	t.zeroPassword()
	if err != nil {
		return err
	}
	return ErrAuth
}

// zeroPassword ensures the Password field is set to the zero value
func (t *Token) zeroPassword() {
	t.Password = ""
}

// comparePassword is used to verify the user supplied password
// against a scrypth64.Mcf
func (t *Token) comparePassword(mcf scrypth64.Mcf) (bool, error) {
	return scrypth64.Verify(t.Password, mcf)
}

// mixToken generates a new password token
func (t *Token) mixToken(key, seed []byte) error {
	var (
		salt, bin, btime []byte
		err              error
		valid, expires   time.Time
	)
	// expiry time
	valid = time.Now().UTC()
	expires = valid.Add(
		time.Duration(TokenExpirySeconds) * time.Second,
	).UTC()
	if btime, err = expires.MarshalBinary(); err != nil {
		goto fail
	}
	t.ValidFrom = valid.Format(rfc3339Milli)
	t.ExpiresAt = expires.Format(rfc3339Milli)

	// add random salt
	salt = make([]byte, 16)
	if _, err = rand.Read(salt); err != nil {
		goto fail
	}
	t.Salt = hex.EncodeToString(salt)

	// compute the token
	bin = computeToken(
		[]byte(t.UserName),
		key,
		seed,
		btime,
		salt,
		[]byte(t.SourceIP.String()),
	)
	t.Token = hex.EncodeToString(bin)

	return nil

fail:
	return err
}

// SetIPAddress records the client's IP address
func (t *Token) SetIPAddress(r *http.Request) {
	t.SetIPAddressString(r.RemoteAddr)
}

// SetIPAddressString records the client's IP address
func (t *Token) SetIPAddressString(addr string) {
	t.SourceIP = net.ParseIP(extractAddress(addr))
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package clang

// #include <stdlib.h>
// #include "clang-c/Index.h"
// #include "go-clang.h"
// inline static
// CXCursor _go_clang_ocursor_at(CXCursor *c, int idx) {
//   return c[idx];
// }
import "C"

import (
	"fmt"
)

// TokenKind describes a kind of token
type TokenKind uint32

const (
	/**
	 * \brief A token that contains some kind of punctuation.
	 */
	TK_Punctuation = C.CXToken_Punctuation

	/**
	 * \brief A language keyword.
	 */
	TK_Keyword = C.CXToken_Keyword

	/**
	 * \brief An identifier (that is not a keyword).
	 */
	TK_Identifier = C.CXToken_Identifier

	/**
	 * \brief A numeric, string, or character literal.
	 */
	TK_Literal = C.CXToken_Literal

	/**
	 * \brief A comment.
	 */
	TK_Comment = C.CXToken_Comment
)

func (tk TokenKind) String() string {
	switch tk {
	case TK_Punctuation:
		return "Punctuation"
	case TK_Keyword:
		return "Keyword"
	case TK_Identifier:
		return "Identifier"
	case TK_Literal:
		return "Literal"
	case TK_Comment:
		return "Comment"
	default:
		panic(fmt.Errorf("clang: invalid TokenKind value (%d)", uint32(tk)))
	}
}

// Token is a single preprocessing token.
type Token struct {
	c C.CXToken
}

// Kind determines the kind of this token
func (t Token) Kind() TokenKind {
	o := C.clang_getTokenKind(t.c)
	return TokenKind(o)
}

/**
 * \brief Determine the spelling of the given token.
 *
 * The spelling of a token is the textual representation of that token, e.g.,
 * the text of an identifier or keyword.
 */
func (tu TranslationUnit) TokenSpelling(tok Token) string {
	cstr := cxstring{C.clang_getTokenSpelling(tu.c, tok.c)}
	defer cstr.Dispose()
	return cstr.String()
}

/**
 * \brief Retrieve the source location of the given token.
 */
func (tu TranslationUnit) TokenLocation(tok Token) SourceLocation {
	o := C.clang_getTokenLocation(tu.c, tok.c)
	return SourceLocation{o}
}

/**
 * \brief Retrieve a source range that covers the given token.
 */
func (tu TranslationUnit) TokenExtent(tok Token) SourceRange {
	o := C.clang_getTokenExtent(tu.c, tok.c)
	return SourceRange{o}
}

/**
 * \brief Tokenize the source code described by the given range into raw
 * lexical tokens.
 *
 * \param TU the translation unit whose text is being tokenized.
 *
 * \param Range the source range in which text should be tokenized. All of the
 * tokens produced by tokenization will fall within this source range,
 *
 * \param Tokens this pointer will be set to point to the array of tokens
 * that occur within the given source range. The returned pointer must be
 * freed with clang_disposeTokens() before the translation unit is destroyed.
 *
 * \param NumTokens will be set to the number of tokens in the \c *Tokens
 * array.
 *
 */
func Tokenize(tu TranslationUnit, src SourceRange) Tokens {
	tokens := Tokens{}
	tokens.tu = tu.c
	C.clang_tokenize(tu.c, src.c, &tokens.c, &tokens.n)
	return tokens
}

// an array of tokens
type Tokens struct {
	tu C.CXTranslationUnit
	c  *C.CXToken
	n  C.uint
}

/**
 * \brief Annotate the given set of tokens by providing cursors for each token
 * that can be mapped to a specific entity within the abstract syntax tree.
 *
 * This token-annotation routine is equivalent to invoking
 * clang_getCursor() for the source locations of each of the
 * tokens. The cursors provided are filtered, so that only those
 * cursors that have a direct correspondence to the token are
 * accepted. For example, given a function call \c f(x),
 * clang_getCursor() would provide the following cursors:
 *
 *   * when the cursor is over the 'f', a DeclRefExpr cursor referring to 'f'.
 *   * when the cursor is over the '(' or the ')', a CallExpr referring to 'f'.
 *   * when the cursor is over the 'x', a DeclRefExpr cursor referring to 'x'.
 *
 * Only the first and last of these cursors will occur within the
 * annotate, since the tokens "f" and "x' directly refer to a function
 * and a variable, respectively, but the parentheses are just a small
 * part of the full syntax of the function call expression, which is
 * not provided as an annotation.
 *
 * \param TU the translation unit that owns the given tokens.
 *
 * \param Tokens the set of tokens to annotate.
 *
 * \param NumTokens the number of tokens in \p Tokens.
 *
 * \param Cursors an array of \p NumTokens cursors, whose contents will be
 * replaced with the cursors corresponding to each token.
 */
func (t Tokens) Annotate() []Cursor {
	c_cursors := make([]C.CXCursor, int(t.n))
	C.clang_annotateTokens(t.tu, t.c, t.n, &c_cursors[0])
	cursors := make([]Cursor, int(t.n))
	for i, _ := range cursors {
		cursors[i] = Cursor{C._go_clang_ocursor_at(&c_cursors[0], C.int(i))}
	}
	return cursors
}

/**
 * \brief Free the given set of tokens.
 */
func (t Tokens) Dispose() {
	C.clang_disposeTokens(t.tu, t.c, t.n)
}

// EOF
<commit_msg>token: fix possible out-of-range panic<commit_after>package clang

// #include <stdlib.h>
// #include "clang-c/Index.h"
// #include "go-clang.h"
// inline static
// CXCursor _go_clang_ocursor_at(CXCursor *c, int idx) {
//   return c[idx];
// }
import "C"

import (
	"fmt"
)

// TokenKind describes a kind of token
type TokenKind uint32

const (
	/**
	 * \brief A token that contains some kind of punctuation.
	 */
	TK_Punctuation = C.CXToken_Punctuation

	/**
	 * \brief A language keyword.
	 */
	TK_Keyword = C.CXToken_Keyword

	/**
	 * \brief An identifier (that is not a keyword).
	 */
	TK_Identifier = C.CXToken_Identifier

	/**
	 * \brief A numeric, string, or character literal.
	 */
	TK_Literal = C.CXToken_Literal

	/**
	 * \brief A comment.
	 */
	TK_Comment = C.CXToken_Comment
)

func (tk TokenKind) String() string {
	switch tk {
	case TK_Punctuation:
		return "Punctuation"
	case TK_Keyword:
		return "Keyword"
	case TK_Identifier:
		return "Identifier"
	case TK_Literal:
		return "Literal"
	case TK_Comment:
		return "Comment"
	default:
		panic(fmt.Errorf("clang: invalid TokenKind value (%d)", uint32(tk)))
	}
}

// Token is a single preprocessing token.
type Token struct {
	c C.CXToken
}

// Kind determines the kind of this token
func (t Token) Kind() TokenKind {
	o := C.clang_getTokenKind(t.c)
	return TokenKind(o)
}

/**
 * \brief Determine the spelling of the given token.
 *
 * The spelling of a token is the textual representation of that token, e.g.,
 * the text of an identifier or keyword.
 */
func (tu TranslationUnit) TokenSpelling(tok Token) string {
	cstr := cxstring{C.clang_getTokenSpelling(tu.c, tok.c)}
	defer cstr.Dispose()
	return cstr.String()
}

/**
 * \brief Retrieve the source location of the given token.
 */
func (tu TranslationUnit) TokenLocation(tok Token) SourceLocation {
	o := C.clang_getTokenLocation(tu.c, tok.c)
	return SourceLocation{o}
}

/**
 * \brief Retrieve a source range that covers the given token.
 */
func (tu TranslationUnit) TokenExtent(tok Token) SourceRange {
	o := C.clang_getTokenExtent(tu.c, tok.c)
	return SourceRange{o}
}

/**
 * \brief Tokenize the source code described by the given range into raw
 * lexical tokens.
 *
 * \param TU the translation unit whose text is being tokenized.
 *
 * \param Range the source range in which text should be tokenized. All of the
 * tokens produced by tokenization will fall within this source range,
 *
 * \param Tokens this pointer will be set to point to the array of tokens
 * that occur within the given source range. The returned pointer must be
 * freed with clang_disposeTokens() before the translation unit is destroyed.
 *
 * \param NumTokens will be set to the number of tokens in the \c *Tokens
 * array.
 *
 */
func Tokenize(tu TranslationUnit, src SourceRange) Tokens {
	tokens := Tokens{}
	tokens.tu = tu.c
	C.clang_tokenize(tu.c, src.c, &tokens.c, &tokens.n)
	return tokens
}

// an array of tokens
type Tokens struct {
	tu C.CXTranslationUnit
	c  *C.CXToken
	n  C.uint
}

/**
 * \brief Annotate the given set of tokens by providing cursors for each token
 * that can be mapped to a specific entity within the abstract syntax tree.
 *
 * This token-annotation routine is equivalent to invoking
 * clang_getCursor() for the source locations of each of the
 * tokens. The cursors provided are filtered, so that only those
 * cursors that have a direct correspondence to the token are
 * accepted. For example, given a function call \c f(x),
 * clang_getCursor() would provide the following cursors:
 *
 *   * when the cursor is over the 'f', a DeclRefExpr cursor referring to 'f'.
 *   * when the cursor is over the '(' or the ')', a CallExpr referring to 'f'.
 *   * when the cursor is over the 'x', a DeclRefExpr cursor referring to 'x'.
 *
 * Only the first and last of these cursors will occur within the
 * annotate, since the tokens "f" and "x' directly refer to a function
 * and a variable, respectively, but the parentheses are just a small
 * part of the full syntax of the function call expression, which is
 * not provided as an annotation.
 *
 * \param TU the translation unit that owns the given tokens.
 *
 * \param Tokens the set of tokens to annotate.
 *
 * \param NumTokens the number of tokens in \p Tokens.
 *
 * \param Cursors an array of \p NumTokens cursors, whose contents will be
 * replaced with the cursors corresponding to each token.
 */
func (t Tokens) Annotate() []Cursor {
	c_cursors := make([]C.CXCursor, int(t.n))
	if t.n <= 0 {
		return cursors
	}
	C.clang_annotateTokens(t.tu, t.c, t.n, &c_cursors[0])
	cursors := make([]Cursor, int(t.n))
	for i, _ := range cursors {
		cursors[i] = Cursor{C._go_clang_ocursor_at(&c_cursors[0], C.int(i))}
	}
	return cursors
}

/**
 * \brief Free the given set of tokens.
 */
func (t Tokens) Dispose() {
	C.clang_disposeTokens(t.tu, t.c, t.n)
}

// EOF
<|endoftext|>


<commit_before>package pgtype

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
)

type Text struct {
	String string
	Status Status
}

func (dst *Text) Set(src interface{}) error {
	if src == nil {
		*dst = Text{Status: Null}
		return nil
	}

	if value, ok := src.(interface{ Get() interface{} }); ok {
		value2 := value.Get()
		if value2 != value {
			return dst.Set(value2)
		}
	}

	switch value := src.(type) {
	case string:
		*dst = Text{String: value, Status: Present}
	case *string:
		if value == nil {
			*dst = Text{Status: Null}
		} else {
			*dst = Text{String: *value, Status: Present}
		}
	case []byte:
		if value == nil {
			*dst = Text{Status: Null}
		} else {
			*dst = Text{String: string(value), Status: Present}
		}
	default:
		if originalSrc, ok := underlyingStringType(src); ok {
			return dst.Set(originalSrc)
		}
		return fmt.Errorf("cannot convert %v to Text", value)
	}

	return nil
}

func (dst Text) Get() interface{} {
	switch dst.Status {
	case Present:
		return dst.String
	case Null:
		return nil
	default:
		return dst.Status
	}
}

func (src *Text) AssignTo(dst interface{}) error {
	switch src.Status {
	case Present:
		switch v := dst.(type) {
		case *string:
			*v = src.String
			return nil
		case *[]byte:
			*v = make([]byte, len(src.String))
			copy(*v, src.String)
			return nil
		default:
			if nextDst, retry := GetAssignToDstType(dst); retry {
				return src.AssignTo(nextDst)
			}
			return fmt.Errorf("unable to assign to %T", dst)
		}
	case Null:
		return NullAssignTo(dst)
	}

	return fmt.Errorf("cannot decode %#v into %T", src, dst)
}

func (Text) PreferredResultFormat() int16 {
	return TextFormatCode
}

func (dst *Text) DecodeText(ci *ConnInfo, src []byte) error {
	if src == nil {
		*dst = Text{Status: Null}
		return nil
	}

	*dst = Text{String: string(src), Status: Present}
	return nil
}

func (dst *Text) DecodeBinary(ci *ConnInfo, src []byte) error {
	return dst.DecodeText(ci, src)
}

func (Text) PreferredParamFormat() int16 {
	return TextFormatCode
}

func (src Text) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
	switch src.Status {
	case Null:
		return nil, nil
	case Undefined:
		return nil, errUndefined
	}

	return append(buf, src.String...), nil
}

func (src Text) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
	return src.EncodeText(ci, buf)
}

// Scan implements the database/sql Scanner interface.
func (dst *Text) Scan(src interface{}) error {
	if src == nil {
		*dst = Text{Status: Null}
		return nil
	}

	switch src := src.(type) {
	case string:
		return dst.DecodeText(nil, []byte(src))
	case []byte:
		srcCopy := make([]byte, len(src))
		copy(srcCopy, src)
		return dst.DecodeText(nil, srcCopy)
	}

	return fmt.Errorf("cannot scan %T", src)
}

// Value implements the database/sql/driver Valuer interface.
func (src Text) Value() (driver.Value, error) {
	switch src.Status {
	case Present:
		return src.String, nil
	case Null:
		return nil, nil
	default:
		return nil, errUndefined
	}
}

func (src Text) MarshalJSON() ([]byte, error) {
	switch src.Status {
	case Present:
		return json.Marshal(src.String)
	case Null:
		return []byte("null"), nil
	case Undefined:
		return nil, errUndefined
	}

	return nil, errBadStatus
}

func (dst *Text) UnmarshalJSON(b []byte) error {
	var s *string
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}

	if s == nil {
		*dst = Text{Status: Null}
	} else {
		*dst = Text{String: *s, Status: Present}
	}

	return nil
}
<commit_msg>Add support for fmt.Stringer and driver.Valuer in String fields encoding<commit_after>package pgtype

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
)

type Text struct {
	String string
	Status Status
}

func (dst *Text) Set(src interface{}) error {
	if src == nil {
		*dst = Text{Status: Null}
		return nil
	}

	if value, ok := src.(interface{ Get() interface{} }); ok {
		value2 := value.Get()
		if value2 != value {
			return dst.Set(value2)
		}
	}

	switch value := src.(type) {
	case string:
		*dst = Text{String: value, Status: Present}
	case *string:
		if value == nil {
			*dst = Text{Status: Null}
		} else {
			*dst = Text{String: *value, Status: Present}
		}
	case []byte:
		if value == nil {
			*dst = Text{Status: Null}
		} else {
			*dst = Text{String: string(value), Status: Present}
		}
	case fmt.Stringer:
		if value == fmt.Stringer(nil) {
			*dst = Text{Status: Null}
		} else {
			*dst = Text{String: value.String(), Status: Present}
		}
	default:
		// Cannot be part of the switch: If Value() returns nil on
		// non-string, we should still try to checks the underlying type
		// using reflection.
		//
		// For example the struct might implement driver.Valuer with
		// pointer receiver and fmt.Stringer with value receiver.
		if value, ok := src.(driver.Valuer); ok {
			if value == driver.Valuer(nil) {
				*dst = Text{Status: Null}
				return nil
			} else {
				v, err := value.Value()
				if err != nil {
					return fmt.Errorf("driver.Valuer Value() method failed: %w", err)
				}

				// Handles also v == nil case.
				if s, ok := v.(string); ok {
					*dst = Text{String: s, Status: Present}
					return nil
				}
			}
		}

		if originalSrc, ok := underlyingStringType(src); ok {
			return dst.Set(originalSrc)
		}
		return fmt.Errorf("cannot convert %v to Text", value)
	}

	return nil
}

func (dst Text) Get() interface{} {
	switch dst.Status {
	case Present:
		return dst.String
	case Null:
		return nil
	default:
		return dst.Status
	}
}

func (src *Text) AssignTo(dst interface{}) error {
	switch src.Status {
	case Present:
		switch v := dst.(type) {
		case *string:
			*v = src.String
			return nil
		case *[]byte:
			*v = make([]byte, len(src.String))
			copy(*v, src.String)
			return nil
		default:
			if nextDst, retry := GetAssignToDstType(dst); retry {
				return src.AssignTo(nextDst)
			}
			return fmt.Errorf("unable to assign to %T", dst)
		}
	case Null:
		return NullAssignTo(dst)
	}

	return fmt.Errorf("cannot decode %#v into %T", src, dst)
}

func (Text) PreferredResultFormat() int16 {
	return TextFormatCode
}

func (dst *Text) DecodeText(ci *ConnInfo, src []byte) error {
	if src == nil {
		*dst = Text{Status: Null}
		return nil
	}

	*dst = Text{String: string(src), Status: Present}
	return nil
}

func (dst *Text) DecodeBinary(ci *ConnInfo, src []byte) error {
	return dst.DecodeText(ci, src)
}

func (Text) PreferredParamFormat() int16 {
	return TextFormatCode
}

func (src Text) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
	switch src.Status {
	case Null:
		return nil, nil
	case Undefined:
		return nil, errUndefined
	}

	return append(buf, src.String...), nil
}

func (src Text) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
	return src.EncodeText(ci, buf)
}

// Scan implements the database/sql Scanner interface.
func (dst *Text) Scan(src interface{}) error {
	if src == nil {
		*dst = Text{Status: Null}
		return nil
	}

	switch src := src.(type) {
	case string:
		return dst.DecodeText(nil, []byte(src))
	case []byte:
		srcCopy := make([]byte, len(src))
		copy(srcCopy, src)
		return dst.DecodeText(nil, srcCopy)
	}

	return fmt.Errorf("cannot scan %T", src)
}

// Value implements the database/sql/driver Valuer interface.
func (src Text) Value() (driver.Value, error) {
	switch src.Status {
	case Present:
		return src.String, nil
	case Null:
		return nil, nil
	default:
		return nil, errUndefined
	}
}

func (src Text) MarshalJSON() ([]byte, error) {
	switch src.Status {
	case Present:
		return json.Marshal(src.String)
	case Null:
		return []byte("null"), nil
	case Undefined:
		return nil, errUndefined
	}

	return nil, errBadStatus
}

func (dst *Text) UnmarshalJSON(b []byte) error {
	var s *string
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}

	if s == nil {
		*dst = Text{Status: Null}
	} else {
		*dst = Text{String: *s, Status: Present}
	}

	return nil
}
<|endoftext|>


<commit_before>package z

import (
	"strconv"
	"time"
)

// 获取本地时间戳纳秒,以字符串格式返回
func UnixNano() string {
	return strconv.FormatInt(time.Now().UnixNano(), 10)
}

// 获取本地事件毫秒
func UnixMsSec(off int) int64 {
	return (time.Now().Unix() + int64(off)) * 1000
}

// 获取某个时间当天的绝对秒数
func DAoffSec(t time.Time, off int) int {
	hour, min, sec := t.Clock()
	return hour*3600 + min*60 + sec + off
}

// 获取当天的绝对秒数，根据当前时间 +n
func DAsec(off int) int {
	return DAoffSec(time.Now(), off)
}

// 获得当前系统时间
func GetTime() string {
	return time.Now().Format("2006/01/02 15/04/05")
}
<commit_msg>添加两个事件parse方法<commit_after>package z

import (
	"strconv"
	"time"
)

const FORMAT_DATE string = "2006-01-02"
const FORMAT_DATE_TIME string = "2006-01-02 15:04:05"

// 获取本地时间戳纳秒,以字符串格式返回
func UnixNano() string {
	return strconv.FormatInt(time.Now().UnixNano(), 10)
}

// 获取本地事件毫秒
func UnixMsSec(off int) int64 {
	return (time.Now().Unix() + int64(off)) * 1000
}

// 获取某个时间当天的绝对秒数
func DAoffSec(t time.Time, off int) int {
	hour, min, sec := t.Clock()
	return hour*3600 + min*60 + sec + off
}

// 获取当天的绝对秒数，根据当前时间 +n
func DAsec(off int) int {
	return DAoffSec(time.Now(), off)
}

// 获得当前系统时间
func GetTime() string {
	return time.Now().Format(FORMAT_DATE_TIME)
}

func ParseDate(dstr string) time.Time {
	t, _ := time.Parse(FORMAT_DATE, dstr)
	return t
}

func ParseDateTime(dtstr string) time.Time {
	t, _ := time.Parse(FORMAT_DATE_TIME, dtstr)
	return t
}
<|endoftext|>


<commit_before>package ircclient

import (
	"strings"
	"sync"

	"github.com/goshuirc/irc-go/ircmsg"
)

/**
 * ClientCaps holds the capabilities between the client and server
 */
type ClientCaps struct {
	Wanted    []string
	Enabled   map[string]string
	Available map[string]string
}

// CommonCaps returns a slice of caps that both the client and server support
func (caps *ClientCaps) CommonCaps() []string {
	var common []string

	for _, wantedCap := range caps.Wanted {
		_, exists := caps.Available[wantedCap]
		if exists {
			common = append(common, wantedCap)
		}
	}

	return common
}

// IsEnabled checks if a particular cap is enabled for this connection
func (caps *ClientCaps) IsEnabled(cap string) bool {
	_, exists := caps.Enabled[cap]
	return exists
}

/**
 * Client is the IRC client
 */
type Client struct {
	sync.RWMutex
	Socket
	Nick             string
	Username         string
	Realname         string
	Password         string
	BindHost         string
	Caps             *ClientCaps
	Supported        map[string]string
	HasRegistered    bool
	CommandListeners map[string][]func(*ircmsg.IrcMessage)
}

func NewClient() *Client {
	client := &Client{
		Socket:           *NewSocket(),
		Supported:        make(map[string]string),
		CommandListeners: make(map[string][]func(*ircmsg.IrcMessage)),
	}

	client.Caps = &ClientCaps{
		Enabled:   make(map[string]string),
		Available: make(map[string]string),
	}

	client.Caps.Wanted = append(
		client.Caps.Wanted,
		"account-notify",
		"away-notify",
		"extended-join",
		"multi-prefix",
		"sasl",
		"account-tag",
		"cap-notify",
		"chghost",
		"invite-notify",
		"server-time",
		"userhost-in-names",
	)

	return client
}

func (client *Client) Connect() error {
	err := client.Socket.Connect()
	if err != nil {
		return err
	}

	go client.messageDispatcher()

	client.WriteLine("CAP LS 302")
	client.WriteLine("NICK %s", client.Nick)
	client.WriteLine("USER %s 0 * :%s", client.Username, client.Realname)

	return nil
}

func (client *Client) HandleCommand(command string, fn func(*ircmsg.IrcMessage)) {
	command = strings.ToUpper(command)

	ar, _ := client.CommandListeners[command]
	if ar == nil {
		ar = make([]func(*ircmsg.IrcMessage), 0)
		client.CommandListeners[command] = ar
	}

	client.CommandListeners[command] = append(client.CommandListeners[command], fn)
}

func (client *Client) messageDispatcher() {
	var handlers []func(*ircmsg.IrcMessage)

	for {
		message, isOK := <-client.MessagesIn
		if !isOK {
			break
		}

		// Run our internal command handlers first
		command, commandExists := ServerCommands[message.Command]
		if commandExists {
			command.Run(client, &message)
		}

		// Dispatch any command handler
		handlers, _ = client.CommandListeners[strings.ToUpper(message.Command)]
		if handlers != nil {
			for _, handler := range handlers {
				handler(&message)
			}
		}

		// Dispatch any ALL handlers
		handlers, _ = client.CommandListeners["ALL"]
		if handlers != nil {
			for _, handler := range handlers {
				handler(&message)
			}
		}
	}

	handlers, _ = client.CommandListeners["CLOSED"]
	if handlers != nil {
		for _, handler := range handlers {
			handler(nil)
		}
	}

	client.HasRegistered = false
}

func (client *Client) JoinChannel(channel string, key string) {
	if client.Connected {
		client.WriteLine("JOIN %s %s", channel, key)
	}
}
<commit_msg>Precautionary locks on ircclient<commit_after>package ircclient

import (
	"strings"
	"sync"

	"github.com/goshuirc/irc-go/ircmsg"
)

/**
 * ClientCaps holds the capabilities between the client and server
 */
type ClientCaps struct {
	Wanted    []string
	Enabled   map[string]string
	Available map[string]string
}

// CommonCaps returns a slice of caps that both the client and server support
func (caps *ClientCaps) CommonCaps() []string {
	var common []string

	for _, wantedCap := range caps.Wanted {
		_, exists := caps.Available[wantedCap]
		if exists {
			common = append(common, wantedCap)
		}
	}

	return common
}

// IsEnabled checks if a particular cap is enabled for this connection
func (caps *ClientCaps) IsEnabled(cap string) bool {
	_, exists := caps.Enabled[cap]
	return exists
}

/**
 * Client is the IRC client
 */
type Client struct {
	sync.RWMutex
	Socket
	Nick             string
	Username         string
	Realname         string
	Password         string
	BindHost         string
	Caps             *ClientCaps
	Supported        map[string]string
	HasRegistered    bool
	CommandListeners map[string][]func(*ircmsg.IrcMessage)
}

func NewClient() *Client {
	client := &Client{
		Socket:           *NewSocket(),
		Supported:        make(map[string]string),
		CommandListeners: make(map[string][]func(*ircmsg.IrcMessage)),
	}

	client.Caps = &ClientCaps{
		Enabled:   make(map[string]string),
		Available: make(map[string]string),
	}

	client.Caps.Wanted = append(
		client.Caps.Wanted,
		"account-notify",
		"away-notify",
		"extended-join",
		"multi-prefix",
		"sasl",
		"account-tag",
		"cap-notify",
		"chghost",
		"invite-notify",
		"server-time",
		"userhost-in-names",
	)

	return client
}

func (client *Client) Connect() error {
	err := client.Socket.Connect()
	if err != nil {
		return err
	}

	go client.messageDispatcher()

	client.WriteLine("CAP LS 302")
	client.WriteLine("NICK %s", client.Nick)
	client.WriteLine("USER %s 0 * :%s", client.Username, client.Realname)

	return nil
}

func (client *Client) HandleCommand(command string, fn func(*ircmsg.IrcMessage)) {
	client.Lock()
	defer client.Unlock()

	command = strings.ToUpper(command)

	ar, _ := client.CommandListeners[command]
	if ar == nil {
		ar = make([]func(*ircmsg.IrcMessage), 0)
		client.CommandListeners[command] = ar
	}

	client.CommandListeners[command] = append(client.CommandListeners[command], fn)
}

func (client *Client) messageDispatcher() {
	var handlers []func(*ircmsg.IrcMessage)

	for {
		message, isOK := <-client.MessagesIn
		if !isOK {
			break
		}

		// Run our internal command handlers first
		command, commandExists := ServerCommands[message.Command]
		if commandExists {
			command.Run(client, &message)
		}

		// Dispatch any command handler
		handlers, _ = client.CommandListeners[strings.ToUpper(message.Command)]
		if handlers != nil {
			for _, handler := range handlers {
				handler(&message)
			}
		}

		// Dispatch any ALL handlers
		handlers, _ = client.CommandListeners["ALL"]
		if handlers != nil {
			for _, handler := range handlers {
				handler(&message)
			}
		}
	}

	handlers, _ = client.CommandListeners["CLOSED"]
	if handlers != nil {
		for _, handler := range handlers {
			handler(nil)
		}
	}

	client.Lock()
	client.HasRegistered = false
	client.Unlock()
}

func (client *Client) JoinChannel(channel string, key string) {
	if client.Connected {
		client.WriteLine("JOIN %s %s", channel, key)
	}
}
<|endoftext|>


<commit_before>package maze

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"

	tk "github.com/quintans/toolkit"
	"github.com/quintans/toolkit/log"
)

var logger = log.LoggerFor("github.com/quintans/maze")

// NewMaze creates maze with context factory. If nil, it uses a default context factory
func NewMaze(contextFactory func(w http.ResponseWriter, r *http.Request, filters []*Filter) IContext) *Maze {
	this := new(Maze)
	this.filters = make([]*Filter, 0)
	this.contextFactory = contextFactory
	return this
}

type Maze struct {
	filters        []*Filter
	contextFactory func(w http.ResponseWriter, r *http.Request, filters []*Filter) IContext
	lastRule       string
}

func (this *Maze) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if len(this.filters) > 0 {
		var ctx IContext
		if this.contextFactory == nil {
			// default
			ctx = NewContext(w, r, this.filters)
		} else {
			ctx = this.contextFactory(w, r, this.filters)
		}
		err := ctx.Proceed()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

func (this *Maze) GET(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"GET"}, rule, filters...)
}

func (this *Maze) POST(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"POST"}, rule, filters...)
}

func (this *Maze) PUT(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"PUT"}, rule, filters...)
}

func (this *Maze) DELETE(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"DELETE"}, rule, filters...)
}

func (this *Maze) Push(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod(nil, rule, filters...)
}

// PushMethod adds the filters to the end of the last filters.
// If the rule does NOT start with '/' the applied rule will be
// the concatenation of the last rule that started with '/' and ended with a '*'
// with this one (the '*' is omitted).
// ex: /greet/* + sayHi/{Id} = /greet/sayHi/{Id}
func (this *Maze) PushMethod(methods []string, rule string, handlers ...func(ctx IContext) error) {
	if strings.HasPrefix(rule, "/") {
		if strings.HasSuffix(rule, "*") {
			this.lastRule = rule[:len(rule)-1]
			logger.Debug("Last main rule set as", this.lastRule)
		} else {
			// resets lastRule
			this.lastRule = ""
		}
	} else if !strings.HasPrefix(rule, "*") {
		if this.lastRule == "" {
			rule = "/" + rule
		} else {
			rule = this.lastRule + rule
		}
	}

	if len(handlers) > 0 {
		f := ConvertHandlers(handlers...)
		// rule is only set for the first filter
		if rule != "" {
			logger.Debug("registering rule", rule)
			f[0].rule = rule
			if i := strings.Index(rule, "{"); i != -1 {
				f[0].template = strings.Split(rule, "/")
			}
		}
		f[0].allowedMethods = methods

		this.filters = append(this.filters, f...)
	}
}

func (this *Maze) Add(filters ...*Filter) {
	this.filters = append(this.filters, filters...)
}

type IContext interface {
	Proceed() error
	GetResponse() http.ResponseWriter
	GetRequest() *http.Request
	GetAttribute(interface{}) interface{}
	SetAttribute(interface{}, interface{})
	CurrentFilter() *Filter

	// Payload put the json string in the request body into the struct passed as an interface{}
	Payload(interface{}) error
	// PathVars put the path parameters in a url into the struct passed as an interface{}
	PathVars(interface{}) error
	// QueryVars put the parameters in the query part of a url into the struct passed as an interface{}
	QueryVars(interface{}) error
	// Vars
	Vars(interface{}) error
	// Reply marshals the interface{} value into a json string and sends it into the response
	JSON(interface{}) error
}

var _ IContext = &Context{}

type Context struct {
	Response   http.ResponseWriter
	Request    *http.Request
	Attributes map[interface{}]interface{} // attributes only valid in this request
	filters    []*Filter
	filterPos  int
	// Enable to call methods of the extended struct
	// or to cast the IContext parameter of the handler function
	// to the right context struct
	Overrider IContext
}

func NewContext(w http.ResponseWriter, r *http.Request, filters []*Filter) *Context {
	var this = new(Context)
	this.Overrider = this
	this.Response = w
	this.Request = r
	this.filterPos = -1
	this.filters = filters
	this.Attributes = make(map[interface{}]interface{})
	return this
}

func (this *Context) nextFilter() *Filter {
	this.filterPos++
	if this.filterPos < len(this.filters) {
		return this.filters[this.filterPos]
	}
	// don't let ir go higher than the max
	this.filterPos = len(this.filters)

	return nil
}

// Proceed proceeds to the next valid rule
func (this *Context) Proceed() error {
	var c = this.Overrider
	var next = this.nextFilter()
	if next != nil {
		if next.rule == "" {
			logger.Debug("executing filter without rule")
			return next.handler(c)
		} else {
			// go to the next valid filter.
			// I don't use recursivity for this, because it can be very deep
			for i := this.filterPos; i < len(this.filters); i++ {
				var n = this.filters[i]
				if n.rule != "" && n.IsValid(c) {
					this.filterPos = i
					logger.Debugf("executing filter %s", n.rule)
					return n.handler(c)
				}
			}
		}
	}

	return nil
}

func (this *Context) GetResponse() http.ResponseWriter {
	return this.Response
}

func (this *Context) GetRequest() *http.Request {
	return this.Request
}

func (this *Context) GetAttribute(key interface{}) interface{} {
	return this.Attributes[key]
}

func (this *Context) SetAttribute(key interface{}, value interface{}) {
	this.Attributes[key] = value
}

func (this *Context) CurrentFilter() *Filter {
	if this.filterPos < len(this.filters) {
		return this.filters[this.filterPos]
	}
	return nil
}

func (this *Context) Payload(value interface{}) error {
	if this.Request.Body != nil {
		payload, err := ioutil.ReadAll(this.Request.Body)
		if err != nil {
			return err
		}

		return json.Unmarshal(payload, value)
	}

	return nil
}

// PathVars put the path parameters in a url into the struct passed as an interface{}
func (this *Context) PathVars(value interface{}) error {
	var filter = this.CurrentFilter()
	if filter.jsonPath != "" {
		return json.Unmarshal([]byte(filter.jsonPath), value)
	}

	return nil
}

// QueryVars put the parameters in the query part of a url into the struct passed as an interface{}
func (this *Context) QueryVars(value interface{}) error {
	var t = reflect.TypeOf(value)
	if t.Kind() != reflect.Ptr {
		return errors.New("Query value must be a pointer, not " + t.Kind().String())
	}
	t = t.Elem()
	if t.Kind() != reflect.Struct {
		return errors.New("Query value must be of kind struct, not " + t.Kind().String())
	}

	// create a json string and then unmarshal
	var values = this.GetRequest().URL.Query()
	var jsonQuery string
	if len(values) > 0 {
		var json = ""

		for i := 0; i < t.NumField(); i++ {
			var f = t.Field(i)
			var name = f.Name
			var v = values.Get(name)

			if v == "" {
				name = tk.UncapFirst(f.Name)
				v = values.Get(name)
			}

			if v != "" {
				var k = f.Type.Kind()
				if k == reflect.Bool {
					v = toJsonVal(v, "bool")
				} else if k >= reflect.Int && k <= reflect.Float64 {
					v = toJsonVal(v, "number")
				} else {
					v = toJsonVal(v, "string")
				}

				if len(json) > 0 {
					json += ", "
				}
				json += fmt.Sprintf(`"%s": %s`, name, v)
			}
		}
		if json != "" {
			jsonQuery = "{" + json + "}"
		}
	}

	if jsonQuery != "" {
		return json.Unmarshal([]byte(jsonQuery), value)
	}

	return nil
}

func (this *Context) Vars(value interface{}) error {
	if err := this.QueryVars(value); err != nil {
		return err
	}
	if err := this.PathVars(value); err != nil {
		return err
	}

	return nil
}

func (this *Context) JSON(value interface{}) error {
	var s string
	if value == nil {
		s = tk.ToString(value)
		_, err := this.Response.Write([]byte(s))
		return err
	}

	this.GetResponse().WriteHeader(http.StatusOK)
	return nil
}

type Filterer interface {
	Handle(ctx IContext) error
}

type Filter struct {
	rule           string
	template       []string
	jsonPath       string
	allowedMethods []string

	handler func(ctx IContext) error
}

func NewFilter(rule string, handler func(c IContext) error) *Filter {
	var this = new(Filter)
	this.rule = rule
	this.handler = handler
	return this
}

func (this *Filter) IsValid(ctx IContext) bool {
	// verify if method is allowed
	var allowed bool
	if this.allowedMethods == nil {
		allowed = true
	} else {
		var method = ctx.GetRequest().Method
		if method == "" {
			method = "GET"
		}
		for _, v := range this.allowedMethods {
			if method == v {
				allowed = true
				break
			}
		}
	}

	if allowed {
		var path = ctx.GetRequest().URL.Path
		if strings.HasPrefix(this.rule, "*") {
			return strings.HasSuffix(path, this.rule[1:])
		} else if strings.HasSuffix(this.rule, "*") {
			return strings.HasPrefix(path, this.rule[:len(this.rule)-1])
		} else if this.template != nil {
			var ok bool
			this.jsonPath, ok = this.parseToJson(path)
			return ok
		} else {
			return path == this.rule
		}
	}

	return false
}

// parseToJson converts path vars into json string
// and also checks if its a valid match with the url template
func (this *Filter) parseToJson(path string) (string, bool) {
	var json = ""
	var parts = strings.Split(path, "/")

	if len(parts) != len(this.template) {
		return "", false
	}

	for k, v := range this.template {
		if strings.HasPrefix(v, "{") {
			var name = v[1 : len(v)-1]
			var nameType = strings.Split(name, ":")
			name = nameType[0]
			var typ string
			if len(nameType) > 1 {
				typ = nameType[1]
			}

			var val = toJsonVal(parts[k], typ)
			if len(json) > 0 {
				json += ", "
			}
			json += fmt.Sprintf(`"%s": %s`, name, val)

		} else if v != parts[k] {
			return "", false
		}
	}

	return "{" + json + "}", true
}

func toJsonVal(ori string, typ string) string {
	var val = ori

	switch typ {
	case "number":
	case "bool":
		if val == "1" || val == "true" || val == "t" {
			val = "true"
		} else {
			val = "false"
		}
	default:
		val = "\"" + val + "\""
	}

	return val
}

func ConvertHandlers(handlers ...func(ctx IContext) error) []*Filter {
	var filters = make([]*Filter, len(handlers))
	for k, v := range handlers {
		filters[k] = &Filter{handler: v}
	}
	return filters
}
<commit_msg>fixed Context.JSON() and added IContext.SetResponse()<commit_after>package maze

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"

	tk "github.com/quintans/toolkit"
	"github.com/quintans/toolkit/log"
	"github.com/quintans/toolkit/web"
)

var logger = log.LoggerFor("github.com/quintans/maze")

// NewMaze creates maze with context factory. If nil, it uses a default context factory
func NewMaze(contextFactory func(w http.ResponseWriter, r *http.Request, filters []*Filter) IContext) *Maze {
	this := new(Maze)
	this.filters = make([]*Filter, 0)
	this.contextFactory = contextFactory
	return this
}

type Maze struct {
	filters        []*Filter
	contextFactory func(w http.ResponseWriter, r *http.Request, filters []*Filter) IContext
	lastRule       string
}

func (this *Maze) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if len(this.filters) > 0 {
		var ctx IContext
		if this.contextFactory == nil {
			// default
			ctx = NewContext(w, r, this.filters)
		} else {
			ctx = this.contextFactory(w, r, this.filters)
		}
		err := ctx.Proceed()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

func (this *Maze) GET(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"GET"}, rule, filters...)
}

func (this *Maze) POST(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"POST"}, rule, filters...)
}

func (this *Maze) PUT(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"PUT"}, rule, filters...)
}

func (this *Maze) DELETE(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod([]string{"DELETE"}, rule, filters...)
}

func (this *Maze) Push(rule string, filters ...func(ctx IContext) error) {
	this.PushMethod(nil, rule, filters...)
}

// PushMethod adds the filters to the end of the last filters.
// If the rule does NOT start with '/' the applied rule will be
// the concatenation of the last rule that started with '/' and ended with a '*'
// with this one (the '*' is omitted).
// ex: /greet/* + sayHi/{Id} = /greet/sayHi/{Id}
func (this *Maze) PushMethod(methods []string, rule string, handlers ...func(ctx IContext) error) {
	if strings.HasPrefix(rule, "/") {
		if strings.HasSuffix(rule, "*") {
			this.lastRule = rule[:len(rule)-1]
			logger.Debug("Last main rule set as", this.lastRule)
		} else {
			// resets lastRule
			this.lastRule = ""
		}
	} else if !strings.HasPrefix(rule, "*") {
		if this.lastRule == "" {
			rule = "/" + rule
		} else {
			rule = this.lastRule + rule
		}
	}

	if len(handlers) > 0 {
		f := ConvertHandlers(handlers...)
		// rule is only set for the first filter
		if rule != "" {
			logger.Debug("registering rule", rule)
			f[0].rule = rule
			if i := strings.Index(rule, "{"); i != -1 {
				f[0].template = strings.Split(rule, "/")
			}
		}
		f[0].allowedMethods = methods

		this.filters = append(this.filters, f...)
	}
}

func (this *Maze) Add(filters ...*Filter) {
	this.filters = append(this.filters, filters...)
}

// Static serves static content.
// rule defines the rule and dir the relative path
func (this *Maze) Static(rule string, dir string) {
	// delivering static content and preventing malicious access
	var fs = web.OnlyFilesFS{http.Dir(dir)}
	var fileServer = http.FileServer(fs)
	this.GET(rule, func(ctx IContext) error {
		fileServer.ServeHTTP(ctx.GetResponse(), ctx.GetRequest())
		return nil
	})
}

type IContext interface {
	Proceed() error
	GetResponse() http.ResponseWriter
	SetResponse(http.ResponseWriter)
	GetRequest() *http.Request
	GetAttribute(interface{}) interface{}
	SetAttribute(interface{}, interface{})
	CurrentFilter() *Filter

	// Payload put the json string in the request body into the struct passed as an interface{}
	Payload(interface{}) error
	// PathVars put the path parameters in a url into the struct passed as an interface{}
	PathVars(interface{}) error
	// QueryVars put the parameters in the query part of a url into the struct passed as an interface{}
	QueryVars(interface{}) error
	// Vars
	Vars(interface{}) error
	// TEXT converts to string the interface{} value and sends it into the response
	TEXT(interface{}) error
	// JSON marshals the interface{} value into a json string and sends it into the response
	JSON(interface{}) error
}

var _ IContext = &Context{}

type Context struct {
	Response   http.ResponseWriter
	Request    *http.Request
	Attributes map[interface{}]interface{} // attributes only valid in this request
	filters    []*Filter
	filterPos  int
	// Enable to call methods of the extended struct
	// or to cast the IContext parameter of the handler function
	// to the right context struct
	Overrider IContext
}

func NewContext(w http.ResponseWriter, r *http.Request, filters []*Filter) *Context {
	var this = new(Context)
	this.Overrider = this
	this.Response = w
	this.Request = r
	this.filterPos = -1
	this.filters = filters
	this.Attributes = make(map[interface{}]interface{})
	return this
}

func (this *Context) nextFilter() *Filter {
	this.filterPos++
	if this.filterPos < len(this.filters) {
		return this.filters[this.filterPos]
	}
	// don't let ir go higher than the max
	this.filterPos = len(this.filters)

	return nil
}

// Proceed proceeds to the next valid rule
func (this *Context) Proceed() error {
	var c = this.Overrider
	var next = this.nextFilter()
	if next != nil {
		if next.rule == "" {
			logger.Debug("executing filter without rule")
			return next.handler(c)
		} else {
			// go to the next valid filter.
			// I don't use recursivity for this, because it can be very deep
			for i := this.filterPos; i < len(this.filters); i++ {
				var n = this.filters[i]
				if n.rule != "" && n.IsValid(c) {
					this.filterPos = i
					logger.Debugf("executing filter %s", n.rule)
					return n.handler(c)
				}
			}
		}
	}

	return nil
}

func (this *Context) GetResponse() http.ResponseWriter {
	return this.Response
}

func (this *Context) SetResponse(w http.ResponseWriter) {
	this.Response = w
}

func (this *Context) GetRequest() *http.Request {
	return this.Request
}

func (this *Context) GetAttribute(key interface{}) interface{} {
	return this.Attributes[key]
}

func (this *Context) SetAttribute(key interface{}, value interface{}) {
	this.Attributes[key] = value
}

func (this *Context) CurrentFilter() *Filter {
	if this.filterPos < len(this.filters) {
		return this.filters[this.filterPos]
	}
	return nil
}

func (this *Context) Payload(value interface{}) error {
	if this.Request.Body != nil {
		payload, err := ioutil.ReadAll(this.Request.Body)
		if err != nil {
			return err
		}

		return json.Unmarshal(payload, value)
	}

	return nil
}

// PathVars put the path parameters in a url into the struct passed as an interface{}
func (this *Context) PathVars(value interface{}) error {
	var filter = this.CurrentFilter()
	if filter.jsonPath != "" {
		return json.Unmarshal([]byte(filter.jsonPath), value)
	}

	return nil
}

// QueryVars put the parameters in the query part of a url into the struct passed as an interface{}
func (this *Context) QueryVars(value interface{}) error {
	var t = reflect.TypeOf(value)
	if t.Kind() != reflect.Ptr {
		return errors.New("Query value must be a pointer, not " + t.Kind().String())
	}
	t = t.Elem()
	if t.Kind() != reflect.Struct {
		return errors.New("Query value must be of kind struct, not " + t.Kind().String())
	}

	// create a json string and then unmarshal
	var values = this.GetRequest().URL.Query()
	var jsonQuery string
	if len(values) > 0 {
		var json = ""

		for i := 0; i < t.NumField(); i++ {
			var f = t.Field(i)
			var name = f.Name
			var v = values.Get(name)

			if v == "" {
				name = tk.UncapFirst(f.Name)
				v = values.Get(name)
			}

			if v != "" {
				var k = f.Type.Kind()
				if k == reflect.Bool {
					v = toJsonVal(v, "bool")
				} else if k >= reflect.Int && k <= reflect.Float64 {
					v = toJsonVal(v, "number")
				} else {
					v = toJsonVal(v, "string")
				}

				if len(json) > 0 {
					json += ", "
				}
				json += fmt.Sprintf(`"%s": %s`, name, v)
			}
		}
		if json != "" {
			jsonQuery = "{" + json + "}"
		}
	}

	if jsonQuery != "" {
		return json.Unmarshal([]byte(jsonQuery), value)
	}

	return nil
}

func (this *Context) Vars(value interface{}) error {
	if err := this.QueryVars(value); err != nil {
		return err
	}
	if err := this.PathVars(value); err != nil {
		return err
	}

	return nil
}

func (this *Context) TEXT(value interface{}) error {
	var w = this.GetResponse()
	//w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	if value != nil {
		var s = tk.ToString(value)
		if _, err := w.Write([]byte(s)); err != nil {
			return err
		}
	}

	w.WriteHeader(http.StatusOK)
	return nil
}

func (this *Context) JSON(value interface{}) error {
	var w = this.GetResponse()
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	if value != nil {
		result, err := json.Marshal(value)
		if err != nil {
			return err
		}
		_, err = w.Write(result)
		if err != nil {
			return err
		}
	}

	w.WriteHeader(http.StatusOK)
	return nil
}

type Filterer interface {
	Handle(ctx IContext) error
}

type Filter struct {
	rule           string
	template       []string
	jsonPath       string
	allowedMethods []string

	handler func(ctx IContext) error
}

func NewFilter(rule string, handler func(c IContext) error) *Filter {
	var this = new(Filter)
	this.rule = rule
	this.handler = handler
	return this
}

func (this *Filter) IsValid(ctx IContext) bool {
	// verify if method is allowed
	var allowed bool
	if this.allowedMethods == nil {
		allowed = true
	} else {
		var method = ctx.GetRequest().Method
		if method == "" {
			method = "GET"
		}
		for _, v := range this.allowedMethods {
			if method == v {
				allowed = true
				break
			}
		}
	}

	if allowed {
		var path = ctx.GetRequest().URL.Path
		if strings.HasPrefix(this.rule, "*") {
			return strings.HasSuffix(path, this.rule[1:])
		} else if strings.HasSuffix(this.rule, "*") {
			return strings.HasPrefix(path, this.rule[:len(this.rule)-1])
		} else if this.template != nil {
			var ok bool
			this.jsonPath, ok = this.parseToJson(path)
			return ok
		} else {
			return path == this.rule
		}
	}

	return false
}

// parseToJson converts path vars into json string
// and also checks if its a valid match with the url template
func (this *Filter) parseToJson(path string) (string, bool) {
	var json = ""
	var parts = strings.Split(path, "/")

	if len(parts) != len(this.template) {
		return "", false
	}

	for k, v := range this.template {
		if strings.HasPrefix(v, "{") {
			var name = v[1 : len(v)-1]
			var nameType = strings.Split(name, ":")
			name = nameType[0]
			var typ string
			if len(nameType) > 1 {
				typ = nameType[1]
			}

			var val = toJsonVal(parts[k], typ)
			if len(json) > 0 {
				json += ", "
			}
			json += fmt.Sprintf(`"%s": %s`, name, val)

		} else if v != parts[k] {
			return "", false
		}
	}

	return "{" + json + "}", true
}

func toJsonVal(ori string, typ string) string {
	var val = ori

	switch typ {
	case "number":
	case "bool":
		if val == "1" || val == "true" || val == "t" {
			val = "true"
		} else {
			val = "false"
		}
	default:
		val = "\"" + val + "\""
	}

	return val
}

func ConvertHandlers(handlers ...func(ctx IContext) error) []*Filter {
	var filters = make([]*Filter, len(handlers))
	for k, v := range handlers {
		filters[k] = &Filter{handler: v}
	}
	return filters
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"
	"strings"
	"time"
)

const (
	defaultMinoX, defaultMinoY = 3, -1
	minoWidth, minoHeight      = 4, 4
)

var (
	blocks = []string{
		`
		  ....
			.gg.
			gg..
			....
		`, `
		  ....
			.rr.
			..rr
			....
		`, `
		  ....
			.YY.
			.YY.
			....
		`, `
		  ....
			....
			CCCC
			....
		`, `
		  ....
			.M..
			MMM.
			....
		`, `
		  ....
			.b..
			.bbb
			....
		`, `
		  ....
			..m.
			mmm.
			....
		`,
	}
)

var (
	currentMino *Mino
	nextMino    *Mino
)

type Mino struct {
	block string
	x     int
	y     int
}

func NewMino() *Mino {
	rand.Seed(time.Now().UnixNano())
	block := blocks[rand.Intn(len(blocks))]
	block = strings.Replace(block, "\t", "", -1)
	block = strings.Replace(block, " ", "", -1)
	block = strings.Trim(block, "\n")
	return &Mino{block: block}
}

func (m *Mino) cell(x, y int) rune {
	return rune(m.block[x+(minoWidth+1)*y])
}

func (m *Mino) setCell(x, y int, cell rune) {
	buf := []rune(m.block)
	buf[x+(minoWidth+1)*y] = cell
	m.block = string(buf)
}

func (m *Mino) applyGravity() {
	m.moveDown()
}

func (m *Mino) moveDown() {
	dstMino := *m
	dstMino.y++
	if dstMino.isOnBoard() {
		m.y++
	} else {
		board.setCells(m.cells())
		pushMino()
	}
}

func (m *Mino) moveLeft() {
	dstMino := *m
	dstMino.x--
	if dstMino.isOnBoard() {
		m.x--
	}
}

func (m *Mino) moveRight() {
	dstMino := *m
	dstMino.x++
	if dstMino.isOnBoard() {
		m.x++
	}
}

func (m *Mino) rotateRight() {
	oldMino := *m

	for j := 0; j < minoHeight; j++ {
		for i := 0; i < minoWidth; i++ {
			m.setCell(minoHeight-j-1, i, oldMino.cell(i, j))
		}
	}
}

func (m *Mino) rotateLeft() {
	oldMino := *m

	for j := 0; j < minoHeight; j++ {
		for i := 0; i < minoWidth; i++ {
			m.setCell(j, minoWidth-i-1, oldMino.cell(i, j))
		}
	}
}

func (m *Mino) isOnBoard() bool {
	for _, cell := range m.cells() {
		cell.isOnBoard()
		if !cell.isOnBoard() {
			return false
		}
	}
	return true
}

func (m *Mino) cells() []*Cell {
	cells := []*Cell{}
	for i := 0; i < minoWidth; i++ {
		for j := 0; j < minoHeight; j++ {
			if m.cell(i, j) != '.' {
				cells = append(cells, NewCell(m.x+i, m.y+j, m.cell(i, j)))
			}
		}
	}
	return cells
}
<commit_msg>Rotate guard<commit_after>package main

import (
	"math/rand"
	"strings"
	"time"
)

const (
	defaultMinoX, defaultMinoY = 3, -1
	minoWidth, minoHeight      = 4, 4
)

var (
	blocks = []string{
		`
		  ....
			.gg.
			gg..
			....
		`, `
		  ....
			.rr.
			..rr
			....
		`, `
		  ....
			.YY.
			.YY.
			....
		`, `
		  ....
			....
			CCCC
			....
		`, `
		  ....
			.M..
			MMM.
			....
		`, `
		  ....
			.b..
			.bbb
			....
		`, `
		  ....
			..m.
			mmm.
			....
		`,
	}
)

var (
	currentMino *Mino
	nextMino    *Mino
)

type Mino struct {
	block string
	x     int
	y     int
}

func NewMino() *Mino {
	rand.Seed(time.Now().UnixNano())
	block := blocks[rand.Intn(len(blocks))]
	block = strings.Replace(block, "\t", "", -1)
	block = strings.Replace(block, " ", "", -1)
	block = strings.Trim(block, "\n")
	return &Mino{block: block}
}

func (m *Mino) cell(x, y int) rune {
	return rune(m.block[x+(minoWidth+1)*y])
}

func (m *Mino) setCell(x, y int, cell rune) {
	buf := []rune(m.block)
	buf[x+(minoWidth+1)*y] = cell
	m.block = string(buf)
}

func (m *Mino) applyGravity() {
	m.moveDown()
}

func (m *Mino) moveDown() {
	dstMino := *m
	dstMino.y++
	if dstMino.isOnBoard() {
		m.y++
	} else {
		board.setCells(m.cells())
		pushMino()
	}
}

func (m *Mino) moveLeft() {
	dstMino := *m
	dstMino.x--
	if dstMino.isOnBoard() {
		m.x--
	}
}

func (m *Mino) moveRight() {
	dstMino := *m
	dstMino.x++
	if dstMino.isOnBoard() {
		m.x++
	}
}

func (m *Mino) rotateRight() {
	dstMino := *m
	dstMino.forceRotateRight()
	if dstMino.isOnBoard() {
		m.forceRotateRight()
	}
}

func (m *Mino) forceRotateRight() {
	oldMino := *m
	for j := 0; j < minoHeight; j++ {
		for i := 0; i < minoWidth; i++ {
			m.setCell(minoHeight-j-1, i, oldMino.cell(i, j))
		}
	}
}

func (m *Mino) rotateLeft() {
	dstMino := *m
	dstMino.forceRotateLeft()
	if dstMino.isOnBoard() {
		m.forceRotateLeft()
	}
}

func (m *Mino) forceRotateLeft() {
	oldMino := *m
	for j := 0; j < minoHeight; j++ {
		for i := 0; i < minoWidth; i++ {
			m.setCell(j, minoWidth-i-1, oldMino.cell(i, j))
		}
	}
}

func (m *Mino) isOnBoard() bool {
	for _, cell := range m.cells() {
		cell.isOnBoard()
		if !cell.isOnBoard() {
			return false
		}
	}
	return true
}

func (m *Mino) cells() []*Cell {
	cells := []*Cell{}
	for i := 0; i < minoWidth; i++ {
		for j := 0; j < minoHeight; j++ {
			if m.cell(i, j) != '.' {
				cells = append(cells, NewCell(m.x+i, m.y+j, m.cell(i, j)))
			}
		}
	}
	return cells
}
<|endoftext|>


<commit_before>package psi

import (
	"github.com/ziutek/dvb"
)

type ServiceType byte

const (
	DigitalTelevisionService ServiceType = iota + 1
	DigitalRadioSoundService
	TeletextService
	NVODReferenceService
	NVODTimeShiftedService
	MosaicService
	PALCodedSignal
	SCAMCodedSignal
	D2MAC
	FMRadio
	NTSCCodedSignal
	DataBroadcastService
)

var stn = []string{
	"digital television service",
	"digital radio sound service",
	"Teletext service",
	"NVOD reference service",
	"NVOD time-shifted service",
	"mosaic service",
	"PAL coded signal",
	"SECAM coded signal",
	"D/D2-MAC",
	"FM Radio",
	"NTSC coded signal",
	"data broadcast service",
}

func (t ServiceType) String() string {
	if t == 0 || t > DataBroadcastService && t <= 0x7F {
		return "reserved"
	}
	if t > 0x7F && t <= 0xfe {
		return "user defined"
	}
	return stn[t-1]
}

type ServiceDescriptor struct {
	Type         ServiceType
	ProviderName []byte
	ServiceName  []byte
}

func ParseServiceDescriptor(d Descriptor) (sd ServiceDescriptor, ok bool) {
	if d.Tag() != ServiceTag {
		return
	}
	data := d.Data()
	if len(data) < 2 {
		return
	}
	sd.Type = ServiceType(data[0])
	providerNameLen := data[1]
	data = data[2:]

	if len(data) < int(providerNameLen+1) {
		return
	}
	sd.ProviderName = data[:providerNameLen]
	serviceNameLen := data[providerNameLen]
	data = data[providerNameLen+1:]

	if len(data) < int(serviceNameLen) {
		return
	}
	sd.ServiceName = data[:serviceNameLen]

	ok = true
	return
}

type NetworkNameDescriptor []byte

func ParseNetworkNameDescriptor(d Descriptor) (nnd NetworkNameDescriptor, ok bool) {
	if d.Tag() != NetworkNameTag {
		return
	}
	nnd = NetworkNameDescriptor(d.Data())
	ok = true
	return
}

type ServiceListDescriptor []byte

func ParseServiceListDescriptor(d Descriptor) (sld ServiceListDescriptor, ok bool) {
	if d.Tag() != ServiceListTag {
		return
	}
	sld = ServiceListDescriptor(d.Data())
	ok = true
	return
}

// Pop returns first (sid, typ) pair from d. Remaining pairs are returned in rd.
// If there is no more pairs to read len(rd) == 0.
// If an error occurs rd = nil
func (d ServiceListDescriptor) Pop() (sid uint16, typ ServiceType, rd ServiceListDescriptor) {
	if len(d) < 3 {
		return
	}
	sid = decodeU16(d[0:2])
	typ = ServiceType(d[2])
	rd = d[3:]
	return
}

type TerrestrialDeliverySystemDescriptor struct {
	Freq          uint64 // center frequency [Hz]
	Bandwidth     uint32 // bandwidth [Hz]
	Constellation dvb.Modulation
	Hierarchy     dvb.Hierarchy
	CodeRateHP    dvb.CodeRate
	CodeRateLP    dvb.CodeRate
	Guard         dvb.Guard
	TxMode        dvb.TxMode
	OtherFreq     bool
}

func codeRate(cr byte) dvb.CodeRate {
	if cr < 3 {
		return dvb.CodeRate(cr + 1)
	}
	switch cr {
	case 3:
		return dvb.FEC56
	case 4:
		return dvb.FEC78
	}
	return dvb.FECNone
}

func ParseTerrestrialDeliverySystemDescriptor(d Descriptor) (tds TerrestrialDeliverySystemDescriptor, ok bool) {
	if d.Tag() != TerrestrialDeliverySystemTag {
		return
	}
	data := d.Data()
	tds.Freq = uint64(decodeU32(data[0:4])) * 10
	switch data[4] >> 5 {
	case 0:
		tds.Bandwidth = 8e6
	case 1:
		tds.Bandwidth = 7e6
	default:
		return
	}
	switch data[5] >> 6 {
	case 0:
		tds.Constellation = dvb.QPSK
	case 1:
		tds.Constellation = dvb.QAM16
	case 2:
		tds.Constellation = dvb.QAM64
	default:
		return
	}
	tds.Hierarchy = dvb.Hierarchy((data[5] >> 3) & 0x07)
	if tds.Hierarchy > dvb.Hierarchy4 {
		return
	}
	tds.CodeRateHP = codeRate(data[5] & 0x07)
	if tds.CodeRateHP == dvb.FECNone {
		return
	}
	tds.CodeRateLP = codeRate(data[6] >> 5)
	if tds.CodeRateLP == dvb.FECNone {
		return
	}
	tds.Guard = dvb.Guard((data[6] >> 3) & 0x03)
	tds.TxMode = dvb.TxMode((data[6] >> 1) & 0x3)
	if tds.TxMode > dvb.TxMode8k {
		return
	}
	tds.OtherFreq = data[6]&0x01 != 0
	ok = true
	return
}
<commit_msg>New service types<commit_after>package psi

import (
	"github.com/ziutek/dvb"
)

type ServiceType byte

const (
	DigitalTelevisionService = ServiceType(0x01)
	DigitalRadioSoundService = ServiceType(0x02)
	TeletextService          = ServiceType(0x03)
	NVODReferenceService     = ServiceType(0x04)
	NVODTimeShiftedService   = ServiceType(0x05)
	MosaicService            = ServiceType(0x06)
	FMRadioService           = ServiceType(0x07)
	DVBSRMService            = ServiceType(0x08)
	// 0x09
	AdvancedCodecDigitalRadioSoundService = ServiceType(0x0a)
	AdvancedCodecMosaicService            = ServiceType(0x0b)
	DataBroadcastService                  = ServiceType(0x0c)
	// 0x0d
	RCSMapService                   = ServiceType(0x0e)
	RCSFLSService                   = ServiceType(0x0f)
	DVBMHPService                   = ServiceType(0x10)
	MPEG2HDDigitalTelevisionService = ServiceType(0x11)
	// 0x12
	// 0x13
	// 0x14
	// 0x15
	AdvancedCodecSDDigitalTelevisionService = ServiceType(0x16)
	AdvancedCodecSDNVODTimeShiftedService   = ServiceType(0x17)
	AdvancedCodecSDNVODReferenceService     = ServiceType(0x18)
	AdvancedCodecHDDigitalTelevisionService = ServiceType(0x19)
	AdvancedCodecHDNVODTimeShiftedService   = ServiceType(0x1a)
	AdvancedCodecHDNVODReferenceService     = ServiceType(0x1b)
)

var stn = []string{
	"digital television",
	"digital radio sound",
	"teletext",
	"NVOD reference",
	"NVOD time-shifted",
	"mosaic",
	"FM radio",
	"DVB SRM",
	"reserved",
	"advanced codec digital radio sound",
	"advanced codec mosaic",
	"data broadcast",
	"reserved",
	"RCS Map",
	"RCS FLS",
	"DVB MHP",
	"MPEG-2 HD digital television",
	"reserved",
	"reserved",
	"reserved",
	"reserved",
	"advanced codec SD digital television",
	"advanced codec SD NVOD time-shifted",
	"advanced codec SD NVOD reference",
	"advanced codec HD digital television",
	"advanced codec HD NVOD time-shifted",
	"advanced codec HD NVOD reference",
}

func (t ServiceType) String() string {
	if t == 0 || t == 0xff || t > AdvancedCodecHDNVODReferenceService && t <= 0x7F {
		return "reserved"
	}
	if t > 0x7F {
		return "user defined"
	}
	return stn[t-1]
}

type ServiceDescriptor struct {
	Type         ServiceType
	ProviderName []byte
	ServiceName  []byte
}

func ParseServiceDescriptor(d Descriptor) (sd ServiceDescriptor, ok bool) {
	if d.Tag() != ServiceTag {
		return
	}
	data := d.Data()
	if len(data) < 2 {
		return
	}
	sd.Type = ServiceType(data[0])
	providerNameLen := data[1]
	data = data[2:]

	if len(data) < int(providerNameLen+1) {
		return
	}
	sd.ProviderName = data[:providerNameLen]
	serviceNameLen := data[providerNameLen]
	data = data[providerNameLen+1:]

	if len(data) < int(serviceNameLen) {
		return
	}
	sd.ServiceName = data[:serviceNameLen]

	ok = true
	return
}

type NetworkNameDescriptor []byte

func ParseNetworkNameDescriptor(d Descriptor) (nnd NetworkNameDescriptor, ok bool) {
	if d.Tag() != NetworkNameTag {
		return
	}
	nnd = NetworkNameDescriptor(d.Data())
	ok = true
	return
}

type ServiceListDescriptor []byte

func ParseServiceListDescriptor(d Descriptor) (sld ServiceListDescriptor, ok bool) {
	if d.Tag() != ServiceListTag {
		return
	}
	sld = ServiceListDescriptor(d.Data())
	ok = true
	return
}

// Pop returns first (sid, typ) pair from d. Remaining pairs are returned in rd.
// If there is no more pairs to read len(rd) == 0.
// If an error occurs rd = nil
func (d ServiceListDescriptor) Pop() (sid uint16, typ ServiceType, rd ServiceListDescriptor) {
	if len(d) < 3 {
		return
	}
	sid = decodeU16(d[0:2])
	typ = ServiceType(d[2])
	rd = d[3:]
	return
}

type TerrestrialDeliverySystemDescriptor struct {
	Freq          uint64 // center frequency [Hz]
	Bandwidth     uint32 // bandwidth [Hz]
	Constellation dvb.Modulation
	Hierarchy     dvb.Hierarchy
	CodeRateHP    dvb.CodeRate
	CodeRateLP    dvb.CodeRate
	Guard         dvb.Guard
	TxMode        dvb.TxMode
	OtherFreq     bool
}

func codeRate(cr byte) dvb.CodeRate {
	if cr < 3 {
		return dvb.CodeRate(cr + 1)
	}
	switch cr {
	case 3:
		return dvb.FEC56
	case 4:
		return dvb.FEC78
	}
	return dvb.FECNone
}

func ParseTerrestrialDeliverySystemDescriptor(d Descriptor) (tds TerrestrialDeliverySystemDescriptor, ok bool) {
	if d.Tag() != TerrestrialDeliverySystemTag {
		return
	}
	data := d.Data()
	tds.Freq = uint64(decodeU32(data[0:4])) * 10
	switch data[4] >> 5 {
	case 0:
		tds.Bandwidth = 8e6
	case 1:
		tds.Bandwidth = 7e6
	default:
		return
	}
	switch data[5] >> 6 {
	case 0:
		tds.Constellation = dvb.QPSK
	case 1:
		tds.Constellation = dvb.QAM16
	case 2:
		tds.Constellation = dvb.QAM64
	default:
		return
	}
	tds.Hierarchy = dvb.Hierarchy((data[5] >> 3) & 0x07)
	if tds.Hierarchy > dvb.Hierarchy4 {
		return
	}
	tds.CodeRateHP = codeRate(data[5] & 0x07)
	if tds.CodeRateHP == dvb.FECNone {
		return
	}
	tds.CodeRateLP = codeRate(data[6] >> 5)
	if tds.CodeRateLP == dvb.FECNone {
		return
	}
	tds.Guard = dvb.Guard((data[6] >> 3) & 0x03)
	tds.TxMode = dvb.TxMode((data[6] >> 1) & 0x3)
	if tds.TxMode > dvb.TxMode8k {
		return
	}
	tds.OtherFreq = data[6]&0x01 != 0
	ok = true
	return
}
<|endoftext|>


<commit_before>/*
Package aws_sns provides the library to communicate to sns service
*/
package aws_sdk_go

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"fmt"
	"github.com/aws/aws-sdk-go/aws/credentials"
)

func ConfigAws(regionName, accessKey, secretKey string, doIam bool) (*aws.Config, error) {

	awsConf := &aws.Config{Region: aws.String(regionName)}

	if !doIam {
		if len(accessKey) == 0 || len(secretKey) == 0 {
			return nil,fmt.Errorf("ses access key and/or secret key is/are blank")
		} else {
			token := ""
			creds := credentials.NewStaticCredentials(accessKey, secretKey, token)
			_, err := creds.Get()
			if err != nil {
				return nil,err
			}
			awsConf = &aws.Config{
				Region: aws.String(regionName),
				Credentials: creds}
		}
	}
	return awsConf,nil
}

func ConnectSns(config *aws.Config) (*sns.SNS, error) {
	awsSession := session.New(config)
	snsService := sns.New(awsSession)
	return snsService,nil
}
<commit_msg>aws-sdk-go beta version<commit_after>/*
Package aws_sns provides the library to communicate to sns service
*/
package aws_sdk_go

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
)

func ConfigAws(regionName, accessKey, secretKey string, doIam bool) (*aws.Config, error) {
	sess:= session.New()
	awsConfig := aws.NewConfig().WithCredentials(credentials.NewChainCredentials([]credentials.Provider{
		&ec2rolecreds.EC2RoleProvider{
			Client: ec2metadata.New(sess),
		},
		&credentials.StaticProvider{
			Value: credentials.Value{
				AccessKeyID:     accessKey,
				SecretAccessKey: secretKey,
				SessionToken:    "",
			},
		},
	})).WithRegion(regionName)
	return awsConfig,nil
}

func ConnectSns(config *aws.Config) (*sns.SNS, error) {
	awsSession := session.New(config)
	snsService := sns.New(awsSession)
	return snsService,nil
}
<|endoftext|>


<commit_before>package chalmers_chop

var packageVersion string = "0.1.7"
<commit_msg>Increase version number<commit_after>package chalmers_chop

var packageVersion string = "0.1.8"
<|endoftext|>


<commit_before>package list

import (
	"container/list"
	"sync"

	"github.com/solefaucet/sole-server/services/hub"
)

// Hub stores connections in doubly linked list
type Hub struct {
	conns  *list.List
	rwlock sync.RWMutex
}

var _ hub.Hub = &Hub{}

// New creates a new Hub
func New() *Hub {
	return &Hub{
		conns: list.New(),
	}
}

// PutConn puts a new connection into list
func (h *Hub) PutConn(c hub.Conn) {
	h.rwlock.Lock()
	defer h.rwlock.Unlock()
	h.conns.PushFront(c)
}

// Broadcast broadcast message to all connections
func (h *Hub) Broadcast(m []byte) {
	go func() {
		// construct slice of connections
		elems := h.elems()

		// broadcast message
		// collect errored connections
		errElems := []*list.Element{}
		wg := &sync.WaitGroup{}
		for i := range elems {
			wg.Add(1)
			go func(e *list.Element) {
				defer wg.Done()
				if err := e.Value.(hub.Conn).Write(m); err != nil {
					errElems = append(errElems, e)
				}
			}(elems[i])
		}
		wg.Wait()

		// remove errored connections
		h.removeErrElems(errElems)
	}()
}

// Len returns number of active connections
func (h *Hub) Len() int {
	h.rwlock.RLock()
	defer h.rwlock.RUnlock()
	return h.conns.Len()
}

// iterate list, construct slice of connections
func (h *Hub) elems() []*list.Element {
	h.rwlock.RLock()
	defer h.rwlock.RUnlock()
	elems := make([]*list.Element, h.conns.Len())
	for e, i := h.conns.Front(), 0; e != nil; e, i = e.Next(), i+1 {
		elems[i] = e
	}

	return elems
}

// remove errored connections from list
func (h *Hub) removeErrElems(errElems []*list.Element) {
	if len(errElems) == 0 {
		return
	}

	h.rwlock.Lock()
	defer h.rwlock.Unlock()
	for i := range errElems {
		errElems[i].Value.(hub.Conn).Close()
		h.conns.Remove(errElems[i])
	}
}
<commit_msg>Fix race condition<commit_after>package list

import (
	"container/list"
	"sync"

	"github.com/solefaucet/sole-server/services/hub"
)

// Hub stores connections in doubly linked list
type Hub struct {
	conns  *list.List
	rwlock sync.RWMutex
}

var _ hub.Hub = &Hub{}

// New creates a new Hub
func New() *Hub {
	return &Hub{
		conns: list.New(),
	}
}

// PutConn puts a new connection into list
func (h *Hub) PutConn(c hub.Conn) {
	h.rwlock.Lock()
	defer h.rwlock.Unlock()
	h.conns.PushFront(c)
}

// Broadcast broadcast message to all connections
func (h *Hub) Broadcast(m []byte) {
	go func() {
		// construct slice of connections
		elems := h.elems()

		// broadcast message
		// collect errored connections
		errElems := []*list.Element{}
		wg := &sync.WaitGroup{}
		for i := range elems {
			wg.Add(1)
			go func(e *list.Element) {
				defer wg.Done()
				if err := e.Value.(hub.Conn).Write(m); err != nil {
					errElems = append(errElems, e)
				}
			}(elems[i])
		}
		wg.Wait()

		// remove errored connections
		h.removeErrElems(errElems)
	}()
}

// Len returns number of active connections
func (h *Hub) Len() int {
	h.rwlock.RLock()
	defer h.rwlock.RUnlock()
	return h.conns.Len()
}

// iterate list, construct slice of connections
func (h *Hub) elems() []*list.Element {
	h.rwlock.RLock()
	defer h.rwlock.RUnlock()
	elems := make([]*list.Element, h.conns.Len())
	for e, i := h.conns.Front(), 0; e != nil; e, i = e.Next(), i+1 {
		elems[i] = e
	}

	return elems
}

// remove errored connections from list
func (h *Hub) removeErrElems(errElems []*list.Element) {
	h.rwlock.Lock()
	defer h.rwlock.Unlock()

	for i := range errElems {
		errElems[i].Value.(hub.Conn).Close()
		h.conns.Remove(errElems[i])
	}
}
<|endoftext|>


<commit_before>package postgresql

import (
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/honeycombio/honeytail/event"
	"github.com/stretchr/testify/assert"
)

// Test parsing individual log statements with different prefix formats.
func TestSingleQueryParsing(t *testing.T) {
	testcases := []struct {
		description  string
		in           string
		prefixFormat string
		expected     event.Event
	}{
		{
			description: "parse a multiline log statement from a default postgres 9.5 log",
			in: `2017-11-07 23:05:16 UTC [3053-3] postgres@postgres LOG:  duration: 0.681 ms  statement: SELECT d.datname as "Name",
	       pg_catalog.pg_get_userbyid(d.datdba) as "Owner",
	       pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding",
	       d.datcollate as "Collate",
	       d.datctype as "Ctype",
	       pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges"
	FROM pg_catalog.pg_database d
	ORDER BY 1;`,
			prefixFormat: "%t [%p-%l] %u@%d",
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 7, 23, 5, 16, 0, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "postgres",
					"duration": 0.681,
					"pid":      3053,
					"session_line_number": 3,
					"query":               "SELECT d.datname as \"Name\", pg_catalog.pg_get_userbyid(d.datdba) as \"Owner\", pg_catalog.pg_encoding_to_char(d.encoding) as \"Encoding\", d.datcollate as \"Collate\", d.datctype as \"Ctype\", pg_catalog.array_to_string(d.datacl, E'\\n') AS \"Access privileges\" FROM pg_catalog.pg_database d ORDER BY 1;",
					"normalized_query":    "select d.datname as ?, pg_catalog.pg_get_userbyid(d.datdba) as ?, pg_catalog.pg_encoding_to_char(d.encoding) as ?, d.datcollate as ?, d.datctype as ?, pg_catalog.array_to_string(d.datacl, e?) as ? from pg_catalog.pg_database d order by ?;",
				},
			},
		},
		{
			description:  "extract everything you can put in a line prefix",
			in:           `2017-11-08 03:02:49.314 UTC [8544-1] postgres@test (3/0) (0) (00000) (2017-11-08 03:02:38 UTC) (psql)LOG:  duration: 2.753 ms  statement: select * from test;`,
			prefixFormat: `%m [%p-%l] %q%u@%d (%v) (%x) (%e) (%s) (%a)`,
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 8, 3, 2, 49, 314000000, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "test",
					"duration": 2.753,
					"pid":      8544,
					"session_line_number":    1,
					"virtual_transaction_id": "3/0",
					"transaction_id":         "0",
					"sql_state":              "00000",
					"session_start":          "2017-11-08 03:02:38 UTC",
					"application":            "psql",
					"query":                  "select * from test;",
					"normalized_query":       "select * from test;",
				},
			},
		},
		{
			description:  "extract the event timestamp from a unix time",
			in:           `1510258541402 [8544-1] postgres@test LOG:  duration: 2.753 ms  statement: select * from test;`,
			prefixFormat: "%n [%p-%l] %u@%d",
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 9, 20, 15, 41, 402000000, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "test",
					"duration": 2.753,
					"pid":      8544,
					"session_line_number": 1,
					"query":               "select * from test;",
					"normalized_query":    "select * from test;",
				},
			},
		},
		{
			description:  "parse a prepared statement",
			in:           `2017-11-07 23:05:16 UTC [3053-3] postgres@postgres LOG:  duration: 0.681 ms  execute sbstmt-1751784287-397260381: SELECT c FROM sbtest1 WHERE id=$1`,
			prefixFormat: "%t [%p-%l] %u@%d",
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 7, 23, 5, 16, 0, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "postgres",
					"duration": 0.681,
					"pid":      3053,
					"session_line_number": 3,
					"query":               "SELECT c FROM sbtest1 WHERE id=$1",
					"normalized_query":    "select c from sbtest1 where id=$?",
				},
			},
		},
	}

	for _, tc := range testcases {
		t.Run(tc.description, func(t *testing.T) {
			in := make(chan []string)
			out := make(chan event.Event)
			p := Parser{}
			p.Init(&Options{LogLinePrefix: tc.prefixFormat})
			wg := &sync.WaitGroup{}
			wg.Add(1)
			go p.handleEvents(in, out, wg)
			in <- strings.Split(tc.in, "\n")
			close(in)
			got := <-out
			assert.Equal(t, tc.expected, got)
		})
	}
}

// Test grouping and parsing multiple log statements.
func TestMultipleQueryParsing(t *testing.T) {
	in := `
2017-11-07 01:43:18 UTC [3542-5] postgres@test LOG:  duration: 9.263 ms  statement: INSERT INTO test (id, name, value) VALUES (1, 'Alice', 'foo');
2017-11-07 01:43:27 UTC [3542-6] postgres@test LOG:  duration: 0.841 ms  statement: INSERT INTO test (id, name, value) VALUES (2, 'Bob', 'bar');
2017-11-07 01:43:39 UTC [3542-7] postgres@test LOG:  duration: 15.577 ms  statement: SELECT * FROM test
	WHERE id=1;
2017-11-07 01:43:42 UTC [3542-8] postgres@test LOG:  duration: 0.501 ms  statement: SELECT * FROM test
	WHERE id=2;
`
	out := []event.Event{
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 18, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 9.263,
				"pid":      3542,
				"session_line_number": 5,
				"query":               "INSERT INTO test (id, name, value) VALUES (1, 'Alice', 'foo');",
				"normalized_query":    "insert into test (id, name, value) values (?, ?, ?);",
			},
		},
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 27, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 0.841,
				"pid":      3542,
				"session_line_number": 6,
				"query":               "INSERT INTO test (id, name, value) VALUES (2, 'Bob', 'bar');",
				"normalized_query":    "insert into test (id, name, value) values (?, ?, ?);",
			},
		},
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 39, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 15.577,
				"pid":      3542,
				"session_line_number": 7,
				"query":               "SELECT * FROM test WHERE id=1;",
				"normalized_query":    "select * from test where id=?;",
			},
		},
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 42, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 0.501,
				"pid":      3542,
				"session_line_number": 8,
				"query":               "SELECT * FROM test WHERE id=2;",
				"normalized_query":    "select * from test where id=?;",
			},
		},
	}

	parser := Parser{}
	parser.Init(nil)
	inChan := make(chan string)
	sendChan := make(chan event.Event, 4)
	go parser.ProcessLines(inChan, sendChan, nil)
	for _, line := range strings.Split(in, "\n") {
		inChan <- line
	}
	close(inChan)
	for _, expected := range out {
		got := <-sendChan
		assert.Equal(t, expected, got)
	}
}

// Test handling log statements that aren't slow query logs
func TestSkipNonQueryLogLines(t *testing.T) {
	parser := Parser{}
	parser.Init(nil)
	testcases := []string{
		"la la la",
		"2017-11-06 19:20:32 UTC [11534-2] LOG:  autovacuum launcher shutting down",
		"2017-11-07 01:43:39 UTC [3542-7] postgres@test ERROR: relation \"test\" does not exist at character 15",
	}

	for _, tc := range testcases {
		lineGroup := []string{tc}
		ev := parser.handleEvent(lineGroup)
		assert.Nil(t, ev)
	}
}

func TestEnsureRegexMatchesBeginningOfLine(t *testing.T) {
	parser := Parser{}
	parser.Init(&Options{
		// missing "[PUCE] " prefix
		LogLinePrefix: "[%p-%l]  sql_error_code = %e",
	})
	line := "[PUCE] [200-1]  sql_error_code = 00000 LOG:  duration: 1050.729 ms  execute <unnamed>: UPDATE \"repositories\" SET \"current_build_id\" = 341933279, \"updated_at\" = '2018-02-15 15:21:55.174858' WHERE \"repositories\".\"id\" = 16235973"

	lineGroup := []string{line}
	got := parser.handleEvent(lineGroup)
	assert.Nil(t, got)
}

func TestCustomLogLinePrefix(t *testing.T) {
	parser := Parser{}
	parser.Init(&Options{
		// missing "[PUCE] " prefix
		LogLinePrefix: "[PUCE] [%p-%l]  sql_error_code = %e",
	})
	line := "[PUCE] [200-1]  sql_error_code = 00000 LOG:  duration: 1050.729 ms  execute <unnamed>: UPDATE \"repositories\" SET \"current_build_id\" = 341933279, \"updated_at\" = '2018-02-15 15:21:55.174858' WHERE \"repositories\".\"id\" = 16235973"
	expected := &event.Event{
		Timestamp: time.Date(0001, 1, 1, 0, 0, 0, 0, time.UTC),
		Data: map[string]interface{}{
			"duration": 1050.729,
			"pid":      200,
			"session_line_number": 1,
			"query":               "UPDATE \"repositories\" SET \"current_build_id\" = 341933279, \"updated_at\" = '2018-02-15 15:21:55.174858' WHERE \"repositories\".\"id\" = 16235973",
			"normalized_query":    "update ? set ? = ?, ? = ? where ?.? = ?",
			"sql_state":           "00000",
		},
	}

	lineGroup := []string{line}
	got := parser.handleEvent(lineGroup)
	assert.Equal(t, expected, got)
}
<commit_msg>fix comment in test case<commit_after>package postgresql

import (
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/honeycombio/honeytail/event"
	"github.com/stretchr/testify/assert"
)

// Test parsing individual log statements with different prefix formats.
func TestSingleQueryParsing(t *testing.T) {
	testcases := []struct {
		description  string
		in           string
		prefixFormat string
		expected     event.Event
	}{
		{
			description: "parse a multiline log statement from a default postgres 9.5 log",
			in: `2017-11-07 23:05:16 UTC [3053-3] postgres@postgres LOG:  duration: 0.681 ms  statement: SELECT d.datname as "Name",
	       pg_catalog.pg_get_userbyid(d.datdba) as "Owner",
	       pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding",
	       d.datcollate as "Collate",
	       d.datctype as "Ctype",
	       pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges"
	FROM pg_catalog.pg_database d
	ORDER BY 1;`,
			prefixFormat: "%t [%p-%l] %u@%d",
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 7, 23, 5, 16, 0, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "postgres",
					"duration": 0.681,
					"pid":      3053,
					"session_line_number": 3,
					"query":               "SELECT d.datname as \"Name\", pg_catalog.pg_get_userbyid(d.datdba) as \"Owner\", pg_catalog.pg_encoding_to_char(d.encoding) as \"Encoding\", d.datcollate as \"Collate\", d.datctype as \"Ctype\", pg_catalog.array_to_string(d.datacl, E'\\n') AS \"Access privileges\" FROM pg_catalog.pg_database d ORDER BY 1;",
					"normalized_query":    "select d.datname as ?, pg_catalog.pg_get_userbyid(d.datdba) as ?, pg_catalog.pg_encoding_to_char(d.encoding) as ?, d.datcollate as ?, d.datctype as ?, pg_catalog.array_to_string(d.datacl, e?) as ? from pg_catalog.pg_database d order by ?;",
				},
			},
		},
		{
			description:  "extract everything you can put in a line prefix",
			in:           `2017-11-08 03:02:49.314 UTC [8544-1] postgres@test (3/0) (0) (00000) (2017-11-08 03:02:38 UTC) (psql)LOG:  duration: 2.753 ms  statement: select * from test;`,
			prefixFormat: `%m [%p-%l] %q%u@%d (%v) (%x) (%e) (%s) (%a)`,
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 8, 3, 2, 49, 314000000, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "test",
					"duration": 2.753,
					"pid":      8544,
					"session_line_number":    1,
					"virtual_transaction_id": "3/0",
					"transaction_id":         "0",
					"sql_state":              "00000",
					"session_start":          "2017-11-08 03:02:38 UTC",
					"application":            "psql",
					"query":                  "select * from test;",
					"normalized_query":       "select * from test;",
				},
			},
		},
		{
			description:  "extract the event timestamp from a unix time",
			in:           `1510258541402 [8544-1] postgres@test LOG:  duration: 2.753 ms  statement: select * from test;`,
			prefixFormat: "%n [%p-%l] %u@%d",
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 9, 20, 15, 41, 402000000, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "test",
					"duration": 2.753,
					"pid":      8544,
					"session_line_number": 1,
					"query":               "select * from test;",
					"normalized_query":    "select * from test;",
				},
			},
		},
		{
			description:  "parse a prepared statement",
			in:           `2017-11-07 23:05:16 UTC [3053-3] postgres@postgres LOG:  duration: 0.681 ms  execute sbstmt-1751784287-397260381: SELECT c FROM sbtest1 WHERE id=$1`,
			prefixFormat: "%t [%p-%l] %u@%d",
			expected: event.Event{
				Timestamp: time.Date(2017, 11, 7, 23, 5, 16, 0, time.UTC),
				Data: map[string]interface{}{
					"user":     "postgres",
					"database": "postgres",
					"duration": 0.681,
					"pid":      3053,
					"session_line_number": 3,
					"query":               "SELECT c FROM sbtest1 WHERE id=$1",
					"normalized_query":    "select c from sbtest1 where id=$?",
				},
			},
		},
	}

	for _, tc := range testcases {
		t.Run(tc.description, func(t *testing.T) {
			in := make(chan []string)
			out := make(chan event.Event)
			p := Parser{}
			p.Init(&Options{LogLinePrefix: tc.prefixFormat})
			wg := &sync.WaitGroup{}
			wg.Add(1)
			go p.handleEvents(in, out, wg)
			in <- strings.Split(tc.in, "\n")
			close(in)
			got := <-out
			assert.Equal(t, tc.expected, got)
		})
	}
}

// Test grouping and parsing multiple log statements.
func TestMultipleQueryParsing(t *testing.T) {
	in := `
2017-11-07 01:43:18 UTC [3542-5] postgres@test LOG:  duration: 9.263 ms  statement: INSERT INTO test (id, name, value) VALUES (1, 'Alice', 'foo');
2017-11-07 01:43:27 UTC [3542-6] postgres@test LOG:  duration: 0.841 ms  statement: INSERT INTO test (id, name, value) VALUES (2, 'Bob', 'bar');
2017-11-07 01:43:39 UTC [3542-7] postgres@test LOG:  duration: 15.577 ms  statement: SELECT * FROM test
	WHERE id=1;
2017-11-07 01:43:42 UTC [3542-8] postgres@test LOG:  duration: 0.501 ms  statement: SELECT * FROM test
	WHERE id=2;
`
	out := []event.Event{
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 18, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 9.263,
				"pid":      3542,
				"session_line_number": 5,
				"query":               "INSERT INTO test (id, name, value) VALUES (1, 'Alice', 'foo');",
				"normalized_query":    "insert into test (id, name, value) values (?, ?, ?);",
			},
		},
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 27, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 0.841,
				"pid":      3542,
				"session_line_number": 6,
				"query":               "INSERT INTO test (id, name, value) VALUES (2, 'Bob', 'bar');",
				"normalized_query":    "insert into test (id, name, value) values (?, ?, ?);",
			},
		},
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 39, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 15.577,
				"pid":      3542,
				"session_line_number": 7,
				"query":               "SELECT * FROM test WHERE id=1;",
				"normalized_query":    "select * from test where id=?;",
			},
		},
		event.Event{
			Timestamp: time.Date(2017, 11, 7, 1, 43, 42, 0, time.UTC),
			Data: map[string]interface{}{
				"user":     "postgres",
				"database": "test",
				"duration": 0.501,
				"pid":      3542,
				"session_line_number": 8,
				"query":               "SELECT * FROM test WHERE id=2;",
				"normalized_query":    "select * from test where id=?;",
			},
		},
	}

	parser := Parser{}
	parser.Init(nil)
	inChan := make(chan string)
	sendChan := make(chan event.Event, 4)
	go parser.ProcessLines(inChan, sendChan, nil)
	for _, line := range strings.Split(in, "\n") {
		inChan <- line
	}
	close(inChan)
	for _, expected := range out {
		got := <-sendChan
		assert.Equal(t, expected, got)
	}
}

// Test handling log statements that aren't slow query logs
func TestSkipNonQueryLogLines(t *testing.T) {
	parser := Parser{}
	parser.Init(nil)
	testcases := []string{
		"la la la",
		"2017-11-06 19:20:32 UTC [11534-2] LOG:  autovacuum launcher shutting down",
		"2017-11-07 01:43:39 UTC [3542-7] postgres@test ERROR: relation \"test\" does not exist at character 15",
	}

	for _, tc := range testcases {
		lineGroup := []string{tc}
		ev := parser.handleEvent(lineGroup)
		assert.Nil(t, ev)
	}
}

func TestEnsureRegexMatchesBeginningOfLine(t *testing.T) {
	parser := Parser{}
	parser.Init(&Options{
		// missing "[PUCE] " prefix
		LogLinePrefix: "[%p-%l]  sql_error_code = %e",
	})
	line := "[PUCE] [200-1]  sql_error_code = 00000 LOG:  duration: 1050.729 ms  execute <unnamed>: UPDATE \"repositories\" SET \"current_build_id\" = 341933279, \"updated_at\" = '2018-02-15 15:21:55.174858' WHERE \"repositories\".\"id\" = 16235973"

	lineGroup := []string{line}
	got := parser.handleEvent(lineGroup)
	assert.Nil(t, got)
}

func TestCustomLogLinePrefix(t *testing.T) {
	parser := Parser{}
	parser.Init(&Options{
		LogLinePrefix: "[PUCE] [%p-%l]  sql_error_code = %e",
	})
	line := "[PUCE] [200-1]  sql_error_code = 00000 LOG:  duration: 1050.729 ms  execute <unnamed>: UPDATE \"repositories\" SET \"current_build_id\" = 341933279, \"updated_at\" = '2018-02-15 15:21:55.174858' WHERE \"repositories\".\"id\" = 16235973"
	expected := &event.Event{
		Timestamp: time.Date(0001, 1, 1, 0, 0, 0, 0, time.UTC),
		Data: map[string]interface{}{
			"duration": 1050.729,
			"pid":      200,
			"session_line_number": 1,
			"query":               "UPDATE \"repositories\" SET \"current_build_id\" = 341933279, \"updated_at\" = '2018-02-15 15:21:55.174858' WHERE \"repositories\".\"id\" = 16235973",
			"normalized_query":    "update ? set ? = ?, ? = ? where ?.? = ?",
			"sql_state":           "00000",
		},
	}

	lineGroup := []string{line}
	got := parser.handleEvent(lineGroup)
	assert.Equal(t, expected, got)
}
<|endoftext|>