<commit_before>package main

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"
	"sync/atomic"
	"testing"
	"time"

	"github.com/buger/gor/listener"
	"github.com/buger/gor/replay"

	"math/rand"
)

func isEqual(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Error("Original and Replayed request not match\n", a, "!=", b)
	}
}

var envs int

type Env struct {
	Verbose bool

	ListenHandler http.HandlerFunc
	ReplayHandler http.HandlerFunc

	ReplayLimit   int
	ListenerLimit int
	ForwardPort   int
}

func (e *Env) start() (p int) {
	p = 50000 + envs*10

	go e.startHTTP(p, http.HandlerFunc(e.ListenHandler))
	go e.startHTTP(p+2, http.HandlerFunc(e.ReplayHandler))
	go e.startListener(p, p+1)
	go e.startReplay(p+1, p+2)

	// Time to start http and gor instances
	time.Sleep(time.Millisecond * 100)

	envs++

	return
}

func (e *Env) startListener(port int, replayPort int) {
	listener.Settings.Verbose = e.Verbose
	listener.Settings.Address = "127.0.0.1"
	listener.Settings.ReplayAddress = "127.0.0.1:" + strconv.Itoa(replayPort)
	listener.Settings.Port = port

	if e.ListenerLimit != 0 {
		listener.Settings.ReplayLimit = e.ListenerLimit
	}

	listener.Run()
}

func (e *Env) startReplay(port int, forwardPort int) {
	replay.Settings.Verbose = e.Verbose
	replay.Settings.Host = "127.0.0.1"
	replay.Settings.Address = "127.0.0.1:" + strconv.Itoa(port)
	replay.Settings.ForwardAddress = "127.0.0.1:" + strconv.Itoa(forwardPort)
	replay.Settings.Port = port

	if e.ReplayLimit != 0 {
		replay.Settings.ForwardAddress += "|" + strconv.Itoa(e.ReplayLimit)
	}

	replay.Run()
}

func (e *Env) startHTTP(port int, handler http.Handler) {
	err := http.ListenAndServe(":"+strconv.Itoa(port), handler)

	if err != nil {
		fmt.Println("Error while starting http server:", err)
	}
}

func getRequest(port int) *http.Request {
	var req *http.Request

	if rand.Int()%2 == 0 {
		req, _ = http.NewRequest("GET", "http://localhost:"+strconv.Itoa(port)+"/test", nil)
	} else {
		buf := bytes.NewReader([]byte("a=b&c=d"))

		req, _ = http.NewRequest("POST", "http://localhost:"+strconv.Itoa(port)+"/test", buf)
	}

	ck1 := new(http.Cookie)
	ck1.Name = "test"
	ck1.Value = "value"

	req.AddCookie(ck1)

	return req
}

func TestReplay(t *testing.T) {
	var request *http.Request
	received := make(chan int)

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusAccepted)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		isEqual(t, r.URL.Path, request.URL.Path)

		if len(r.Cookies()) > 0 {
			isEqual(t, r.Cookies()[0].Value, request.Cookies()[0].Value)
		} else {
			t.Error("Cookies should not be blank")
		}

		http.Error(w, "OK", http.StatusAccepted)

		if t.Failed() {
			fmt.Println("\nReplayed:", r, "\nOriginal:", request)
		}

		received <- 1
	}

	env := &Env{
		Verbose:       true,
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
	}
	p := env.start()

	request = getRequest(p)

	_, err := http.DefaultClient.Do(request)

	if err != nil {
		t.Error("Can't make request", err)
	}

	select {
	case <-received:
	case <-time.After(time.Second):
		t.Error("Timeout error")
	}
}

func rateLimitEnv(replayLimit int, listenerLimit int, connCount int) int32 {
	var processed int32

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusAccepted)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		atomic.AddInt32(&processed, 1)
		http.Error(w, "OK", http.StatusAccepted)
	}

	env := &Env{
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
		ReplayLimit:   replayLimit,
		ListenerLimit: listenerLimit,
	}

	p := env.start()
	req := getRequest(p)

	for i := 0; i < connCount; i++ {
		go func() {
			http.DefaultClient.Do(req)
		}()
	}

	time.Sleep(time.Millisecond * 500)

	return processed
}

func TestWithoutReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 0, 10)

	if processed != 10 {
		t.Error("It should forward all requests without rate-limiting", processed)
	}
}

func TestReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(5, 0, 10)

	if processed != 5 {
		t.Error("It should forward only 5 requests with rate-limiting", processed)
	}
}

func TestListenerRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 3, 100)

	if processed != 3 {
		t.Error("It should forward only 3 requests with rate-limiting", processed)
	}
}

func (e *Env) startFileListener() (p int) {
	p = 50000 + envs*10

	e.ForwardPort = p + 2
	go e.startHTTP(p, http.HandlerFunc(e.ListenHandler))
	go e.startHTTP(p+2, http.HandlerFunc(e.ReplayHandler))
	go e.startFileUsingListener(p, p+1)

	// Time to start http and gor instances
	time.Sleep(time.Millisecond * 100)

	envs++

	return
}

func (e *Env) startFileUsingListener(port int, replayPort int) {
	listener.Settings.Verbose = e.Verbose
	listener.Settings.Address = "127.0.0.1"
	listener.Settings.FileToReplyPath = "integration_request.gor"
	listener.Settings.Port = port

	if e.ListenerLimit != 0 {
		listener.Settings.ReplayAddress += "|" + strconv.Itoa(e.ListenerLimit)
	}

	listener.Run()
}

func (e *Env) startFileUsingReplay() {
	replay.Settings.Verbose = e.Verbose
	replay.Settings.FileToReplyPath = "integration_request.gor"
	replay.Settings.ForwardAddress = "127.0.0.1:" + strconv.Itoa(e.ForwardPort)

	if e.ReplayLimit != 0 {
		replay.Settings.ForwardAddress += "|" + strconv.Itoa(e.ReplayLimit)
	}

	replay.Run()
}

func TestSavingRequestToFileAndReplyThem(t *testing.T) {
	var request *http.Request
	processed := make(chan int)

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusNotFound)
	}

	requestsCount := 0
	var replayedRequests []*http.Request
	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		requestsCount++

		isEqual(t, r.URL.Path, request.URL.Path)
		isEqual(t, r.Cookies()[0].Value, request.Cookies()[0].Value)

		http.Error(w, "404 page not found", http.StatusNotFound)

		replayedRequests = append(replayedRequests, r)
		if t.Failed() {
			fmt.Println("\nReplayed:", r, "\nOriginal:", request)
		}

		if requestsCount > 1 {
			processed <- 1
		}
	}

	env := &Env{
		Verbose:       true,
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
	}

	p := env.startFileListener()

	request = getRequest(p)

	for i := 0; i < 2; i++ {
		go func() {
			_, err := http.DefaultClient.Do(request)

			if err != nil {
				t.Error("Can't make request", err)
			}
		}()
	}

	// TODO: wait until gor will process response, should be kind of flag/semaphore
	time.Sleep(time.Millisecond * 700)
	go env.startFileUsingReplay()

	select {
	case <-processed:
	case <-time.After(2 * time.Second):
		for _, value := range replayedRequests {
			fmt.Println(value)
		}
		t.Error("Timeout error")
	}
}
<commit_msg>Turn on verbose mode for tests<commit_after>package main

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"
	"sync/atomic"
	"testing"
	"time"

	"github.com/buger/gor/listener"
	"github.com/buger/gor/replay"

	"math/rand"
)

func isEqual(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Error("Original and Replayed request not match\n", a, "!=", b)
	}
}

var envs int

type Env struct {
	Verbose bool

	ListenHandler http.HandlerFunc
	ReplayHandler http.HandlerFunc

	ReplayLimit   int
	ListenerLimit int
	ForwardPort   int
}

func (e *Env) start() (p int) {
	p = 50000 + envs*10

	go e.startHTTP(p, http.HandlerFunc(e.ListenHandler))
	go e.startHTTP(p+2, http.HandlerFunc(e.ReplayHandler))
	go e.startListener(p, p+1)
	go e.startReplay(p+1, p+2)

	// Time to start http and gor instances
	time.Sleep(time.Millisecond * 100)

	envs++

	return
}

func (e *Env) startListener(port int, replayPort int) {
	listener.Settings.Verbose = e.Verbose
	listener.Settings.Address = "127.0.0.1"
	listener.Settings.ReplayAddress = "127.0.0.1:" + strconv.Itoa(replayPort)
	listener.Settings.Port = port

	if e.ListenerLimit != 0 {
		listener.Settings.ReplayLimit = e.ListenerLimit
	}

	listener.Run()
}

func (e *Env) startReplay(port int, forwardPort int) {
	replay.Settings.Verbose = e.Verbose
	replay.Settings.Host = "127.0.0.1"
	replay.Settings.Address = "127.0.0.1:" + strconv.Itoa(port)
	replay.Settings.ForwardAddress = "127.0.0.1:" + strconv.Itoa(forwardPort)
	replay.Settings.Port = port

	if e.ReplayLimit != 0 {
		replay.Settings.ForwardAddress += "|" + strconv.Itoa(e.ReplayLimit)
	}

	replay.Run()
}

func (e *Env) startHTTP(port int, handler http.Handler) {
	err := http.ListenAndServe(":"+strconv.Itoa(port), handler)

	if err != nil {
		fmt.Println("Error while starting http server:", err)
	}
}

func getRequest(port int) *http.Request {
	var req *http.Request

	if rand.Int()%2 == 0 {
		req, _ = http.NewRequest("GET", "http://localhost:"+strconv.Itoa(port)+"/test", nil)
	} else {
		buf := bytes.NewReader([]byte("a=b&c=d"))

		req, _ = http.NewRequest("POST", "http://localhost:"+strconv.Itoa(port)+"/test", buf)
	}

	ck1 := new(http.Cookie)
	ck1.Name = "test"
	ck1.Value = "value"

	req.AddCookie(ck1)

	return req
}

func TestReplay(t *testing.T) {
	var request *http.Request
	received := make(chan int)

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusAccepted)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		isEqual(t, r.URL.Path, request.URL.Path)

		if len(r.Cookies()) > 0 {
			isEqual(t, r.Cookies()[0].Value, request.Cookies()[0].Value)
		} else {
			t.Error("Cookies should not be blank")
		}

		http.Error(w, "OK", http.StatusAccepted)

		if t.Failed() {
			fmt.Println("\nReplayed:", r, "\nOriginal:", request)
		}

		received <- 1
	}

	env := &Env{
		Verbose:       true,
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
	}
	p := env.start()

	request = getRequest(p)

	_, err := http.DefaultClient.Do(request)

	if err != nil {
		t.Error("Can't make request", err)
	}

	select {
	case <-received:
	case <-time.After(time.Second):
		t.Error("Timeout error")
	}
}

func rateLimitEnv(replayLimit int, listenerLimit int, connCount int) int32 {
	var processed int32

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusAccepted)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		atomic.AddInt32(&processed, 1)
		http.Error(w, "OK", http.StatusAccepted)
	}

	env := &Env{
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
		ReplayLimit:   replayLimit,
		ListenerLimit: listenerLimit,
		Verbose:       true,
	}

	p := env.start()
	req := getRequest(p)

	for i := 0; i < connCount; i++ {
		go func() {
			http.DefaultClient.Do(req)
		}()
	}

	time.Sleep(time.Millisecond * 500)

	return processed
}

func TestWithoutReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 0, 10)

	if processed != 10 {
		t.Error("It should forward all requests without rate-limiting, got:", processed)
	}
}

func TestReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(5, 0, 10)

	if processed != 5 {
		t.Error("It should forward only 5 requests with rate-limiting, got:", processed)
	}
}

func TestListenerRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 3, 100)

	if processed != 3 {
		t.Error("It should forward only 3 requests with rate-limiting, got:", processed)
	}
}

func (e *Env) startFileListener() (p int) {
	p = 50000 + envs*10

	e.ForwardPort = p + 2
	go e.startHTTP(p, http.HandlerFunc(e.ListenHandler))
	go e.startHTTP(p+2, http.HandlerFunc(e.ReplayHandler))
	go e.startFileUsingListener(p, p+1)

	// Time to start http and gor instances
	time.Sleep(time.Millisecond * 100)

	envs++

	return
}

func (e *Env) startFileUsingListener(port int, replayPort int) {
	listener.Settings.Verbose = e.Verbose
	listener.Settings.Address = "127.0.0.1"
	listener.Settings.FileToReplyPath = "integration_request.gor"
	listener.Settings.Port = port

	if e.ListenerLimit != 0 {
		listener.Settings.ReplayAddress += "|" + strconv.Itoa(e.ListenerLimit)
	}

	listener.Run()
}

func (e *Env) startFileUsingReplay() {
	replay.Settings.Verbose = e.Verbose
	replay.Settings.FileToReplyPath = "integration_request.gor"
	replay.Settings.ForwardAddress = "127.0.0.1:" + strconv.Itoa(e.ForwardPort)

	if e.ReplayLimit != 0 {
		replay.Settings.ForwardAddress += "|" + strconv.Itoa(e.ReplayLimit)
	}

	replay.Run()
}

func TestSavingRequestToFileAndReplyThem(t *testing.T) {
	var request *http.Request
	processed := make(chan int)

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusNotFound)
	}

	requestsCount := 0
	var replayedRequests []*http.Request
	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		requestsCount++

		isEqual(t, r.URL.Path, request.URL.Path)
		isEqual(t, r.Cookies()[0].Value, request.Cookies()[0].Value)

		http.Error(w, "404 page not found", http.StatusNotFound)

		replayedRequests = append(replayedRequests, r)
		if t.Failed() {
			fmt.Println("\nReplayed:", r, "\nOriginal:", request)
		}

		if requestsCount > 1 {
			processed <- 1
		}
	}

	env := &Env{
		Verbose:       true,
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
	}

	p := env.startFileListener()

	request = getRequest(p)

	for i := 0; i < 2; i++ {
		go func() {
			_, err := http.DefaultClient.Do(request)

			if err != nil {
				t.Error("Can't make request", err)
			}
		}()
	}

	// TODO: wait until gor will process response, should be kind of flag/semaphore
	time.Sleep(time.Millisecond * 700)
	go env.startFileUsingReplay()

	select {
	case <-processed:
	case <-time.After(2 * time.Second):
		for _, value := range replayedRequests {
			fmt.Println(value)
		}
		t.Error("Timeout error")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Datacratic. All rights reserved.

package nfork

import (
	"net"
	"net/http"
	"time"
)

// Copied and tweaked from http.DefaultTransport.
func httpTransport(idleConnections int) *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		MaxIdleConnsPerHost: idleConnections,
	}
}

// Copied and tweaked from http.ListenAndServe.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<commit_msg>Adapt imports to include contexts<commit_after>// Copyright (c) 2014 Datacratic. All rights reserved.

package nfork

import (
	"net"
	"net/http"
	"time"
)

// Copied and tweaked from http.DefaultTransport.
func httpTransport(idleConnections int) *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:        idleConnections,
		IdleConnTimeout:     90 * time.Second,
		TLSHandshakeTimeout: 10 * time.Second,
	}
}

// Copied and tweaked from http.ListenAndServe.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<|endoftext|>


<commit_before>package service

import (
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_registry"
	"github.com/cloudfoundry/cli/cf/errors"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
	"github.com/simonleung8/flags/flag"
)

type PurgeServiceInstance struct {
	ui          terminal.UI
	serviceRepo api.ServiceRepository
}

func init() {
	command_registry.Register(&PurgeServiceInstance{})
}

func (cmd *PurgeServiceInstance) MetaData() command_registry.CommandMetadata {
	fs := make(map[string]flags.FlagSet)
	fs["f"] = &cliFlags.BoolFlag{Name: "f", Usage: T("Force deletion without confirmation")}

	return command_registry.CommandMetadata{
		Name:        "purge-service-instance",
		Description: T("Recursively remove a service instance and child objects from Cloud Foundry database without making requests to a service broker"),
		Usage:       T("CF_NAME purge-service-instance SERVICE_INSTANCE") + "\n\n" + cmd.scaryWarningMessage(),
		Flags:       fs,
	}
}

func (cmd *PurgeServiceInstance) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
	if len(fc.Args()) != 1 {
		cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + command_registry.Commands.CommandUsage("purge-service-instance"))
	}

	return []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
	}, nil
}

func (cmd *PurgeServiceInstance) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command {
	cmd.ui = deps.Ui
	cmd.serviceRepo = deps.RepoLocator.GetServiceRepository()
	return cmd
}

func (cmd *PurgeServiceInstance) scaryWarningMessage() string {
	return T(`WARNING: This operation assumes that the service broker responsible for this service instance is no longer available or is not responding with a 200 or 410, and the service instance has been deleted, leaving orphan records in Cloud Foundry's database. All knowledge of the service instance will be removed from Cloud Foundry, including service bindings and service keys.`)
}

func (cmd *PurgeServiceInstance) Execute(c flags.FlagContext) {
	instanceName := c.Args()[0]

	instance, apiErr := cmd.serviceRepo.FindInstanceByName(instanceName)

	switch apiErr.(type) {
	case nil:
	case *errors.ModelNotFoundError:
		cmd.ui.Warn(T("Service instance {{.InstanceName}} not found",
			map[string]interface{}{"InstanceName": instanceName},
		))
		return
	default:
		cmd.ui.Failed(apiErr.Error())
	}

	confirmed := c.Bool("f")
	if !confirmed {
		cmd.ui.Warn(cmd.scaryWarningMessage())
		confirmed = cmd.ui.Confirm(T("Really purge service instance {{.InstanceName}} from Cloud Foundry?",
			map[string]interface{}{"InstanceName": instanceName},
		))
	}

	if !confirmed {
		return
	}
	cmd.ui.Say(T("Purging service {{.InstanceName}}...", map[string]interface{}{"InstanceName": instanceName}))
	err := cmd.serviceRepo.PurgeServiceInstance(instance)
	if err != nil {
		cmd.ui.Failed(err.Error())
	}

	cmd.ui.Ok()
}
<commit_msg>purge-service-instance: Use idiomatic error check<commit_after>package service

import (
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_registry"
	"github.com/cloudfoundry/cli/cf/errors"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
	"github.com/simonleung8/flags/flag"
)

type PurgeServiceInstance struct {
	ui          terminal.UI
	serviceRepo api.ServiceRepository
}

func init() {
	command_registry.Register(&PurgeServiceInstance{})
}

func (cmd *PurgeServiceInstance) MetaData() command_registry.CommandMetadata {
	fs := make(map[string]flags.FlagSet)
	fs["f"] = &cliFlags.BoolFlag{Name: "f", Usage: T("Force deletion without confirmation")}

	return command_registry.CommandMetadata{
		Name:        "purge-service-instance",
		Description: T("Recursively remove a service instance and child objects from Cloud Foundry database without making requests to a service broker"),
		Usage:       T("CF_NAME purge-service-instance SERVICE_INSTANCE") + "\n\n" + cmd.scaryWarningMessage(),
		Flags:       fs,
	}
}

func (cmd *PurgeServiceInstance) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
	if len(fc.Args()) != 1 {
		cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + command_registry.Commands.CommandUsage("purge-service-instance"))
	}

	return []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
	}, nil
}

func (cmd *PurgeServiceInstance) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command {
	cmd.ui = deps.Ui
	cmd.serviceRepo = deps.RepoLocator.GetServiceRepository()
	return cmd
}

func (cmd *PurgeServiceInstance) scaryWarningMessage() string {
	return T(`WARNING: This operation assumes that the service broker responsible for this service instance is no longer available or is not responding with a 200 or 410, and the service instance has been deleted, leaving orphan records in Cloud Foundry's database. All knowledge of the service instance will be removed from Cloud Foundry, including service bindings and service keys.`)
}

func (cmd *PurgeServiceInstance) Execute(c flags.FlagContext) {
	instanceName := c.Args()[0]

	instance, err := cmd.serviceRepo.FindInstanceByName(instanceName)
	if err != nil {
		if _, ok := err.(*errors.ModelNotFoundError); ok {
			cmd.ui.Warn(T("Service instance {{.InstanceName}} not found", map[string]interface{}{"InstanceName": instanceName}))
			return
		}

		cmd.ui.Failed(err.Error())
	}

	confirmed := c.Bool("f")
	if !confirmed {
		cmd.ui.Warn(cmd.scaryWarningMessage())
		confirmed = cmd.ui.Confirm(T("Really purge service instance {{.InstanceName}} from Cloud Foundry?",
			map[string]interface{}{"InstanceName": instanceName},
		))
	}

	if !confirmed {
		return
	}
	cmd.ui.Say(T("Purging service {{.InstanceName}}...", map[string]interface{}{"InstanceName": instanceName}))
	err = cmd.serviceRepo.PurgeServiceInstance(instance)
	if err != nil {
		cmd.ui.Failed(err.Error())
	}

	cmd.ui.Ok()
}
<|endoftext|>


<commit_before>package dedup_test

import (
	"testing"

	"bytes"
	"crypto/rand"
	"io"

	"io/ioutil"

	"github.com/klauspost/dedup"
)

func TestFixedWriter(t *testing.T) {
	idx := bytes.Buffer{}
	data := bytes.Buffer{}
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	input = bytes.NewBuffer(b)
	w, err := dedup.NewWriter(&idx, &data, dedup.ModeFixed, size)
	if err != nil {
		t.Fatal(err)
	}
	io.Copy(w, input)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}
	removed := ((totalinput) - data.Len()) / size

	t.Log(dedup.BirthDayProblem(totalinput / size))
	t.Log("Index size:", idx.Len())
	t.Log("Data size:", data.Len())
	t.Log("Removed", removed, "blocks")
	// We should get at least 50 blocks
	if removed < 50 {
		t.Fatal("didn't remove at least 50 blocks")
	}
	if removed > 60 {
		t.Fatal("removed unreasonable high amount of blocks")
	}
}

func TestDynamicWriter(t *testing.T) {
	idx := bytes.Buffer{}
	data := bytes.Buffer{}
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	input = bytes.NewBuffer(b)
	w, err := dedup.NewWriter(&idx, &data, dedup.ModeDynamic, size)
	if err != nil {
		t.Fatal(err)
	}
	io.Copy(w, input)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}
	removed := ((totalinput) - data.Len()) / size

	t.Log("Dynamic Index size:", idx.Len())
	t.Log("Dynamic Data size:", data.Len())
	t.Log("Removed", removed, "blocks")
	// We don't know how many, but it should remove some blocks
	if removed < 10 {
		t.Fatal("didn't remove at least 10 blocks")
	}
}

func BenchmarkFixedWriter64K(t *testing.B) {
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	t.ResetTimer()
	t.SetBytes(totalinput)
	for i := 0; i < t.N; i++ {
		input = bytes.NewBuffer(b)
		w, _ := dedup.NewWriter(ioutil.Discard, ioutil.Discard, dedup.ModeFixed, size)
		io.Copy(w, input)
		err = w.Close()
		if err != nil {
			t.Fatal(err)
		}
	}
}

func BenchmarkFixedWriter4K(t *testing.B) {
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 4 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 500; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	t.ResetTimer()
	t.SetBytes(totalinput)
	for i := 0; i < t.N; i++ {
		input = bytes.NewBuffer(b)
		w, _ := dedup.NewWriter(ioutil.Discard, ioutil.Discard, dedup.ModeFixed, size)
		io.Copy(w, input)
		err = w.Close()
		if err != nil {
			t.Fatal(err)
		}
	}
}

// Maximum block size:64k
func BenchmarkDynamicWriter64K(t *testing.B) {
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	t.ResetTimer()
	t.SetBytes(totalinput)
	for i := 0; i < t.N; i++ {
		input = bytes.NewBuffer(b)
		w, _ := dedup.NewWriter(ioutil.Discard, ioutil.Discard, dedup.ModeDynamic, size)
		io.Copy(w, input)
		err = w.Close()
		if err != nil {
			t.Fatal(err)
		}
	}
}

func TestBirthday(t *testing.T) {
	t.Log("Hash size is", dedup.HashSize*8, "bits")
	t.Log("1GiB, 1KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 30) / (1 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<30)/(1<<10))>>20, "MiB memory")
	t.Log("1TiB, 4KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 40) / (4 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<40)/(4<<10))>>20, "MiB memory")
	t.Log("1PiB, 4KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 50) / (4 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<50)/(4<<10))>>20, "MiB memory")
	t.Log("1EiB, 64KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 60) / (64 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<60)/(64<<10))>>20, "MiB memory")
	t.Log("1EiB, 1KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 60) / (1 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<60)/(1<<10))>>20, "MiB memory")
}
<commit_msg>Add Stream writer tests.<commit_after>package dedup_test

import (
	"testing"

	"bytes"
	"crypto/rand"
	"io"

	"io/ioutil"

	"github.com/klauspost/dedup"
)

func TestFixedWriter(t *testing.T) {
	idx := bytes.Buffer{}
	data := bytes.Buffer{}
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	input = bytes.NewBuffer(b)
	w, err := dedup.NewWriter(&idx, &data, dedup.ModeFixed, size)
	if err != nil {
		t.Fatal(err)
	}
	io.Copy(w, input)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}
	removed := ((totalinput) - data.Len()) / size

	t.Log(dedup.BirthDayProblem(totalinput / size))
	t.Log("Index size:", idx.Len())
	t.Log("Data size:", data.Len())
	t.Log("Removed", removed, "blocks")
	// We should get at least 50 blocks
	if removed < 50 {
		t.Fatal("didn't remove at least 50 blocks")
	}
	if removed > 60 {
		t.Fatal("removed unreasonable high amount of blocks")
	}
}

func TestDynamicWriter(t *testing.T) {
	idx := bytes.Buffer{}
	data := bytes.Buffer{}
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	input = bytes.NewBuffer(b)
	w, err := dedup.NewWriter(&idx, &data, dedup.ModeDynamic, size)
	if err != nil {
		t.Fatal(err)
	}
	io.Copy(w, input)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}
	removed := ((totalinput) - data.Len()) / size

	t.Log("Dynamic Index size:", idx.Len())
	t.Log("Dynamic Data size:", data.Len())
	t.Log("Removed", removed, "blocks")
	// We don't know how many, but it should remove some blocks
	if removed < 40 {
		t.Fatal("didn't remove at least 40 blocks")
	}
}

func TestFixedStreamWriter(t *testing.T) {
	data := bytes.Buffer{}
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	input = bytes.NewBuffer(b)
	w, err := dedup.NewStreamWriter(&data, dedup.ModeFixed, size, 10)
	if err != nil {
		t.Fatal(err)
	}
	io.Copy(w, input)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}
	removed := ((totalinput) - data.Len()) / size

	t.Log("Data size:", data.Len())
	t.Log("Removed", removed, "blocks")
	// We should get at least 50 blocks, but there is a little overhead
	if removed < 49 {
		t.Fatal("didn't remove at least 49 blocks")
	}
	if removed > 60 {
		t.Fatal("removed unreasonable high amount of blocks")
	}
}

func TestDynamicStreamWriter(t *testing.T) {
	data := bytes.Buffer{}
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	input = bytes.NewBuffer(b)
	w, err := dedup.NewStreamWriter(&data, dedup.ModeDynamic, size, 10*8)
	if err != nil {
		t.Fatal(err)
	}
	io.Copy(w, input)
	err = w.Close()
	if err != nil {
		t.Fatal(err)
	}
	removed := ((totalinput) - data.Len()) / size

	t.Log("Dynamic Data size:", data.Len())
	t.Log("Removed", removed, "blocks")
	// We don't know how many, but it should remove some blocks
	if removed < 40 {
		t.Fatal("didn't remove at least 40 blocks")
	}
}

func BenchmarkFixedWriter64K(t *testing.B) {
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	t.ResetTimer()
	t.SetBytes(totalinput)
	for i := 0; i < t.N; i++ {
		input = bytes.NewBuffer(b)
		w, _ := dedup.NewWriter(ioutil.Discard, ioutil.Discard, dedup.ModeFixed, size)
		io.Copy(w, input)
		err = w.Close()
		if err != nil {
			t.Fatal(err)
		}
	}
}

func BenchmarkFixedWriter4K(t *testing.B) {
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 4 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 500; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	t.ResetTimer()
	t.SetBytes(totalinput)
	for i := 0; i < t.N; i++ {
		input = bytes.NewBuffer(b)
		w, _ := dedup.NewWriter(ioutil.Discard, ioutil.Discard, dedup.ModeFixed, size)
		io.Copy(w, input)
		err = w.Close()
		if err != nil {
			t.Fatal(err)
		}
	}
}

// Maximum block size:64k
func BenchmarkDynamicWriter64K(t *testing.B) {
	input := &bytes.Buffer{}

	const totalinput = 10 << 20
	_, err := io.CopyN(input, rand.Reader, totalinput)
	if err != nil {
		t.Fatal(err)
	}
	const size = 64 << 10
	b := input.Bytes()
	// Create some duplicates
	for i := 0; i < 50; i++ {
		// Read from 10 first blocks
		src := b[(i%10)*size : (i%10)*size+size]
		// Write into the following ones
		dst := b[(10+i)*size : (i+10)*size+size]
		copy(dst, src)
	}
	t.ResetTimer()
	t.SetBytes(totalinput)
	for i := 0; i < t.N; i++ {
		input = bytes.NewBuffer(b)
		w, _ := dedup.NewWriter(ioutil.Discard, ioutil.Discard, dedup.ModeDynamic, size)
		io.Copy(w, input)
		err = w.Close()
		if err != nil {
			t.Fatal(err)
		}
	}
}

func TestBirthday(t *testing.T) {
	t.Log("Hash size is", dedup.HashSize*8, "bits")
	t.Log("1GiB, 1KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 30) / (1 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<30)/(1<<10))>>20, "MiB memory")
	t.Log("1TiB, 4KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 40) / (4 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<40)/(4<<10))>>20, "MiB memory")
	t.Log("1PiB, 4KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 50) / (4 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<50)/(4<<10))>>20, "MiB memory")
	t.Log("1EiB, 64KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 60) / (64 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<60)/(64<<10))>>20, "MiB memory")
	t.Log("1EiB, 1KiB blocks:")
	t.Log(dedup.BirthDayProblem((1 << 60) / (1 << 10)))
	t.Log("It will use", dedup.FixedMemUse((1<<60)/(1<<10))>>20, "MiB memory")
}
<|endoftext|>


<commit_before>package openapi

import (
	"context"
	"fmt"
	"net/http"
)

type Channel struct {
	ID            *string       `json:"id,omitempty"`
	TeamID        *string       `json:"team_id,omitempty"`
	VChannelID    *string       `json:"vchannel_id,omitempty"`
	UserID        *string       `json:"uid,omitempty"`
	Name          *string       `json:"name,omitempty"`
	Type          *VChannelType `json:"type,omitempty"`
	Private       *bool         `json:"private,omitempty"`
	General       *bool         `json:"general,omitempty"`
	Topic         *string       `json:"topic,omitempty"`
	IsMember      *bool         `json:"is_member,omitempty"`
	IsActive      *bool         `json:"is_active,omitempty"`
	MemberUserIDs []string      `json:"member_uids,omitempty"`
	LatestTS      *VChannelTS   `json:"latest_ts,omitempty"`
}

type ChannelService service

type ChannelInfoOptions struct {
	ChannelID string
}

// Info implements `GET /channel.info`
func (c *ChannelService) Info(ctx context.Context, opt *ChannelInfoOptions) (*Channel, *http.Response, error) {
	endpoint := fmt.Sprintf("channel.info?channel_id=%s", opt.ChannelID)
	req, err := c.client.newRequest("GET", endpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

// List implements `GET /channel.list`
func (c *ChannelService) List(ctx context.Context) ([]*Channel, *http.Response, error) {
	req, err := c.client.newRequest("GET", "channel.list", nil)
	if err != nil {
		return nil, nil, err
	}

	var channels []*Channel
	resp, err := c.client.do(ctx, req, &channels)
	if err != nil {
		return nil, resp, err
	}
	return channels, resp, nil
}

type ChannelCreateOptions struct {
	Name    string  `json:"name"`
	Topic   *string `json:"topic,omitempty"`
	Private *bool   `json:"private,omitempty"`
}

func (c *ChannelService) Create(ctx context.Context, opt *ChannelCreateOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.create", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}
<commit_msg>feat(openapi): implement `channel.archive`<commit_after>package openapi

import (
	"context"
	"fmt"
	"net/http"
)

type Channel struct {
	ID            *string       `json:"id,omitempty"`
	TeamID        *string       `json:"team_id,omitempty"`
	VChannelID    *string       `json:"vchannel_id,omitempty"`
	UserID        *string       `json:"uid,omitempty"`
	Name          *string       `json:"name,omitempty"`
	Type          *VChannelType `json:"type,omitempty"`
	Private       *bool         `json:"private,omitempty"`
	General       *bool         `json:"general,omitempty"`
	Topic         *string       `json:"topic,omitempty"`
	IsMember      *bool         `json:"is_member,omitempty"`
	IsActive      *bool         `json:"is_active,omitempty"`
	MemberUserIDs []string      `json:"member_uids,omitempty"`
	LatestTS      *VChannelTS   `json:"latest_ts,omitempty"`
}

type ChannelService service

type ChannelInfoOptions struct {
	ChannelID string
}

// Info implements `GET /channel.info`
func (c *ChannelService) Info(ctx context.Context, opt *ChannelInfoOptions) (*Channel, *http.Response, error) {
	endpoint := fmt.Sprintf("channel.info?channel_id=%s", opt.ChannelID)
	req, err := c.client.newRequest("GET", endpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

// List implements `GET /channel.list`
func (c *ChannelService) List(ctx context.Context) ([]*Channel, *http.Response, error) {
	req, err := c.client.newRequest("GET", "channel.list", nil)
	if err != nil {
		return nil, nil, err
	}

	var channels []*Channel
	resp, err := c.client.do(ctx, req, &channels)
	if err != nil {
		return nil, resp, err
	}
	return channels, resp, nil
}

type ChannelCreateOptions struct {
	Name    string  `json:"name"`
	Topic   *string `json:"topic,omitempty"`
	Private *bool   `json:"private,omitempty"`
}

// Create implements `POST /channel.create`
func (c *ChannelService) Create(ctx context.Context, opt *ChannelCreateOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.create", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelArchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

func (c *ChannelService) Archive(ctx context.Context, opt *ChannelArchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.archive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}
<|endoftext|>


<commit_before>package quest

type ProgressBar struct {
	Qreq     *Qrequest
	Total    int64
	Current  int64
	Progress func(current, total, expected int64)
}

func (p *ProgressBar) Write(b []byte) (int, error) {
	current := len(b)
	// Response ContentLength
	if p.Total != -1 {
		p.Current += int64(current)
		p.Progress(p.Current, p.Total, p.Total-p.Current)
	}
	return current, nil
}
<commit_msg>update progressbar<commit_after>package quest

type ProgressBar struct {
	Qreq                     *Qrequest
	Progress                 func(current, total, expected int64)
	Total, Current, Expected int64
}

func (p *ProgressBar) Write(b []byte) (int, error) {
	current := len(b)
	// Response ContentLength
	if p.Total != -1 {
		p.calculate(int64(current))
		p.Progress(p.Current, p.Total, p.Expected)
	}
	return current, nil
}

func (p *ProgressBar) calculate(i int64) {
	p.Current += i
	p.Expected = p.Total - p.Current
}
<|endoftext|>


<commit_before>package mqtt

import (
	"encoding/json"
	"fmt"
	"log"
	"time"

	"github.com/bbqgophers/messages"
	"github.com/bbqgophers/qpid"
	"github.com/gomqtt/client"
	"github.com/pkg/errors"
)

// Sink is a qpid.MetricSink that
// Reports metrics to MQTT
type Sink struct {
	config  *client.Config
	service *client.Service
	topic   string
}

//NewSink returns a new PrometheusSink
func NewSink(topic string) *Sink {
	config := client.NewConfigWithClientID("mqtt://bketelsen:ncc1701c@mqtt.bbq.live", "qpid")
	config.CleanSession = false
	s := client.NewService()

	s.OnlineCallback = func(resumed bool) {
		fmt.Println("Online with mqtt")
		fmt.Printf("resumed: %v\n", resumed)
	}
	s.OfflineCallback = func() {
		fmt.Println("offline with mqtt!")
	}
	err := client.ClearSession(config)
	if err != nil {
		panic(err)
	}
	s.Start(config)

	return &Sink{
		config:  config,
		service: s,
		topic:   topic,
	}
}

// Listen starts a GrillStatus listener on GrillStatus channel
// reporting messages received to Prometheus.  Must be started
// in a goroutine before starting grill run loop or grill will block
// when it tries to send first status
func (p *Sink) Listen(s chan qpid.GrillStatus) {
	for status := range s {
		var fst int
		if status.FanOn {
			fst = 1
		}
		fsm := messages.FanStatus{
			FanOn: fst,
		}

		b, err := json.Marshal(fsm)
		if err != nil {
			fmt.Println("Err marshaling Fan Status", err)
		}
		fut := p.service.Publish(p.FanTopic(), b, 0, false)

		err = fut.Wait(5 * time.Second)
		if err != nil {
			panic(err)
		}
		for _, s := range status.GrillSensors {
			t, err := s.Temperature()
			if err != nil {
				log.Println(errors.Wrap(err, "get temperature"))
			}

			tm := messages.GrillTemp{
				Temp: t,
			}

			b, err := json.Marshal(tm)
			if err != nil {
				fmt.Println("Err marshaling Grill Temp", err)
			}

			p.service.Publish(p.GrillTopic(), b, 0, false)

			set, err := s.Setpoint()
			if err != nil {
				log.Println(errors.Wrap(err, "get setpoint"))
			}

			gtm := messages.GrillTarget{
				Temp: set,
			}

			b, err = json.Marshal(gtm)
			if err != nil {
				fmt.Println("Err marshaling Grill Setpoint", err)
			}

			p.service.Publish(p.SetTopic(), b, 0, false)
		}
	}

}

func (p *Sink) FanTopic() string {
	return p.topic + "/fan"
}

func (p *Sink) GrillTopic() string {
	return p.topic + "/grill"
}

func (p *Sink) SetTopic() string {
	return p.topic + "/setpoint"
}
<commit_msg>add setpoint<commit_after>package mqtt

import (
	"encoding/json"
	"fmt"
	"log"
	"time"

	"github.com/bbqgophers/messages"
	"github.com/bbqgophers/qpid"
	"github.com/gomqtt/client"
	"github.com/pkg/errors"
)

// Sink is a qpid.MetricSink that
// Reports metrics to MQTT
type Sink struct {
	config  *client.Config
	service *client.Service
	topic   string
}

//NewSink returns a new PrometheusSink
func NewSink(topic string) *Sink {
	config := client.NewConfigWithClientID("mqtt://bketelsen:ncc1701c@mqtt.bbq.live", "qpid")
	config.CleanSession = false
	s := client.NewService()

	s.OnlineCallback = func(resumed bool) {
		fmt.Println("Online with mqtt")
		fmt.Printf("resumed: %v\n", resumed)
	}
	s.OfflineCallback = func() {
		fmt.Println("offline with mqtt!")
	}
	err := client.ClearSession(config)
	if err != nil {
		panic(err)
	}
	s.Start(config)

	return &Sink{
		config:  config,
		service: s,
		topic:   topic,
	}
}

// Listen starts a GrillStatus listener on GrillStatus channel
// reporting messages received to Prometheus.  Must be started
// in a goroutine before starting grill run loop or grill will block
// when it tries to send first status
func (p *Sink) Listen(s chan qpid.GrillStatus) {
	for status := range s {
		var fst int
		if status.FanOn {
			fst = 1
		}
		fsm := messages.FanStatus{
			FanOn: fst,
			Time:  time.Now(),
		}

		b, err := json.Marshal(fsm)
		if err != nil {
			fmt.Println("Err marshaling Fan Status", err)
		}
		fut := p.service.Publish(p.FanTopic(), b, 0, false)

		err = fut.Wait(5 * time.Second)
		if err != nil {
			panic(err)
		}
		for _, s := range status.GrillSensors {
			t, err := s.Temperature()
			if err != nil {
				log.Println(errors.Wrap(err, "get temperature"))
			}

			tm := messages.GrillTemp{
				Temp: t,
				Time: time.Now(),
			}

			b, err := json.Marshal(tm)
			if err != nil {
				fmt.Println("Err marshaling Grill Temp", err)
			}

			p.service.Publish(p.GrillTopic(), b, 0, false)

			set, err := s.Setpoint()
			if err != nil {
				log.Println(errors.Wrap(err, "get setpoint"))
			}

			gtm := messages.GrillTarget{
				Temp: set,
				Time: time.Now(),
			}

			b, err = json.Marshal(gtm)
			if err != nil {
				fmt.Println("Err marshaling Grill Setpoint", err)
			}

			p.service.Publish(p.SetTopic(), b, 0, false)
		}
	}

}

func (p *Sink) FanTopic() string {
	return p.topic + "/fan"
}

func (p *Sink) GrillTopic() string {
	return p.topic + "/grill"
}

func (p *Sink) SetTopic() string {
	return p.topic + "/setpoint"
}
<|endoftext|>


<commit_before>package mqtt

import (
	"bytes"
	"reflect"
	"testing"

	gbt "github.com/huin/gobinarytest"
)

var bitCnt = uint32(0)

func Test(t *testing.T) {
	tests := []struct {
		Msg      Message
		Expected gbt.Matcher
	}{
		{
			Msg: &Connect{
				ProtocolName:    "MQIsdp",
				ProtocolVersion: 3,
				UsernameFlag:    true,
				PasswordFlag:    true,
				WillRetain:      false,
				WillQos:         1,
				WillFlag:        true,
				CleanSession:    true,
				KeepAliveTimer:  10,
				ClientId:        "xixihaha",
				WillTopic:       "topic",
				WillMessage:     "message",
				Username:        "name",
				Password:        "pwd",
			},
			Expected: gbt.InOrder{
				gbt.Named{"Header byte", gbt.Literal{0x10}},
				gbt.Named{"Remaining length", gbt.Literal{12 + 5*2 + 8 + 5 + 7 + 4 + 3}},

				// Extended headers for CONNECT:
				gbt.Named{"Protocol name", gbt.InOrder{gbt.Literal{0x00, 0x06}, gbt.Literal("MQIsdp")}},
				gbt.Named{
					"Extended headers for CONNECT",
					gbt.Literal{
						0x03,       // Protocol version number
						0xce,       // Connect flags
						0x00, 0x0a, // Keep alive timer
					},
				},

				// CONNECT payload:
				gbt.Named{"Client identifier", gbt.InOrder{gbt.Literal{0x00, 0x08}, gbt.Literal("xixihaha")}},
				gbt.Named{"Will topic", gbt.InOrder{gbt.Literal{0x00, 0x05}, gbt.Literal("topic")}},
				gbt.Named{"Will message", gbt.InOrder{gbt.Literal{0x00, 0x07}, gbt.Literal("message")}},
				gbt.Named{"Username", gbt.InOrder{gbt.Literal{0x00, 0x04}, gbt.Literal("name")}},
				gbt.Named{"Password", gbt.InOrder{gbt.Literal{0x00, 0x03}, gbt.Literal("pwd")}},
			},
		},
	}

	for _, test := range tests {
		encodedBuf := new(bytes.Buffer)
		if err := test.Msg.Encode(encodedBuf); err != nil {
			t.Errorf("Unexpected error during encoding: %v", err)
		} else if err = gbt.Matches(test.Expected, encodedBuf.Bytes()); err != nil {
			t.Errorf("Unexpected encoding output: %v", err)
		}

		expectedBuf := new(bytes.Buffer)
		test.Expected.Write(expectedBuf)

		if decodedMsg, err := DecodeOneMessage(expectedBuf); err != nil {
			t.Errorf("Unexpected error during decoding: %v", err)
		} else if !reflect.DeepEqual(test.Msg, decodedMsg) {
			t.Errorf("Decoded value mismatch\n     got = %#v\nexpected = %#v",
				decodedMsg, test.Msg)
		}
	}
}

func TestDecodeLength(t *testing.T) {
	tests := []struct {
		Expected int32
		Bytes    []byte
	}{
		{0, []byte{0}},
		{1, []byte{1}},
		{20, []byte{20}},

		// Boundary conditions used as tests taken from MQTT 3.1 spec.
		{0, []byte{0x00}},
		{127, []byte{0x7F}},
		{128, []byte{0x80, 0x01}},
		{16383, []byte{0xFF, 0x7F}},
		{16384, []byte{0x80, 0x80, 0x01}},
		{2097151, []byte{0xFF, 0xFF, 0x7F}},
		{2097152, []byte{0x80, 0x80, 0x80, 0x01}},
		{268435455, []byte{0xFF, 0xFF, 0xFF, 0x7F}},
	}

	for _, test := range tests {
		buf := bytes.NewBuffer(test.Bytes)
		if result := decodeLength(buf); test.Expected != result {
			t.Errorf("Test %v: got %d", test, result)
		}
	}
}
<commit_msg>Add CONNACK encoding test.<commit_after>package mqtt

import (
	"bytes"
	"reflect"
	"testing"

	gbt "github.com/huin/gobinarytest"
)

var bitCnt = uint32(0)

func Test(t *testing.T) {
	tests := []struct {
		Comment  string
		Msg      Message
		Expected gbt.Matcher
	}{
		{
			Comment: "CONNECT message",
			Msg: &Connect{
				ProtocolName:    "MQIsdp",
				ProtocolVersion: 3,
				UsernameFlag:    true,
				PasswordFlag:    true,
				WillRetain:      false,
				WillQos:         1,
				WillFlag:        true,
				CleanSession:    true,
				KeepAliveTimer:  10,
				ClientId:        "xixihaha",
				WillTopic:       "topic",
				WillMessage:     "message",
				Username:        "name",
				Password:        "pwd",
			},
			Expected: gbt.InOrder{
				gbt.Named{"Header byte", gbt.Literal{0x10}},
				gbt.Named{"Remaining length", gbt.Literal{12 + 5*2 + 8 + 5 + 7 + 4 + 3}},

				// Extended headers for CONNECT:
				gbt.Named{"Protocol name", gbt.InOrder{gbt.Literal{0x00, 0x06}, gbt.Literal("MQIsdp")}},
				gbt.Named{
					"Extended headers for CONNECT",
					gbt.Literal{
						0x03,       // Protocol version number
						0xce,       // Connect flags
						0x00, 0x0a, // Keep alive timer
					},
				},

				// CONNECT payload:
				gbt.Named{"Client identifier", gbt.InOrder{gbt.Literal{0x00, 0x08}, gbt.Literal("xixihaha")}},
				gbt.Named{"Will topic", gbt.InOrder{gbt.Literal{0x00, 0x05}, gbt.Literal("topic")}},
				gbt.Named{"Will message", gbt.InOrder{gbt.Literal{0x00, 0x07}, gbt.Literal("message")}},
				gbt.Named{"Username", gbt.InOrder{gbt.Literal{0x00, 0x04}, gbt.Literal("name")}},
				gbt.Named{"Password", gbt.InOrder{gbt.Literal{0x00, 0x03}, gbt.Literal("pwd")}},
			},
		},

		{
			Comment: "CONNACK message",
			Msg: &ConnAck{
				ReturnCode: RetCodeBadUsernameOrPassword,
			},
			Expected: gbt.InOrder{
				gbt.Named{"Header byte", gbt.Literal{0x20}},
				gbt.Named{"Remaining length", gbt.Literal{2}},

				gbt.Named{"Reserved byte", gbt.Literal{0}},
				gbt.Named{"Return code", gbt.Literal{4}},
			},
		},
	}

	for _, test := range tests {
		encodedBuf := new(bytes.Buffer)
		if err := test.Msg.Encode(encodedBuf); err != nil {
			t.Errorf("%s: Unexpected error during encoding: %v", test.Comment, err)
		} else if err = gbt.Matches(test.Expected, encodedBuf.Bytes()); err != nil {
			t.Errorf("%s: Unexpected encoding output: %v", test.Comment, err)
		}

		expectedBuf := new(bytes.Buffer)
		test.Expected.Write(expectedBuf)

		if decodedMsg, err := DecodeOneMessage(expectedBuf); err != nil {
			t.Errorf("%s: Unexpected error during decoding: %v", test.Comment, err)
		} else if !reflect.DeepEqual(test.Msg, decodedMsg) {
			t.Errorf("%s: Decoded value mismatch\n     got = %#v\nexpected = %#v",
				test.Comment, decodedMsg, test.Msg)
		}
	}
}

func TestDecodeLength(t *testing.T) {
	tests := []struct {
		Expected int32
		Bytes    []byte
	}{
		{0, []byte{0}},
		{1, []byte{1}},
		{20, []byte{20}},

		// Boundary conditions used as tests taken from MQTT 3.1 spec.
		{0, []byte{0x00}},
		{127, []byte{0x7F}},
		{128, []byte{0x80, 0x01}},
		{16383, []byte{0xFF, 0x7F}},
		{16384, []byte{0x80, 0x80, 0x01}},
		{2097151, []byte{0xFF, 0xFF, 0x7F}},
		{2097152, []byte{0x80, 0x80, 0x80, 0x01}},
		{268435455, []byte{0xFF, 0xFF, 0xFF, 0x7F}},
	}

	for _, test := range tests {
		buf := bytes.NewBuffer(test.Bytes)
		if result := decodeLength(buf); test.Expected != result {
			t.Errorf("Test %v: got %d", test, result)
		}
	}
}
<|endoftext|>


<commit_before>package carto

import (
	"testing"

	"github.com/lukeroth/gdal"
)

var buildMap_tests = []struct {
	ll       FloatExtents
	elvrt    string
	lcvrt    string
	minmaxes []RasterInfo
}{
	{
		FloatExtents{-71.575, -71.576, 41.189, 41.191},
		"test_elevation.tif",
		"test_landcover.tif",
		[]RasterInfo{
			RasterInfo{"Int16", 11, 95},
			RasterInfo{"Int16", 62, 64},
			RasterInfo{"Int16", 0, 30},
			RasterInfo{"Int16", 1, 4},
			RasterInfo{"Int16", 0, 24},
		},
	},
}

func Test_buildMap(t *testing.T) {
	for _, tt := range buildMap_tests {
		r := MakeRegion("Pie", tt.ll)
		r.tilesize = 16
		r.vrts["elevation"] = tt.elvrt
		r.vrts["landcover"] = tt.lcvrt
		r.buildMap()

		// check the raster minmaxes
		ds, err := gdal.Open(r.mapfile, gdal.ReadOnly)
		if err != nil {
			t.Fail()
		}
		if Debug {
			datasetInfo(ds, "Test")
		}
		minmaxes := datasetMinMaxes(ds)

		if len(minmaxes) != len(tt.minmaxes) {
			t.Fatalf("len(minmaxes) %d != len(tt.minmaxes) %d", len(minmaxes), len(tt.minmaxes))
		}
		for i, v := range minmaxes {
			if tt.minmaxes[i] != v {
				t.Errorf("Raster #%d: expected \"%s\", got \"%s\"", i+1, tt.minmaxes[i], v)
			}
		}
	}
}
<commit_msg>Modified test routines to use new directory structure.<commit_after>package carto

import (
	"path"
	"testing"

	"github.com/lukeroth/gdal"
)

var buildMap_tests = []struct {
	name     string
	ll       FloatExtents
	minmaxes []RasterInfo
}{
	{
		"BlockIsland",
		FloatExtents{-71.575, -71.576, 41.189, 41.191},
		[]RasterInfo{
			RasterInfo{"Int16", 11, 95},
			RasterInfo{"Int16", 62, 64},
			RasterInfo{"Int16", 0, 30},
			RasterInfo{"Int16", 1, 4},
			RasterInfo{"Int16", 0, 24},
		},
	},
}

func Test_buildMap(t *testing.T) {
	for _, tt := range buildMap_tests {
		r := MakeRegion(tt.name, tt.ll)
		r.tilesize = 16
		r.vrts["elevation"] = path.Join(tt.name, "elevation.tif")
		r.vrts["landcover"] = path.Join(tt.name, "landcover.tif")
		Debug = true
		r.buildMap()
		Debug = true

		// check the raster minmaxes
		ds, err := gdal.Open(r.mapfile, gdal.ReadOnly)
		if err != nil {
			t.Fail()
		}
		if Debug {
			datasetInfo(ds, "Test")
		}
		minmaxes := datasetMinMaxes(ds)

		if len(minmaxes) != len(tt.minmaxes) {
			t.Fatalf("len(minmaxes) %d != len(tt.minmaxes) %d", len(minmaxes), len(tt.minmaxes))
		}
		for i, v := range minmaxes {
			if tt.minmaxes[i] != v {
				t.Errorf("Raster #%d: expected \"%s\", got \"%s\"", i+1, tt.minmaxes[i], v)
			}
		}
	}
}
<|endoftext|>


<commit_before>package sinmetalcraft

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

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/taskqueue"
	"google.golang.org/appengine/urlfetch"

	"google.golang.org/api/compute/v1"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

type OverviewerAPI struct{}

const OverviewerInstanceName = "overviewer"
const OverViewerWorldDiskFormat = "%s-overviewer-world-%s"

func init() {
	api := OverviewerAPI{}

	http.HandleFunc("/cron/1/overviewer", api.handler)
	http.HandleFunc("/tq/1/overviewer/instance/create", api.handleTQCreateInstace)
}

func (a *OverviewerAPI) handler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	q := datastore.NewQuery("Minecraft").Order("-UpdatedAt")

	list := make([]*Minecraft, 0)
	for t := q.Run(ctx); ; {
		var entity Minecraft
		key, err := t.Next(&entity)
		if err == datastore.Done {
			break
		}
		if err != nil {
			log.Errorf(ctx, "Minecraft Query Error. error = %s", err.Error())
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		entity.Key = key
		entity.KeyStr = key.Encode()
		list = append(list, &entity)
	}

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}

	// TODO 本来は1つずつTQにする方がよい
	for _, minecraft := range list {
		if minecraft.LatestSnapshot == minecraft.OverviewerSnapshot {
			continue
		}

		s, err := compute.New(client)
		if err != nil {
			log.Errorf(ctx, "ERROR compute.New: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		ds := compute.NewDisksService(s)
		ope, err := a.createDiskFromSnapshot(ctx, ds, *minecraft)
		if err != nil {
			log.Errorf(ctx, "ERROR create disk: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		_, err = a.CallCreateInstance(ctx, minecraft.Key, ope.Name)
		if err != nil {
			log.Errorf(ctx, "ERROR call create instance tq: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		err = minecraft.UpdateOverviewerSnapshot(ctx, minecraft.Key)
		if err != nil {
			log.Errorf(ctx, "ERROR Update OverviewerSnapshot: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
}

// create disk from snapshot
func (a *OverviewerAPI) createDiskFromSnapshot(ctx context.Context, ds *compute.DisksService, minecraft Minecraft) (*compute.Operation, error) {
	name := fmt.Sprintf(OverViewerWorldDiskFormat, INSTANCE_NAME, minecraft.World)
	d := &compute.Disk{
		Name:           name,
		SizeGb:         100,
		SourceSnapshot: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/global/snapshots/" + minecraft.LatestSnapshot,
		Type:           "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/diskTypes/pd-ssd",
	}

	ope, err := ds.Insert(PROJECT_NAME, minecraft.Zone, d).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR insert disk: %s", err)
		return nil, err
	}
	WriteLog(ctx, "INSTNCE_DISK_OPE", ope)

	return ope, err
}

// create gce instance
func (a *OverviewerAPI) createInstance(ctx context.Context, is *compute.InstancesService, minecraft Minecraft) (string, error) {
	name := OverviewerInstanceName + "-" + minecraft.World
	worldDiskName := fmt.Sprintf(OverViewerWorldDiskFormat, INSTANCE_NAME, minecraft.World)
	log.Infof(ctx, "create instance name = %s", name)

	startupScriptURL := "gs://sinmetalcraft-minecraft-shell/minecraft-overviewer-server-startup-script.sh"
	shutdownScriptURL := "gs://sinmetalcraft-minecraft-shell/minecraft-overviewer-shutdown-script.sh"
	stateValue := "new"
	newIns := &compute.Instance{
		Name:        name,
		Zone:        "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone,
		MachineType: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/machineTypes/n1-highcpu-4",
		Disks: []*compute.AttachedDisk{
			&compute.AttachedDisk{
				AutoDelete: true,
				Boot:       true,
				DeviceName: name,
				Mode:       "READ_WRITE",
				InitializeParams: &compute.AttachedDiskInitializeParams{
					SourceImage: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/global/images/family/minecraft-overviewer",
					DiskType:    "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/diskTypes/pd-ssd",
					DiskSizeGb:  100,
				},
			},
			&compute.AttachedDisk{
				AutoDelete: true,
				Boot:       false,
				DeviceName: worldDiskName,
				Mode:       "READ_WRITE",
				Source:     "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/disks/" + worldDiskName,
			},
		},
		CanIpForward: false,
		NetworkInterfaces: []*compute.NetworkInterface{
			&compute.NetworkInterface{
				Network: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/global/networks/default",
				AccessConfigs: []*compute.AccessConfig{
					&compute.AccessConfig{
						Name: "External NAT",
						Type: "ONE_TO_ONE_NAT",
					},
				},
			},
		},
		Tags: &compute.Tags{
			Items: []string{},
		},
		Metadata: &compute.Metadata{
			Items: []*compute.MetadataItems{
				&compute.MetadataItems{
					Key:   "startup-script-url",
					Value: &startupScriptURL,
				},
				&compute.MetadataItems{
					Key:   "shutdown-script-url",
					Value: &shutdownScriptURL,
				},
				&compute.MetadataItems{
					Key:   "world",
					Value: &minecraft.World,
				},
				&compute.MetadataItems{
					Key:   "state",
					Value: &stateValue,
				},
				&compute.MetadataItems{
					Key:   "minecraft-version",
					Value: &minecraft.JarVersion,
				},
			},
		},
		ServiceAccounts: []*compute.ServiceAccount{
			&compute.ServiceAccount{
				Email: "default",
				Scopes: []string{
					compute.DevstorageReadWriteScope,
					compute.ComputeScope,
					"https://www.googleapis.com/auth/logging.write",
				},
			},
		},
		Scheduling: &compute.Scheduling{
			AutomaticRestart:  false,
			OnHostMaintenance: "TERMINATE",
			Preemptible:       true,
		},
	}
	ope, err := is.Insert(PROJECT_NAME, minecraft.Zone, newIns).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR insert instance: %s", err)
		return "", err
	}
	WriteLog(ctx, "INSTNCE_CREATE_OPE", ope)

	return name, nil
}

// delete instance
func (a *OverviewerAPI) deleteInstance(ctx context.Context, is *compute.InstancesService, instanceName string) error {
	log.Infof(ctx, "delete instance name = %s", instanceName)

	ope, err := is.Delete(PROJECT_NAME, "asia-east1-b", instanceName).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR delete instance: %s", err)
		return err
	}
	WriteLog(ctx, "INSTNCE_DELETE_OPE", ope)

	// TODO opeの結果を追うTQを作成する

	return nil
}

func (a *OverviewerAPI) CallCreateInstance(c context.Context, minecraftKey *datastore.Key, operationID string) (*taskqueue.Task, error) {
	log.Infof(c, "Call Minecraft TQ, key = %v, operationID = %s", minecraftKey, operationID)
	if minecraftKey == nil {
		return nil, errors.New("key is required")
	}
	if len(operationID) < 1 {
		return nil, errors.New("operationID is required")
	}

	t := taskqueue.NewPOSTTask("/tq/1/overviewer/instance/create", url.Values{
		"keyStr":      {minecraftKey.Encode()},
		"operationID": {operationID},
	})
	t.Delay = time.Second * 30
	return taskqueue.Add(c, t, "minecraft")
}

// handleTQCreateInstace is Overviewerのためにインスタンスを作成するためのTQ Handler
// Snapshotから復元されたDiskが作成されたのを確認してから、インスタンスを作成する
func (a *OverviewerAPI) handleTQCreateInstace(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	keyStr := r.FormValue("keyStr")
	operationID := r.FormValue("operationID")

	log.Infof(ctx, "keyStr = %s, operationID = %s", keyStr, operationID)

	key, err := datastore.DecodeKey(keyStr)
	if err != nil {
		log.Errorf(ctx, "key decode error. keyStr = %s, err = %s", keyStr, err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	nzos := compute.NewZoneOperationsService(s)
	ope, err := nzos.Get(PROJECT_NAME, "asia-east1-b", operationID).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR compute Zone Operation Get Error. zone = %s, operation = %s, error = %s", "asia-east1-b", operationID, err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	WriteLog(ctx, "__GET_ZONE_COMPUTE_OPE__", ope)

	if ope.Status != "DONE" {
		log.Infof(ctx, "operation status = %s", ope.Status)
		w.WriteHeader(http.StatusRequestTimeout)
		return
	}

	var entity Minecraft
	err = datastore.Get(ctx, key, &entity)
	if err != nil {
		log.Errorf(ctx, "datastore get error. key = %s. error = %v", key.StringID(), err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	entity.Key = key

	is := compute.NewInstancesService(s)
	name, err := a.createInstance(ctx, is, entity)
	if err != nil {
		log.Errorf(ctx, "instance create error. error = %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Infof(ctx, "instance create done. name = %s", name)
	w.WriteHeader(http.StatusOK)
}
<commit_msg>Minecraft Overviewをasia-northeast1-bに移動 refs #36<commit_after>package sinmetalcraft

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

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/taskqueue"
	"google.golang.org/appengine/urlfetch"

	"google.golang.org/api/compute/v1"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

type OverviewerAPI struct{}

const OverviewerInstanceName = "overviewer"
const OverViewerWorldDiskFormat = "%s-overviewer-world-%s"

func init() {
	api := OverviewerAPI{}

	http.HandleFunc("/cron/1/overviewer", api.handler)
	http.HandleFunc("/tq/1/overviewer/instance/create", api.handleTQCreateInstace)
}

func (a *OverviewerAPI) handler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	q := datastore.NewQuery("Minecraft").Order("-UpdatedAt")

	list := make([]*Minecraft, 0)
	for t := q.Run(ctx); ; {
		var entity Minecraft
		key, err := t.Next(&entity)
		if err == datastore.Done {
			break
		}
		if err != nil {
			log.Errorf(ctx, "Minecraft Query Error. error = %s", err.Error())
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		entity.Key = key
		entity.KeyStr = key.Encode()
		list = append(list, &entity)
	}

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}

	// TODO 本来は1つずつTQにする方がよい
	for _, minecraft := range list {
		if minecraft.LatestSnapshot == minecraft.OverviewerSnapshot {
			continue
		}

		s, err := compute.New(client)
		if err != nil {
			log.Errorf(ctx, "ERROR compute.New: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		ds := compute.NewDisksService(s)
		ope, err := a.createDiskFromSnapshot(ctx, ds, *minecraft)
		if err != nil {
			log.Errorf(ctx, "ERROR create disk: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		_, err = a.CallCreateInstance(ctx, minecraft.Key, ope.Name)
		if err != nil {
			log.Errorf(ctx, "ERROR call create instance tq: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		err = minecraft.UpdateOverviewerSnapshot(ctx, minecraft.Key)
		if err != nil {
			log.Errorf(ctx, "ERROR Update OverviewerSnapshot: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
}

// create disk from snapshot
func (a *OverviewerAPI) createDiskFromSnapshot(ctx context.Context, ds *compute.DisksService, minecraft Minecraft) (*compute.Operation, error) {
	name := fmt.Sprintf(OverViewerWorldDiskFormat, INSTANCE_NAME, minecraft.World)
	d := &compute.Disk{
		Name:           name,
		SizeGb:         100,
		SourceSnapshot: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/global/snapshots/" + minecraft.LatestSnapshot,
		Type:           "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/diskTypes/pd-ssd",
	}

	ope, err := ds.Insert(PROJECT_NAME, minecraft.Zone, d).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR insert disk: %s", err)
		return nil, err
	}
	WriteLog(ctx, "INSTNCE_DISK_OPE", ope)

	return ope, err
}

// create gce instance
func (a *OverviewerAPI) createInstance(ctx context.Context, is *compute.InstancesService, minecraft Minecraft) (string, error) {
	name := OverviewerInstanceName + "-" + minecraft.World
	worldDiskName := fmt.Sprintf(OverViewerWorldDiskFormat, INSTANCE_NAME, minecraft.World)
	log.Infof(ctx, "create instance name = %s", name)

	startupScriptURL := "gs://sinmetalcraft-minecraft-shell/minecraft-overviewer-server-startup-script.sh"
	shutdownScriptURL := "gs://sinmetalcraft-minecraft-shell/minecraft-overviewer-shutdown-script.sh"
	stateValue := "new"
	newIns := &compute.Instance{
		Name:        name,
		Zone:        "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone,
		MachineType: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/machineTypes/n1-highcpu-4",
		Disks: []*compute.AttachedDisk{
			&compute.AttachedDisk{
				AutoDelete: true,
				Boot:       true,
				DeviceName: name,
				Mode:       "READ_WRITE",
				InitializeParams: &compute.AttachedDiskInitializeParams{
					SourceImage: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/global/images/family/minecraft-overviewer",
					DiskType:    "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/diskTypes/pd-ssd",
					DiskSizeGb:  100,
				},
			},
			&compute.AttachedDisk{
				AutoDelete: true,
				Boot:       false,
				DeviceName: worldDiskName,
				Mode:       "READ_WRITE",
				Source:     "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/zones/" + minecraft.Zone + "/disks/" + worldDiskName,
			},
		},
		CanIpForward: false,
		NetworkInterfaces: []*compute.NetworkInterface{
			&compute.NetworkInterface{
				Network: "https://www.googleapis.com/compute/v1/projects/" + PROJECT_NAME + "/global/networks/default",
				AccessConfigs: []*compute.AccessConfig{
					&compute.AccessConfig{
						Name: "External NAT",
						Type: "ONE_TO_ONE_NAT",
					},
				},
			},
		},
		Tags: &compute.Tags{
			Items: []string{},
		},
		Metadata: &compute.Metadata{
			Items: []*compute.MetadataItems{
				&compute.MetadataItems{
					Key:   "startup-script-url",
					Value: &startupScriptURL,
				},
				&compute.MetadataItems{
					Key:   "shutdown-script-url",
					Value: &shutdownScriptURL,
				},
				&compute.MetadataItems{
					Key:   "world",
					Value: &minecraft.World,
				},
				&compute.MetadataItems{
					Key:   "state",
					Value: &stateValue,
				},
				&compute.MetadataItems{
					Key:   "minecraft-version",
					Value: &minecraft.JarVersion,
				},
			},
		},
		ServiceAccounts: []*compute.ServiceAccount{
			&compute.ServiceAccount{
				Email: "default",
				Scopes: []string{
					compute.DevstorageReadWriteScope,
					compute.ComputeScope,
					"https://www.googleapis.com/auth/logging.write",
				},
			},
		},
		Scheduling: &compute.Scheduling{
			AutomaticRestart:  false,
			OnHostMaintenance: "TERMINATE",
			Preemptible:       true,
		},
	}
	ope, err := is.Insert(PROJECT_NAME, minecraft.Zone, newIns).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR insert instance: %s", err)
		return "", err
	}
	WriteLog(ctx, "INSTNCE_CREATE_OPE", ope)

	return name, nil
}

// delete instance
func (a *OverviewerAPI) deleteInstance(ctx context.Context, is *compute.InstancesService, instanceName string) error {
	log.Infof(ctx, "delete instance name = %s", instanceName)

	ope, err := is.Delete(PROJECT_NAME, "asia-northeast1-b", instanceName).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR delete instance: %s", err)
		return err
	}
	WriteLog(ctx, "INSTNCE_DELETE_OPE", ope)

	// TODO opeの結果を追うTQを作成する

	return nil
}

func (a *OverviewerAPI) CallCreateInstance(c context.Context, minecraftKey *datastore.Key, operationID string) (*taskqueue.Task, error) {
	log.Infof(c, "Call Minecraft TQ, key = %v, operationID = %s", minecraftKey, operationID)
	if minecraftKey == nil {
		return nil, errors.New("key is required")
	}
	if len(operationID) < 1 {
		return nil, errors.New("operationID is required")
	}

	t := taskqueue.NewPOSTTask("/tq/1/overviewer/instance/create", url.Values{
		"keyStr":      {minecraftKey.Encode()},
		"operationID": {operationID},
	})
	t.Delay = time.Second * 30
	return taskqueue.Add(c, t, "minecraft")
}

// handleTQCreateInstace is Overviewerのためにインスタンスを作成するためのTQ Handler
// Snapshotから復元されたDiskが作成されたのを確認してから、インスタンスを作成する
func (a *OverviewerAPI) handleTQCreateInstace(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	keyStr := r.FormValue("keyStr")
	operationID := r.FormValue("operationID")

	log.Infof(ctx, "keyStr = %s, operationID = %s", keyStr, operationID)

	key, err := datastore.DecodeKey(keyStr)
	if err != nil {
		log.Errorf(ctx, "key decode error. keyStr = %s, err = %s", keyStr, err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	nzos := compute.NewZoneOperationsService(s)
	ope, err := nzos.Get(PROJECT_NAME, "asia-northeast1-b", operationID).Do()
	if err != nil {
		log.Errorf(ctx, "ERROR compute Zone Operation Get Error. zone = %s, operation = %s, error = %s", "asia-northeast1-b", operationID, err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	WriteLog(ctx, "__GET_ZONE_COMPUTE_OPE__", ope)

	if ope.Status != "DONE" {
		log.Infof(ctx, "operation status = %s", ope.Status)
		w.WriteHeader(http.StatusRequestTimeout)
		return
	}

	var entity Minecraft
	err = datastore.Get(ctx, key, &entity)
	if err != nil {
		log.Errorf(ctx, "datastore get error. key = %s. error = %v", key.StringID(), err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	entity.Key = key

	is := compute.NewInstancesService(s)
	name, err := a.createInstance(ctx, is, entity)
	if err != nil {
		log.Errorf(ctx, "instance create error. error = %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Infof(ctx, "instance create done. name = %s", name)
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>package cmd

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

	"github.com/go-errors/errors"
	"github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/irmaserver"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/x-cray/logrus-prefixed-formatter"
)

const pollInterval = 1000 * time.Millisecond

var (
	httpServer *http.Server
	irmaServer *irmaserver.Server
	logger     *logrus.Logger
	defaulturl string
)

// sessionCmd represents the session command
var sessionCmd = &cobra.Command{
	Use:   "session",
	Short: "Perform an IRMA disclosure, issuance or signature session",
	Long: `Perform an IRMA disclosure, issuance or signature session on the command line

Using either the builtin IRMA server library, or an external IRMA server (specify its URL
with --server), an IRMA session is started; the QR is printed in the terminal; and the session
result is printed when the session completes or fails.

A session request can either be constructed using the --disclose, --issue, and --sign together
with --message flags, or it can be specified as JSON to the --request flag.`,
	Example: `irma session --disclose irma-demo.MijnOverheid.root.BSN
irma session --sign irma-demo.MijnOverheid.root.BSN --message message
irma session --issue irma-demo.MijnOverheid.ageLower=yes,yes,yes,no --disclose irma-demo.MijnOverheid.root.BSN
irma session --request '{"type":"disclosing","content":[{"label":"BSN","attributes":["irma-demo.MijnOverheid.root.BSN"]}]}'
irma session --server http://localhost:8088 --authmethod token --key mytoken --disclose irma-demo.MijnOverheid.root.BSN`,
	Run: func(cmd *cobra.Command, args []string) {
		request, irmaconfig, err := configure(cmd)
		if err != nil {
			die("", err)
		}

		// Make sure we always run with latest configuration
		irmaconfig.UpdateSchemes()

		var result *server.SessionResult
		url, _ := cmd.Flags().GetString("url")
		serverurl, _ := cmd.Flags().GetString("server")
		noqr, _ := cmd.Flags().GetBool("noqr")
		flags := cmd.Flags()

		if url != defaulturl && serverurl != "" {
			die("Failed to read configuration", errors.New("--url can't be combined with --server"))
		}

		if serverurl == "" {
			port, _ := flags.GetInt("port")
			privatekeysPath, _ := flags.GetString("privkeys")
			verbosity, _ := cmd.Flags().GetCount("verbose")
			result, err = libraryRequest(request, irmaconfig, url, port, privatekeysPath, noqr, verbosity)
		} else {
			authmethod, _ := flags.GetString("authmethod")
			key, _ := flags.GetString("key")
			name, _ := flags.GetString("name")
			result, err = serverRequest(request, serverurl, authmethod, key, name, noqr)
		}
		if err != nil {
			die("Session failed", err)
		}

		printSessionResult(result)

		// Done!
		if httpServer != nil {
			_ = httpServer.Close()
		}
	},
}

func libraryRequest(
	request irma.RequestorRequest,
	irmaconfig *irma.Configuration,
	url string,
	port int,
	privatekeysPath string,
	noqr bool,
	verbosity int,
) (*server.SessionResult, error) {
	if err := configureServer(url, port, privatekeysPath, irmaconfig, verbosity); err != nil {
		return nil, err
	}
	startServer(port)

	// Start the session
	resultchan := make(chan *server.SessionResult)
	qr, _, err := irmaServer.StartSession(request, func(r *server.SessionResult) {
		resultchan <- r
	})
	if err != nil {
		return nil, errors.WrapPrefix(err, "IRMA session failed", 0)
	}

	// Print QR code
	if err := printQr(qr, noqr); err != nil {
		return nil, errors.WrapPrefix(err, "Failed to print QR", 0)
	}

	// Wait for session to finish and then return session result
	return <-resultchan, nil
}

func serverRequest(
	request irma.RequestorRequest,
	serverurl, authmethod, key, name string,
	noqr bool,
) (*server.SessionResult, error) {
	logger.Debug("Server URL: ", serverurl)

	// Start session at server
	qr, transport, err := postRequest(serverurl, request, name, authmethod, key)
	if err != nil {
		return nil, err
	}

	// Print session QR
	logger.Debug("QR: ", prettyprint(qr))
	if err := printQr(qr, noqr); err != nil {
		return nil, errors.WrapPrefix(err, "Failed to print QR", 0)
	}

	statuschan := make(chan server.Status)

	// Wait until client connects
	go poll(server.StatusInitialized, transport, statuschan)
	status := <-statuschan
	if status != server.StatusConnected {
		return nil, errors.Errorf("Unexpected status: %s", status)
	}

	// Wait until client finishes
	go poll(server.StatusConnected, transport, statuschan)
	status = <-statuschan
	if status != server.StatusDone {
		return nil, errors.Errorf("Unexpected status: %s", status)
	}

	// Retrieve session result
	result := &server.SessionResult{}
	if err := transport.Get("result", result); err != nil {
		return nil, errors.WrapPrefix(err, "Failed to get session result", 0)
	}
	return result, nil
}

func postRequest(serverurl string, request irma.RequestorRequest, name, authmethod, key string) (*irma.Qr, *irma.HTTPTransport, error) {
	var (
		err       error
		pkg       = &server.SessionPackage{}
		transport = irma.NewHTTPTransport(serverurl)
	)

	switch authmethod {
	case "none":
		err = transport.Post("session", pkg, request)
	case "token":
		transport.SetHeader("Authorization", key)
		err = transport.Post("session", pkg, request)
	case "hmac", "rsa":
		var jwtstr string
		jwtstr, err = signRequest(request, name, authmethod, key)
		if err != nil {
			return nil, nil, err
		}
		logger.Debug("Session request JWT: ", jwtstr)
		err = transport.Post("session", pkg, jwtstr)
	default:
		return nil, nil, errors.New("Invalid authentication method (must be none, token, hmac or rsa)")
	}

	token := pkg.Token
	transport.Server += fmt.Sprintf("session/%s/", token)
	return pkg.SessionPtr, transport, err
}

// Configuration functions

func configureServer(url string, port int, privatekeysPath string, irmaconfig *irma.Configuration, verbosity int) error {
	// Replace "port" in url with actual port
	replace := "$1:" + strconv.Itoa(port)
	url = string(regexp.MustCompile("(https?://[^/]*):port").ReplaceAll([]byte(url), []byte(replace)))

	config := &server.Configuration{
		IrmaConfiguration:    irmaconfig,
		Logger:               logger,
		URL:                  url,
		DisableSchemesUpdate: true,
		Verbose:              verbosity,
	}
	if privatekeysPath != "" {
		config.IssuerPrivateKeysPath = privatekeysPath
	}

	var err error
	irmaServer, err = irmaserver.New(config)
	return err
}

func configure(cmd *cobra.Command) (irma.RequestorRequest, *irma.Configuration, error) {
	verbosity, _ := cmd.Flags().GetCount("verbose")
	logger = logrus.New()
	logger.Level = server.Verbosity(verbosity)
	logger.Formatter = &prefixed.TextFormatter{FullTimestamp: true}
	irma.Logger = logger

	return configureRequest(cmd)
}

func init() {
	RootCmd.AddCommand(sessionCmd)

	var err error
	defaulturl, err = server.LocalIP()
	if err != nil {
		logger.Warn("Could not determine local IP address: ", err.Error())
	} else {
		defaulturl = "http://" + defaulturl + ":port/session"
	}

	flags := sessionCmd.Flags()
	flags.SortFlags = false
	flags.String("server", "", "External IRMA server to post request to (leave blank to use builtin library)")
	flags.StringP("url", "u", defaulturl, "external URL to which IRMA app connects (when not using --server)")
	flags.IntP("port", "p", 48680, "port to listen at (when not using --server)")
	flags.Bool("noqr", false, "Print JSON instead of draw QR")
	flags.StringP("request", "r", "", "JSON session request")
	flags.StringP("privkeys", "k", "", "path to private keys")

	addRequestFlags(flags)

	flags.CountP("verbose", "v", "verbose (repeatable)")
}
<commit_msg>Fix for nil pointer dereference when not having network interfaces<commit_after>package cmd

import (
	"fmt"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
	"net/http"
	"regexp"
	"strconv"
	"time"

	"github.com/go-errors/errors"
	"github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/server/irmaserver"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

const pollInterval = 1000 * time.Millisecond

var (
	httpServer *http.Server
	irmaServer *irmaserver.Server
	logger     *logrus.Logger
	defaulturl string
)

// sessionCmd represents the session command
var sessionCmd = &cobra.Command{
	Use:   "session",
	Short: "Perform an IRMA disclosure, issuance or signature session",
	Long: `Perform an IRMA disclosure, issuance or signature session on the command line

Using either the builtin IRMA server library, or an external IRMA server (specify its URL
with --server), an IRMA session is started; the QR is printed in the terminal; and the session
result is printed when the session completes or fails.

A session request can either be constructed using the --disclose, --issue, and --sign together
with --message flags, or it can be specified as JSON to the --request flag.`,
	Example: `irma session --disclose irma-demo.MijnOverheid.root.BSN
irma session --sign irma-demo.MijnOverheid.root.BSN --message message
irma session --issue irma-demo.MijnOverheid.ageLower=yes,yes,yes,no --disclose irma-demo.MijnOverheid.root.BSN
irma session --request '{"type":"disclosing","content":[{"label":"BSN","attributes":["irma-demo.MijnOverheid.root.BSN"]}]}'
irma session --server http://localhost:8088 --authmethod token --key mytoken --disclose irma-demo.MijnOverheid.root.BSN`,
	Run: func(cmd *cobra.Command, args []string) {
		request, irmaconfig, err := configure(cmd)
		if err != nil {
			die("", err)
		}

		// Make sure we always run with latest configuration
		irmaconfig.UpdateSchemes()

		var result *server.SessionResult
		url, _ := cmd.Flags().GetString("url")
		serverurl, _ := cmd.Flags().GetString("server")
		noqr, _ := cmd.Flags().GetBool("noqr")
		flags := cmd.Flags()

		if url != defaulturl && serverurl != "" {
			die("Failed to read configuration", errors.New("--url can't be combined with --server"))
		}

		if serverurl == "" {
			port, _ := flags.GetInt("port")
			privatekeysPath, _ := flags.GetString("privkeys")
			verbosity, _ := cmd.Flags().GetCount("verbose")
			result, err = libraryRequest(request, irmaconfig, url, port, privatekeysPath, noqr, verbosity)
		} else {
			authmethod, _ := flags.GetString("authmethod")
			key, _ := flags.GetString("key")
			name, _ := flags.GetString("name")
			result, err = serverRequest(request, serverurl, authmethod, key, name, noqr)
		}
		if err != nil {
			die("Session failed", err)
		}

		printSessionResult(result)

		// Done!
		if httpServer != nil {
			_ = httpServer.Close()
		}
	},
}

func libraryRequest(
	request irma.RequestorRequest,
	irmaconfig *irma.Configuration,
	url string,
	port int,
	privatekeysPath string,
	noqr bool,
	verbosity int,
) (*server.SessionResult, error) {
	if err := configureServer(url, port, privatekeysPath, irmaconfig, verbosity); err != nil {
		return nil, err
	}
	startServer(port)

	// Start the session
	resultchan := make(chan *server.SessionResult)
	qr, _, err := irmaServer.StartSession(request, func(r *server.SessionResult) {
		resultchan <- r
	})
	if err != nil {
		return nil, errors.WrapPrefix(err, "IRMA session failed", 0)
	}

	// Print QR code
	if err := printQr(qr, noqr); err != nil {
		return nil, errors.WrapPrefix(err, "Failed to print QR", 0)
	}

	// Wait for session to finish and then return session result
	return <-resultchan, nil
}

func serverRequest(
	request irma.RequestorRequest,
	serverurl, authmethod, key, name string,
	noqr bool,
) (*server.SessionResult, error) {
	logger.Debug("Server URL: ", serverurl)

	// Start session at server
	qr, transport, err := postRequest(serverurl, request, name, authmethod, key)
	if err != nil {
		return nil, err
	}

	// Print session QR
	logger.Debug("QR: ", prettyprint(qr))
	if err := printQr(qr, noqr); err != nil {
		return nil, errors.WrapPrefix(err, "Failed to print QR", 0)
	}

	statuschan := make(chan server.Status)

	// Wait until client connects
	go poll(server.StatusInitialized, transport, statuschan)
	status := <-statuschan
	if status != server.StatusConnected {
		return nil, errors.Errorf("Unexpected status: %s", status)
	}

	// Wait until client finishes
	go poll(server.StatusConnected, transport, statuschan)
	status = <-statuschan
	if status != server.StatusDone {
		return nil, errors.Errorf("Unexpected status: %s", status)
	}

	// Retrieve session result
	result := &server.SessionResult{}
	if err := transport.Get("result", result); err != nil {
		return nil, errors.WrapPrefix(err, "Failed to get session result", 0)
	}
	return result, nil
}

func postRequest(serverurl string, request irma.RequestorRequest, name, authmethod, key string) (*irma.Qr, *irma.HTTPTransport, error) {
	var (
		err       error
		pkg       = &server.SessionPackage{}
		transport = irma.NewHTTPTransport(serverurl)
	)

	switch authmethod {
	case "none":
		err = transport.Post("session", pkg, request)
	case "token":
		transport.SetHeader("Authorization", key)
		err = transport.Post("session", pkg, request)
	case "hmac", "rsa":
		var jwtstr string
		jwtstr, err = signRequest(request, name, authmethod, key)
		if err != nil {
			return nil, nil, err
		}
		logger.Debug("Session request JWT: ", jwtstr)
		err = transport.Post("session", pkg, jwtstr)
	default:
		return nil, nil, errors.New("Invalid authentication method (must be none, token, hmac or rsa)")
	}

	token := pkg.Token
	transport.Server += fmt.Sprintf("session/%s/", token)
	return pkg.SessionPtr, transport, err
}

// Configuration functions

func configureServer(url string, port int, privatekeysPath string, irmaconfig *irma.Configuration, verbosity int) error {
	// Replace "port" in url with actual port
	replace := "$1:" + strconv.Itoa(port)
	url = string(regexp.MustCompile("(https?://[^/]*):port").ReplaceAll([]byte(url), []byte(replace)))

	config := &server.Configuration{
		IrmaConfiguration:    irmaconfig,
		Logger:               logger,
		URL:                  url,
		DisableSchemesUpdate: true,
		Verbose:              verbosity,
	}
	if privatekeysPath != "" {
		config.IssuerPrivateKeysPath = privatekeysPath
	}

	var err error
	irmaServer, err = irmaserver.New(config)
	return err
}

func configure(cmd *cobra.Command) (irma.RequestorRequest, *irma.Configuration, error) {
	verbosity, _ := cmd.Flags().GetCount("verbose")
	logger.Level = server.Verbosity(verbosity)
	irma.Logger = logger

	return configureRequest(cmd)
}

func init() {
	RootCmd.AddCommand(sessionCmd)

	logger = logrus.New()
	logger.Formatter = &prefixed.TextFormatter{FullTimestamp: true}

	var err error
	defaulturl, err = server.LocalIP()
	if err != nil {
		logger.Warn("Could not determine local IP address: ", err.Error())
	} else {
		defaulturl = "http://" + defaulturl + ":port/session"
	}

	flags := sessionCmd.Flags()
	flags.SortFlags = false
	flags.String("server", "", "External IRMA server to post request to (leave blank to use builtin library)")
	flags.StringP("url", "u", defaulturl, "external URL to which IRMA app connects (when not using --server)")
	flags.IntP("port", "p", 48680, "port to listen at (when not using --server)")
	flags.Bool("noqr", false, "Print JSON instead of draw QR")
	flags.StringP("request", "r", "", "JSON session request")
	flags.StringP("privkeys", "k", "", "path to private keys")

	addRequestFlags(flags)

	flags.CountP("verbose", "v", "verbose (repeatable)")
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package gowsdl

var opsTmpl = `
{{range .}}
	{{$privateType := .Name | makePrivate}}
	{{$exportType := .Name | makePublic}}

	type {{$exportType}} interface {
		{{range .Operations}}
			{{$faults := len .Faults}}
			{{$soapAction := findSOAPAction .Name $privateType}}
			{{$requestType := findType .Input.Message | replaceReservedWords | makePublic}}
			{{$responseType := findType .Output.Message | replaceReservedWords | makePublic}}

			{{/*if ne $soapAction ""*/}}
			{{if gt $faults 0}}
			// Error can be either of the following types:
			// {{range .Faults}}
			//   - {{.Name}} {{.Doc}}{{end}}{{end}}
			{{if ne .Doc ""}}/* {{.Doc}} */{{end}}
			{{makePublic .Name | replaceReservedWords}} ({{if ne $requestType ""}}request *{{$requestType}}{{end}}) (*{{$responseType}}, error)
			{{/*end*/}}
		{{end}}
	}

	type {{$privateType}} struct {
		client *soap.Client
	}

	func New{{$exportType}}(client *soap.Client) {{$exportType}} {
		return &{{$privateType}}{
			client: client,
		}
	}

	{{range .Operations}}
		{{$requestType := findType .Input.Message | replaceReservedWords | makePublic}}
		{{$soapAction := findSOAPAction .Name $privateType}}
		{{$responseType := findType .Output.Message | replaceReservedWords | makePublic}}
		func (service *{{$privateType}}) {{makePublic .Name | replaceReservedWords}} ({{if ne $requestType ""}}request *{{$requestType}}{{end}}) (*{{$responseType}}, error) {
			response := new({{$responseType}})
			err := service.client.Call("{{$soapAction}}", {{if ne $requestType ""}}request{{else}}nil{{end}}, response)
			if err != nil {
				return nil, err
			}

			return response, nil
		}
	{{end}}
{{end}}
`
<commit_msg>Fix the code generation of methods with empty responses.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package gowsdl

var opsTmpl = `
{{range .}}
	{{$privateType := .Name | makePrivate}}
	{{$exportType := .Name | makePublic}}

	type {{$exportType}} interface {
		{{range .Operations}}
			{{$faults := len .Faults}}
			{{$soapAction := findSOAPAction .Name $privateType}}
			{{$requestType := findType .Input.Message | replaceReservedWords | makePublic}}
			{{$responseType := findType .Output.Message | replaceReservedWords | makePublic}}

			{{/*if ne $soapAction ""*/}}
			{{if gt $faults 0}}
			// Error can be either of the following types:
			// {{range .Faults}}
			//   - {{.Name}} {{.Doc}}{{end}}{{end}}
			{{if ne .Doc ""}}/* {{.Doc}} */{{end}}
			{{makePublic .Name | replaceReservedWords}} ({{if ne $requestType ""}}request *{{$requestType}}{{end}}) ({{if ne $responseType ""}}*{{$responseType}}, {{end}}error)
			{{/*end*/}}
		{{end}}
	}

	type {{$privateType}} struct {
		client *soap.Client
	}

	func New{{$exportType}}(client *soap.Client) {{$exportType}} {
		return &{{$privateType}}{
			client: client,
		}
	}

	{{range .Operations}}
		{{$requestType := findType .Input.Message | replaceReservedWords | makePublic}}
		{{$soapAction := findSOAPAction .Name $privateType}}
		{{$responseType := findType .Output.Message | replaceReservedWords | makePublic}}
		func (service *{{$privateType}}) {{makePublic .Name | replaceReservedWords}} ({{if ne $requestType ""}}request *{{$requestType}}{{end}}) ({{if ne $responseType ""}}*{{$responseType}}, {{end}}error) {
			{{if ne $responseType ""}}response := new({{$responseType}}){{end}}
			err := service.client.Call("{{$soapAction}}", {{if ne $requestType ""}}request{{else}}nil{{end}}, {{if ne $responseType ""}}response{{else}}struct{}{}{{end}})
			if err != nil {
				return {{if ne $responseType ""}}nil, {{end}}err
			}

			return {{if ne $responseType ""}}response, {{end}}nil
		}
	{{end}}
{{end}}
`
<|endoftext|>


<commit_before>package main

import (
	"net"
	"fmt"
  "os/signal"
)

func broadcast(connections map[net.Conn]bool, msg string) {
  for conn, _ := range(connections) {
    go func() {
      fmt.Fprint(conn, msg)
    }()
  }
}

func main() {
  newConnections := make(chan *net.TCPConn)
  connections := make(map[net.Conn]bool)

	tcp, tcperr := net.ListenTCP("tcp", &net.TCPAddr{})
	if tcperr != nil {
		fmt.Println("Error opening TCP socket:", tcperr)
		return
	}
	defer tcp.Close()
	fmt.Println("Listening on", tcp.Addr().Network(), tcp.Addr())

	go func() {
	  for {
  		conn, connerr := tcp.AcceptTCP()
  		if connerr != nil {
  			fmt.Println("Error accepting TCP connection:", connerr)
  		} else {
        newConnections <- conn
  		}
	  }
	}() //go func accepting connections

	for {
	  select {
	    case signal := <-signal.Incoming:
			  fmt.Println("got signal:", signal)
			  broadcast(connections, "Goodbye.\n")
			  return
	    case conn := <- newConnections:
	      connections[conn] = true
  	    fmt.Fprint(conn, "Hello.\n")
	  }
	}
}
<commit_msg>different tcp server 4: send using channels<commit_after>package main

import (
	"net"
	"fmt"
  "os/signal"
)

func makeSenderChan(conn net.Conn) chan<- string {
  ch := make(chan string)
  go func() {
    //close channel when returning
    defer close(ch)
    //close conn when returning
    defer conn.Close()

    for {
      s, ok := <-ch
      if !ok {
        return
      }
      _, err := fmt.Fprint(conn, s)
      if err != nil {
        return
      }
    }
  }()
  return ch
}

func broadcast(connections map[chan<- string]bool, msg string) {
  for conn, _ := range(connections) {
    conn <- msg
  }
}

func main() {
  newConnections := make(chan *net.TCPConn)
  connections := make(map[chan<- string]bool)

	tcp, tcperr := net.ListenTCP("tcp", &net.TCPAddr{})
	if tcperr != nil {
		fmt.Println("Error opening TCP socket:", tcperr)
		return
	}
	defer tcp.Close()
	fmt.Println("Listening on", tcp.Addr().Network(), tcp.Addr())

	go func() {
	  for {
  		conn, connerr := tcp.AcceptTCP()
  		if connerr != nil {
  			fmt.Println("Error accepting TCP connection:", connerr)
  		} else {
        newConnections <- conn
  		}
	  }
	}() //go func accepting connections

	for {
	  select {
	    case signal := <-signal.Incoming:
			  fmt.Println("got signal:", signal)
			  broadcast(connections, "Goodbye.\n")
			  return
	    case conn := <- newConnections:
  	    fmt.Fprint(conn, "Hello.\n")
	      connections[makeSenderChan(conn)] = true
	  }
	}
}
<|endoftext|>