<commit_before>package gko

import (
	"bytes"

	"crypto/tls"
	"encoding/base64"
	"net/http"
	"strings"

	"sync"

	"github.com/RobotsAndPencils/buford/certificate"
	"github.com/koichirokamoto/apns"
	"github.com/koichirokamoto/webpush"
	"golang.org/x/net/context"
	"google.golang.org/api/gensupport"
	"google.golang.org/appengine/socket"
	"google.golang.org/appengine/urlfetch"
)

var pushEb = gensupport.DefaultBackoffStrategy()

const (
	fcmURL = "https://fcm.googleapis.com/fcm/send"
	gcmURL = "https://android.googleapis.com/gcm/send"
)

type worker interface {
	work() error
}

func runWorker(wrk <-chan worker) {
	var wg sync.WaitGroup
	for w := range wrk {
		wg.Add(1)
		go func(w worker) {
			defer wg.Done()
			Retry(w.work, pushEb)
		}(w)
	}
	wg.Wait()
}

// FcmSubscription is fcm subscription.
type FcmSubscription struct {
	Endpoint string
	Key      string
	Auth     string
}

// SendFcmNotification push fcm notification to user.
func SendFcmNotification(ctx context.Context, serverKey string, subs []*FcmSubscription, payload []byte) {
	in := make(chan worker)
	go func() {
		for _, sub := range subs {
			in <- &fcmWorker{ctx, sub, payload, serverKey}
		}
		close(in)
	}()

	runWorker(in)
}

type fcmWorker struct {
	ctx       context.Context
	sub       *FcmSubscription
	payload   []byte
	serverKey string
}

func (f *fcmWorker) work() error {
	encryption, err := webpush.Encryption(f.sub.Key, f.sub.Auth, f.payload, 0)
	if err != nil {
		return err
	}

	endpoint := strings.Replace(f.sub.Endpoint, gcmURL, fcmURL, 1)
	req, err := http.NewRequest("POST", endpoint, bytes.NewReader(encryption.Payload))
	if err != nil {
		return err
	}
	defer req.Body.Close()
	req.Header.Set("Authorization", "key="+f.serverKey)
	req.Header.Set("Encryption", "salt="+base64.URLEncoding.EncodeToString(encryption.Salt))
	req.Header.Set("Crypto-Key", "dh="+base64.URLEncoding.EncodeToString(encryption.PublickKey))
	req.Header.Set("Content-Encoding", "aesgcm")
	req.ContentLength = int64(len(encryption.Payload))
	res, err := urlfetch.Client(f.ctx).Do(req)
	if err != nil {
		return err
	}
	res.Body.Close()
	return nil
}

const apnsGateway = "gateway.push.apple.com:2195"

// ApnsConfig is apns notification setting.
type ApnsConfig struct {
	Filename string
	Password string
	Host     string
}

// SendApnsNotification send apns2 notification.
func SendApnsNotification(ctx context.Context, deviceTokens []string, config *ApnsConfig, notification *apns.PushNotification) {
	in := make(chan worker)
	go func() {
		for _, d := range deviceTokens {
			payload, err := notification.ToBytes(d)
			if err != nil {
				continue
			}
			in <- &apnsWorker{ctx, config, payload}
		}
		close(in)
	}()

	runWorker(in)
}

type apnsWorker struct {
	ctx     context.Context
	config  *ApnsConfig
	payload []byte
}

func (a *apnsWorker) work() error {
	cert, err := certificate.Load(a.config.Filename, a.config.Password)
	if err != nil {
		return err
	}

	tlsconfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName:   strings.Split(apnsGateway, ":")[0],
	}

	conn, err := socket.Dial(a.ctx, "tcp", apnsGateway)
	if err != nil {
		return err
	}

	tlsconn := tls.Client(conn, tlsconfig)
	if err := tlsconn.Handshake(); err != nil {
		return err
	}
	defer tlsconn.Close()

	if _, err := tlsconn.Write(a.payload); err != nil {
		return err
	}

	// TODO: handle apns feedback or error
	return nil
}
<commit_msg>create unique backoff setting each push worker<commit_after>package gko

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"net/http"
	"strings"
	"sync"

	"github.com/RobotsAndPencils/buford/certificate"
	"github.com/koichirokamoto/apns"
	"github.com/koichirokamoto/webpush"
	"golang.org/x/net/context"
	"google.golang.org/api/gensupport"
	"google.golang.org/appengine/socket"
	"google.golang.org/appengine/urlfetch"
)

const (
	fcmURL = "https://fcm.googleapis.com/fcm/send"
	gcmURL = "https://android.googleapis.com/gcm/send"
)

type worker interface {
	work() error
}

func runWorker(wrk <-chan worker) {
	var wg sync.WaitGroup
	for w := range wrk {
		wg.Add(1)
		go func(w worker) {
			defer wg.Done()
			Retry(w.work, gensupport.DefaultBackoffStrategy())
		}(w)
	}
	wg.Wait()
}

// FcmSubscription is fcm subscription.
type FcmSubscription struct {
	Endpoint string
	Key      string
	Auth     string
}

// SendFcmNotification push fcm notification to user.
func SendFcmNotification(ctx context.Context, serverKey string, subs []*FcmSubscription, payload []byte) {
	in := make(chan worker)
	go func() {
		for _, sub := range subs {
			in <- &fcmWorker{ctx, sub, payload, serverKey}
		}
		close(in)
	}()

	runWorker(in)
}

type fcmWorker struct {
	ctx       context.Context
	sub       *FcmSubscription
	payload   []byte
	serverKey string
}

func (f *fcmWorker) work() error {
	encryption, err := webpush.Encryption(f.sub.Key, f.sub.Auth, f.payload, 0)
	if err != nil {
		return err
	}

	endpoint := strings.Replace(f.sub.Endpoint, gcmURL, fcmURL, 1)
	req, err := http.NewRequest("POST", endpoint, bytes.NewReader(encryption.Payload))
	if err != nil {
		return err
	}
	defer req.Body.Close()
	req.Header.Set("Authorization", "key="+f.serverKey)
	req.Header.Set("Encryption", "salt="+base64.URLEncoding.EncodeToString(encryption.Salt))
	req.Header.Set("Crypto-Key", "dh="+base64.URLEncoding.EncodeToString(encryption.PublickKey))
	req.Header.Set("Content-Encoding", "aesgcm")
	req.ContentLength = int64(len(encryption.Payload))
	res, err := urlfetch.Client(f.ctx).Do(req)
	if err != nil {
		return err
	}
	res.Body.Close()
	return nil
}

const apnsGateway = "gateway.push.apple.com:2195"

// ApnsConfig is apns notification setting.
type ApnsConfig struct {
	Filename string
	Password string
	Host     string
}

// SendApnsNotification send apns2 notification.
func SendApnsNotification(ctx context.Context, deviceTokens []string, config *ApnsConfig, notification *apns.PushNotification) {
	in := make(chan worker)
	go func() {
		for _, d := range deviceTokens {
			payload, err := notification.ToBytes(d)
			if err != nil {
				continue
			}
			in <- &apnsWorker{ctx, config, payload}
		}
		close(in)
	}()

	runWorker(in)
}

type apnsWorker struct {
	ctx     context.Context
	config  *ApnsConfig
	payload []byte
}

func (a *apnsWorker) work() error {
	cert, err := certificate.Load(a.config.Filename, a.config.Password)
	if err != nil {
		return err
	}

	tlsconfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName:   strings.Split(apnsGateway, ":")[0],
	}

	conn, err := socket.Dial(a.ctx, "tcp", apnsGateway)
	if err != nil {
		return err
	}

	tlsconn := tls.Client(conn, tlsconfig)
	if err := tlsconn.Handshake(); err != nil {
		return err
	}
	defer tlsconn.Close()

	if _, err := tlsconn.Write(a.payload); err != nil {
		return err
	}

	// TODO: handle apns feedback or error
	return nil
}
<|endoftext|>


<commit_before>package proxmox

import (
	"errors"
	"net/url"
	"strconv"
	"strings"
	"time"

	_ "github.com/davecgh/go-spew/spew"
)

type QemuVM struct {
	Mem       float64 `json:"mem"`
	CPUs      float64 `json:"cpus"`
	NetOut    float64 `json:"netout"`
	PID       string  `json:"pid"`
	Disk      float64 `json:"disk"`
	MaxMem    float64 `json:"maxmem"`
	Status    string  `json:"status"`
	Template  float64 `json:"template"`
	NetIn     float64 `json:"netin"`
	MaxDisk   float64 `json:"maxdisk"`
	Name      string  `json:"name"`
	DiskWrite float64 `json:"diskwrite"`
	CPU       float64 `json:"cpu"`
	VMId      float64 `json:"vmid"`
	DiskRead  float64 `json:"diskread"`
	Uptime    float64 `json:"uptime"`
	Node      Node
}

type QemuList map[string]QemuVM

type QemuNet map[string]string

type QemuConfig struct {
	Bootdisk string  `json:"bootdisk"`
	Cores    float64 `json:"cores"`
	Digest   string  `json:"digest"`
	Memory   float64 `json:"memory"`
	Net      map[string]QemuNet
	SMBios1  string            `json:"smbios1"`
	Sockets  float64           `json:"sockets"`
	Disks    map[string]string `json:"disks"`
}

type QemuStatus struct {
	CPU       float64 `json:"cpu"`
	CPUs      float64 `json:"cpus"`
	Mem       float64 `json:"mem"`
	MaxMem    float64 `json:"maxmem"`
	Disk      float64 `json:"disk"`
	MaxDisk   float64 `json:"maxdisk"`
	DiskWrite float64 `json:"diskwrite"`
	DiskRead  float64 `json:"diskread"`
	NetIn     float64 `json:"netin"`
	NetOut    float64 `json:"netout"`
	Uptime    float64 `json:"uptime"`
	QmpStatus string  `json:"qmpstatus"`
	Status    string  `json:"status"`
	Template  string  `json:"template"`
}

func (qemu QemuVM) Delete() (map[string]interface{}, error) {
	var target string
	var data map[string]interface{}
	var err error

	//fmt.Print("!QemuDelete ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64)
	data, err = qemu.Node.Proxmox.Delete(target)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func stringToMap(data string, itemSeparator string, kvSeparator string) map[string]string {
	var result map[string]string

	result = make(map[string]string)
	list := strings.Split(data, itemSeparator)
	for _, item := range list {
		kv := strings.Split(item, kvSeparator)
		result[kv[0]] = kv[1]
	}
	return result
}

func (qemu QemuVM) Config() (QemuConfig, error) {
	var target string
	var data map[string]interface{}
	var results map[string]interface{}
	var config QemuConfig
	var err error

	//fmt.Print("!QemuConfig ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"
	data, err = qemu.Node.Proxmox.Get(target)
	results = data["data"].(map[string]interface{})
	if err != nil {
		return config, err
	}
	config = QemuConfig{
		Bootdisk: results["bootdisk"].(string),
		Cores:    results["cores"].(float64),
		Digest:   results["digest"].(string),
		Memory:   results["memory"].(float64),
		Sockets:  results["sockets"].(float64),
		SMBios1:  results["smbios1"].(string),
	}
	disktype := [3]string{"virtio", "sata", "ide"}
	disknum := [4]string{"0", "1", "2", "3"}
	config.Disks = make(map[string]string)
	for _, d := range disktype {
		for _, i := range disknum {
			id := d + i
			if disk, ok := results[id]; ok {
				config.Disks[id] = disk.(string)
			}
		}
	}
	config.Net = make(map[string]QemuNet)
	netnum := [4]string{"0", "1", "2", "3"}
	for _, n := range netnum {
		if net, ok := results["net"+n]; ok {
			config.Net["net"+n] = stringToMap(net.(string), ",", "=")
		}
	}

	return config, nil
}

func (qemu QemuVM) CurrentStatus() (QemuStatus, error) {
	var target string
	var err error
	var data map[string]interface{}
	var results map[string]interface{}
	var status QemuStatus

	//fmt.Println("!QemuStatus ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/current"
	data, err = qemu.Node.Proxmox.Get(target)
	if err != nil {
		return status, err
	}
	results = data["data"].(map[string]interface{})
	status = QemuStatus{
		CPU:       results["cpu"].(float64),
		CPUs:      results["cpus"].(float64),
		Mem:       results["mem"].(float64),
		MaxMem:    results["maxmem"].(float64),
		Disk:      results["disk"].(float64),
		MaxDisk:   results["maxdisk"].(float64),
		DiskWrite: results["diskwrite"].(float64),
		DiskRead:  results["diskread"].(float64),
		NetIn:     results["netin"].(float64),
		NetOut:    results["netout"].(float64),
		Uptime:    results["uptime"].(float64),
		QmpStatus: results["qmpstatus"].(string),
		Status:    results["status"].(string),
		Template:  results["template"].(string),
	}
	return status, nil
}

func (qemu QemuVM) WaitForStatus(status string, timeout int) error {
	var i int
	var err error
	var qStatus QemuStatus
	for i = 0; i < timeout; i++ {
		qStatus, err = qemu.CurrentStatus()
		if err != nil {
			return err
		}

		if qStatus.Status == status {
			return nil
		}
		time.Sleep(time.Second * 1)
	}
	return errors.New("Timeout reached")
}

func (qemu QemuVM) Start() error {
	var target string
	var err error

	//fmt.Println("!QemuStart ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/start"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Stop() error {
	var target string
	var err error

	//fmt.Print("!QemuStop ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/stop"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Shutdown() error {
	var target string
	var err error

	//fmt.Print("!QemuShutdown ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/shutdown"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Suspend() error {
	var target string
	var err error

	//fmt.Print("!QemuSuspend ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/suspend"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Resume() error {
	var target string
	var err error

	//fmt.Print("!QemuResume ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/resume"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Clone(newId float64, name string, targetName string) (string, error) {
	var target string
	var err error

	newVMID := strconv.FormatFloat(newId, 'f', 0, 64)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/clone"

	form := url.Values{
		"newid":  {newVMID},
		"name":   {name},
		"target": {targetName},
	}

	data, err := qemu.Node.Proxmox.PostForm(target, form)
	if err != err {
		return "", err
	}

	UPid := data["data"].(string)

	return UPid, nil
}
<commit_msg>qemu.Stop() return task id<commit_after>package proxmox

import (
	"errors"
	"net/url"
	"strconv"
	"strings"
	"time"

	_ "github.com/davecgh/go-spew/spew"
)

type QemuVM struct {
	Mem       float64 `json:"mem"`
	CPUs      float64 `json:"cpus"`
	NetOut    float64 `json:"netout"`
	PID       string  `json:"pid"`
	Disk      float64 `json:"disk"`
	MaxMem    float64 `json:"maxmem"`
	Status    string  `json:"status"`
	Template  float64 `json:"template"`
	NetIn     float64 `json:"netin"`
	MaxDisk   float64 `json:"maxdisk"`
	Name      string  `json:"name"`
	DiskWrite float64 `json:"diskwrite"`
	CPU       float64 `json:"cpu"`
	VMId      float64 `json:"vmid"`
	DiskRead  float64 `json:"diskread"`
	Uptime    float64 `json:"uptime"`
	Node      Node
}

type QemuList map[string]QemuVM

type QemuNet map[string]string

type QemuConfig struct {
	Bootdisk string  `json:"bootdisk"`
	Cores    float64 `json:"cores"`
	Digest   string  `json:"digest"`
	Memory   float64 `json:"memory"`
	Net      map[string]QemuNet
	SMBios1  string            `json:"smbios1"`
	Sockets  float64           `json:"sockets"`
	Disks    map[string]string `json:"disks"`
}

type QemuStatus struct {
	CPU       float64 `json:"cpu"`
	CPUs      float64 `json:"cpus"`
	Mem       float64 `json:"mem"`
	MaxMem    float64 `json:"maxmem"`
	Disk      float64 `json:"disk"`
	MaxDisk   float64 `json:"maxdisk"`
	DiskWrite float64 `json:"diskwrite"`
	DiskRead  float64 `json:"diskread"`
	NetIn     float64 `json:"netin"`
	NetOut    float64 `json:"netout"`
	Uptime    float64 `json:"uptime"`
	QmpStatus string  `json:"qmpstatus"`
	Status    string  `json:"status"`
	Template  string  `json:"template"`
}

func (qemu QemuVM) Delete() (map[string]interface{}, error) {
	var target string
	var data map[string]interface{}
	var err error

	//fmt.Print("!QemuDelete ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64)
	data, err = qemu.Node.Proxmox.Delete(target)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func stringToMap(data string, itemSeparator string, kvSeparator string) map[string]string {
	var result map[string]string

	result = make(map[string]string)
	list := strings.Split(data, itemSeparator)
	for _, item := range list {
		kv := strings.Split(item, kvSeparator)
		result[kv[0]] = kv[1]
	}
	return result
}

func (qemu QemuVM) Config() (QemuConfig, error) {
	var target string
	var data map[string]interface{}
	var results map[string]interface{}
	var config QemuConfig
	var err error

	//fmt.Print("!QemuConfig ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"
	data, err = qemu.Node.Proxmox.Get(target)
	results = data["data"].(map[string]interface{})
	if err != nil {
		return config, err
	}
	config = QemuConfig{
		Bootdisk: results["bootdisk"].(string),
		Cores:    results["cores"].(float64),
		Digest:   results["digest"].(string),
		Memory:   results["memory"].(float64),
		Sockets:  results["sockets"].(float64),
		SMBios1:  results["smbios1"].(string),
	}
	disktype := [3]string{"virtio", "sata", "ide"}
	disknum := [4]string{"0", "1", "2", "3"}
	config.Disks = make(map[string]string)
	for _, d := range disktype {
		for _, i := range disknum {
			id := d + i
			if disk, ok := results[id]; ok {
				config.Disks[id] = disk.(string)
			}
		}
	}
	config.Net = make(map[string]QemuNet)
	netnum := [4]string{"0", "1", "2", "3"}
	for _, n := range netnum {
		if net, ok := results["net"+n]; ok {
			config.Net["net"+n] = stringToMap(net.(string), ",", "=")
		}
	}

	return config, nil
}

func (qemu QemuVM) CurrentStatus() (QemuStatus, error) {
	var target string
	var err error
	var data map[string]interface{}
	var results map[string]interface{}
	var status QemuStatus

	//fmt.Println("!QemuStatus ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/current"
	data, err = qemu.Node.Proxmox.Get(target)
	if err != nil {
		return status, err
	}
	results = data["data"].(map[string]interface{})
	status = QemuStatus{
		CPU:       results["cpu"].(float64),
		CPUs:      results["cpus"].(float64),
		Mem:       results["mem"].(float64),
		MaxMem:    results["maxmem"].(float64),
		Disk:      results["disk"].(float64),
		MaxDisk:   results["maxdisk"].(float64),
		DiskWrite: results["diskwrite"].(float64),
		DiskRead:  results["diskread"].(float64),
		NetIn:     results["netin"].(float64),
		NetOut:    results["netout"].(float64),
		Uptime:    results["uptime"].(float64),
		QmpStatus: results["qmpstatus"].(string),
		Status:    results["status"].(string),
		Template:  results["template"].(string),
	}
	return status, nil
}

func (qemu QemuVM) WaitForStatus(status string, timeout int) error {
	var i int
	var err error
	var qStatus QemuStatus
	for i = 0; i < timeout; i++ {
		qStatus, err = qemu.CurrentStatus()
		if err != nil {
			return err
		}

		if qStatus.Status == status {
			return nil
		}
		time.Sleep(time.Second * 1)
	}
	return errors.New("Timeout reached")
}

func (qemu QemuVM) Start() error {
	var target string
	var err error

	//fmt.Println("!QemuStart ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/start"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Stop() (string, error) {
	var target string
	var err error

	//fmt.Print("!QemuStop ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/stop"
	data, err := qemu.Node.Proxmox.Post(target, "")
	if err != nil {
		return "", err
	}

	UPid := data["data"].(string)

	return UPid, nil
}

func (qemu QemuVM) Shutdown() error {
	var target string
	var err error

	//fmt.Print("!QemuShutdown ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/shutdown"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Suspend() error {
	var target string
	var err error

	//fmt.Print("!QemuSuspend ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/suspend"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Resume() error {
	var target string
	var err error

	//fmt.Print("!QemuResume ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/resume"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Clone(newId float64, name string, targetName string) (string, error) {
	var target string
	var err error

	newVMID := strconv.FormatFloat(newId, 'f', 0, 64)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/clone"

	form := url.Values{
		"newid":  {newVMID},
		"name":   {name},
		"target": {targetName},
	}

	data, err := qemu.Node.Proxmox.PostForm(target, form)
	if err != err {
		return "", err
	}

	UPid := data["data"].(string)

	return UPid, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var sock string

func parseAddress(uri string) (scheme, path, port string, err error) {
	u, err := url.Parse(uri)
	if err != nil {
		return scheme, path, port, err
	}

	scheme = u.Scheme
	path = u.Path
	if path == "" {
		path = u.Host
	}

	host := strings.Split(u.Host, ":")
	if len(host) == 1 {
		port = "80"
	} else {
		port = host[1]
	}

	return scheme, path, port, err
}

func parseBody(r io.Reader, index string) (stats map[string]interface{}, err error) {
	scanner := bufio.NewScanner(r)
	stats = make(map[string]interface{})
	for scanner.Scan() {
		p := strings.Split(scanner.Text(), " ")
		if len(p) == 2 {
			stats[strings.Trim(p[0], ":")], err = strconv.ParseFloat(p[1], 64)
		} else {
			re := regexp.MustCompile(fmt.Sprintf("%s$", index))
			if ok := re.Match([]byte(p[0])); ok && err == nil {
				stats[strings.Trim(p[len(p)-2], ":")], err = strconv.ParseFloat(p[len(p)-1], 64)
			}
		}
	}
	stats["active"] = stats["active"].(float64) - 1

	return stats, err
}

func parseBodyHTTP(uri, port string) (stats map[string]interface{}, err error) {
	var req *http.Request
	req, err = http.NewRequest("GET", uri, nil)
	if err != nil {
		return stats, err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return stats, err
	}
	defer resp.Body.Close()

	stats, err = parseBody(resp.Body, ":"+port)

	return stats, err
}

func fakeDial(proto, addr string) (conn net.Conn, err error) {
	return net.Dial("unix", sock)
}

func parseBodyUnix(path string) (stats map[string]interface{}, err error) {
	tr := &http.Transport{
		Dial: fakeDial,
	}

	client := &http.Client{Transport: tr}
	resp, err := client.Get(fmt.Sprintf("http://dummy/%s", strings.TrimLeft(path, "/")))

	if err != nil {
		return stats, err
	}
	defer resp.Body.Close()

	stats, err = parseBody(resp.Body, sock)

	return stats, err
}

// RackStatsPlugin mackerel plugin for Rack servers
type RackStatsPlugin struct {
	Address   string
	Path      string
	MetricKey string
}

// FetchMetrics interface for mackerelplugin
func (u RackStatsPlugin) FetchMetrics() (stats map[string]interface{}, err error) {
	stats, err = u.parseStats()
	return stats, err
}

func (u RackStatsPlugin) parseStats() (stats map[string]interface{}, err error) {
	scheme, path, port, err := parseAddress(u.Address)

	switch scheme {
	case "http":
		stats, err = parseBodyHTTP(fmt.Sprintf("%s/%s", u.Address, strings.TrimLeft(u.Path, "/")), port)
	case "unix":
		sock = path
		stats, err = parseBodyUnix(u.Path)
	}

	return stats, err
}

// GraphDefinition interface for mackerelplugin
func (u RackStatsPlugin) GraphDefinition() map[string](mp.Graphs) {
	scheme, path, port, err := parseAddress(u.Address)
	if err != nil {
		log.Fatal(err)
	}

	var label string
	if u.MetricKey == "" {
		switch scheme {
		case "http":
			u.MetricKey = port
			label = fmt.Sprintf("Rack Port %s Stats", port)
		case "unix":
			u.MetricKey = strings.Replace(strings.Replace(path, "/", "_", -1), ".", "_", -1)
			label = fmt.Sprintf("Rack %s Stats", path)
		}
	} else {
		label = fmt.Sprintf("Rack %s Stats", u.MetricKey)
	}

	return map[string](mp.Graphs){
		fmt.Sprintf("%s.rack.stats", u.MetricKey): mp.Graphs{
			Label: label,
			Unit:  "integer",
			Metrics: [](mp.Metrics){
				mp.Metrics{Name: "queued", Label: "Queued", Diff: false},
				mp.Metrics{Name: "active", Label: "Active", Diff: false},
				mp.Metrics{Name: "writing", Label: "Writing", Diff: false},
				mp.Metrics{Name: "calling", Label: "Calling", Diff: false},
			},
		},
	}
}

func main() {
	optAddress := flag.String("address", "http://localhost:8080", "URL or Unix Domain Socket")
	optPath := flag.String("path", "/_raindrops", "Path")
	optMetricKey := flag.String("metric-key", "", "Metric Key")
	optVersion := flag.Bool("version", false, "Version")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	if *optVersion {
		fmt.Println("0.3")
		os.Exit(0)
	}

	var rack RackStatsPlugin
	rack.Address = *optAddress
	rack.Path = *optPath
	rack.MetricKey = *optMetricKey

	helper := mp.NewMackerelPlugin(rack)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-rack-stats")
	}

	helper.Run()
}
<commit_msg>-metric-key -> -metric-key-prefix<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var sock string

func parseAddress(uri string) (scheme, path, port string, err error) {
	u, err := url.Parse(uri)
	if err != nil {
		return scheme, path, port, err
	}

	scheme = u.Scheme
	path = u.Path
	if path == "" {
		path = u.Host
	}

	host := strings.Split(u.Host, ":")
	if len(host) == 1 {
		port = "80"
	} else {
		port = host[1]
	}

	return scheme, path, port, err
}

func parseBody(r io.Reader, index string) (stats map[string]interface{}, err error) {
	scanner := bufio.NewScanner(r)
	stats = make(map[string]interface{})
	for scanner.Scan() {
		p := strings.Split(scanner.Text(), " ")
		if len(p) == 2 {
			stats[strings.Trim(p[0], ":")], err = strconv.ParseFloat(p[1], 64)
		} else {
			re := regexp.MustCompile(fmt.Sprintf("%s$", index))
			if ok := re.Match([]byte(p[0])); ok && err == nil {
				stats[strings.Trim(p[len(p)-2], ":")], err = strconv.ParseFloat(p[len(p)-1], 64)
			}
		}
	}
	stats["active"] = stats["active"].(float64) - 1

	return stats, err
}

func parseBodyHTTP(uri, port string) (stats map[string]interface{}, err error) {
	var req *http.Request
	req, err = http.NewRequest("GET", uri, nil)
	if err != nil {
		return stats, err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return stats, err
	}
	defer resp.Body.Close()

	stats, err = parseBody(resp.Body, ":"+port)

	return stats, err
}

func fakeDial(proto, addr string) (conn net.Conn, err error) {
	return net.Dial("unix", sock)
}

func parseBodyUnix(path string) (stats map[string]interface{}, err error) {
	tr := &http.Transport{
		Dial: fakeDial,
	}

	client := &http.Client{Transport: tr}
	resp, err := client.Get(fmt.Sprintf("http://dummy/%s", strings.TrimLeft(path, "/")))

	if err != nil {
		return stats, err
	}
	defer resp.Body.Close()

	stats, err = parseBody(resp.Body, sock)

	return stats, err
}

// RackStatsPlugin mackerel plugin for Rack servers
type RackStatsPlugin struct {
	Address   string
	Path      string
	MetricKey string
}

// FetchMetrics interface for mackerelplugin
func (u RackStatsPlugin) FetchMetrics() (stats map[string]interface{}, err error) {
	stats, err = u.parseStats()
	return stats, err
}

func (u RackStatsPlugin) parseStats() (stats map[string]interface{}, err error) {
	scheme, path, port, err := parseAddress(u.Address)

	switch scheme {
	case "http":
		stats, err = parseBodyHTTP(fmt.Sprintf("%s/%s", u.Address, strings.TrimLeft(u.Path, "/")), port)
	case "unix":
		sock = path
		stats, err = parseBodyUnix(u.Path)
	}

	return stats, err
}

// GraphDefinition interface for mackerelplugin
func (u RackStatsPlugin) GraphDefinition() map[string](mp.Graphs) {
	scheme, path, port, err := parseAddress(u.Address)
	if err != nil {
		log.Fatal(err)
	}

	var label string
	if u.MetricKey == "" {
		switch scheme {
		case "http":
			u.MetricKey = port
			label = fmt.Sprintf("Rack Port %s Stats", port)
		case "unix":
			u.MetricKey = strings.Replace(strings.Replace(path, "/", "_", -1), ".", "_", -1)
			label = fmt.Sprintf("Rack %s Stats", path)
		}
	} else {
		label = fmt.Sprintf("Rack %s Stats", u.MetricKey)
	}

	return map[string](mp.Graphs){
		fmt.Sprintf("%s.rack.stats", u.MetricKey): mp.Graphs{
			Label: label,
			Unit:  "integer",
			Metrics: [](mp.Metrics){
				mp.Metrics{Name: "queued", Label: "Queued", Diff: false},
				mp.Metrics{Name: "active", Label: "Active", Diff: false},
				mp.Metrics{Name: "writing", Label: "Writing", Diff: false},
				mp.Metrics{Name: "calling", Label: "Calling", Diff: false},
			},
		},
	}
}

func main() {
	optAddress := flag.String("address", "http://localhost:8080", "URL or Unix Domain Socket")
	optPath := flag.String("path", "/_raindrops", "Path")
	optMetricKey := flag.String("metric-key-prefix", "", "Metric Key Prefix")
	optVersion := flag.Bool("version", false, "Version")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	if *optVersion {
		fmt.Println("0.3")
		os.Exit(0)
	}

	var rack RackStatsPlugin
	rack.Address = *optAddress
	rack.Path = *optPath
	rack.MetricKey = *optMetricKey

	helper := mp.NewMackerelPlugin(rack)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-rack-stats")
	}

	helper.Run()
}
<|endoftext|>


<commit_before>package terminfo

import (
	"errors"
	"io"
	"os"
	"strings"
	"sync"

	"github.com/nhooyr/terminfo/caps"
)

var (
	ErrSmallFile  = errors.New("terminfo: file too small")
	ErrBadString  = errors.New("terminfo: bad string")
	ErrBigSection = errors.New("terminfo: section too big")
	ErrBadHeader  = errors.New("terminfo: bad header")
)

// header represents a Terminfo file's header.
type header [5]int16

// No need to store magic.
const (
	lenNames = iota
	lenBools
	lenNumbers
	lenStrings
	lenTable
)

const (
	lenExtBools = iota
	lenExtNumbers
	lenExtStrings
	lenExtOff
)

// lenFile returns the length of the file the header describes in bytes.
func (h header) lenFile() int16 {
	return h[lenNames] +
		h[lenBools] +
		(h[lenNames]+h[lenBools])%2 +
		h[lenNumbers]*2 +
		h[lenStrings]*2 +
		h[lenTable]
}

func (h header) lenExt() int16 {
	return h.len() +
		h[lenExtBools] +
		h[lenExtBools]%2 +
		h[lenExtNumbers]*2 +
		h[lenExtOff]*2 +
		h[lenTable]
}

// len returns the length of the header in bytes.
func (h header) len() int16 {
	return int16(len(h) * 2)
}

// littleEndian decodes a int16 starting at i in buf using little-endian byte order.
func littleEndian(i int16, buf []byte) int16 {
	return int16(buf[i+1])<<8 | int16(buf[i])
}

type reader struct {
	pos int16
	buf []byte
	ti  *Terminfo
	// TODO: use pointer here or nah?
	h              header
	extStringTable []byte
	extNameOffPos  int16 // position in the name offsets
	extNameTable   []byte
}

var readerPool = sync.Pool{
	New: func() interface{} {
		r := new(reader)
		// TODO: What is the max entry size talking about in terminfo(5)?
		r.buf = make([]byte, 4096)
		return r
	},
}

func (r *reader) sliceOff(off int16) []byte {
	// Just use off as ppos.
	off, r.pos = r.pos, r.pos+off
	return r.buf[off:r.pos]
}

func (r *reader) evenBoundary(i int16) {
	if i%2 == 1 {
		// Skip extra null byte inserted to align everything on word boundaries.
		r.pos++
	}
}

func (r *reader) nextExtName() (string, error) {
	loff := littleEndian(r.extNameOffPos, r.buf)
	lpos := loff
	for {
		if lpos >= r.h[lenTable] {
			return "", ErrBadString
		}
		if r.extNameTable[lpos] == 0 {
			r.extNameOffPos += 2
			return string(r.extNameTable[loff:lpos]), nil
		}
		lpos++
	}
}

// TODO read ncurses and find more sanity checks
func (r *reader) read(f *os.File) (err error) {
	fi, err := f.Stat()
	if err != nil {
		return
	}
	s := int16(fi.Size())
	if s < r.h.len() {
		return ErrSmallFile
	}
	if s > int16(cap(r.buf)) {
		r.buf = make([]byte, s, s*2+1)
	} else {
		r.buf = r.buf[:s]
	}
	if _, err = io.ReadAtLeast(f, r.buf, int(s)); err != nil {
		return
	}
	if littleEndian(0, r.buf) != 0x11A {
		return ErrBadHeader
	}
	r.pos = 2 // skip magic
	if err = r.readHeader(); err != nil {
		return
	}
	if s-r.pos < r.h.lenFile() {
		return ErrSmallFile
	}
	r.ti = new(Terminfo)
	r.ti.Names = strings.Split(string(r.sliceOff(r.h[lenNames])), "|")
	r.readBools()
	r.evenBoundary(r.pos)
	r.readNumbers()
	if err = r.readStrings(); err != nil || s <= r.pos {
		return
	}
	// We have extended capabilities.
	r.evenBoundary(r.pos)
	s -= r.pos
	if s < r.h.len() {
		return ErrSmallFile
	}
	if err = r.readHeader(); err != nil {
		return
	}
	if s < r.h.lenExt() {
		return ErrSmallFile
	}
	if err = r.setExtNameTable(); err != nil {
		return
	}
	if err = r.readExtBools(); err != nil {
		return
	}
	r.evenBoundary(r.h[lenExtBools])
	if err = r.readExtNumbers(); err != nil {
		return
	}
	return r.readExtStrings()
}

func (r *reader) readHeader() error {
	hbuf := r.sliceOff(r.h.len())
	for i := 0; i < len(r.h); i++ {
		n := littleEndian(int16(i*2), hbuf)
		if n < 0 {
			return ErrBadHeader
		}
		r.h[i] = n
	}
	return nil
}

func (r *reader) readBools() {
	if r.h[lenBools] >= caps.BoolCount {
		r.h[lenBools] = caps.BoolCount
	}
	for i, b := range r.sliceOff(r.h[lenBools]) {
		if b == 1 {
			r.ti.Bools[i] = true
		}
	}
}

func (r *reader) readNumbers() {
	if r.h[lenNumbers] >= caps.NumberCount {
		r.h[lenNumbers] = caps.NumberCount
	}
	nbuf := r.sliceOff(r.h[lenNumbers] * 2)
	for i := int16(0); i < r.h[lenNumbers]; i++ {
		if n := littleEndian(i*2, nbuf); n > -1 {
			r.ti.Numbers[i] = n
		}
	}
}

// readStrings reads the string and string table sections.
func (r *reader) readStrings() error {
	if r.h[lenStrings] >= caps.StringCount {
		r.h[lenStrings] = caps.StringCount
	}
	sbuf := r.sliceOff(r.h[lenStrings] * 2)
	table := r.sliceOff(r.h[lenTable])
	for i := int16(0); i < r.h[lenStrings]; i++ {
		if off := littleEndian(i*2, sbuf); off > -1 {
			j := off
			for {
				if j >= r.h[lenTable] {
					return ErrBadString
				}
				if table[j] == 0 {
					break
				}
				j++
			}
			r.ti.Strings[i] = string(table[off:j])
		}
	}
	return nil
}

func (r *reader) setExtNameTable() error {
	// Beginning of name offsets.
	nameOffPos := r.pos +
		r.h[lenExtBools] +
		r.h[lenExtBools]%2 +
		r.h[lenExtNumbers]*2 +
		r.h[lenExtStrings]*2
	lenNameOffs := (r.h[lenExtOff] - r.h[lenExtStrings]) * 2
	// Find last string offset.
	lpos, loff := nameOffPos, int16(0)
	for {
		lpos -= 2
		if lpos < r.pos {
			// TODO error?
			return ErrBadString
		}
		r.h[lenExtStrings]--
		if loff = littleEndian(lpos, r.buf); loff > -1 {
			break
		}
	}
	// Read the capability value.
	r.extStringTable = r.buf[nameOffPos+lenNameOffs:]
	val := ""
	for i := loff; ; i++ {
		if i >= r.h[lenTable] {
			return ErrBadString
		}
		if r.extStringTable[i] == 0 {
			val = string(r.extStringTable[loff:i])
			i++
			r.extStringTable, r.extNameTable = r.extStringTable[:loff], r.extStringTable[i:]
			break
		}
	}
	r.extNameOffPos = lpos + lenNameOffs
	name, err := r.nextExtName()
	if err != nil {
		// TODO error?
		return ErrBadString
	}
	r.ti.ExtStrings = make(map[string]string)
	r.ti.ExtStrings[name] = val
	// Set extNameOffPos to the start of the name offset section.
	r.extNameOffPos = nameOffPos
	return nil
}

func (r *reader) readExtBools() error {
	r.ti.ExtBools = make(map[string]bool)
	for _, b := range r.sliceOff(r.h[lenExtBools]) {
		if b == 1 {
			name, err := r.nextExtName()
			if err != nil {
				return err
			}
			r.ti.ExtBools[name] = true
		}
	}
	return nil
}

func (r *reader) readExtNumbers() error {
	r.ti.ExtNumbers = make(map[string]int16)
	nbuf := r.sliceOff(r.h[lenExtNumbers] * 2)
	for i := int16(0); i < r.h[lenExtNumbers]; i++ {
		if n := littleEndian(i*2, nbuf); n > -1 {
			name, err := r.nextExtName()
			if err != nil {
				return err
			}
			r.ti.ExtNumbers[name] = n
		}
	}
	return nil
}

func (r *reader) readExtStrings() error {
OFFLOOP:
	for lastPos := r.pos + r.h[lenExtStrings]*2; r.pos < lastPos; r.pos += 2 {
		if off := littleEndian(r.pos, r.buf); off > -1 {
			for i := int(off); i < len(r.extStringTable); i++ {
				if r.extStringTable[i] == 0 {
					name, err := r.nextExtName()
					if err != nil {
						return err
					}
					r.ti.ExtStrings[name] = string(r.extStringTable[off:i])
					continue OFFLOOP
				}
			}
			return ErrBadString
		}
	}
	return nil
}
<commit_msg>more cleanup<commit_after>package terminfo

import (
	"errors"
	"io"
	"os"
	"strings"
	"sync"

	"github.com/nhooyr/terminfo/caps"
)

var (
	ErrSmallFile  = errors.New("terminfo: file too small")
	ErrBadString  = errors.New("terminfo: bad string")
	ErrBigSection = errors.New("terminfo: section too big")
	ErrBadHeader  = errors.New("terminfo: bad header")
)

// header represents a Terminfo file's header.
type header [5]int16

// No need to store magic.
const (
	lenNames = iota
	lenBools
	lenNumbers
	lenStrings
	lenTable
)

const (
	lenExtBools = iota
	lenExtNumbers
	lenExtStrings
	lenExtOff
)

// lenFile returns the length of the file the header describes in bytes.
func (h header) lenFile() int16 {
	return h[lenNames] +
		h[lenBools] +
		(h[lenNames]+h[lenBools])%2 +
		h[lenNumbers]*2 +
		h[lenStrings]*2 +
		h[lenTable]
}

func (h header) lenExt() int16 {
	return h.len() +
		h[lenExtBools] +
		h[lenExtBools]%2 +
		h[lenExtNumbers]*2 +
		h[lenExtOff]*2 +
		h[lenTable]
}

// len returns the length of the header in bytes.
func (h header) len() int16 {
	return int16(len(h) * 2)
}

// littleEndian decodes a int16 starting at i in buf using little-endian byte order.
func littleEndian(i int16, buf []byte) int16 {
	return int16(buf[i+1])<<8 | int16(buf[i])
}

type reader struct {
	pos int16
	buf []byte
	ti  *Terminfo
	// TODO: use pointer here or nah?
	h              header
	extStringTable []byte
	extNameOffPos  int16 // position in the name offsets
	extNameTable   []byte
}

var readerPool = sync.Pool{
	New: func() interface{} {
		r := new(reader)
		// TODO: What is the max entry size talking about in terminfo(5)?
		r.buf = make([]byte, 4096)
		return r
	},
}

func (r *reader) sliceOff(off int16) []byte {
	// Just use off as ppos.
	off, r.pos = r.pos, r.pos+off
	return r.buf[off:r.pos]
}

func (r *reader) evenBoundary(i int16) {
	if i%2 == 1 {
		// Skip extra null byte inserted to align everything on word boundaries.
		r.pos++
	}
}

func (r *reader) nextExtName() (string, error) {
	loff := littleEndian(r.extNameOffPos, r.buf)
	lpos := loff
	for {
		if lpos >= r.h[lenTable] {
			return "", ErrBadString
		}
		if r.extNameTable[lpos] == 0 {
			r.extNameOffPos += 2
			return string(r.extNameTable[loff:lpos]), nil
		}
		lpos++
	}
}

// TODO read ncurses and find more sanity checks
func (r *reader) read(f *os.File) (err error) {
	fi, err := f.Stat()
	if err != nil {
		return
	}
	s := int16(fi.Size())
	if s < r.h.len() {
		return ErrSmallFile
	}
	if s > int16(cap(r.buf)) {
		r.buf = make([]byte, s, s*2+1)
	} else {
		r.buf = r.buf[:s]
	}
	if _, err = io.ReadAtLeast(f, r.buf, int(s)); err != nil {
		return
	}
	if littleEndian(0, r.buf) != 0x11A {
		return ErrBadHeader
	}
	r.pos = 2 // skip magic
	if err = r.readHeader(); err != nil {
		return
	}
	if s-r.pos < r.h.lenFile() {
		return ErrSmallFile
	}
	r.ti = new(Terminfo)
	r.ti.Names = strings.Split(string(r.sliceOff(r.h[lenNames])), "|")
	r.readBools()
	r.evenBoundary(r.pos)
	r.readNumbers()
	if err = r.readStrings(); err != nil || s <= r.pos {
		return
	}
	// We have extended capabilities.
	r.evenBoundary(r.pos)
	s -= r.pos
	if s < r.h.len() {
		return ErrSmallFile
	}
	if err = r.readHeader(); err != nil {
		return
	}
	if s < r.h.lenExt() {
		return ErrSmallFile
	}
	if err = r.setExtNameTable(); err != nil {
		return
	}
	if err = r.readExtBools(); err != nil {
		return
	}
	r.evenBoundary(r.h[lenExtBools])
	if err = r.readExtNumbers(); err != nil {
		return
	}
	return r.readExtStrings()
}

func (r *reader) readHeader() error {
	hbuf := r.sliceOff(r.h.len())
	for i := 0; i < len(r.h); i++ {
		n := littleEndian(int16(i*2), hbuf)
		if n < 0 {
			return ErrBadHeader
		}
		r.h[i] = n
	}
	return nil
}

func (r *reader) readBools() {
	if r.h[lenBools] >= caps.BoolCount {
		r.h[lenBools] = caps.BoolCount
	}
	for i, b := range r.sliceOff(r.h[lenBools]) {
		if b == 1 {
			r.ti.Bools[i] = true
		}
	}
}

func (r *reader) readNumbers() {
	if r.h[lenNumbers] >= caps.NumberCount {
		r.h[lenNumbers] = caps.NumberCount
	}
	nbuf := r.sliceOff(r.h[lenNumbers] * 2)
	for i := int16(0); i < r.h[lenNumbers]; i++ {
		if n := littleEndian(i*2, nbuf); n > -1 {
			r.ti.Numbers[i] = n
		}
	}
}

// readStrings reads the string and string table sections.
func (r *reader) readStrings() error {
	if r.h[lenStrings] >= caps.StringCount {
		r.h[lenStrings] = caps.StringCount
	}
	sbuf := r.sliceOff(r.h[lenStrings] * 2)
	table := r.sliceOff(r.h[lenTable])
	for i := int16(0); i < r.h[lenStrings]; i++ {
		if off := littleEndian(i*2, sbuf); off > -1 {
			j := off
			for {
				if j >= r.h[lenTable] {
					return ErrBadString
				}
				if table[j] == 0 {
					break
				}
				j++
			}
			r.ti.Strings[i] = string(table[off:j])
		}
	}
	return nil
}

func (r *reader) setExtNameTable() error {
	// Beginning of name offsets.
	nameOffPos := r.pos +
		r.h[lenExtBools] +
		r.h[lenExtBools]%2 +
		r.h[lenExtNumbers]*2 +
		r.h[lenExtStrings]*2
	lenNameOffs := (r.h[lenExtOff] - r.h[lenExtStrings]) * 2
	// Find last string offset.
	lpos, loff := nameOffPos, int16(0)
	for {
		lpos -= 2
		if lpos < r.pos {
			// TODO error?
			return ErrBadString
		}
		r.h[lenExtStrings]--
		if loff = littleEndian(lpos, r.buf); loff > -1 {
			break
		}
	}
	// Read the capability value.
	r.extStringTable = r.buf[nameOffPos+lenNameOffs:]
	i := loff
	for ; ; i++ {
		if i >= r.h[lenTable] {
			return ErrBadString
		}
		if r.extStringTable[i] == 0 {
			break
		}
	}
	val := string(r.extStringTable[loff:i])
	r.extNameTable = r.extStringTable[i+1:]
	r.extStringTable = r.extStringTable[:loff]
	r.extNameOffPos = lpos + lenNameOffs
	key, err := r.nextExtName()
	if err != nil {
		// TODO error?
		return ErrBadString
	}
	r.ti.ExtStrings = make(map[string]string)
	r.ti.ExtStrings[key] = val
	// Set extNameOffPos to the start of the name offset section.
	r.extNameOffPos = nameOffPos
	return nil
}

func (r *reader) readExtBools() error {
	r.ti.ExtBools = make(map[string]bool)
	for _, b := range r.sliceOff(r.h[lenExtBools]) {
		if b == 1 {
			key, err := r.nextExtName()
			if err != nil {
				return err
			}
			r.ti.ExtBools[key] = true
		}
	}
	return nil
}

func (r *reader) readExtNumbers() error {
	r.ti.ExtNumbers = make(map[string]int16)
	nbuf := r.sliceOff(r.h[lenExtNumbers] * 2)
	for i := int16(0); i < r.h[lenExtNumbers]; i++ {
		if n := littleEndian(i*2, nbuf); n > -1 {
			key, err := r.nextExtName()
			if err != nil {
				return err
			}
			r.ti.ExtNumbers[key] = n
		}
	}
	return nil
}

func (r *reader) readExtStrings() error {
OFFLOOP:
	for lastPos := r.pos + r.h[lenExtStrings]*2; r.pos < lastPos; r.pos += 2 {
		if off := littleEndian(r.pos, r.buf); off > -1 {
			for i := int(off); i < len(r.extStringTable); i++ {
				if r.extStringTable[i] == 0 {
					key, err := r.nextExtName()
					if err != nil {
						return err
					}
					r.ti.ExtStrings[key] = string(r.extStringTable[off:i])
					continue OFFLOOP
				}
			}
			return ErrBadString
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/xml"
	"errors"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"net/http"
	"regexp"
	"strconv"
)

const createUserTable = `create table if not exists user(id integer primary key, name varchar(255))`

func OpenWithMigrate(path string) (*sql.DB, error) {
	db, err := sql.Open("sqlite3", path)
	if err != nil {
		return nil, fmt.Errorf("failed to open user database %v", path)
	}
	if _, err := db.Exec(createUserTable); err != nil {
		return nil, err
	}
	return db, nil
}

var rawUserIDReg = regexp.MustCompile(`^\d+$`)

type UserRepo struct {
	db *sql.DB
	mp map[int64]User
}

func NewUserRepo(db *sql.DB) *UserRepo {
	return &UserRepo{
		db: db,
		mp: make(map[int64]User),
	}
}

func (r *UserRepo) Get(ID string) User {
	if !rawUserIDReg.MatchString(ID) {
		return User{
			IsRawUser: false,
			ID:        0,
			Name:      "184",
		}
	}

	id, err := strconv.ParseInt(ID, 10, 64)
	if err != nil {
		return User{
			IsRawUser: true,
			ID:        0,
			Name:      ID,
		}
	}

	u, err := r.getByRawID(id)
	if err != nil {
		return User{
			IsRawUser: true,
			ID:        id,
			Name:      ID,
		}
	}

	u.IsRawUser = true
	return u
}

func (r *UserRepo) writeToDB(user User) error {
	_, err := r.db.Exec("insert into user values(?, ?)", user.ID, user.Name)
	return err
}

func (r *UserRepo) readFromDB(id int64) (User, error) {
	row := r.db.QueryRow("select from user where id = ?", id)
	var user User
	err := row.Scan(&user.ID, &user.Name)
	return user, err
}

func (r *UserRepo) getByRawID(id int64) (User, error) {
	if user, ok := r.mp[id]; ok {
		return user, nil
	}
	if user, err := r.readFromDB(id); err == nil {
		r.mp[id] = user
		return user, nil
	}
	user, err := getUserFromAPI(id)
	if err == nil {
		r.mp[id] = user
		r.writeToDB(user)
		return user, nil
	}
	return User{}, err
}

func getUserFromAPI(id int64) (User, error) {
	u := fmt.Sprintf("http://seiga.nicovideo.jp/api/user/info?id=%d", id)
	res, err := http.Get(u)
	if err != nil {
		return User{}, err
	}
	defer res.Body.Close()

	var resXML struct {
		XMLName xml.Name `xml:"response"`
		User    User     `xml:"user"`
	}
	if err := xml.NewDecoder(res.Body).Decode(&resXML); err != nil {
		return User{}, err
	}
	if resXML.User.ID != id || resXML.User.Name == "-" {
		return User{}, errors.New("user not found")
	}
	return resXML.User, nil
}
<commit_msg>ユーザー情報取得API変更<commit_after>package main

import (
	"database/sql"
	"encoding/xml"
	"errors"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"net/http"
	"regexp"
	"strconv"
)

const createUserTable = `create table if not exists user(id integer primary key, name varchar(255))`

func OpenWithMigrate(path string) (*sql.DB, error) {
	db, err := sql.Open("sqlite3", path)
	if err != nil {
		return nil, fmt.Errorf("failed to open user database %v", path)
	}
	if _, err := db.Exec(createUserTable); err != nil {
		return nil, err
	}
	return db, nil
}

var rawUserIDReg = regexp.MustCompile(`^\d+$`)

type UserRepo struct {
	db *sql.DB
	mp map[int64]User
}

func NewUserRepo(db *sql.DB) *UserRepo {
	return &UserRepo{
		db: db,
		mp: make(map[int64]User),
	}
}

func (r *UserRepo) Get(ID string) User {
	if !rawUserIDReg.MatchString(ID) {
		return User{
			IsRawUser: false,
			ID:        0,
			Name:      "184",
		}
	}

	id, err := strconv.ParseInt(ID, 10, 64)
	if err != nil {
		return User{
			IsRawUser: true,
			ID:        0,
			Name:      ID,
		}
	}

	u, err := r.getByRawID(id)
	if err != nil {
		return User{
			IsRawUser: true,
			ID:        id,
			Name:      ID,
		}
	}

	u.IsRawUser = true
	return u
}

func (r *UserRepo) writeToDB(user User) error {
	_, err := r.db.Exec("insert into user values(?, ?)", user.ID, user.Name)
	return err
}

func (r *UserRepo) readFromDB(id int64) (User, error) {
	row := r.db.QueryRow("select from user where id = ?", id)
	var user User
	err := row.Scan(&user.ID, &user.Name)
	return user, err
}

func (r *UserRepo) getByRawID(id int64) (User, error) {
	if user, ok := r.mp[id]; ok {
		return user, nil
	}
	if user, err := r.readFromDB(id); err == nil {
		r.mp[id] = user
		return user, nil
	}
	user, err := getUserFromAPI(id)
	if err == nil {
		r.mp[id] = user
		r.writeToDB(user)
		return user, nil
	}
	return User{}, err
}

func getUserFromAPI(id int64) (User, error) {
	u := fmt.Sprintf("http://api.ce.nicovideo.jp/api/v1/user.info?user_id=%d", id)
	res, err := http.Get(u)
	if err != nil {
		return User{}, err
	}
	defer res.Body.Close()

	var resXML struct {
		XMLName xml.Name `xml:"nicovideo_user_response"`
		Status  string   `xml:"status,attr"`
		User    User     `xml:"user"`
	}
	if err := xml.NewDecoder(res.Body).Decode(&resXML); err != nil {
		return User{}, err
	}
	if resXML.Status != "ok" {
		return User{}, errors.New("user not found")
	}
	return resXML.User, nil
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbft

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"

	bleveHttp "github.com/blevesearch/bleve/http"

	"github.com/gorilla/mux"

	log "github.com/couchbase/clog"
)

var startTime = time.Now()

func NewManagerRESTRouter(versionMain string, mgr *Manager,
	staticDir, staticETag string, mr *MsgRing) (*mux.Router, error) {
	// create a router to serve static files
	r := staticFileRouter(staticDir, staticETag, []string{
		"/indexes",
		"/nodes",
		"/monitor",
		"/manage",
		"/logs",
		"/debug",
	})

	r.Handle("/api/index", NewListIndexHandler(mgr)).Methods("GET")
	r.Handle("/api/index/{indexName}", NewCreateIndexHandler(mgr)).Methods("PUT")
	r.Handle("/api/index/{indexName}", NewDeleteIndexHandler(mgr)).Methods("DELETE")
	r.Handle("/api/index/{indexName}", NewGetIndexHandler(mgr)).Methods("GET")

	if mgr.tagsMap == nil || mgr.tagsMap["queryer"] {
		r.Handle("/api/index/{indexName}/count",
			NewCountHandler(mgr)).Methods("GET")
		r.Handle("/api/index/{indexName}/query",
			NewQueryHandler(mgr)).Methods("POST")
	}

	r.Handle("/api/index/{indexName}/planFreezeControl/{op}",
		NewIndexControlHandler(mgr, "planFreeze", map[string]bool{
			"freeze":   true,
			"unfreeze": true,
		})).Methods("POST")
	r.Handle("/api/index/{indexName}/ingestControl/{op}",
		NewIndexControlHandler(mgr, "write", map[string]bool{
			"pause":  true,
			"resume": true,
		})).Methods("POST")
	r.Handle("/api/index/{indexName}/queryControl/{op}",
		NewIndexControlHandler(mgr, "read", map[string]bool{
			"allow":    true,
			"disallow": true,
		})).Methods("POST")

	// We use standard bleveHttp handlers for the /api/pindex-bleve endpoints.
	//
	// TODO: Need to cleanly separate the /api/pindex and
	// /api/pindex-bleve endpoints.
	if mgr.tagsMap == nil || mgr.tagsMap["pindex"] {
		r.Handle("/api/pindex",
			NewListPIndexHandler(mgr)).Methods("GET")
		r.Handle("/api/pindex/{pindexName}",
			NewGetPIndexHandler(mgr)).Methods("GET")
		r.Handle("/api/pindex/{pindexName}/count",
			NewCountPIndexHandler(mgr)).Methods("GET")
		r.Handle("/api/pindex/{pindexName}/query",
			NewQueryPIndexHandler(mgr)).Methods("POST")

		listIndexesHandler := bleveHttp.NewListIndexesHandler()
		r.Handle("/api/pindex-bleve",
			listIndexesHandler).Methods("GET")

		getIndexHandler := bleveHttp.NewGetIndexHandler()
		getIndexHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}",
			getIndexHandler).Methods("GET")

		docCountHandler := bleveHttp.NewDocCountHandler("")
		docCountHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}/count",
			docCountHandler).Methods("GET")

		searchHandler := bleveHttp.NewSearchHandler("")
		searchHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}/query",
			searchHandler).Methods("POST")

		docGetHandler := bleveHttp.NewDocGetHandler("")
		docGetHandler.IndexNameLookup = pindexNameLookup
		docGetHandler.DocIDLookup = docIDLookup
		r.Handle("/api/pindex-bleve/{pindexName}/doc/{docID}",
			docGetHandler).Methods("GET")

		debugDocHandler := bleveHttp.NewDebugDocumentHandler("")
		debugDocHandler.IndexNameLookup = pindexNameLookup
		debugDocHandler.DocIDLookup = docIDLookup
		r.Handle("/api/pindex-bleve/{pindexName}/docDebug/{docID}",
			debugDocHandler).Methods("GET")

		listFieldsHandler := bleveHttp.NewListFieldsHandler("")
		listFieldsHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}/fields",
			listFieldsHandler).Methods("GET")
	}

	r.Handle("/api/cfg", NewCfgGetHandler(mgr)).Methods("GET")
	r.Handle("/api/cfgRefresh", NewCfgRefreshHandler(mgr)).Methods("POST")

	r.Handle("/api/diag", NewDiagGetHandler(versionMain, mgr, mr)).Methods("GET")

	r.Handle("/api/log", NewGetLogHandler(mr)).Methods("GET")

	r.Handle("/api/managerKick", NewManagerKickHandler(mgr)).Methods("POST")
	r.Handle("/api/managerMeta", NewManagerMetaHandler(mgr)).Methods("GET")

	r.Handle("/api/runtime", NewRuntimeGetHandler(versionMain, mgr)).Methods("GET")

	r.HandleFunc("/api/runtime/flags", restGetRuntimeFlags).Methods("GET")
	r.HandleFunc("/api/runtime/gc", restPostRuntimeGC).Methods("POST")
	r.HandleFunc("/api/runtime/profile/cpu", restProfileCPU).Methods("POST")
	r.HandleFunc("/api/runtime/profile/memory", restProfileMemory).Methods("POST")
	r.HandleFunc("/api/runtime/statsMem", restGetRuntimeStatsMem).Methods("GET")
	r.HandleFunc("/api/runtime/stats", restGetRuntimeStats).Methods("GET")

	r.Handle("/api/stats", NewStatsHandler(mgr)).Methods("GET")

	return r, nil
}

func muxVariableLookup(req *http.Request, name string) string {
	return mux.Vars(req)[name]
}

type RuntimeGetHandler struct {
	versionMain string
	mgr         *Manager
}

func NewRuntimeGetHandler(versionMain string, mgr *Manager) *RuntimeGetHandler {
	return &RuntimeGetHandler{versionMain: versionMain, mgr: mgr}
}

func (h *RuntimeGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	mustEncode(w, map[string]interface{}{
		"versionMain": h.versionMain,
		"versionData": h.mgr.version,
		"arch":        runtime.GOARCH,
		"os":          runtime.GOOS,
		"numCPU":      runtime.NumCPU(),
		"go": map[string]interface{}{
			"GOMAXPROCS": runtime.GOMAXPROCS(0),
			"GOROOT":     runtime.GOROOT(),
			"version":    runtime.Version(),
			"compiler":   runtime.Compiler,
		},
	})
}

func restGetRuntimeFlags(w http.ResponseWriter, r *http.Request) {
	m := map[string]interface{}{}
	flag.VisitAll(func(f *flag.Flag) {
		m[f.Name] = f.Value
	})
	mustEncode(w, m)
}

func restPostRuntimeGC(w http.ResponseWriter, r *http.Request) {
	runtime.GC()
}

// To start a cpu profiling...
//    curl -X POST http://127.0.0.1:9090/api/runtime/profile/cpu -d secs=5
// To analyze a profiling...
//    go tool pprof ./cbft run-cpu.pprof
func restProfileCPU(w http.ResponseWriter, r *http.Request) {
	secs, err := strconv.Atoi(r.FormValue("secs"))
	if err != nil || secs <= 0 {
		http.Error(w, "incorrect or missing secs parameter", 400)
		return
	}
	fname := "./run-cpu.pprof"
	os.Remove(fname)
	f, err := os.Create(fname)
	if err != nil {
		http.Error(w, fmt.Sprintf("profileCPU:"+
			" couldn't create file: %s, err: %v",
			fname, err), 500)
		return
	}
	log.Printf("profileCPU: start, file: %s", fname)
	err = pprof.StartCPUProfile(f)
	if err != nil {
		http.Error(w, fmt.Sprintf("profileCPU:"+
			" couldn't start CPU profile, file: %s, err: %v",
			fname, err), 500)
		return
	}
	go func() {
		time.Sleep(time.Duration(secs) * time.Second)
		pprof.StopCPUProfile()
		f.Close()
		log.Printf("profileCPU: end, file: %s", fname)
	}()
	w.WriteHeader(204)
}

// To grab a memory profiling...
//    curl -X POST http://127.0.0.1:9090/api/runtime/profile/memory
// To analyze a profiling...
//    go tool pprof ./cbft run-memory.pprof
func restProfileMemory(w http.ResponseWriter, r *http.Request) {
	fname := "./run-memory.pprof"
	os.Remove(fname)
	f, err := os.Create(fname)
	if err != nil {
		http.Error(w, fmt.Sprintf("profileMemory:"+
			" couldn't create file: %v, err: %v",
			fname, err), 500)
		return
	}
	defer f.Close()
	pprof.WriteHeapProfile(f)
}

func restGetRuntimeStatsMem(w http.ResponseWriter, r *http.Request) {
	memStats := &runtime.MemStats{}
	runtime.ReadMemStats(memStats)
	mustEncode(w, memStats)
}

func restGetRuntimeStats(w http.ResponseWriter, r *http.Request) {
	mustEncode(w, map[string]interface{}{
		"startTime": startTime,
		"go": map[string]interface{}{
			"numGoroutine":   runtime.NumGoroutine(),
			"numCgoCall":     runtime.NumCgoCall(),
			"memProfileRate": runtime.MemProfileRate,
		},
	})
}
<commit_msg>sorted the REST handler registrations<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbft

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"

	bleveHttp "github.com/blevesearch/bleve/http"

	"github.com/gorilla/mux"

	log "github.com/couchbase/clog"
)

var startTime = time.Now()

func NewManagerRESTRouter(versionMain string, mgr *Manager,
	staticDir, staticETag string, mr *MsgRing) (*mux.Router, error) {
	// create a router to serve static files
	r := staticFileRouter(staticDir, staticETag, []string{
		"/indexes",
		"/nodes",
		"/monitor",
		"/manage",
		"/logs",
		"/debug",
	})

	r.Handle("/api/index", NewListIndexHandler(mgr)).Methods("GET")
	r.Handle("/api/index/{indexName}", NewCreateIndexHandler(mgr)).Methods("PUT")
	r.Handle("/api/index/{indexName}", NewDeleteIndexHandler(mgr)).Methods("DELETE")
	r.Handle("/api/index/{indexName}", NewGetIndexHandler(mgr)).Methods("GET")

	if mgr.tagsMap == nil || mgr.tagsMap["queryer"] {
		r.Handle("/api/index/{indexName}/count",
			NewCountHandler(mgr)).Methods("GET")
		r.Handle("/api/index/{indexName}/query",
			NewQueryHandler(mgr)).Methods("POST")
	}

	r.Handle("/api/index/{indexName}/planFreezeControl/{op}",
		NewIndexControlHandler(mgr, "planFreeze", map[string]bool{
			"freeze":   true,
			"unfreeze": true,
		})).Methods("POST")
	r.Handle("/api/index/{indexName}/ingestControl/{op}",
		NewIndexControlHandler(mgr, "write", map[string]bool{
			"pause":  true,
			"resume": true,
		})).Methods("POST")
	r.Handle("/api/index/{indexName}/queryControl/{op}",
		NewIndexControlHandler(mgr, "read", map[string]bool{
			"allow":    true,
			"disallow": true,
		})).Methods("POST")

	// We use standard bleveHttp handlers for the /api/pindex-bleve endpoints.
	//
	// TODO: Need to cleanly separate the /api/pindex and
	// /api/pindex-bleve endpoints.
	if mgr.tagsMap == nil || mgr.tagsMap["pindex"] {
		r.Handle("/api/pindex",
			NewListPIndexHandler(mgr)).Methods("GET")
		r.Handle("/api/pindex/{pindexName}",
			NewGetPIndexHandler(mgr)).Methods("GET")
		r.Handle("/api/pindex/{pindexName}/count",
			NewCountPIndexHandler(mgr)).Methods("GET")
		r.Handle("/api/pindex/{pindexName}/query",
			NewQueryPIndexHandler(mgr)).Methods("POST")

		listIndexesHandler := bleveHttp.NewListIndexesHandler()
		r.Handle("/api/pindex-bleve",
			listIndexesHandler).Methods("GET")

		getIndexHandler := bleveHttp.NewGetIndexHandler()
		getIndexHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}",
			getIndexHandler).Methods("GET")

		docCountHandler := bleveHttp.NewDocCountHandler("")
		docCountHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}/count",
			docCountHandler).Methods("GET")

		searchHandler := bleveHttp.NewSearchHandler("")
		searchHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}/query",
			searchHandler).Methods("POST")

		docGetHandler := bleveHttp.NewDocGetHandler("")
		docGetHandler.IndexNameLookup = pindexNameLookup
		docGetHandler.DocIDLookup = docIDLookup
		r.Handle("/api/pindex-bleve/{pindexName}/doc/{docID}",
			docGetHandler).Methods("GET")

		debugDocHandler := bleveHttp.NewDebugDocumentHandler("")
		debugDocHandler.IndexNameLookup = pindexNameLookup
		debugDocHandler.DocIDLookup = docIDLookup
		r.Handle("/api/pindex-bleve/{pindexName}/docDebug/{docID}",
			debugDocHandler).Methods("GET")

		listFieldsHandler := bleveHttp.NewListFieldsHandler("")
		listFieldsHandler.IndexNameLookup = pindexNameLookup
		r.Handle("/api/pindex-bleve/{pindexName}/fields",
			listFieldsHandler).Methods("GET")
	}

	r.Handle("/api/cfg", NewCfgGetHandler(mgr)).Methods("GET")
	r.Handle("/api/cfgRefresh", NewCfgRefreshHandler(mgr)).Methods("POST")

	r.Handle("/api/diag", NewDiagGetHandler(versionMain, mgr, mr)).Methods("GET")

	r.Handle("/api/log", NewGetLogHandler(mr)).Methods("GET")

	r.Handle("/api/managerKick", NewManagerKickHandler(mgr)).Methods("POST")
	r.Handle("/api/managerMeta", NewManagerMetaHandler(mgr)).Methods("GET")

	r.Handle("/api/runtime", NewRuntimeGetHandler(versionMain, mgr)).Methods("GET")

	r.HandleFunc("/api/runtime/flags", restGetRuntimeFlags).Methods("GET")
	r.HandleFunc("/api/runtime/gc", restPostRuntimeGC).Methods("POST")
	r.HandleFunc("/api/runtime/profile/cpu", restProfileCPU).Methods("POST")
	r.HandleFunc("/api/runtime/profile/memory", restProfileMemory).Methods("POST")
	r.HandleFunc("/api/runtime/stats", restGetRuntimeStats).Methods("GET")
	r.HandleFunc("/api/runtime/statsMem", restGetRuntimeStatsMem).Methods("GET")

	r.Handle("/api/stats", NewStatsHandler(mgr)).Methods("GET")

	return r, nil
}

func muxVariableLookup(req *http.Request, name string) string {
	return mux.Vars(req)[name]
}

type RuntimeGetHandler struct {
	versionMain string
	mgr         *Manager
}

func NewRuntimeGetHandler(versionMain string, mgr *Manager) *RuntimeGetHandler {
	return &RuntimeGetHandler{versionMain: versionMain, mgr: mgr}
}

func (h *RuntimeGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	mustEncode(w, map[string]interface{}{
		"versionMain": h.versionMain,
		"versionData": h.mgr.version,
		"arch":        runtime.GOARCH,
		"os":          runtime.GOOS,
		"numCPU":      runtime.NumCPU(),
		"go": map[string]interface{}{
			"GOMAXPROCS": runtime.GOMAXPROCS(0),
			"GOROOT":     runtime.GOROOT(),
			"version":    runtime.Version(),
			"compiler":   runtime.Compiler,
		},
	})
}

func restGetRuntimeFlags(w http.ResponseWriter, r *http.Request) {
	m := map[string]interface{}{}
	flag.VisitAll(func(f *flag.Flag) {
		m[f.Name] = f.Value
	})
	mustEncode(w, m)
}

func restPostRuntimeGC(w http.ResponseWriter, r *http.Request) {
	runtime.GC()
}

// To start a cpu profiling...
//    curl -X POST http://127.0.0.1:9090/api/runtime/profile/cpu -d secs=5
// To analyze a profiling...
//    go tool pprof ./cbft run-cpu.pprof
func restProfileCPU(w http.ResponseWriter, r *http.Request) {
	secs, err := strconv.Atoi(r.FormValue("secs"))
	if err != nil || secs <= 0 {
		http.Error(w, "incorrect or missing secs parameter", 400)
		return
	}
	fname := "./run-cpu.pprof"
	os.Remove(fname)
	f, err := os.Create(fname)
	if err != nil {
		http.Error(w, fmt.Sprintf("profileCPU:"+
			" couldn't create file: %s, err: %v",
			fname, err), 500)
		return
	}
	log.Printf("profileCPU: start, file: %s", fname)
	err = pprof.StartCPUProfile(f)
	if err != nil {
		http.Error(w, fmt.Sprintf("profileCPU:"+
			" couldn't start CPU profile, file: %s, err: %v",
			fname, err), 500)
		return
	}
	go func() {
		time.Sleep(time.Duration(secs) * time.Second)
		pprof.StopCPUProfile()
		f.Close()
		log.Printf("profileCPU: end, file: %s", fname)
	}()
	w.WriteHeader(204)
}

// To grab a memory profiling...
//    curl -X POST http://127.0.0.1:9090/api/runtime/profile/memory
// To analyze a profiling...
//    go tool pprof ./cbft run-memory.pprof
func restProfileMemory(w http.ResponseWriter, r *http.Request) {
	fname := "./run-memory.pprof"
	os.Remove(fname)
	f, err := os.Create(fname)
	if err != nil {
		http.Error(w, fmt.Sprintf("profileMemory:"+
			" couldn't create file: %v, err: %v",
			fname, err), 500)
		return
	}
	defer f.Close()
	pprof.WriteHeapProfile(f)
}

func restGetRuntimeStatsMem(w http.ResponseWriter, r *http.Request) {
	memStats := &runtime.MemStats{}
	runtime.ReadMemStats(memStats)
	mustEncode(w, memStats)
}

func restGetRuntimeStats(w http.ResponseWriter, r *http.Request) {
	mustEncode(w, map[string]interface{}{
		"startTime": startTime,
		"go": map[string]interface{}{
			"numGoroutine":   runtime.NumGoroutine(),
			"numCgoCall":     runtime.NumCgoCall(),
			"memProfileRate": runtime.MemProfileRate,
		},
	})
}
<|endoftext|>


<commit_before>package ring

/*
The DefaultCapacity of an uninitialized Ring buffer.

Changing this value only affects ring buffers created after it is changed.
*/
var DefaultCapacity int = 10

/*
Type Ring implements a Circular Buffer.
The default value of the Ring struct is a valid (empty) Ring buffer with capacity DefaultCapacify.
*/
type Ring struct {
	head int // the most recent value written
	tail int // the least recent value written
	buff []interface{}
}

/*
Set the maximum size of the ring buffer.
*/
func (r *Ring) SetCapacity(size int) {
	r.checkInit()
	r.extend(size)
}

/*
Capacity returns the current capacity of the ring buffer.
*/
func (r Ring) Capacity() int {
	return len(r.buff)
}

/*
Enqueue a value into the Ring buffer.
*/
func (r *Ring) Enqueue(i interface{}) {
	r.checkInit()
	r.set(r.head+1, i)
	old := r.head
	r.head = r.mod(r.head+1)
	if old != -1 && r.head == r.tail {
		r.tail = r.mod(r.tail + 1)
	}
}

/*
Dequeue a value from the Ring buffer.

Returns nil if the ring buffer is empty.
*/
func (r *Ring) Dequeue() interface{} {
	r.checkInit()
	if r.head == -1 {
		return nil
	}
	v := r.get(r.tail)
	if r.tail == r.head {
		r.head = -1
		r.tail = 0
	} else {
		r.tail = r.mod(r.tail + 1)
	}
	return v
}

/*
Read the value that Dequeue would have dequeued without actually dequeuing it.

Returns nil if the ring buffer is empty.
*/
func (r *Ring) Peek() interface{} {
	r.checkInit()
	if r.head == -1 {
		return nil
	}
	return r.get(r.tail)
}

/*
Values returns a slice of all the values in the circular buffer without modifying them at all.
The returned slice can be modified independently of the circular buffer. However, the values inside the slice
are shared between the slice and circular buffer.
*/
func (r *Ring) Values() []interface{} {
	if r.head == -1 {
		return []interface{}{}
	}
	arr := make([]interface{}, 0, r.Capacity())
	for i := 0; i < r.Capacity(); i++ {
		idx := r.mod(i+r.tail)
		arr = append(arr, r.get(idx))
		if idx == r.head {
			break
		}
	}
	return arr
}

/**
*** Unexported methods beyond this point.
**/

// sets a value at the given unmodified index and returns the modified index of the value
func (r *Ring) set(p int, v interface{}) {
	r.buff[r.mod(p)] = v
}

// gets a value based at a given unmodified index
func (r *Ring) get(p int) interface{} {
	return r.buff[r.mod(p)]
}

// returns the modified index of an unmodified index
func (r *Ring) mod(p int) int {
	return p % len(r.buff)
}

func (r *Ring) checkInit() {
	if r.buff == nil {
		r.buff = make([]interface{}, DefaultCapacity)
		for i := range r.buff {
			r.buff[i] = nil
		}
		r.head, r.tail = -1, 0
	}
}

func (r *Ring) extend(size int) {
	if size == len(r.buff) {
		return
	} else if size < len(r.buff) {
		r.buff = r.buff[0:size]
	}
	newb := make([]interface{}, size-len(r.buff))
	for i := range newb {
		newb[i] = nil
	}
	r.buff = append(r.buff, newb...)
}
<commit_msg>Added pkg doc<commit_after>/*
Package ring provides a simple implementation of a ring buffer.
*/
package ring

/*
The DefaultCapacity of an uninitialized Ring buffer.

Changing this value only affects ring buffers created after it is changed.
*/
var DefaultCapacity int = 10

/*
Type Ring implements a Circular Buffer.
The default value of the Ring struct is a valid (empty) Ring buffer with capacity DefaultCapacify.
*/
type Ring struct {
	head int // the most recent value written
	tail int // the least recent value written
	buff []interface{}
}

/*
Set the maximum size of the ring buffer.
*/
func (r *Ring) SetCapacity(size int) {
	r.checkInit()
	r.extend(size)
}

/*
Capacity returns the current capacity of the ring buffer.
*/
func (r Ring) Capacity() int {
	return len(r.buff)
}

/*
Enqueue a value into the Ring buffer.
*/
func (r *Ring) Enqueue(i interface{}) {
	r.checkInit()
	r.set(r.head+1, i)
	old := r.head
	r.head = r.mod(r.head+1)
	if old != -1 && r.head == r.tail {
		r.tail = r.mod(r.tail + 1)
	}
}

/*
Dequeue a value from the Ring buffer.

Returns nil if the ring buffer is empty.
*/
func (r *Ring) Dequeue() interface{} {
	r.checkInit()
	if r.head == -1 {
		return nil
	}
	v := r.get(r.tail)
	if r.tail == r.head {
		r.head = -1
		r.tail = 0
	} else {
		r.tail = r.mod(r.tail + 1)
	}
	return v
}

/*
Read the value that Dequeue would have dequeued without actually dequeuing it.

Returns nil if the ring buffer is empty.
*/
func (r *Ring) Peek() interface{} {
	r.checkInit()
	if r.head == -1 {
		return nil
	}
	return r.get(r.tail)
}

/*
Values returns a slice of all the values in the circular buffer without modifying them at all.
The returned slice can be modified independently of the circular buffer. However, the values inside the slice
are shared between the slice and circular buffer.
*/
func (r *Ring) Values() []interface{} {
	if r.head == -1 {
		return []interface{}{}
	}
	arr := make([]interface{}, 0, r.Capacity())
	for i := 0; i < r.Capacity(); i++ {
		idx := r.mod(i+r.tail)
		arr = append(arr, r.get(idx))
		if idx == r.head {
			break
		}
	}
	return arr
}

/**
*** Unexported methods beyond this point.
**/

// sets a value at the given unmodified index and returns the modified index of the value
func (r *Ring) set(p int, v interface{}) {
	r.buff[r.mod(p)] = v
}

// gets a value based at a given unmodified index
func (r *Ring) get(p int) interface{} {
	return r.buff[r.mod(p)]
}

// returns the modified index of an unmodified index
func (r *Ring) mod(p int) int {
	return p % len(r.buff)
}

func (r *Ring) checkInit() {
	if r.buff == nil {
		r.buff = make([]interface{}, DefaultCapacity)
		for i := range r.buff {
			r.buff[i] = nil
		}
		r.head, r.tail = -1, 0
	}
}

func (r *Ring) extend(size int) {
	if size == len(r.buff) {
		return
	} else if size < len(r.buff) {
		r.buff = r.buff[0:size]
	}
	newb := make([]interface{}, size-len(r.buff))
	for i := range newb {
		newb[i] = nil
	}
	r.buff = append(r.buff, newb...)
}
<|endoftext|>


<commit_before>package commands

import (
	"context"
	"encoding/json"
	"io"
	"os"
	"time"

	"github.com/hyperledger/burrow/execution/state"

	"github.com/hyperledger/burrow/rpc/rpcdump"
	amino "github.com/tendermint/go-amino"
	"github.com/tendermint/tendermint/libs/db"

	cli "github.com/jawher/mow.cli"
	"google.golang.org/grpc"
)

var cdc = amino.NewCodec()

// Dump saves the state from a remote chain
func Dump(output Output) func(cmd *cli.Cmd) {
	return func(cmd *cli.Cmd) {
		chainURLOpt := cmd.StringOpt("c chain", "127.0.0.1:10997", "chain to be used in IP:PORT format")
		heightOpt := cmd.IntOpt("h height", 0, "Block height to dump to, defaults to latest block height")
		filename := cmd.StringArg("FILE", "", "Save dump here")
		useJSON := cmd.BoolOpt("j json", false, "Output in json")
		timeoutOpt := cmd.IntOpt("t timeout", 0, "Timeout in seconds")

		s := state.NewState(db.NewMemDB())

		cmd.Action = func() {
			ctx, cancel := context.WithCancel(context.Background())
			if *timeoutOpt != 0 {
				timeout := time.Duration(*timeoutOpt) * time.Second
				ctx, cancel = context.WithTimeout(context.Background(), timeout)
			}
			defer cancel()

			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.DialContext(ctx, *chainURLOpt, opts...)
			if err != nil {
				output.Fatalf("failed to connect: %v", err)
				return
			}

			dc := rpcdump.NewDumpClient(conn)
			dump, err := dc.GetDump(ctx, &rpcdump.GetDumpParam{Height: uint64(*heightOpt)})
			if err != nil {
				output.Fatalf("failed to retrieve dump: %v", err)
				return
			}
			output.Logf("Connected to %s", conn.Target())

			f, err := os.OpenFile(*filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
			if err != nil {
				output.Fatalf("%s: failed to save dump: %v", *filename, err)
				return
			}

			_, _, err = s.Update(func(ws state.Updatable) error {
				for {
					resp, err := dump.Recv()
					if err == io.EOF {
						break
					}
					if err != nil {
						output.Fatalf("failed to recv dump: %v", err)
						return err
					}

					// update our temporary state
					if resp.Account != nil {
						ws.UpdateAccount(resp.Account)
					}
					if resp.AccountStorage != nil {
						for _, storage := range resp.AccountStorage.Storage {
							ws.SetStorage(resp.AccountStorage.Address, storage.Key, storage.Value)
						}
					}
					if resp.Name != nil {
						ws.UpdateName(resp.Name)
					}

					var bs []byte
					if *useJSON {
						bs, err = json.Marshal(resp)
						if bs != nil {
							bs = append(bs, []byte("\n")...)
						}
					} else {
						bs, err = cdc.MarshalBinaryLengthPrefixed(resp)
					}
					if err != nil {
						output.Fatalf("failed to marshall dump: %v", *filename, err)
					}

					n, err := f.Write(bs)
					if err == nil && n < len(bs) {
						output.Fatalf("%s: failed to save dump: %v", *filename, err)
					}
				}

				return nil
			})

			if err := f.Close(); err != nil {
				output.Fatalf("%s: failed to save dump: %v", *filename, err)
			}
		}
	}
}
<commit_msg>actually print useful conn info on dump<commit_after>package commands

import (
	"context"
	"encoding/json"
	"io"
	"os"
	"time"

	"github.com/hyperledger/burrow/execution/state"

	"github.com/hyperledger/burrow/rpc/rpcdump"
	"github.com/hyperledger/burrow/rpc/rpcquery"
	amino "github.com/tendermint/go-amino"
	"github.com/tendermint/tendermint/libs/db"

	cli "github.com/jawher/mow.cli"
	"google.golang.org/grpc"
)

var cdc = amino.NewCodec()

// Dump saves the state from a remote chain
func Dump(output Output) func(cmd *cli.Cmd) {
	return func(cmd *cli.Cmd) {
		chainURLOpt := cmd.StringOpt("c chain", "127.0.0.1:10997", "chain to be used in IP:PORT format")
		heightOpt := cmd.IntOpt("h height", 0, "Block height to dump to, defaults to latest block height")
		filename := cmd.StringArg("FILE", "", "Save dump here")
		useJSON := cmd.BoolOpt("j json", false, "Output in json")
		timeoutOpt := cmd.IntOpt("t timeout", 0, "Timeout in seconds")

		s := state.NewState(db.NewMemDB())

		cmd.Action = func() {
			ctx, cancel := context.WithCancel(context.Background())
			if *timeoutOpt != 0 {
				timeout := time.Duration(*timeoutOpt) * time.Second
				ctx, cancel = context.WithTimeout(context.Background(), timeout)
			}
			defer cancel()

			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.DialContext(ctx, *chainURLOpt, opts...)
			if err != nil {
				output.Fatalf("failed to connect: %v", err)
				return
			}

			dc := rpcdump.NewDumpClient(conn)
			dump, err := dc.GetDump(ctx, &rpcdump.GetDumpParam{Height: uint64(*heightOpt)})
			if err != nil {
				output.Fatalf("failed to retrieve dump: %v", err)
				return
			}

			qCli := rpcquery.NewQueryClient(conn)
			chainStatus, err := qCli.Status(context.Background(), &rpcquery.StatusParam{})
			if err != nil {
				output.Logf("could not get chain status: %v", err)
			}
			stat, err := json.Marshal(chainStatus)
			if err != nil {
				output.Logf("failed to marshal: %v", err)
			}
			output.Logf(string(stat))

			f, err := os.OpenFile(*filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
			if err != nil {
				output.Fatalf("%s: failed to save dump: %v", *filename, err)
				return
			}

			_, _, err = s.Update(func(ws state.Updatable) error {
				for {
					resp, err := dump.Recv()
					if err == io.EOF {
						break
					}
					if err != nil {
						output.Fatalf("failed to recv dump: %v", err)
						return err
					}

					// update our temporary state
					if resp.Account != nil {
						ws.UpdateAccount(resp.Account)
					}
					if resp.AccountStorage != nil {
						for _, storage := range resp.AccountStorage.Storage {
							ws.SetStorage(resp.AccountStorage.Address, storage.Key, storage.Value)
						}
					}
					if resp.Name != nil {
						ws.UpdateName(resp.Name)
					}

					var bs []byte
					if *useJSON {
						bs, err = json.Marshal(resp)
						if bs != nil {
							bs = append(bs, []byte("\n")...)
						}
					} else {
						bs, err = cdc.MarshalBinaryLengthPrefixed(resp)
					}
					if err != nil {
						output.Fatalf("failed to marshall dump: %v", *filename, err)
					}

					n, err := f.Write(bs)
					if err == nil && n < len(bs) {
						output.Fatalf("%s: failed to save dump: %v", *filename, err)
					}
				}

				return nil
			})

			if err := f.Close(); err != nil {
				output.Fatalf("%s: failed to save dump: %v", *filename, err)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Enumerates USB devices, finds and identifies CrazyRadio USB dongle.
package main

import (
	"fmt"
	"os"

	"github.com/kylelemons/gousb/usb"
)

const (
	Vendor  = 0x1915
	Product = 0x7777
)

func listDongles() error {
	ctx := usb.NewContext()
	defer ctx.Close()

	devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
		if desc.Vendor == 0x1915 && desc.Product == 0x7777 {
			return true
		}
		return false
	})

	defer func() {
		for _, d := range devs {
			d.Close()
		}
	}()

	if err != nil {
		return err
	}

	if len(devs) == 0 {
		return fmt.Errorf("No CrazyRadio dongles found!")
	}

	for _, dev := range devs {
		fmt.Printf("dev: %v\n", dev)
	}

	return nil
}

func main() {
	if err := listDongles(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}
<commit_msg>Print CrazyRadio USB dongle version<commit_after>// Enumerates USB devices, finds and identifies CrazyRadio USB dongle.
package main

import (
	"fmt"
	"os"

	"github.com/kylelemons/gousb/usb"
)

const (
	Vendor  = 0x1915
	Product = 0x7777
)

func listDongles() error {
	ctx := usb.NewContext()
	defer ctx.Close()

	devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
		if desc.Vendor == 0x1915 && desc.Product == 0x7777 {
			return true
		}
		return false
	})

	defer func() {
		for _, d := range devs {
			d.Close()
		}
	}()

	if err != nil {
		return err
	}

	if len(devs) == 0 {
		return fmt.Errorf("No CrazyRadio dongles found!")
	}

	for _, dev := range devs {
		fmt.Printf("CrazyRadio USB dongle v%s\n", dev.Device)
	}

	return nil
}

func main() {
	if err := listDongles(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package cmd

// DO NOT EDIT manually! Generated by hack/update-version.sh
var version = "0.10.2"
<commit_msg>Bump version to 0.10.2-dev<commit_after>package cmd

// DO NOT EDIT manually! Generated by hack/update-version.sh
var version = "0.10.2-dev"
<|endoftext|>


<commit_before>package main

import (
	"github.com/Symantec/health-agent/httpd"
	"github.com/Symantec/health-agent/probers/filesystems"
	"github.com/Symantec/health-agent/probers/loadavg"
	"github.com/Symantec/health-agent/probers/memory"
	"github.com/Symantec/health-agent/probers/netif"
	"github.com/Symantec/health-agent/probers/network"
	"github.com/Symantec/health-agent/probers/storage"
	"github.com/Symantec/health-agent/probers/systime"
	"github.com/Symantec/tricorder/go/tricorder"
	"io"
	"log"
)

type prober interface {
	Probe() error
}

type proberList []prober

func setupProbers() (proberList, error) {
	topMetricsDir, err := tricorder.RegisterDirectory("/sys")
	if err != nil {
		return nil, err
	}
	var probers proberList
	probers = append(probers, filesystems.Register(mkdir(topMetricsDir, "fs")))
	probers = append(probers, loadavg.Register(mkdir(topMetricsDir, "loadavg")))
	probers = append(probers, memory.Register(mkdir(topMetricsDir, "memory")))
	probers = append(probers, netif.Register(mkdir(topMetricsDir, "netif")))
	probers = append(probers, network.Register(mkdir(topMetricsDir, "network")))
	probers = append(probers, storage.Register(mkdir(topMetricsDir, "storage")))
	probers = append(probers, systime.Register(mkdir(topMetricsDir, "")))
	return probers, nil
}

func mkdir(dir *tricorder.DirectorySpec, name string) *tricorder.DirectorySpec {
	if name == "" {
		return dir
	}
	subdir, err := dir.RegisterDirectory(name)
	if err != nil {
		panic(err)
	}
	return subdir
}

func (probers proberList) Probe(logger *log.Logger) {
	for _, p := range probers {
		if err := p.Probe(); err != nil {
			logger.Println(err)
		}
	}
}

func (probers proberList) WriteHtml(writer io.Writer) {
	for _, p := range probers {
		if htmler, ok := p.(httpd.HtmlWriter); ok {
			htmler.WriteHtml(writer)
		}
	}
}
<commit_msg>Add line break between dashboard sections.<commit_after>package main

import (
	"fmt"
	"github.com/Symantec/health-agent/httpd"
	"github.com/Symantec/health-agent/probers/filesystems"
	"github.com/Symantec/health-agent/probers/loadavg"
	"github.com/Symantec/health-agent/probers/memory"
	"github.com/Symantec/health-agent/probers/netif"
	"github.com/Symantec/health-agent/probers/network"
	"github.com/Symantec/health-agent/probers/storage"
	"github.com/Symantec/health-agent/probers/systime"
	"github.com/Symantec/tricorder/go/tricorder"
	"io"
	"log"
)

type prober interface {
	Probe() error
}

type proberList []prober

func setupProbers() (proberList, error) {
	topMetricsDir, err := tricorder.RegisterDirectory("/sys")
	if err != nil {
		return nil, err
	}
	var probers proberList
	probers = append(probers, filesystems.Register(mkdir(topMetricsDir, "fs")))
	probers = append(probers, loadavg.Register(mkdir(topMetricsDir, "loadavg")))
	probers = append(probers, memory.Register(mkdir(topMetricsDir, "memory")))
	probers = append(probers, netif.Register(mkdir(topMetricsDir, "netif")))
	probers = append(probers, network.Register(mkdir(topMetricsDir, "network")))
	probers = append(probers, storage.Register(mkdir(topMetricsDir, "storage")))
	probers = append(probers, systime.Register(mkdir(topMetricsDir, "")))
	return probers, nil
}

func mkdir(dir *tricorder.DirectorySpec, name string) *tricorder.DirectorySpec {
	if name == "" {
		return dir
	}
	subdir, err := dir.RegisterDirectory(name)
	if err != nil {
		panic(err)
	}
	return subdir
}

func (probers proberList) Probe(logger *log.Logger) {
	for _, p := range probers {
		if err := p.Probe(); err != nil {
			logger.Println(err)
		}
	}
}

func (probers proberList) WriteHtml(writer io.Writer) {
	for _, p := range probers {
		if htmler, ok := p.(httpd.HtmlWriter); ok {
			htmler.WriteHtml(writer)
			fmt.Fprintln(writer, "<br>")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"log"
	"os"
)

var app *cli.App
var service *Service

func init() {
	log.SetFlags(0)

	app = cli.NewApp()
	app.Name = "rambler"
	app.Usage = "Migrate all the things!"
	app.Version = "3"
	app.Authors = []cli.Author{
		{
			Name:  "Romain Baugue",
			Email: "romain.baugue@elwinar.com",
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "configuration, c",
			Value: "rambler.json",
			Usage: "path to the configuration file",
		},
		cli.StringFlag{
			Name:  "environment, e",
			Value: "default",
			Usage: "set the working environment",
		},
	}
	app.Before = Bootstrap
	app.Commands = []cli.Command{
		{
			Name:   "noop",
			Usage:  "no-op command for testing purpose",
			Action: func(_ *cli.Context) { return },
		},
		// 		{
		// 			Name:   "apply",
		// 			Usage:  "apply the next migration",
		// 			Flags: []cli.Flag{
		// 				cli.BoolFlag{
		// 					Name:  "all, a",
		// 					Usage: "Apply all migrations",
		// 				},
		// 			},
		// 			Action: Apply,
		// 		},
		// 		{
		// 			Name:   "reverse",
		// 			Usage:  "reverse the last migration",
		// 			Flags: []cli.Flag{
		// 				cli.BoolFlag{
		// 					Name:  "all, a",
		// 					Usage: "Reverse all migrations",
		// 				},
		// 			},
		// 			Action: Reverse,
		// 		},
	}
}

func main() {
	err := app.Run(os.Args)
	if err != nil {
		log.Println(err)
	}
}
<commit_msg>Remove the noop command as I don't need it anymore<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"log"
	"os"
)

var app *cli.App
var service *Service

func init() {
	log.SetFlags(0)

	app = cli.NewApp()
	app.Name = "rambler"
	app.Usage = "Migrate all the things!"
	app.Version = "3"
	app.Authors = []cli.Author{
		{
			Name:  "Romain Baugue",
			Email: "romain.baugue@elwinar.com",
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "configuration, c",
			Value: "rambler.json",
			Usage: "path to the configuration file",
		},
		cli.StringFlag{
			Name:  "environment, e",
			Value: "default",
			Usage: "set the working environment",
		},
	}
	app.Before = Bootstrap
	app.Commands = []cli.Command{
		{
			Name:   "apply",
			Usage:  "apply the next migration",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "all, a",
					Usage: "Apply all migrations",
				},
			},
			Action: Apply,
		},
		// 		{
		// 			Name:   "reverse",
		// 			Usage:  "reverse the last migration",
		// 			Flags: []cli.Flag{
		// 				cli.BoolFlag{
		// 					Name:  "all, a",
		// 					Usage: "Reverse all migrations",
		// 				},
		// 			},
		// 			Action: Reverse,
		// 		},
	}
}

func main() {
	err := app.Run(os.Args)
	if err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/Cloud-Foundations/keymaster/lib/instrumentedwriter"
	"github.com/Cloud-Foundations/keymaster/lib/paths"
	"gopkg.in/square/go-jose.v2"
	"gopkg.in/square/go-jose.v2/jwt"
)

func (state *RuntimeState) generateAuthJWT(username string) (string, error) {
	signer, err := jose.NewSigner(jose.SigningKey{
		Algorithm: jose.RS256,
		Key:       state.Signer,
	}, (&jose.SignerOptions{}).WithType("JWT"))
	if err != nil {
		return "", err
	}
	issuer := state.idpGetIssuer()
	now := time.Now().Unix()
	authToken := authInfoJWT{
		Issuer:   issuer,
		Subject:  username,
		Audience: []string{issuer},
		Expiration: now + int64(
			state.Config.Base.WebauthTokenForCliLifetime/time.Second),
		NotBefore: now,
		IssuedAt:  now,
		TokenType: "keymaster_token_auth",
	}
	return jwt.Signed(signer).Claims(authToken).CompactSerialize()
}

func (state *RuntimeState) SendAuthDocumentHandler(w http.ResponseWriter,
	r *http.Request) {
	state.logger.Debugln(1, "Entered SendAuthDocumentHandler()")
	if state.sendFailureToClientIfLocked(w, r) {
		return
	}
	if r.Method != "GET" && r.Method != "POST" {
		state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "")
		return
	}
	if err := r.ParseForm(); err != nil {
		state.logger.Println(err)
		state.writeFailureResponse(w, r, http.StatusInternalServerError,
			"Error parsing form")
		return
	}
	authData, err := state.checkAuth(w, r, state.getRequiredWebUIAuthLevel())
	if err != nil {
		state.logger.Debugln(1, err)
		return
	}
	w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username)
	state.logger.Printf("%s requested authentication document export\n",
		authData.Username)
	// Fetch form/query data.
	var portNumber, token string
	if val, ok := r.Form["port"]; !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No CLI port number provided")
		state.logger.Printf("SendAuthDocument without port number")
		return
	} else {
		if len(val) > 1 {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Just one port number allowed")
			state.logger.Printf("SendAuthDocument with multiple port values")
			return
		}
		portNumber = val[0]
	}
	if val, ok := r.Form["token"]; !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No token provided")
		state.logger.Printf("SendAuthDocument without token")
		return
	} else {
		if len(val) > 1 {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Just one token allowed")
			state.logger.Printf("SendAuthDocument with multiple token values")
			return
		}
		token = val[0]
	}
	authInfo, err := state.getAuthInfoFromJWT(token, "keymaster_token_auth")
	if err != nil {
		state.writeFailureResponse(w, r, http.StatusBadRequest, "Bad token")
		state.logger.Debugln(0, err)
		return
	}
	if authInfo.Username != authData.Username {
		state.writeFailureResponse(w, r, http.StatusBadRequest, "User mismatch")
		state.logger.Printf(
			"SendAuthDocumentHandler: authticated user: %s != token user: %s\n",
			authData.Username, authInfo.Username)
		return
	}
	if time.Until(authInfo.ExpiresAt) < 0 {
		state.writeFailureResponse(w, r, http.StatusBadRequest, "Token expired")
		state.logger.Debugln(0, "token expired")
		return
	}
	var authCookie *http.Cookie
	for _, cookie := range r.Cookies() {
		if cookie.Name != authCookieName {
			continue
		}
		authCookie = cookie
	}
	if authCookie == nil {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No auth_cookie")
		state.logger.Debugln(0, "no auth_cookie")
		return
	}
	http.Redirect(w, r,
		fmt.Sprintf("http://localhost:%s%s?auth_cookie=%s",
			portNumber, paths.ReceiveAuthDocument, authCookie.Value),
		http.StatusPermanentRedirect)
}

func (state *RuntimeState) ShowAuthTokenHandler(w http.ResponseWriter,
	r *http.Request) {
	state.logger.Debugf(1, "Entered GetAuthTokenHandler(). URL: %v\n", r.URL)
	if state.sendFailureToClientIfLocked(w, r) {
		return
	}
	if r.Method != "GET" && r.Method != "POST" {
		state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "")
		return
	}
	if err := r.ParseForm(); err != nil {
		logger.Println(err)
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Error parsing form")
		return
	}
	authData, err := state.checkAuth(w, r, state.getRequiredWebUIAuthLevel())
	if err != nil {
		state.logger.Debugf(1, "%s", err)
		return
	}
	w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username)
	displayData := authCodePageTemplateData{
		Title:        "Keymaster CLI Token Display",
		AuthUsername: authData.Username,
	}
	token, err := state.generateAuthJWT(authData.Username)
	if err != nil {
		state.logger.Debugf(1, "%s", err)
		displayData.ErrorMessage = "Unable to generate token"
	} else {
		state.logger.Printf(
			"generated webauth CLI token for: %s, lifetime: %s\n",
			authData.Username, state.Config.Base.WebauthTokenForCliLifetime)
		displayData.Token = token
	}
	err = state.htmlTemplate.ExecuteTemplate(w, "authTokenPage", displayData)
	if err != nil {
		logger.Printf("Failed to execute %s", err)
		http.Error(w, "error", http.StatusInternalServerError)
		return
	}
}

func (state *RuntimeState) VerifyAuthTokenHandler(w http.ResponseWriter,
	r *http.Request) {
	state.logger.Debugf(1, "Entered VerifyAuthTokenHandler(). URL: %v\n", r.URL)
	if state.sendFailureToClientIfLocked(w, r) {
		return
	}
	if r.Method != "GET" && r.Method != "POST" {
		state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "")
		return
	}
	if err := r.ParseForm(); err != nil {
		logger.Println(err)
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Error parsing form")
		return
	}
	// Fetch form/query data.
	var token string
	if val, ok := r.Form["token"]; !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No token provided")
		state.logger.Printf("VerifyAuthToken without token")
		return
	} else {
		if len(val) > 1 {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Just one token allowed")
			state.logger.Printf("VerifyAuthToken with multiple token values")
			return
		}
		token = val[0]
	}
	authInfo, err := state.getAuthInfoFromJWT(token, "keymaster_token_auth")
	if err != nil {
		state.writeFailureResponse(w, r, http.StatusNotAcceptable, "Bad token")
		state.logger.Debugln(0, err)
		return
	}
	if time.Until(authInfo.ExpiresAt) < 0 {
		state.writeFailureResponse(w, r, http.StatusGone, "Token expired")
		state.logger.Debugln(0, "token expired")
		return
	}
	w.Write([]byte("OK\n"))
}
<commit_msg>keymasterd: parse and validate port number.<commit_after>package main

import (
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/Cloud-Foundations/keymaster/lib/instrumentedwriter"
	"github.com/Cloud-Foundations/keymaster/lib/paths"
	"gopkg.in/square/go-jose.v2"
	"gopkg.in/square/go-jose.v2/jwt"
)

func (state *RuntimeState) generateAuthJWT(username string) (string, error) {
	signer, err := jose.NewSigner(jose.SigningKey{
		Algorithm: jose.RS256,
		Key:       state.Signer,
	}, (&jose.SignerOptions{}).WithType("JWT"))
	if err != nil {
		return "", err
	}
	issuer := state.idpGetIssuer()
	now := time.Now().Unix()
	authToken := authInfoJWT{
		Issuer:   issuer,
		Subject:  username,
		Audience: []string{issuer},
		Expiration: now + int64(
			state.Config.Base.WebauthTokenForCliLifetime/time.Second),
		NotBefore: now,
		IssuedAt:  now,
		TokenType: "keymaster_token_auth",
	}
	return jwt.Signed(signer).Claims(authToken).CompactSerialize()
}

func (state *RuntimeState) SendAuthDocumentHandler(w http.ResponseWriter,
	r *http.Request) {
	state.logger.Debugln(1, "Entered SendAuthDocumentHandler()")
	if state.sendFailureToClientIfLocked(w, r) {
		return
	}
	if r.Method != "GET" && r.Method != "POST" {
		state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "")
		return
	}
	if err := r.ParseForm(); err != nil {
		state.logger.Println(err)
		state.writeFailureResponse(w, r, http.StatusInternalServerError,
			"Error parsing form")
		return
	}
	authData, err := state.checkAuth(w, r, state.getRequiredWebUIAuthLevel())
	if err != nil {
		state.logger.Debugln(1, err)
		return
	}
	w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username)
	state.logger.Printf("%s requested authentication document export\n",
		authData.Username)
	// Fetch form/query data.
	var portNumber uint64
	var token string
	if val, ok := r.Form["port"]; !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No CLI port number provided")
		state.logger.Printf("SendAuthDocument without port number")
		return
	} else {
		if len(val) > 1 {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Just one port number allowed")
			state.logger.Printf("SendAuthDocument with multiple port values")
			return
		}
		if portNumber, err = strconv.ParseUint(val[0], 10, 16); err != nil {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Invalid port number")
			state.logger.Printf("SendAuthDocument with invalid port number")
			return
		}
	}
	if val, ok := r.Form["token"]; !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No token provided")
		state.logger.Printf("SendAuthDocument without token")
		return
	} else {
		if len(val) > 1 {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Just one token allowed")
			state.logger.Printf("SendAuthDocument with multiple token values")
			return
		}
		token = val[0]
	}
	authInfo, err := state.getAuthInfoFromJWT(token, "keymaster_token_auth")
	if err != nil {
		state.writeFailureResponse(w, r, http.StatusBadRequest, "Bad token")
		state.logger.Debugln(0, err)
		return
	}
	if authInfo.Username != authData.Username {
		state.writeFailureResponse(w, r, http.StatusBadRequest, "User mismatch")
		state.logger.Printf(
			"SendAuthDocumentHandler: authticated user: %s != token user: %s\n",
			authData.Username, authInfo.Username)
		return
	}
	if time.Until(authInfo.ExpiresAt) < 0 {
		state.writeFailureResponse(w, r, http.StatusBadRequest, "Token expired")
		state.logger.Debugln(0, "token expired")
		return
	}
	var authCookie *http.Cookie
	for _, cookie := range r.Cookies() {
		if cookie.Name != authCookieName {
			continue
		}
		authCookie = cookie
	}
	if authCookie == nil {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No auth_cookie")
		state.logger.Debugln(0, "no auth_cookie")
		return
	}
	http.Redirect(w, r,
		fmt.Sprintf("http://localhost:%d%s?auth_cookie=%s",
			portNumber, paths.ReceiveAuthDocument, authCookie.Value),
		http.StatusPermanentRedirect)
}

func (state *RuntimeState) ShowAuthTokenHandler(w http.ResponseWriter,
	r *http.Request) {
	state.logger.Debugf(1, "Entered GetAuthTokenHandler(). URL: %v\n", r.URL)
	if state.sendFailureToClientIfLocked(w, r) {
		return
	}
	if r.Method != "GET" && r.Method != "POST" {
		state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "")
		return
	}
	if err := r.ParseForm(); err != nil {
		logger.Println(err)
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Error parsing form")
		return
	}
	authData, err := state.checkAuth(w, r, state.getRequiredWebUIAuthLevel())
	if err != nil {
		state.logger.Debugf(1, "%s", err)
		return
	}
	w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username)
	displayData := authCodePageTemplateData{
		Title:        "Keymaster CLI Token Display",
		AuthUsername: authData.Username,
	}
	token, err := state.generateAuthJWT(authData.Username)
	if err != nil {
		state.logger.Debugf(1, "%s", err)
		displayData.ErrorMessage = "Unable to generate token"
	} else {
		state.logger.Printf(
			"generated webauth CLI token for: %s, lifetime: %s\n",
			authData.Username, state.Config.Base.WebauthTokenForCliLifetime)
		displayData.Token = token
	}
	err = state.htmlTemplate.ExecuteTemplate(w, "authTokenPage", displayData)
	if err != nil {
		logger.Printf("Failed to execute %s", err)
		http.Error(w, "error", http.StatusInternalServerError)
		return
	}
}

func (state *RuntimeState) VerifyAuthTokenHandler(w http.ResponseWriter,
	r *http.Request) {
	state.logger.Debugf(1, "Entered VerifyAuthTokenHandler(). URL: %v\n", r.URL)
	if state.sendFailureToClientIfLocked(w, r) {
		return
	}
	if r.Method != "GET" && r.Method != "POST" {
		state.writeFailureResponse(w, r, http.StatusMethodNotAllowed, "")
		return
	}
	if err := r.ParseForm(); err != nil {
		logger.Println(err)
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"Error parsing form")
		return
	}
	// Fetch form/query data.
	var token string
	if val, ok := r.Form["token"]; !ok {
		state.writeFailureResponse(w, r, http.StatusBadRequest,
			"No token provided")
		state.logger.Printf("VerifyAuthToken without token")
		return
	} else {
		if len(val) > 1 {
			state.writeFailureResponse(w, r, http.StatusBadRequest,
				"Just one token allowed")
			state.logger.Printf("VerifyAuthToken with multiple token values")
			return
		}
		token = val[0]
	}
	authInfo, err := state.getAuthInfoFromJWT(token, "keymaster_token_auth")
	if err != nil {
		state.writeFailureResponse(w, r, http.StatusNotAcceptable, "Bad token")
		state.logger.Debugln(0, err)
		return
	}
	if time.Until(authInfo.ExpiresAt) < 0 {
		state.writeFailureResponse(w, r, http.StatusGone, "Token expired")
		state.logger.Debugln(0, "token expired")
		return
	}
	w.Write([]byte("OK\n"))
}
<|endoftext|>