<commit_before>// Package proctl provides functions for attaching to and manipulating
// a process during the debug session.
package proctl

import (
	"bytes"
	"debug/elf"
	"debug/gosym"
	"encoding/binary"
	"fmt"
	"os"
	"syscall"

	"github.com/derekparker/dbg/dwarf/frame"
	"github.com/derekparker/dbg/dwarf/line"
)

// Struct representing a debugged process. Holds onto pid, register values,
// process struct and process state.
type DebuggedProcess struct {
	Pid          int
	Regs         *syscall.PtraceRegs
	Process      *os.Process
	ProcessState *os.ProcessState
	Executable   *elf.File
	Symbols      []elf.Symbol
	GoSymTable   *gosym.Table
	FrameEntries frame.FrameDescriptionEntries
	DebugLine    *line.DebugLineInfo
	BreakPoints  map[string]*BreakPoint
}

// Represents a single breakpoint. Stores information on the break
// point including the byte of data that originally was stored at that
// address.
type BreakPoint struct {
	FunctionName string
	File         string
	Line         int
	Addr         uint64
	OriginalData []byte
}

type BreakPointExistsError struct {
	file string
	line int
	addr uintptr
}

func (bpe BreakPointExistsError) Error() string {
	return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr)
}

// Returns a new DebuggedProcess struct with sensible defaults.
func NewDebugProcess(pid int) (*DebuggedProcess, error) {
	proc, err := os.FindProcess(pid)
	if err != nil {
		return nil, err
	}

	err = syscall.PtraceAttach(pid)
	if err != nil {
		return nil, err
	}

	ps, err := proc.Wait()
	if err != nil {
		return nil, err
	}

	debuggedProc := DebuggedProcess{
		Pid:          pid,
		Regs:         &syscall.PtraceRegs{},
		Process:      proc,
		ProcessState: ps,
		BreakPoints:  make(map[string]*BreakPoint),
	}

	err = debuggedProc.LoadInformation()
	if err != nil {
		return nil, err
	}

	return &debuggedProc, nil
}

// Finds the executable from /proc/<pid>/exe and then
// uses that to parse the Go symbol table.
func (dbp *DebuggedProcess) LoadInformation() error {
	err := dbp.findExecutable()
	if err != nil {
		return err
	}

	err = dbp.parseDebugFrame()
	if err != nil {
		return err
	}

	err = dbp.parseDebugLine()
	if err != nil {
		return err
	}

	err = dbp.obtainGoSymbols()
	if err != nil {
		return err
	}

	return nil
}

// Obtains register values from the debugged process.
func (dbp *DebuggedProcess) Registers() (*syscall.PtraceRegs, error) {
	err := syscall.PtraceGetRegs(dbp.Pid, dbp.Regs)
	if err != nil {
		return nil, fmt.Errorf("Registers():", err)
	}

	return dbp.Regs, nil
}

// Sets a breakpoint in the running process.
func (dbp *DebuggedProcess) Break(addr uintptr) (*BreakPoint, error) {
	var (
		int3         = []byte{0xCC}
		f, l, fn     = dbp.GoSymTable.PCToLine(uint64(addr))
		originalData = make([]byte, 1)
	)

	_, err := syscall.PtracePeekData(dbp.Pid, addr, originalData)
	if err != nil {
		return nil, err
	}

	if bytes.Equal(originalData, int3) {
		return nil, BreakPointExistsError{f, l, addr}
	}

	_, err = syscall.PtracePokeData(dbp.Pid, addr, int3)
	if err != nil {
		return nil, err
	}

	breakpoint := &BreakPoint{
		FunctionName: fn.Name,
		File:         f,
		Line:         l,
		Addr:         uint64(addr),
		OriginalData: originalData,
	}

	fname := fmt.Sprintf("%s:%d", f, l)
	dbp.BreakPoints[fname] = breakpoint

	return breakpoint, nil
}

// Clears a breakpoint.
func (dbp *DebuggedProcess) Clear(pc uint64) (*BreakPoint, error) {
	bp, ok := dbp.PCtoBP(pc)
	if !ok {
		return nil, fmt.Errorf("No breakpoint currently set for %s", bp.FunctionName)
	}

	_, err := syscall.PtracePokeData(dbp.Pid, uintptr(bp.Addr), bp.OriginalData)
	if err != nil {
		return nil, err
	}

	delete(dbp.BreakPoints, fmt.Sprintf("%s:%d", bp.File, bp.Line))

	return bp, nil
}

// Steps through process.
func (dbp *DebuggedProcess) Step() (err error) {
	regs, err := dbp.Registers()
	if err != nil {
		return err
	}

	bp, ok := dbp.PCtoBP(regs.PC() - 1)
	if ok {
		// Clear the breakpoint so that we can continue execution.
		_, err = dbp.Clear(bp.Addr)
		if err != nil {
			return err
		}

		// Reset program counter to our restored instruction.
		regs.SetPC(bp.Addr)
		err = syscall.PtraceSetRegs(dbp.Pid, regs)
		if err != nil {
			return err
		}

		// Restore breakpoint now that we have passed it.
		defer func() {
			_, err = dbp.Break(uintptr(bp.Addr))
		}()
	}

	err = dbp.handleResult(syscall.PtraceSingleStep(dbp.Pid))
	if err != nil {
		return fmt.Errorf("step failed: ", err.Error())
	}

	return nil
}

// Step over function calls.
func (dbp *DebuggedProcess) Next() error {
	addrs := make([]uint64, 0, 3)
	pc, err := dbp.CurrentPC()
	if err != nil {
		return err
	}

	pc-- // account for breakpoint instruction

	fde, err := dbp.FrameEntries.FDEForPC(pc)
	if err != nil {
		return err
	}

	loc := dbp.DebugLine.NextLocAfterPC(pc)
	if !fde.AddressRange.Cover(loc.Address) {
		// Next line is outside current frame, use return addr.
		addr := dbp.ReturnAddressFromOffset(fde.ReturnAddressOffset(pc))
		loc = dbp.DebugLine.LocationInfoForPC(addr)
	}
	addrs = append(addrs, loc.Address)

	if loc.Delta < 0 {
		// We are likely in a loop, set breakpoints at entry and exit.
		entry := dbp.DebugLine.LoopEntryLocation(loc.Line)
		exit := dbp.DebugLine.LoopExitLocation(pc)
		addrs = append(addrs, entry.Address, exit.Address)
	}

	for _, addr := range addrs {
		if _, err := dbp.Break(uintptr(addr)); err != nil {
			if _, ok := err.(BreakPointExistsError); !ok {
				return err
			}
		}
	}

	return dbp.Continue()
}

// Continue process until next breakpoint.
func (dbp *DebuggedProcess) Continue() error {
	// Stepping first will ensure we are able to continue
	// past a breakpoint if that's currently where we are stopped.
	err := dbp.Step()
	if err != nil {
		return err
	}

	return dbp.handleResult(syscall.PtraceCont(dbp.Pid, 0))
}

func (dbp *DebuggedProcess) CurrentPC() (uint64, error) {
	regs, err := dbp.Registers()
	if err != nil {
		return 0, err
	}

	return regs.Rip, nil
}

func (dbp *DebuggedProcess) handleResult(err error) error {
	if err != nil {
		return err
	}

	ps, err := dbp.Process.Wait()
	if err != nil {
		return err
	}

	dbp.ProcessState = ps

	return nil
}

func (dbp *DebuggedProcess) findExecutable() error {
	procpath := fmt.Sprintf("/proc/%d/exe", dbp.Pid)

	f, err := os.Open(procpath)
	if err != nil {
		return err
	}

	elffile, err := elf.NewFile(f)
	if err != nil {
		return err
	}

	dbp.Executable = elffile

	return nil
}

func (dbp *DebuggedProcess) parseDebugLine() error {
	debugLine, err := dbp.Executable.Section(".debug_line").Data()
	if err != nil {
		return err
	}

	dbp.DebugLine = line.Parse(debugLine)
	return nil
}
func (dbp *DebuggedProcess) parseDebugFrame() error {
	debugFrame, err := dbp.Executable.Section(".debug_frame").Data()
	if err != nil {
		return err
	}

	dbp.FrameEntries = frame.Parse(debugFrame)
	return nil
}

func (dbp *DebuggedProcess) obtainGoSymbols() error {
	symdat, err := dbp.Executable.Section(".gosymtab").Data()
	if err != nil {
		return err
	}

	pclndat, err := dbp.Executable.Section(".gopclntab").Data()
	if err != nil {
		return err
	}

	pcln := gosym.NewLineTable(pclndat, dbp.Executable.Section(".text").Addr)
	tab, err := gosym.NewTable(symdat, pcln)
	if err != nil {
		return err
	}

	dbp.GoSymTable = tab

	return nil
}

// Converts a program counter value into a breakpoint, if one was set
// for the function containing pc.
func (dbp *DebuggedProcess) PCtoBP(pc uint64) (*BreakPoint, bool) {
	f, l, _ := dbp.GoSymTable.PCToLine(pc)
	bp, ok := dbp.BreakPoints[fmt.Sprintf("%s:%d", f, l)]
	return bp, ok
}

// Takes an offset from RSP and returns the address of the
// instruction the currect function is going to return to.
func (dbp *DebuggedProcess) ReturnAddressFromOffset(offset int64) uint64 {
	regs, err := dbp.Registers()
	if err != nil {
		panic("Could not obtain register values")
	}

	retaddr := int64(regs.Rsp) + offset
	data := make([]byte, 8)
	syscall.PtracePeekText(dbp.Pid, uintptr(retaddr), data)
	return binary.LittleEndian.Uint64(data)
}
<commit_msg>Add line between functions<commit_after>// Package proctl provides functions for attaching to and manipulating
// a process during the debug session.
package proctl

import (
	"bytes"
	"debug/elf"
	"debug/gosym"
	"encoding/binary"
	"fmt"
	"os"
	"syscall"

	"github.com/derekparker/dbg/dwarf/frame"
	"github.com/derekparker/dbg/dwarf/line"
)

// Struct representing a debugged process. Holds onto pid, register values,
// process struct and process state.
type DebuggedProcess struct {
	Pid          int
	Regs         *syscall.PtraceRegs
	Process      *os.Process
	ProcessState *os.ProcessState
	Executable   *elf.File
	Symbols      []elf.Symbol
	GoSymTable   *gosym.Table
	FrameEntries frame.FrameDescriptionEntries
	DebugLine    *line.DebugLineInfo
	BreakPoints  map[string]*BreakPoint
}

// Represents a single breakpoint. Stores information on the break
// point including the byte of data that originally was stored at that
// address.
type BreakPoint struct {
	FunctionName string
	File         string
	Line         int
	Addr         uint64
	OriginalData []byte
}

type BreakPointExistsError struct {
	file string
	line int
	addr uintptr
}

func (bpe BreakPointExistsError) Error() string {
	return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr)
}

// Returns a new DebuggedProcess struct with sensible defaults.
func NewDebugProcess(pid int) (*DebuggedProcess, error) {
	proc, err := os.FindProcess(pid)
	if err != nil {
		return nil, err
	}

	err = syscall.PtraceAttach(pid)
	if err != nil {
		return nil, err
	}

	ps, err := proc.Wait()
	if err != nil {
		return nil, err
	}

	debuggedProc := DebuggedProcess{
		Pid:          pid,
		Regs:         &syscall.PtraceRegs{},
		Process:      proc,
		ProcessState: ps,
		BreakPoints:  make(map[string]*BreakPoint),
	}

	err = debuggedProc.LoadInformation()
	if err != nil {
		return nil, err
	}

	return &debuggedProc, nil
}

// Finds the executable from /proc/<pid>/exe and then
// uses that to parse the Go symbol table.
func (dbp *DebuggedProcess) LoadInformation() error {
	err := dbp.findExecutable()
	if err != nil {
		return err
	}

	err = dbp.parseDebugFrame()
	if err != nil {
		return err
	}

	err = dbp.parseDebugLine()
	if err != nil {
		return err
	}

	err = dbp.obtainGoSymbols()
	if err != nil {
		return err
	}

	return nil
}

// Obtains register values from the debugged process.
func (dbp *DebuggedProcess) Registers() (*syscall.PtraceRegs, error) {
	err := syscall.PtraceGetRegs(dbp.Pid, dbp.Regs)
	if err != nil {
		return nil, fmt.Errorf("Registers():", err)
	}

	return dbp.Regs, nil
}

// Sets a breakpoint in the running process.
func (dbp *DebuggedProcess) Break(addr uintptr) (*BreakPoint, error) {
	var (
		int3         = []byte{0xCC}
		f, l, fn     = dbp.GoSymTable.PCToLine(uint64(addr))
		originalData = make([]byte, 1)
	)

	_, err := syscall.PtracePeekData(dbp.Pid, addr, originalData)
	if err != nil {
		return nil, err
	}

	if bytes.Equal(originalData, int3) {
		return nil, BreakPointExistsError{f, l, addr}
	}

	_, err = syscall.PtracePokeData(dbp.Pid, addr, int3)
	if err != nil {
		return nil, err
	}

	breakpoint := &BreakPoint{
		FunctionName: fn.Name,
		File:         f,
		Line:         l,
		Addr:         uint64(addr),
		OriginalData: originalData,
	}

	fname := fmt.Sprintf("%s:%d", f, l)
	dbp.BreakPoints[fname] = breakpoint

	return breakpoint, nil
}

// Clears a breakpoint.
func (dbp *DebuggedProcess) Clear(pc uint64) (*BreakPoint, error) {
	bp, ok := dbp.PCtoBP(pc)
	if !ok {
		return nil, fmt.Errorf("No breakpoint currently set for %s", bp.FunctionName)
	}

	_, err := syscall.PtracePokeData(dbp.Pid, uintptr(bp.Addr), bp.OriginalData)
	if err != nil {
		return nil, err
	}

	delete(dbp.BreakPoints, fmt.Sprintf("%s:%d", bp.File, bp.Line))

	return bp, nil
}

// Steps through process.
func (dbp *DebuggedProcess) Step() (err error) {
	regs, err := dbp.Registers()
	if err != nil {
		return err
	}

	bp, ok := dbp.PCtoBP(regs.PC() - 1)
	if ok {
		// Clear the breakpoint so that we can continue execution.
		_, err = dbp.Clear(bp.Addr)
		if err != nil {
			return err
		}

		// Reset program counter to our restored instruction.
		regs.SetPC(bp.Addr)
		err = syscall.PtraceSetRegs(dbp.Pid, regs)
		if err != nil {
			return err
		}

		// Restore breakpoint now that we have passed it.
		defer func() {
			_, err = dbp.Break(uintptr(bp.Addr))
		}()
	}

	err = dbp.handleResult(syscall.PtraceSingleStep(dbp.Pid))
	if err != nil {
		return fmt.Errorf("step failed: ", err.Error())
	}

	return nil
}

// Step over function calls.
func (dbp *DebuggedProcess) Next() error {
	addrs := make([]uint64, 0, 3)
	pc, err := dbp.CurrentPC()
	if err != nil {
		return err
	}

	pc-- // account for breakpoint instruction

	fde, err := dbp.FrameEntries.FDEForPC(pc)
	if err != nil {
		return err
	}

	loc := dbp.DebugLine.NextLocAfterPC(pc)
	if !fde.AddressRange.Cover(loc.Address) {
		// Next line is outside current frame, use return addr.
		addr := dbp.ReturnAddressFromOffset(fde.ReturnAddressOffset(pc))
		loc = dbp.DebugLine.LocationInfoForPC(addr)
	}
	addrs = append(addrs, loc.Address)

	if loc.Delta < 0 {
		// We are likely in a loop, set breakpoints at entry and exit.
		entry := dbp.DebugLine.LoopEntryLocation(loc.Line)
		exit := dbp.DebugLine.LoopExitLocation(pc)
		addrs = append(addrs, entry.Address, exit.Address)
	}

	for _, addr := range addrs {
		if _, err := dbp.Break(uintptr(addr)); err != nil {
			if _, ok := err.(BreakPointExistsError); !ok {
				return err
			}
		}
	}

	return dbp.Continue()
}

// Continue process until next breakpoint.
func (dbp *DebuggedProcess) Continue() error {
	// Stepping first will ensure we are able to continue
	// past a breakpoint if that's currently where we are stopped.
	err := dbp.Step()
	if err != nil {
		return err
	}

	return dbp.handleResult(syscall.PtraceCont(dbp.Pid, 0))
}

func (dbp *DebuggedProcess) CurrentPC() (uint64, error) {
	regs, err := dbp.Registers()
	if err != nil {
		return 0, err
	}

	return regs.Rip, nil
}

func (dbp *DebuggedProcess) handleResult(err error) error {
	if err != nil {
		return err
	}

	ps, err := dbp.Process.Wait()
	if err != nil {
		return err
	}

	dbp.ProcessState = ps

	return nil
}

func (dbp *DebuggedProcess) findExecutable() error {
	procpath := fmt.Sprintf("/proc/%d/exe", dbp.Pid)

	f, err := os.Open(procpath)
	if err != nil {
		return err
	}

	elffile, err := elf.NewFile(f)
	if err != nil {
		return err
	}

	dbp.Executable = elffile

	return nil
}

func (dbp *DebuggedProcess) parseDebugLine() error {
	debugLine, err := dbp.Executable.Section(".debug_line").Data()
	if err != nil {
		return err
	}

	dbp.DebugLine = line.Parse(debugLine)
	return nil
}

func (dbp *DebuggedProcess) parseDebugFrame() error {
	debugFrame, err := dbp.Executable.Section(".debug_frame").Data()
	if err != nil {
		return err
	}

	dbp.FrameEntries = frame.Parse(debugFrame)
	return nil
}

func (dbp *DebuggedProcess) obtainGoSymbols() error {
	symdat, err := dbp.Executable.Section(".gosymtab").Data()
	if err != nil {
		return err
	}

	pclndat, err := dbp.Executable.Section(".gopclntab").Data()
	if err != nil {
		return err
	}

	pcln := gosym.NewLineTable(pclndat, dbp.Executable.Section(".text").Addr)
	tab, err := gosym.NewTable(symdat, pcln)
	if err != nil {
		return err
	}

	dbp.GoSymTable = tab

	return nil
}

// Converts a program counter value into a breakpoint, if one was set
// for the function containing pc.
func (dbp *DebuggedProcess) PCtoBP(pc uint64) (*BreakPoint, bool) {
	f, l, _ := dbp.GoSymTable.PCToLine(pc)
	bp, ok := dbp.BreakPoints[fmt.Sprintf("%s:%d", f, l)]
	return bp, ok
}

// Takes an offset from RSP and returns the address of the
// instruction the currect function is going to return to.
func (dbp *DebuggedProcess) ReturnAddressFromOffset(offset int64) uint64 {
	regs, err := dbp.Registers()
	if err != nil {
		panic("Could not obtain register values")
	}

	retaddr := int64(regs.Rsp) + offset
	data := make([]byte, 8)
	syscall.PtracePeekText(dbp.Pid, uintptr(retaddr), data)
	return binary.LittleEndian.Uint64(data)
}
<|endoftext|>


<commit_before>// Copyright © 2016 Zenly <hello@zen.ly>.
//
// 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 protoscan

import (
	"fmt"
	"reflect"

	"github.com/gogo/protobuf/proto"
	"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
	"github.com/pkg/errors"
)

// -----------------------------------------------------------------------------

type descriptorNode struct {
	// descr is either a DescriptorProto (Message) or an
	// EnumDescriptorProto (Enum).
	descr proto.Message

	// hashSingle is the the hash (as implemented in byte_sslice.go) of
	// `this.descr`.
	// hashSingle = SHA1(d.descr)
	//
	// It is used to uniquely and deterministically identify a Message or Enum
	// type that has been instanciated by a protobuf library.
	//
	// hashSingle is necessary for the internal DescriptorTree machinery to work,
	// but it is never exposed to the end-user of the protoscan package.
	hashSingle []byte
	// hashRecursive is the the hash (as implemented in byte_sslice.go) of
	// `this.descr` + the hashes of every type it depends on (recursively).
	// Note that, to ensure determinism, the list of hashes used to compute
	// the final `hashRecursive` value is alphabetically-sorted first.
	// hashRecursive = SHA1(SORT(d.hashSingle, d.AllDependencyHashes))
	//
	// It is the unique, deterministic and versioned identifier for a Message or
	// Enum type.
	// This is the actual value that is exposed to the end-user of the protoscan
	// package, and is traditionally used as the key inside a schema registry.
	hashRecursive []byte
}

// -----------------------------------------------------------------------------

// A DescriptorTree is a dependency tree of Message/Enum descriptors.
type DescriptorTree struct {
	*descriptorNode
	children []*DescriptorTree
}

// UID returns a unique, deterministic, versioned identifier for this particular
// DescriptorTree.
//
// This identifier is computed from `dt`'s protobuf schema as well as its
// dependencies' schemas.
// This means that modifying any schema in the dependency tree, not just `dt`'s,
// will result in a new identifier being generated.
//
// The returned string is the hexadecimal representation of `dt`'s internal
// recursive hash.
func (dt *DescriptorTree) UID() string {
	return fmt.Sprintf("%x", dt.hashRecursive)
}

// DependencyUIDs recursively walks through the dependencies of `dt` and
// returns a sorted list of the hexadecimal representations of their
// respective recursive hashes.
//
// This should only be called once the linking & recursive hashing computation
// have been done.
func (dt *DescriptorTree) DependencyUIDs() []string {
	// used to avoid cyclic dependencies
	alreadyMet := make(map[*DescriptorTree]struct{}, len(dt.children))
	var recurseChildren func(dts []*DescriptorTree) ByteSSlice
	recurseChildren = func(dts []*DescriptorTree) ByteSSlice {
		recursiveHashes := make(ByteSSlice, 0, len(dts))
		for _, dt := range dts {
			if _, ok := alreadyMet[dt]; ok {
				continue
			}
			alreadyMet[dt] = struct{}{}
			recursiveHashes = append(recursiveHashes, dt.hashSingle)
			recursiveHashes = append(
				recursiveHashes, recurseChildren(dt.children)...,
			)
		}
		return recursiveHashes
	}

	recursiveHashes := recurseChildren(dt.children)
	recursiveHashes.Sort()

	hexHashes := make([]string, len(recursiveHashes))
	for i, rh := range recursiveHashes {
		hexHashes[i] = string(rh)
	}

	return hexHashes
}

// -----------------------------------------------------------------------------

func NewDescriptorTrees(
	fdps map[string]*descriptor.FileDescriptorProto,
) (map[string]*DescriptorTree, error) {
	/* DEBUG */
	for file, fdp := range fdps {
		fmt.Println("file:", file)
		for _, dep := range fdp.GetDependency() {
			fmt.Println("\tdependency:", dep)
		}
		for _, et := range fdp.GetEnumType() {
			fmt.Println("\tenum type:", et.GetName())
		}
		for _, mt := range fdp.GetMessageType() {
			fmt.Println("\tmessage type:", mt.GetName())
		}
	}

	// all of the Message/Enum/Nested types currently instanciated,
	// arranged by their fully-qualified names
	dtsByName, err := collectDescriptorTypes(fdps)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	// Computes the `children` lists for every available DescriptorTree.
	//
	// Note that we need all the dependency trees of all DescriptorTrees
	// to be already computed before we can compute the definitive recursive
	// hashes.
	for _, dt := range dtsByName {
		if err := dt.computeDependencyLinks(dtsByName); err != nil {
			return nil, errors.WithStack(err)
		}
	}

	// computes the recursive hash value for each available DescriptorTree
	for _, dt := range dtsByName {
		if err := dt.computeRecursiveHash(); err != nil {
			return nil, errors.WithStack(err)
		}
	}

	return nil, nil
}

// newDescriptorTree returns a new DescriptorTree with its `hashSingle`
// field already computed.
// At this stage, dependencies have not been calculated yet, hence the
// `children` slice of the DescriptorTree is nil.
func newDescriptorTree(descr proto.Message) (*DescriptorTree, error) {
	dt := &DescriptorTree{descriptorNode: &descriptorNode{descr: descr}}

	if err := checkDescriptorType(descr); err != nil {
		return nil, errors.WithStack(err)
	}

	descrBytes, err := proto.Marshal(descr)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	hashSingle, err := ByteSSlice{descrBytes}.Hash()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	dt.hashSingle = hashSingle

	return dt, nil
}

// -----------------------------------------------------------------------------

// computeDependencyLinks appends the DependencyTrees of `dt`'s dependencies
// to its list of children.
//
// At this stage, the newly-appended dependencies are not guaranteed to have
// their own dependency-links already computed (i.e. their respective
// `children` lists are still nil), since their `computeDependencyLinks`
// might not have been called yet (the order in which each DescriptorTree
// gets its links computed is random).
// For that reason, recursive hashes cannot yet be computed here.
//
// This must be called before calling `computeRecursiveHash()`.
func (dt *DescriptorTree) computeDependencyLinks(
	dtsByName map[string]*DescriptorTree,
) error {
	switch descr := dt.descr.(type) {
	case *descriptor.DescriptorProto:
		for _, f := range descr.GetField() {
			// `typeName` is non-empty only if it references a Message or
			// Enum type
			if typeName := f.GetTypeName(); len(typeName) > 0 {
				child, ok := dtsByName[typeName]
				if !ok {
					return errors.Errorf("`%s`: no such type")
				}
				dt.children = append(dt.children, child)
			}
		}
	case *descriptor.EnumDescriptorProto:
		// nothing to do
	default:
		return errors.Errorf("`%v`: illegal type", reflect.TypeOf(descr))
	}
	return nil
}

// computeRecursiveHash recursively walks through `dt`'s dependencies
// in order to compute its recursive hash.
//
// `computeDependencyLinks()` must be called first for every available
// DescriptorTree.
func (dt *DescriptorTree) computeRecursiveHash() error {
	// used to avoid cyclic dependencies
	alreadyMet := make(map[*DescriptorTree]struct{}, len(dt.children))
	var recurseChildren func(dts []*DescriptorTree) (ByteSSlice, error)
	recurseChildren = func(dts []*DescriptorTree) (ByteSSlice, error) {
		singleHashes := make(ByteSSlice, 0, len(dts))
		for _, dt := range dts {
			if _, ok := alreadyMet[dt]; ok {
				continue
			}
			alreadyMet[dt] = struct{}{}
			singleHashesRec, err := recurseChildren(dt.children)
			if err != nil {
				return nil, errors.WithStack(err)
			}
			singleHashes = append(singleHashes, dt.hashSingle)
			singleHashes = append(singleHashes, singleHashesRec...)
		}
		return singleHashes, nil
	}

	singleHashes, err := recurseChildren(dt.children)
	if err != nil {
		return errors.WithStack(err)
	}
	hashRecursive, err := singleHashes.Hash()
	if err != nil {
		return errors.WithStack(err)
	}
	dt.hashRecursive = hashRecursive

	return nil
}

// -----------------------------------------------------------------------------

// collectDescriptorTypes recursively goes through all the FileDescriptorProtos
// that are passed to it in order to collect all of the Message, Enum & Nested
// types that can be found in these descriptors.
//
// The result is a flattened map of single-level (i.e. `children` is nil)
// DescriptorTrees arranged by the types' absolute names
// (e.g. `.google.protobuf.Timestamp`).
//
// This map is a necessary intermediate representation for computing the final
// dependency trees.
func collectDescriptorTypes(
	fdps map[string]*descriptor.FileDescriptorProto,
) (map[string]*DescriptorTree, error) {
	// Pre-allocating len(fdps)*3, assuming an average of 3 Message/Enum
	// types per file.
	// This mapping is arranged by the descriptors' respective name and is
	// a necessary intermediate representation for the final computation of
	// dependency trees.
	dtsByName := make(map[string]*DescriptorTree, len(fdps)*3)

	// recurse through a protoFile and pushes every Message/Enum/Nested
	// type to the `dtsByName` map
	var recurseMessages func(mt *descriptor.DescriptorProto, parent string) error
	recurseMessages = func(mt *descriptor.DescriptorProto, parent string) error {
		dt, err := newDescriptorTree(mt)
		if err != nil {
			return errors.WithStack(err)
		}
		parent += ("." + mt.GetName())
		dtsByName[parent] = dt
		for _, et := range mt.GetEnumType() {
			dt, err := newDescriptorTree(et)
			if err != nil {
				return errors.WithStack(err)
			}
			dtsByName[parent+"."+et.GetName()] = dt
		}
		for _, nmt := range mt.GetNestedType() {
			if err := recurseMessages(nmt, parent); err != nil {
				return errors.WithStack(err)
			}
		}
		return nil
	}

	// walk through the protoFiles
	for _, fdp := range fdps {
		parent := "." + fdp.GetPackage()
		for _, et := range fdp.GetEnumType() {
			dt, err := newDescriptorTree(et)
			if err != nil {
				return nil, errors.WithStack(err)
			}
			dtsByName[parent+"."+et.GetName()] = dt
		}
		for _, mt := range fdp.GetMessageType() {
			if err := recurseMessages(mt, parent); err != nil {
				return nil, errors.WithStack(err)
			}
		}
	}

	return dtsByName, nil
}

// -----------------------------------------------------------------------------

func checkDescriptorType(descr proto.Message) error {
	switch descr.(type) {
	case *descriptor.DescriptorProto:
	case *descriptor.EnumDescriptorProto:
	default:
		return errors.Errorf("`%v`: illegal type", reflect.TypeOf(descr))
	}
	return nil
}
<commit_msg>protoscan > implemented fully-qualified names for DescriptorTree<commit_after>// Copyright © 2016 Zenly <hello@zen.ly>.
//
// 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 protoscan

import (
	"fmt"
	"reflect"

	"github.com/gogo/protobuf/proto"
	"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
	"github.com/pkg/errors"
)

// -----------------------------------------------------------------------------

type descriptorNode struct {
	// descr is either a DescriptorProto (Message) or an
	// EnumDescriptorProto (Enum).
	descr proto.Message
	// fqName is the fully-qualified name of the descriptor `descr`
	// (e.g. .google.protobuf.Timestamp).
	fqName string

	// hashSingle is the the hash (as implemented in byte_sslice.go) of
	// `this.descr`.
	// hashSingle = SHA1(d.descr)
	//
	// It is used to uniquely and deterministically identify a Message or Enum
	// type that has been instanciated by a protobuf library.
	//
	// hashSingle is necessary for the internal DescriptorTree machinery to work,
	// but it is never exposed to the end-user of the protoscan package.
	hashSingle []byte
	// hashRecursive is the the hash (as implemented in byte_sslice.go) of
	// `this.descr` + the hashes of every type it depends on (recursively).
	// Note that, to ensure determinism, the list of hashes used to compute
	// the final `hashRecursive` value is alphabetically-sorted first.
	// hashRecursive = SHA1(SORT(d.hashSingle, d.AllDependencyHashes))
	//
	// It is the unique, deterministic and versioned identifier for a Message or
	// Enum type.
	// This is the actual value that is exposed to the end-user of the protoscan
	// package, and is traditionally used as the key inside a schema registry.
	hashRecursive []byte
}

// -----------------------------------------------------------------------------

// A DescriptorTree is a dependency tree of Message/Enum descriptors.
type DescriptorTree struct {
	*descriptorNode
	children []*DescriptorTree
}

// FQName returns the fully-qualified name of the underlying descriptor `descr`
// (e.g. .google.protobuf.Timestamp).
func (dt *DescriptorTree) FQName() string { return dt.fqName }

// UID returns a unique, deterministic, versioned identifier for this particular
// DescriptorTree.
//
// This identifier is computed from `dt`'s protobuf schema as well as its
// dependencies' schemas.
// This means that modifying any schema in the dependency tree, not just `dt`'s,
// will result in a new identifier being generated.
//
// The returned string is the hexadecimal representation of `dt`'s internal
// recursive hash.
func (dt *DescriptorTree) UID() string {
	return fmt.Sprintf("%x", dt.hashRecursive)
}

// DependencyUIDs recursively walks through the dependencies of `dt` and
// returns a sorted list of the hexadecimal representations of their
// respective recursive hashes.
//
// This should only be called once the linking & recursive hashing computation
// have been done.
func (dt *DescriptorTree) DependencyUIDs() []string {
	// used to avoid cyclic dependencies
	alreadyMet := make(map[*DescriptorTree]struct{}, len(dt.children))
	var recurseChildren func(dts []*DescriptorTree) []string
	recurseChildren = func(dts []*DescriptorTree) []string {
		recursiveHashes := make([]string, 0, len(dts))
		for _, dt := range dts {
			if _, ok := alreadyMet[dt]; ok {
				continue
			}
			alreadyMet[dt] = struct{}{}
			recursiveHashes = append(recursiveHashes, dt.UID())
			recursiveHashes = append(
				recursiveHashes, recurseChildren(dt.children)...,
			)
		}
		return recursiveHashes
	}

	return recurseChildren(dt.children)
}

// -----------------------------------------------------------------------------

func NewDescriptorTrees(
	fdps map[string]*descriptor.FileDescriptorProto,
) (map[string]*DescriptorTree, error) {
	// all of the Message/Enum/Nested types currently instanciated,
	// arranged by their fully-qualified names
	dtsByName, err := collectDescriptorTypes(fdps)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	// Computes the `children` lists for every available DescriptorTree.
	//
	// Note that we need all the dependency trees of all DescriptorTrees
	// to be already computed before we can compute the definitive recursive
	// hashes.
	for _, dt := range dtsByName {
		if err := dt.computeDependencyLinks(dtsByName); err != nil {
			return nil, errors.WithStack(err)
		}
	}

	// computes the recursive hash value for each available DescriptorTree
	for _, dt := range dtsByName {
		if err := dt.computeRecursiveHash(); err != nil {
			return nil, errors.WithStack(err)
		}
	}

	// builds the final map of DescriptorTrees, arranged by UIDs
	// (i.e. recursive hashes)
	dtsByUID := make(map[string]*DescriptorTree, len(dtsByName))
	for _, dt := range dtsByName {
		dtsByUID[dt.UID()] = dt
	}

	return dtsByUID, nil
}

// newDescriptorTree returns a new DescriptorTree with its `hashSingle`
// field already computed.
// At this stage, dependencies have not been calculated yet, hence the
// `children` slice of the DescriptorTree is nil.
func newDescriptorTree(descr proto.Message) (*DescriptorTree, error) {
	dt := &DescriptorTree{descriptorNode: &descriptorNode{descr: descr}}

	if err := checkDescriptorType(descr); err != nil {
		return nil, errors.WithStack(err)
	}

	descrBytes, err := proto.Marshal(descr)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	hashSingle, err := ByteSSlice{descrBytes}.Hash()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	dt.hashSingle = hashSingle

	return dt, nil
}

// -----------------------------------------------------------------------------

// computeDependencyLinks appends the DependencyTrees of `dt`'s dependencies
// to its list of children.
//
// At this stage, the newly-appended dependencies are not guaranteed to have
// their own dependency-links already computed (i.e. their respective
// `children` lists are still nil), since their `computeDependencyLinks`
// might not have been called yet (the order in which each DescriptorTree
// gets its links computed is random).
// For that reason, recursive hashes cannot yet be computed here.
//
// This must be called before calling `computeRecursiveHash()`.
func (dt *DescriptorTree) computeDependencyLinks(
	dtsByName map[string]*DescriptorTree,
) error {
	switch descr := dt.descr.(type) {
	case *descriptor.DescriptorProto:
		for _, f := range descr.GetField() {
			// `typeName` is non-empty only if it references a Message or
			// Enum type
			if typeName := f.GetTypeName(); len(typeName) > 0 {
				child, ok := dtsByName[typeName]
				if !ok {
					return errors.Errorf("`%s`: no such type")
				}
				dt.children = append(dt.children, child)
			}
		}
	case *descriptor.EnumDescriptorProto:
		// nothing to do
	default:
		return errors.Errorf("`%v`: illegal type", reflect.TypeOf(descr))
	}
	return nil
}

// computeRecursiveHash recursively walks through `dt`'s dependencies
// in order to compute its recursive hash.
//
// `computeDependencyLinks()` must be called first for every available
// DescriptorTree.
func (dt *DescriptorTree) computeRecursiveHash() error {
	// used to avoid cyclic dependencies
	alreadyMet := make(map[*DescriptorTree]struct{}, len(dt.children))
	var recurseChildren func(dts []*DescriptorTree) (ByteSSlice, error)
	recurseChildren = func(dts []*DescriptorTree) (ByteSSlice, error) {
		singleHashes := make(ByteSSlice, 0, len(dts))
		for _, dt := range dts {
			if _, ok := alreadyMet[dt]; ok {
				continue
			}
			alreadyMet[dt] = struct{}{}
			singleHashesRec, err := recurseChildren(dt.children)
			if err != nil {
				return nil, errors.WithStack(err)
			}
			singleHashes = append(singleHashes, dt.hashSingle)
			singleHashes = append(singleHashes, singleHashesRec...)
		}
		return singleHashes, nil
	}

	singleHashes, err := recurseChildren(dt.children)
	if err != nil {
		return errors.WithStack(err)
	}
	hashRecursive, err := singleHashes.Hash()
	if err != nil {
		return errors.WithStack(err)
	}
	dt.hashRecursive = hashRecursive

	return nil
}

// -----------------------------------------------------------------------------

// collectDescriptorTypes recursively goes through all the FileDescriptorProtos
// that are passed to it in order to collect all of the Message, Enum & Nested
// types that can be found in these descriptors.
//
// The result is a flattened map of single-level (i.e. `children` is nil)
// DescriptorTrees arranged by the types' absolute names
// (e.g. `.google.protobuf.Timestamp`).
//
// This map is a necessary intermediate representation for computing the final
// dependency trees.
func collectDescriptorTypes(
	fdps map[string]*descriptor.FileDescriptorProto,
) (map[string]*DescriptorTree, error) {
	// Pre-allocating len(fdps)*3, assuming an average of 3 Message/Enum
	// types per file.
	// This mapping is arranged by the descriptors' respective name and is
	// a necessary intermediate representation for the final computation of
	// dependency trees.
	dtsByName := make(map[string]*DescriptorTree, len(fdps)*3)

	// recurse through a protoFile and pushes every Message/Enum/Nested
	// type to the `dtsByName` map
	var recurseMessages func(mt *descriptor.DescriptorProto, parent string) error
	recurseMessages = func(mt *descriptor.DescriptorProto, parent string) error {
		dt, err := newDescriptorTree(mt)
		if err != nil {
			return errors.WithStack(err)
		}
		parent += ("." + mt.GetName())
		dt.fqName = parent
		dtsByName[dt.fqName] = dt
		for _, et := range mt.GetEnumType() {
			dt, err := newDescriptorTree(et)
			if err != nil {
				return errors.WithStack(err)
			}
			dt.fqName = parent + "." + et.GetName()
			dtsByName[dt.fqName] = dt
		}
		for _, nmt := range mt.GetNestedType() {
			if err := recurseMessages(nmt, parent); err != nil {
				return errors.WithStack(err)
			}
		}
		return nil
	}

	// walk through the protoFiles
	for _, fdp := range fdps {
		parent := "." + fdp.GetPackage()
		for _, et := range fdp.GetEnumType() {
			dt, err := newDescriptorTree(et)
			if err != nil {
				return nil, errors.WithStack(err)
			}
			dt.fqName = parent + "." + et.GetName()
			dtsByName[dt.fqName] = dt
		}
		for _, mt := range fdp.GetMessageType() {
			if err := recurseMessages(mt, parent); err != nil {
				return nil, errors.WithStack(err)
			}
		}
	}

	return dtsByName, nil
}

// -----------------------------------------------------------------------------

func checkDescriptorType(descr proto.Message) error {
	switch descr.(type) {
	case *descriptor.DescriptorProto:
	case *descriptor.EnumDescriptorProto:
	default:
		return errors.Errorf("`%v`: illegal type", reflect.TypeOf(descr))
	}
	return nil
}
<|endoftext|>


<commit_before>package ns1

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"gopkg.in/ns1/ns1-go.v2/rest"
	"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
	"gopkg.in/ns1/ns1-go.v2/rest/model/filter"

	"github.com/StackExchange/dnscontrol/v3/models"
	"github.com/StackExchange/dnscontrol/v3/pkg/diff"
	"github.com/StackExchange/dnscontrol/v3/providers"
)

var docNotes = providers.DocumentationNotes{
	providers.CanUseAlias:            providers.Can(),
	providers.CanUsePTR:              providers.Can(),
	providers.DocCreateDomains:       providers.Cannot(),
	providers.DocOfficiallySupported: providers.Cannot(),
	providers.DocDualHost:            providers.Can(),
}

func init() {
	fns := providers.DspFuncs{
		Initializer:   newProvider,
		RecordAuditor: AuditRecords,
	}
	providers.RegisterDomainServiceProviderType("NS1", fns, providers.CanUseSRV, docNotes)
	providers.RegisterCustomRecordType("NS1_URLFWD", "NS1", "URLFWD")
}

type nsone struct {
	*rest.Client
}

func newProvider(creds map[string]string, meta json.RawMessage) (providers.DNSServiceProvider, error) {
	if creds["api_token"] == "" {
		return nil, fmt.Errorf("api_token required for ns1")
	}
	return &nsone{rest.NewClient(http.DefaultClient, rest.SetAPIKey(creds["api_token"]))}, nil
}

func (n *nsone) GetNameservers(domain string) ([]*models.Nameserver, error) {
	z, _, err := n.Zones.Get(domain)
	if err != nil {
		return nil, err
	}
	return models.ToNameservers(z.DNSServers)
}

// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
func (n *nsone) GetZoneRecords(domain string) (models.Records, error) {
	return nil, fmt.Errorf("not implemented")
	// This enables the get-zones subcommand.
	// Implement this by extracting the code from GetDomainCorrections into
	// a single function.  For most providers this should be relatively easy.
}

func (n *nsone) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
	dc.Punycode()
	//dc.CombineMXs()
	z, _, err := n.Zones.Get(dc.Name)
	if err != nil {
		return nil, err
	}

	found := models.Records{}
	for _, r := range z.Records {
		zrs, err := convert(r, dc.Name)
		if err != nil {
			return nil, err
		}
		found = append(found, zrs...)
	}
	foundGrouped := found.GroupedByKey()
	desiredGrouped := dc.Records.GroupedByKey()

	//  Normalize
	models.PostProcessRecords(found)

	differ := diff.New(dc)
	changedGroups, err := differ.ChangedGroups(found)
	if err != nil {
		return nil, err
	}
	corrections := []*models.Correction{}
	// each name/type is given to the api as a unit.
	for k, descs := range changedGroups {
		key := k
		desc := strings.Join(descs, "\n")
		_, current := foundGrouped[k]
		recs, wanted := desiredGrouped[k]
		if wanted && !current {
			// pure addition
			corrections = append(corrections, &models.Correction{
				Msg: desc,
				F:   func() error { return n.add(recs, dc.Name) },
			})
		} else if current && !wanted {
			// pure deletion
			corrections = append(corrections, &models.Correction{
				Msg: desc,
				F:   func() error { return n.remove(key, dc.Name) },
			})
		} else {
			// modification
			corrections = append(corrections, &models.Correction{
				Msg: desc,
				F:   func() error { return n.modify(recs, dc.Name) },
			})
		}
	}
	return corrections, nil
}

func (n *nsone) add(recs models.Records, domain string) error {
	_, err := n.Records.Create(buildRecord(recs, domain, ""))
	return err
}

func (n *nsone) remove(key models.RecordKey, domain string) error {
	_, err := n.Records.Delete(domain, key.NameFQDN, key.Type)
	return err
}

func (n *nsone) modify(recs models.Records, domain string) error {
	_, err := n.Records.Update(buildRecord(recs, domain, ""))
	return err
}

func buildRecord(recs models.Records, domain string, id string) *dns.Record {
	r := recs[0]
	rec := &dns.Record{
		Domain:  r.GetLabelFQDN(),
		Type:    r.Type,
		ID:      id,
		TTL:     int(r.TTL),
		Zone:    domain,
		Filters: []*filter.Filter{}, // Work through a bug in the NS1 API library that causes 400 Input validation failed (Value None for field '<obj>.filters' is not of type array)
	}
	for _, r := range recs {
		if r.Type == "MX" {
			rec.AddAnswer(&dns.Answer{Rdata: strings.Split(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()), " ")})
		} else if r.Type == "TXT" {
			rec.AddAnswer(&dns.Answer{Rdata: r.TxtStrings})
		} else if r.Type == "SRV" {
			rec.AddAnswer(&dns.Answer{Rdata: strings.Split(fmt.Sprintf("%d %d %d %v", r.SrvPriority, r.SrvWeight, r.SrvPort, r.GetTargetField()), " ")})
		} else {
			rec.AddAnswer(&dns.Answer{Rdata: strings.Split(r.GetTargetField(), " ")})
		}
	}
	return rec
}

func convert(zr *dns.ZoneRecord, domain string) ([]*models.RecordConfig, error) {
	found := []*models.RecordConfig{}
	for _, ans := range zr.ShortAns {
		rec := &models.RecordConfig{
			TTL:      uint32(zr.TTL),
			Original: zr,
		}
		rec.SetLabelFromFQDN(zr.Domain, domain)
		switch rtype := zr.Type; rtype {
		case "ALIAS":
		case "URLFWD":
			rec.Type = rtype
			if err := rec.SetTarget(ans); err != nil {
				panic(fmt.Errorf("unparsable %s record received from ns1: %w", rtype, err))
			}
		default:
			if err := rec.PopulateFromString(rtype, ans, domain); err != nil {
				panic(fmt.Errorf("unparsable record received from ns1: %w", err))
			}
		}
		found = append(found, rec)
	}
	return found, nil
}
<commit_msg>NS1: fix ALIAS handling (#1154)<commit_after>package ns1

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"gopkg.in/ns1/ns1-go.v2/rest"
	"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
	"gopkg.in/ns1/ns1-go.v2/rest/model/filter"

	"github.com/StackExchange/dnscontrol/v3/models"
	"github.com/StackExchange/dnscontrol/v3/pkg/diff"
	"github.com/StackExchange/dnscontrol/v3/providers"
)

var docNotes = providers.DocumentationNotes{
	providers.CanUseAlias:            providers.Can(),
	providers.CanUsePTR:              providers.Can(),
	providers.DocCreateDomains:       providers.Cannot(),
	providers.DocOfficiallySupported: providers.Cannot(),
	providers.DocDualHost:            providers.Can(),
}

func init() {
	fns := providers.DspFuncs{
		Initializer:   newProvider,
		RecordAuditor: AuditRecords,
	}
	providers.RegisterDomainServiceProviderType("NS1", fns, providers.CanUseSRV, docNotes)
	providers.RegisterCustomRecordType("NS1_URLFWD", "NS1", "URLFWD")
}

type nsone struct {
	*rest.Client
}

func newProvider(creds map[string]string, meta json.RawMessage) (providers.DNSServiceProvider, error) {
	if creds["api_token"] == "" {
		return nil, fmt.Errorf("api_token required for ns1")
	}
	return &nsone{rest.NewClient(http.DefaultClient, rest.SetAPIKey(creds["api_token"]))}, nil
}

func (n *nsone) GetNameservers(domain string) ([]*models.Nameserver, error) {
	z, _, err := n.Zones.Get(domain)
	if err != nil {
		return nil, err
	}
	return models.ToNameservers(z.DNSServers)
}

// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
func (n *nsone) GetZoneRecords(domain string) (models.Records, error) {
	return nil, fmt.Errorf("not implemented")
	// This enables the get-zones subcommand.
	// Implement this by extracting the code from GetDomainCorrections into
	// a single function.  For most providers this should be relatively easy.
}

func (n *nsone) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
	dc.Punycode()
	//dc.CombineMXs()
	z, _, err := n.Zones.Get(dc.Name)
	if err != nil {
		return nil, err
	}

	found := models.Records{}
	for _, r := range z.Records {
		zrs, err := convert(r, dc.Name)
		if err != nil {
			return nil, err
		}
		found = append(found, zrs...)
	}
	foundGrouped := found.GroupedByKey()
	desiredGrouped := dc.Records.GroupedByKey()

	//  Normalize
	models.PostProcessRecords(found)

	differ := diff.New(dc)
	changedGroups, err := differ.ChangedGroups(found)
	if err != nil {
		return nil, err
	}
	corrections := []*models.Correction{}
	// each name/type is given to the api as a unit.
	for k, descs := range changedGroups {
		key := k

		desc := strings.Join(descs, "\n")
		_, current := foundGrouped[k]
		recs, wanted := desiredGrouped[k]
		if wanted && !current {
			// pure addition
			corrections = append(corrections, &models.Correction{
				Msg: desc,
				F:   func() error { return n.add(recs, dc.Name) },
			})
		} else if current && !wanted {
			// pure deletion
			corrections = append(corrections, &models.Correction{
				Msg: desc,
				F:   func() error { return n.remove(key, dc.Name) },
			})
		} else {
			// modification
			corrections = append(corrections, &models.Correction{
				Msg: desc,
				F:   func() error { return n.modify(recs, dc.Name) },
			})
		}
	}
	return corrections, nil
}

func (n *nsone) add(recs models.Records, domain string) error {
	_, err := n.Records.Create(buildRecord(recs, domain, ""))
	return err
}

func (n *nsone) remove(key models.RecordKey, domain string) error {
	_, err := n.Records.Delete(domain, key.NameFQDN, key.Type)
	return err
}

func (n *nsone) modify(recs models.Records, domain string) error {
	_, err := n.Records.Update(buildRecord(recs, domain, ""))
	return err
}

func buildRecord(recs models.Records, domain string, id string) *dns.Record {
	r := recs[0]
	rec := &dns.Record{
		Domain:  r.GetLabelFQDN(),
		Type:    r.Type,
		ID:      id,
		TTL:     int(r.TTL),
		Zone:    domain,
		Filters: []*filter.Filter{}, // Work through a bug in the NS1 API library that causes 400 Input validation failed (Value None for field '<obj>.filters' is not of type array)
	}
	for _, r := range recs {
		if r.Type == "MX" {
			rec.AddAnswer(&dns.Answer{Rdata: strings.Split(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()), " ")})
		} else if r.Type == "TXT" {
			rec.AddAnswer(&dns.Answer{Rdata: r.TxtStrings})
		} else if r.Type == "SRV" {
			rec.AddAnswer(&dns.Answer{Rdata: strings.Split(fmt.Sprintf("%d %d %d %v", r.SrvPriority, r.SrvWeight, r.SrvPort, r.GetTargetField()), " ")})
		} else {
			rec.AddAnswer(&dns.Answer{Rdata: strings.Split(r.GetTargetField(), " ")})
		}
	}
	return rec
}

func convert(zr *dns.ZoneRecord, domain string) ([]*models.RecordConfig, error) {
	found := []*models.RecordConfig{}
	for _, ans := range zr.ShortAns {
		rec := &models.RecordConfig{
			TTL:      uint32(zr.TTL),
			Original: zr,
		}
		rec.SetLabelFromFQDN(zr.Domain, domain)
		switch rtype := zr.Type; rtype {
		case "ALIAS":
			rec.Type = rtype
			if err := rec.SetTarget(ans); err != nil {
				panic(fmt.Errorf("unparsable %s record received from ns1: %w", rtype, err))
			}
		case "URLFWD":
			rec.Type = rtype
			if err := rec.SetTarget(ans); err != nil {
				panic(fmt.Errorf("unparsable %s record received from ns1: %w", rtype, err))
			}
		default:
			if err := rec.PopulateFromString(rtype, ans, domain); err != nil {
				panic(fmt.Errorf("unparsable record received from ns1: %w", err))
			}
		}
		found = append(found, rec)
	}
	return found, nil
}
<|endoftext|>


<commit_before>package security

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"google.golang.org/grpc/credentials/tls/certprovider/pemfile"
	"google.golang.org/grpc/security/advancedtls"
	"io/ioutil"
	"strings"
	"time"

	grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/peer"
	"google.golang.org/grpc/status"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/util"
)

const credRefreshingInterval = 5 * time.Minute

type Authenticator struct {
	AllowedWildcardDomain string
	AllowedCommonNames    map[string]bool
}

func LoadServerTLS(config *util.ViperProxy, component string) (grpc.ServerOption, grpc.ServerOption) {
	if config == nil {
		return nil, nil
	}

	serverOptions := pemfile.Options{
		CertFile:        config.GetString(component + ".cert"),
		KeyFile:         config.GetString(component + ".key"),
		RefreshDuration: credRefreshingInterval,
	}

	serverIdentityProvider, err := pemfile.NewProvider(serverOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed: %v", serverOptions, err)
		return nil, nil
	}
	defer serverIdentityProvider.Close()

	serverRootOptions := pemfile.Options{
		RootFile:        config.GetString("grpc.ca"),
		RefreshDuration: credRefreshingInterval,
	}
	serverRootProvider, err := pemfile.NewProvider(serverRootOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed: %v", serverRootOptions, err)
		return nil, nil
	}
	defer serverIdentityProvider.Close()
	// Start a server and create a client using advancedtls API with Provider.
	options := &advancedtls.ServerOptions{
		IdentityOptions: advancedtls.IdentityCertificateOptions{
			IdentityProvider: serverIdentityProvider,
		},
		RootOptions: advancedtls.RootCertificateOptions{
			RootProvider: serverRootProvider,
		},
		RequireClientCert: true,
		VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) {
			glog.V(0).Infof("Client common name: %s.\n", params.Leaf.Subject.CommonName)
			return &advancedtls.VerificationResults{}, nil
		},
		VType: advancedtls.CertVerification,
	}
	ta, err := advancedtls.NewServerCreds(options)
	if err != nil {
		glog.Warningf("advancedtls.NewServerCreds(%v) failed: %v", options, err)
		return nil, nil
	}
	allowedCommonNames := config.GetString(component + ".allowed_commonNames")
	allowedWildcardDomain := config.GetString("grpc.allowed_wildcard_domain")
	if allowedCommonNames != "" || allowedWildcardDomain != "" {
		allowedCommonNamesMap := make(map[string]bool)
		for _, s := range strings.Split(allowedCommonNames, ",") {
			allowedCommonNamesMap[s] = true
		}
		auther := Authenticator{
			AllowedCommonNames:    allowedCommonNamesMap,
			AllowedWildcardDomain: allowedWildcardDomain,
		}
		return grpc.Creds(ta), grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(auther.Authenticate))
	}
	return grpc.Creds(ta), nil
}

func LoadClientTLS(config *util.ViperProxy, component string) grpc.DialOption {
	if config == nil {
		return grpc.WithInsecure()
	}

	certFileName, keyFileName, caFileName := config.GetString(component+".cert"), config.GetString(component+".key"), config.GetString("grpc.ca")
	if certFileName == "" || keyFileName == "" || caFileName == "" {
		return grpc.WithInsecure()
	}

	// Initialize credential struct using reloading API.
	clientOptions := pemfile.Options{
		CertFile:        certFileName,
		KeyFile:         keyFileName,
		RootFile:        caFileName,
		RefreshDuration: credRefreshingInterval,
	}
	clientProvider, err := pemfile.NewProvider(clientOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed %v", clientOptions, err)
		return grpc.WithInsecure()
	}
	defer clientProvider.Close()
	options := &advancedtls.ClientOptions{
		VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) {
			return &advancedtls.VerificationResults{}, nil
		},
		RootOptions: advancedtls.RootCertificateOptions{
			RootProvider: clientProvider,
		},
		VType: advancedtls.CertVerification,
	}
	ta, err := advancedtls.NewClientCreds(options)
	if err != nil {
		glog.Warningf("advancedtls.NewClientCreds(%v) failed: %v", options, err)
		return grpc.WithInsecure()
	}
	return grpc.WithTransportCredentials(ta)
}

func LoadClientTLSHTTP(clientCertFile string) *tls.Config {
	clientCerts, err := ioutil.ReadFile(clientCertFile)
	if err != nil {
		glog.Fatal(err)
	}
	certPool := x509.NewCertPool()
	ok := certPool.AppendCertsFromPEM(clientCerts)
	if !ok {
		glog.Fatalf("Error processing client certificate in %s\n", clientCertFile)
	}

	return &tls.Config{
		ClientCAs:  certPool,
		ClientAuth: tls.RequireAndVerifyClientCert,
	}
}

func (a Authenticator) Authenticate(ctx context.Context) (newCtx context.Context, err error) {
	p, ok := peer.FromContext(ctx)
	if !ok {
		return ctx, status.Error(codes.Unauthenticated, "no peer found")
	}

	tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo)
	if !ok {
		return ctx, status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
	}
	if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 {
		return ctx, status.Error(codes.Unauthenticated, "could not verify peer certificate")
	}

	commonName := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName
	if a.AllowedWildcardDomain != "" && strings.HasSuffix(commonName, a.AllowedWildcardDomain) {
		return ctx, nil
	}
	if _, ok := a.AllowedCommonNames[commonName]; ok {
		return ctx, nil
	}

	return ctx, status.Errorf(codes.Unauthenticated, "invalid subject common name: %s", commonName)
}
<commit_msg>seperate option<commit_after>package security

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"google.golang.org/grpc/credentials/tls/certprovider/pemfile"
	"google.golang.org/grpc/security/advancedtls"
	"io/ioutil"
	"strings"
	"time"

	grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/peer"
	"google.golang.org/grpc/status"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/util"
)

const credRefreshingInterval = time.Duration(5) * time.Hour

type Authenticator struct {
	AllowedWildcardDomain string
	AllowedCommonNames    map[string]bool
}

func LoadServerTLS(config *util.ViperProxy, component string) (grpc.ServerOption, grpc.ServerOption) {
	if config == nil {
		return nil, nil
	}

	serverOptions := pemfile.Options{
		CertFile:        config.GetString(component + ".cert"),
		KeyFile:         config.GetString(component + ".key"),
		RefreshDuration: credRefreshingInterval,
	}

	serverIdentityProvider, err := pemfile.NewProvider(serverOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed: %v", serverOptions, err)
		return nil, nil
	}
	defer serverIdentityProvider.Close()

	serverRootOptions := pemfile.Options{
		RootFile:        config.GetString("grpc.ca"),
		RefreshDuration: credRefreshingInterval,
	}
	serverRootProvider, err := pemfile.NewProvider(serverRootOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed: %v", serverRootOptions, err)
		return nil, nil
	}
	defer serverIdentityProvider.Close()
	// Start a server and create a client using advancedtls API with Provider.
	options := &advancedtls.ServerOptions{
		IdentityOptions: advancedtls.IdentityCertificateOptions{
			IdentityProvider: serverIdentityProvider,
		},
		RootOptions: advancedtls.RootCertificateOptions{
			RootProvider: serverRootProvider,
		},
		RequireClientCert: false,
		VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) {
			glog.V(0).Infof("Client common name: %s.\n", params.Leaf.Subject.CommonName)
			return &advancedtls.VerificationResults{}, nil
		},
		VType: advancedtls.SkipVerification,
	}
	ta, err := advancedtls.NewServerCreds(options)
	if err != nil {
		glog.Warningf("advancedtls.NewServerCreds(%v) failed: %v", options, err)
		return nil, nil
	}
	allowedCommonNames := config.GetString(component + ".allowed_commonNames")
	allowedWildcardDomain := config.GetString("grpc.allowed_wildcard_domain")
	if allowedCommonNames != "" || allowedWildcardDomain != "" {
		allowedCommonNamesMap := make(map[string]bool)
		for _, s := range strings.Split(allowedCommonNames, ",") {
			allowedCommonNamesMap[s] = true
		}
		auther := Authenticator{
			AllowedCommonNames:    allowedCommonNamesMap,
			AllowedWildcardDomain: allowedWildcardDomain,
		}
		return grpc.Creds(ta), grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(auther.Authenticate))
	}
	return grpc.Creds(ta), nil
}

func LoadClientTLS(config *util.ViperProxy, component string) grpc.DialOption {
	if config == nil {
		return grpc.WithInsecure()
	}

	certFileName, keyFileName, caFileName := config.GetString(component+".cert"), config.GetString(component+".key"), config.GetString("grpc.ca")
	if certFileName == "" || keyFileName == "" || caFileName == "" {
		return grpc.WithInsecure()
	}

	// Initialize credential struct using reloading API.
	clientOptions := pemfile.Options{
		CertFile:        certFileName,
		KeyFile:         keyFileName,
		RefreshDuration: credRefreshingInterval,
	}
	clientProvider, err := pemfile.NewProvider(clientOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed %v", clientOptions, err)
		return grpc.WithInsecure()
	}
	defer clientProvider.Close()
	clientRootOptions := pemfile.Options{
		RootFile:        config.GetString("grpc.ca"),
		RefreshDuration: credRefreshingInterval,
	}
	clientRootProvider, err := pemfile.NewProvider(clientRootOptions)
	if err != nil {
		glog.Warningf("pemfile.NewProvider(%v) failed: %v", clientRootOptions, err)
		return grpc.WithInsecure()
	}
	defer clientRootProvider.Close()
	options := &advancedtls.ClientOptions{
		IdentityOptions: advancedtls.IdentityCertificateOptions{
			IdentityProvider: clientProvider,
		},
		VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) {
			return &advancedtls.VerificationResults{}, nil
		},
		RootOptions: advancedtls.RootCertificateOptions{
			RootProvider: clientRootProvider,
		},
		VType: advancedtls.SkipVerification,
	}
	ta, err := advancedtls.NewClientCreds(options)
	if err != nil {
		glog.Warningf("advancedtls.NewClientCreds(%v) failed: %v", options, err)
		return grpc.WithInsecure()
	}
	return grpc.WithTransportCredentials(ta)
}

func LoadClientTLSHTTP(clientCertFile string) *tls.Config {
	clientCerts, err := ioutil.ReadFile(clientCertFile)
	if err != nil {
		glog.Fatal(err)
	}
	certPool := x509.NewCertPool()
	ok := certPool.AppendCertsFromPEM(clientCerts)
	if !ok {
		glog.Fatalf("Error processing client certificate in %s\n", clientCertFile)
	}

	return &tls.Config{
		ClientCAs:  certPool,
		ClientAuth: tls.RequireAndVerifyClientCert,
	}
}

func (a Authenticator) Authenticate(ctx context.Context) (newCtx context.Context, err error) {
	p, ok := peer.FromContext(ctx)
	if !ok {
		return ctx, status.Error(codes.Unauthenticated, "no peer found")
	}

	tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo)
	if !ok {
		return ctx, status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
	}
	if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 {
		return ctx, status.Error(codes.Unauthenticated, "could not verify peer certificate")
	}

	commonName := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName
	if a.AllowedWildcardDomain != "" && strings.HasSuffix(commonName, a.AllowedWildcardDomain) {
		return ctx, nil
	}
	if _, ok := a.AllowedCommonNames[commonName]; ok {
		return ctx, nil
	}

	return ctx, status.Errorf(codes.Unauthenticated, "invalid subject common name: %s", commonName)
}
<|endoftext|>


<commit_before>package sdk

/*
   Copyright 2016 Alexander I.Grafov <grafov@gmail.com>

   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.

   ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
)

// GetActualUser gets an actual user.
// Reflects GET /api/user API call.
func (r *Client) GetActualUser() (User, error) {
	var (
		raw  []byte
		user User
		code int
		err  error
	)
	if raw, code, err = r.get("api/user", nil); err != nil {
		return user, err
	}
	if code != 200 {
		return user, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&user); err != nil {
		return user, fmt.Errorf("unmarshal user: %s\n%s", err, raw)
	}
	return user, err
}

// GetUser gets an user by ID.
// Reflects GET /api/users/:id API call.
func (r *Client) GetUser(id uint) (User, error) {
	var (
		raw  []byte
		user User
		code int
		err  error
	)
	if raw, code, err = r.get(fmt.Sprintf("api/users/%d", id), nil); err != nil {
		return user, err
	}
	if code != 200 {
		return user, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&user); err != nil {
		return user, fmt.Errorf("unmarshal user: %s\n%s", err, raw)
	}
	return user, err
}

// GetAllUsers gets all users.
// Reflects GET /api/users API call.
func (r *Client) GetAllUsers() ([]User, error) {
	var (
		raw   []byte
		users []User
		code  int
		err   error
	)

	params := url.Values{}
	params.Set("perpage", "99999")
	if raw, code, err = r.get("api/users", params); err != nil {
		return users, err
	}
	if code != 200 {
		return users, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&users); err != nil {
		return users, fmt.Errorf("unmarshal users: %s\n%s", err, raw)
	}
	return users, err
}

// SearchUsersWithPaging search users with paging.
// query optional.  query value is contained in one of the name, login or email fields. Query values with spaces need to be url encoded e.g. query=Jane%20Doe
// perpage optional. default 1000
// page optional. default 1
// http://docs.grafana.org/http_api/user/#search-users
// http://docs.grafana.org/http_api/user/#search-users-with-paging
//
// Reflects GET /api/users/search API call.
func (r *Client) SearchUsersWithPaging(query *string, perpage, page *int) (PageUsers, error) {
	var (
		raw       []byte
		pageUsers PageUsers
		code      int
		err       error
	)

	var params url.Values = nil
	if perpage != nil && page != nil {
		if params == nil {
			params = url.Values{}
		}
		params["perpage"] = []string{string(*perpage)}
		params["page"] = []string{string(*page)}
	}

	if query != nil {
		if params == nil {
			params = url.Values{}
		}
		params["query"] = []string{*query}
	}

	if raw, code, err = r.get("api/users/search", params); err != nil {
		return pageUsers, err
	}
	if code != 200 {
		return pageUsers, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&pageUsers); err != nil {
		return pageUsers, fmt.Errorf("unmarshal users: %s\n%s", err, raw)
	}
	return pageUsers, err
}
<commit_msg>Do gofmt<commit_after>package sdk

/*
   Copyright 2016 Alexander I.Grafov <grafov@gmail.com>

   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.

   ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
)

// GetActualUser gets an actual user.
// Reflects GET /api/user API call.
func (r *Client) GetActualUser() (User, error) {
	var (
		raw  []byte
		user User
		code int
		err  error
	)
	if raw, code, err = r.get("api/user", nil); err != nil {
		return user, err
	}
	if code != 200 {
		return user, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&user); err != nil {
		return user, fmt.Errorf("unmarshal user: %s\n%s", err, raw)
	}
	return user, err
}

// GetUser gets an user by ID.
// Reflects GET /api/users/:id API call.
func (r *Client) GetUser(id uint) (User, error) {
	var (
		raw  []byte
		user User
		code int
		err  error
	)
	if raw, code, err = r.get(fmt.Sprintf("api/users/%d", id), nil); err != nil {
		return user, err
	}
	if code != 200 {
		return user, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&user); err != nil {
		return user, fmt.Errorf("unmarshal user: %s\n%s", err, raw)
	}
	return user, err
}

// GetAllUsers gets all users.
// Reflects GET /api/users API call.
func (r *Client) GetAllUsers() ([]User, error) {
	var (
		raw   []byte
		users []User
		code  int
		err   error
	)

	params := url.Values{}
	params.Set("perpage", "99999")
	if raw, code, err = r.get("api/users", params); err != nil {
		return users, err
	}
	if code != 200 {
		return users, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&users); err != nil {
		return users, fmt.Errorf("unmarshal users: %s\n%s", err, raw)
	}
	return users, err
}

// SearchUsersWithPaging search users with paging.
// query optional.  query value is contained in one of the name, login or email fields. Query values with spaces need to be url encoded e.g. query=Jane%20Doe
// perpage optional. default 1000
// page optional. default 1
// http://docs.grafana.org/http_api/user/#search-users
// http://docs.grafana.org/http_api/user/#search-users-with-paging
//
// Reflects GET /api/users/search API call.
func (r *Client) SearchUsersWithPaging(query *string, perpage, page *int) (PageUsers, error) {
	var (
		raw       []byte
		pageUsers PageUsers
		code      int
		err       error
	)

	var params url.Values = nil
	if perpage != nil && page != nil {
		if params == nil {
			params = url.Values{}
		}
		params["perpage"] = []string{string(*perpage)}
		params["page"] = []string{string(*page)}
	}

	if query != nil {
		if params == nil {
			params = url.Values{}
		}
		params["query"] = []string{*query}
	}

	if raw, code, err = r.get("api/users/search", params); err != nil {
		return pageUsers, err
	}
	if code != 200 {
		return pageUsers, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.UseNumber()
	if err := dec.Decode(&pageUsers); err != nil {
		return pageUsers, fmt.Errorf("unmarshal users: %s\n%s", err, raw)
	}
	return pageUsers, err
}
<|endoftext|>


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

// Package reuseport provides a function that returns a net.Listener powered by a net.FileListener with a SO_REUSEPORT option set to the socket.
package reuseport

import (
	"errors"
	"net"
	"os"
	"strconv"
	"syscall"
)

const (
	unsupportedProtoError = "Only tcp4 and tcp6 are supported"
	filePrefix            = "port."
)

// getSockaddr parses protocol and address and returns implementor syscall.Sockaddr: syscall.SockaddrInet4 or syscall.SockaddrInet6.
func getSockaddr(proto, addr string) (sa syscall.Sockaddr, soType int, err error) {
	var (
		addr4   [4]byte
		addr6   [16]byte
		tcpAddr *net.TCPAddr
		udpAddr *net.UDPAddr
	)

	if proto == "tcp" || proto == "tcp4" || proto == "tcp6" {
		tcpAddr, err = net.ResolveTCPAddr(proto, addr)
		if err != nil {
			return nil, -1, err
		}
	} else {
		udpAddr, err = net.ResolveUDPAddr(proto, addr)
		if err != nil {
			return nil, -1, err
		}
	}

	switch proto[len(proto)-1] {
	default:
		return nil, -1, errors.New(unsupportedProtoError)
	case "tcp":
	case "tcp4":
		if tcpAddr.IP != nil {
			copy(addr4[:], tcpAddr.IP[12:16]) // copy last 4 bytes of slice to array
		}
		return &syscall.SockaddrInet4{Port: tcpAddr.Port, Addr: addr4}, syscall.AF_INET, nil
	case "tcp6":
		if tcpAddr.IP != nil {
			copy(addr6[:], tcpAddr.IP) // copy all bytes of slice to array
		}
		return &syscall.SockaddrInet6{Port: tcpAddr.Port, Addr: addr6}, syscall.AF_INET6, nil
	case "udp":
	case "udp4":
		if tcpAddr.IP != nil {
			copy(addr4[:], tcpAddr.IP[12:16]) // copy last 4 bytes of slice to array
		}
		return &syscall.SockaddrInet4{Port: tcpAddr.Port, Addr: addr4}, syscall.AF_INET, nil
	case "udp6":
		if tcpAddr.IP != nil {
			copy(addr6[:], tcpAddr.IP) // copy all bytes of slice to array
		}
		return &syscall.SockaddrInet6{Port: tcpAddr.Port, Addr: addr6}, syscall.AF_INET6, nil
	}
}

// NewReusablePortListener returns net.FileListener that created from a file discriptor for a socket with SO_REUSEPORT option.
func NewReusablePortListener(proto, addr string) (l net.Listener, err error) {
	var (
		soType, fd int
		file       *os.File
		sockaddr   syscall.Sockaddr
	)

	if sockaddr, soType, err = getSockaddr(proto, addr); err != nil {
		return nil, err
	}

	if proto == "tcp" || proto == "tcp4" || proto == "tcp6" {
		if fd, err = syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); err != nil {
			return nil, err
		}
	} else {
		if fd, err = syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_UDP); err != nil {
			return nil, err
		}
	}

	if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, reusePort, 1); err != nil {
		return nil, err
	}

	if err = syscall.Bind(fd, sockaddr); err != nil {
		return nil, err
	}

	// Set backlog size to the maximum
	if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil {
		return nil, err
	}

	// File Name get be nil
	file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
	if l, err = net.FileListener(file); err != nil {
		return nil, err
	}

	if err = file.Close(); err != nil {
		return nil, err
	}

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

// Package reuseport provides a function that returns a net.Listener powered by a net.FileListener with a SO_REUSEPORT option set to the socket.
package reuseport

import (
	"errors"
	"net"
	"os"
	"strconv"
	"syscall"
)

const (
	unsupportedProtoError = "Only tcp4 and tcp6 are supported"
	filePrefix            = "port."
)

// getSockaddr parses protocol and address and returns implementor syscall.Sockaddr: syscall.SockaddrInet4 or syscall.SockaddrInet6.
func getSockaddr(proto, addr string) (sa syscall.Sockaddr, soType int, err error) {
	var (
		addr4   [4]byte
		addr6   [16]byte
		tcpAddr *net.TCPAddr
		udpAddr *net.UDPAddr
	)

	if proto == "tcp" || proto == "tcp4" || proto == "tcp6" {
		tcpAddr, err = net.ResolveTCPAddr(proto, addr)
		if err != nil {
			return nil, -1, err
		}
	} else {
		udpAddr, err = net.ResolveUDPAddr(proto, addr)
		if err != nil {
			return nil, -1, err
		}
	}

	switch proto {
	default:
		return nil, -1, errors.New(unsupportedProtoError)
	case "tcp":
	case "tcp4":
		if tcpAddr.IP != nil {
			copy(addr4[:], tcpAddr.IP[12:16]) // copy last 4 bytes of slice to array
		}
		return &syscall.SockaddrInet4{Port: tcpAddr.Port, Addr: addr4}, syscall.AF_INET, nil
	case "tcp6":
		if tcpAddr.IP != nil {
			copy(addr6[:], tcpAddr.IP) // copy all bytes of slice to array
		}
		return &syscall.SockaddrInet6{Port: tcpAddr.Port, Addr: addr6}, syscall.AF_INET6, nil
	case "udp":
	case "udp4":
		if tcpAddr.IP != nil {
			copy(addr4[:], tcpAddr.IP[12:16]) // copy last 4 bytes of slice to array
		}
		return &syscall.SockaddrInet4{Port: tcpAddr.Port, Addr: addr4}, syscall.AF_INET, nil
	case "udp6":
		if tcpAddr.IP != nil {
			copy(addr6[:], tcpAddr.IP) // copy all bytes of slice to array
		}
		return &syscall.SockaddrInet6{Port: tcpAddr.Port, Addr: addr6}, syscall.AF_INET6, nil
	}
}

// NewReusablePortListener returns net.FileListener that created from a file discriptor for a socket with SO_REUSEPORT option.
func NewReusablePortListener(proto, addr string) (l net.Listener, err error) {
	var (
		soType, fd int
		file       *os.File
		sockaddr   syscall.Sockaddr
	)

	if sockaddr, soType, err = getSockaddr(proto, addr); err != nil {
		return nil, err
	}

	if proto == "tcp" || proto == "tcp4" || proto == "tcp6" {
		if fd, err = syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); err != nil {
			return nil, err
		}
	} else {
		if fd, err = syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_UDP); err != nil {
			return nil, err
		}
	}

	if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, reusePort, 1); err != nil {
		return nil, err
	}

	if err = syscall.Bind(fd, sockaddr); err != nil {
		return nil, err
	}

	// Set backlog size to the maximum
	if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil {
		return nil, err
	}

	// File Name get be nil
	file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
	if l, err = net.FileListener(file); err != nil {
		return nil, err
	}

	if err = file.Close(); err != nil {
		return nil, err
	}

	return l, err
}
<|endoftext|>


<commit_before>package ring

import "testing"

type testNode struct {
	id uint64
}

func (n *testNode) NodeID() uint64 {
	return n.id
}

func (n *testNode) Active() bool {
	return true
}

func (n *testNode) Capacity() uint32 {
	return 1
}

func (n *testNode) TierValues() []int {
	return nil
}

func (n *testNode) Address() string {
	return ""
}

func TestRingVersion(t *testing.T) {
	v := (&ringImpl{version: 1}).Version()
	if v != 1 {
		t.Fatalf("Version() gave %d instead of 1", v)
	}
}

func TestRingPartitionBitCount(t *testing.T) {
	v := (&ringImpl{partitionBitCount: 1}).PartitionBitCount()
	if v != 1 {
		t.Fatalf("PartitionBitCount() gave %d instead of 1", v)
	}
}

func TestRingReplicaCount(t *testing.T) {
	v := (&ringImpl{replicaToPartitionToNodeIndex: make([][]int32, 3)}).ReplicaCount()
	if v != 3 {
		t.Fatalf("ReplicaCount() gave %d instead of 3", v)
	}
}

func TestRingNodes(t *testing.T) {
	v := (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Nodes()
	if len(v) != 2 {
		t.Fatalf("Nodes() gave %d entries instead of 2", len(v))
	}
	if v[0].NodeID() != 1 || v[1].NodeID() != 2 {
		t.Fatalf("Nodes() gave [%v, %v] instead of [&{1}, &{2}]", v[0], v[1])
	}
}

func TestRingNode(t *testing.T) {
	v := (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Node(1)
	if v.NodeID() != 1 {
		t.Fatalf("Nodes() gave %v instead of &{1}", v)
	}
	v = (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Node(2)
	if v.NodeID() != 2 {
		t.Fatalf("Nodes() gave %v instead of &{2}", v)
	}
	v = (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Node(3)
	if v != nil {
		t.Fatalf("Nodes() gave %v instead of nil", v)
	}
}

func TestRingLocalNode(t *testing.T) {
	v := (&ringImpl{localNodeIndex: -1}).LocalNode()
	if v != nil {
		t.Fatalf("LocalNode() gave %v instead of nil", v)
	}
	v = (&ringImpl{localNodeIndex: 0, nodes: []Node{&testNode{id: 123}, &testNode{456}, &testNode{789}}}).LocalNode()
	if v.NodeID() != 123 {
		t.Fatalf("LocalNode() gave %v instead of 0", v)
	}
	v = (&ringImpl{localNodeIndex: 1, nodes: []Node{&testNode{id: 123}, &testNode{id: 456}, &testNode{id: 789}}}).LocalNode()
	if v.NodeID() != 456 {
		t.Fatalf("LocalNode() gave %v instead of 0", v)
	}
}

func TestRingResponsible(t *testing.T) {
	v := (&ringImpl{localNodeIndex: -1}).Responsible(123)
	if v {
		t.Fatal("Responsible(123) gave true instead of false")
	}
	d := make([][]int32, 3)
	d[0] = []int32{0, 1, 2}
	d[1] = []int32{3, 4, 5}
	d[2] = []int32{6, 7, 8}
	v = (&ringImpl{localNodeIndex: 0, replicaToPartitionToNodeIndex: d}).Responsible(0)
	if !v {
		t.Fatal("Responsible(0) gave false instead of true")
	}
	v = (&ringImpl{localNodeIndex: 0, replicaToPartitionToNodeIndex: d}).Responsible(1)
	if v {
		t.Fatal("Responsible(1) gave true instead of false")
	}
}

func TestRingResponsibleIDs(t *testing.T) {
	d := make([][]int32, 3)
	d[0] = []int32{0, 1, 2}
	d[1] = []int32{3, 4, 5}
	d[2] = []int32{6, 7, 8}
	v := (&ringImpl{nodes: []Node{&testNode{id: 10}, &testNode{id: 11}, &testNode{id: 12}, &testNode{id: 13}, &testNode{id: 14}, &testNode{id: 15}, &testNode{id: 16}, &testNode{id: 17}, &testNode{id: 18}}, replicaToPartitionToNodeIndex: d}).ResponsibleNodes(0)
	if len(v) != 3 || v[0].NodeID() != 10 || v[1].NodeID() != 13 || v[2].NodeID() != 16 {
		t.Fatalf("ResponsibleNodes(0) gave %v instead of [10 13 16]", v)
	}
	v = (&ringImpl{nodes: []Node{&testNode{id: 10}, &testNode{id: 11}, &testNode{id: 12}, &testNode{id: 13}, &testNode{id: 14}, &testNode{id: 15}, &testNode{id: 16}, &testNode{id: 17}, &testNode{id: 18}}, replicaToPartitionToNodeIndex: d}).ResponsibleNodes(2)
	if len(v) != 3 || v[0].NodeID() != 12 || v[1].NodeID() != 15 || v[2].NodeID() != 18 {
		t.Fatalf("ResponsibleNodes(2) gave %v instead of [12 15 18]", v)
	}
}
<commit_msg>RingStats tests<commit_after>package ring

import "testing"

type testNode struct {
	id       uint64
	capacity uint32
	inactive bool
}

func (n *testNode) NodeID() uint64 {
	return n.id
}

func (n *testNode) Active() bool {
	return !n.inactive
}

func (n *testNode) Capacity() uint32 {
	return n.capacity
}

func (n *testNode) TierValues() []int {
	return nil
}

func (n *testNode) Address() string {
	return ""
}

func TestRingVersion(t *testing.T) {
	v := (&ringImpl{version: 1}).Version()
	if v != 1 {
		t.Fatalf("Version() gave %d instead of 1", v)
	}
}

func TestRingPartitionBitCount(t *testing.T) {
	v := (&ringImpl{partitionBitCount: 1}).PartitionBitCount()
	if v != 1 {
		t.Fatalf("PartitionBitCount() gave %d instead of 1", v)
	}
}

func TestRingReplicaCount(t *testing.T) {
	v := (&ringImpl{replicaToPartitionToNodeIndex: make([][]int32, 3)}).ReplicaCount()
	if v != 3 {
		t.Fatalf("ReplicaCount() gave %d instead of 3", v)
	}
}

func TestRingNodes(t *testing.T) {
	v := (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Nodes()
	if len(v) != 2 {
		t.Fatalf("Nodes() gave %d entries instead of 2", len(v))
	}
	if v[0].NodeID() != 1 || v[1].NodeID() != 2 {
		t.Fatalf("Nodes() gave [%v, %v] instead of [&{1}, &{2}]", v[0], v[1])
	}
}

func TestRingNode(t *testing.T) {
	v := (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Node(1)
	if v.NodeID() != 1 {
		t.Fatalf("Nodes() gave %v instead of &{1}", v)
	}
	v = (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Node(2)
	if v.NodeID() != 2 {
		t.Fatalf("Nodes() gave %v instead of &{2}", v)
	}
	v = (&ringImpl{nodes: []Node{&testNode{id: 1}, &testNode{id: 2}}}).Node(3)
	if v != nil {
		t.Fatalf("Nodes() gave %v instead of nil", v)
	}
}

func TestRingLocalNode(t *testing.T) {
	v := (&ringImpl{localNodeIndex: -1}).LocalNode()
	if v != nil {
		t.Fatalf("LocalNode() gave %v instead of nil", v)
	}
	v = (&ringImpl{localNodeIndex: 0, nodes: []Node{&testNode{id: 123}, &testNode{id: 456}, &testNode{id: 789}}}).LocalNode()
	if v.NodeID() != 123 {
		t.Fatalf("LocalNode() gave %v instead of 0", v)
	}
	v = (&ringImpl{localNodeIndex: 1, nodes: []Node{&testNode{id: 123}, &testNode{id: 456}, &testNode{id: 789}}}).LocalNode()
	if v.NodeID() != 456 {
		t.Fatalf("LocalNode() gave %v instead of 0", v)
	}
}

func TestRingResponsible(t *testing.T) {
	v := (&ringImpl{localNodeIndex: -1}).Responsible(123)
	if v {
		t.Fatal("Responsible(123) gave true instead of false")
	}
	d := make([][]int32, 3)
	d[0] = []int32{0, 1, 2}
	d[1] = []int32{3, 4, 5}
	d[2] = []int32{6, 7, 8}
	v = (&ringImpl{localNodeIndex: 0, replicaToPartitionToNodeIndex: d}).Responsible(0)
	if !v {
		t.Fatal("Responsible(0) gave false instead of true")
	}
	v = (&ringImpl{localNodeIndex: 0, replicaToPartitionToNodeIndex: d}).Responsible(1)
	if v {
		t.Fatal("Responsible(1) gave true instead of false")
	}
}

func TestRingResponsibleIDs(t *testing.T) {
	d := make([][]int32, 3)
	d[0] = []int32{0, 1, 2}
	d[1] = []int32{3, 4, 5}
	d[2] = []int32{6, 7, 8}
	v := (&ringImpl{nodes: []Node{&testNode{id: 10}, &testNode{id: 11}, &testNode{id: 12}, &testNode{id: 13}, &testNode{id: 14}, &testNode{id: 15}, &testNode{id: 16}, &testNode{id: 17}, &testNode{id: 18}}, replicaToPartitionToNodeIndex: d}).ResponsibleNodes(0)
	if len(v) != 3 || v[0].NodeID() != 10 || v[1].NodeID() != 13 || v[2].NodeID() != 16 {
		t.Fatalf("ResponsibleNodes(0) gave %v instead of [10 13 16]", v)
	}
	v = (&ringImpl{nodes: []Node{&testNode{id: 10}, &testNode{id: 11}, &testNode{id: 12}, &testNode{id: 13}, &testNode{id: 14}, &testNode{id: 15}, &testNode{id: 16}, &testNode{id: 17}, &testNode{id: 18}}, replicaToPartitionToNodeIndex: d}).ResponsibleNodes(2)
	if len(v) != 3 || v[0].NodeID() != 12 || v[1].NodeID() != 15 || v[2].NodeID() != 18 {
		t.Fatalf("ResponsibleNodes(2) gave %v instead of [12 15 18]", v)
	}
}

func TestRingStats(t *testing.T) {
	s := (&ringImpl{
		partitionBitCount: 2,
		nodes: []Node{
			&testNode{id: 0, capacity: 100},
			&testNode{id: 1, capacity: 101},
			&testNode{id: 2, capacity: 102},
			&testNode{id: 3, capacity: 103},
			&testNode{id: 4, capacity: 104},
			&testNode{id: 5, inactive: true},
		},
		replicaToPartitionToNodeIndex: [][]int32{
			[]int32{0, 1, 2, 3},
			[]int32{4, 0, 1, 2},
			[]int32{3, 4, 0, 1},
		},
	}).Stats()
	if s.ReplicaCount != 3 {
		t.Fatalf("RingStats gave ReplicaCount of %d instead of 3", s.ReplicaCount)
	}
	if s.NodeCount != 6 {
		t.Fatalf("RingStats gave NodeCount of %d instead of 6", s.NodeCount)
	}
	if s.InactiveNodeCount != 1 {
		t.Fatalf("RingStats gave InactiveNodeCount of %d instead of 1", s.InactiveNodeCount)
	}
	if s.PartitionBitCount != 2 {
		t.Fatalf("RingStats gave PartitionBitCount of %d instead of 2", s.PartitionBitCount)
	}
	if s.PartitionCount != 4 {
		t.Fatalf("RingStats gave PartitionCount of %d instead of 4", s.PartitionCount)
	}
	if s.TotalCapacity != 510 {
		t.Fatalf("RingStats gave TotalCapacity of %d instead of 510", s.TotalCapacity)
	}
	// Node id 4 should be most underweight.
	d := float64(104.0) / 510.0 * 4 * 3
	v := float64(100.0) * (d - 2) / d
	if s.MaxUnderNodePercentage != v {
		t.Fatalf("RingStats gave MaxUnderNodePercentage of %v instead of %v", s.MaxUnderNodePercentage, v)
	}
	// Node id 0 should be most overweight.
	d = float64(100.0) / 510.0 * 4 * 3
	v = float64(100.0) * (3 - d) / d
	if s.MaxOverNodePercentage != v {
		t.Fatalf("RingStats gave MaxOverNodePercentage of %v instead of %v", s.MaxOverNodePercentage, v)
	}
}
<|endoftext|>


<commit_before>package gocards

import "testing"

func TestNonDealers(t *testing.T) {
    players := []Player{ Player{Points:1},
        Player{Points:5},
        Player{Points:6},
        Player{Points:8},
        Player{Points:0},
    }

    room := NewRoom()
    room.SetPlayers(players)

    for i := 0; i < len(players); i++ {
        room.RotateDealer()

        for p := range room.NonDealers() {
            if p.Points == room.Dealer().Points {
                t.Errorf("Player should not be in dealers! %v", p)
            }
        }
    }

    room.SetPlayers([]Player{})

    for _ = range room.NonDealers() {
        t.Errorf("Should not be in here!")
    }

    room.SetPlayers([]Player{Player{Points:1}})

    for _ = range room.NonDealers() {
        t.Errorf("Should not be in here!")
    }
}<commit_msg>improving test suite<commit_after>package gocards

import "testing"

func TestNonDealers(t *testing.T) {
    players := []Player{ Player{Points:1},
        Player{Points:5},
        Player{Points:6},
        Player{Points:8},
        Player{Points:0},
    }

    room := NewRoom()
    room.SetPlayers(players)

    for i := 0; i < len(players); i++ {
        room.RotateDealer()

        for p := range room.NonDealers() {
            if p.Points == room.Dealer().Points {
                t.Errorf("Player should not be in dealers! %v", p)
            }
        }
    }

    room.SetPlayers([]Player{})

    for _ = range room.NonDealers() {
        t.Errorf("Should not be in here!")
    }

    room.SetPlayers([]Player{Player{Points:1}})

    for _ = range room.NonDealers() {
        t.Errorf("Should not be in here!")
    }
}

func TestRotateDealers(t *testing.T) {
    players := []Player{ Player{Points:1},
        Player{Points:2},
        Player{Points:3},
        Player{Points:4},
        Player{Points:5},
    }

    room := NewRoom()
    room.SetPlayers(players)

    if room.Dealer().Points != players[0].Points {
        t.Errorf("Incorrect dealer set as default")
    }

    room.RotateDealer()

    if room.Dealer().Points != players[1].Points {
        t.Errorf("Expected dealer with points %v, got dealer with points %v",
            players[1],
            room.Dealer().Points)
    }

}<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"

	"github.com/blevesearch/bleve"
)

func main() {

}

// Bleve example
func bleveExample() {
	// open a new index
	mapping := bleve.NewIndexMapping()
	index, err := bleve.New("example.bleve", mapping)
	if err != nil {
		fmt.Println(err)
		return
	}

	data := struct {
		Name string
	}{
		Name: "text",
	}

	// index some data
	index.Index("id", data)

	// search for some text
	query := bleve.NewMatchQuery("text")
	search := bleve.NewSearchRequest(query)
	searchResults, err := index.Search(search)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(searchResults)
}

// mgo example
type person struct {
	Name  string
	Phone string
}

func mgoExemple() {

	session, err := mgo.Dial("server1.example.com,server2.example.com")

	if err != nil {
		panic(err)
	}

	defer session.Close()

	// Optional. Switch the session to a monotonic behavior.
	session.SetMode(mgo.Monotonic, true)

	c := session.DB("test").C("people")

	err = c.Insert(
		&person{"Ale", "+55 53 8116 9639"},
		&person{"Cla", "+55 53 8402 8510"},
	)

	if err != nil {
		log.Fatal(err)
	}

	result := person{}
	err = c.Find(bson.M{"name": "Ale"}).One(&result)

	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Phone:", result.Phone)
}

type testDocument struct {
	Title string
	Note  string
}
<commit_msg>Remove MongoDB Example from main file<commit_after>package main

import (
	"fmt"

	"github.com/blevesearch/bleve"
)

func main() {

}

// Bleve example
func bleveExample() {
	// open a new index
	mapping := bleve.NewIndexMapping()
	index, err := bleve.New("example.bleve", mapping)
	if err != nil {
		fmt.Println(err)
		return
	}

	data := struct {
		Name string
	}{
		Name: "text",
	}

	// index some data
	index.Index("id", data)

	// search for some text
	query := bleve.NewMatchQuery("text")
	search := bleve.NewSearchRequest(query)
	searchResults, err := index.Search(search)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(searchResults)
}
<|endoftext|>


<commit_before>package rsrc

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/akavel/rsrc/binutil"
	"github.com/akavel/rsrc/coff"
	"github.com/akavel/rsrc/ico"
	"github.com/akavel/rsrc/internal"
)

// on storing icons, see: http://blogs.msdn.com/b/oldnewthing/archive/2012/07/20/10331787.aspx
type _GRPICONDIR struct {
	ico.ICONDIR
	Entries []_GRPICONDIRENTRY
}

func (group _GRPICONDIR) Size() int64 {
	return int64(binary.Size(group.ICONDIR) + len(group.Entries)*binary.Size(group.Entries[0]))
}

func (group _GRPICONDIR) AlignedSize() int64 {
	return binutil.Align(group.Size())
}

type _GRPICONDIRENTRY struct {
	ico.IconDirEntryCommon
	Id uint16
}

func Embed(fnameout, arch, fnamein, fnameico string) error {
	lastid := uint16(0)
	newid := func() uint16 {
		lastid++
		return lastid
	}

	out := coff.NewRSRC()
	err := out.Arch(arch)
	if err != nil {
		return err
	}

	if fnamein != "" {
		manifest, err := binutil.SizedOpen(fnamein)
		if err != nil {
			return fmt.Errorf("rsrc: error opening manifest file '%s': %s", fnamein, err)
		}
		defer manifest.Close()

		id := newid()
		out.AddResource(coff.RT_MANIFEST, id, manifest)
		// TODO(akavel): reintroduce the Printlns in package main after Embed returns
		// fmt.Println("Manifest ID: ", id)
	}
	if fnameico != "" {
		for _, fnameicosingle := range strings.Split(fnameico, ",") {
			f, err := addIcon(out, fnameicosingle, newid)
			if err != nil {
				return err
			}
			defer f.Close()
		}
	}

	out.Freeze()

	return internal.Write(out, fnameout)
}

func addIcon(out *coff.Coff, fname string, newid func() uint16) (io.Closer, error) {
	f, err := os.Open(fname)
	if err != nil {
		return nil, err
	}

	icons, err := ico.DecodeHeaders(f)
	if err != nil {
		f.Close()
		return nil, err
	}

	if len(icons) > 0 {
		// RT_ICONs
		group := _GRPICONDIR{ICONDIR: ico.ICONDIR{
			Reserved: 0, // magic num.
			Type:     1, // magic num.
			Count:    uint16(len(icons)),
		}}
		for _, icon := range icons {
			id := newid()
			r := binutil.AlignedSectionReader{SectionReader: io.NewSectionReader(f, int64(icon.ImageOffset), int64(icon.BytesInRes))}
			out.AddResource(coff.RT_ICON, id, r)
			group.Entries = append(group.Entries, _GRPICONDIRENTRY{icon.IconDirEntryCommon, id})
		}
		id := newid()
		out.AddResource(coff.RT_GROUP_ICON, id, group)
		// TODO(akavel): reintroduce the Printlns in package main after Embed returns
		// fmt.Println("Icon ", fname, " ID: ", id)
	}

	return f, nil
}
<commit_msg>Update rsrc/rsrc.go<commit_after>package rsrc

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/akavel/rsrc/binutil"
	"github.com/akavel/rsrc/coff"
	"github.com/akavel/rsrc/ico"
	"github.com/akavel/rsrc/internal"
)

// on storing icons, see: http://blogs.msdn.com/b/oldnewthing/archive/2012/07/20/10331787.aspx
type _GRPICONDIR struct {
	ico.ICONDIR
	Entries []_GRPICONDIRENTRY
}

func (group _GRPICONDIR) Size() int64 {
	return int64(binary.Size(group.ICONDIR) + len(group.Entries)*binary.Size(group.Entries[0]))
}

func (group _GRPICONDIR) AlignedSize() int64 {
	return binutil.Align(group.Size())
}

type _GRPICONDIRENTRY struct {
	ico.IconDirEntryCommon
	Id uint16
}

func Embed(fnameout, arch, fnamein, fnameico string) error {
	lastid := uint16(0)
	newid := func() uint16 {
		lastid++
		return lastid
	}

	out := coff.NewRSRC()
	err := out.Arch(arch)
	if err != nil {
		return err
	}

	if fnamein != "" {
		manifest, err := binutil.SizedOpen(fnamein)
		if err != nil {
			return fmt.Errorf("rsrc: error opening manifest file '%s': %s", fnamein, err)
		}
		defer manifest.Close()

		id := newid()
		out.AddResource(coff.RT_MANIFEST, id, manifest)
		// TODO(akavel): reintroduce the Printlns in package main after Embed returns
		// fmt.Println("Manifest ID: ", id)
	}
	if fnameico != "" {
		for _, fnameicosingle := range strings.Split(fnameico, ",") {
			f, err := addIcon(out, fnameicosingle, newid)
			if err != nil {
				return err
			}
			defer f.Close()
		}
	}

	out.Freeze()

	return internal.Write(out, fnameout)
}

func addIcon(out *coff.Coff, fname string, newid func() uint16) (io.Closer, error) {
	f, err := os.Open(fname)
	if err != nil {
		return nil, err
	}

	icons, err := ico.DecodeHeaders(f)
	if err != nil {
		f.Close()
		return nil, err
	}

	if len(icons) > 0 {
		// RT_ICONs
		group := _GRPICONDIR{ICONDIR: ico.ICONDIR{
			Reserved: 0, // magic num.
			Type:     1, // magic num.
			Count:    uint16(len(icons)),
		}}
		for _, icon := range icons {
			id := newid()
			r := binutil.AlignedSectionReader{io.NewSectionReader(f, int64(icon.ImageOffset), int64(icon.BytesInRes))}
			out.AddResource(coff.RT_ICON, id, r)
			group.Entries = append(group.Entries, _GRPICONDIRENTRY{icon.IconDirEntryCommon, id})
		}
		id := newid()
		out.AddResource(coff.RT_GROUP_ICON, id, group)
		// TODO(akavel): reintroduce the Printlns in package main after Embed returns
		// fmt.Println("Icon ", fname, " ID: ", id)
	}

	return f, nil
}
<|endoftext|>