<commit_before>// Package arp implements an ARP client and server, as described in RFC 826.
package arp

import (
	"encoding/binary"
	"errors"
	"io"
	"net"

	"github.com/mdlayher/ethernet"
)

//go:generate stringer -output=string.go -type=Operation

var (
	// ErrInvalidMAC is returned when one or more invalid MAC addresses are
	// passed to NewPacket.
	ErrInvalidMAC = errors.New("invalid MAC address")

	// ErrInvalidIP is returned when one or more invalid IPv4 addresses are
	// passed to NewPacket.
	ErrInvalidIP = errors.New("invalid IPv4 address")
)

// An Operation is an ARP operation, such as request or reply.
type Operation uint16

// Operation constants which indicate an ARP request or reply.
const (
	OperationRequest Operation = 1
	OperationReply   Operation = 2
)

// A Packet is a raw ARP packet, as described in RFC 826.
type Packet struct {
	// HardwareType specifies an IANA-assigned hardware type, as described
	// in RFC 826.
	HardwareType uint16

	// ProtocolType specifies the internetwork protocol for which the ARP
	// request is intended.  Typically, this is the IPv4 EtherType.
	ProtocolType uint16

	// MACLength specifies the length of the sender and target MAC addresses
	// included in a Packet.
	MACLength uint8

	// IPLength specifies the length of the sender and target IPv4 addresses
	// included in a Packet.
	IPLength uint8

	// Operation specifies the ARP operation being performed, such as request
	// or reply.
	Operation Operation

	// SenderMAC specifies the MAC address of the sender of this Packet.
	SenderMAC net.HardwareAddr

	// SenderIP specifies the IPv4 address of the sender of this Packet.
	SenderIP net.IP

	// TargetMAC specifies the MAC address of the target of this Packet.
	TargetMAC net.HardwareAddr

	// TargetIP specifies the IPv4 address of the target of this Packet.
	TargetIP net.IP
}

// NewPacket creates a new Packet from an input Operation and MAC/IPv4 address
// values for both a sender and target.
//
// If either MAC address is less than 6 bytes in length, or there is a length
// mismatch between the two, ErrInvalidMAC is returned.
//
// If either IP address is not an IPv4 address, or there is a length mismatch
// between the two, ErrInvalidIP is returned.
func NewPacket(op Operation, srcMAC net.HardwareAddr, srcIP net.IP, dstMAC net.HardwareAddr, dstIP net.IP) (*Packet, error) {
	// Validate MAC addresses for minimum length, and matching length
	if len(srcMAC) < 6 {
		return nil, ErrInvalidMAC
	}
	if len(dstMAC) < 6 {
		return nil, ErrInvalidMAC
	}
	if len(srcMAC) != len(dstMAC) {
		return nil, ErrInvalidMAC
	}

	// Validate IP addresses to ensure they are IPv4 addresses, and
	// correct length
	srcIP = srcIP.To4()
	if srcIP == nil {
		return nil, ErrInvalidIP
	}
	dstIP = dstIP.To4()
	if dstIP == nil {
		return nil, ErrInvalidIP
	}
	if len(srcIP) != len(dstIP) {
		return nil, ErrInvalidIP
	}

	return &Packet{
		// There is no Go-native way to detect hardware type of a network
		// interface, so default to 1 (ethernet 10Mb) for now
		HardwareType: 1,

		// Default to EtherType for IPv4
		ProtocolType: uint16(ethernet.EtherTypeIPv4),

		// Populate other fields using input data
		MACLength: uint8(len(srcMAC)),
		IPLength:  uint8(len(srcIP)),
		Operation: op,
		SenderMAC: srcMAC,
		SenderIP:  srcIP,
		TargetMAC: dstMAC,
		TargetIP:  dstIP,
	}, nil
}

// MarshalBinary allocates a byte slice containing the data from a Packet.
//
// MarshalBinary never returns an error.
func (p *Packet) MarshalBinary() ([]byte, error) {
	// 2 bytes: hardware type
	// 2 bytes: protocol type
	// 1 byte : hardware address length
	// 1 byte : protocol length
	// 2 bytes: operation
	// N bytes: source hardware address
	// 4 bytes: source protocol address
	// N bytes: target hardware address
	// 4 bytes: target protocol address
	b := make([]byte, 2+2+1+1+2+4+4+(p.MACLength*2))

	// Marshal fixed length data

	binary.BigEndian.PutUint16(b[0:2], p.HardwareType)
	binary.BigEndian.PutUint16(b[2:4], p.ProtocolType)

	b[4] = p.MACLength
	b[5] = p.IPLength

	binary.BigEndian.PutUint16(b[6:8], uint16(p.Operation))

	// Marshal variable length data at correct offset using lengths
	// defined in p

	n := 8
	hal := int(p.MACLength)
	pl := int(p.IPLength)

	copy(b[n:n+hal], p.SenderMAC)
	n += hal

	copy(b[n:n+pl], p.SenderIP)
	n += pl

	copy(b[n:n+hal], p.TargetMAC)
	n += hal

	copy(b[n:n+pl], p.TargetIP)

	return b, nil
}

// UnmarshalBinary unmarshals a raw byte slice into a Packet.
func (p *Packet) UnmarshalBinary(b []byte) error {
	// Must have enough room to retrieve MAC and IP lengths
	if len(b) < 8 {
		return io.ErrUnexpectedEOF
	}

	// Retrieve fixed length data

	p.HardwareType = binary.BigEndian.Uint16(b[0:2])
	p.ProtocolType = binary.BigEndian.Uint16(b[2:4])

	p.MACLength = b[4]
	p.IPLength = b[5]

	p.Operation = Operation(binary.BigEndian.Uint16(b[6:8]))

	// Unmarshal variable length data at correct offset using lengths
	// defined by ml and il
	n := 8
	ml := int(p.MACLength)
	il := int(p.IPLength)

	// Must have enough room to retrieve both MAC and IP addresses
	if len(b) < 8+(2*ml)+(2*il) {
		return io.ErrUnexpectedEOF
	}

	sha := make(net.HardwareAddr, ml)
	copy(sha, b[n:n+ml])
	p.SenderMAC = sha
	n += ml

	spa := make(net.IP, il)
	copy(spa, b[n:n+il])
	p.SenderIP = spa
	n += il

	tha := make(net.HardwareAddr, ml)
	copy(tha, b[n:n+ml])
	p.TargetMAC = tha
	n += ml

	tpa := make(net.IP, il)
	copy(tpa, b[n:n+il])
	p.TargetIP = tpa

	return nil
}
<commit_msg>arp: remove unreachable error<commit_after>// Package arp implements an ARP client and server, as described in RFC 826.
package arp

import (
	"encoding/binary"
	"errors"
	"io"
	"net"

	"github.com/mdlayher/ethernet"
)

//go:generate stringer -output=string.go -type=Operation

var (
	// ErrInvalidMAC is returned when one or more invalid MAC addresses are
	// passed to NewPacket.
	ErrInvalidMAC = errors.New("invalid MAC address")

	// ErrInvalidIP is returned when one or more invalid IPv4 addresses are
	// passed to NewPacket.
	ErrInvalidIP = errors.New("invalid IPv4 address")
)

// An Operation is an ARP operation, such as request or reply.
type Operation uint16

// Operation constants which indicate an ARP request or reply.
const (
	OperationRequest Operation = 1
	OperationReply   Operation = 2
)

// A Packet is a raw ARP packet, as described in RFC 826.
type Packet struct {
	// HardwareType specifies an IANA-assigned hardware type, as described
	// in RFC 826.
	HardwareType uint16

	// ProtocolType specifies the internetwork protocol for which the ARP
	// request is intended.  Typically, this is the IPv4 EtherType.
	ProtocolType uint16

	// MACLength specifies the length of the sender and target MAC addresses
	// included in a Packet.
	MACLength uint8

	// IPLength specifies the length of the sender and target IPv4 addresses
	// included in a Packet.
	IPLength uint8

	// Operation specifies the ARP operation being performed, such as request
	// or reply.
	Operation Operation

	// SenderMAC specifies the MAC address of the sender of this Packet.
	SenderMAC net.HardwareAddr

	// SenderIP specifies the IPv4 address of the sender of this Packet.
	SenderIP net.IP

	// TargetMAC specifies the MAC address of the target of this Packet.
	TargetMAC net.HardwareAddr

	// TargetIP specifies the IPv4 address of the target of this Packet.
	TargetIP net.IP
}

// NewPacket creates a new Packet from an input Operation and MAC/IPv4 address
// values for both a sender and target.
//
// If either MAC address is less than 6 bytes in length, or there is a length
// mismatch between the two, ErrInvalidMAC is returned.
//
// If either IP address is not an IPv4 address, or there is a length mismatch
// between the two, ErrInvalidIP is returned.
func NewPacket(op Operation, srcMAC net.HardwareAddr, srcIP net.IP, dstMAC net.HardwareAddr, dstIP net.IP) (*Packet, error) {
	// Validate MAC addresses for minimum length, and matching length
	if len(srcMAC) < 6 {
		return nil, ErrInvalidMAC
	}
	if len(dstMAC) < 6 {
		return nil, ErrInvalidMAC
	}
	if len(srcMAC) != len(dstMAC) {
		return nil, ErrInvalidMAC
	}

	// Validate IP addresses to ensure they are IPv4 addresses, and
	// correct length
	srcIP = srcIP.To4()
	if srcIP == nil {
		return nil, ErrInvalidIP
	}
	dstIP = dstIP.To4()
	if dstIP == nil {
		return nil, ErrInvalidIP
	}

	return &Packet{
		// There is no Go-native way to detect hardware type of a network
		// interface, so default to 1 (ethernet 10Mb) for now
		HardwareType: 1,

		// Default to EtherType for IPv4
		ProtocolType: uint16(ethernet.EtherTypeIPv4),

		// Populate other fields using input data
		MACLength: uint8(len(srcMAC)),
		IPLength:  uint8(len(srcIP)),
		Operation: op,
		SenderMAC: srcMAC,
		SenderIP:  srcIP,
		TargetMAC: dstMAC,
		TargetIP:  dstIP,
	}, nil
}

// MarshalBinary allocates a byte slice containing the data from a Packet.
//
// MarshalBinary never returns an error.
func (p *Packet) MarshalBinary() ([]byte, error) {
	// 2 bytes: hardware type
	// 2 bytes: protocol type
	// 1 byte : hardware address length
	// 1 byte : protocol length
	// 2 bytes: operation
	// N bytes: source hardware address
	// 4 bytes: source protocol address
	// N bytes: target hardware address
	// 4 bytes: target protocol address
	b := make([]byte, 2+2+1+1+2+4+4+(p.MACLength*2))

	// Marshal fixed length data

	binary.BigEndian.PutUint16(b[0:2], p.HardwareType)
	binary.BigEndian.PutUint16(b[2:4], p.ProtocolType)

	b[4] = p.MACLength
	b[5] = p.IPLength

	binary.BigEndian.PutUint16(b[6:8], uint16(p.Operation))

	// Marshal variable length data at correct offset using lengths
	// defined in p

	n := 8
	hal := int(p.MACLength)
	pl := int(p.IPLength)

	copy(b[n:n+hal], p.SenderMAC)
	n += hal

	copy(b[n:n+pl], p.SenderIP)
	n += pl

	copy(b[n:n+hal], p.TargetMAC)
	n += hal

	copy(b[n:n+pl], p.TargetIP)

	return b, nil
}

// UnmarshalBinary unmarshals a raw byte slice into a Packet.
func (p *Packet) UnmarshalBinary(b []byte) error {
	// Must have enough room to retrieve MAC and IP lengths
	if len(b) < 8 {
		return io.ErrUnexpectedEOF
	}

	// Retrieve fixed length data

	p.HardwareType = binary.BigEndian.Uint16(b[0:2])
	p.ProtocolType = binary.BigEndian.Uint16(b[2:4])

	p.MACLength = b[4]
	p.IPLength = b[5]

	p.Operation = Operation(binary.BigEndian.Uint16(b[6:8]))

	// Unmarshal variable length data at correct offset using lengths
	// defined by ml and il
	n := 8
	ml := int(p.MACLength)
	il := int(p.IPLength)

	// Must have enough room to retrieve both MAC and IP addresses
	if len(b) < 8+(2*ml)+(2*il) {
		return io.ErrUnexpectedEOF
	}

	sha := make(net.HardwareAddr, ml)
	copy(sha, b[n:n+ml])
	p.SenderMAC = sha
	n += ml

	spa := make(net.IP, il)
	copy(spa, b[n:n+il])
	p.SenderIP = spa
	n += il

	tha := make(net.HardwareAddr, ml)
	copy(tha, b[n:n+ml])
	p.TargetMAC = tha
	n += ml

	tpa := make(net.IP, il)
	copy(tpa, b[n:n+il])
	p.TargetIP = tpa

	return nil
}
<|endoftext|>


<commit_before>package chainlib

import (
	"flag"
	"fmt"
	"os"
	"strings"
)

func assert(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

// Convenience function for writing utilities which use Bernstein chaining to
// pass environment variables. Function f should perform logic to retrieve data
// to be serialized to environment variables and return them as a map of strings,
// or error if something went wrong.
func Main(prefix string, f func() (map[string]string, error)) {
	var upcase bool
	var rprefix string
	flag.StringVar(&rprefix, "prefix", prefix, "Prefix")
	flag.BoolVar(&upcase, "upcase", true, "Upcase variables")
	flag.Parse()

	env, err := f()
	assert(err)
	var menv []string
	for k, v := range env {
		key := SafeEnv(k)
		if upcase {
			key = strings.ToUpper(key)
		}
		menv = append(menv, fmt.Sprintf("%s_%s=%s", rprefix, key, v))
	}
	assert(Exec(flag.Args(), menv))
}
<commit_msg>Permit empty prefix<commit_after>package chainlib

import (
	"flag"
	"fmt"
	"os"
	"strings"
)

func assert(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

// Convenience function for writing utilities which use Bernstein chaining to
// pass environment variables. Function f should perform logic to retrieve data
// to be serialized to environment variables and return them as a map of strings,
// or error if something went wrong.
func Main(prefix string, f func() (map[string]string, error)) {
	var upcase bool
	var rprefix string
	flag.StringVar(&rprefix, "prefix", prefix, "Prefix")
	flag.BoolVar(&upcase, "upcase", true, "Upcase variables")
	flag.Parse()

	env, err := f()
	assert(err)
	var menv []string
	for k, v := range env {
		key := SafeEnv(k)
		if upcase {
			key = strings.ToUpper(key)
		}
		envvar := fmt.Sprintf("%s=%s", key, v)
		if rprefix != "" {
			envvar = fmt.Sprintf("%s_%s", rprefix, key)
		}
		menv = append(menv, envvar)
	}
	assert(Exec(flag.Args(), menv))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"
)

type Bot struct {
	Server         string
	ssl            bool
	Conn           net.Conn
	Reader         *bufio.Reader
	plugins        []*Plugin
	mutex          *sync.Mutex
	reconnectMutex *sync.Mutex
	pluginsMutex   *sync.Mutex
	toConn         chan string
	toStderr       chan string
}

func dispatcher(bot *Bot, line string) {
	logIn.Print(line)

	bot.pluginsMutex.Lock()
	for _, plugin := range bot.plugins {
		if plugin != nil {
			fmt.Fprintln(plugin.stdin, line)
		}
	}
	bot.pluginsMutex.Unlock()
}

func (bot *Bot) connect() error {
	if bot.ssl {
		conn, err := tls.Dial("tcp", bot.Server, nil)
		if err != nil {
			return err
		}
		bot.Conn = conn
		bot.Reader = bufio.NewReader(conn)
	} else {
		conn, err := net.Dial("tcp", bot.Server)
		if err != nil {
			return err
		}
		bot.Conn = conn
		bot.Reader = bufio.NewReader(conn)
	}
	return nil
}
func (bot *Bot) disconnect() error {
	bot.Reader = nil
	bot.Conn.Close()
	return nil
}

var reconnecting bool = false

func (bot *Bot) reconnect() {
	if reconnecting {
		// already reconnecting, just wait
		bot.reconnectMutex.Lock()
		bot.reconnectMutex.Unlock()
		return
	}

	bot.reconnectMutex.Lock()
	reconnecting = true
	log.Println("reconnecting...")
	bot.disconnect()
	delay := 2 * time.Second
	for {
		err := bot.connect()
		if err == nil {
			break
		}
		logErr.Println(err)
		log.Printf("Reconnecting in %s seconds...\n", delay)
		time.Sleep(delay)
		delay = delay * 2
	}
	reconnecting = false
	bot.reconnectMutex.Unlock()
}

var logErr *log.Logger
var logIn *log.Logger
var logOut *log.Logger

func (bot *Bot) consume() {
	defer wg.Done()
	for {
		select {
		case line := <-bot.toConn:
			bot.mutex.Lock()
			fmt.Fprint(bot.Conn, line)

			// Do not output passwords
			if !strings.Contains(line, "PRIVMSG Nickserv :identify") {
				logOut.Print(line)
			}

			bot.mutex.Unlock()
		case line := <-bot.toStderr:
			logErr.Print(line)
		}
	}
}

func main() {
	logErr = log.New(os.Stderr, "!!! ", log.LstdFlags)
	logOut = log.New(os.Stdout, "--> ", log.LstdFlags)
	logIn = log.New(os.Stdout, "<-- ", log.LstdFlags)
	log.SetPrefix("iii ")
	server := flag.String("server", "chat.freenode.net:6667", "IRC server address to connect to")
	ssl := flag.Bool("ssl", false, "use SSL")
	flag.Parse()

	bot := &Bot{
		Server:         *server,
		ssl:            *ssl,
		mutex:          &sync.Mutex{},
		reconnectMutex: &sync.Mutex{},
		pluginsMutex:   &sync.Mutex{},
	}
	bot.toConn = make(chan string)
	bot.toStderr = make(chan string)
	bot.connect()

	// consume chan toConn and toStderr
	go bot.consume()

	// signals
	sigs := make(chan os.Signal, 1)

	signal.Notify(sigs, syscall.SIGHUP, syscall.SIGUSR1)
	go func() {
		for {
			sig := <-sigs
			switch sig {
			case os.Interrupt:
			case syscall.SIGHUP:
				fmt.Println("Signal HUP received")
				bot.reloadAllPlugins()
			case syscall.SIGUSR1:
				fmt.Println("Signal USR1 received")
				bot.reconnect()
			default:
				fmt.Println("unhandled signal")
			}
		}
	}()

	bot.LoadAllPlugins()

	// Stdin loop: allow user to chat with server directly
	// (useful for debugging)
	go func() {
		stdin := bufio.NewReader(os.Stdin)

		for {
			line, _ := stdin.ReadString('\n')
			bot.toConn <- line
		}

	}()

	// Main loop
	for {
		line, err := bot.Reader.ReadString('\n')
		if err != nil {
			bot.reconnect()
			fmt.Println(err)
			time.Sleep(2 * time.Second)
		} else {
			dispatcher(bot, line)
		}
	}
}
<commit_msg>Do not pass stdin by default (daemon mode openrc)<commit_after>package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"
)

type Bot struct {
	Server         string
	ssl            bool
	Conn           net.Conn
	Reader         *bufio.Reader
	plugins        []*Plugin
	mutex          *sync.Mutex
	reconnectMutex *sync.Mutex
	pluginsMutex   *sync.Mutex
	toConn         chan string
	toStderr       chan string
}

func dispatcher(bot *Bot, line string) {
	logIn.Print(line)

	bot.pluginsMutex.Lock()
	for _, plugin := range bot.plugins {
		if plugin != nil {
			fmt.Fprintln(plugin.stdin, line)
		}
	}
	bot.pluginsMutex.Unlock()
}

func (bot *Bot) connect() error {
	if bot.ssl {
		conn, err := tls.Dial("tcp", bot.Server, nil)
		if err != nil {
			return err
		}
		bot.Conn = conn
		bot.Reader = bufio.NewReader(conn)
	} else {
		conn, err := net.Dial("tcp", bot.Server)
		if err != nil {
			return err
		}
		bot.Conn = conn
		bot.Reader = bufio.NewReader(conn)
	}
	return nil
}
func (bot *Bot) disconnect() error {
	bot.Reader = nil
	bot.Conn.Close()
	return nil
}

var reconnecting bool = false

func (bot *Bot) reconnect() {
	if reconnecting {
		// already reconnecting, just wait
		bot.reconnectMutex.Lock()
		bot.reconnectMutex.Unlock()
		return
	}

	bot.reconnectMutex.Lock()
	reconnecting = true
	log.Println("reconnecting...")
	bot.disconnect()
	delay := 2 * time.Second
	for {
		err := bot.connect()
		if err == nil {
			break
		}
		logErr.Println(err)
		log.Printf("Reconnecting in %s seconds...\n", delay)
		time.Sleep(delay)
		delay = delay * 2
	}
	reconnecting = false
	bot.reconnectMutex.Unlock()
}

var logErr *log.Logger
var logIn *log.Logger
var logOut *log.Logger

func (bot *Bot) consume() {
	defer wg.Done()
	for {
		select {
		case line := <-bot.toConn:
			bot.mutex.Lock()
			fmt.Fprint(bot.Conn, line)

			// Do not output passwords
			if !strings.Contains(line, "PRIVMSG Nickserv :identify") {
				logOut.Print(line)
			}

			bot.mutex.Unlock()
		case line := <-bot.toStderr:
			logErr.Print(line)
		}
	}
}

func main() {
	logErr = log.New(os.Stderr, "!!! ", log.LstdFlags)
	logOut = log.New(os.Stdout, "--> ", log.LstdFlags)
	logIn = log.New(os.Stdout, "<-- ", log.LstdFlags)
	log.SetPrefix("iii ")
	server := flag.String("server", "chat.freenode.net:6667", "IRC server address to connect to")
	ssl := flag.Bool("ssl", false, "use SSL")
	interactive := flag.Bool("interactive", false, "pass stdin")
	flag.Parse()

	bot := &Bot{
		Server:         *server,
		ssl:            *ssl,
		mutex:          &sync.Mutex{},
		reconnectMutex: &sync.Mutex{},
		pluginsMutex:   &sync.Mutex{},
	}
	bot.toConn = make(chan string)
	bot.toStderr = make(chan string)
	bot.connect()

	// consume chan toConn and toStderr
	go bot.consume()

	// signals
	sigs := make(chan os.Signal, 1)

	signal.Notify(sigs, syscall.SIGHUP, syscall.SIGUSR1)
	go func() {
		for {
			sig := <-sigs
			switch sig {
			case os.Interrupt:
			case syscall.SIGHUP:
				fmt.Println("Signal HUP received")
				bot.reloadAllPlugins()
			case syscall.SIGUSR1:
				fmt.Println("Signal USR1 received")
				bot.reconnect()
			default:
				fmt.Println("unhandled signal")
			}
		}
	}()

	bot.LoadAllPlugins()

	// Stdin loop: allow user to chat with server directly
	// (useful for debugging)
	if *interactive {
		go func() {
			stdin := bufio.NewReader(os.Stdin)

			for {
				line, _ := stdin.ReadString('\n')
				bot.toConn <- line
			}

		}()
	}

	// Main loop
	for {
		line, err := bot.Reader.ReadString('\n')
		if err != nil {
			bot.reconnect()
			fmt.Println(err)
			time.Sleep(2 * time.Second)
		} else {
			dispatcher(bot, line)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Update control.go<commit_after><|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"io/ioutil"
	"strings"
)

func CDRConf(w http.ResponseWriter, r *http.Request) {
	var err string
	type JSONRequest struct {
		Server string
		Duname string
		Dpass string
		Dname string
		Ctab string
		Ckey string
	}

	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	dpath,_:=Shell("locate libmyodbc.so")
	spath,_:=Shell("locate libodbcmyS.so")
	result := JSONResult{true, 0, "", ""}

	w.Header().Add("Content-Type", "text/html")

	body, _ := ioutil.ReadAll(r.Body)
	var jrequest JSONRequest
	er := json.Unmarshal(body, &jrequest)
	if er != nil {
		result.Success = false
		result.Errorcode = 1
		result.Message = er.Error()
	} else {
		//set cdr configuration in configuration file
		if strings.Compare(dpath,"")!=0 {
			dpath=dpath[:len(dpath)-1]
			spath=spath[:len(spath)-1]
			msqlcont:="Description     = MySQL driver\nDriver          = "+
				dpath+" \nSetup           = "+spath
			err=addConfNode("/etc/odbcinst.ini","[Default]","Driver          = "+dpath)
			addConfNode("/etc/odbcinst.ini","[MySQL]",msqlcont)
			ser:=jrequest.Server
			duname:=jrequest.Duname
			dpass:=jrequest.Dpass
			dname:=jrequest.Dname
			cdrtab:=jrequest.Ctab
			cdrkey:=jrequest.Ckey
			astdsncont:="Driver          = MySQL\nDescription     = MySQL Connector for Asterisk\nServer          = "+
				ser+"\nPort            = 3306\nDatabase        = "+
				dname+"\nusername        = "+
				duname+"\npassword        = "+
				dpass+"\nOption          = 3\nSocket          = /var/run/mysqld/mysqld.sock"
			err=addConfNode("/etc/odbc.ini","[MySQL-asterisk]",astdsncont)
			backupFile("res_odbc.conf")
			rsodcont:="enabled=yes\ndsn=MySQL-asterisk\nusername="+
				duname+"\npassword="+
				dpass+"\npooling=no\nlimit=1\npre-connect=yes\nshare_connections=yes\nsanitysql=select 1\nisolation=repeatable_read"
			err=addConfNode("/etc/asterisk/res_odbc.conf","[asterisk]",rsodcont)
			backupFile("cdr_odbc.conf")
			cdrodbccont:="dsn=asterisk\nloguniqueid=yes\ntable=" +
				cdrtab+"\ndispositionstring=yes\nusegmtime=no\nhrtime=yes"
			err=addConfNode("/etc/asterisk/cdr_odbc.conf","[global]",cdrodbccont)
			backupFile("cdr_manager.conf")
			err=modifyConfNode("/etc/asterisk/cdr_manager.conf","[general]","enabled = yes")
			backupFile("cdr_adaptive_odbc.conf")
			cdradcont:="connection=asterisk\ntable="+
				cdrtab+"\nalias start="+
				cdrkey
			err=addConfNode("/etc/asterisk/cdr_adaptive_odbc.conf","[asteriskcdr]",cdradcont)
			if strings.Compare(err,"")!=0 {
				result.Success = false
				result.Errorcode = 2
				result.Message = err
				writeLog("Error in CDRConf: " + err )
			}else{
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdbserver",ser)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdruser",duname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrpass",dpass)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdatabase",dname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrtable",cdrtab)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrkeyfield",cdrkey)
				ExecCLI("core reload")
			}
		} else{

			result.Success = false
			result.Errorcode = 3
			result.Message = "libmyodbc not installed to install do command: sudo apt-get install libmyodbc "
			writeLog("Error in CDRConf: " + result.Message )
		}

	}

	output, _ := json.Marshal(result)

	w.Write(output)

}
func ModifyCDRConf(w http.ResponseWriter, r *http.Request) {
	var err string
	type JSONRequest struct {
		Server string
		Duname string
		Dpass string
		Dname string
		Ctab string
		Ckey string
	}

	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}

	w.Header().Add("Content-Type", "text/html")

	body, _ := ioutil.ReadAll(r.Body)
	var jrequest JSONRequest
	er := json.Unmarshal(body, &jrequest)
	if er != nil {
		result.Success = false
		result.Errorcode = 1
		result.Message = er.Error()
	} else {
		//set cdr configuration in configuration file
			ser:=jrequest.Server
			duname:=jrequest.Duname
			dpass:=jrequest.Dpass
			dname:=jrequest.Dname
			cdrtab:=jrequest.Ctab
			cdrkey:=jrequest.Ckey
			astdsncont:="Driver          = MySQL\nDescription     = MySQL Connector for Asterisk\nServer          = "+
				ser+"\nPort            = 3306\nDatabase        = "+
				dname+"\nusername        = "+
				duname+"\npassword        = "+
				dpass+"\nOption          = 3\nSocket          = /var/run/mysqld/mysqld.sock"
			err=modifyConfNode("/etc/odbc.ini","[MySQL-asterisk]",astdsncont)
			backupFile("res_odbc.conf")
			rsodcont:="enabled=yes\ndsn=MySQL-asterisk\nusername="+
				duname+"\npassword="+
				dpass+"\npooling=no\nlimit=1\npre-connect=yes\nshare_connections=yes\nsanitysql=select 1\nisolation=repeatable_read"
			err=modifyConfNode("/etc/asterisk/res_odbc.conf","[asterisk]",rsodcont)
			backupFile("cdr_odbc.conf")
			cdrodbccont:="dsn=asterisk\nloguniqueid=yes\ntable=" +
				cdrtab+"\ndispositionstring=yes\nusegmtime=no\nhrtime=yes"
			err=modifyConfNode("/etc/asterisk/cdr_odbc.conf","[global]",cdrodbccont)
			cdradcont:="connection=asterisk\ntable="+
				cdrtab+"\nalias start="+
				cdrkey
			err=modifyConfNode("/etc/asterisk/cdr_adaptive_odbc.conf","[asteriskcdr]",cdradcont)
			if strings.Compare(err,"")!=0 {
				result.Success = false
				result.Errorcode = 2
				result.Message = err
				writeLog("Error in CDRConf: " + err )
			}else{
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdbserver",ser)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdruser",duname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrpass",dpass)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdatabase",dname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrtable",cdrtab)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrkeyfield",cdrkey)
				ExecCLI("core reload")
			}

	}

	output, _ := json.Marshal(result)

	w.Write(output)

}
func GetCDRConf(w http.ResponseWriter,r *http.Request){

	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}
	w.Header().Add("Content-Type", "text/html")
	result.Result=getConfigValueLocal("cdrdbserver")+":"+
		getConfigValueLocal("cdruser")+":"+
		getConfigValueLocal("cdrpass")+":"+
		getConfigValueLocal("cdrdatabase")+":"+
		getConfigValueLocal("cdrtable")+":"+
		getConfigValueLocal("cdrkeyfield")
	output, _ := json.Marshal(result)
	w.Write(output)
}
func IsCDRConf(w http.ResponseWriter,r *http.Request){
	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}
	w.Header().Add("Content-Type", "text/html")
	if strings.Compare(getConfigValueLocal("cdrdbserver"),"")== 0{
		result.Success=false
	}
	output, _ := json.Marshal(result)
	w.Write(output)
}
func GetCDRConfStatus(w http.ResponseWriter,r *http.Request){
	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}
	w.Header().Add("Content-Type", "text/html")
	rs,_:=ExecCLI("odbc show all")
	if !strings.Contains(rs,"Connected: Yes"){
		result.Success=false
		result.Message="Configuration Error"
	}
	output, _ := json.Marshal(result)
	w.Write(output)
}
<commit_msg>cdr configuration bug  fix<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"io/ioutil"
	"strings"
)

func CDRConf(w http.ResponseWriter, r *http.Request) {
	var err string
	type JSONRequest struct {
		Server string
		Duname string
		Dpass string
		Dname string
		Ctab string
		Ckey string
	}

	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	dpath,_:=Shell("locate libmyodbc.so")
	spath,_:=Shell("locate libodbcmyS.so")
	result := JSONResult{true, 0, "", ""}

	w.Header().Add("Content-Type", "text/html")

	body, _ := ioutil.ReadAll(r.Body)
	var jrequest JSONRequest
	er := json.Unmarshal(body, &jrequest)
	if er != nil {
		result.Success = false
		result.Errorcode = 1
		result.Message = er.Error()
	} else {
		//set cdr configuration in configuration file
		if strings.Compare(dpath,"")!=0 && strings.Compare(spath,"")!=0 {
			dpath=dpath[:len(dpath)-1]
			spath=spath[:len(spath)-1]
			msqlcont:="Description     = MySQL driver\nDriver          = "+
				dpath+" \nSetup           = "+spath
			err=addConfNode("/etc/odbcinst.ini","[Default]","Driver          = "+dpath)
			addConfNode("/etc/odbcinst.ini","[MySQL]",msqlcont)
			ser:=jrequest.Server
			duname:=jrequest.Duname
			dpass:=jrequest.Dpass
			dname:=jrequest.Dname
			cdrtab:=jrequest.Ctab
			cdrkey:=jrequest.Ckey
			astdsncont:="Driver          = MySQL\nDescription     = MySQL Connector for Asterisk\nServer          = "+
				ser+"\nPort            = 3306\nDatabase        = "+
				dname+"\nusername        = "+
				duname+"\npassword        = "+
				dpass+"\nOption          = 3\nSocket          = /var/run/mysqld/mysqld.sock"
			err=addConfNode("/etc/odbc.ini","[MySQL-asterisk]",astdsncont)
			backupFile("res_odbc.conf")
			rsodcont:="enabled=yes\ndsn=MySQL-asterisk\nusername="+
				duname+"\npassword="+
				dpass+"\npooling=no\nlimit=1\npre-connect=yes\nshare_connections=yes\nsanitysql=select 1\nisolation=repeatable_read"
			err=addConfNode("/etc/asterisk/res_odbc.conf","[asterisk]",rsodcont)
			backupFile("cdr_odbc.conf")
			cdrodbccont:="dsn=asterisk\nloguniqueid=yes\ntable=" +
				cdrtab+"\ndispositionstring=yes\nusegmtime=no\nhrtime=yes"
			err=addConfNode("/etc/asterisk/cdr_odbc.conf","[global]",cdrodbccont)
			backupFile("cdr_manager.conf")
			err=modifyConfNode("/etc/asterisk/cdr_manager.conf","[general]","enabled = yes")
			backupFile("cdr_adaptive_odbc.conf")
			cdradcont:="connection=asterisk\ntable="+
				cdrtab+"\nalias start="+
				cdrkey
			err=addConfNode("/etc/asterisk/cdr_adaptive_odbc.conf","[asteriskcdr]",cdradcont)
			if strings.Compare(err,"")!=0 {
				result.Success = false
				result.Errorcode = 2
				result.Message = err
				writeLog("Error in CDRConf: " + err )
			}else{
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdbserver",ser)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdruser",duname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrpass",dpass)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdatabase",dname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrtable",cdrtab)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrkeyfield",cdrkey)
				ExecCLI("core reload")
			}
		} else{

			result.Success = false
			result.Errorcode = 3
			result.Message = "libmyodbc not installed to install do command: sudo apt-get install libmyodbc "
			writeLog("Error in CDRConf: " + result.Message )
		}

	}

	output, _ := json.Marshal(result)

	w.Write(output)

}
func ModifyCDRConf(w http.ResponseWriter, r *http.Request) {
	var err string
	type JSONRequest struct {
		Server string
		Duname string
		Dpass string
		Dname string
		Ctab string
		Ckey string
	}

	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}

	w.Header().Add("Content-Type", "text/html")

	body, _ := ioutil.ReadAll(r.Body)
	var jrequest JSONRequest
	er := json.Unmarshal(body, &jrequest)
	if er != nil {
		result.Success = false
		result.Errorcode = 1
		result.Message = er.Error()
	} else {
		//set cdr configuration in configuration file
			ser:=jrequest.Server
			duname:=jrequest.Duname
			dpass:=jrequest.Dpass
			dname:=jrequest.Dname
			cdrtab:=jrequest.Ctab
			cdrkey:=jrequest.Ckey
			astdsncont:="Driver          = MySQL\nDescription     = MySQL Connector for Asterisk\nServer          = "+
				ser+"\nPort            = 3306\nDatabase        = "+
				dname+"\nusername        = "+
				duname+"\npassword        = "+
				dpass+"\nOption          = 3\nSocket          = /var/run/mysqld/mysqld.sock"
			err=modifyConfNode("/etc/odbc.ini","[MySQL-asterisk]",astdsncont)
			backupFile("res_odbc.conf")
			rsodcont:="enabled=yes\ndsn=MySQL-asterisk\nusername="+
				duname+"\npassword="+
				dpass+"\npooling=no\nlimit=1\npre-connect=yes\nshare_connections=yes\nsanitysql=select 1\nisolation=repeatable_read"
			err=modifyConfNode("/etc/asterisk/res_odbc.conf","[asterisk]",rsodcont)
			backupFile("cdr_odbc.conf")
			cdrodbccont:="dsn=asterisk\nloguniqueid=yes\ntable=" +
				cdrtab+"\ndispositionstring=yes\nusegmtime=no\nhrtime=yes"
			err=modifyConfNode("/etc/asterisk/cdr_odbc.conf","[global]",cdrodbccont)
			cdradcont:="connection=asterisk\ntable="+
				cdrtab+"\nalias start="+
				cdrkey
			err=modifyConfNode("/etc/asterisk/cdr_adaptive_odbc.conf","[asteriskcdr]",cdradcont)
			if strings.Compare(err,"")!=0 {
				result.Success = false
				result.Errorcode = 2
				result.Message = err
				writeLog("Error in CDRConf: " + err )
			}else{
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdbserver",ser)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdruser",duname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrpass",dpass)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrdatabase",dname)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrtable",cdrtab)
				setConfigParameter("/etc/simpletrunk/stagent.ini","cdrkeyfield",cdrkey)
				ExecCLI("core reload")
			}

	}

	output, _ := json.Marshal(result)

	w.Write(output)

}
func GetCDRConf(w http.ResponseWriter,r *http.Request){

	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}
	keyf:=getConfigValueLocal("cdrkeyfield")
	if keyf==""{
		keyf="calldate"
	}
	w.Header().Add("Content-Type", "text/html")
	result.Result=getConfigValueLocal("cdrdbserver")+":"+
		getConfigValueLocal("cdruser")+":"+
		getConfigValueLocal("cdrpass")+":"+
		getConfigValueLocal("cdrdatabase")+":"+
		getConfigValueLocal("cdrtable")+":"+
		keyf

	output, _ := json.Marshal(result)
	w.Write(output)
}
func IsCDRConf(w http.ResponseWriter,r *http.Request){
	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}
	w.Header().Add("Content-Type", "text/html")
	if strings.Compare(getConfigValueLocal("cdrdbserver"),"")== 0{
		result.Success=false
		result.Errorcode=1
		result.Message="Not Config yet"
	}
	output, _ := json.Marshal(result)
	w.Write(output)
}
func GetCDRConfStatus(w http.ResponseWriter,r *http.Request){
	type JSONResult struct {
		Success   bool   `json:"success"`
		Errorcode int    `json:"errorcode"`
		Result    string `json:"result"`
		Message   string `json:"message"`
	}
	result := JSONResult{true, 0, "", ""}
	w.Header().Add("Content-Type", "text/html")
	rs,_:=ExecCLI("odbc show all")
	if !strings.Contains(rs,"Connected: Yes"){
		result.Success=false
		result.Errorcode=1
		result.Message="Configuration Error"
	}
	output, _ := json.Marshal(result)
	w.Write(output)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Kurt Jung (Gmail: kurt.w.jung)
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package cgi

import (
	"bytes"
	"errors"
	"net/http"
	"net/http/cgi"
	"path"
	"path/filepath"

	"github.com/mholt/caddy/caddyhttp/httpserver"
)

// match returns true if the request string (reqStr) matches the pattern string
// (patternStr), false otherwise. If true is returned, it is followed by the
// prefix that matches the pattern and the unmatched portion to its right.
// patternStr uses glob notation; see path/Match for matching details. If the
// pattern is invalid (for example, contains an unpaired "["), false is
// returned.
func match(reqStr, patternStr string) (ok bool, prefixStr, suffixStr string) {
	var str, last string
	var err error
	str = reqStr
	last = ""
	for last != str && !ok && err == nil {
		ok, err = path.Match(patternStr, str)
		if err == nil {
			if !ok {
				last = str
				str = filepath.Dir(str)
			}
		}
	}
	if ok && err == nil {
		return true, str, reqStr[len(str):]
	}
	return false, "", ""
}

// currentDir returns the current working directory
func currentDir() (wdStr string) {
	wdStr, _ = filepath.Abs(".")
	return
}

// setupCall instantiates a CGI handler based on the incoming request and the
// configuration rule that it matches.
func setupCall(h handlerType, rule ruleType, lfStr, rtStr string,
	rep httpserver.Replacer, username string) (cgiHnd cgi.Handler) {
	cgiHnd.Root = "/"
	cgiHnd.Dir = h.root
	rep.Set("root", h.root)
	rep.Set("match", lfStr)
	rep.Set(".", currentDir())
	cgiHnd.Path = rep.Replace(rule.exe)
	cgiHnd.Env = append(cgiHnd.Env, "REMOTE_USER="+username)
	envAdd := func(key, val string) {
		val = rep.Replace(val)
		cgiHnd.Env = append(cgiHnd.Env, key+"="+val)
	}
	// 	if r.TLS != nil {
	// 		env["HTTPS"] = "on"
	// 	}
	for _, env := range rule.envs {
		envAdd(env[0], env[1])
	}
	for _, env := range rule.envs {
		envAdd(env[0], env[1])
	}
	envAdd("PATH_INFO", rtStr)
	envAdd("SCRIPT_FILENAME", cgiHnd.Path)
	envAdd("SCRIPT_NAME", lfStr)
	cgiHnd.InheritEnv = append(cgiHnd.InheritEnv, rule.passEnvs...)
	cgiHnd.InheritEnv = append(cgiHnd.InheritEnv, rule.passEnvs...)
	for _, str := range rule.args {
		cgiHnd.Args = append(cgiHnd.Args, rep.Replace(str))
	}
	envAdd("SCRIPT_EXEC", trim(sprintf("%s %s", cgiHnd.Path, join(cgiHnd.Args, " "))))
	return
}

// ServeHTTP satisfies the httpserver.Handler interface.
func (h handlerType) ServeHTTP(w http.ResponseWriter, r *http.Request) (code int, err error) {
	rep := httpserver.NewReplacer(r, nil, "")
	for _, rule := range h.rules {
		for _, matchStr := range rule.matches {
			ok, lfStr, rtStr := match(r.URL.Path, matchStr)
			if ok {
				var buf bytes.Buffer
				cgiHnd := setupCall(h, rule, lfStr, rtStr, rep, r.Header.Get("Authorized"))
				cgiHnd.Stderr = &buf
				cgiHnd.ServeHTTP(w, r)
				if buf.Len() > 0 {
					err = errors.New(trim(buf.String()))
				}
				return
			}
		}
	}
	return h.next.ServeHTTP(w, r)
}
<commit_msg>Use context to retrieve authorized user set by basicauth or other authorization plugin<commit_after>/*
 * Copyright (c) 2017 Kurt Jung (Gmail: kurt.w.jung)
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package cgi

import (
	"bytes"
	"errors"
	"net/http"
	"net/http/cgi"
	"path"
	"path/filepath"

	"github.com/mholt/caddy/caddyhttp/httpserver"
)

// match returns true if the request string (reqStr) matches the pattern string
// (patternStr), false otherwise. If true is returned, it is followed by the
// prefix that matches the pattern and the unmatched portion to its right.
// patternStr uses glob notation; see path/Match for matching details. If the
// pattern is invalid (for example, contains an unpaired "["), false is
// returned.
func match(reqStr, patternStr string) (ok bool, prefixStr, suffixStr string) {
	var str, last string
	var err error
	str = reqStr
	last = ""
	for last != str && !ok && err == nil {
		ok, err = path.Match(patternStr, str)
		if err == nil {
			if !ok {
				last = str
				str = filepath.Dir(str)
			}
		}
	}
	if ok && err == nil {
		return true, str, reqStr[len(str):]
	}
	return false, "", ""
}

// currentDir returns the current working directory
func currentDir() (wdStr string) {
	wdStr, _ = filepath.Abs(".")
	return
}

// setupCall instantiates a CGI handler based on the incoming request and the
// configuration rule that it matches.
func setupCall(h handlerType, rule ruleType, lfStr, rtStr string,
	rep httpserver.Replacer, username string) (cgiHnd cgi.Handler) {
	cgiHnd.Root = "/"
	cgiHnd.Dir = h.root
	rep.Set("root", h.root)
	rep.Set("match", lfStr)
	rep.Set(".", currentDir())
	cgiHnd.Path = rep.Replace(rule.exe)
	cgiHnd.Env = append(cgiHnd.Env, "REMOTE_USER="+username)
	envAdd := func(key, val string) {
		val = rep.Replace(val)
		cgiHnd.Env = append(cgiHnd.Env, key+"="+val)
	}
	// 	if r.TLS != nil {
	// 		env["HTTPS"] = "on"
	// 	}
	for _, env := range rule.envs {
		envAdd(env[0], env[1])
	}
	for _, env := range rule.envs {
		envAdd(env[0], env[1])
	}
	envAdd("PATH_INFO", rtStr)
	envAdd("SCRIPT_FILENAME", cgiHnd.Path)
	envAdd("SCRIPT_NAME", lfStr)
	cgiHnd.InheritEnv = append(cgiHnd.InheritEnv, rule.passEnvs...)
	cgiHnd.InheritEnv = append(cgiHnd.InheritEnv, rule.passEnvs...)
	for _, str := range rule.args {
		cgiHnd.Args = append(cgiHnd.Args, rep.Replace(str))
	}
	envAdd("SCRIPT_EXEC", trim(sprintf("%s %s", cgiHnd.Path, join(cgiHnd.Args, " "))))
	return
}

// ServeHTTP satisfies the httpserver.Handler interface.
func (h handlerType) ServeHTTP(w http.ResponseWriter, r *http.Request) (code int, err error) {
	rep := httpserver.NewReplacer(r, nil, "")
	for _, rule := range h.rules {
		for _, matchStr := range rule.matches {
			ok, lfStr, rtStr := match(r.URL.Path, matchStr)
			if ok {
				var buf bytes.Buffer
				// Retrieve name of remote user that was set by some downstream middleware,
				// possibly basicauth.
				remoteUser, _ := r.Context().Value(httpserver.CtxKey("remote_user")).(string) // Blank if not set
				cgiHnd := setupCall(h, rule, lfStr, rtStr, rep, remoteUser)
				cgiHnd.Stderr = &buf
				cgiHnd.ServeHTTP(w, r)
				if buf.Len() > 0 {
					err = errors.New(trim(buf.String()))
				}
				return
			}
		}
	}
	return h.next.ServeHTTP(w, r)
}
<|endoftext|>


<commit_before>package uniq_test

import (
	"github.com/infogulch/uniq"
	"math/rand"
	"sort"
	"testing"
)

type uniquer func(uniq.Interface) int

func testUniqEmpty(unique uniquer, t *testing.T) {
	a := []int{}
	a = a[:unique(sort.IntSlice(a))]
	if len(a) != 0 {
		t.Errorf("Congratulations, you broke loops")
	}
}

func TestUniqEmpty(t *testing.T)   { testUniqEmpty(uniq.Uniq, t) }
func TestStableEmpty(t *testing.T) { testUniqEmpty(uniq.Stable, t) }

func testUniqOne(unique uniquer, t *testing.T) {
	const value int = 100
	a := []int{value}
	a = a[:unique(sort.IntSlice(a))]
	if len(a) != 1 {
		t.Errorf("Wrong length")
	} else if a[0] != value {
		t.Errorf("Changed values. Should be %d: %d", value, a[0])
	}
}

func TestUniqOne(t *testing.T)   { testUniqOne(uniq.Uniq, t) }
func TestStableOne(t *testing.T) { testUniqOne(uniq.Stable, t) }

func testUniqTiny(unique uniquer, t *testing.T) {
	a := []int{1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9}
	u := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	a = a[:unique(sort.IntSlice(a))]
	compareIntSlice(a, u, t)
}

func TestUniqTiny(t *testing.T)   { testUniqTiny(uniq.Uniq, t) }
func TestStableTiny(t *testing.T) { testUniqTiny(uniq.Stable, t) }

func testUniqRandom(unique uniquer, t *testing.T, size, count int) {
	rand.Seed(0) // specify seed for determinism
	u, a := make([]int, size), make([]int, 100*size)
	for i, _ := range u {
		u[i] = i
	}
	for ; count > 0; count-- {
		for i, _ := range a {
			a[i] = rand.Intn(size)
		}
		sort.Sort(sort.IntSlice(a))
		b := a[:unique(sort.IntSlice(a))]
		compareIntSlice(b, u, t)
	}
}

func TestUniqSmall(t *testing.T)   { testUniqRandom(uniq.Uniq, t, 30, 1000) }
func TestStableSmall(t *testing.T) { testUniqRandom(uniq.Stable, t, 30, 1000) }

func TestUniqMedium(t *testing.T)   { testUniqRandom(uniq.Uniq, t, 1000, 10) }
func TestStableMedium(t *testing.T) { testUniqRandom(uniq.Stable, t, 1000, 10) }

func TestUniqLarge(t *testing.T)   { testUniqRandom(uniq.Uniq, t, 10000, 2) }
func TestStableLarge(t *testing.T) { testUniqRandom(uniq.Stable, t, 10000, 2) }

func testUniqAllDuplicate(unique uniquer, t *testing.T) {
	a := make([]int, 1000)
	const value int = 123
	for i, _ := range a {
		a[i] = value
	}
	a = a[:unique(sort.IntSlice(a))]
	if len(a) != 1 {
		t.Errorf("Didn't eliminate all duplicates. len should be 1: %d", len(a))
	} else if a[0] != value {
		t.Errorf("Changed values. Should be %d: %d", value, a[0])
	}
}

func TestUniqAllDuplicate(t *testing.T)   { testUniqAllDuplicate(uniq.Uniq, t) }
func TestStableAllDuplicate(t *testing.T) { testUniqAllDuplicate(uniq.Stable, t) }

// types for stability tests

// stability tests

// helper functions
func compareIntSlice(a, b []int, t *testing.T) {
	for i, v := range a {
		if v != b[i] {
			t.Errorf("(a[%d] = %d) != (b[%d] = %d)", i, v, i, b[i])
		}
	}
}
<commit_msg>Add stability test for Stable()<commit_after>package uniq_test

import (
	"github.com/infogulch/uniq"
	"math/rand"
	"sort"
	"testing"
)

type uniquer func(uniq.Interface) int

func testUniqEmpty(unique uniquer, t *testing.T) {
	a := []int{}
	a = a[:unique(sort.IntSlice(a))]
	if len(a) != 0 {
		t.Errorf("Congratulations, you broke loops")
	}
}

func TestUniqEmpty(t *testing.T)   { testUniqEmpty(uniq.Uniq, t) }
func TestStableEmpty(t *testing.T) { testUniqEmpty(uniq.Stable, t) }

func testUniqOne(unique uniquer, t *testing.T) {
	const value int = 100
	a := []int{value}
	a = a[:unique(sort.IntSlice(a))]
	if len(a) != 1 {
		t.Errorf("Wrong length")
	} else if a[0] != value {
		t.Errorf("Changed values. Should be %d: %d", value, a[0])
	}
}

func TestUniqOne(t *testing.T)   { testUniqOne(uniq.Uniq, t) }
func TestStableOne(t *testing.T) { testUniqOne(uniq.Stable, t) }

func testUniqTiny(unique uniquer, t *testing.T) {
	a := []int{1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9}
	u := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	a = a[:unique(sort.IntSlice(a))]
	compareIntSlice(a, u, t)
}

func TestUniqTiny(t *testing.T)   { testUniqTiny(uniq.Uniq, t) }
func TestStableTiny(t *testing.T) { testUniqTiny(uniq.Stable, t) }

func testUniqRandom(unique uniquer, t *testing.T, size, count int) {
	rand.Seed(0) // specify seed for determinism
	u, a := make([]int, size), make([]int, 100*size)
	for i, _ := range u {
		u[i] = i
	}
	for ; count > 0; count-- {
		for i, _ := range a {
			a[i] = rand.Intn(size)
		}
		sort.Sort(sort.IntSlice(a))
		b := a[:unique(sort.IntSlice(a))]
		compareIntSlice(b, u, t)
	}
}

func TestUniqSmall(t *testing.T)   { testUniqRandom(uniq.Uniq, t, 30, 1000) }
func TestStableSmall(t *testing.T) { testUniqRandom(uniq.Stable, t, 30, 1000) }

func TestUniqMedium(t *testing.T)   { testUniqRandom(uniq.Uniq, t, 1000, 10) }
func TestStableMedium(t *testing.T) { testUniqRandom(uniq.Stable, t, 1000, 10) }

func TestUniqLarge(t *testing.T)   { testUniqRandom(uniq.Uniq, t, 10000, 2) }
func TestStableLarge(t *testing.T) { testUniqRandom(uniq.Stable, t, 10000, 2) }

func testUniqAllDuplicate(unique uniquer, t *testing.T) {
	a := make([]int, 1000)
	const value int = 123
	for i, _ := range a {
		a[i] = value
	}
	a = a[:unique(sort.IntSlice(a))]
	if len(a) != 1 {
		t.Errorf("Didn't eliminate all duplicates. len should be 1: %d", len(a))
	} else if a[0] != value {
		t.Errorf("Changed values. Should be %d: %d", value, a[0])
	}
}

func TestUniqAllDuplicate(t *testing.T)   { testUniqAllDuplicate(uniq.Uniq, t) }
func TestStableAllDuplicate(t *testing.T) { testUniqAllDuplicate(uniq.Stable, t) }

// types for stability tests
type Pair struct{ a, b int }
type Pairs []Pair

func (p Pairs) Len() int           { return len(p) }
func (p Pairs) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Pairs) Less(i, j int) bool { return p[i].a < p[j].a }

func TestStability(t *testing.T) {
	n := 10000
	a := make([]Pair, n)
	for i, _ := range a {
		a[i] = Pair{rand.Intn(100), i}
	}
	sort.Stable(Pairs(a))
	r := uniq.Stable(Pairs(a))
	if !uniq.IsSortedUnique(Pairs(a[:r])) {
		t.Errorf("Not unique")
	}
	if !sort.IsSorted(Pairs(a[r:])) {
		t.Errorf("Not sorted")
	}
	for i := 1; i < n; i++ {
		if a[i-1].a == a[i].a && a[i-1].b >= a[i].b {
			t.Errorf("Not stable")
		}
	}
}

// helper functions
func compareIntSlice(a, b []int, t *testing.T) {
	for i, v := range a {
		if v != b[i] {
			t.Errorf("(a[%d] = %d) != (b[%d] = %d)", i, v, i, b[i])
		}
	}
}
<|endoftext|>


<commit_before>package requests

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

// set is a simple slice of unique strings.
type set []string

// add appends a variadic amount of strings to a set, returning the
// resulting set.  Duplicates will only exist once in the resulting
// set.
func (s set) add(values ...string) set {
	for _, newValue := range values {
		exists := false
		for _, value := range s {
			if newValue == value {
				exists = true
				break
			}
		}
		if !exists {
			s = append(s, newValue)
		}
	}
	return s
}

// UnmarshalReplace performs the same process as Unmarshal, except
// that values not found in the request will be updated to their zero
// value.  For example, if foo.Bar == "baz" and foo.Bar has no
// corresponding data in a request, Unmarshal would leave it as "baz",
// but UnmarshalReplace will update it to "".
//
// Exceptions are made for unexported fields and fields which are
// found to have a name of "-".  Those are left alone.
func (request *Request) UnmarshalReplace(target interface{}) error {
	return request.unmarshal(target, true)
}

// Unmarshal unmarshals a request to a struct, using field tags to
// locate corresponding values in the request and check/parse them
// before assigning them to struct fields.  It acts similar to json's
// Unmarshal when used on a struct, but works with any codec
// registered with AddCodec().
//
// Field tags are used as follows:
//
// * All field tags are considered to be of the format
// name,option1,option2,...
//
// * Options will *only* be parsed from the "request" tag.
//
// * By default, name will only be checked in the "request" tag, but
// you can add fallback tag names using AddFallbackTag.
//
// * If no non-empty name is found using field tags, the lowercase
// field name will be used instead.
//
// * Once a name is found, if the name is "-", then the field will be
// treated as if it does not exist.
//
// For an explanation on how options work, see the documentation for
// RegisterOption.  For a list of tag options built in to this
// library, see the options package in this package.
//
// Fields which have no data in the request will be left as their
// current value.  They will still be passed through the option parser
// for the purposes of options like "required".
//
// Fields which implement Receiver will have their Receive method
// called using the value from the request after calling all
// OptionFuncs matching the field's tag options.
//
// An error will be returned if the target type is not a pointer to a
// struct, or if the target implements PreUnmarshaller, Unmarshaller,
// or PostUnmarshaller and the corresponding methods fail.  An
// UnusedFields error will be returned if fields in the request had no
// corresponding fields on the target struct.
//
// Any errors encountered while attempting to apply input values to
// the target's fields will be stored in an error of type InputErrors.
// At the end of the Unmarshal process, the InputErrors error will be
// returned if any errors were encountered.
//
// A simple example:
//
//     type Example struct {
//         Foo string `request:",required"`
//         Bar string `response:"baz"`
//         Baz string `response:"-"`
//         Bacon string `response:"-" request:"bacon,required"`
//     }
//
//     func CreateExample(request *http.Request) (*Example, error) {
//         target := new(Example)
//         if err := requests.New(request).Unmarshal(target); err != nil {
//             if inputErrs, ok := err.(InputErrors); ok {
//                 // inputErrs is a map of input names to error
//                 // messages, so send them to a function to turn
//                 // them into a proper user-friendly error message.
//                 return nil, userErrors(inputErrs)
//             }
//             return nil, err
//         }
//         return target, nil
//     }
//
func (request *Request) Unmarshal(target interface{}) error {
	return request.unmarshal(target, false)
}

// unmarshal performes all of the logic for Unmarshal and
// UnmarshalReplace.
func (request *Request) unmarshal(target interface{}, replace bool) (unmarshalErr error) {
	targetValue := reflect.ValueOf(target)
	if targetValue.Kind() != reflect.Ptr || targetValue.Elem().Kind() != reflect.Struct {
		return errors.New("The value passed to Unmarshal must be a pointer to a struct")
	}
	targetValue = targetValue.Elem()
	params, err := request.Params()
	if err != nil {
		return err
	}

	if preUnmarshaller, ok := target.(PreUnmarshaller); ok {
		if unmarshalErr = preUnmarshaller.PreUnmarshal(); unmarshalErr != nil {
			return
		}
	}
	if postUnmarshaller, ok := target.(PostUnmarshaller); ok {
		defer func() {
			if unmarshalErr == nil {
				unmarshalErr = postUnmarshaller.PostUnmarshal()
			}
		}()
	}
	if unmarshaller, ok := target.(Unmarshaller); ok {
		return unmarshaller.Unmarshal(params)
	}

	matchedFields, inputErrs := unmarshalToValue(params, targetValue, replace)
	if len(inputErrs) > 0 {
		return inputErrs
	}

	unused := &UnusedFields{
		params:  params,
		matched: matchedFields,
	}
	if unused.HasMissing() {
		return unused
	}
	return nil
}

// unmarshalToValue is a helper for UnmarshalParams, which keeps track
// of the total number of fields matched in a request and which fields
// were missing from a request.
func unmarshalToValue(params map[string]interface{}, targetValue reflect.Value, replace bool) (matchedFields set, parseErrs InputErrors) {
	matchedFields = make(set, 0, len(params))
	parseErrs = make(InputErrors)
	defer func() {
		// Clean up any nil errors from the error map.
		parseErrs = parseErrs.Errors()
	}()

	targetType := targetValue.Type()
	for i := 0; i < targetValue.NumField(); i++ {
		fieldValue := targetValue.Field(i)
		field := targetType.Field(i)
		if field.Anonymous {
			// Ignore non-struct anonymous fields, but treat fields in
			// struct or struct pointer anonymous fields as if they
			// were fields on the child struct.
			if fieldValue.Kind() == reflect.Ptr {
				fieldValue = fieldValue.Elem()
			}
			if fieldValue.Kind() == reflect.Struct {
				embeddedFields, newErrs := unmarshalToValue(params, fieldValue, replace)
				if newErrs != nil {
					// Override input errors in the anonymous field
					// with input errors in the child.  Non-nil
					// errors from anonymous fields will be
					// overwritten with nil errors from overriding
					// child fields.
					parseErrs = newErrs.Merge(parseErrs)
				}
				matchedFields = matchedFields.add(embeddedFields...)
			}
			continue
		}

		// Skip unexported fields
		if field.PkgPath == "" {
			name := name(field)
			if name == "-" {
				continue
			}

			value, fromParams := params[name]
			if fromParams {
				matchedFields = matchedFields.add(name)
			} else {
				// If we're not replacing the value, use the field's
				// current value.  If we are, use the field's zero
				// value.
				zero := reflect.Zero(fieldValue.Type())
				if replace {
					if zero.IsNil() {
						value = nil
					} else {
						value = zero.Interface()
					}
				} else {
					if fieldValue.IsNil() {
						value = nil
					} else {
						value = fieldValue.Interface()
					}
				}
				if value == nil || value == zero.Interface() {
					// The value is empty, so see if its default can
					// be loaded.
					if defaulter, ok := value.(Defaulter); ok {
						value = defaulter.DefaultValue()
					}
				}
			}
			var inputErr error
			value, inputErr = ApplyOptions(field, fieldValue.Interface(), value)
			if parseErrs.Set(name, inputErr) {
				continue
			}
			parseErrs.Set(name, setValue(fieldValue, value, fromParams))
		}
	}
	return
}

func callReceivers(target reflect.Value, value interface{}) (receiverFound bool, err error) {
	preReceiver, hasPreReceive := target.Interface().(PreReceiver)
	receiver, hasReceive := target.Interface().(Receiver)
	postReceiver, hasPostReceive := target.Interface().(PostReceiver)
	if target.CanAddr() {
		// If interfaces weren't found, try again with the pointer
		targetPtr := target.Addr().Interface()
		if !hasPreReceive {
			preReceiver, hasPreReceive = targetPtr.(PreReceiver)
		}
		if !hasReceive {
			receiver, hasReceive = targetPtr.(Receiver)
		}
		if !hasPostReceive {
			postReceiver, hasPostReceive = targetPtr.(PostReceiver)
		}
	}
	receiverFound = hasReceive

	if hasPreReceive {
		if err = preReceiver.PreReceive(); err != nil {
			return
		}
	}
	if hasPostReceive {
		defer func() {
			if err == nil {
				err = postReceiver.PostReceive()
			}
		}()
	}
	if hasReceive {
		err = receiver.Receive(value)
	}
	return
}

// setValue takes a target and a value, and updates the target to
// match the value.
func setValue(target reflect.Value, value interface{}, fromRequest bool) (parseErr error) {
	if value == nil {
		if target.Kind() != reflect.Ptr {
			return errors.New("Cannot set non-pointer value to null")
		}
		if !target.IsNil() {
			target.Set(reflect.Zero(target.Type()))
		}
		return nil
	}

	if target.Kind() == reflect.Ptr && target.IsNil() {
		target.Set(reflect.New(target.Type().Elem()))
	}

	// Only worry about the receive methods if the value is from a
	// request.
	if fromRequest {
		if receiverFound, err := callReceivers(target, value); err != nil || receiverFound {
			return err
		}
	}

	for target.Kind() == reflect.Ptr {
		target = target.Elem()
	}
	switch target.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		parseErr = setInt(target, value)
	case reflect.Float32, reflect.Float64:
		parseErr = setFloat(target, value)
	default:
		inputType := reflect.TypeOf(value)
		if !inputType.ConvertibleTo(target.Type()) {
			return fmt.Errorf("Cannot convert value of type %s to type %s",
				inputType.Name(), target.Type().Name())
		}
		target.Set(reflect.ValueOf(value).Convert(target.Type()))
	}
	return
}

func setInt(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		intVal, err := strconv.ParseInt(src, 10, 64)
		if err != nil {
			return err
		}
		target.SetInt(intVal)
	case int:
		target.SetInt(int64(src))
	case int8:
		target.SetInt(int64(src))
	case int16:
		target.SetInt(int64(src))
	case int32:
		target.SetInt(int64(src))
	case int64:
		target.SetInt(src)
	case float32:
		target.SetInt(int64(src))
	case float64:
		target.SetInt(int64(src))
	}
	return nil
}

func setFloat(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		floatVal, err := strconv.ParseFloat(src, 64)
		if err != nil {
			return err
		}
		target.SetFloat(floatVal)
	case int:
		target.SetFloat(float64(src))
	case int8:
		target.SetFloat(float64(src))
	case int16:
		target.SetFloat(float64(src))
	case int32:
		target.SetFloat(float64(src))
	case int64:
		target.SetFloat(float64(src))
	case float32:
		target.SetFloat(float64(src))
	case float64:
		target.SetFloat(src)
	}
	return nil
}
<commit_msg>Take better care of nil values<commit_after>package requests

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

// set is a simple slice of unique strings.
type set []string

// add appends a variadic amount of strings to a set, returning the
// resulting set.  Duplicates will only exist once in the resulting
// set.
func (s set) add(values ...string) set {
	for _, newValue := range values {
		exists := false
		for _, value := range s {
			if newValue == value {
				exists = true
				break
			}
		}
		if !exists {
			s = append(s, newValue)
		}
	}
	return s
}

// UnmarshalReplace performs the same process as Unmarshal, except
// that values not found in the request will be updated to their zero
// value.  For example, if foo.Bar == "baz" and foo.Bar has no
// corresponding data in a request, Unmarshal would leave it as "baz",
// but UnmarshalReplace will update it to "".
//
// Exceptions are made for unexported fields and fields which are
// found to have a name of "-".  Those are left alone.
func (request *Request) UnmarshalReplace(target interface{}) error {
	return request.unmarshal(target, true)
}

// Unmarshal unmarshals a request to a struct, using field tags to
// locate corresponding values in the request and check/parse them
// before assigning them to struct fields.  It acts similar to json's
// Unmarshal when used on a struct, but works with any codec
// registered with AddCodec().
//
// Field tags are used as follows:
//
// * All field tags are considered to be of the format
// name,option1,option2,...
//
// * Options will *only* be parsed from the "request" tag.
//
// * By default, name will only be checked in the "request" tag, but
// you can add fallback tag names using AddFallbackTag.
//
// * If no non-empty name is found using field tags, the lowercase
// field name will be used instead.
//
// * Once a name is found, if the name is "-", then the field will be
// treated as if it does not exist.
//
// For an explanation on how options work, see the documentation for
// RegisterOption.  For a list of tag options built in to this
// library, see the options package in this package.
//
// Fields which have no data in the request will be left as their
// current value.  They will still be passed through the option parser
// for the purposes of options like "required".
//
// Fields which implement Receiver will have their Receive method
// called using the value from the request after calling all
// OptionFuncs matching the field's tag options.
//
// An error will be returned if the target type is not a pointer to a
// struct, or if the target implements PreUnmarshaller, Unmarshaller,
// or PostUnmarshaller and the corresponding methods fail.  An
// UnusedFields error will be returned if fields in the request had no
// corresponding fields on the target struct.
//
// Any errors encountered while attempting to apply input values to
// the target's fields will be stored in an error of type InputErrors.
// At the end of the Unmarshal process, the InputErrors error will be
// returned if any errors were encountered.
//
// A simple example:
//
//     type Example struct {
//         Foo string `request:",required"`
//         Bar string `response:"baz"`
//         Baz string `response:"-"`
//         Bacon string `response:"-" request:"bacon,required"`
//     }
//
//     func CreateExample(request *http.Request) (*Example, error) {
//         target := new(Example)
//         if err := requests.New(request).Unmarshal(target); err != nil {
//             if inputErrs, ok := err.(InputErrors); ok {
//                 // inputErrs is a map of input names to error
//                 // messages, so send them to a function to turn
//                 // them into a proper user-friendly error message.
//                 return nil, userErrors(inputErrs)
//             }
//             return nil, err
//         }
//         return target, nil
//     }
//
func (request *Request) Unmarshal(target interface{}) error {
	return request.unmarshal(target, false)
}

// unmarshal performes all of the logic for Unmarshal and
// UnmarshalReplace.
func (request *Request) unmarshal(target interface{}, replace bool) (unmarshalErr error) {
	targetValue := reflect.ValueOf(target)
	if targetValue.Kind() != reflect.Ptr || targetValue.Elem().Kind() != reflect.Struct {
		return errors.New("The value passed to Unmarshal must be a pointer to a struct")
	}
	targetValue = targetValue.Elem()
	params, err := request.Params()
	if err != nil {
		return err
	}

	if preUnmarshaller, ok := target.(PreUnmarshaller); ok {
		if unmarshalErr = preUnmarshaller.PreUnmarshal(); unmarshalErr != nil {
			return
		}
	}
	if postUnmarshaller, ok := target.(PostUnmarshaller); ok {
		defer func() {
			if unmarshalErr == nil {
				unmarshalErr = postUnmarshaller.PostUnmarshal()
			}
		}()
	}
	if unmarshaller, ok := target.(Unmarshaller); ok {
		return unmarshaller.Unmarshal(params)
	}

	matchedFields, inputErrs := unmarshalToValue(params, targetValue, replace)
	if len(inputErrs) > 0 {
		return inputErrs
	}

	unused := &UnusedFields{
		params:  params,
		matched: matchedFields,
	}
	if unused.HasMissing() {
		return unused
	}
	return nil
}

// unmarshalToValue is a helper for UnmarshalParams, which keeps track
// of the total number of fields matched in a request and which fields
// were missing from a request.
func unmarshalToValue(params map[string]interface{}, targetValue reflect.Value, replace bool) (matchedFields set, parseErrs InputErrors) {
	matchedFields = make(set, 0, len(params))
	parseErrs = make(InputErrors)
	defer func() {
		// Clean up any nil errors from the error map.
		parseErrs = parseErrs.Errors()
	}()

	targetType := targetValue.Type()
	for i := 0; i < targetValue.NumField(); i++ {
		fieldValue := targetValue.Field(i)
		field := targetType.Field(i)
		if field.Anonymous {
			// Ignore non-struct anonymous fields, but treat fields in
			// struct or struct pointer anonymous fields as if they
			// were fields on the child struct.
			if fieldValue.Kind() == reflect.Ptr {
				fieldValue = fieldValue.Elem()
			}
			if fieldValue.Kind() == reflect.Struct {
				embeddedFields, newErrs := unmarshalToValue(params, fieldValue, replace)
				if newErrs != nil {
					// Override input errors in the anonymous field
					// with input errors in the child.  Non-nil
					// errors from anonymous fields will be
					// overwritten with nil errors from overriding
					// child fields.
					parseErrs = newErrs.Merge(parseErrs)
				}
				matchedFields = matchedFields.add(embeddedFields...)
			}
			continue
		}

		// Skip unexported fields
		if field.PkgPath == "" {
			name := name(field)
			if name == "-" {
				continue
			}

			valueInter, fromParams := params[name]
			var value reflect.Value
			if fromParams {
				value = reflect.ValueOf(valueInter)
				matchedFields = matchedFields.add(name)
			} else {
				// If we're not replacing the value, use the field's
				// current value.  If we are, use the field's zero
				// value.
				zero := reflect.Zero(fieldValue.Type())
				if replace {
					value = zero
				} else {
					value = fieldValue
				}
				if value == zero {
					// The value is empty, so see if its default can
					// be loaded.
					if defaulter, ok := fieldValue.Interface().(Defaulter); ok {
						value = reflect.ValueOf(defaulter.DefaultValue())
					}
				}
			}
			var optionValue interface{}
			if value.IsValid() {
				optionValue = value.Interface()
			}
			newVal, inputErr := ApplyOptions(field, fieldValue.Interface(), optionValue)
			if parseErrs.Set(name, inputErr) {
				continue
			}
			value = reflect.ValueOf(newVal)
			parseErrs.Set(name, setValue(fieldValue, value, fromParams))
		}
	}
	return
}

// isNil returns true if value.IsValid() returns false or if
// value.IsNil() returns true.  Returns false otherwise.  Recovers
// panics from value.IsNil().
func isNil(value reflect.Value) bool {
	defer func() {
		recover()
	}()
	if !value.IsValid() {
		return true
	}
	if value.IsNil() {
		return true
	}
	return false
}

func checkNil(target, value reflect.Value) (valueIsNil bool, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("Nil value found, but type %s cannot be nil.", target.Type().Name())
		}
	}()

	if valueIsNil = isNil(value); valueIsNil {
		// target.IsNil() will panic if target's zero value is
		// non-nil.
		if !target.IsNil() {
			target.Set(reflect.Zero(target.Type()))
		}
		return
	}

	if isNil(target) {
		target.Set(reflect.New(target.Type().Elem()))
	}
	return
}

func callReceivers(target reflect.Value, value interface{}) (receiverFound bool, err error) {
	preReceiver, hasPreReceive := target.Interface().(PreReceiver)
	receiver, hasReceive := target.Interface().(Receiver)
	postReceiver, hasPostReceive := target.Interface().(PostReceiver)
	if target.CanAddr() {
		// If interfaces weren't found, try again with the pointer
		targetPtr := target.Addr().Interface()
		if !hasPreReceive {
			preReceiver, hasPreReceive = targetPtr.(PreReceiver)
		}
		if !hasReceive {
			receiver, hasReceive = targetPtr.(Receiver)
		}
		if !hasPostReceive {
			postReceiver, hasPostReceive = targetPtr.(PostReceiver)
		}
	}
	receiverFound = hasReceive

	if hasPreReceive {
		if err = preReceiver.PreReceive(); err != nil {
			return
		}
	}
	if hasPostReceive {
		defer func() {
			if err == nil {
				err = postReceiver.PostReceive()
			}
		}()
	}
	if hasReceive {
		err = receiver.Receive(value)
	}
	return
}

// setValue takes a target and a value, and updates the target to
// match the value.
func setValue(target, value reflect.Value, fromRequest bool) (parseErr error) {
	if isNil, err := checkNil(target, value); isNil || err != nil {
		return err
	}

	// Only worry about the receive methods if the value is from a
	// request.
	if fromRequest {
		if receiverFound, err := callReceivers(target, value.Interface()); err != nil || receiverFound {
			return err
		}
	}

	for target.Kind() == reflect.Ptr {
		target = target.Elem()
	}
	switch target.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		parseErr = setInt(target, value.Interface())
	case reflect.Float32, reflect.Float64:
		parseErr = setFloat(target, value.Interface())
	default:
		inputType := value.Type()
		if !inputType.ConvertibleTo(target.Type()) {
			return fmt.Errorf("Cannot convert value of type %s to type %s",
				inputType.Name(), target.Type().Name())
		}
		target.Set(value.Convert(target.Type()))
	}
	return
}

func setInt(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		intVal, err := strconv.ParseInt(src, 10, 64)
		if err != nil {
			return err
		}
		target.SetInt(intVal)
	case int:
		target.SetInt(int64(src))
	case int8:
		target.SetInt(int64(src))
	case int16:
		target.SetInt(int64(src))
	case int32:
		target.SetInt(int64(src))
	case int64:
		target.SetInt(src)
	case float32:
		target.SetInt(int64(src))
	case float64:
		target.SetInt(int64(src))
	}
	return nil
}

func setFloat(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		floatVal, err := strconv.ParseFloat(src, 64)
		if err != nil {
			return err
		}
		target.SetFloat(floatVal)
	case int:
		target.SetFloat(float64(src))
	case int8:
		target.SetFloat(float64(src))
	case int16:
		target.SetFloat(float64(src))
	case int32:
		target.SetFloat(float64(src))
	case int64:
		target.SetFloat(float64(src))
	case float32:
		target.SetFloat(float64(src))
	case float64:
		target.SetFloat(src)
	}
	return nil
}
<|endoftext|>


<commit_before>package xls

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

//content type
type contentHandler interface {
	String(*WorkBook) []string
	FirstCol() uint16
	LastCol() uint16
}

type Col struct {
	RowB      uint16
	FirstColB uint16
}

type Coler interface {
	Row() uint16
}

func (c *Col) Row() uint16 {
	return c.RowB
}

func (c *Col) FirstCol() uint16 {
	return c.FirstColB
}

func (c *Col) LastCol() uint16 {
	return c.FirstColB
}

func (c *Col) String(wb *WorkBook) []string {
	return []string{"default"}
}

type XfRk struct {
	Index uint16
	Rk    RK
}

func (xf *XfRk) String(wb *WorkBook) string {
	idx := int(xf.Index)
	if len(wb.Xfs) > idx {
		fNo := wb.Xfs[idx].formatNo()
		if fNo >= 164 { // user defined format
			if fmt := wb.Formats[fNo]; fmt != nil && strings.Contains(fmt.str, "YY") {
				i, f, isFloat := xf.Rk.number()
				if !isFloat {
					f = float64(i)
				}
				t := timeFromExcelTime(f, wb.dateMode == 1)
				return t.Format(time.RFC3339) //TODO it should be international
			}
			// see http://www.openoffice.org/sc/excelfileformat.pdf
		} else if 14 <= fNo && fNo <= 17 || fNo == 22 || 27 <= fNo && fNo <= 36 || 50 <= fNo && fNo <= 58 { // jp. date format
			i, f, isFloat := xf.Rk.number()
			if !isFloat {
				f = float64(i)
			}
			t := timeFromExcelTime(f, wb.dateMode == 1)
			return t.Format("2006.01") //TODO it should be international
		}
	}
	return xf.Rk.String()
}

type RK uint32

func (rk RK) number() (intNum int64, floatNum float64, isFloat bool) {
	multiplied := rk & 1
	isInt := rk & 2
	val := rk >> 2
	if isInt == 0 {
		isFloat = true
		floatNum = math.Float64frombits(uint64(val) << 34)
		if multiplied != 0 {
			floatNum = floatNum / 100
		}
		return
	}
	return int64(val), 0, false
}

func (rk RK) String() string {
	i, f, isFloat := rk.number()
	if isFloat {
		return strconv.FormatFloat(f, 'f', -1, 64)
	}
	return strconv.FormatInt(i, 10)
}

var ErrIsInt = fmt.Errorf("is int")

func (rk RK) Float() (float64, error) {
	_, f, isFloat := rk.number()
	if !isFloat {
		return 0, ErrIsInt
	}
	return f, nil
}

type MulrkCol struct {
	Col
	Xfrks    []XfRk
	LastColB uint16
}

func (c *MulrkCol) LastCol() uint16 {
	return c.LastColB
}

func (c *MulrkCol) String(wb *WorkBook) []string {
	var res = make([]string, len(c.Xfrks))
	for i := 0; i < len(c.Xfrks); i++ {
		xfrk := c.Xfrks[i]
		res[i] = xfrk.String(wb)
	}
	return res
}

type MulBlankCol struct {
	Col
	Xfs      []uint16
	LastColB uint16
}

func (c *MulBlankCol) LastCol() uint16 {
	return c.LastColB
}

func (c *MulBlankCol) String(wb *WorkBook) []string {
	return make([]string, len(c.Xfs))
}

type NumberCol struct {
	Col
	Index uint16
	Float float64
}

func (c *NumberCol) String(wb *WorkBook) []string {
	return []string{fmt.Sprintf("%f", c.Float)}
}

type FormulaCol struct {
	Header struct {
		Col
		IndexXf uint16
		Result  [8]byte
		Flags   uint16
		_       uint32
	}
	Bts []byte
}

func (c *FormulaCol) String(wb *WorkBook) []string {
	return []string{"FormulaCol"}
}

type RkCol struct {
	Col
	Xfrk XfRk
}

func (c *RkCol) String(wb *WorkBook) []string {
	return []string{c.Xfrk.String(wb)}
}

type LabelsstCol struct {
	Col
	Xf  uint16
	Sst uint32
}

func (c *LabelsstCol) String(wb *WorkBook) []string {
	return []string{wb.sst[int(c.Sst)]}
}

type labelCol struct {
	BlankCol
	Str string
}

func (c *labelCol) String(wb *WorkBook) []string {
	return []string{c.Str}
}

type BlankCol struct {
	Col
	Xf uint16
}

func (c *BlankCol) String(wb *WorkBook) []string {
	return []string{""}
}
<commit_msg>float format<commit_after>package xls

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

//content type
type contentHandler interface {
	String(*WorkBook) []string
	FirstCol() uint16
	LastCol() uint16
}

type Col struct {
	RowB      uint16
	FirstColB uint16
}

type Coler interface {
	Row() uint16
}

func (c *Col) Row() uint16 {
	return c.RowB
}

func (c *Col) FirstCol() uint16 {
	return c.FirstColB
}

func (c *Col) LastCol() uint16 {
	return c.FirstColB
}

func (c *Col) String(wb *WorkBook) []string {
	return []string{"default"}
}

type XfRk struct {
	Index uint16
	Rk    RK
}

func (xf *XfRk) String(wb *WorkBook) string {
	idx := int(xf.Index)
	if len(wb.Xfs) > idx {
		fNo := wb.Xfs[idx].formatNo()
		if fNo >= 164 { // user defined format
			if fmt := wb.Formats[fNo]; fmt != nil && strings.Contains(fmt.str, "YY") {
				i, f, isFloat := xf.Rk.number()
				if !isFloat {
					f = float64(i)
				}
				t := timeFromExcelTime(f, wb.dateMode == 1)
				return t.Format(time.RFC3339) //TODO it should be international
			}
			// see http://www.openoffice.org/sc/excelfileformat.pdf
		} else if 14 <= fNo && fNo <= 17 || fNo == 22 || 27 <= fNo && fNo <= 36 || 50 <= fNo && fNo <= 58 { // jp. date format
			i, f, isFloat := xf.Rk.number()
			if !isFloat {
				f = float64(i)
			}
			t := timeFromExcelTime(f, wb.dateMode == 1)
			return t.Format("2006.01") //TODO it should be international
		}
	}
	return xf.Rk.String()
}

type RK uint32

func (rk RK) number() (intNum int64, floatNum float64, isFloat bool) {
	multiplied := rk & 1
	isInt := rk & 2
	val := rk >> 2
	if isInt == 0 {
		isFloat = true
		floatNum = math.Float64frombits(uint64(val) << 34)
		if multiplied != 0 {
			floatNum = floatNum / 100
		}
		return
	}
	return int64(val), 0, false
}

func (rk RK) String() string {
	i, f, isFloat := rk.number()
	if isFloat {
		return strconv.FormatFloat(f, 'f', -1, 64)
	}
	return strconv.FormatInt(i, 10)
}

var ErrIsInt = fmt.Errorf("is int")

func (rk RK) Float() (float64, error) {
	_, f, isFloat := rk.number()
	if !isFloat {
		return 0, ErrIsInt
	}
	return f, nil
}

type MulrkCol struct {
	Col
	Xfrks    []XfRk
	LastColB uint16
}

func (c *MulrkCol) LastCol() uint16 {
	return c.LastColB
}

func (c *MulrkCol) String(wb *WorkBook) []string {
	var res = make([]string, len(c.Xfrks))
	for i := 0; i < len(c.Xfrks); i++ {
		xfrk := c.Xfrks[i]
		res[i] = xfrk.String(wb)
	}
	return res
}

type MulBlankCol struct {
	Col
	Xfs      []uint16
	LastColB uint16
}

func (c *MulBlankCol) LastCol() uint16 {
	return c.LastColB
}

func (c *MulBlankCol) String(wb *WorkBook) []string {
	return make([]string, len(c.Xfs))
}

type NumberCol struct {
	Col
	Index uint16
	Float float64
}

func (c *NumberCol) String(wb *WorkBook) []string {
	return []string{strconv.FormatFloat(c.Float, 'f', -1, 64)}
}

type FormulaCol struct {
	Header struct {
		Col
		IndexXf uint16
		Result  [8]byte
		Flags   uint16
		_       uint32
	}
	Bts []byte
}

func (c *FormulaCol) String(wb *WorkBook) []string {
	return []string{"FormulaCol"}
}

type RkCol struct {
	Col
	Xfrk XfRk
}

func (c *RkCol) String(wb *WorkBook) []string {
	return []string{c.Xfrk.String(wb)}
}

type LabelsstCol struct {
	Col
	Xf  uint16
	Sst uint32
}

func (c *LabelsstCol) String(wb *WorkBook) []string {
	return []string{wb.sst[int(c.Sst)]}
}

type labelCol struct {
	BlankCol
	Str string
}

func (c *labelCol) String(wb *WorkBook) []string {
	return []string{c.Str}
}

type BlankCol struct {
	Col
	Xf uint16
}

func (c *BlankCol) String(wb *WorkBook) []string {
	return []string{""}
}
<|endoftext|>


<commit_before>package lapi

import "io/ioutil"

// Hook acts as a middleware of processing request
type Hook interface {
	// SetUp executes Hook before handler runs
	// if one of hooks returns an error during process, hooking should be stopped
	SetUp(connection Connection) error

	// TearDown executes Hook after handler runs
	// if one of hooks returns an error during process, hooking should be stopped
	TearDown(connection Connection, result interface{}, err error) error
}

// SystemHook acts as mandatory hook
type SystemHook struct{}

func (h *SystemHook) SetUp(connection Connection) error {
	request := connection.Request()
	if request.Ancestor().Body == nil {
		return nil
	}

	body, err := ioutil.ReadAll(request.Ancestor().Body)
	if err != nil {
		return err
	}
	request.WithContentBytes(body, request.Route().RequestInput())
	return nil
}

func (h *SystemHook) TearDown(connection Connection, result interface{}, err error) error {
	if err != nil {
		// let rescuer handle error
		return err
	}

	connection.Response().WithContent(result)
	return nil
}

type ParserHook struct{}

func (h *ParserHook) SetUp(connection Connection) error {
	connection.Response().WithParser(new(JsonParser))
	return nil
}

func (h *ParserHook) TearDown(connection Connection, result interface{}, err error) error {
	return nil
}
<commit_msg>Improve systemhook not to set nil content<commit_after>package lapi

import "io/ioutil"

// Hook acts as a middleware of processing request
type Hook interface {
	// SetUp executes Hook before handler runs
	// if one of hooks returns an error during process, hooking should be stopped
	SetUp(connection Connection) error

	// TearDown executes Hook after handler runs
	// if one of hooks returns an error during process, hooking should be stopped
	TearDown(connection Connection, result interface{}, err error) error
}

// SystemHook acts as mandatory hook
type SystemHook struct{}

func (h *SystemHook) SetUp(connection Connection) error {
	request := connection.Request()
	if request.Ancestor().Body == nil {
		return nil
	}

	body, err := ioutil.ReadAll(request.Ancestor().Body)
	if err != nil {
		return err
	}
	request.WithContentBytes(body, request.Route().RequestInput())
	return nil
}

func (h *SystemHook) TearDown(connection Connection, result interface{}, err error) error {
	if err != nil {
		// let rescuer handle error
		return err
	}

	if result == nil {
		return nil
	}

	connection.Response().WithContent(result)
	return nil
}

type ParserHook struct{}

func (h *ParserHook) SetUp(connection Connection) error {
	connection.Response().WithParser(new(JsonParser))
	return nil
}

func (h *ParserHook) TearDown(connection Connection, result interface{}, err error) error {
	return nil
}
<|endoftext|>


<commit_before>package makross

import (
	"pueue"
)

var (
	ops uint64 = 0
)

type Node struct {
	priority uint64
	key      string
	callback func([]byte) []byte
}

func (n *Node) Less(other interface{}) bool {
	return n.priority < other.(*Node).priority
}

func (m *Makross) NewPriorityQueue() *pueue.PriorityQueue {
	return pueue.New()
}

func (c *Context) NewPriorityQueue() *pueue.PriorityQueue {
	return c.makross.NewPriorityQueue()
}

func (m *Makross) NewPriorityQueuesMap() map[string]*pueue.PriorityQueue {
	return map[string]*pueue.PriorityQueue{}
}

func (c *Context) NewPriorityQueuesMap() map[string]*pueue.PriorityQueue {
	return c.makross.NewPriorityQueuesMap()
}

func (m *Makross) RemoveFilterHook(key string) {
	if m.HasFilterHook(key) {
		delete(m.FiltersMap, key)
	}
}

func (c *Context) RemoveFilterHook(key string, globals ...bool) {
	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}
	if global {
		c.makross.RemoveFilterHook(key)
	} else if c.HasFilterHook(key) {
		delete(c.FiltersMap, key)
	}
}

func (m *Makross) RemoveActionHook(key string) {
	if m.HasActionHook(key) {
		delete(m.QueuesMap, key)
		delete(m.FiltersMap, key)
	}
}

func (c *Context) RemoveActionHook(key string, globals ...bool) {
	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}
	if global {
		c.makross.RemoveActionHook(key)
	} else if c.HasActionHook(key) {
		delete(c.makross.QueuesMap, key)
		delete(c.FiltersMap, key)
	}
}

func (m *Makross) RemoveActionsHook() {
	m.QueuesMap = nil
}

func (c *Context) RemoveActionsHook() {
	c.makross.RemoveActionsHook()
}

func (m *Makross) HasFilterHook(key string) bool {
	if _, okay := m.FiltersMap[key]; okay {
		return true
	}
	return false
}

func (c *Context) HasFilterHook(key string, globals ...bool) bool {
	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}
	if global {
		return c.makross.HasFilterHook(key)
	} else if _, okay := c.FiltersMap[key]; okay {
		return true
	}
	return false
}

func (m *Makross) HasActionHook(key string) bool {
	if _, okay := m.QueuesMap[key]; okay {
		if _, okay := m.QueuesMap[key].Top().(*Node); okay {
			return true
		}
	}
	return false
}

func (c *Context) HasActionHook(key string) bool {
	return c.makross.HasActionHook(key)
}

func (m *Makross) AddActionHook(key string, function func(), priorities ...uint64) {
	m.AddFilterHook(key, func([]byte) []byte {
		function()
		return nil
	}, priorities...)
}

func (c *Context) AddActionHook(key string, function func(), priorities ...uint64) {
	c.AddFilterHook(key, func([]byte) []byte {
		function()
		return nil
	}, priorities...)
}

func (m *Makross) AddFilterHook(key string, function func([]byte) []byte, priorities ...uint64) {
	if !m.HasActionHook(key) {
		if m.QueuesMap == nil {
			m.QueuesMap = m.NewPriorityQueuesMap()
		}
		m.QueuesMap[key] = m.NewPriorityQueue()
	}

	var priority uint64
	if len(priorities) > 0 {
		priority = priorities[0]
	} else {
		//atomic.AddUint64(&ops, 1)
		priority = ops
	}

	m.QueuesMap[key].Push(&Node{priority: priority, key: key, callback: function})
}

func (c *Context) AddFilterHook(key string, function func([]byte) []byte, priorities ...uint64) {
	if !c.HasActionHook(key) {
		if c.makross.QueuesMap == nil {
			c.makross.QueuesMap = c.NewPriorityQueuesMap()
		}
		c.makross.QueuesMap[key] = c.NewPriorityQueue()
	}

	var priority uint64
	if len(priorities) > 0 {
		priority = priorities[0]
	} else {
		//atomic.AddUint64(&ops, 1)
		priority = ops
	}

	c.makross.QueuesMap[key].Push(&Node{priority: priority, key: key, callback: function})
}

// DoActionHook Global DoActionHook
func (m *Makross) DoActionHook(key string) {
	m.DoFilterHook(key, nil)
}

func (c *Context) DoActionHook(key string, globals ...bool) {
	c.DoFilterHook(key, nil, globals...)
}

// DoFilterHook Global DoFilterHook
func (m *Makross) DoFilterHook(key string, function func() []byte) []byte {

	if !m.HasActionHook(key) {
		m.AddFilterHook(key, func(b []byte) []byte {
			if function == nil {
				return b
			}
			return function()
		})
		return m.DoFilterHook(key, function)
	}

	if !m.HasFilterHook(key) {
		if m.FiltersMap == nil {
			m.FiltersMap = make(map[string][]byte)
		}
	}

	if m.HasActionHook(key) {
		for m.QueuesMap[key].Len() > 0 {
			n, okay := m.QueuesMap[key].Pop().(*Node)
			if !okay {
				continue
			}

			if function != nil { //for Global Filter
				if m.FiltersMap[key] != nil {
					m.FiltersMap[key] = n.callback(m.FiltersMap[key])
				} else {
					m.FiltersMap[key] = n.callback(function())
				}
			} else { //for Global Action
				m.FiltersMap[key] = n.callback(nil)
			}
		}
	}

	return m.FiltersMap[key]

}

func (c *Context) DoFilterHook(key string, function func() []byte, globals ...bool) []byte {

	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}

	var filterBytes []byte

	if !c.HasActionHook(key) {
		c.AddFilterHook(key, func(b []byte) []byte {
			if function == nil {
				return b
			}
			return function()
		})
		return c.DoFilterHook(key, function, globals...)
	}

	if global {
		if !c.makross.HasFilterHook(key) {
			if c.makross.FiltersMap == nil {
				c.makross.FiltersMap = make(map[string][]byte)
			}
		}
	} else {
		if !c.HasFilterHook(key) {
			if c.FiltersMap == nil {
				c.FiltersMap = make(map[string][]byte)
			}
		}
	}

	if c.HasActionHook(key) {
		for c.makross.QueuesMap[key].Len() > 0 {
			n, okay := c.makross.QueuesMap[key].Pop().(*Node)
			if !okay {
				continue
			}
			if global {
				if function != nil { //for Global Filter
					if c.makross.FiltersMap[key] != nil {
						c.makross.FiltersMap[key] = n.callback(c.makross.FiltersMap[key])
					} else {
						c.makross.FiltersMap[key] = n.callback(function())
					}
				} else { //for Global Action
					c.makross.FiltersMap[key] = n.callback(nil)
				}
				filterBytes = c.makross.FiltersMap[key]
			} else {
				if function != nil { //for Filter
					if c.FiltersMap[key] != nil {
						c.FiltersMap[key] = n.callback(c.FiltersMap[key])
					} else {
						c.FiltersMap[key] = n.callback(function())
					}
				} else { //for Action
					c.FiltersMap[key] = n.callback(nil)
				}
				filterBytes = c.FiltersMap[key]
			}

		}
	}

	return filterBytes

}
<commit_msg>fix DoFilterHook<commit_after>package makross

import (
	"pueue"
)

var (
	ops uint64 = 0
)

type Node struct {
	priority uint64
	key      string
	callback func([]byte) []byte
}

func (n *Node) Less(other interface{}) bool {
	return n.priority < other.(*Node).priority
}

func (m *Makross) NewPriorityQueue() *pueue.PriorityQueue {
	return pueue.New()
}

func (c *Context) NewPriorityQueue() *pueue.PriorityQueue {
	return c.makross.NewPriorityQueue()
}

func (m *Makross) NewPriorityQueuesMap() map[string]*pueue.PriorityQueue {
	return map[string]*pueue.PriorityQueue{}
}

func (c *Context) NewPriorityQueuesMap() map[string]*pueue.PriorityQueue {
	return c.makross.NewPriorityQueuesMap()
}

func (m *Makross) RemoveFilterHook(key string) {
	if m.HasFilterHook(key) {
		delete(m.FiltersMap, key)
	}
}

func (c *Context) RemoveFilterHook(key string, globals ...bool) {
	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}
	if global {
		c.makross.RemoveFilterHook(key)
	} else if c.HasFilterHook(key) {
		delete(c.FiltersMap, key)
	}
}

func (m *Makross) RemoveActionHook(key string) {
	if m.HasActionHook(key) {
		delete(m.QueuesMap, key)
		delete(m.FiltersMap, key)
	}
}

func (c *Context) RemoveActionHook(key string, globals ...bool) {
	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}
	if global {
		c.makross.RemoveActionHook(key)
	} else if c.HasActionHook(key) {
		delete(c.makross.QueuesMap, key)
		delete(c.FiltersMap, key)
	}
}

func (m *Makross) RemoveActionsHook() {
	m.QueuesMap = nil
}

func (c *Context) RemoveActionsHook() {
	c.makross.RemoveActionsHook()
}

func (m *Makross) HasFilterHook(key string) bool {
	if _, okay := m.FiltersMap[key]; okay {
		return true
	}
	return false
}

func (c *Context) HasFilterHook(key string, globals ...bool) bool {
	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}
	if global {
		return c.makross.HasFilterHook(key)
	} else if _, okay := c.FiltersMap[key]; okay {
		return true
	}
	return false
}

func (m *Makross) HasActionHook(key string) bool {
	if _, okay := m.QueuesMap[key]; okay {
		if _, okay := m.QueuesMap[key].Top().(*Node); okay {
			return true
		}
	}
	return false
}

func (c *Context) HasActionHook(key string) bool {
	return c.makross.HasActionHook(key)
}

func (m *Makross) AddActionHook(key string, function func(), priorities ...uint64) {
	m.AddFilterHook(key, func([]byte) []byte {
		function()
		return nil
	}, priorities...)
}

func (c *Context) AddActionHook(key string, function func(), priorities ...uint64) {
	c.AddFilterHook(key, func([]byte) []byte {
		function()
		return nil
	}, priorities...)
}

func (m *Makross) AddFilterHook(key string, function func([]byte) []byte, priorities ...uint64) {
	if !m.HasActionHook(key) {
		if m.QueuesMap == nil {
			m.QueuesMap = m.NewPriorityQueuesMap()
		}
		m.QueuesMap[key] = m.NewPriorityQueue()
	}

	var priority uint64
	if len(priorities) > 0 {
		priority = priorities[0]
	} else {
		//atomic.AddUint64(&ops, 1)
		priority = ops
	}

	m.QueuesMap[key].Push(&Node{priority: priority, key: key, callback: function})
}

func (c *Context) AddFilterHook(key string, function func([]byte) []byte, priorities ...uint64) {
	if !c.HasActionHook(key) {
		if c.makross.QueuesMap == nil {
			c.makross.QueuesMap = c.NewPriorityQueuesMap()
		}
		c.makross.QueuesMap[key] = c.NewPriorityQueue()
	}

	var priority uint64
	if len(priorities) > 0 {
		priority = priorities[0]
	} else {
		//atomic.AddUint64(&ops, 1)
		priority = ops
	}

	c.makross.QueuesMap[key].Push(&Node{priority: priority, key: key, callback: function})
}

// DoActionHook Global DoActionHook
func (m *Makross) DoActionHook(key string) {
	m.DoFilterHook(key, nil)
}

func (c *Context) DoActionHook(key string, globals ...bool) {
	c.DoFilterHook(key, nil, globals...)
}

// DoFilterHook Global DoFilterHook
func (m *Makross) DoFilterHook(key string, function func() []byte) []byte {

	if !m.HasActionHook(key) {
		m.AddFilterHook(key, func(b []byte) []byte {
			if function == nil {
				return b
			}
			return function()
		})
		return m.DoFilterHook(key, function)
	}

	if !m.HasFilterHook(key) {
		if m.FiltersMap == nil {
			m.FiltersMap = make(map[string][]byte)
		}
	}

	if m.HasActionHook(key) {
		for m.QueuesMap[key].Len() > 0 {
			n, okay := m.QueuesMap[key].Pop().(*Node)
			if !okay {
				continue
			}

			if function != nil { //for Global Filter
				if m.FiltersMap[key] != nil {
					m.FiltersMap[key] = n.callback(m.FiltersMap[key])
				} else {
					m.FiltersMap[key] = n.callback(function())
				}
			} else { //for Global Action
				m.FiltersMap[key] = n.callback(nil)
			}
		}
	}

	return m.FiltersMap[key]

}

func (c *Context) DoFilterHook(key string, function func() []byte, globals ...bool) []byte {

	var global = false
	if len(globals) > 0 {
		global = globals[0]
	}

	var filterBytes []byte

	if !c.HasActionHook(key) {
		c.AddFilterHook(key, func(b []byte) []byte {
			if function == nil {
				return b
			}
			return function()
		})
		return c.DoFilterHook(key, function, globals...)
	}

	if !c.HasFilterHook(key, global) {
		if global {
			if c.makross.FiltersMap == nil {
				c.makross.FiltersMap = make(map[string][]byte)
			}
		} else {
			if c.FiltersMap == nil {
				c.FiltersMap = make(map[string][]byte)
			}
		}
	}

	if c.HasActionHook(key) {
		for c.makross.QueuesMap[key].Len() > 0 {
			n, okay := c.makross.QueuesMap[key].Pop().(*Node)
			if !okay {
				continue
			}
			if global {
				if function != nil { //for Global Filter
					if c.makross.FiltersMap[key] != nil {
						c.makross.FiltersMap[key] = n.callback(c.makross.FiltersMap[key])
					} else {
						c.makross.FiltersMap[key] = n.callback(function())
					}
				} else { //for Global Action
					c.makross.FiltersMap[key] = n.callback(nil)
				}
				filterBytes = c.makross.FiltersMap[key]
			} else {
				if function != nil { //for Filter
					if c.FiltersMap[key] != nil {
						c.FiltersMap[key] = n.callback(c.FiltersMap[key])
					} else {
						c.FiltersMap[key] = n.callback(function())
					}
				} else { //for Action
					c.FiltersMap[key] = n.callback(nil)
				}
				filterBytes = c.FiltersMap[key]
			}

		}
	}

	return filterBytes

}
<|endoftext|>