<commit_before>package main

// Functions connected with parsing data form original statsd format

import (
	"bytes"
	"io"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
)

// GaugeData - struct for gauges :)
type GaugeData struct {
	Relative bool
	Negative bool
	Value    float64
}

// Packet - meter definition, read from statsd format
type Packet struct {
	Bucket      string
	Value       interface{}
	SrcBucket   string
	CleanBucket string
	// Tags        map[string]string
	Modifier string
	Sampling float32
}

func parseTo(conn io.ReadCloser, partialReads bool, out chan<- *Packet) {
	defer conn.Close()

	parser := NewParser(conn, partialReads)
	for {
		p, more := parser.Next()
		if p != nil {
			out <- p
		}

		if !more {
			break
		}
	}
}

// MsgParser - struct for reading data from UDP/TCP packet
type MsgParser struct {
	reader       io.Reader
	buffer       []byte
	partialReads bool
	done         bool
}

// NewParser - for UDP/TCP packet
func NewParser(reader io.Reader, partialReads bool) *MsgParser {
	return &MsgParser{reader, []byte{}, partialReads, false}
}

// Next - for reading whole meter data from packet
// return *Packet parsed from raw data
func (mp *MsgParser) Next() (*Packet, bool) {

	logCtx := log.WithFields(log.Fields{
		"in":  "MsgParser Next",
		"ctx": "Parse packet",
	})
	buf := mp.buffer

	for {

		line, rest := mp.lineFrom(buf)

		if line != nil {
			mp.buffer = rest
			return parseLine(line), true
		}

		if mp.done {
			return parseLine(rest), false
		}

		idx := len(buf)
		end := idx
		if mp.partialReads {
			end += tcpReadSize
		} else {
			end += int(Config.MaxUDPPacketSize)
		}
		if cap(buf) >= end {
			buf = buf[:end]
		} else {
			tmp := buf
			buf = make([]byte, end)
			copy(buf, tmp)
		}

		n, err := mp.reader.Read(buf[idx:])
		buf = buf[:idx+n]
		if err != nil {
			if err != io.EOF {
				logCtx.WithField("after", "Read").Errorf("%s", err)
				Stat.ErrorIncr()
			}

			mp.done = true

			line, rest = mp.lineFrom(buf)
			if line != nil {
				mp.buffer = rest
				return parseLine(line), len(rest) > 0
			}

			if len(rest) > 0 {
				return parseLine(rest), false
			}

			return nil, false
		}
	}
}

func (mp *MsgParser) lineFrom(input []byte) ([]byte, []byte) {

	split := bytes.SplitAfterN(input, []byte("\n"), 2)
	if len(split) == 2 {
		return split[0][:len(split[0])-1], split[1]
	}

	if !mp.partialReads {
		if len(input) == 0 {
			input = nil
		}
		return input, []byte{}
	}

	if bytes.HasSuffix(input, []byte("\n")) {
		return input[:len(input)-1], []byte{}
	}

	return nil, input
}

func parseLine(line []byte) *Packet {

	logCtx := log.WithFields(log.Fields{
		"in":  "parseLine",
		"ctx": "Parse packet",
	})

	tagsFromBucketName := make(map[string]string)

	logCtx.WithField("after", "parseLine").Debugf("Input packet line: %s", string(line))

	split := bytes.SplitN(line, []byte{'|'}, 3)
	if len(split) < 2 {
		logCtx.WithField("after", "parseLine").Errorf("Failed to parse line: %s", line)
		Stat.ErrorIncr()
		return nil
	}

	keyval := split[0]
	typeCode := string(split[1]) // expected c, g, s, ms, kv

	sampling := float32(1)
	if strings.HasPrefix(typeCode, "c") || strings.HasPrefix(typeCode, "ms") {
		if len(split) == 3 && len(split[2]) > 0 && split[2][0] == '@' {
			f64, err := strconv.ParseFloat(string(split[2][1:]), 32)
			if err != nil {
				logCtx.WithField("after", "ParseFloat").Errorf("Failed to ParseFloat %s - %s", string(split[2][1:]), err)
				Stat.ErrorIncr()
				return nil
			}
			sampling = float32(f64)
		}
	}

	split = bytes.SplitN(keyval, []byte{':'}, 2)
	if len(split) < 2 {
		logCtx.WithField("after", "parseLine").Errorf("Failed to parse line: %s", line)
		Stat.ErrorIncr()
		return nil
	}
	// raw bucket name from line
	name := string(split[0])
	val := split[1]
	if len(val) == 0 {
		logCtx.WithField("after", "parseLine").Errorf("Failed to parse line: %s", line)
		Stat.ErrorIncr()
		return nil
	}

	var (
		err         error
		value       interface{}
		bucket      string
		cleanBucket string
	)

	switch typeCode {
	case "c":
		value, err = strconv.ParseInt(string(val), 10, 64)
		if err != nil {
			logCtx.WithField("after", "Counter - ParseInt").Errorf("Failed to ParseInt %s - %s", string(val), err)
			Stat.ErrorIncr()
			return nil
		}
	case "g":
		var rel, neg bool
		var s string

		switch val[0] {
		case '+':
			rel = true
			neg = false
			s = string(val[1:])
		case '-':
			rel = true
			neg = true
			s = string(val[1:])
		default:
			rel = false
			neg = false
			s = string(val)
		}

		value, err = strconv.ParseFloat(s, 64)
		if err != nil {
			logCtx.WithField("after", "Gauge - ParseFloat").Errorf("Failed to ParseFloat %s - %s", string(val), err)
			Stat.ErrorIncr()
			return nil
		}

		value = GaugeData{rel, neg, value.(float64)}
	case "s":
		value = string(val)
	case "ms":
		value, err = strconv.ParseFloat(string(val), 64)
		if err != nil {
			logCtx.WithField("after", "Timer - ParseFloat").Errorf("Failed to ParseFloat %s - %s", string(val), err)
			Stat.ErrorIncr()
			return nil
		}
	case "kv":
		value = string(val) // Key/value should not need transformation
	default:
		logCtx.WithField("after", "default").Errorf("Unrecognized type code %q", typeCode)
		Stat.ErrorIncr()
		return nil
	}

	// parse tags from bucket name
	tagsFromBucketName = map[string]string{}
	cleanBucket, tagsFromBucketName, err = parseBucketAndTags(string(name))
	if err != nil {
		logCtx.WithField("after", "parseBucketAndTags").Errorf("Problem parsing %s (clean version %s): %v\n", string(name), cleanBucket, err)
		Stat.ErrorIncr()
		return nil
	}

	// bucket is set to a name WITH tags
	firstDelim := ""
	if len(tagsFromBucketName) > 0 || len(Config.ExtraTagsHash) > 0 {
		firstDelim, _, _ = tagsDelims(tfDefault)
	}
	bucket = Config.Prefix + sanitizeBucket(cleanBucket) + firstDelim + normalizeTags(addTags(tagsFromBucketName, Config.ExtraTagsHash), tfDefault)

	return &Packet{
		Bucket:      bucket,
		Value:       value,
		SrcBucket:   string(name),
		CleanBucket: cleanBucket,
		// Tags:        tagsFromBucketName,
		Modifier: typeCode,
		Sampling: sampling,
	}
}

func sanitizeBucket(bucket string) string {
	b := make([]byte, len(bucket))
	var bl int

	for i := 0; i < len(bucket); i++ {
		c := bucket[i]
		switch {
		case (c >= byte('a') && c <= byte('z')) || (c >= byte('A') && c <= byte('Z')) || (c >= byte('0') && c <= byte('9')) || c == byte('-') || c == byte('.') || c == byte('_'):
			b[bl] = c
			bl++
		case c == byte(' '):
			b[bl] = byte('_')
			bl++
		case c == byte('/'):
			b[bl] = byte('-')
			bl++
		}
	}
	return string(b[:bl])
}

func removeEmptyLines(lines []string) []string {
	var outLines []string

	for _, v := range lines {
		if len(v) > 0 {
			outLines = append(outLines, v)
		}
	}
	return outLines
}

func fixNewLine(s string) string {
	return strings.Replace(s, "\n", "\\n", -1)
}
<commit_msg>small log changes<commit_after>package main

// Functions connected with parsing data form original statsd format

import (
	"bytes"
	"io"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
)

// GaugeData - struct for gauges :)
type GaugeData struct {
	Relative bool
	Negative bool
	Value    float64
}

// Packet - meter definition, read from statsd format
type Packet struct {
	Bucket      string
	Value       interface{}
	SrcBucket   string
	CleanBucket string
	// Tags        map[string]string
	Modifier string
	Sampling float32
}

func parseTo(conn io.ReadCloser, partialReads bool, out chan<- *Packet) {
	defer conn.Close()

	parser := NewParser(conn, partialReads)
	for {
		p, more := parser.Next()
		if p != nil {
			out <- p
		}

		if !more {
			break
		}
	}
}

// MsgParser - struct for reading data from UDP/TCP packet
type MsgParser struct {
	reader       io.Reader
	buffer       []byte
	partialReads bool
	done         bool
}

// NewParser - for UDP/TCP packet
func NewParser(reader io.Reader, partialReads bool) *MsgParser {
	return &MsgParser{reader, []byte{}, partialReads, false}
}

// Next - for reading whole meter data from packet
// return *Packet parsed from raw data
func (mp *MsgParser) Next() (*Packet, bool) {

	logCtx := log.WithFields(log.Fields{
		"in":  "MsgParser Next",
		"ctx": "Parse packet",
	})
	buf := mp.buffer

	for {

		line, rest := mp.lineFrom(buf)

		if line != nil {
			mp.buffer = rest
			return parseLine(line), true
		}

		if mp.done {
			return parseLine(rest), false
		}

		idx := len(buf)
		end := idx
		if mp.partialReads {
			end += tcpReadSize
		} else {
			end += int(Config.MaxUDPPacketSize)
		}
		if cap(buf) >= end {
			buf = buf[:end]
		} else {
			tmp := buf
			buf = make([]byte, end)
			copy(buf, tmp)
		}

		n, err := mp.reader.Read(buf[idx:])
		buf = buf[:idx+n]
		if err != nil {
			if err != io.EOF {
				logCtx.WithField("after", "Read").Errorf("%s", err)
				Stat.ErrorIncr()
			}

			mp.done = true

			line, rest = mp.lineFrom(buf)
			if line != nil {
				mp.buffer = rest
				return parseLine(line), len(rest) > 0
			}

			if len(rest) > 0 {
				return parseLine(rest), false
			}

			return nil, false
		}
	}
}

func (mp *MsgParser) lineFrom(input []byte) ([]byte, []byte) {

	split := bytes.SplitAfterN(input, []byte("\n"), 2)
	if len(split) == 2 {
		return split[0][:len(split[0])-1], split[1]
	}

	if !mp.partialReads {
		if len(input) == 0 {
			input = nil
		}
		return input, []byte{}
	}

	if bytes.HasSuffix(input, []byte("\n")) {
		return input[:len(input)-1], []byte{}
	}

	return nil, input
}

func parseLine(line []byte) *Packet {

	logCtx := log.WithFields(log.Fields{
		"in":  "parseLine",
		"ctx": "Parse packet",
	})

	tagsFromBucketName := make(map[string]string)

	logCtx.WithField("after", "parseLine").Debugf("Input packet line: %s", string(line))

	split := bytes.SplitN(line, []byte{'|'}, 3)
	if len(split) < 2 {
		logCtx.WithField("after", "parseLine").Errorf("Failed to parse line: %s", line)
		Stat.ErrorIncr()
		return nil
	}

	keyval := split[0]
	typeCode := string(split[1]) // expected c, g, s, ms, kv

	sampling := float32(1)
	if strings.HasPrefix(typeCode, "c") || strings.HasPrefix(typeCode, "ms") {
		if len(split) == 3 && len(split[2]) > 0 && split[2][0] == '@' {
			f64, err := strconv.ParseFloat(string(split[2][1:]), 32)
			if err != nil {
				logCtx.WithField("after", "ParseFloat").Errorf("Failed to ParseFloat %s - %s", string(split[2][1:]), err)
				Stat.ErrorIncr()
				return nil
			}
			sampling = float32(f64)
		}
	}

	split = bytes.SplitN(keyval, []byte{':'}, 2)
	if len(split) < 2 {
		logCtx.WithField("after", "parseLine").Errorf("Failed to parse line: %s", line)
		Stat.ErrorIncr()
		return nil
	}
	// raw bucket name from line
	name := string(split[0])
	val := split[1]
	if len(val) == 0 {
		logCtx.WithField("after", "parseLine").Errorf("Failed to parse line: %s", line)
		Stat.ErrorIncr()
		return nil
	}

	var (
		err         error
		value       interface{}
		bucket      string
		cleanBucket string
	)

	switch typeCode {
	case "c":
		value, err = strconv.ParseInt(string(val), 10, 64)
		if err != nil {
			logCtx.WithField("after", "Counter - ParseInt").Errorf("Failed to ParseInt %s - %s, raw bucket: %s, line: %s", string(val), err,name,line)
			Stat.ErrorIncr()
			return nil
		}
	case "g":
		var rel, neg bool
		var s string

		switch val[0] {
		case '+':
			rel = true
			neg = false
			s = string(val[1:])
		case '-':
			rel = true
			neg = true
			s = string(val[1:])
		default:
			rel = false
			neg = false
			s = string(val)
		}

		value, err = strconv.ParseFloat(s, 64)
		if err != nil {
			logCtx.WithField("after", "Gauge - ParseFloat").Errorf("Failed to ParseFloat %s - %s, raw bucket: %s, line: %s", string(val), err,name,line)
			Stat.ErrorIncr()
			return nil
		}

		value = GaugeData{rel, neg, value.(float64)}
	case "s":
		value = string(val)
	case "ms":
		value, err = strconv.ParseFloat(string(val), 64)
		if err != nil {
			logCtx.WithField("after", "Timer - ParseFloat").Errorf("Failed to ParseFloat %s - %s, raw bucket: %s,, line: %s", string(val), err,name,line)
			Stat.ErrorIncr()
			return nil
		}
	case "kv":
		value = string(val) // Key/value should not need transformation
	default:
		logCtx.WithField("after", "default").Errorf("Unrecognized type code %q, raw bucket: %s, line: %s", typeCode, name,line)
		Stat.ErrorIncr()
		return nil
	}

	// parse tags from bucket name
	tagsFromBucketName = map[string]string{}
	cleanBucket, tagsFromBucketName, err = parseBucketAndTags(string(name))
	if err != nil {
		logCtx.WithField("after", "parseBucketAndTags").Errorf("Problem parsing %s (clean version %s): %v\n", string(name), cleanBucket, err)
		Stat.ErrorIncr()
		return nil
	}

	// bucket is set to a name WITH tags
	firstDelim := ""
	if len(tagsFromBucketName) > 0 || len(Config.ExtraTagsHash) > 0 {
		firstDelim, _, _ = tagsDelims(tfDefault)
	}
	bucket = Config.Prefix + sanitizeBucket(cleanBucket) + firstDelim + normalizeTags(addTags(tagsFromBucketName, Config.ExtraTagsHash), tfDefault)

	return &Packet{
		Bucket:      bucket,
		Value:       value,
		SrcBucket:   string(name),
		CleanBucket: cleanBucket,
		// Tags:        tagsFromBucketName,
		Modifier: typeCode,
		Sampling: sampling,
	}
}

func sanitizeBucket(bucket string) string {
	b := make([]byte, len(bucket))
	var bl int

	for i := 0; i < len(bucket); i++ {
		c := bucket[i]
		switch {
		case (c >= byte('a') && c <= byte('z')) || (c >= byte('A') && c <= byte('Z')) || (c >= byte('0') && c <= byte('9')) || c == byte('-') || c == byte('.') || c == byte('_'):
			b[bl] = c
			bl++
		case c == byte(' '):
			b[bl] = byte('_')
			bl++
		case c == byte('/'):
			b[bl] = byte('-')
			bl++
		}
	}
	return string(b[:bl])
}

func removeEmptyLines(lines []string) []string {
	var outLines []string

	for _, v := range lines {
		if len(v) > 0 {
			outLines = append(outLines, v)
		}
	}
	return outLines
}

func fixNewLine(s string) string {
	return strings.Replace(s, "\n", "\\n", -1)
}
<|endoftext|>


<commit_before>package parser

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
)

func normalizePath(path string) string {
	// use lower case, as Windows file systems will almost always be case insensitive
	return strings.ToLower(strings.Replace(path, "\\", "/", -1))
}

func getPkgPath(fname string, isDir bool) (string, error) {
	// path.IsAbs doesn't work properly on Windows; use filepath.IsAbs instead
	if !filepath.IsAbs(fname) {
		pwd, err := os.Getwd()
		if err != nil {
			return "", err
		}
		fname = path.Join(pwd, fname)
	}

	fname = normalizePath(fname)

	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		var err error
		gopath, err = getDefaultGoPath()
		if err != nil {
			return "", fmt.Errorf("cannot determine GOPATH: %s", err)
		}
	}

	for _, p := range strings.Split(os.Getenv("GOPATH"), ";") {
		prefix := path.Join(normalizePath(p), "src") + "/"
		if rel := strings.TrimPrefix(fname, prefix); rel != fname {
			if !isDir {
				return path.Dir(rel), nil
			} else {
				return path.Clean(rel), nil
			}
		}
	}

	return "", fmt.Errorf("file '%v' is not in GOPATH", fname)
}
<commit_msg>Removed Windows path lower-case conversion.<commit_after>package parser

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
)

func normalizePath(path string) string {
	return strings.Replace(path, "\\", "/", -1)
}

func getPkgPath(fname string, isDir bool) (string, error) {
	// path.IsAbs doesn't work properly on Windows; use filepath.IsAbs instead
	if !filepath.IsAbs(fname) {
		pwd, err := os.Getwd()
		if err != nil {
			return "", err
		}
		fname = path.Join(pwd, fname)
	}

	fname = normalizePath(fname)

	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		var err error
		gopath, err = getDefaultGoPath()
		if err != nil {
			return "", fmt.Errorf("cannot determine GOPATH: %s", err)
		}
	}

	for _, p := range strings.Split(os.Getenv("GOPATH"), ";") {
		prefix := path.Join(normalizePath(p), "src") + "/"
		if rel := strings.TrimPrefix(fname, prefix); rel != fname {
			if !isDir {
				return path.Dir(rel), nil
			} else {
				return path.Clean(rel), nil
			}
		}
	}

	return "", fmt.Errorf("file '%v' is not in GOPATH", fname)
}
<|endoftext|>


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

package server

import (
	log "github.com/Sirupsen/logrus"
	"github.com/osrg/gobgp/packet"
	"github.com/osrg/gobgp/table"
	"github.com/osrg/gobgp/zebra"
	"net"
	"strconv"
	"strings"
	"time"
)

type broadcastZapiMsg struct {
	client *zebra.Client
	msg    *zebra.Message
}

func (m *broadcastZapiMsg) send() {
	m.client.Send(m.msg)
}

func newIPRouteMessage(path *table.Path) *zebra.Message {
	l := strings.SplitN(path.GetNlri().String(), "/", 2)
	var command zebra.API_TYPE
	var prefix net.IP
	nexthops := []net.IP{}
	switch path.GetRouteFamily() {
	case bgp.RF_IPv4_UC:
		if path.IsWithdraw == true {
			command = zebra.IPV4_ROUTE_DELETE
		} else {
			command = zebra.IPV4_ROUTE_ADD
		}
		prefix = net.ParseIP(l[0]).To4()
		nexthops = append(nexthops, path.GetNexthop().To4())
	case bgp.RF_IPv6_UC:
		if path.IsWithdraw == true {
			command = zebra.IPV6_ROUTE_DELETE
		} else {
			command = zebra.IPV6_ROUTE_ADD
		}
		prefix = net.ParseIP(l[0]).To16()
		nexthops = append(nexthops, path.GetNexthop().To16())
	default:
		return nil
	}

	flags := uint8(zebra.MESSAGE_NEXTHOP)
	plen, _ := strconv.Atoi(l[1])
	med, err := path.GetMed()
	if err == nil {
		flags |= zebra.MESSAGE_METRIC
	}
	return &zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HEADER_SIZE,
			Marker:  zebra.HEADER_MARKER,
			Version: zebra.VERSION,
			Command: command,
		},
		Body: &zebra.IPRouteBody{
			Type:         zebra.ROUTE_BGP,
			SAFI:         zebra.SAFI_UNICAST,
			Message:      flags,
			Prefix:       prefix,
			PrefixLength: uint8(plen),
			Nexthops:     nexthops,
			Metric:       med,
		},
	}
}

func createPathFromIPRouteMessage(m *zebra.Message, peerInfo *table.PeerInfo) *table.Path {

	header := m.Header
	body := m.Body.(*zebra.IPRouteBody)
	isV4 := header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE

	var nlri bgp.AddrPrefixInterface
	pattr := make([]bgp.PathAttributeInterface, 0)
	var mpnlri *bgp.PathAttributeMpReachNLRI
	var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE

	origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)
	pattr = append(pattr, origin)

	log.WithFields(log.Fields{
		"Topic":        "Zebra",
		"RouteType":    body.Type.String(),
		"Flag":         body.Flags.String(),
		"Message":      body.Message,
		"Prefix":       body.Prefix,
		"PrefixLength": body.PrefixLength,
		"Nexthop":      body.Nexthops,
		"api":          header.Command.String(),
	}).Debugf("create path from ip route message.")

	if isV4 {
		nlri = bgp.NewNLRInfo(body.PrefixLength, body.Prefix.String())
		nexthop := bgp.NewPathAttributeNextHop("0.0.0.0")
		pattr = append(pattr, nexthop)
	} else {
		nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String())
		mpnlri = bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})
		pattr = append(pattr, mpnlri)
	}

	med := bgp.NewPathAttributeMultiExitDisc(body.Metric)
	pattr = append(pattr, med)

	p := table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), true)
	p.IsFromZebra = true
	return p
}

func newBroadcastZapiBestMsg(cli *zebra.Client, path *table.Path) *broadcastZapiMsg {
	if cli == nil {
		return nil
	}
	m := newIPRouteMessage(path)
	if m == nil {
		return nil
	}
	return &broadcastZapiMsg{
		client: cli,
		msg:    m,
	}
}

func handleZapiMsg(msg *zebra.Message, server *BgpServer) []*SenderMsg {

	switch b := msg.Body.(type) {
	case *zebra.IPRouteBody:
		pi := &table.PeerInfo{
			AS:      server.bgpConfig.Global.GlobalConfig.As,
			LocalID: server.bgpConfig.Global.GlobalConfig.RouterId,
		}

		if b.Prefix != nil && len(b.Nexthops) > 0 && b.Type != zebra.ROUTE_KERNEL {
			p := createPathFromIPRouteMessage(msg, pi)
			msgs := server.propagateUpdate("", false, []*table.Path{p})
			return msgs
		}
	}

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

package server

import (
	log "github.com/Sirupsen/logrus"
	"github.com/osrg/gobgp/packet"
	"github.com/osrg/gobgp/table"
	"github.com/osrg/gobgp/zebra"
	"net"
	"strconv"
	"strings"
	"time"
)

type broadcastZapiMsg struct {
	client *zebra.Client
	msg    *zebra.Message
}

func (m *broadcastZapiMsg) send() {
	m.client.Send(m.msg)
}

func newIPRouteMessage(path *table.Path) *zebra.Message {
	l := strings.SplitN(path.GetNlri().String(), "/", 2)
	var command zebra.API_TYPE
	var prefix net.IP
	nexthops := []net.IP{}
	switch path.GetRouteFamily() {
	case bgp.RF_IPv4_UC:
		if path.IsWithdraw == true {
			command = zebra.IPV4_ROUTE_DELETE
		} else {
			command = zebra.IPV4_ROUTE_ADD
		}
		prefix = net.ParseIP(l[0]).To4()
		nexthops = append(nexthops, path.GetNexthop().To4())
	case bgp.RF_IPv6_UC:
		if path.IsWithdraw == true {
			command = zebra.IPV6_ROUTE_DELETE
		} else {
			command = zebra.IPV6_ROUTE_ADD
		}
		prefix = net.ParseIP(l[0]).To16()
		nexthops = append(nexthops, path.GetNexthop().To16())
	default:
		return nil
	}

	flags := uint8(zebra.MESSAGE_NEXTHOP)
	plen, _ := strconv.Atoi(l[1])
	med, err := path.GetMed()
	if err == nil {
		flags |= zebra.MESSAGE_METRIC
	}
	return &zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HEADER_SIZE,
			Marker:  zebra.HEADER_MARKER,
			Version: zebra.VERSION,
			Command: command,
		},
		Body: &zebra.IPRouteBody{
			Type:         zebra.ROUTE_BGP,
			SAFI:         zebra.SAFI_UNICAST,
			Message:      flags,
			Prefix:       prefix,
			PrefixLength: uint8(plen),
			Nexthops:     nexthops,
			Metric:       med,
		},
	}
}

func createPathFromIPRouteMessage(m *zebra.Message, peerInfo *table.PeerInfo) *table.Path {

	header := m.Header
	body := m.Body.(*zebra.IPRouteBody)
	isV4 := header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE

	var nlri bgp.AddrPrefixInterface
	pattr := make([]bgp.PathAttributeInterface, 0)
	var mpnlri *bgp.PathAttributeMpReachNLRI
	var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE

	origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)
	pattr = append(pattr, origin)

	log.WithFields(log.Fields{
		"Topic":        "Zebra",
		"RouteType":    body.Type.String(),
		"Flag":         body.Flags.String(),
		"Message":      body.Message,
		"Prefix":       body.Prefix,
		"PrefixLength": body.PrefixLength,
		"Nexthop":      body.Nexthops,
		"Metric":       body.Metric,
		"Distance":     body.Distance,
		"api":          header.Command.String(),
	}).Debugf("create path from ip route message.")

	if isV4 {
		nlri = bgp.NewNLRInfo(body.PrefixLength, body.Prefix.String())
		nexthop := bgp.NewPathAttributeNextHop("0.0.0.0")
		pattr = append(pattr, nexthop)
	} else {
		nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String())
		mpnlri = bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})
		pattr = append(pattr, mpnlri)
	}

	med := bgp.NewPathAttributeMultiExitDisc(body.Metric)
	pattr = append(pattr, med)

	p := table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), true)
	p.IsFromZebra = true
	return p
}

func newBroadcastZapiBestMsg(cli *zebra.Client, path *table.Path) *broadcastZapiMsg {
	if cli == nil {
		return nil
	}
	m := newIPRouteMessage(path)
	if m == nil {
		return nil
	}
	return &broadcastZapiMsg{
		client: cli,
		msg:    m,
	}
}

func handleZapiMsg(msg *zebra.Message, server *BgpServer) []*SenderMsg {

	switch b := msg.Body.(type) {
	case *zebra.IPRouteBody:
		pi := &table.PeerInfo{
			AS:      server.bgpConfig.Global.GlobalConfig.As,
			LocalID: server.bgpConfig.Global.GlobalConfig.RouterId,
		}

		if b.Prefix != nil && len(b.Nexthops) > 0 && b.Type != zebra.ROUTE_KERNEL {
			p := createPathFromIPRouteMessage(msg, pi)
			msgs := server.propagateUpdate("", false, []*table.Path{p})
			return msgs
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

type Ident struct {
	level        int
	padding      string
	prompt       string
	promptActive bool
}

var defaultIdent Ident = Ident{
	level:        0,
	padding:      "  ",
	prompt:       "* ",
	promptActive: false,
}

func viewServerText(options *ServerQueryOptions, servers []ServerAttrPair) {
	for _, server := range servers {
		textFormatServer(server, defaultIdent, options)
		fmt.Println("\n")
	}
}

func textFormatServer(server ServerAttrPair, ident Ident, options *ServerQueryOptions) {
	ident.Println("Server: ", server.Attrs.Address)
	ident.level++

	textFormatServerInfo(server.Attrs.Info, ident, options)
}

func textFormatServerInfo(info MaybeInfo, ident Ident, options *ServerQueryOptions) {
	if options.NoInfo {
		return
	}

	ident.Println("Info:")
	ident.level++

	if info.Error != nil {
		ident.Println("Error fetching server info: ", info.Error.Error())
		return
	}

	// TODO: Use fields by hand
	// Let package JSON do the hard reflection work for us.

	jsobj, err := json.Marshal(info.Info)
	if err != nil {
		ident.Println("Error marshalling json: ", err.Error())
	}

	mapped := make(map[string]interface{})

	err = json.Unmarshal(jsobj, &mapped)
	if err != nil {
		ident.Println("Error unmarshalling json: ", err.Error())
	}

	maxKeySize := 0

	for key, _ := range mapped {
		keySize := len(key)
		if keySize > maxKeySize {
			maxKeySize = keySize
		}
	}

	pad := func(n int) string {
		return strings.Repeat(" ", n)
	}

	for key, val := range mapped {
		ident.Printf("| %s:%s %v\n", key, pad(maxKeySize-len(key)), val)
	}
}

func (ident *Ident) Println(args ...interface{}) {
	fmt.Print(ident.GetPrefix())
	fmt.Println(args...)
}

func (ident *Ident) Printf(format string, args ...interface{}) {
	fmt.Print(ident.GetPrefix())
	fmt.Printf(format, args...)
}

func (ident *Ident) GetPrefix() string {
	return strings.Repeat(ident.padding, ident.level)
}
<commit_msg>Don't display SteamID as a float, sort by Key<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"
)

type Ident struct {
	level        int
	padding      string
	prompt       string
	promptActive bool
}

var defaultIdent Ident = Ident{
	level:        0,
	padding:      "  ",
	prompt:       "* ",
	promptActive: false,
}

func viewServerText(options *ServerQueryOptions, servers []ServerAttrPair) {
	for _, server := range servers {
		textFormatServer(server, defaultIdent, options)
		fmt.Println("\n")
	}
}

func textFormatServer(server ServerAttrPair, ident Ident, options *ServerQueryOptions) {
	ident.Println("Server: ", server.Attrs.Address)
	ident.level++

	textFormatServerInfo(server.Attrs.Info, ident, options)
}

func textFormatServerInfo(info MaybeInfo, ident Ident, options *ServerQueryOptions) {
	if options.NoInfo {
		return
	}

	ident.Println("Info:")
	ident.level++

	if info.Error != nil {
		ident.Println("Error fetching server info: ", info.Error.Error())
		return
	}

	// TODO: Use fields by hand
	// Let package JSON do the hard reflection work for us.

	jsobj, err := json.Marshal(info.Info)
	if err != nil {
		ident.Println("Error marshalling json: ", err.Error())
	}

	mapped := make(map[string]interface{})

	err = json.Unmarshal(jsobj, &mapped)
	if err != nil {
		ident.Println("Error unmarshalling json: ", err.Error())
	}

	maxKeySize := 0

	for key, _ := range mapped {
		keySize := len(key)
		if keySize > maxKeySize {
			maxKeySize = keySize
		}
	}

	pad := func(n int) string {
		return strings.Repeat(" ", n)
	}

	filters := map[string]func(interface{}) interface{}{
		"SteamID": func(interface{}) interface{} {
			return info.Info.GetSteamID()
		},
	}

	keys := getKeys(mapped)
	sort.Strings(keys)

	for _, key := range keys {
		val := mapped[key]

		if _, ok := filters[key]; ok {
			val = filters[key](val)
		}

		ident.Printf("| %s:%s %v\n", key, pad(maxKeySize-len(key)), val)
	}
}

func (ident *Ident) Println(args ...interface{}) {
	fmt.Print(ident.GetPrefix())
	fmt.Println(args...)
}

func (ident *Ident) Printf(format string, args ...interface{}) {
	fmt.Print(ident.GetPrefix())
	fmt.Printf(format, args...)
}

func (ident *Ident) GetPrefix() string {
	return strings.Repeat(ident.padding, ident.level)
}

func getKeys(amap map[string]interface{}) []string {
	keys := make([]string, 0, len(amap))
	for key, _ := range amap {
		keys = append(keys, key)
	}
	return keys
}
<|endoftext|>


<commit_before>package toolbox

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"reflect"
	"strings"
	"time"
)

var jsonContentType = "application/json"
var textPlainContentType = "text/plain"

const (
	MethodGet     = "GET"
	MethodHead    = "HEAD"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodPatch   = "PATCH" // RFC 5789
	MethodDelete  = "DELETE"
	MethodOptions = "OPTIONS"
	MethodTrace   = "TRACE"
)

var httpMethods = map[string]bool{
	MethodDelete:  true,
	MethodGet:     true,
	MethodPatch:   true,
	MethodPost:    true,
	MethodPut:     true,
	MethodHead:    true,
	MethodTrace:   true,
	MethodOptions: true,
}

//HandlerInvoker method is responsible  of passing required parameters to router handler.
type HandlerInvoker func(serviceRouting *ServiceRouting, request *http.Request, response http.ResponseWriter, parameters map[string]interface{}) error

//DefaultEncoderFactory  - NewJSONEncoderFactory
var DefaultEncoderFactory = NewJSONEncoderFactory()

//DefaultDecoderFactory - NewJSONDecoderFactory
var DefaultDecoderFactory = NewJSONDecoderFactory()

//ServiceRouting represents a simple web services routing rule, which is matched with http request
type ServiceRouting struct {
	URI                 string      //matching uri
	Handler             interface{} //has to be func
	HTTPMethod          string
	Parameters          []string
	ContentTypeEncoders map[string]EncoderFactory //content type encoder factory
	ContentTypeDecoders map[string]DecoderFactory //content type decoder factory
	HandlerInvoker      HandlerInvoker            //optional function that will be used instead of reflection to invoke a handler.
}

func (sr ServiceRouting) getDecoderFactory(contentType string) DecoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeDecoders[contentType]; found {
			return factory
		}
	}
	return DefaultDecoderFactory
}

func (sr ServiceRouting) getEncoderFactory(contentType string) EncoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeEncoders[contentType]; found {
			return factory
		}
	}
	return DefaultEncoderFactory
}

func (sr ServiceRouting) extractParameterFromBody(parameterName string, targetType reflect.Type, request *http.Request) (interface{}, error) {
	targetValuePointer := reflect.New(targetType)
	contentType := getContentTypeOrJSONContentType(request.Header.Get("Content-Type"))
	decoderFactory := sr.getDecoderFactory(contentType)
	decoder := decoderFactory.Create(request.Body)
	if !strings.Contains(parameterName, ":") {
		err := decoder.Decode(targetValuePointer.Interface())
		if err != nil {
			return nil, fmt.Errorf("unable to extract %T due to %v", targetValuePointer.Interface(), err)
		}
	} else {
		var valueMap = make(map[string]interface{})
		pair := strings.SplitN(parameterName, ":", 2)
		valueMap[pair[1]] = targetValuePointer.Interface()
		err := decoder.Decode(&valueMap)
		if err != nil {
			return nil, fmt.Errorf("unable to extract %T due to %v", targetValuePointer.Interface(), err)
		}
	}
	return targetValuePointer.Interface(), nil
}

func (sr ServiceRouting) extractParameters(request *http.Request, response http.ResponseWriter) (map[string]interface{}, error) {
	var result = make(map[string]interface{})
	request.ParseForm()
	functionSignature := GetFuncSignature(sr.Handler)
	uriParameters, _ := ExtractURIParameters(sr.URI, request.RequestURI)
	for _, name := range sr.Parameters {
		value, found := uriParameters[name]
		if found {
			if strings.Contains(value, ",") {
				result[name] = strings.Split(value, ",")
			} else {
				result[name] = value
			}
			continue
		}

		value = request.Form.Get(name)
		if len(value) > 0 {
			result[name] = value
		} else {
			continue
		}
	}
	if HasSliceAnyElements(sr.Parameters, "@httpRequest") {
		result["@httpRequest"] = request
	}
	if HasSliceAnyElements(sr.Parameters, "@httpResponseWriter") {
		result["@httpResponseWriter"] = response
	}

	if request.ContentLength > 0 {
		for i, parameter := range sr.Parameters {
			if _, found := result[parameter]; !found {
				value, err := sr.extractParameterFromBody(parameter, functionSignature[i], request)
				if err != nil {
					return nil, fmt.Errorf("failed to extract parameters for %v %v due to %v", sr.HTTPMethod, sr.URI, err)
				}
				result[parameter] = value
				break
			}
		}
	}
	return result, nil
}

//ServiceRouter represents routing rule
type ServiceRouter struct {
	serviceRouting []*ServiceRouting
}

func (r *ServiceRouter) match(request *http.Request) []*ServiceRouting {
	var result = make([]*ServiceRouting, 0)
	for _, candidate := range r.serviceRouting {
		if candidate.HTTPMethod == request.Method {
			_, matched := ExtractURIParameters(candidate.URI, request.RequestURI)
			if matched {
				result = append(result, candidate)
			}
		}
	}
	return result
}

func getContentTypeOrJSONContentType(contentType string) string {
	if strings.Contains(contentType, textPlainContentType) || strings.Contains(contentType, jsonContentType) || contentType == "" {
		return jsonContentType
	}
	return contentType
}

//Route matches  service routing by http method , and number of parameters, then it call routing method, and sent back its response.
func (r *ServiceRouter) Route(response http.ResponseWriter, request *http.Request) error {
	candidates := r.match(request)
	if len(candidates) == 0 {
		var uriTemplates = make([]string, 0)
		for _, routing := range r.serviceRouting {
			uriTemplates = append(uriTemplates, routing.URI)
		}
		return fmt.Errorf("failed to route request - unable to match %v with one of %v", request.RequestURI, strings.Join(uriTemplates, ","))
	}
	var finalError error

	for _, serviceRouting := range candidates {

		parameterValues, err := serviceRouting.extractParameters(request, response)
		if err != nil {
			finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			continue
		}

		if serviceRouting.HandlerInvoker != nil {
			err := serviceRouting.HandlerInvoker(serviceRouting, request, response, parameterValues)
			if err != nil {
				finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			}
			continue
		}

		functionParameters, err := BuildFunctionParameters(serviceRouting.Handler, serviceRouting.Parameters, parameterValues)
		if err != nil {
			finalError = fmt.Errorf("unable to build function parameters %T due to %v", serviceRouting.Handler, err)
			continue
		}

		result := CallFunction(serviceRouting.Handler, functionParameters...)
		if len(result) > 0 {
			err = WriteServiceRoutingResponse(response, request, serviceRouting, result[0])
			if err != nil {
				return fmt.Errorf("failed to write response response %v, due to %v", result[0], err)
			}
			return nil
		}
		response.Header().Set("Content-Type", textPlainContentType)
	}
	if finalError != nil {
		return fmt.Errorf("failed to route request - %v", finalError)
	}
	return nil
}

//WriteServiceRoutingResponse writes service router response
func WriteServiceRoutingResponse(response http.ResponseWriter, request *http.Request, serviceRouting *ServiceRouting, result interface{}) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoderFactory := serviceRouting.getEncoderFactory(responseContentType)
	encoder := encoderFactory.Create(response)
	response.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(result)
	if err != nil {
		return fmt.Errorf("failed to encode response %v, due to %v", response, err)
	}
	return nil

	if err != nil {
		return fmt.Errorf("failed to write response response %v, due to %v", result, err)
	}
	return nil
}

//WriteResponse writes response to response writer, it used encoder factory to encode passed in response to the writer, it sets back request contenttype to response.
func (r *ServiceRouter) WriteResponse(encoderFactory EncoderFactory, response interface{}, request *http.Request, responseWriter http.ResponseWriter) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoder := encoderFactory.Create(responseWriter)
	responseWriter.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(response)
	if err != nil {
		return fmt.Errorf("failed to encode response %v, due to %v", response, err)
	}
	return nil
}

//NewServiceRouter creates a new service router, is takes list of service routing as arguments
func NewServiceRouter(serviceRouting ...ServiceRouting) *ServiceRouter {
	var routings = make([]*ServiceRouting, 0)
	for i := range serviceRouting {
		routings = append(routings, &serviceRouting[i])
	}
	return &ServiceRouter{routings}
}

//RouteToService calls web service url, with passed in json request, and encodes http json response into passed response
func RouteToService(method, url string, request, response interface{}) (err error) {
	client, err := NewToolboxHTTPClient()
	if err != nil {
		return err
	}
	return client.Request(method, url, request, response, NewJSONEncoderFactory(), NewJSONDecoderFactory())
}

type HttpOptions struct {
	Key   string
	Value interface{}
}

func NewHttpClient(options ...*HttpOptions) (*http.Client, error) {
	if len(options) == 0 {
		return http.DefaultClient, nil
	}

	var (
		// Default values matching DefaultHttpClient
		RequestTimeoutMs      = 30 * time.Second
		KeepAliveTimeMs       = 30 * time.Second
		TLSHandshakeTimeoutMs = 10 * time.Second
		ExpectContinueTimeout = 1 * time.Second
		IdleConnTimeout       = 90 * time.Second
		DualStack             = true
		MaxIdleConnsPerHost   = http.DefaultMaxIdleConnsPerHost
		MaxIdleConns          = 100

		ResponseHeaderTimeoutMs time.Duration
		TimeoutMs               time.Duration
	)

	for _, option := range options {
		switch option.Key {
		case "RequestTimeoutMs":
			RequestTimeoutMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "TimeoutMs":
			TimeoutMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "KeepAliveTimeMs":
			KeepAliveTimeMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "TLSHandshakeTimeoutMs":
			KeepAliveTimeMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "ResponseHeaderTimeoutMs":
			ResponseHeaderTimeoutMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "MaxIdleConns":
			MaxIdleConns = AsInt(option.Value)
		default:
			return nil, fmt.Errorf("Invalid option: %v", option.Key)

		}
	}
	roundTripper := http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   RequestTimeoutMs,
			KeepAlive: KeepAliveTimeMs,
			DualStack: DualStack,
		}).Dial,
		MaxIdleConns:          MaxIdleConns,
		ExpectContinueTimeout: ExpectContinueTimeout,
		IdleConnTimeout:       IdleConnTimeout,
		TLSHandshakeTimeout:   TLSHandshakeTimeoutMs,
		MaxIdleConnsPerHost:   MaxIdleConnsPerHost,
		ResponseHeaderTimeout: ResponseHeaderTimeoutMs,
	}

	return &http.Client{
		Transport: &roundTripper,
		Timeout:   TimeoutMs,
	}, nil

}

// ToolboxHTTPClient contains preconfigured http client
type ToolboxHTTPClient struct {
	httpClient *http.Client
}

// NewToolboxHTTPClient instantiate new client with provided options
func NewToolboxHTTPClient(options ...*HttpOptions) (*ToolboxHTTPClient, error) {
	client, err := NewHttpClient(options...)
	if err != nil {
		return nil, err
	}
	return &ToolboxHTTPClient{client}, nil
}

// Request sends http request using the existing client
func (c *ToolboxHTTPClient) Request(method, url string, request, response interface{}, encoderFactory EncoderFactory, decoderFactory DecoderFactory) (err error) {
	if _, found := httpMethods[strings.ToUpper(method)]; !found {
		return errors.New("unsupported method:" + method)
	}
	var buffer *bytes.Buffer

	if request != nil {
		buffer = new(bytes.Buffer)
		if IsString(request) {
			buffer.Write([]byte(AsString(request)))
		} else {
			err := encoderFactory.Create(buffer).Encode(&request)
			if err != nil {
				return fmt.Errorf("failed to encode request: %v due to ", err)
			}
		}
	}
	var serverResponse *http.Response
	var httpRequest *http.Request
	httpMethod := strings.ToUpper(method)
	if request != nil {
		httpRequest, err = http.NewRequest(httpMethod, url, buffer)
		if err != nil {
			return err
		}
		httpRequest.Header.Set("Content-Type", jsonContentType)
	} else {
		httpRequest, err = http.NewRequest(httpMethod, url, nil)
		if err != nil {
			return err
		}
	}

	serverResponse, err = c.httpClient.Do(httpRequest)
	if serverResponse != nil {
		// must close we have serverResponse to avoid fd leak
		defer serverResponse.Body.Close()
	}
	if err != nil && serverResponse != nil {
		return fmt.Errorf("failed to get response %v %v", err, serverResponse.Header.Get("error"))
	}

	if response != nil {
		statusSettable, canSetStatus := response.(StatusCodeSettable)
		if canSetStatus {
			statusSettable.SetStatusCode(serverResponse.StatusCode)
		}
		if serverResponse == nil  {
			return fmt.Errorf("failed to receive response %v", err)
		}
		var errorPrefix = fmt.Sprintf("failed to process response: %v, ", serverResponse.StatusCode)
		body, err := ioutil.ReadAll(serverResponse.Body)
		if err != nil {
			return fmt.Errorf("%v unable read body %v",errorPrefix, err)
		}
		if len(body) == 0 {
			return fmt.Errorf("%v response body was empty", errorPrefix)
		}

		err = decoderFactory.Create(strings.NewReader(string(body))).Decode(response)
		if err != nil {
			return fmt.Errorf("%v. unable decode response as %T: body: %v: %v", errorPrefix, response, string(body), err)
		}
		if canSetStatus {
			statusSettable.SetStatusCode(serverResponse.StatusCode)
		}
	}
	return nil
}

type StatusCodeSettable interface {
	SetStatusCode(code int)
}<commit_msg>corrected type<commit_after>package toolbox

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"reflect"
	"strings"
	"time"
)

var jsonContentType = "application/json"
var textPlainContentType = "text/plain"

const (
	MethodGet     = "GET"
	MethodHead    = "HEAD"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodPatch   = "PATCH" // RFC 5789
	MethodDelete  = "DELETE"
	MethodOptions = "OPTIONS"
	MethodTrace   = "TRACE"
)

var httpMethods = map[string]bool{
	MethodDelete:  true,
	MethodGet:     true,
	MethodPatch:   true,
	MethodPost:    true,
	MethodPut:     true,
	MethodHead:    true,
	MethodTrace:   true,
	MethodOptions: true,
}

//HandlerInvoker method is responsible  of passing required parameters to router handler.
type HandlerInvoker func(serviceRouting *ServiceRouting, request *http.Request, response http.ResponseWriter, parameters map[string]interface{}) error

//DefaultEncoderFactory  - NewJSONEncoderFactory
var DefaultEncoderFactory = NewJSONEncoderFactory()

//DefaultDecoderFactory - NewJSONDecoderFactory
var DefaultDecoderFactory = NewJSONDecoderFactory()

//ServiceRouting represents a simple web services routing rule, which is matched with http request
type ServiceRouting struct {
	URI                 string      //matching uri
	Handler             interface{} //has to be func
	HTTPMethod          string
	Parameters          []string
	ContentTypeEncoders map[string]EncoderFactory //content type encoder factory
	ContentTypeDecoders map[string]DecoderFactory //content type decoder factory
	HandlerInvoker      HandlerInvoker            //optional function that will be used instead of reflection to invoke a handler.
}

func (sr ServiceRouting) getDecoderFactory(contentType string) DecoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeDecoders[contentType]; found {
			return factory
		}
	}
	return DefaultDecoderFactory
}

func (sr ServiceRouting) getEncoderFactory(contentType string) EncoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeEncoders[contentType]; found {
			return factory
		}
	}
	return DefaultEncoderFactory
}

func (sr ServiceRouting) extractParameterFromBody(parameterName string, targetType reflect.Type, request *http.Request) (interface{}, error) {
	targetValuePointer := reflect.New(targetType)
	contentType := getContentTypeOrJSONContentType(request.Header.Get("Content-Type"))
	decoderFactory := sr.getDecoderFactory(contentType)
	decoder := decoderFactory.Create(request.Body)
	if !strings.Contains(parameterName, ":") {
		err := decoder.Decode(targetValuePointer.Interface())
		if err != nil {
			return nil, fmt.Errorf("unable to extract %T due to %v", targetValuePointer.Interface(), err)
		}
	} else {
		var valueMap = make(map[string]interface{})
		pair := strings.SplitN(parameterName, ":", 2)
		valueMap[pair[1]] = targetValuePointer.Interface()
		err := decoder.Decode(&valueMap)
		if err != nil {
			return nil, fmt.Errorf("unable to extract %T due to %v", targetValuePointer.Interface(), err)
		}
	}
	return targetValuePointer.Interface(), nil
}

func (sr ServiceRouting) extractParameters(request *http.Request, response http.ResponseWriter) (map[string]interface{}, error) {
	var result = make(map[string]interface{})
	request.ParseForm()
	functionSignature := GetFuncSignature(sr.Handler)
	uriParameters, _ := ExtractURIParameters(sr.URI, request.RequestURI)
	for _, name := range sr.Parameters {
		value, found := uriParameters[name]
		if found {
			if strings.Contains(value, ",") {
				result[name] = strings.Split(value, ",")
			} else {
				result[name] = value
			}
			continue
		}

		value = request.Form.Get(name)
		if len(value) > 0 {
			result[name] = value
		} else {
			continue
		}
	}
	if HasSliceAnyElements(sr.Parameters, "@httpRequest") {
		result["@httpRequest"] = request
	}
	if HasSliceAnyElements(sr.Parameters, "@httpResponseWriter") {
		result["@httpResponseWriter"] = response
	}

	if request.ContentLength > 0 {
		for i, parameter := range sr.Parameters {
			if _, found := result[parameter]; !found {
				value, err := sr.extractParameterFromBody(parameter, functionSignature[i], request)
				if err != nil {
					return nil, fmt.Errorf("failed to extract parameters for %v %v due to %v", sr.HTTPMethod, sr.URI, err)
				}
				result[parameter] = value
				break
			}
		}
	}
	return result, nil
}

//ServiceRouter represents routing rule
type ServiceRouter struct {
	serviceRouting []*ServiceRouting
}

func (r *ServiceRouter) match(request *http.Request) []*ServiceRouting {
	var result = make([]*ServiceRouting, 0)
	for _, candidate := range r.serviceRouting {
		if candidate.HTTPMethod == request.Method {
			_, matched := ExtractURIParameters(candidate.URI, request.RequestURI)
			if matched {
				result = append(result, candidate)
			}
		}
	}
	return result
}

func getContentTypeOrJSONContentType(contentType string) string {
	if strings.Contains(contentType, textPlainContentType) || strings.Contains(contentType, jsonContentType) || contentType == "" {
		return jsonContentType
	}
	return contentType
}

//Route matches  service routing by http method , and number of parameters, then it call routing method, and sent back its response.
func (r *ServiceRouter) Route(response http.ResponseWriter, request *http.Request) error {
	candidates := r.match(request)
	if len(candidates) == 0 {
		var uriTemplates = make([]string, 0)
		for _, routing := range r.serviceRouting {
			uriTemplates = append(uriTemplates, routing.URI)
		}
		return fmt.Errorf("failed to route request - unable to match %v with one of %v", request.RequestURI, strings.Join(uriTemplates, ","))
	}
	var finalError error

	for _, serviceRouting := range candidates {

		parameterValues, err := serviceRouting.extractParameters(request, response)
		if err != nil {
			finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			continue
		}

		if serviceRouting.HandlerInvoker != nil {
			err := serviceRouting.HandlerInvoker(serviceRouting, request, response, parameterValues)
			if err != nil {
				finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			}
			continue
		}

		functionParameters, err := BuildFunctionParameters(serviceRouting.Handler, serviceRouting.Parameters, parameterValues)
		if err != nil {
			finalError = fmt.Errorf("unable to build function parameters %T due to %v", serviceRouting.Handler, err)
			continue
		}

		result := CallFunction(serviceRouting.Handler, functionParameters...)
		if len(result) > 0 {
			err = WriteServiceRoutingResponse(response, request, serviceRouting, result[0])
			if err != nil {
				return fmt.Errorf("failed to write response response %v, due to %v", result[0], err)
			}
			return nil
		}
		response.Header().Set("Content-Type", textPlainContentType)
	}
	if finalError != nil {
		return fmt.Errorf("failed to route request - %v", finalError)
	}
	return nil
}

//WriteServiceRoutingResponse writes service router response
func WriteServiceRoutingResponse(response http.ResponseWriter, request *http.Request, serviceRouting *ServiceRouting, result interface{}) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoderFactory := serviceRouting.getEncoderFactory(responseContentType)
	encoder := encoderFactory.Create(response)
	response.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(result)
	if err != nil {
		return fmt.Errorf("failed to encode response %v, due to %v", response, err)
	}
	return nil

	if err != nil {
		return fmt.Errorf("failed to write response response %v, due to %v", result, err)
	}
	return nil
}

//WriteResponse writes response to response writer, it used encoder factory to encode passed in response to the writer, it sets back request contenttype to response.
func (r *ServiceRouter) WriteResponse(encoderFactory EncoderFactory, response interface{}, request *http.Request, responseWriter http.ResponseWriter) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoder := encoderFactory.Create(responseWriter)
	responseWriter.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(response)
	if err != nil {
		return fmt.Errorf("failed to encode response %v, due to %v", response, err)
	}
	return nil
}

//NewServiceRouter creates a new service router, is takes list of service routing as arguments
func NewServiceRouter(serviceRouting ...ServiceRouting) *ServiceRouter {
	var routings = make([]*ServiceRouting, 0)
	for i := range serviceRouting {
		routings = append(routings, &serviceRouting[i])
	}
	return &ServiceRouter{routings}
}

//RouteToService calls web service url, with passed in json request, and encodes http json response into passed response
func RouteToService(method, url string, request, response interface{}) (err error) {
	client, err := NewToolboxHTTPClient()
	if err != nil {
		return err
	}
	return client.Request(method, url, request, response, NewJSONEncoderFactory(), NewJSONDecoderFactory())
}

type HttpOptions struct {
	Key   string
	Value interface{}
}

func NewHttpClient(options ...*HttpOptions) (*http.Client, error) {
	if len(options) == 0 {
		return http.DefaultClient, nil
	}

	var (
		// Default values matching DefaultHttpClient
		RequestTimeoutMs      = 30 * time.Second
		KeepAliveTimeMs       = 30 * time.Second
		TLSHandshakeTimeoutMs = 10 * time.Second
		ExpectContinueTimeout = 1 * time.Second
		IdleConnTimeout       = 90 * time.Second
		DualStack             = true
		MaxIdleConnsPerHost   = http.DefaultMaxIdleConnsPerHost
		MaxIdleConns          = 100

		ResponseHeaderTimeoutMs time.Duration
		TimeoutMs               time.Duration
	)

	for _, option := range options {
		switch option.Key {
		case "RequestTimeoutMs":
			RequestTimeoutMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "TimeoutMs":
			TimeoutMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "KeepAliveTimeMs":
			KeepAliveTimeMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "TLSHandshakeTimeoutMs":
			KeepAliveTimeMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "ResponseHeaderTimeoutMs":
			ResponseHeaderTimeoutMs = time.Duration(AsInt(option.Value)) * time.Millisecond
		case "MaxIdleConns":
			MaxIdleConns = AsInt(option.Value)
		default:
			return nil, fmt.Errorf("Invalid option: %v", option.Key)

		}
	}
	roundTripper := http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   RequestTimeoutMs,
			KeepAlive: KeepAliveTimeMs,
			DualStack: DualStack,
		}).Dial,
		MaxIdleConns:          MaxIdleConns,
		ExpectContinueTimeout: ExpectContinueTimeout,
		IdleConnTimeout:       IdleConnTimeout,
		TLSHandshakeTimeout:   TLSHandshakeTimeoutMs,
		MaxIdleConnsPerHost:   MaxIdleConnsPerHost,
		ResponseHeaderTimeout: ResponseHeaderTimeoutMs,
	}

	return &http.Client{
		Transport: &roundTripper,
		Timeout:   TimeoutMs,
	}, nil

}

// ToolboxHTTPClient contains preconfigured http client
type ToolboxHTTPClient struct {
	httpClient *http.Client
}

// NewToolboxHTTPClient instantiate new client with provided options
func NewToolboxHTTPClient(options ...*HttpOptions) (*ToolboxHTTPClient, error) {
	client, err := NewHttpClient(options...)
	if err != nil {
		return nil, err
	}
	return &ToolboxHTTPClient{client}, nil
}

// Request sends http request using the existing client
func (c *ToolboxHTTPClient) Request(method, url string, request, response interface{}, encoderFactory EncoderFactory, decoderFactory DecoderFactory) (err error) {
	if _, found := httpMethods[strings.ToUpper(method)]; !found {
		return errors.New("unsupported method:" + method)
	}
	var buffer *bytes.Buffer

	if request != nil {
		buffer = new(bytes.Buffer)
		if IsString(request) {
			buffer.Write([]byte(AsString(request)))
		} else {
			err := encoderFactory.Create(buffer).Encode(&request)
			if err != nil {
				return fmt.Errorf("failed to encode request: %v due to ", err)
			}
		}
	}
	var serverResponse *http.Response
	var httpRequest *http.Request
	httpMethod := strings.ToUpper(method)
	if request != nil {
		httpRequest, err = http.NewRequest(httpMethod, url, buffer)
		if err != nil {
			return err
		}
		httpRequest.Header.Set("Content-Type", jsonContentType)
	} else {
		httpRequest, err = http.NewRequest(httpMethod, url, nil)
		if err != nil {
			return err
		}
	}

	serverResponse, err = c.httpClient.Do(httpRequest)
	if serverResponse != nil {
		// must close we have serverResponse to avoid fd leak
		defer serverResponse.Body.Close()
	}
	if err != nil && serverResponse != nil {
		return fmt.Errorf("failed to get response %v %v", err, serverResponse.Header.Get("error"))
	}

	if response != nil {
		statusSettable, canSetStatus := response.(StatusCodeSettable)
		if canSetStatus {
			statusSettable.SetStatusCode(serverResponse.StatusCode)
		}
		if serverResponse == nil {
			return fmt.Errorf("failed to receive response %v", err)
		}
		var errorPrefix = fmt.Sprintf("failed to process response: %v, ", serverResponse.StatusCode)
		body, err := ioutil.ReadAll(serverResponse.Body)
		if err != nil {
			return fmt.Errorf("%v unable read body %v", errorPrefix, err)
		}
		if len(body) == 0 {
			return fmt.Errorf("%v response body was empty", errorPrefix)
		}

		err = decoderFactory.Create(strings.NewReader(string(body))).Decode(response)
		if err != nil {
			return fmt.Errorf("%v. unable decode response as %T: body: %v: %v", errorPrefix, response, string(body), err)
		}
		if canSetStatus {
			statusSettable.SetStatusCode(serverResponse.StatusCode)
		}
	}
	return nil
}

type StatusCodeSettable interface {
	SetStatusCode(code int)
}
<|endoftext|>


<commit_before>// timerq.go - Time delayed queue
// Copyright (C) 2018, 2019  Masala, David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package session

import (
	"fmt"
	"sync"
	"time"

	"container/heap"
	"github.com/katzenpost/core/queue"
	"github.com/katzenpost/core/worker"
)

type nqueue interface {
	Push(*Message) error
}

// TimerQ is a queue that delays messages before forwarding to another queue
type TimerQ struct {
	sync.Mutex
	sync.Cond
	worker.Worker

	priq  *queue.PriorityQueue
	nextQ nqueue

	timer  *time.Timer
	wakech chan struct{}
}

// NewTimerQ intantiates a new TimerQ and starts the worker routine
func NewTimerQ(nextQueue nqueue) *TimerQ {
	a := &TimerQ{
		nextQ: nextQueue,
		timer: time.NewTimer(0),
		priq:  queue.New(),
	}
	a.L = new(sync.Mutex)
	a.Go(a.worker)
	return a
}

// Push adds a message to the TimerQ
func (a *TimerQ) Push(priority uint64, m interface{}) {
	a.Lock()
	a.priq.Enqueue(priority, m)
	a.Unlock()
	a.Signal()
}

// Remove removes a Message from the TimerQ
func (a *TimerQ) Remove(m *Message) error {
	a.Lock()
	defer a.Unlock()
	if mo := a.priq.Peek(); mo != nil {
		if mo.Value.(*Message) == m {
			heap.Pop(a.priq)
			if a.priq.Len() > 0 {
				// wake up the worker to reset the timer
				a.Signal()
			}
		} else {
			mo := a.priq.RemovePriority(mo.Priority)
			switch mo {
			case nil:
				return fmt.Errorf("Failed to remove %v", m)
			case m == mo.(*Message):
			default:
				return fmt.Errorf("Failed to remove %v", m)
			}
		}
	}
	return nil
}

// wakeupCh() returns the channel that fires upon Signal of the TimerQ's sync.Cond
func (a *TimerQ) wakeupCh() chan struct{} {
	if a.wakech != nil {
		return a.wakech
	}
	c := make(chan struct{})
	go func() {
		defer close(c)
		var v struct{}
		for {
			a.L.Lock()
			a.Wait()
			a.L.Unlock()
			select {
			case <-a.HaltCh():
				return
			case c <- v:
			}
		}
	}()
	a.wakech = c
	return c
}

// pop top item from queue and forward to next queue
func (a *TimerQ) forward() {
	a.Lock()
	m := heap.Pop(a.priq)
	a.Unlock()
	if m == nil {
		return
	}

	if err := a.nextQ.Push(m.(*queue.Entry).Value.(*Message)); err != nil {
		panic(err)
	}
}

func (a *TimerQ) worker() {
	for {
		var c <-chan time.Time
		a.Lock()
		if m := a.priq.Peek(); m != nil {
			// Figure out if the message needs to be handled now.
			timeLeft := m.Priority - uint64(time.Now().UnixNano())
			if timeLeft <= 0 {
				a.Unlock()
				a.forward()
				continue
			} else {
				c = time.After(time.Duration(time.Duration(timeLeft)))
			}
		}
		a.Unlock()
		select {
		case <-a.HaltCh():
			return
		case <-c:
			a.forward()
		case <-a.wakeupCh():
		}
	}
}
<commit_msg>Fix timerq typo<commit_after>// timerq.go - Time delayed queue
// Copyright (C) 2018, 2019  Masala, David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package session

import (
	"fmt"
	"sync"
	"time"

	"container/heap"
	"github.com/katzenpost/core/queue"
	"github.com/katzenpost/core/worker"
)

type nqueue interface {
	Push(*Message) error
}

// TimerQ is a queue that delays messages before forwarding to another queue
type TimerQ struct {
	sync.Mutex
	sync.Cond
	worker.Worker

	priq  *queue.PriorityQueue
	nextQ nqueue

	timer  *time.Timer
	wakech chan struct{}
}

// NewTimerQ intantiates a new TimerQ and starts the worker routine
func NewTimerQ(nextQueue nqueue) *TimerQ {
	a := &TimerQ{
		nextQ: nextQueue,
		timer: time.NewTimer(0),
		priq:  queue.New(),
	}
	a.L = new(sync.Mutex)
	a.Go(a.worker)
	return a
}

// Push adds a message to the TimerQ
func (a *TimerQ) Push(priority uint64, m interface{}) {
	a.Lock()
	a.priq.Enqueue(priority, m)
	a.Unlock()
	a.Signal()
}

// Remove removes a Message from the TimerQ
func (a *TimerQ) Remove(m *Message) error {
	a.Lock()
	defer a.Unlock()
	if mo := a.priq.Peek(); mo != nil {
		if mo.Value.(*Message) == m {
			heap.Pop(a.priq)
			if a.priq.Len() > 0 {
				// wake up the worker to reset the timer
				a.Signal()
			}
		} else {
			mo := a.priq.RemovePriority(mo.Priority)
			switch mo {
			case nil:
				return fmt.Errorf("Failed to remove %v", m)
			case m == mo.(*Message):
			default:
				return fmt.Errorf("Failed to remove %v", m)
			}
		}
	}
	return nil
}

// wakeupCh() returns the channel that fires upon Signal of the TimerQ's sync.Cond
func (a *TimerQ) wakeupCh() chan struct{} {
	if a.wakech != nil {
		return a.wakech
	}
	c := make(chan struct{})
	go func() {
		defer close(c)
		var v struct{}
		for {
			a.L.Lock()
			a.Wait()
			a.L.Unlock()
			select {
			case <-a.HaltCh():
				return
			case c <- v:
			}
		}
	}()
	a.wakech = c
	return c
}

// pop top item from queue and forward to next queue
func (a *TimerQ) forward() {
	a.Lock()
	m := heap.Pop(a.priq)
	a.Unlock()
	if m == nil {
		return
	}

	if err := a.nextQ.Push(m.(*queue.Entry).Value.(*Message)); err != nil {
		panic(err)
	}
}

func (a *TimerQ) worker() {
	for {
		var c <-chan time.Time
		a.Lock()
		if m := a.priq.Peek(); m != nil {
			// Figure out if the message needs to be handled now.
			timeLeft := m.Priority - uint64(time.Now().UnixNano())
			if timeLeft <= 0 {
				a.Unlock()
				a.forward()
				continue
			} else {
				c = time.After(time.Duration(timeLeft))
			}
		}
		a.Unlock()
		select {
		case <-a.HaltCh():
			return
		case <-c:
			a.forward()
		case <-a.wakeupCh():
		}
	}
}
<|endoftext|>


<commit_before>package services

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"encoding/pem"
	"github.com/dgrijalva/jwt-go"
	"github.com/pufferpanel/apufferi/v3"
	"github.com/pufferpanel/apufferi/v3/logging"
	"github.com/pufferpanel/apufferi/v3/scope"
	"github.com/pufferpanel/pufferpanel/v2/database"
	"github.com/pufferpanel/pufferpanel/v2/models"
	"github.com/spf13/viper"
	"io"
	"os"
	"strconv"
	"sync"
	"time"
)

var signingMethod = jwt.SigningMethodES256
var privateKey *ecdsa.PrivateKey
var locker sync.Mutex

func Generate(claims jwt.Claims) (string, error) {
	ValidateTokenLoaded()
	token := jwt.NewWithClaims(signingMethod, claims)
	return token.SignedString(privateKey)
}
func GenerateSession(id uint) (string, error) {
	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "session",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
			Subject:   strconv.Itoa(int(id)),
		},
	}

	return Generate(claims)
}

func GenerateOAuthForClient(client *models.Client) (string, error) {
	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "oauth2",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
		},
		PanelClaims: apufferi.PanelClaims{
			Scopes: map[string][]scope.Scope{
				client.ServerId: client.Scopes,
			},
		},
	}

	return Generate(claims)
}

func GenerateOAuthForNode(nodeId uint) (string, error) {
	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "oauth2",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
		},
		PanelClaims: apufferi.PanelClaims{
			Scopes: map[string][]scope.Scope{
				"": {scope.OAuth2Auth},
			},
		},
	}
	return Generate(claims)
}

func GenerateOAuthForUser(userId uint, serverId *string) (string, error) {
	db, err := database.GetConnection()
	if err != nil {
		return "", err
	}
	ps := &Permission{DB: db}

	var permissions []*models.Permissions

	if serverId == nil {
		permissions, err = ps.GetForUser(userId)
	} else {
		var perm *models.Permissions
		perm, err = ps.GetForUserAndServer(userId, serverId)
		if err == nil {
			permissions = []*models.Permissions{perm}
		}
	}

	if err != nil {
		return "", err
	}

	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "oauth2",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
		},
		PanelClaims: apufferi.PanelClaims{},
	}

	for _, perm := range permissions {
		var existing []scope.Scope
		if perm.ServerIdentifier == nil {
			existing = claims.PanelClaims.Scopes[""]
		} else {
			existing = claims.PanelClaims.Scopes[*perm.ServerIdentifier]
		}

		if existing == nil {
			existing = make([]scope.Scope, 0)
		}

		existing = append(existing, perm.ToScopes()...)

		if perm.ServerIdentifier == nil {
			claims.PanelClaims.Scopes[""] = existing
		} else {
			claims.PanelClaims.Scopes[*perm.ServerIdentifier] = existing
		}
	}

	return Generate(claims)
}

func ParseToken(token string) (*apufferi.Token, error) {
	ValidateTokenLoaded()
	return apufferi.ParseToken(&privateKey.PublicKey, token)
}

func ValidateTokenLoaded() {
	locker.Lock()
	defer locker.Unlock()
	if privateKey == nil {
		load()
	}
}

func load() {
	var privKey *ecdsa.PrivateKey
	privKeyFile, err := os.OpenFile(viper.GetString("token.private"), os.O_RDONLY, 0600)
	defer apufferi.Close(privKeyFile)
	if os.IsNotExist(err) {
		privKey, err = generatePrivateKey()
	} else if err == nil {
		var buf bytes.Buffer
		_, _ = io.Copy(&buf, privKeyFile)
		block, _ := pem.Decode(buf.Bytes())

		privKey, err = ecdsa.GenerateKey(elliptic.P256(), bytes.NewReader(block.Bytes))
	}

	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}

	privateKey = privKey

	pubKey := &privateKey.PublicKey
	pubKeyEncoded, err := x509.MarshalPKIXPublicKey(pubKey)
	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}

	pubKeyFile, err := os.OpenFile(viper.GetString("token.public"), os.O_CREATE|os.O_RDWR, 0644)
	defer apufferi.Close(pubKeyFile)
	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}
	err = pem.Encode(pubKeyFile, &pem.Block{Type: "PUBLIC KEY", Bytes: pubKeyEncoded})
	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}

	return
}

func generatePrivateKey() (privKey *ecdsa.PrivateKey, err error) {
	var key bytes.Buffer
	privKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return
	}

	privKeyEncoded, _ := x509.MarshalECPrivateKey(privKey)
	privKeyFile, err := os.OpenFile(viper.GetString("token.private"), os.O_CREATE|os.O_WRONLY, 0600)
	defer apufferi.Close(privKeyFile)
	if err != nil {
		return
	}
	err = pem.Encode(privKeyFile, &pem.Block{Type: "PRIVATE KEY", Bytes: privKeyEncoded})
	if err != nil {
		return
	}
	err = pem.Encode(&key, &pem.Block{Type: "PRIVATE KEY", Bytes: privKeyEncoded})
	if err != nil {
		return
	}

	return
}
<commit_msg>Define the map<commit_after>package services

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"encoding/pem"
	"github.com/dgrijalva/jwt-go"
	"github.com/pufferpanel/apufferi/v3"
	"github.com/pufferpanel/apufferi/v3/logging"
	"github.com/pufferpanel/apufferi/v3/scope"
	"github.com/pufferpanel/pufferpanel/v2/database"
	"github.com/pufferpanel/pufferpanel/v2/models"
	"github.com/spf13/viper"
	"io"
	"os"
	"strconv"
	"sync"
	"time"
)

var signingMethod = jwt.SigningMethodES256
var privateKey *ecdsa.PrivateKey
var locker sync.Mutex

func Generate(claims jwt.Claims) (string, error) {
	ValidateTokenLoaded()
	token := jwt.NewWithClaims(signingMethod, claims)
	return token.SignedString(privateKey)
}
func GenerateSession(id uint) (string, error) {
	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "session",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
			Subject:   strconv.Itoa(int(id)),
		},
	}

	return Generate(claims)
}

func GenerateOAuthForClient(client *models.Client) (string, error) {
	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "oauth2",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
		},
		PanelClaims: apufferi.PanelClaims{
			Scopes: map[string][]scope.Scope{
				client.ServerId: client.Scopes,
			},
		},
	}

	return Generate(claims)
}

func GenerateOAuthForNode(nodeId uint) (string, error) {
	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "oauth2",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
		},
		PanelClaims: apufferi.PanelClaims{
			Scopes: map[string][]scope.Scope{
				"": {scope.OAuth2Auth},
			},
		},
	}
	return Generate(claims)
}

func GenerateOAuthForUser(userId uint, serverId *string) (string, error) {
	db, err := database.GetConnection()
	if err != nil {
		return "", err
	}
	ps := &Permission{DB: db}

	var permissions []*models.Permissions

	if serverId == nil {
		permissions, err = ps.GetForUser(userId)
	} else {
		var perm *models.Permissions
		perm, err = ps.GetForUserAndServer(userId, serverId)
		if err == nil {
			permissions = []*models.Permissions{perm}
		}
	}

	if err != nil {
		return "", err
	}

	claims := &apufferi.Claim{
		StandardClaims: jwt.StandardClaims{
			Audience:  "oauth2",
			ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
			IssuedAt:  time.Now().Unix(),
		},
		PanelClaims: apufferi.PanelClaims{
			Scopes: map[string][]scope.Scope{},
		},
	}

	for _, perm := range permissions {
		var existing []scope.Scope
		if perm.ServerIdentifier == nil {
			existing = claims.PanelClaims.Scopes[""]
		} else {
			existing = claims.PanelClaims.Scopes[*perm.ServerIdentifier]
		}

		if existing == nil {
			existing = make([]scope.Scope, 0)
		}

		existing = append(existing, perm.ToScopes()...)

		if perm.ServerIdentifier == nil {
			claims.PanelClaims.Scopes[""] = existing
		} else {
			claims.PanelClaims.Scopes[*perm.ServerIdentifier] = existing
		}
	}

	return Generate(claims)
}

func ParseToken(token string) (*apufferi.Token, error) {
	ValidateTokenLoaded()
	return apufferi.ParseToken(&privateKey.PublicKey, token)
}

func ValidateTokenLoaded() {
	locker.Lock()
	defer locker.Unlock()
	if privateKey == nil {
		load()
	}
}

func load() {
	var privKey *ecdsa.PrivateKey
	privKeyFile, err := os.OpenFile(viper.GetString("token.private"), os.O_RDONLY, 0600)
	defer apufferi.Close(privKeyFile)
	if os.IsNotExist(err) {
		privKey, err = generatePrivateKey()
	} else if err == nil {
		var buf bytes.Buffer
		_, _ = io.Copy(&buf, privKeyFile)
		block, _ := pem.Decode(buf.Bytes())

		privKey, err = ecdsa.GenerateKey(elliptic.P256(), bytes.NewReader(block.Bytes))
	}

	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}

	privateKey = privKey

	pubKey := &privateKey.PublicKey
	pubKeyEncoded, err := x509.MarshalPKIXPublicKey(pubKey)
	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}

	pubKeyFile, err := os.OpenFile(viper.GetString("token.public"), os.O_CREATE|os.O_RDWR, 0644)
	defer apufferi.Close(pubKeyFile)
	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}
	err = pem.Encode(pubKeyFile, &pem.Block{Type: "PUBLIC KEY", Bytes: pubKeyEncoded})
	if err != nil {
		logging.Build(logging.ERROR).WithMessage("internal error on token service").WithError(err).Log()
		return
	}

	return
}

func generatePrivateKey() (privKey *ecdsa.PrivateKey, err error) {
	var key bytes.Buffer
	privKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return
	}

	privKeyEncoded, _ := x509.MarshalECPrivateKey(privKey)
	privKeyFile, err := os.OpenFile(viper.GetString("token.private"), os.O_CREATE|os.O_WRONLY, 0600)
	defer apufferi.Close(privKeyFile)
	if err != nil {
		return
	}
	err = pem.Encode(privKeyFile, &pem.Block{Type: "PRIVATE KEY", Bytes: privKeyEncoded})
	if err != nil {
		return
	}
	err = pem.Encode(&key, &pem.Block{Type: "PRIVATE KEY", Bytes: privKeyEncoded})
	if err != nil {
		return
	}

	return
}
<|endoftext|>


<commit_before>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// NOTE: Func does not expose the actual unexported fields, because we return *Func
// values to users, and we want to keep them from being able to overwrite the data
// with (say) *f = Func{}.
// All code operating on a *Func must call raw to get the *_func instead.

// A Func represents a Go function in the running binary.
type Func struct {
	opaque struct{} // unexported field to disallow conversions
}

func (f *Func) raw() *_func {
	return (*_func)(unsafe.Pointer(f))
}

// funcdata.h
const (
	_PCDATA_ArgSize             = 0
	_PCDATA_StackMapIndex       = 1
	_FUNCDATA_ArgsPointerMaps   = 0
	_FUNCDATA_LocalsPointerMaps = 1
	_FUNCDATA_DeadValueMaps     = 2
	_ArgsSizeUnknown            = -0x80000000
)

var (
	pclntable []byte
	ftab      []functab
	filetab   []uint32

	pclntab, epclntab struct{} // linker symbols
)

type functab struct {
	entry   uintptr
	funcoff uintptr
}

func symtabinit() {
	// See golang.org/s/go12symtab for header: 0xfffffffb,
	// two zero bytes, a byte giving the PC quantum,
	// and a byte giving the pointer width in bytes.
	pcln := (*[8]byte)(unsafe.Pointer(&pclntab))
	pcln32 := (*[2]uint32)(unsafe.Pointer(&pclntab))
	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
		gothrow("invalid function symbol table\n")
	}

	// pclntable is all bytes of pclntab symbol.
	sp := (*sliceStruct)(unsafe.Pointer(&pclntable))
	sp.array = unsafe.Pointer(&pclntab)
	sp.len = int(uintptr(unsafe.Pointer(&epclntab)) - uintptr(unsafe.Pointer(&pclntab)))
	sp.cap = sp.len

	// ftab is lookup table for function by program counter.
	nftab := int(*(*uintptr)(add(unsafe.Pointer(pcln), 8)))
	p := add(unsafe.Pointer(pcln), 8+ptrSize)
	sp = (*sliceStruct)(unsafe.Pointer(&ftab))
	sp.array = p
	sp.len = nftab + 1
	sp.cap = sp.len
	for i := 0; i < nftab; i++ {
		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
		if ftab[i].entry > ftab[i+1].entry {
			f1 := (*_func)(unsafe.Pointer(&pclntable[ftab[i].funcoff]))
			f2 := (*_func)(unsafe.Pointer(&pclntable[ftab[i+1].funcoff]))
			f2name := "end"
			if i+1 < nftab {
				f2name = gofuncname(f2)
			}
			println("function symbol table not sorted by program counter:", hex(ftab[i].entry), gofuncname(f1), ">", hex(ftab[i+1].entry), f2name)
			for j := 0; j <= i; j++ {
				print("\t", hex(ftab[j].entry), " ", gofuncname((*_func)(unsafe.Pointer(&pclntable[ftab[j].funcoff]))))
			}
			gothrow("invalid runtime symbol table")
		}
	}

	// file table follows ftab.
	sp = (*sliceStruct)(unsafe.Pointer(&filetab))
	p = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff))
	sp.array = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff))
	// length is in first element of array.
	// set len to 1 so we can get first element.
	sp.len = 1
	sp.cap = 1
	sp.len = int(filetab[0])
	sp.cap = sp.len
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func {
	return (*Func)(unsafe.Pointer(findfunc(pc)))
}

// Name returns the name of the function.
func (f *Func) Name() string {
	return gofuncname(f.raw())
}

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr {
	return f.raw().entry
}

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	// Pass strict=false here, because anyone can call this function,
	// and they might just be wrong about targetpc belonging to f.
	line = int(funcline1(f.raw(), pc, &file, false))
	return file, line
}

func findfunc(pc uintptr) *_func {
	if len(ftab) == 0 {
		return nil
	}

	if pc < ftab[0].entry || pc >= ftab[len(ftab)-1].entry {
		return nil
	}

	// binary search to find func with entry <= pc.
	lo := 0
	nf := len(ftab) - 1 // last entry is sentinel
	for nf > 0 {
		n := nf / 2
		f := &ftab[lo+n]
		if f.entry <= pc && pc < ftab[lo+n+1].entry {
			return (*_func)(unsafe.Pointer(&pclntable[f.funcoff]))
		} else if pc < f.entry {
			nf = n
		} else {
			lo += n + 1
			nf -= n + 1
		}
	}

	gothrow("findfunc: binary search failed")
	return nil
}

func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
	if off == 0 {
		return -1
	}
	p := pclntable[off:]
	pc := f.entry
	val := int32(-1)
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		if targetpc < pc {
			return val
		}
	}

	// If there was a table, it should have covered all program counters.
	// If not, something is wrong.
	if panicking != 0 || !strict {
		return -1
	}

	print("runtime: invalid pc-encoded table f=", gofuncname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")

	p = pclntable[off:]
	pc = f.entry
	val = -1
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		print("\tvalue=", val, " until pc=", hex(pc), "\n")
	}

	gothrow("invalid runtime symbol table")
	return -1
}

func funcname(f *_func) *byte {
	if f == nil || f.nameoff == 0 {
		return nil
	}
	return (*byte)(unsafe.Pointer(&pclntable[f.nameoff]))
}

func gofuncname(f *_func) string {
	return gostringnocopy(funcname(f))
}

func funcline1(f *_func, targetpc uintptr, file *string, strict bool) int32 {
	*file = "?"
	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
	line := pcvalue(f, f.pcln, targetpc, strict)
	if fileno == -1 || line == -1 || fileno >= len(filetab) {
		// print("looking for ", hex(targetpc), " in ", gofuncname(f), " got file=", fileno, " line=", lineno, "\n")
		return 0
	}
	*file = gostringnocopy(&pclntable[filetab[fileno]])
	return line
}

func funcline(f *_func, targetpc uintptr, file *string) int32 {
	return funcline1(f, targetpc, file, true)
}

func funcspdelta(f *_func, targetpc uintptr) int32 {
	x := pcvalue(f, f.pcsp, targetpc, true)
	if x&(ptrSize-1) != 0 {
		print("invalid spdelta ", f.pcsp, " ", x, "\n")
	}
	return x
}

func pcdatavalue(f *_func, table int32, targetpc uintptr) int32 {
	if table < 0 || table >= f.npcdata {
		return -1
	}
	off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
	return pcvalue(f, off, targetpc, true)
}

func funcdata(f *_func, i int32) unsafe.Pointer {
	if i < 0 || i >= f.nfuncdata {
		return nil
	}
	p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
	if ptrSize == 8 && uintptr(p)&4 != 0 {
		if uintptr(unsafe.Pointer(f))&4 != 0 {
			println("runtime: misaligned func", f)
		}
		p = add(p, 4)
	}
	return *(*unsafe.Pointer)(add(p, uintptr(i)*ptrSize))
}

// step advances to the next pc, value pair in the encoded table.
func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
	p, uvdelta := readvarint(p)
	if uvdelta == 0 && !first {
		return nil, false
	}
	if uvdelta&1 != 0 {
		uvdelta = ^(uvdelta >> 1)
	} else {
		uvdelta >>= 1
	}
	vdelta := int32(uvdelta)
	p, pcdelta := readvarint(p)
	*pc += uintptr(pcdelta * _PCQuantum)
	*val += vdelta
	return p, true
}

// readvarint reads a varint from p.
func readvarint(p []byte) (newp []byte, val uint32) {
	var v, shift uint32
	for {
		b := p[0]
		p = p[1:]
		v |= (uint32(b) & 0x7F) << shift
		if b&0x80 == 0 {
			break
		}
		shift += 7
	}
	return p, v
}
<commit_msg>runtime: fix endianness assumption when decoding ftab<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// NOTE: Func does not expose the actual unexported fields, because we return *Func
// values to users, and we want to keep them from being able to overwrite the data
// with (say) *f = Func{}.
// All code operating on a *Func must call raw to get the *_func instead.

// A Func represents a Go function in the running binary.
type Func struct {
	opaque struct{} // unexported field to disallow conversions
}

func (f *Func) raw() *_func {
	return (*_func)(unsafe.Pointer(f))
}

// funcdata.h
const (
	_PCDATA_ArgSize             = 0
	_PCDATA_StackMapIndex       = 1
	_FUNCDATA_ArgsPointerMaps   = 0
	_FUNCDATA_LocalsPointerMaps = 1
	_FUNCDATA_DeadValueMaps     = 2
	_ArgsSizeUnknown            = -0x80000000
)

var (
	pclntable []byte
	ftab      []functab
	filetab   []uint32

	pclntab, epclntab struct{} // linker symbols
)

type functab struct {
	entry   uintptr
	funcoff uintptr
}

func symtabinit() {
	// See golang.org/s/go12symtab for header: 0xfffffffb,
	// two zero bytes, a byte giving the PC quantum,
	// and a byte giving the pointer width in bytes.
	pcln := (*[8]byte)(unsafe.Pointer(&pclntab))
	pcln32 := (*[2]uint32)(unsafe.Pointer(&pclntab))
	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
		gothrow("invalid function symbol table\n")
	}

	// pclntable is all bytes of pclntab symbol.
	sp := (*sliceStruct)(unsafe.Pointer(&pclntable))
	sp.array = unsafe.Pointer(&pclntab)
	sp.len = int(uintptr(unsafe.Pointer(&epclntab)) - uintptr(unsafe.Pointer(&pclntab)))
	sp.cap = sp.len

	// ftab is lookup table for function by program counter.
	nftab := int(*(*uintptr)(add(unsafe.Pointer(pcln), 8)))
	p := add(unsafe.Pointer(pcln), 8+ptrSize)
	sp = (*sliceStruct)(unsafe.Pointer(&ftab))
	sp.array = p
	sp.len = nftab + 1
	sp.cap = sp.len
	for i := 0; i < nftab; i++ {
		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
		if ftab[i].entry > ftab[i+1].entry {
			f1 := (*_func)(unsafe.Pointer(&pclntable[ftab[i].funcoff]))
			f2 := (*_func)(unsafe.Pointer(&pclntable[ftab[i+1].funcoff]))
			f2name := "end"
			if i+1 < nftab {
				f2name = gofuncname(f2)
			}
			println("function symbol table not sorted by program counter:", hex(ftab[i].entry), gofuncname(f1), ">", hex(ftab[i+1].entry), f2name)
			for j := 0; j <= i; j++ {
				print("\t", hex(ftab[j].entry), " ", gofuncname((*_func)(unsafe.Pointer(&pclntable[ftab[j].funcoff]))))
			}
			gothrow("invalid runtime symbol table")
		}
	}

	// The ftab ends with a half functab consisting only of
	// 'entry', followed by a uint32 giving the pcln-relative
	// offset of the file table.
	sp = (*sliceStruct)(unsafe.Pointer(&filetab))
	end := unsafe.Pointer(&ftab[nftab].funcoff) // just beyond ftab
	fileoffset := *(*uint32)(end)
	sp.array = unsafe.Pointer(&pclntable[fileoffset])
	// length is in first element of array.
	// set len to 1 so we can get first element.
	sp.len = 1
	sp.cap = 1
	sp.len = int(filetab[0])
	sp.cap = sp.len
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func {
	return (*Func)(unsafe.Pointer(findfunc(pc)))
}

// Name returns the name of the function.
func (f *Func) Name() string {
	return gofuncname(f.raw())
}

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr {
	return f.raw().entry
}

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	// Pass strict=false here, because anyone can call this function,
	// and they might just be wrong about targetpc belonging to f.
	line = int(funcline1(f.raw(), pc, &file, false))
	return file, line
}

func findfunc(pc uintptr) *_func {
	if len(ftab) == 0 {
		return nil
	}

	if pc < ftab[0].entry || pc >= ftab[len(ftab)-1].entry {
		return nil
	}

	// binary search to find func with entry <= pc.
	lo := 0
	nf := len(ftab) - 1 // last entry is sentinel
	for nf > 0 {
		n := nf / 2
		f := &ftab[lo+n]
		if f.entry <= pc && pc < ftab[lo+n+1].entry {
			return (*_func)(unsafe.Pointer(&pclntable[f.funcoff]))
		} else if pc < f.entry {
			nf = n
		} else {
			lo += n + 1
			nf -= n + 1
		}
	}

	gothrow("findfunc: binary search failed")
	return nil
}

func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
	if off == 0 {
		return -1
	}
	p := pclntable[off:]
	pc := f.entry
	val := int32(-1)
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		if targetpc < pc {
			return val
		}
	}

	// If there was a table, it should have covered all program counters.
	// If not, something is wrong.
	if panicking != 0 || !strict {
		return -1
	}

	print("runtime: invalid pc-encoded table f=", gofuncname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")

	p = pclntable[off:]
	pc = f.entry
	val = -1
	for {
		var ok bool
		p, ok = step(p, &pc, &val, pc == f.entry)
		if !ok {
			break
		}
		print("\tvalue=", val, " until pc=", hex(pc), "\n")
	}

	gothrow("invalid runtime symbol table")
	return -1
}

func funcname(f *_func) *byte {
	if f == nil || f.nameoff == 0 {
		return nil
	}
	return (*byte)(unsafe.Pointer(&pclntable[f.nameoff]))
}

func gofuncname(f *_func) string {
	return gostringnocopy(funcname(f))
}

func funcline1(f *_func, targetpc uintptr, file *string, strict bool) int32 {
	*file = "?"
	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
	line := pcvalue(f, f.pcln, targetpc, strict)
	if fileno == -1 || line == -1 || fileno >= len(filetab) {
		// print("looking for ", hex(targetpc), " in ", gofuncname(f), " got file=", fileno, " line=", lineno, "\n")
		return 0
	}
	*file = gostringnocopy(&pclntable[filetab[fileno]])
	return line
}

func funcline(f *_func, targetpc uintptr, file *string) int32 {
	return funcline1(f, targetpc, file, true)
}

func funcspdelta(f *_func, targetpc uintptr) int32 {
	x := pcvalue(f, f.pcsp, targetpc, true)
	if x&(ptrSize-1) != 0 {
		print("invalid spdelta ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
	}
	return x
}

func pcdatavalue(f *_func, table int32, targetpc uintptr) int32 {
	if table < 0 || table >= f.npcdata {
		return -1
	}
	off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
	return pcvalue(f, off, targetpc, true)
}

func funcdata(f *_func, i int32) unsafe.Pointer {
	if i < 0 || i >= f.nfuncdata {
		return nil
	}
	p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
	if ptrSize == 8 && uintptr(p)&4 != 0 {
		if uintptr(unsafe.Pointer(f))&4 != 0 {
			println("runtime: misaligned func", f)
		}
		p = add(p, 4)
	}
	return *(*unsafe.Pointer)(add(p, uintptr(i)*ptrSize))
}

// step advances to the next pc, value pair in the encoded table.
func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
	p, uvdelta := readvarint(p)
	if uvdelta == 0 && !first {
		return nil, false
	}
	if uvdelta&1 != 0 {
		uvdelta = ^(uvdelta >> 1)
	} else {
		uvdelta >>= 1
	}
	vdelta := int32(uvdelta)
	p, pcdelta := readvarint(p)
	*pc += uintptr(pcdelta * _PCQuantum)
	*val += vdelta
	return p, true
}

// readvarint reads a varint from p.
func readvarint(p []byte) (newp []byte, val uint32) {
	var v, shift uint32
	for {
		b := p[0]
		p = p[1:]
		v |= (uint32(b) & 0x7F) << shift
		if b&0x80 == 0 {
			break
		}
		shift += 7
	}
	return p, v
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/esoui/lexicon/bot"
)

func main() {
	b := bot.New()

	b.Handle(`hi|hello`, func(msg *bot.Message) {
		b.Reply("Hi there!")
	})

	b.Listen()
}
<commit_msg>Remove unecessary blank lines<commit_after>package main

import (
	"github.com/esoui/lexicon/bot"
)

func main() {
	b := bot.New()
	b.Handle(`hi|hello`, func(msg *bot.Message) {
		b.Reply("Hi there!")
	})
	b.Listen()
}
<|endoftext|>


<commit_before>package lexicon

import (
	"bufio"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
)

// DefaultDataPath gets the lexicon word list file location from the LEXICON_DATA environment variable.
func DefaultDataPath() string {
	dir := os.Getenv("LEXICON_DATA")
	if dir == "" {
		log.Fatal("Set LEXICON_DATA variable to directory of lexicon data files")
	}
	return dir
}

// CountChars counts all the characters in a language lexicon.
func CountChars(words map[string]bool) map[rune]int {
	chars := make(map[rune]int)
	for word := range words {
		for _, ch := range word {
			chars[ch]++
		}
	}
	return chars
}

// CountSubstrings counts all the substrings of given length in a language lexicon.
func CountSubstrings(words map[string]bool, length int) map[string]int {
	substrings := make(map[string]int)
	for word := range words {
		// Cast word as a rune slice.
		runes := []rune(word)
		n := len(runes)
		if n >= length {
			max := n - length
			for i := 0; i <= max; i++ {
				// Cast portion of rune slice back to string.
				substring := string(runes[i : i+length])
				substrings[substring]++
			}
		}
	}
	return substrings
}

// LoadAllLanguages loads all the language files.
func LoadAllLanguages(langDir string) map[string]map[string]bool {
	// Load the languages.
	langFiles, err := ioutil.ReadDir(langDir)
	if err != nil {
		log.Fatal(err)
	}
	langWords := make(map[string]map[string]bool)
	for _, langFile := range langFiles {
		name := langFile.Name()
		path := path.Join(langDir, name)
		langWords[name] = LoadLanguage(path)
	}
	return langWords
}

// LoadLanguage loads a language file.
func LoadLanguage(langFile string) map[string]bool {
	// Open file.
	handle, err := os.Open(langFile)
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	// Scan file line by line.
	words := make(map[string]bool)
	scanner := bufio.NewScanner(handle)
	for scanner.Scan() {
		line := scanner.Text()
		if err := scanner.Err(); err != nil {
			log.Fatal(err)
		}
		word := strings.TrimSpace(strings.ToLower(line))
		words[word] = true
	}
	return words
}
<commit_msg>Moving substring counter to function<commit_after>package lexicon

import (
	"bufio"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
)

// DefaultDataPath gets the lexicon word list file location from the LEXICON_DATA environment variable.
func DefaultDataPath() string {
	dir := os.Getenv("LEXICON_DATA")
	if dir == "" {
		log.Fatal("Set LEXICON_DATA variable to directory of lexicon data files")
	}
	return dir
}

// CountChars counts all the characters in a language lexicon.
func CountChars(words map[string]bool) map[rune]int {
	chars := make(map[rune]int)
	for word := range words {
		for _, ch := range word {
			chars[ch]++
		}
	}
	return chars
}

// CountSubstrings counts all the substrings of given length in a language lexicon.
func CountSubstrings(words map[string]bool, length int) map[string]int {
	substrings := make(map[string]int)
	for word := range words {
		list := ListSubstrings(word, length)
		for _, substring := range list {
			substrings[substring]++
		}
	}
	return substrings
}

// ListSubstrings lists all the substrings of a word of given length.
func ListSubstrings(word string, length int) []string {
	// Cast word as a rune slice.
	runes := []rune(word)
	n := len(runes)
	subcount := n - length + 1
	if subcount < 0 {
		subcount = 0
	}
	substrings := make([]string, subcount)
	if n >= length {
		max := n - length
		for i := 0; i <= max; i++ {
			// Cast portion of rune slice back to string.
			substring := string(runes[i : i+length])
			substrings = append(substrings, substring)
		}
	}
	return substrings
}

// LoadAllLanguages loads all the language files.
func LoadAllLanguages(langDir string) map[string]map[string]bool {
	// Load the languages.
	langFiles, err := ioutil.ReadDir(langDir)
	if err != nil {
		log.Fatal(err)
	}
	langWords := make(map[string]map[string]bool)
	for _, langFile := range langFiles {
		name := langFile.Name()
		path := path.Join(langDir, name)
		langWords[name] = LoadLanguage(path)
	}
	return langWords
}

// LoadLanguage loads a language file.
func LoadLanguage(langFile string) map[string]bool {
	// Open file.
	handle, err := os.Open(langFile)
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	// Scan file line by line.
	words := make(map[string]bool)
	scanner := bufio.NewScanner(handle)
	for scanner.Scan() {
		line := scanner.Text()
		if err := scanner.Err(); err != nil {
			log.Fatal(err)
		}
		word := strings.TrimSpace(strings.ToLower(line))
		words[word] = true
	}
	return words
}
<|endoftext|>