<commit_before>package nv

import (
	"encoding/binary"
	"fmt"
	"io"
	"reflect"
)

func decodePreamble(r io.Reader, byteOrder binary.ByteOrder) (codec, endianness, error) {
	var err error
	enc := encoding{}
	if err = binary.Read(r, byteOrder, &enc); err != nil {
		return enc.Encoding, enc.Endianess, err
	}

	if enc.Encoding > maxCodec {
		err = fmt.Errorf("invalid encoding: %v", enc.Encoding)
	} else if enc.Endianess > maxEndian {
		err = fmt.Errorf("invalid endianess: %v", enc.Endianess)
	} else if enc.Reserved1 != 0 {
		err = fmt.Errorf("unexpected reserved1 value: %v", enc.Reserved1)
	} else if enc.Reserved2 != 0 {
		err = fmt.Errorf("unexpected reserved2 value: %v", enc.Reserved2)
	}
	return enc.Encoding, enc.Endianess, err
}

// fieldSetFunc is used to set the value if the target is a field within a
// struct
type fieldSetFunc func(reflect.Value, reflect.Value)

func decodeList(dec decoder, target reflect.Value) error {
	// Validate data header
	h, err := dec.header()
	if err != nil {
		return err
	}
	if h.Version != 0 {
		return fmt.Errorf("unexpected version: %v", h.Version)
	}
	if h.Flag < _UNIQUE_NAME || h.Flag > _UNIQUE_NAME_TYPE {
		return fmt.Errorf("unexpected Flag: %v", h.Flag)
	}

	// If the target is a pointer, initialize and dereference.
	if target.Kind() == reflect.Ptr {
		target.Set(reflect.New(target.Type().Elem()))
		target = reflect.Indirect(target)
	}

	// maps and structs have slightly different handling
	// interface types will be handled as maps
	isMap := (target.Kind() == reflect.Map || target.Kind() == reflect.Interface)

	if isMap {
		// Initialize the map. Can't add keys without this.
		if target.Kind() == reflect.Interface {
			target.Set(reflect.MakeMap(reflect.TypeOf(map[string]interface{}{})))
			target = target.Elem()
		} else {
			target.Set(reflect.MakeMap(target.Type()))
		}
	}

	// Special map alias that collects values and nvlist types
	isList := target.Type().String() == "nv.list"

	// For structs, create the lookup table for field name/tag -> field index
	var targetFieldIndexMap map[string]int
	if !isMap {
		targetFieldIndexMap = fieldIndexMap(target)
	}

	// Start decoding data
	for {
		// Done when there's no more data or an error has occurred
		if end, err := dec.isEnd(); end || err != nil {
			return err
		}

		// Get next encoded data pair
		// Note: This just gets the data pair metadata. The actual value
		// data is left on the reader, to be pulled off by the decoder.
		pName, pType, err := dec.meta()
		if err != nil {
			return err
		}

		// If not dealing with a map, look up the corresponding struct field
		var targetField reflect.Value
		if !isMap {
			targetFieldIndex, ok := targetFieldIndexMap[pName]
			// If there's no corresponding struct field, skip the data and move
			// on to the next data pair
			if !ok {
				if err := dec.skip(); err != nil {
					return err
				}
				continue
			}
			targetField = target.Field(targetFieldIndex)
		}

		var targetType reflect.Type
		if isList {
			targetType = target.Type()
		} else if isMap {
			targetType = target.Type().Elem()
		} else {
			targetType = targetField.Type()
		}

		// value can be used directly if target is a map, if it is a
		// struct we need to use fieldSetter since the struct needs to
		// be set with a non-interface type
		value, fieldSetter, err := dec.value(targetType)
		if err != nil {
			return err
		}

		// Set the value appropriately
		if isMap {
			name := reflect.ValueOf(pName)
			if isList {
				value = reflect.ValueOf(map[string]interface{}{
					"type":  pType.String(),
					"value": value.Interface(),
				})
			}
			target.SetMapIndex(name, value)
		} else {
			fieldSetter(targetField, value)
		}
	}
	return nil
}

// fieldIndexMap creates a map of field names, with tag name overrides,
// to their index
func fieldIndexMap(v reflect.Value) map[string]int {
	vFieldIndexMap := make(map[string]int)
	forEachField(v, func(i int, field reflect.Value) bool {
		// Skip fields that can't be set (e.g. unexported)
		if !field.CanSet() {
			return true
		}
		name := v.Type().Field(i).Name
		if tags := getTags(i, v); len(tags) > 0 && tags[0] != "" {
			name = tags[0]
		}
		vFieldIndexMap[name] = i
		return true
	})
	return vFieldIndexMap
}
<commit_msg>Add support for Extra fields<commit_after>package nv

import (
	"encoding/binary"
	"fmt"
	"io"
	"reflect"
)

const (
	extraName = "__extra"
)

func decodePreamble(r io.Reader, byteOrder binary.ByteOrder) (codec, endianness, error) {
	var err error
	enc := encoding{}
	if err = binary.Read(r, byteOrder, &enc); err != nil {
		return enc.Encoding, enc.Endianess, err
	}

	if enc.Encoding > maxCodec {
		err = fmt.Errorf("invalid encoding: %v", enc.Encoding)
	} else if enc.Endianess > maxEndian {
		err = fmt.Errorf("invalid endianess: %v", enc.Endianess)
	} else if enc.Reserved1 != 0 {
		err = fmt.Errorf("unexpected reserved1 value: %v", enc.Reserved1)
	} else if enc.Reserved2 != 0 {
		err = fmt.Errorf("unexpected reserved2 value: %v", enc.Reserved2)
	}
	return enc.Encoding, enc.Endianess, err
}

// fieldSetFunc is used to set the value if the target is a field within a
// struct
type fieldSetFunc func(reflect.Value, reflect.Value)

func decodeList(dec decoder, target reflect.Value) error {
	// Validate data header
	h, err := dec.header()
	if err != nil {
		return err
	}
	if h.Version != 0 {
		return fmt.Errorf("unexpected version: %v", h.Version)
	}
	if h.Flag < _UNIQUE_NAME || h.Flag > _UNIQUE_NAME_TYPE {
		return fmt.Errorf("unexpected Flag: %v", h.Flag)
	}

	// If the target is a pointer, initialize and dereference.
	if target.Kind() == reflect.Ptr {
		target.Set(reflect.New(target.Type().Elem()))
		target = reflect.Indirect(target)
	}

	// maps and structs have slightly different handling
	// interface types will be handled as maps
	isMap := (target.Kind() == reflect.Map || target.Kind() == reflect.Interface)

	if isMap {
		initializeMap(&target)
	}

	// Special map alias that collects values and nvlist types
	isList := target.Type().String() == "nv.list"

	// For structs, create the lookup table for field name/tag -> field index
	var targetFieldIndexMap map[string]int
	if !isMap {
		targetFieldIndexMap = fieldIndexMap(target)
	}

	// Set up the extra field map for fields not defined in the struct
	var extraMap reflect.Value
	if !isMap {
		if index, ok := targetFieldIndexMap[extraName]; ok {
			extraMap = target.Field(index)
			initializeMap(&extraMap)
		}
	}

	// Start decoding data
	for {
		// Reset the iteration target and map status
		iterTarget := target
		iterIsMap := isMap

		// Done when there's no more data or an error has occurred
		if end, err := dec.isEnd(); end || err != nil {
			return err
		}

		// Get next encoded data pair
		// Note: This just gets the data pair metadata. The actual value
		// data is left on the reader, to be pulled off by the decoder.
		pName, pType, err := dec.meta()
		if err != nil {
			return err
		}

		// If not dealing with a map, look up the corresponding struct field
		var targetField reflect.Value
		if !isMap {
			targetFieldIndex, ok := targetFieldIndexMap[pName]
			// If there's no corresponding struct field and no field for
			// extras, skip the data and move on to the next data pair. If
			// there is an field for extras, make that the new target for this
			// iteration.
			if !ok {
				if !extraMap.IsValid() {
					if err := dec.skip(); err != nil {
						return err
					}
					continue
				}
				iterTarget = extraMap
				iterIsMap = true
			} else {
				targetField = target.Field(targetFieldIndex)
			}
		}

		var targetType reflect.Type
		if isList {
			targetType = iterTarget.Type()
		} else if iterIsMap {
			targetType = iterTarget.Type().Elem()
		} else {
			targetType = targetField.Type()
		}

		// value can be used directly if target is a map, if it is a
		// struct we need to use fieldSetter since the struct needs to
		// be set with a non-interface type
		value, fieldSetter, err := dec.value(targetType)
		if err != nil {
			return err
		}

		// Set the value appropriately
		if iterIsMap {
			name := reflect.ValueOf(pName)
			if isList {
				value = reflect.ValueOf(map[string]interface{}{
					"type":  pType.String(),
					"value": value.Interface(),
				})
			}
			iterTarget.SetMapIndex(name, value)
		} else {
			fieldSetter(targetField, value)
		}
	}
	return nil
}

// fieldIndexMap creates a map of field names, with tag name overrides,
// to their index
func fieldIndexMap(v reflect.Value) map[string]int {
	vFieldIndexMap := make(map[string]int)
	forEachField(v, func(i int, field reflect.Value) bool {
		// Skip fields that can't be set (e.g. unexported)
		if !field.CanSet() {
			return true
		}

		name := v.Type().Field(i).Name
		tags := getTags(i, v)
		isMap := (field.Kind() == reflect.Map || field.Kind() == reflect.Interface)

		if len(tags) > 1 && tags[1] == "extra" && isMap {
			name = extraName
		} else if len(tags) > 0 && tags[0] != "" {
			name = tags[0]
		}
		vFieldIndexMap[name] = i
		return true
	})
	return vFieldIndexMap
}

func initializeMap(target *reflect.Value) {
	// Initialize the map. Can't add keys without this.
	if target.Kind() == reflect.Interface {
		target.Set(reflect.MakeMap(reflect.TypeOf(map[string]interface{}{})))
		*target = target.Elem()
	} else {
		target.Set(reflect.MakeMap(target.Type()))
	}
}
<|endoftext|>


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

package gosh

import (
	"sort"
	"strings"
	"unicode"
)

type completer struct {
	topLevelCommands CommandMap
}

func newCompleter(commands CommandMap) *completer {
	return &completer{commands}
}

func (this completer) complete(line string, pos int) (string, []string, string) {
	var c []string
	tail := line[pos:]
	line = line[:pos]

	head := ""
	fields := strings.Fields(line[:pos])
	/* We need to make sure that there are empty fields
	 * in the event of a blank line, or a line that ends
	 * in a space.  Otherwise, there is nothing to attempt
	 * to match on below
	 */
	if len(fields) == 0 {
		fields = []string{""}
	} else if unicode.IsSpace(rune(line[pos-1])) {
		fields = append(fields, "")
	}

	commands := this.topLevelCommands
	for i, field := range fields {
		completions := commands.getCompletions(field)
		for completion, command := range completions {
			/* If it is an exact match then
			 * continue to the next field
			 */
			if field == completion {
				head = head + completion + " "
				if treeCommand, ok := command.(TreeCommand); ok {
					commands = treeCommand.SubCommands()
					break
				} else if completable, ok := command.(Completable); ok {
					nextField := ""
					if i < len(fields)-1 {
						nextField = fields[i+1]
					}
					nextCompletions := completable.Completions(nextField)
					commands = make(CommandMap, len(nextCompletions))
					for _, nextCompletion := range nextCompletions {
						commands[nextCompletion] = command
					}
					break
				}
			} else if i == len(fields)-1 {
				c = append(c, completion)
			}
		}
	}
	sort.Strings(c)
	return head, c, tail
}
<commit_msg>Changed receiver name from this<commit_after>/**
 * Copyright 2015 Andrew Bates
 *
 * Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package gosh

import (
	"sort"
	"strings"
	"unicode"
)

type completer struct {
	topLevelCommands CommandMap
}

func newCompleter(commands CommandMap) *completer {
	return &completer{commands}
}

func (c completer) complete(line string, pos int) (string, []string, string) {
	var candidates []string
	tail := line[pos:]
	line = line[:pos]

	head := ""
	fields := strings.Fields(line[:pos])
	/* We need to make sure that there are empty fields
	 * in the event of a blank line, or a line that ends
	 * in a space.  Otherwise, there is nothing to attempt
	 * to match on below
	 */
	if len(fields) == 0 {
		fields = []string{""}
	} else if unicode.IsSpace(rune(line[pos-1])) {
		fields = append(fields, "")
	}

	commands := c.topLevelCommands
	for i, field := range fields {
		completions := commands.getCompletions(field)
		for completion, command := range completions {
			/* If it is an exact match then
			 * continue to the next field
			 */
			if field == completion {
				head = head + completion + " "
				if treeCommand, ok := command.(TreeCommand); ok {
					commands = treeCommand.SubCommands()
					break
				} else if completable, ok := command.(Completable); ok {
					nextField := ""
					if i < len(fields)-1 {
						nextField = fields[i+1]
					}
					nextCompletions := completable.Completions(nextField)
					commands = make(CommandMap, len(nextCompletions))
					for _, nextCompletion := range nextCompletions {
						commands[nextCompletion] = command
					}
					break
				}
			} else if i == len(fields)-1 {
				candidates = append(candidates, completion)
			}
		}
	}
	sort.Strings(candidates)
	return head, candidates, tail
}
<|endoftext|>


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

package main

import (
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

type CommandCompleter struct {
	Root   *cobra.Command
	Finder ResourceFinder
}

func (cc *CommandCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
	cmd, args := cc.Root, []string{}
	word := string(line[:pos])
	lastSpace := strings.LastIndex(string(line[:pos]), " ") + 1
	lastComma := strings.LastIndex(string(line[:pos]), ",") + 1
	if lastSpace > 0 {
		if lastComma > lastSpace {
			word = word[lastComma:pos]
		} else {
			word = word[lastSpace:pos]
		}
		var err error
		cmd, args, err = cc.Root.Find(strings.Split(string(line), " "))
		if err != nil {
			return
		}
	}
	for _, completion := range completions(cc.Finder, word, cmd, args) {
		if len(word) >= len(completion) {
			if len(word) == len(completion) {
				newLine = append(newLine, []rune{' '})
			} else {
				newLine = append(newLine, []rune(completion))
			}
			offset = len(completion)
		} else {
			newLine = append(newLine, []rune(completion)[len(word):])
			offset = len(word)
		}

	}
	return
}

func completions(finder ResourceFinder, prefix string, cmd *cobra.Command, args []string) []string {
	candidates := []string{}
	if strings.HasPrefix(prefix, "-") {
		candidates = flags(cmd)
	} else {
		candidates = subCommands(cmd)
		if len(candidates) == 0 {
			switch cmd.Name() {
			case "logs", "attach", "exec", "port-forward":
				candidates = resources(finder, "pods")
			case "rolling-update":
				candidates = resources(finder, "rc")
			case "cordon", "uncordon", "drain":
				candidates = resources(finder, "node")
			default:
				if t := resourceType(args); len(t) > 0 {
					candidates = resources(finder, t)
				} else {
					candidates = resourceTypes(cmd)
				}
			}
		}
	}
	return complete(prefix, candidates)
}

func complete(prefix string, candidates []string) (results []string) {
	for _, s := range candidates {
		if strings.HasPrefix(s, prefix) {
			results = append(results, s)
		}
	}
	return
}

func subCommands(cmd *cobra.Command) []string {
	prefixes := make([]string, len(cmd.Commands()))
	for i, c := range cmd.Commands() {
		prefixes[i] = c.Name() + " "
	}
	return prefixes
}

func resourceTypes(cmd *cobra.Command) []string {
	args := cmd.ValidArgs
	sort.Strings(args)
	return args
}

// resourceType returns the resource type identified in the args,
// which could be a comma-delimited list of multiple types
func resourceType(args []string) string {
	// TODO: something more sophisticated?
	x := []string{}
	for _, s := range args {
		if !strings.HasPrefix(s, "-") {
			x = append(x, s)
		}
	}
	if len(x) > 1 {
		return x[0]
	} else {
		return ""
	}
}

func resources(finder ResourceFinder, resourceType string) []string {

	resources, err := finder.Lookup([]string{resourceType})
	ret := []string{}

	if err == nil {
		for _, r := range resources {
			ret = append(ret, r.name)
		}
	}

	return ret
}

func flags(cmd *cobra.Command) []string {
	flags := []string{}
	fn := func(f *pflag.Flag) {
		if len(f.Deprecated) > 0 || f.Hidden {
			return
		}
		flag := "--" + f.Name
		if len(f.NoOptDefVal) == 0 {
			flag += "="
		} else {
			flag += " "
		}
		flags = append(flags, flag)
	}
	cmd.NonInheritedFlags().VisitAll(fn)
	cmd.InheritedFlags().VisitAll(fn)
	return flags
}
<commit_msg>Hang fns on Completer to avoid passing factory<commit_after>// Copyright 2016 Red Hat, Inc, and individual contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

type CommandCompleter struct {
	Root   *cobra.Command
	Finder ResourceFinder
}

func (cc *CommandCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
	cmd, args := cc.Root, []string{}
	word := string(line[:pos])
	lastSpace := strings.LastIndex(string(line[:pos]), " ") + 1
	lastComma := strings.LastIndex(string(line[:pos]), ",") + 1
	if lastSpace > 0 {
		if lastComma > lastSpace {
			word = word[lastComma:pos]
		} else {
			word = word[lastSpace:pos]
		}
		var err error
		cmd, args, err = cc.Root.Find(strings.Split(string(line), " "))
		if err != nil {
			return
		}
	}
	for _, completion := range cc.completions(word, cmd, args) {
		if len(word) >= len(completion) {
			if len(word) == len(completion) {
				newLine = append(newLine, []rune{' '})
			} else {
				newLine = append(newLine, []rune(completion))
			}
			offset = len(completion)
		} else {
			newLine = append(newLine, []rune(completion)[len(word):])
			offset = len(word)
		}

	}
	return
}

func (cc *CommandCompleter) completions(prefix string, cmd *cobra.Command, args []string) []string {
	candidates := []string{}
	if strings.HasPrefix(prefix, "-") {
		candidates = flags(cmd)
	} else {
		candidates = subCommands(cmd)
		if len(candidates) == 0 {
			switch cmd.Name() {
			case "logs", "attach", "exec", "port-forward":
				candidates = cc.resources("pods")
			case "rolling-update":
				candidates = cc.resources("rc")
			case "cordon", "uncordon", "drain":
				candidates = cc.resources("node")
			default:
				if t := resourceType(args); len(t) > 0 {
					candidates = cc.resources(t)
				} else {
					candidates = resourceTypes(cmd)
				}
			}
		}
	}
	return complete(prefix, candidates)
}

func (cc *CommandCompleter) resources(resourceType string) []string {

	resources, err := cc.Finder.Lookup([]string{resourceType})
	ret := []string{}

	if err == nil {
		for _, r := range resources {
			ret = append(ret, r.name)
		}
	}

	return ret
}

func complete(prefix string, candidates []string) (results []string) {
	for _, s := range candidates {
		if strings.HasPrefix(s, prefix) {
			results = append(results, s)
		}
	}
	return
}

func subCommands(cmd *cobra.Command) []string {
	prefixes := make([]string, len(cmd.Commands()))
	for i, c := range cmd.Commands() {
		prefixes[i] = c.Name() + " "
	}
	return prefixes
}

func flags(cmd *cobra.Command) []string {
	flags := []string{}
	fn := func(f *pflag.Flag) {
		if len(f.Deprecated) > 0 || f.Hidden {
			return
		}
		flag := "--" + f.Name
		if len(f.NoOptDefVal) == 0 {
			flag += "="
		} else {
			flag += " "
		}
		flags = append(flags, flag)
	}
	cmd.NonInheritedFlags().VisitAll(fn)
	cmd.InheritedFlags().VisitAll(fn)
	return flags
}

func resourceTypes(cmd *cobra.Command) []string {
	args := cmd.ValidArgs
	sort.Strings(args)
	return args
}

// resourceType returns the resource type identified in the args,
// which could be a comma-delimited list of multiple types
func resourceType(args []string) string {
	x := []string{}
	for _, s := range args {
		if !strings.HasPrefix(s, "-") {
			x = append(x, s)
		}
	}
	if len(x) > 1 {
		return x[0]
	} else {
		return ""
	}
}
<|endoftext|>


<commit_before>package sms // import "github.com/mndrix/sms-over-xmpp"

import (
	"crypto/rand"
	"encoding/base32"
	"encoding/xml"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	xco "github.com/mndrix/go-xco"
	"github.com/pkg/errors"
)

// ErrIgnoreMessage should be returned to indicate that a message
// should be ignored; as if it never happened.
var ErrIgnoreMessage = errors.New("ignore this message")

// Component represents an SMS-over-XMPP component.
type Component struct {
	config Config

	// xmpp is the XMPP component which handles all interactions
	// with an XMPP server.
	xmpp *xco.Component

	// xmppMutex serializes access to the XMPP component to avoid
	// collisions while talking to the XMPP server.
	xmppMutex sync.Mutex
}

// Main runs a component using the given configuration.  It's the main
// entrypoint for launching your own component if you don't want to
// use the sms-over-xmpp command.
func Main(config Config) {
	sc := &Component{config: config}

	// start goroutine for handling XMPP
	xmppErr, err := sc.runXmppComponent()
	if err != nil {
		panic(err)
	}

	// start goroutine for handling HTTP
	httpErr := sc.runHttpServer()

	for {
		select {
		case err := <-httpErr:
			log.Printf("ERROR HTTP: %s", err)
		case err := <-xmppErr:
			log.Printf("ERROR XMPP: %s", err)
		}
	}
}

func (sc *Component) runHttpServer() <-chan error {
	config := sc.config
	addr := fmt.Sprintf("%s:%d", config.HttpHost(), config.HttpPort())
	errCh := make(chan error)
	go func() {
		defer func() { close(errCh) }()
		for {
			errCh <- http.ListenAndServe(addr, sc)
			log.Printf("HTTP server quit. Restarting")
			time.Sleep(1 * time.Second)
		}
	}()
	return errCh
}

func (sc *Component) runXmppComponent() (<-chan error, error) {
	config := sc.config
	opts := xco.Options{
		Name:         config.ComponentName(),
		SharedSecret: config.SharedSecret(),
		Address:      fmt.Sprintf("%s:%d", config.XmppHost(), config.XmppPort()),
		Logger:       log.New(os.Stderr, "", log.LstdFlags),
	}
	c, err := xco.NewComponent(opts)
	if err != nil {
		return nil, err
	}

	c.MessageHandler = sc.onMessage
	c.PresenceHandler = sc.onPresence
	c.IqHandler = sc.onIq
	c.UnknownHandler = sc.onUnknown
	sc.setXmpp(c)

	errCh := make(chan error)
	go func() {
		defer func() { close(errCh) }()
		for {
			errCh <- c.Run()
			log.Printf("lost XMPP connection. Reconnecting")
			time.Sleep(1 * time.Second)
		}
	}()
	return errCh, nil
}

func (sc *Component) setXmpp(c *xco.Component) {
	sc.xmppMutex.Lock()
	defer func() { sc.xmppMutex.Unlock() }()

	sc.xmpp = c
}

func (sc *Component) onMessage(c *xco.Component, m *xco.Message) error {
	log.Printf("Message: %+v", m)
	if m.Body == "" {
		log.Printf("  ignoring message with empty body")
		return nil
	}

	// convert recipient address into a phone number
	toPhone, err := sc.config.AddressToPhone(m.To)
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		return nil
	default:
		return errors.Wrap(err, "converting 'to' address to phone")
	}

	// convert author's address into a phone number
	fromPhone, err := sc.config.AddressToPhone(m.From)
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		return nil
	default:
		return errors.Wrap(err, "converting 'from' address to phone")
	}

	// choose an SMS provider
	provider, err := sc.config.SmsProvider()
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		return nil
	default:
		return errors.Wrap(err, "choosing an SMS provider")
	}

	// send the message
	err = provider.SendSms(fromPhone, toPhone, m.Body)
	return errors.Wrap(err, "sending SMS")
}

func (sc *Component) onPresence(c *xco.Component, p *xco.Presence) error {
	log.Printf("Presence: %+v", p)
	return nil
}

func (sc *Component) onIq(c *xco.Component, iq *xco.Iq) error {
	log.Printf("Iq: %+v", iq)
	return nil
}

func (sc *Component) onUnknown(c *xco.Component, x *xml.StartElement) error {
	log.Printf("Unknown: %+v", x)
	return nil
}

func (sc *Component) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	msgSid := r.FormValue("MessageSid")
	log.Printf("%s %s (%s)", r.Method, r.URL.Path, msgSid)

	// which SMS provider is applicable?
	provider, err := sc.config.SmsProvider()
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		msg := "ignored during provider selection"
		log.Println(msg)
		return
	default:
		msg := fmt.Sprintf("ERROR: choosing an SMS provider: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, msg)
		log.Println(msg)
		return
	}

	fromPhone, toPhone, body, err := provider.ReceiveSms(r)

	// convert author's phone number into XMPP address
	from, err := sc.config.PhoneToAddress(fromPhone)
	switch err {
	case nil:
		// all is well. proceed
	case ErrIgnoreMessage:
		msg := "ignored based on From address"
		log.Println(msg)
		return
	default:
		msg := fmt.Sprintf("ERROR: From address %s: %s", fromPhone, err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, msg)
		log.Println(msg)
		return
	}

	// convert recipient's phone number into XMPP address
	to, err := sc.config.PhoneToAddress(toPhone)
	switch err {
	case nil:
		// all is well. proceed
	case ErrIgnoreMessage:
		msg := "ignored based on To address"
		log.Println(msg)
		return
	default:
		msg := fmt.Sprintf("ERROR: To address %s: %s", toPhone, err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, msg)
		log.Println(msg)
		return
	}

	// deliver message over XMPP
	msg := &xco.Message{
		XMLName: xml.Name{
			Local: "message",
			Space: "jabber:component:accept",
		},

		Header: xco.Header{
			From: from,
			To:   to,
			ID:   NewId(),
		},
		Type: "chat",
		Body: body,
	}
	err = sc.xmppSend(msg)
	if err != nil {
		log.Printf("ERROR: can't send message: %s", err)
	}
}

// xmppSend sends a single XML stanza over the XMPP connection.  It
// serializes concurrent access to avoid collisions on the wire.
func (sc *Component) xmppSend(msg interface{}) error {
	sc.xmppMutex.Lock()
	defer func() { sc.xmppMutex.Unlock() }()

	return sc.xmpp.Send(msg)
}

// NewId generates a random string which is suitable as an XMPP stanza
// ID.  The string contains enough entropy to be universally unique.
func NewId() string {
	// generate 128 random bits (6 more than standard UUID)
	bytes := make([]byte, 16)
	_, err := rand.Read(bytes)
	if err != nil {
		panic(err)
	}

	// convert them to base 32 encoding
	s := base32.StdEncoding.EncodeToString(bytes)
	return strings.ToLower(strings.TrimRight(s, "="))
}
<commit_msg>Recreate XMPP during reconnection<commit_after>package sms // import "github.com/mndrix/sms-over-xmpp"

import (
	"crypto/rand"
	"encoding/base32"
	"encoding/xml"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	xco "github.com/mndrix/go-xco"
	"github.com/pkg/errors"
)

// ErrIgnoreMessage should be returned to indicate that a message
// should be ignored; as if it never happened.
var ErrIgnoreMessage = errors.New("ignore this message")

// Component represents an SMS-over-XMPP component.
type Component struct {
	config Config

	// xmpp is the XMPP component which handles all interactions
	// with an XMPP server.
	xmpp *xco.Component

	// xmppMutex serializes access to the XMPP component to avoid
	// collisions while talking to the XMPP server.
	xmppMutex sync.Mutex
}

// Main runs a component using the given configuration.  It's the main
// entrypoint for launching your own component if you don't want to
// use the sms-over-xmpp command.
func Main(config Config) {
	sc := &Component{config: config}

	// start goroutine for handling XMPP
	xmppErr, err := sc.runXmppComponent()
	if err != nil {
		panic(err)
	}

	// start goroutine for handling HTTP
	httpErr := sc.runHttpServer()

	for {
		select {
		case err := <-httpErr:
			log.Printf("ERROR HTTP: %s", err)
		case err := <-xmppErr:
			log.Printf("ERROR XMPP: %s", err)
		}
	}
}

func (sc *Component) runHttpServer() <-chan error {
	config := sc.config
	addr := fmt.Sprintf("%s:%d", config.HttpHost(), config.HttpPort())
	errCh := make(chan error)
	go func() {
		defer func() { close(errCh) }()
		for {
			errCh <- http.ListenAndServe(addr, sc)
			log.Printf("HTTP server quit. Restarting")
			time.Sleep(1 * time.Second)
		}
	}()
	return errCh
}

func (sc *Component) runXmppComponent() (<-chan error, error) {
	config := sc.config
	opts := xco.Options{
		Name:         config.ComponentName(),
		SharedSecret: config.SharedSecret(),
		Address:      fmt.Sprintf("%s:%d", config.XmppHost(), config.XmppPort()),
		Logger:       log.New(os.Stderr, "", log.LstdFlags),
	}

	errCh := make(chan error)
	go func() {
		defer func() { close(errCh) }()
		for {
			c, err := xco.NewComponent(opts)
			if err != nil {
				errCh <- err
				break
			}

			c.MessageHandler = sc.onMessage
			c.PresenceHandler = sc.onPresence
			c.IqHandler = sc.onIq
			c.UnknownHandler = sc.onUnknown
			sc.setXmpp(c)

			errCh <- c.Run()
			log.Printf("lost XMPP connection. Reconnecting")
			time.Sleep(1 * time.Second)
		}
	}()
	return errCh, nil
}

func (sc *Component) setXmpp(c *xco.Component) {
	sc.xmppMutex.Lock()
	defer func() { sc.xmppMutex.Unlock() }()

	sc.xmpp = c
}

func (sc *Component) onMessage(c *xco.Component, m *xco.Message) error {
	log.Printf("Message: %+v", m)
	if m.Body == "" {
		log.Printf("  ignoring message with empty body")
		return nil
	}

	// convert recipient address into a phone number
	toPhone, err := sc.config.AddressToPhone(m.To)
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		return nil
	default:
		return errors.Wrap(err, "converting 'to' address to phone")
	}

	// convert author's address into a phone number
	fromPhone, err := sc.config.AddressToPhone(m.From)
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		return nil
	default:
		return errors.Wrap(err, "converting 'from' address to phone")
	}

	// choose an SMS provider
	provider, err := sc.config.SmsProvider()
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		return nil
	default:
		return errors.Wrap(err, "choosing an SMS provider")
	}

	// send the message
	err = provider.SendSms(fromPhone, toPhone, m.Body)
	return errors.Wrap(err, "sending SMS")
}

func (sc *Component) onPresence(c *xco.Component, p *xco.Presence) error {
	log.Printf("Presence: %+v", p)
	return nil
}

func (sc *Component) onIq(c *xco.Component, iq *xco.Iq) error {
	log.Printf("Iq: %+v", iq)
	return nil
}

func (sc *Component) onUnknown(c *xco.Component, x *xml.StartElement) error {
	log.Printf("Unknown: %+v", x)
	return nil
}

func (sc *Component) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	msgSid := r.FormValue("MessageSid")
	log.Printf("%s %s (%s)", r.Method, r.URL.Path, msgSid)

	// which SMS provider is applicable?
	provider, err := sc.config.SmsProvider()
	switch err {
	case nil:
		// all is well. we'll continue below
	case ErrIgnoreMessage:
		msg := "ignored during provider selection"
		log.Println(msg)
		return
	default:
		msg := fmt.Sprintf("ERROR: choosing an SMS provider: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, msg)
		log.Println(msg)
		return
	}

	fromPhone, toPhone, body, err := provider.ReceiveSms(r)

	// convert author's phone number into XMPP address
	from, err := sc.config.PhoneToAddress(fromPhone)
	switch err {
	case nil:
		// all is well. proceed
	case ErrIgnoreMessage:
		msg := "ignored based on From address"
		log.Println(msg)
		return
	default:
		msg := fmt.Sprintf("ERROR: From address %s: %s", fromPhone, err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, msg)
		log.Println(msg)
		return
	}

	// convert recipient's phone number into XMPP address
	to, err := sc.config.PhoneToAddress(toPhone)
	switch err {
	case nil:
		// all is well. proceed
	case ErrIgnoreMessage:
		msg := "ignored based on To address"
		log.Println(msg)
		return
	default:
		msg := fmt.Sprintf("ERROR: To address %s: %s", toPhone, err)
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, msg)
		log.Println(msg)
		return
	}

	// deliver message over XMPP
	msg := &xco.Message{
		XMLName: xml.Name{
			Local: "message",
			Space: "jabber:component:accept",
		},

		Header: xco.Header{
			From: from,
			To:   to,
			ID:   NewId(),
		},
		Type: "chat",
		Body: body,
	}
	err = sc.xmppSend(msg)
	if err != nil {
		log.Printf("ERROR: can't send message: %s", err)
	}
}

// xmppSend sends a single XML stanza over the XMPP connection.  It
// serializes concurrent access to avoid collisions on the wire.
func (sc *Component) xmppSend(msg interface{}) error {
	sc.xmppMutex.Lock()
	defer func() { sc.xmppMutex.Unlock() }()

	return sc.xmpp.Send(msg)
}

// NewId generates a random string which is suitable as an XMPP stanza
// ID.  The string contains enough entropy to be universally unique.
func NewId() string {
	// generate 128 random bits (6 more than standard UUID)
	bytes := make([]byte, 16)
	_, err := rand.Read(bytes)
	if err != nil {
		panic(err)
	}

	// convert them to base 32 encoding
	s := base32.StdEncoding.EncodeToString(bytes)
	return strings.ToLower(strings.TrimRight(s, "="))
}
<|endoftext|>


<commit_before>package boardgame

import (
	"crypto/sha1"
	"fmt"
	"strconv"
)

//A Component represents a movable resource in the game. Cards, dice, meeples,
//resource tokens, etc are all components. Values is a struct that stores the
//specific values for the component.
type Component struct {
	Values SubState
	//The deck we're a part of.
	Deck *Deck
	//The index we are in the deck we're in.
	DeckIndex int
}

//Id returns a semi-stable ID for this component within this game and
//currentState. Within this game, it will only change when the shuffleCount
//for this component changes. Across games the Id for the "same" component
//will be different, in a way that cannot be guessed without access to
//game.SecretSalt. See the package doc for more on semi-stable Ids for
//components, what they can be used for, and when they do (and don't) change.
func (c *Component) Id(s State) string {

	var input string

	//In some limited cases state will be nil, but in that case just make a
	//(worse) hash.
	if s != nil {
		game := s.(*state).game
		input = game.Id() + game.SecretSalt()
	}

	input += c.Deck.Name() + strconv.Itoa(c.DeckIndex)

	hash := sha1.Sum([]byte(input))

	return fmt.Sprintf("%x", hash)
}

func (c *Component) DynamicValues(state State) SubState {

	//TODO: test this

	dynamic := state.DynamicComponentValues()

	values := dynamic[c.Deck.Name()]

	if values == nil {
		return nil
	}

	if len(values) <= c.DeckIndex {
		return nil
	}

	if c.DeckIndex < 0 {
		return c.Deck.Chest().Manager().Delegate().EmptyDynamicComponentValues(c.Deck)
	}

	return values[c.DeckIndex]
}
<commit_msg>If component is a generic component its hash should be "". Part of #350.<commit_after>package boardgame

import (
	"crypto/sha1"
	"fmt"
	"strconv"
)

//A Component represents a movable resource in the game. Cards, dice, meeples,
//resource tokens, etc are all components. Values is a struct that stores the
//specific values for the component.
type Component struct {
	Values SubState
	//The deck we're a part of.
	Deck *Deck
	//The index we are in the deck we're in.
	DeckIndex int
}

//Id returns a semi-stable ID for this component within this game and
//currentState. Within this game, it will only change when the shuffleCount
//for this component changes. Across games the Id for the "same" component
//will be different, in a way that cannot be guessed without access to
//game.SecretSalt. See the package doc for more on semi-stable Ids for
//components, what they can be used for, and when they do (and don't) change.
func (c *Component) Id(s State) string {

	var input string

	//Shadow components shouldn't get an Id
	if c == c.Deck.GenericComponent() {
		return ""
	}

	//In some limited cases state will be nil, but in that case just make a
	//(worse) hash.
	if s != nil {
		game := s.(*state).game
		input = game.Id() + game.SecretSalt()
	}

	input += c.Deck.Name() + strconv.Itoa(c.DeckIndex)

	hash := sha1.Sum([]byte(input))

	return fmt.Sprintf("%x", hash)
}

func (c *Component) DynamicValues(state State) SubState {

	//TODO: test this

	dynamic := state.DynamicComponentValues()

	values := dynamic[c.Deck.Name()]

	if values == nil {
		return nil
	}

	if len(values) <= c.DeckIndex {
		return nil
	}

	if c.DeckIndex < 0 {
		return c.Deck.Chest().Manager().Delegate().EmptyDynamicComponentValues(c.Deck)
	}

	return values[c.DeckIndex]
}
<|endoftext|>


<commit_before>package interfaces

import (
	"fmt"
	"strings"

	"github.com/webitel/cdr/src/conf"
	"github.com/webitel/cdr/src/entity"
)

const (
	cdrInsertQueryB     = "INSERT INTO #table#(uuid, parent_uuid, created_at, stored_at, archived_at, size, event, stored_state, archived_state) VALUES "
	cdrInsertQueryA     = "INSERT INTO #table#(uuid, created_at, stored_at, archived_at, size, event, stored_state, archived_state) VALUES "
	cdrValuesB          = "(%v, %v, %v, %v, %v, %v, %v, %v, %v),"
	cdrValuesA          = "(%v, %v, %v, %v, %v, %v, %v, %v),"
	cdrSelectByState    = "SELECT uuid, event FROM #table# WHERE #state#_state=$1 ORDER BY created_at ASC LIMIT $2"
	cdrSelectByStateB   = "SELECT uuid, event FROM #table# WHERE #state#_state=$1 AND parent_uuid != '' ORDER BY created_at ASC LIMIT $2"
	cdrJoin             = "SELECT a.uuid as parent_uuid, b.event as event, b.uuid as uuid FROM #table_a# as a INNER JOIN #table_b# as b ON a.uuid = b.parent_uuid WHERE a.stored_state=$1 AND b.stored_state=$2 ORDER BY b.created_at ASC LIMIT $3"
	cdrUuid             = "uuid=%v OR "
	cdrUpdateStateQuery = "UPDATE #table# SET #state#_state=$1, #state#_at=$2 WHERE "
	cdrCreateTableA     = `
							CREATE TABLE IF NOT EXISTS #table#
							(
								uuid character varying(255) COLLATE pg_catalog."default" NOT NULL,
								created_at bigint,
								stored_at bigint,
								archived_at bigint,
								size integer,
								event bytea,
								stored_state smallint,
								archived_state smallint,
								CONSTRAINT #table#_pkey PRIMARY KEY (uuid)
							)
							WITH (
								OIDS = FALSE
							)
							TABLESPACE pg_default;

							ALTER TABLE #table#
								OWNER to #user#;
						` //$1 - public.cdr $2 - webitel
	/*create index cdr_a_created_at_stored_state_index
		on cdr_a (created_at, stored_state)
	;

	create index cdr_a_created_at_archived_state_index
		on cdr_a (created_at, archived_state)
	;*/
	cdrCreateTableB = `
						CREATE TABLE IF NOT EXISTS #table#
						(
							uuid character varying(255) COLLATE pg_catalog."default" NOT NULL,
							parent_uuid character varying(255) COLLATE pg_catalog."default",
							created_at bigint,
							stored_at bigint,
							archived_at bigint,
							size integer,
							event bytea,
							stored_state smallint,
							archived_state smallint,
							CONSTRAINT #table#_pkey PRIMARY KEY (uuid)
						)
						WITH (
							OIDS = FALSE
						)
						TABLESPACE pg_default;

						ALTER TABLE #table#
							OWNER to #user#;
					` //$1 - public.cdr $2 - webitel
)

var config conf.Postgres

func InitConfig() {
	config = conf.GetPostgres()
}

type DbHandler interface {
	ExecuteQuery(query string, params ...interface{}) error
	GetRows(query string, params ...interface{}) (Row, error)
	CreateTable(query string) error
}

type Row interface {
	Scan(dest ...interface{}) error
	Next() bool
	Close() error
}

type DbRepo struct {
	dbHandlers map[string]DbHandler
	dbHandler  DbHandler
}

type DbCdrARepo DbRepo
type DbCdrBRepo DbRepo

func NewDbCdrARepo(dbHandlers map[string]DbHandler) *DbCdrARepo {
	DbCdrARepo := new(DbCdrARepo)
	DbCdrARepo.dbHandlers = dbHandlers
	DbCdrARepo.dbHandler = dbHandlers["DbCdrARepo"]
	return DbCdrARepo
}

func NewDbCdrBRepo(dbHandlers map[string]DbHandler) *DbCdrBRepo {
	DbCdrBRepo := new(DbCdrBRepo)
	DbCdrBRepo.dbHandlers = dbHandlers
	DbCdrBRepo.dbHandler = dbHandlers["DbCdrBRepo"]
	return DbCdrBRepo
}

func (repo *DbCdrARepo) InsertPack(calls []entity.SqlCdr) error {
	sqlStr := strings.Replace(cdrInsertQueryA, "#table#", config.TableA, -1)
	vals := []interface{}{}
	var strValues string
	valCounter := 1
	for _, row := range calls {
		strValues = fmt.Sprintf(cdrValuesA,
			fmt.Sprintf("$%v", valCounter),
			fmt.Sprintf("$%v", valCounter+1),
			fmt.Sprintf("$%v", valCounter+2),
			fmt.Sprintf("$%v", valCounter+3),
			fmt.Sprintf("$%v", valCounter+4),
			fmt.Sprintf("$%v", valCounter+5),
			fmt.Sprintf("$%v", valCounter+6),
			fmt.Sprintf("$%v", valCounter+7))
		sqlStr += strValues
		vals = append(vals,
			row.Uuid,
			row.Created_at,
			row.Stored_at,
			row.Archived_at,
			row.Size,
			row.Event,
			row.Stored_state,
			row.Archived_state)
		valCounter = valCounter + 8
	}
	sqlStr = sqlStr[0 : len(sqlStr)-1]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrARepo) SelectPackByState(count uint32, state uint8, stateName string) ([]entity.SqlCdr, error) {
	rows, err := repo.dbHandler.GetRows(strings.Replace(strings.Replace(cdrSelectByState, "#table#", config.TableA, -1), "#state#", stateName, -1), state, count)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var cdr []entity.SqlCdr
	var call entity.SqlCdr
	for rows.Next() {
		err = rows.Scan(&call.Uuid, &call.Event)
		if err != nil {
			return nil, err
		}
		cdr = append(cdr, call)
	}
	return cdr, nil
}

func (repo *DbCdrARepo) JoinLegsPack(count uint32) ([]entity.SqlCdr, error) {
	panic(count)
}

func (repo *DbCdrARepo) UpdateState(calls []entity.SqlCdr, state uint8, timestamp uint64, stateName string) error {
	sqlStr := strings.Replace(strings.Replace(cdrUpdateStateQuery, "#table#", config.TableA, -1), "#state#", stateName, -1)
	vals := []interface{}{}
	vals = append(vals, state, timestamp) //uint64(time.Now().UnixNano()/1000000)
	var strValues string
	for i, row := range calls {
		strValues = fmt.Sprintf(cdrUuid, fmt.Sprintf("$%v", i+3))
		sqlStr += strValues
		vals = append(vals, row.Uuid)
	}
	sqlStr = sqlStr[0 : len(sqlStr)-4]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrBRepo) InsertPack(calls []entity.SqlCdr) error {
	sqlStr := strings.Replace(cdrInsertQueryB, "#table#", config.TableB, -1)
	vals := []interface{}{}
	var strValues string
	valCounter := 1
	for _, row := range calls {
		strValues = fmt.Sprintf(cdrValuesB,
			fmt.Sprintf("$%v", valCounter),
			fmt.Sprintf("$%v", valCounter+1),
			fmt.Sprintf("$%v", valCounter+2),
			fmt.Sprintf("$%v", valCounter+3),
			fmt.Sprintf("$%v", valCounter+4),
			fmt.Sprintf("$%v", valCounter+5),
			fmt.Sprintf("$%v", valCounter+6),
			fmt.Sprintf("$%v", valCounter+7),
			fmt.Sprintf("$%v", valCounter+8))
		sqlStr += strValues
		vals = append(vals,
			row.Uuid,
			row.Parent_uuid,
			row.Created_at,
			row.Stored_at,
			row.Archived_at,
			row.Size,
			row.Event,
			row.Stored_state,
			row.Archived_state)
		valCounter = valCounter + 9
	}
	sqlStr = sqlStr[0 : len(sqlStr)-1]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrARepo) CreateTableIfNotExist() error {
	sqlStr := strings.Replace(strings.Replace(cdrCreateTableA, "#table#", config.TableA, -1), "#user#", config.User, -1)
	return repo.dbHandler.CreateTable(sqlStr)
}

func (repo *DbCdrBRepo) SelectPackByState(count uint32, state uint8, stateName string) ([]entity.SqlCdr, error) {
	rows, err := repo.dbHandler.GetRows(strings.Replace(strings.Replace(cdrSelectByStateB, "#table#", config.TableB, -1), "#state#", stateName, -1), state, count)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var cdr []entity.SqlCdr
	var call entity.SqlCdr
	for rows.Next() {
		err = rows.Scan(&call.Uuid, &call.Event)
		if err != nil {
			return nil, err
		}
		cdr = append(cdr, call)
	}
	return cdr, nil
}

func (repo *DbCdrBRepo) JoinLegsPack(count uint32) ([]entity.SqlCdr, error) {
	rows, err := repo.dbHandler.GetRows(strings.Replace(strings.Replace(cdrJoin, "#table_a#", config.TableA, -1), "#table_b#", config.TableB, -1), 2, 0, count)
	if err != nil {
		return nil, err
	}
	var cdr []entity.SqlCdr
	var call entity.SqlCdr
	for rows.Next() {
		err = rows.Scan(&call.Parent_uuid, &call.Event, &call.Uuid)
		if err != nil {
			return nil, err
		}
		cdr = append(cdr, call)
	}
	return cdr, nil
}

func (repo *DbCdrBRepo) UpdateState(calls []entity.SqlCdr, state uint8, timestamp uint64, stateName string) error {
	sqlStr := strings.Replace(strings.Replace(cdrUpdateStateQuery, "#table#", config.TableB, -1), "#state#", stateName, -1)
	vals := []interface{}{}
	vals = append(vals, state, timestamp) //uint64(time.Now().UnixNano()/1000000)
	var strValues string
	for i, row := range calls {
		strValues = fmt.Sprintf(cdrUuid, fmt.Sprintf("$%v", i+3))
		sqlStr += strValues
		vals = append(vals, row.Uuid)
	}
	sqlStr = sqlStr[0 : len(sqlStr)-4]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrBRepo) CreateTableIfNotExist() error {
	sqlStr := strings.Replace(strings.Replace(cdrCreateTableB, "#table#", config.TableB, -1), "#user#", config.User, -1)
	return repo.dbHandler.CreateTable(sqlStr)
}
<commit_msg>select for update<commit_after>package interfaces

import (
	"fmt"
	"strings"

	"github.com/webitel/cdr/src/conf"
	"github.com/webitel/cdr/src/entity"
)

const (
	cdrInsertQueryB     = "INSERT INTO #table#(uuid, parent_uuid, created_at, stored_at, archived_at, size, event, stored_state, archived_state) VALUES "
	cdrInsertQueryA     = "INSERT INTO #table#(uuid, created_at, stored_at, archived_at, size, event, stored_state, archived_state) VALUES "
	cdrValuesB          = "(%v, %v, %v, %v, %v, %v, %v, %v, %v),"
	cdrValuesA          = "(%v, %v, %v, %v, %v, %v, %v, %v),"
	cdrSelectByState    = "SELECT uuid, event FROM #table# WHERE #state#_state=$1 ORDER BY created_at ASC LIMIT $2 FOR UPDATE"
	cdrSelectByStateB   = "SELECT uuid, event FROM #table# WHERE #state#_state=$1 AND parent_uuid != '' ORDER BY created_at ASC LIMIT $2 FOR UPDATE"
	cdrJoin             = "SELECT a.uuid as parent_uuid, b.event as event, b.uuid as uuid FROM #table_a# as a INNER JOIN #table_b# as b ON a.uuid = b.parent_uuid WHERE a.stored_state=$1 AND b.stored_state=$2 ORDER BY b.created_at ASC LIMIT $3"
	cdrUuid             = "uuid=%v OR "
	cdrUpdateStateQuery = "UPDATE #table# SET #state#_state=$1, #state#_at=$2 WHERE "
	cdrCreateTableA     = `
							CREATE TABLE IF NOT EXISTS #table#
							(
								uuid character varying(255) COLLATE pg_catalog."default" NOT NULL,
								created_at bigint,
								stored_at bigint,
								archived_at bigint,
								size integer,
								event bytea,
								stored_state smallint,
								archived_state smallint,
								CONSTRAINT #table#_pkey PRIMARY KEY (uuid)
							)
							WITH (
								OIDS = FALSE
							)
							TABLESPACE pg_default;

							ALTER TABLE #table#
								OWNER to #user#;
						` //$1 - public.cdr $2 - webitel
	/*create index cdr_a_created_at_stored_state_index
		on cdr_a (created_at, stored_state)
	;

	create index cdr_a_created_at_archived_state_index
		on cdr_a (created_at, archived_state)
	;*/
	cdrCreateTableB = `
						CREATE TABLE IF NOT EXISTS #table#
						(
							uuid character varying(255) COLLATE pg_catalog."default" NOT NULL,
							parent_uuid character varying(255) COLLATE pg_catalog."default",
							created_at bigint,
							stored_at bigint,
							archived_at bigint,
							size integer,
							event bytea,
							stored_state smallint,
							archived_state smallint,
							CONSTRAINT #table#_pkey PRIMARY KEY (uuid)
						)
						WITH (
							OIDS = FALSE
						)
						TABLESPACE pg_default;

						ALTER TABLE #table#
							OWNER to #user#;
					` //$1 - public.cdr $2 - webitel
)

var config conf.Postgres

func InitConfig() {
	config = conf.GetPostgres()
}

type DbHandler interface {
	ExecuteQuery(query string, params ...interface{}) error
	GetRows(query string, params ...interface{}) (Row, error)
	CreateTable(query string) error
}

type Row interface {
	Scan(dest ...interface{}) error
	Next() bool
	Close() error
}

type DbRepo struct {
	dbHandlers map[string]DbHandler
	dbHandler  DbHandler
}

type DbCdrARepo DbRepo
type DbCdrBRepo DbRepo

func NewDbCdrARepo(dbHandlers map[string]DbHandler) *DbCdrARepo {
	DbCdrARepo := new(DbCdrARepo)
	DbCdrARepo.dbHandlers = dbHandlers
	DbCdrARepo.dbHandler = dbHandlers["DbCdrARepo"]
	return DbCdrARepo
}

func NewDbCdrBRepo(dbHandlers map[string]DbHandler) *DbCdrBRepo {
	DbCdrBRepo := new(DbCdrBRepo)
	DbCdrBRepo.dbHandlers = dbHandlers
	DbCdrBRepo.dbHandler = dbHandlers["DbCdrBRepo"]
	return DbCdrBRepo
}

func (repo *DbCdrARepo) InsertPack(calls []entity.SqlCdr) error {
	sqlStr := strings.Replace(cdrInsertQueryA, "#table#", config.TableA, -1)
	vals := []interface{}{}
	var strValues string
	valCounter := 1
	for _, row := range calls {
		strValues = fmt.Sprintf(cdrValuesA,
			fmt.Sprintf("$%v", valCounter),
			fmt.Sprintf("$%v", valCounter+1),
			fmt.Sprintf("$%v", valCounter+2),
			fmt.Sprintf("$%v", valCounter+3),
			fmt.Sprintf("$%v", valCounter+4),
			fmt.Sprintf("$%v", valCounter+5),
			fmt.Sprintf("$%v", valCounter+6),
			fmt.Sprintf("$%v", valCounter+7))
		sqlStr += strValues
		vals = append(vals,
			row.Uuid,
			row.Created_at,
			row.Stored_at,
			row.Archived_at,
			row.Size,
			row.Event,
			row.Stored_state,
			row.Archived_state)
		valCounter = valCounter + 8
	}
	sqlStr = sqlStr[0 : len(sqlStr)-1]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrARepo) SelectPackByState(count uint32, state uint8, stateName string) ([]entity.SqlCdr, error) {
	rows, err := repo.dbHandler.GetRows(strings.Replace(strings.Replace(cdrSelectByState, "#table#", config.TableA, -1), "#state#", stateName, -1), state, count)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var cdr []entity.SqlCdr
	var call entity.SqlCdr
	for rows.Next() {
		err = rows.Scan(&call.Uuid, &call.Event)
		if err != nil {
			return nil, err
		}
		cdr = append(cdr, call)
	}
	return cdr, nil
}

func (repo *DbCdrARepo) JoinLegsPack(count uint32) ([]entity.SqlCdr, error) {
	panic(count)
}

func (repo *DbCdrARepo) UpdateState(calls []entity.SqlCdr, state uint8, timestamp uint64, stateName string) error {
	sqlStr := strings.Replace(strings.Replace(cdrUpdateStateQuery, "#table#", config.TableA, -1), "#state#", stateName, -1)
	vals := []interface{}{}
	vals = append(vals, state, timestamp) //uint64(time.Now().UnixNano()/1000000)
	var strValues string
	for i, row := range calls {
		strValues = fmt.Sprintf(cdrUuid, fmt.Sprintf("$%v", i+3))
		sqlStr += strValues
		vals = append(vals, row.Uuid)
	}
	sqlStr = sqlStr[0 : len(sqlStr)-4]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrBRepo) InsertPack(calls []entity.SqlCdr) error {
	sqlStr := strings.Replace(cdrInsertQueryB, "#table#", config.TableB, -1)
	vals := []interface{}{}
	var strValues string
	valCounter := 1
	for _, row := range calls {
		strValues = fmt.Sprintf(cdrValuesB,
			fmt.Sprintf("$%v", valCounter),
			fmt.Sprintf("$%v", valCounter+1),
			fmt.Sprintf("$%v", valCounter+2),
			fmt.Sprintf("$%v", valCounter+3),
			fmt.Sprintf("$%v", valCounter+4),
			fmt.Sprintf("$%v", valCounter+5),
			fmt.Sprintf("$%v", valCounter+6),
			fmt.Sprintf("$%v", valCounter+7),
			fmt.Sprintf("$%v", valCounter+8))
		sqlStr += strValues
		vals = append(vals,
			row.Uuid,
			row.Parent_uuid,
			row.Created_at,
			row.Stored_at,
			row.Archived_at,
			row.Size,
			row.Event,
			row.Stored_state,
			row.Archived_state)
		valCounter = valCounter + 9
	}
	sqlStr = sqlStr[0 : len(sqlStr)-1]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrARepo) CreateTableIfNotExist() error {
	sqlStr := strings.Replace(strings.Replace(cdrCreateTableA, "#table#", config.TableA, -1), "#user#", config.User, -1)
	return repo.dbHandler.CreateTable(sqlStr)
}

func (repo *DbCdrBRepo) SelectPackByState(count uint32, state uint8, stateName string) ([]entity.SqlCdr, error) {
	rows, err := repo.dbHandler.GetRows(strings.Replace(strings.Replace(cdrSelectByStateB, "#table#", config.TableB, -1), "#state#", stateName, -1), state, count)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var cdr []entity.SqlCdr
	var call entity.SqlCdr
	for rows.Next() {
		err = rows.Scan(&call.Uuid, &call.Event)
		if err != nil {
			return nil, err
		}
		cdr = append(cdr, call)
	}
	return cdr, nil
}

func (repo *DbCdrBRepo) JoinLegsPack(count uint32) ([]entity.SqlCdr, error) {
	rows, err := repo.dbHandler.GetRows(strings.Replace(strings.Replace(cdrJoin, "#table_a#", config.TableA, -1), "#table_b#", config.TableB, -1), 2, 0, count)
	if err != nil {
		return nil, err
	}
	var cdr []entity.SqlCdr
	var call entity.SqlCdr
	for rows.Next() {
		err = rows.Scan(&call.Parent_uuid, &call.Event, &call.Uuid)
		if err != nil {
			return nil, err
		}
		cdr = append(cdr, call)
	}
	return cdr, nil
}

func (repo *DbCdrBRepo) UpdateState(calls []entity.SqlCdr, state uint8, timestamp uint64, stateName string) error {
	sqlStr := strings.Replace(strings.Replace(cdrUpdateStateQuery, "#table#", config.TableB, -1), "#state#", stateName, -1)
	vals := []interface{}{}
	vals = append(vals, state, timestamp) //uint64(time.Now().UnixNano()/1000000)
	var strValues string
	for i, row := range calls {
		strValues = fmt.Sprintf(cdrUuid, fmt.Sprintf("$%v", i+3))
		sqlStr += strValues
		vals = append(vals, row.Uuid)
	}
	sqlStr = sqlStr[0 : len(sqlStr)-4]
	return repo.dbHandler.ExecuteQuery(sqlStr, vals...)
}

func (repo *DbCdrBRepo) CreateTableIfNotExist() error {
	sqlStr := strings.Replace(strings.Replace(cdrCreateTableB, "#table#", config.TableB, -1), "#user#", config.User, -1)
	return repo.dbHandler.CreateTable(sqlStr)
}
<|endoftext|>


<commit_before>package fluentd_forwarder

import (
	"bytes"
	"compress/gzip"
	"crypto/x509"
	"errors"
	logging "github.com/op/go-logging"
	td_client "github.com/treasure-data/td-client-go"
	"github.com/ugorji/go/codec"
	"net"
	"os"
	"reflect"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"
)

type tdOutputSpooler struct {
	daemon         *tdOutputSpoolerDaemon
	ticker         *time.Ticker
	tag            string
	databaseName   string
	tableName      string
	key            string
	journal        Journal
	wg             sync.WaitGroup
	shutdownChan   chan struct{}
	isShuttingDown unsafe.Pointer
	client         *td_client.TDClient
}

type tdOutputSpoolerDaemon struct {
	output       *TDOutput
	shutdownChan chan struct{}
	spoolersMtx  sync.Mutex
	spoolers     map[string]*tdOutputSpooler
	tempFactory  TempFileRandomAccessStoreFactory
	wg           sync.WaitGroup
	endNotify    func(*tdOutputSpoolerDaemon)
}

type TDOutput struct {
	logger         *logging.Logger
	codec          *codec.MsgpackHandle
	retryInterval  time.Duration
	databaseName   string
	tableName      string
	tempDir        string
	enc            *codec.Encoder
	conn           net.Conn
	flushInterval  time.Duration
	wg             sync.WaitGroup
	journalGroup   JournalGroup
	emitterChan    chan FluentRecordSet
	spoolerDaemon  *tdOutputSpoolerDaemon
	isShuttingDown unsafe.Pointer
	client         *td_client.TDClient
	sem            chan struct{}
	gcChan         chan *os.File
	completion     sync.Cond
}

func maxInt(a, b int) int {
	if a >= b {
		return a
	} else {
		return b
	}
}

func encodeRecords(encoder *codec.Encoder, records []TinyFluentRecord) error {
	for _, record := range records {
		e := map[string]interface{}{"time": record.Timestamp}
		for k, v := range record.Data {
			e[k] = v
		}
		err := encoder.Encode(e)
		if err != nil {
			return err
		}
	}
	return nil
}

func (spooler *tdOutputSpooler) cleanup() {
	spooler.wg.Wait()
	spooler.ticker.Stop()
	spooler.journal.Dispose()
	spooler.daemon.wg.Done()
}

func (spooler *tdOutputSpooler) handle() {
	defer spooler.cleanup()
	spooler.daemon.output.logger.Notice("Spooler started")
outer:
	for {
		select {
		case <-spooler.ticker.C:
			spooler.daemon.output.logger.Notice("Flushing...")
			err := spooler.journal.Flush(func(chunk JournalChunk) interface{} {
				defer chunk.Dispose()
				if atomic.LoadPointer(&spooler.isShuttingDown) != unsafe.Pointer(uintptr(0)) {
					return errors.New("Flush aborted")
				}
				spooler.daemon.output.logger.Info("Flushing chunk %s", chunk.String())
				size, err := chunk.Size()
				if err != nil {
					return err
				}
				if size == 0 {
					return nil
				}
				futureErr := make(chan error, 1)
				spooler.wg.Add(1)
				sem := spooler.daemon.output.sem
				sem <- struct{}{}
				go func(size int64, chunk JournalChunk, futureErr chan error) {
					defer func() {
						<-sem
						chunk.Dispose()
						spooler.wg.Done()
						x := recover()
						if x != nil {
							futureErr <- &Panicked{x}
						}
					}()
					_, err = spooler.client.Import(
						spooler.databaseName,
						spooler.tableName,
						"msgpack.gz",
						td_client.NewBufferingBlobSize(
							NewCompressingBlob(
								chunk,
								16777216,
								gzip.BestSpeed,
								&spooler.daemon.tempFactory,
							),
							maxInt(4096, int(size/16)),
						),
						chunk.Id(),
					)
					futureErr <- err
					if err != nil {
						spooler.daemon.output.logger.Info("Failed to flush chunk %s (reason: %s)", chunk.String(), err.Error())
					} else {
						spooler.daemon.output.logger.Info("Completed flushing chunk %s", chunk.String())
					}
				}(size, chunk.Dup(), futureErr)
				return (<-chan error)(futureErr)
			})
			if err != nil {
				spooler.daemon.output.logger.Error("Error during reading from the journal: %s", err.Error())
			}
		case <-spooler.shutdownChan:
			break outer
		}
	}
	spooler.daemon.output.logger.Notice("Spooler ended")
}

func normalizeDatabaseName(name string) (string, error) {
	name_ := ([]byte)(name)
	if len(name_) == 0 {
		return "", errors.New("Empty name is not allowed")
	}
	if len(name_) < 3 {
		name_ = append(name_, ("___"[0 : 3-len(name)])...)
	}
	if 255 < len(name_) {
		name_ = append(name_[0:253], "__"...)
	}
	name_ = bytes.ToLower(name_)
	for i, c := range name_ {
		if !((c >= 'a' || c <= 'z') || (c >= '0' && c <= '9') || c == '_') {
			c = '_'
		}
		name_[i] = c
	}
	return (string)(name_), nil
}

func normalizeTableName(name string) (string, error) {
	return normalizeDatabaseName(name)
}

func newTDOutputSpooler(daemon *tdOutputSpoolerDaemon, databaseName, tableName, key string) *tdOutputSpooler {
	journal := daemon.output.journalGroup.GetJournal(key)
	return &tdOutputSpooler{
		daemon:       daemon,
		ticker:       time.NewTicker(daemon.output.flushInterval),
		databaseName: databaseName,
		tableName:    tableName,
		key:          key,
		journal:      journal,
		wg:           sync.WaitGroup{},
		shutdownChan: make(chan struct{}, 1),
		client:       daemon.output.client,
	}
}

func (daemon *tdOutputSpoolerDaemon) spawnSpooler(databaseName, tableName, key string) *tdOutputSpooler {
	daemon.spoolersMtx.Lock()
	defer daemon.spoolersMtx.Unlock()
	spooler, exists := daemon.spoolers[key]
	if exists {
		return spooler
	}
	spooler = newTDOutputSpooler(daemon, databaseName, tableName, key)
	daemon.output.logger.Notice("Spawning spooler " + spooler.key)
	daemon.spoolers[spooler.key] = spooler
	daemon.wg.Add(1)
	go spooler.handle()
	return spooler
}

func (daemon *tdOutputSpoolerDaemon) cleanup() {
	func() {
		daemon.spoolersMtx.Lock()
		defer daemon.spoolersMtx.Unlock()
		for _, spooler := range daemon.spoolers {
			if atomic.CompareAndSwapPointer(&spooler.isShuttingDown, unsafe.Pointer(uintptr(0)), unsafe.Pointer(uintptr(1))) {
				spooler.shutdownChan <- struct{}{}
			}
		}
	}()
	daemon.wg.Wait()
	if daemon.endNotify != nil {
		daemon.endNotify(daemon)
	}
	daemon.output.wg.Done()
}

func (daemon *tdOutputSpoolerDaemon) handle() {
	defer daemon.cleanup()
	daemon.output.logger.Notice("Spooler daemon started")
	// spawn Spooler according to the existing journals
	for _, key := range daemon.output.journalGroup.GetJournalKeys() {
		pair := strings.SplitN(key, ".", 2)
		if len(pair) != 2 {
			daemon.output.logger.Warning("Journal %s ignored", key)
			continue
		}
		daemon.spawnSpooler(pair[0], pair[1], key)
	}
outer:
	for {
		select {
		case <-daemon.shutdownChan:
			break outer
		}
	}
	daemon.output.logger.Notice("Spooler daemon ended")
}

func newTDOutputSpoolerDaemon(output *TDOutput) *tdOutputSpoolerDaemon {
	return &tdOutputSpoolerDaemon{
		output:       output,
		shutdownChan: make(chan struct{}, 1),
		spoolers:     make(map[string]*tdOutputSpooler),
		tempFactory:  TempFileRandomAccessStoreFactory{output.tempDir, "", output.gcChan},
		wg:           sync.WaitGroup{},
		endNotify: func(*tdOutputSpoolerDaemon) {
			close(output.gcChan)
		},
	}
}

func (output *TDOutput) spawnSpoolerDaemon() {
	output.logger.Notice("Spawning spooler daemon")
	output.spoolerDaemon = newTDOutputSpoolerDaemon(output)
	output.wg.Add(1)
	go output.spoolerDaemon.handle()
}

func (daemon *tdOutputSpoolerDaemon) getSpooler(tag string) (*tdOutputSpooler, error) {
	databaseName := daemon.output.databaseName
	tableName := daemon.output.tableName
	if databaseName == "*" {
		if tableName == "*" {
			c := strings.SplitN(tag, ".", 2)
			if len(c) == 1 {
				tableName = c[0]
			} else if len(c) == 2 {
				databaseName = c[0]
				tableName = c[1]
			}
		} else {
			databaseName = tag
		}
	} else {
		if tableName == "*" {
			tableName = tag
		}
	}
	databaseName, err := normalizeDatabaseName(databaseName)
	if err != nil {
		return nil, err
	}
	tableName, err = normalizeTableName(tableName)
	if err != nil {
		return nil, err
	}
	key := databaseName + "." + tableName
	return daemon.spawnSpooler(databaseName, tableName, key), nil
}

func (output *TDOutput) spawnEmitter() {
	output.logger.Notice("Spawning emitter")
	output.wg.Add(1)
	go func() {
		defer func() {
			output.spoolerDaemon.shutdownChan <- struct{}{}
			output.wg.Done()
		}()
		output.logger.Notice("Emitter started")
		buffer := bytes.Buffer{}
		for recordSet := range output.emitterChan {
			buffer.Reset()
			encoder := codec.NewEncoder(&buffer, output.codec)
			err := func() error {
				spooler, err := output.spoolerDaemon.getSpooler(recordSet.Tag)
				if err != nil {
					return err
				}
				err = encodeRecords(encoder, recordSet.Records)
				if err != nil {
					return err
				}
				output.logger.Debug("Emitter processed %d entries", len(recordSet.Records))
				return spooler.journal.Write(buffer.Bytes())
			}()
			if err != nil {
				output.logger.Error("%s", err.Error())
				continue
			}
		}
		output.logger.Notice("Emitter ended")
	}()
}

func (output *TDOutput) spawnTempFileCollector() {
	output.logger.Notice("Spawning temporary file collector")
	output.wg.Add(1)
	go func() {
		defer func() {
			output.wg.Done()
		}()
		for f := range output.gcChan {
			output.logger.Debug("Deleting %s...", f.Name())
			err := os.Remove(f.Name())
			if err != nil {
				output.logger.Warning("Failed to delete %s: %s", f.Name(), err.Error())
			}
		}
		output.logger.Debug("temporary file collector ended")
	}()
}

func (output *TDOutput) Emit(recordSets []FluentRecordSet) error {
	defer func() {
		recover()
	}()
	for _, recordSet := range recordSets {
		output.emitterChan <- recordSet
	}
	return nil
}

func (output *TDOutput) String() string {
	return "output"
}

func (output *TDOutput) Stop() {
	if atomic.CompareAndSwapPointer(&output.isShuttingDown, unsafe.Pointer(uintptr(0)), unsafe.Pointer(uintptr(1))) {
		close(output.emitterChan)
	}
}

func (output *TDOutput) WaitForShutdown() {
	output.completion.L.Lock()
	output.completion.Wait()
	output.completion.L.Unlock()
}

func (output *TDOutput) Start() {
	syncCh := make(chan struct{})
	go func() {
		<-syncCh
		output.wg.Wait()
		err := output.journalGroup.Dispose()
		if err != nil {
			output.logger.Error("%s", err.Error())
		}
		output.completion.Broadcast()
	}()
	output.spawnTempFileCollector()
	output.spawnEmitter()
	output.spawnSpoolerDaemon()
	syncCh <- struct{}{}
}

func NewTDOutput(
	logger *logging.Logger,
	endpoint string,
	retryInterval time.Duration,
	connectionTimeout time.Duration,
	writeTimeout time.Duration,
	flushInterval time.Duration,
	parallelism int,
	journalGroupPath string,
	maxJournalChunkSize int64,
	apiKey string,
	databaseName string,
	tableName string,
	tempDir string,
	useSsl bool,
	rootCAs *x509.CertPool,
	httpProxy string,
) (*TDOutput, error) {
	_codec := codec.MsgpackHandle{}
	_codec.MapType = reflect.TypeOf(map[string]interface{}(nil))
	_codec.RawToString = false
	_codec.StructToArray = true

	journalFactory := NewFileJournalGroupFactory(
		logger,
		randSource,
		time.Now,
		".log",
		os.FileMode(0600),
		maxJournalChunkSize,
	)
	router := (td_client.EndpointRouter)(nil)
	if endpoint != "" {
		router = &td_client.FixedEndpointRouter{endpoint}
	}
	httpProxy_ := (interface{})(nil)
	if httpProxy != "" {
		httpProxy_ = httpProxy
	}
	client, err := td_client.NewTDClient(td_client.Settings{
		ApiKey:            apiKey,
		Router:            router,
		ConnectionTimeout: connectionTimeout,
		// ReadTimeout: readTimeout, // TODO
		SendTimeout: writeTimeout,
		Ssl:         useSsl,
		RootCAs:     rootCAs,
		Proxy:       httpProxy_,
	})
	if err != nil {
		return nil, err
	}
	output := &TDOutput{
		logger:         logger,
		codec:          &_codec,
		retryInterval:  retryInterval,
		wg:             sync.WaitGroup{},
		flushInterval:  flushInterval,
		emitterChan:    make(chan FluentRecordSet),
		isShuttingDown: unsafe.Pointer(uintptr(0)),
		client:         client,
		databaseName:   databaseName,
		tableName:      tableName,
		tempDir:        tempDir,
		sem:            make(chan struct{}, parallelism),
		gcChan:         make(chan *os.File, 10),
		completion:     sync.Cond{L: &sync.Mutex{}},
	}
	journalGroup, err := journalFactory.GetJournalGroup(journalGroupPath, output)
	if err != nil {
		return nil, err
	}
	output.journalGroup = journalGroup
	return output, nil
}
<commit_msg>This default seems way too large<commit_after>package fluentd_forwarder

import (
	"bytes"
	"compress/gzip"
	"crypto/x509"
	"errors"
	logging "github.com/op/go-logging"
	td_client "github.com/treasure-data/td-client-go"
	"github.com/ugorji/go/codec"
	"net"
	"os"
	"reflect"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"
)

type tdOutputSpooler struct {
	daemon         *tdOutputSpoolerDaemon
	ticker         *time.Ticker
	tag            string
	databaseName   string
	tableName      string
	key            string
	journal        Journal
	wg             sync.WaitGroup
	shutdownChan   chan struct{}
	isShuttingDown unsafe.Pointer
	client         *td_client.TDClient
}

type tdOutputSpoolerDaemon struct {
	output       *TDOutput
	shutdownChan chan struct{}
	spoolersMtx  sync.Mutex
	spoolers     map[string]*tdOutputSpooler
	tempFactory  TempFileRandomAccessStoreFactory
	wg           sync.WaitGroup
	endNotify    func(*tdOutputSpoolerDaemon)
}

type TDOutput struct {
	logger         *logging.Logger
	codec          *codec.MsgpackHandle
	retryInterval  time.Duration
	databaseName   string
	tableName      string
	tempDir        string
	enc            *codec.Encoder
	conn           net.Conn
	flushInterval  time.Duration
	wg             sync.WaitGroup
	journalGroup   JournalGroup
	emitterChan    chan FluentRecordSet
	spoolerDaemon  *tdOutputSpoolerDaemon
	isShuttingDown unsafe.Pointer
	client         *td_client.TDClient
	sem            chan struct{}
	gcChan         chan *os.File
	completion     sync.Cond
}

func maxInt(a, b int) int {
	if a >= b {
		return a
	} else {
		return b
	}
}

func encodeRecords(encoder *codec.Encoder, records []TinyFluentRecord) error {
	for _, record := range records {
		e := map[string]interface{}{"time": record.Timestamp}
		for k, v := range record.Data {
			e[k] = v
		}
		err := encoder.Encode(e)
		if err != nil {
			return err
		}
	}
	return nil
}

func (spooler *tdOutputSpooler) cleanup() {
	spooler.wg.Wait()
	spooler.ticker.Stop()
	spooler.journal.Dispose()
	spooler.daemon.wg.Done()
}

func (spooler *tdOutputSpooler) handle() {
	defer spooler.cleanup()
	spooler.daemon.output.logger.Notice("Spooler started")
outer:
	for {
		select {
		case <-spooler.ticker.C:
			spooler.daemon.output.logger.Notice("Flushing...")
			err := spooler.journal.Flush(func(chunk JournalChunk) interface{} {
				defer chunk.Dispose()
				if atomic.LoadPointer(&spooler.isShuttingDown) != unsafe.Pointer(uintptr(0)) {
					return errors.New("Flush aborted")
				}
				spooler.daemon.output.logger.Info("Flushing chunk %s", chunk.String())
				size, err := chunk.Size()
				if err != nil {
					return err
				}
				if size == 0 {
					return nil
				}
				futureErr := make(chan error, 1)
				spooler.wg.Add(1)
				sem := spooler.daemon.output.sem
				sem <- struct{}{}
				go func(size int64, chunk JournalChunk, futureErr chan error) {
					defer func() {
						<-sem
						chunk.Dispose()
						spooler.wg.Done()
						x := recover()
						if x != nil {
							futureErr <- &Panicked{x}
						}
					}()
					_, err = spooler.client.Import(
						spooler.databaseName,
						spooler.tableName,
						"msgpack.gz",
						td_client.NewBufferingBlobSize(
							NewCompressingBlob(
								chunk,
								maxInt(4096, int(size/4)),
								gzip.BestSpeed,
								&spooler.daemon.tempFactory,
							),
							maxInt(4096, int(size/16)),
						),
						chunk.Id(),
					)
					futureErr <- err
					if err != nil {
						spooler.daemon.output.logger.Info("Failed to flush chunk %s (reason: %s)", chunk.String(), err.Error())
					} else {
						spooler.daemon.output.logger.Info("Completed flushing chunk %s", chunk.String())
					}
				}(size, chunk.Dup(), futureErr)
				return (<-chan error)(futureErr)
			})
			if err != nil {
				spooler.daemon.output.logger.Error("Error during reading from the journal: %s", err.Error())
			}
		case <-spooler.shutdownChan:
			break outer
		}
	}
	spooler.daemon.output.logger.Notice("Spooler ended")
}

func normalizeDatabaseName(name string) (string, error) {
	name_ := ([]byte)(name)
	if len(name_) == 0 {
		return "", errors.New("Empty name is not allowed")
	}
	if len(name_) < 3 {
		name_ = append(name_, ("___"[0 : 3-len(name)])...)
	}
	if 255 < len(name_) {
		name_ = append(name_[0:253], "__"...)
	}
	name_ = bytes.ToLower(name_)
	for i, c := range name_ {
		if !((c >= 'a' || c <= 'z') || (c >= '0' && c <= '9') || c == '_') {
			c = '_'
		}
		name_[i] = c
	}
	return (string)(name_), nil
}

func normalizeTableName(name string) (string, error) {
	return normalizeDatabaseName(name)
}

func newTDOutputSpooler(daemon *tdOutputSpoolerDaemon, databaseName, tableName, key string) *tdOutputSpooler {
	journal := daemon.output.journalGroup.GetJournal(key)
	return &tdOutputSpooler{
		daemon:       daemon,
		ticker:       time.NewTicker(daemon.output.flushInterval),
		databaseName: databaseName,
		tableName:    tableName,
		key:          key,
		journal:      journal,
		wg:           sync.WaitGroup{},
		shutdownChan: make(chan struct{}, 1),
		client:       daemon.output.client,
	}
}

func (daemon *tdOutputSpoolerDaemon) spawnSpooler(databaseName, tableName, key string) *tdOutputSpooler {
	daemon.spoolersMtx.Lock()
	defer daemon.spoolersMtx.Unlock()
	spooler, exists := daemon.spoolers[key]
	if exists {
		return spooler
	}
	spooler = newTDOutputSpooler(daemon, databaseName, tableName, key)
	daemon.output.logger.Notice("Spawning spooler " + spooler.key)
	daemon.spoolers[spooler.key] = spooler
	daemon.wg.Add(1)
	go spooler.handle()
	return spooler
}

func (daemon *tdOutputSpoolerDaemon) cleanup() {
	func() {
		daemon.spoolersMtx.Lock()
		defer daemon.spoolersMtx.Unlock()
		for _, spooler := range daemon.spoolers {
			if atomic.CompareAndSwapPointer(&spooler.isShuttingDown, unsafe.Pointer(uintptr(0)), unsafe.Pointer(uintptr(1))) {
				spooler.shutdownChan <- struct{}{}
			}
		}
	}()
	daemon.wg.Wait()
	if daemon.endNotify != nil {
		daemon.endNotify(daemon)
	}
	daemon.output.wg.Done()
}

func (daemon *tdOutputSpoolerDaemon) handle() {
	defer daemon.cleanup()
	daemon.output.logger.Notice("Spooler daemon started")
	// spawn Spooler according to the existing journals
	for _, key := range daemon.output.journalGroup.GetJournalKeys() {
		pair := strings.SplitN(key, ".", 2)
		if len(pair) != 2 {
			daemon.output.logger.Warning("Journal %s ignored", key)
			continue
		}
		daemon.spawnSpooler(pair[0], pair[1], key)
	}
outer:
	for {
		select {
		case <-daemon.shutdownChan:
			break outer
		}
	}
	daemon.output.logger.Notice("Spooler daemon ended")
}

func newTDOutputSpoolerDaemon(output *TDOutput) *tdOutputSpoolerDaemon {
	return &tdOutputSpoolerDaemon{
		output:       output,
		shutdownChan: make(chan struct{}, 1),
		spoolers:     make(map[string]*tdOutputSpooler),
		tempFactory:  TempFileRandomAccessStoreFactory{output.tempDir, "", output.gcChan},
		wg:           sync.WaitGroup{},
		endNotify: func(*tdOutputSpoolerDaemon) {
			close(output.gcChan)
		},
	}
}

func (output *TDOutput) spawnSpoolerDaemon() {
	output.logger.Notice("Spawning spooler daemon")
	output.spoolerDaemon = newTDOutputSpoolerDaemon(output)
	output.wg.Add(1)
	go output.spoolerDaemon.handle()
}

func (daemon *tdOutputSpoolerDaemon) getSpooler(tag string) (*tdOutputSpooler, error) {
	databaseName := daemon.output.databaseName
	tableName := daemon.output.tableName
	if databaseName == "*" {
		if tableName == "*" {
			c := strings.SplitN(tag, ".", 2)
			if len(c) == 1 {
				tableName = c[0]
			} else if len(c) == 2 {
				databaseName = c[0]
				tableName = c[1]
			}
		} else {
			databaseName = tag
		}
	} else {
		if tableName == "*" {
			tableName = tag
		}
	}
	databaseName, err := normalizeDatabaseName(databaseName)
	if err != nil {
		return nil, err
	}
	tableName, err = normalizeTableName(tableName)
	if err != nil {
		return nil, err
	}
	key := databaseName + "." + tableName
	return daemon.spawnSpooler(databaseName, tableName, key), nil
}

func (output *TDOutput) spawnEmitter() {
	output.logger.Notice("Spawning emitter")
	output.wg.Add(1)
	go func() {
		defer func() {
			output.spoolerDaemon.shutdownChan <- struct{}{}
			output.wg.Done()
		}()
		output.logger.Notice("Emitter started")
		buffer := bytes.Buffer{}
		for recordSet := range output.emitterChan {
			buffer.Reset()
			encoder := codec.NewEncoder(&buffer, output.codec)
			err := func() error {
				spooler, err := output.spoolerDaemon.getSpooler(recordSet.Tag)
				if err != nil {
					return err
				}
				err = encodeRecords(encoder, recordSet.Records)
				if err != nil {
					return err
				}
				output.logger.Debug("Emitter processed %d entries", len(recordSet.Records))
				return spooler.journal.Write(buffer.Bytes())
			}()
			if err != nil {
				output.logger.Error("%s", err.Error())
				continue
			}
		}
		output.logger.Notice("Emitter ended")
	}()
}

func (output *TDOutput) spawnTempFileCollector() {
	output.logger.Notice("Spawning temporary file collector")
	output.wg.Add(1)
	go func() {
		defer func() {
			output.wg.Done()
		}()
		for f := range output.gcChan {
			output.logger.Debug("Deleting %s...", f.Name())
			err := os.Remove(f.Name())
			if err != nil {
				output.logger.Warning("Failed to delete %s: %s", f.Name(), err.Error())
			}
		}
		output.logger.Debug("temporary file collector ended")
	}()
}

func (output *TDOutput) Emit(recordSets []FluentRecordSet) error {
	defer func() {
		recover()
	}()
	for _, recordSet := range recordSets {
		output.emitterChan <- recordSet
	}
	return nil
}

func (output *TDOutput) String() string {
	return "output"
}

func (output *TDOutput) Stop() {
	if atomic.CompareAndSwapPointer(&output.isShuttingDown, unsafe.Pointer(uintptr(0)), unsafe.Pointer(uintptr(1))) {
		close(output.emitterChan)
	}
}

func (output *TDOutput) WaitForShutdown() {
	output.completion.L.Lock()
	output.completion.Wait()
	output.completion.L.Unlock()
}

func (output *TDOutput) Start() {
	syncCh := make(chan struct{})
	go func() {
		<-syncCh
		output.wg.Wait()
		err := output.journalGroup.Dispose()
		if err != nil {
			output.logger.Error("%s", err.Error())
		}
		output.completion.Broadcast()
	}()
	output.spawnTempFileCollector()
	output.spawnEmitter()
	output.spawnSpoolerDaemon()
	syncCh <- struct{}{}
}

func NewTDOutput(
	logger *logging.Logger,
	endpoint string,
	retryInterval time.Duration,
	connectionTimeout time.Duration,
	writeTimeout time.Duration,
	flushInterval time.Duration,
	parallelism int,
	journalGroupPath string,
	maxJournalChunkSize int64,
	apiKey string,
	databaseName string,
	tableName string,
	tempDir string,
	useSsl bool,
	rootCAs *x509.CertPool,
	httpProxy string,
) (*TDOutput, error) {
	_codec := codec.MsgpackHandle{}
	_codec.MapType = reflect.TypeOf(map[string]interface{}(nil))
	_codec.RawToString = false
	_codec.StructToArray = true

	journalFactory := NewFileJournalGroupFactory(
		logger,
		randSource,
		time.Now,
		".log",
		os.FileMode(0600),
		maxJournalChunkSize,
	)
	router := (td_client.EndpointRouter)(nil)
	if endpoint != "" {
		router = &td_client.FixedEndpointRouter{endpoint}
	}
	httpProxy_ := (interface{})(nil)
	if httpProxy != "" {
		httpProxy_ = httpProxy
	}
	client, err := td_client.NewTDClient(td_client.Settings{
		ApiKey:            apiKey,
		Router:            router,
		ConnectionTimeout: connectionTimeout,
		// ReadTimeout: readTimeout, // TODO
		SendTimeout: writeTimeout,
		Ssl:         useSsl,
		RootCAs:     rootCAs,
		Proxy:       httpProxy_,
	})
	if err != nil {
		return nil, err
	}
	output := &TDOutput{
		logger:         logger,
		codec:          &_codec,
		retryInterval:  retryInterval,
		wg:             sync.WaitGroup{},
		flushInterval:  flushInterval,
		emitterChan:    make(chan FluentRecordSet),
		isShuttingDown: unsafe.Pointer(uintptr(0)),
		client:         client,
		databaseName:   databaseName,
		tableName:      tableName,
		tempDir:        tempDir,
		sem:            make(chan struct{}, parallelism),
		gcChan:         make(chan *os.File, 10),
		completion:     sync.Cond{L: &sync.Mutex{}},
	}
	journalGroup, err := journalFactory.GetJournalGroup(journalGroupPath, output)
	if err != nil {
		return nil, err
	}
	output.journalGroup = journalGroup
	return output, nil
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	go func() {
		ch <- 1
		ch <- 2
		// close(ch)
	}()

	for n := range ch {
		fmt.Println(n)
	}
}
<commit_msg>chore: add go func example<commit_after>package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 2)
	go func() {
		ch <- 1
		ch <- 2
		// close(ch)
	}()

	for n := range ch {
		fmt.Println(n)
	}

	// go func() {
	// 	for n := range ch {
	// 		fmt.Println(n)
	// 	}
	// }()

	time.Sleep(1 * time.Second)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/rand"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	ic "github.com/libp2p/go-libp2p-core/crypto"
	peer "github.com/libp2p/go-libp2p-core/peer"
	libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
	ma "github.com/multiformats/go-multiaddr"
)

func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: %s <multiaddr> <peer id>", os.Args[0])
		return
	}
	if err := run(os.Args[1], os.Args[2]); err != nil {
		log.Fatalf(err.Error())
	}
}

func run(raddr string, p string) error {
	peerID, err := peer.Decode(p)
	if err != nil {
		return err
	}
	addr, err := ma.NewMultiaddr(raddr)
	if err != nil {
		return err
	}
	priv, _, err := ic.GenerateECDSAKeyPair(rand.Reader)
	if err != nil {
		return err
	}

	t, err := libp2pquic.NewTransport(priv, nil, nil)
	if err != nil {
		return err
	}

	log.Printf("Dialing %s\n", addr.String())
	conn, err := t.Dial(context.Background(), addr, peerID)
	if err != nil {
		return err
	}
	str, err := conn.OpenStream()
	if err != nil {
		return err
	}
	const msg = "Hello world!"
	log.Printf("Sending: %s\n", msg)
	if _, err := str.Write([]byte(msg)); err != nil {
		return err
	}
	if err := str.Close(); err != nil {
		return err
	}
	data, err := ioutil.ReadAll(str)
	if err != nil {
		return err
	}
	log.Printf("Received: %s\n", data)
	return conn.Close()
}
<commit_msg>always close the connection in the cmd client<commit_after>package main

import (
	"context"
	"crypto/rand"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	ic "github.com/libp2p/go-libp2p-core/crypto"
	peer "github.com/libp2p/go-libp2p-core/peer"
	libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
	ma "github.com/multiformats/go-multiaddr"
)

func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: %s <multiaddr> <peer id>", os.Args[0])
		return
	}
	if err := run(os.Args[1], os.Args[2]); err != nil {
		log.Fatalf(err.Error())
	}
}

func run(raddr string, p string) error {
	peerID, err := peer.Decode(p)
	if err != nil {
		return err
	}
	addr, err := ma.NewMultiaddr(raddr)
	if err != nil {
		return err
	}
	priv, _, err := ic.GenerateECDSAKeyPair(rand.Reader)
	if err != nil {
		return err
	}

	t, err := libp2pquic.NewTransport(priv, nil, nil)
	if err != nil {
		return err
	}

	log.Printf("Dialing %s\n", addr.String())
	conn, err := t.Dial(context.Background(), addr, peerID)
	if err != nil {
		return err
	}
	defer conn.Close()
	str, err := conn.OpenStream()
	if err != nil {
		return err
	}
	const msg = "Hello world!"
	log.Printf("Sending: %s\n", msg)
	if _, err := str.Write([]byte(msg)); err != nil {
		return err
	}
	if err := str.Close(); err != nil {
		return err
	}
	data, err := ioutil.ReadAll(str)
	if err != nil {
		return err
	}
	log.Printf("Received: %s\n", data)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

                 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package lib

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

	cfsslapi "github.com/cloudflare/cfssl/api"
	"github.com/cloudflare/cfssl/log"

	"github.com/hyperledger/fabric-ca/api"
	"github.com/hyperledger/fabric-ca/lib/spi"
	"github.com/hyperledger/fabric-ca/util"
)

// registerHandler for register requests
type registerHandler struct {
	server *Server
}

// newRegisterHandler is constructor for register handler
func newRegisterHandler(server *Server) (h http.Handler, err error) {
	// NewHandler is constructor for register handler
	return &cfsslapi.HTTPHandler{
		Handler: &registerHandler{server: server},
		Methods: []string{"POST"},
	}, nil
}

// Handle a register request
func (h *registerHandler) Handle(w http.ResponseWriter, r *http.Request) error {
	log.Debug("Register request received")

	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	r.Body.Close()

	// Parse request body
	var req api.RegistrationRequestNet
	err = json.Unmarshal(reqBody, &req)
	if err != nil {
		return err
	}

	caname := r.Header.Get(caHdrName)

	// Register User
	callerID := r.Header.Get(enrollmentIDHdrName)
	secret, err := h.RegisterUser(&req, callerID, caname)
	if err != nil {
		return err
	}

	resp := &api.RegistrationResponseNet{RegistrationResponse: api.RegistrationResponse{Secret: secret}}

	log.Debugf("Registration completed - sending response %+v", &resp)
	return cfsslapi.SendResponse(w, resp)
}

// RegisterUser will register a user
func (h *registerHandler) RegisterUser(req *api.RegistrationRequestNet, registrar, caname string) (string, error) {

	secret := req.Secret
	req.Secret = "<<user-specified>>"
	log.Debugf("Received registration request from %s: %+v", registrar, req)
	req.Secret = secret

	var err error

	if registrar != "" {
		// Check the permissions of member named 'registrar' to perform this registration
		err = h.canRegister(registrar, req.Type, caname)
		if err != nil {
			log.Debugf("Registration of '%s' failed: %s", req.Name, err)
			return "", err
		}
	}

	err = h.validateID(req, caname)
	if err != nil {
		log.Debugf("Registration of '%s' failed: %s", req.Name, err)
		return "", err
	}

	secret, err = h.registerUserID(req, caname)

	if err != nil {
		log.Debugf("Registration of '%s' failed: %s", req.Name, err)
		return "", err
	}

	return secret, nil
}

func (h *registerHandler) validateID(req *api.RegistrationRequestNet, caname string) error {
	log.Debug("Validate ID")
	// Check whether the affiliation is required for the current user.
	if h.requireAffiliation(req.Type) {
		// If yes, is the affiliation valid
		err := h.isValidAffiliation(req.Affiliation, caname)
		if err != nil {
			return err
		}
	}
	return nil
}

// registerUserID registers a new user and its enrollmentID, role and state
func (h *registerHandler) registerUserID(req *api.RegistrationRequestNet, caname string) (string, error) {
	log.Debugf("Registering user id: %s\n", req.Name)

	if req.Secret == "" {
		req.Secret = util.RandomString(12)
	}

	maxEnrollments := h.server.caMap[caname].Config.Registry.MaxEnrollments

	if (req.MaxEnrollments > maxEnrollments && maxEnrollments != 0) || (req.MaxEnrollments < 0) {
		return "", fmt.Errorf("Invalid max enrollment value specified, value must be equal to or less then %d", maxEnrollments)
	}

	if req.MaxEnrollments == 0 && maxEnrollments != 0 {
		return "", fmt.Errorf("Unlimited enrollments not allowed, value must be equal to or less then %d", maxEnrollments)
	}

	insert := spi.UserInfo{
		Name:           req.Name,
		Pass:           req.Secret,
		Type:           req.Type,
		Affiliation:    req.Affiliation,
		Attributes:     req.Attributes,
		MaxEnrollments: maxEnrollments,
	}

	registry := h.server.caMap[caname].registry

	_, err := registry.GetUser(req.Name, nil)
	if err == nil {
		return "", fmt.Errorf("Identity '%s' is already registered", req.Name)
	}

	err = registry.InsertUser(insert)
	if err != nil {
		return "", err
	}

	return req.Secret, nil
}

func (h *registerHandler) isValidAffiliation(affiliation string, caname string) error {
	log.Debug("Validating affiliation: " + affiliation)

	_, err := h.server.caMap[caname].registry.GetAffiliation(affiliation)
	if err != nil {
		return fmt.Errorf("Failed getting affiliation '%s': %s", affiliation, err)
	}

	return nil
}

func (h *registerHandler) requireAffiliation(idType string) bool {
	log.Debugf("An affiliation is required for identity type %s", idType)
	// Require an affiliation for all identity types
	return true
}

func (h *registerHandler) canRegister(registrar string, userType string, caname string) error {
	log.Debugf("canRegister - Check to see if user %s can register", registrar)

	user, err := h.server.caMap[caname].registry.GetUser(registrar, nil)
	if err != nil {
		return fmt.Errorf("Registrar does not exist: %s", err)
	}

	var roles []string
	rolesStr := user.GetAttribute("hf.Registrar.Roles")
	if rolesStr != "" {
		roles = strings.Split(rolesStr, ",")
	} else {
		roles = make([]string, 0)
	}
	if userType != "" {
		if !util.StrContained(userType, roles) {
			return fmt.Errorf("Identity '%s' may not register type '%s'", registrar, userType)
		}
	} else {
		return errors.New("No identity type provided. Please provide identity type")
	}

	return nil
}
<commit_msg>[FAB-3425] Fix typo in error messages<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

                 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package lib

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

	cfsslapi "github.com/cloudflare/cfssl/api"
	"github.com/cloudflare/cfssl/log"

	"github.com/hyperledger/fabric-ca/api"
	"github.com/hyperledger/fabric-ca/lib/spi"
	"github.com/hyperledger/fabric-ca/util"
)

// registerHandler for register requests
type registerHandler struct {
	server *Server
}

// newRegisterHandler is constructor for register handler
func newRegisterHandler(server *Server) (h http.Handler, err error) {
	// NewHandler is constructor for register handler
	return &cfsslapi.HTTPHandler{
		Handler: &registerHandler{server: server},
		Methods: []string{"POST"},
	}, nil
}

// Handle a register request
func (h *registerHandler) Handle(w http.ResponseWriter, r *http.Request) error {
	log.Debug("Register request received")

	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	r.Body.Close()

	// Parse request body
	var req api.RegistrationRequestNet
	err = json.Unmarshal(reqBody, &req)
	if err != nil {
		return err
	}

	caname := r.Header.Get(caHdrName)

	// Register User
	callerID := r.Header.Get(enrollmentIDHdrName)
	secret, err := h.RegisterUser(&req, callerID, caname)
	if err != nil {
		return err
	}

	resp := &api.RegistrationResponseNet{RegistrationResponse: api.RegistrationResponse{Secret: secret}}

	log.Debugf("Registration completed - sending response %+v", &resp)
	return cfsslapi.SendResponse(w, resp)
}

// RegisterUser will register a user
func (h *registerHandler) RegisterUser(req *api.RegistrationRequestNet, registrar, caname string) (string, error) {

	secret := req.Secret
	req.Secret = "<<user-specified>>"
	log.Debugf("Received registration request from %s: %+v", registrar, req)
	req.Secret = secret

	var err error

	if registrar != "" {
		// Check the permissions of member named 'registrar' to perform this registration
		err = h.canRegister(registrar, req.Type, caname)
		if err != nil {
			log.Debugf("Registration of '%s' failed: %s", req.Name, err)
			return "", err
		}
	}

	err = h.validateID(req, caname)
	if err != nil {
		log.Debugf("Registration of '%s' failed: %s", req.Name, err)
		return "", err
	}

	secret, err = h.registerUserID(req, caname)

	if err != nil {
		log.Debugf("Registration of '%s' failed: %s", req.Name, err)
		return "", err
	}

	return secret, nil
}

func (h *registerHandler) validateID(req *api.RegistrationRequestNet, caname string) error {
	log.Debug("Validate ID")
	// Check whether the affiliation is required for the current user.
	if h.requireAffiliation(req.Type) {
		// If yes, is the affiliation valid
		err := h.isValidAffiliation(req.Affiliation, caname)
		if err != nil {
			return err
		}
	}
	return nil
}

// registerUserID registers a new user and its enrollmentID, role and state
func (h *registerHandler) registerUserID(req *api.RegistrationRequestNet, caname string) (string, error) {
	log.Debugf("Registering user id: %s\n", req.Name)

	if req.Secret == "" {
		req.Secret = util.RandomString(12)
	}

	maxEnrollments := h.server.caMap[caname].Config.Registry.MaxEnrollments

	if (req.MaxEnrollments > maxEnrollments && maxEnrollments != 0) || (req.MaxEnrollments < 0) {
		return "", fmt.Errorf("Invalid max enrollment value specified, value must be equal to or less than %d", maxEnrollments)
	}

	if req.MaxEnrollments == 0 && maxEnrollments != 0 {
		return "", fmt.Errorf("Unlimited enrollments not allowed, value must be equal to or less than %d", maxEnrollments)
	}

	insert := spi.UserInfo{
		Name:           req.Name,
		Pass:           req.Secret,
		Type:           req.Type,
		Affiliation:    req.Affiliation,
		Attributes:     req.Attributes,
		MaxEnrollments: maxEnrollments,
	}

	registry := h.server.caMap[caname].registry

	_, err := registry.GetUser(req.Name, nil)
	if err == nil {
		return "", fmt.Errorf("Identity '%s' is already registered", req.Name)
	}

	err = registry.InsertUser(insert)
	if err != nil {
		return "", err
	}

	return req.Secret, nil
}

func (h *registerHandler) isValidAffiliation(affiliation string, caname string) error {
	log.Debug("Validating affiliation: " + affiliation)

	_, err := h.server.caMap[caname].registry.GetAffiliation(affiliation)
	if err != nil {
		return fmt.Errorf("Failed getting affiliation '%s': %s", affiliation, err)
	}

	return nil
}

func (h *registerHandler) requireAffiliation(idType string) bool {
	log.Debugf("An affiliation is required for identity type %s", idType)
	// Require an affiliation for all identity types
	return true
}

func (h *registerHandler) canRegister(registrar string, userType string, caname string) error {
	log.Debugf("canRegister - Check to see if user %s can register", registrar)

	user, err := h.server.caMap[caname].registry.GetUser(registrar, nil)
	if err != nil {
		return fmt.Errorf("Registrar does not exist: %s", err)
	}

	var roles []string
	rolesStr := user.GetAttribute("hf.Registrar.Roles")
	if rolesStr != "" {
		roles = strings.Split(rolesStr, ",")
	} else {
		roles = make([]string, 0)
	}
	if userType != "" {
		if !util.StrContained(userType, roles) {
			return fmt.Errorf("Identity '%s' may not register type '%s'", registrar, userType)
		}
	} else {
		return errors.New("No identity type provided. Please provide identity type")
	}

	return nil
}
<|endoftext|>