<commit_before>package cheshire

import (
	"fmt"
	"github.com/hoisie/mustache"
	"log"
	"net/http"
)

type HtmlWriter struct {
	*HttpWriter
}

func (this *HtmlWriter) Type() string {
	return "html"
}

// Renders with a layout template.
//
// Layout should have {{content}} variable
func RenderInLayout(txn *Txn, path, layoutPath string, context map[string]interface{}) {
	viewsPath := txn.ServerConfig.MustString("http.html.view_directory", "")
	layPath := fmt.Sprintf("%s%s", viewsPath, layoutPath)
	templatePath := fmt.Sprintf("%s%s", viewsPath, path)
	writeResponse(txn, "text/html", mustache.RenderFileInLayout(templatePath, layPath, contxt(txn, context)))
}

func Render(txn *Txn, path string, context map[string]interface{}) {
	viewsPath := txn.ServerConfig.MustString("http.html.view_directory", "")
	templatePath := fmt.Sprintf("%s%s", viewsPath, path)
	writeResponse(txn, "text/html", mustache.RenderFile(templatePath, contxt(txn, context)))
}

//Adds the special variables to the context.
func contxt(txn *Txn, context map[string]interface{}) map[string]interface{} {
	context["request"] = txn.Request
	context["params"] = txn.Request.Params().Map
	return context
}

func writeResponse(txn *Txn, contentType string, value interface{}) {
	writer, err := toHttpWriter(txn)
	if err != nil {
		SendError(txn, 400, fmt.Sprintf("Error: %s", err))
	}
	writer.Writer.Header().Set("Content-Type", contentType)
	writer.Writer.WriteHeader(200)
	writeContent(writer, value)
}

func toHttpWriter(txn *Txn) (*HttpWriter, error) {
	writer, ok := txn.Writer.(*HttpWriter)
	if !ok {
		wr, ok := txn.Writer.(*HtmlWriter)
		if !ok {
			return writer, fmt.Errorf("Could not convert to httpwriter %s", txn.Writer)
		}
		writer = wr.HttpWriter
	}
	return writer, nil
}

//Issues a redirect (301) to the url
func Redirect(txn *Txn, url string) {
	writer, err := toHttpWriter(txn)
	if err != nil {
		SendError(txn, 400, fmt.Sprintf("Error: %s", err))
	}
	writer.Writer.Header().Set("Location", url)
	writer.Writer.WriteHeader(301)
	writeContent(writer, "<title>Moved</title>
Moved

This page has moved to %s.
")
}

//write out an object
//this assumes the header has been written already
func writeContent(writer *HttpWriter, value interface{}) {
	switch v := value.(type) {
	case string:
		writer.Writer.Write([]byte(v))
	case []byte:
		writer.Writer.Write(v)
	default:
		log.Println("Dont know how to write :", value)
		//TODO: response object, dynmap, map ect.
	}
}

type HtmlController struct {
	Handlers map[string]func(*Txn)
	Conf     *ControllerConfig
}

func NewHtmlController(route string, methods []string, handler func(*Txn)) *HtmlController {
	controller := &HtmlController{
		Handlers: make(map[string]func(*Txn)),
		Conf:     NewControllerConfig(route),
	}

	for _, m := range methods {
		controller.Handlers[m] = handler
	}
	return controller
}

func (this *HtmlController) Config() *ControllerConfig {
	return this.Conf
}

// We hijack the request so we can use the html writer instead of the regular http writer.
// mostly this is so the filters know this is of type="html"
func (this *HtmlController) HttpHijack(writer http.ResponseWriter, req *http.Request, serverConfig *ServerConfig) {
	request := ToStrestRequest(req)
	conn := &HtmlWriter{
		&HttpWriter{
			Writer:       writer,
			HttpRequest:  req,
			Request:      request,
			ServerConfig: serverConfig,
		},
	}
	HandleRequest(request, conn, this, serverConfig)
}

func (this *HtmlController) HandleRequest(txn *Txn) {
	handler := this.Handlers[txn.Request.Method()]
	if handler == nil {
		handler = this.Handlers["ALL"]
	}
	if handler == nil {
		log.Println("Error, not found ", txn.Request.Uri())
		//not found!
		SendError(txn, 404, "Not found")
		return
	}
	if txn.Type() != "html" {
		SendError(txn, 400, "not an html connection")
		return
	}
	handler(txn)
}

// Allows us to use the fast static file handler built into golang standard lib
// Note that this skips the cheshire lifecycle so no middleware filters will be
// executed.
type StaticFileController struct {
	Route   string
	Path    string
	Conf    *ControllerConfig
	Handler http.Handler
}

// initial the handler via http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp")))
func NewStaticFileController(route string, path string) *StaticFileController {
	handler := http.StripPrefix(route, http.FileServer(http.Dir(path)))
	def := &StaticFileController{Handler: handler, Path: path, Route: route, Conf: NewControllerConfig(route)}
	return def
}

func (this *StaticFileController) Config() *ControllerConfig {
	return this.Conf
}

func (this StaticFileController) HandleRequest(txn *Txn) {
	//Empty method, this is never called because we have the HttpHijack method in place
}

func (this StaticFileController) HttpHijack(writer http.ResponseWriter, req *http.Request, serverConfig *ServerConfig) {
	this.Handler.ServeHTTP(writer, req)
}
<commit_msg>add html filter interface<commit_after>package cheshire

import (
	"fmt"
	"github.com/hoisie/mustache"
	"log"
	"net/http"
)

type HtmlWriter struct {
	*HttpWriter
}

func (this *HtmlWriter) Type() string {
	return "html"
}

//Special filter for html lifecycle
type HtmlFilter interface {
	ControllerFilter
	BeforeHtmlWrite(txn *Txn, writer http.ResponseWriter) bool
}

// Renders with a layout template.
//
// Layout should have {{content}} variable
func RenderInLayout(txn *Txn, path, layoutPath string, context map[string]interface{}) {
	viewsPath := txn.ServerConfig.MustString("http.html.view_directory", "")
	layPath := fmt.Sprintf("%s%s", viewsPath, layoutPath)
	templatePath := fmt.Sprintf("%s%s", viewsPath, path)
	writeResponse(txn, "text/html", mustache.RenderFileInLayout(templatePath, layPath, contxt(txn, context)))
}

func Render(txn *Txn, path string, context map[string]interface{}) {
	viewsPath := txn.ServerConfig.MustString("http.html.view_directory", "")
	templatePath := fmt.Sprintf("%s%s", viewsPath, path)
	writeResponse(txn, "text/html", mustache.RenderFile(templatePath, contxt(txn, context)))
}

//Adds the special variables to the context.
func contxt(txn *Txn, context map[string]interface{}) map[string]interface{} {
	context["request"] = txn.Request
	context["params"] = txn.Request.Params().Map
	return context
}

func writeResponse(txn *Txn, contentType string, value interface{}) {
	writer, err := ToHttpWriter(txn)
	if err != nil {
		SendError(txn, 400, fmt.Sprintf("Error: %s", err))
	}
	if !beforeWrite(txn, writer) {
		return
	}
	writer.Writer.Header().Set("Content-Type", contentType)
	writer.Writer.WriteHeader(200)
	writeContent(writer, value)
}

// call the html hooks.
// Always remember to call this!
func beforeWrite(txn *Txn, writer *HttpWriter) bool {
	//Call the filters.
	for _, filter := range txn.Filters {
		f, ok := filter.(HtmlFilter)
		if ok {
			if !f.BeforeHtmlWrite(txn, writer.Writer) {
				return false
			}
		}
	}
	return true
}

func ToHttpWriter(txn *Txn) (*HttpWriter, error) {
	writer, ok := txn.Writer.(*HttpWriter)
	if !ok {
		wr, ok := txn.Writer.(*HtmlWriter)
		if !ok {
			return writer, fmt.Errorf("Could not convert to httpwriter %s", txn.Writer)
		}
		writer = wr.HttpWriter
	}
	return writer, nil
}

//Issues a redirect (301) to the url
func Redirect(txn *Txn, url string) {
	writer, err := ToHttpWriter(txn)
	if err != nil {
		SendError(txn, 400, fmt.Sprintf("Error: %s", err))
	}
	if !beforeWrite(txn, writer) {
		return
	}
	writer.Writer.Header().Set("Location", url)
	writer.Writer.WriteHeader(301)
	writeContent(writer, "<title>Moved</title>
Moved

This page has moved to %s.
")
}

//write out an object
//this assumes the header has been written already
func writeContent(writer *HttpWriter, value interface{}) {
	switch v := value.(type) {
	case string:
		writer.Writer.Write([]byte(v))
	case []byte:
		writer.Writer.Write(v)
	default:
		log.Println("Dont know how to write :", value)
		//TODO: response object, dynmap, map ect.
	}
}

type HtmlController struct {
	Handlers map[string]func(*Txn)
	Conf     *ControllerConfig
}

func NewHtmlController(route string, methods []string, handler func(*Txn)) *HtmlController {
	controller := &HtmlController{
		Handlers: make(map[string]func(*Txn)),
		Conf:     NewControllerConfig(route),
	}

	for _, m := range methods {
		controller.Handlers[m] = handler
	}
	return controller
}

func (this *HtmlController) Config() *ControllerConfig {
	return this.Conf
}

// We hijack the request so we can use the html writer instead of the regular http writer.
// mostly this is so the filters know this is of type="html"
func (this *HtmlController) HttpHijack(writer http.ResponseWriter, req *http.Request, serverConfig *ServerConfig) {
	request := ToStrestRequest(req)
	conn := &HtmlWriter{
		&HttpWriter{
			Writer:       writer,
			HttpRequest:  req,
			Request:      request,
			ServerConfig: serverConfig,
		},
	}
	HandleRequest(request, conn, this, serverConfig)
}

func (this *HtmlController) HandleRequest(txn *Txn) {
	handler := this.Handlers[txn.Request.Method()]
	if handler == nil {
		handler = this.Handlers["ALL"]
	}
	if handler == nil {
		log.Println("Error, not found ", txn.Request.Uri())
		//not found!
		SendError(txn, 404, "Not found")
		return
	}
	if txn.Type() != "html" {
		SendError(txn, 400, "not an html connection")
		return
	}
	handler(txn)
}

// Allows us to use the fast static file handler built into golang standard lib
// Note that this skips the cheshire lifecycle so no middleware filters will be
// executed.
type StaticFileController struct {
	Route   string
	Path    string
	Conf    *ControllerConfig
	Handler http.Handler
}

// initial the handler via http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp")))
func NewStaticFileController(route string, path string) *StaticFileController {
	handler := http.StripPrefix(route, http.FileServer(http.Dir(path)))
	def := &StaticFileController{Handler: handler, Path: path, Route: route, Conf: NewControllerConfig(route)}
	return def
}

func (this *StaticFileController) Config() *ControllerConfig {
	return this.Conf
}

func (this StaticFileController) HandleRequest(txn *Txn) {
	//Empty method, this is never called because we have the HttpHijack method in place
}

func (this StaticFileController) HttpHijack(writer http.ResponseWriter, req *http.Request, serverConfig *ServerConfig) {
	this.Handler.ServeHTTP(writer, req)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"time"

	"encoding/json"
	"net/url"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/cenkalti/backoff"
)

func connectToManager(nivis_ami_uri string) (net.Conn, error) {
	u, err := url.Parse(nivis_ami_uri)
	if err != nil {
		return nil, err
	}
	password, _ := u.User.Password()
	user := u.User.Username()
	hostPort := fmt.Sprintf("%s:%d", u.Host, 5038)

	c, err := net.Dial("tcp", hostPort)
	if err != nil {
		return c, err
	}
	fmt.Fprintf(c, "Action: login\r\n")
	fmt.Fprintf(c, "Username: %s\r\n", user)
	fmt.Fprintf(c, "Secret: %s\r\n", password)
	fmt.Fprintf(c, "\r\n")

	return c, err
}

type Event struct {
	Timestamp int64
	Data      map[string]string
}

func receiveEvents(nivis_ami_uri string, events chan (Event)) error {
	c, err := connectToManager(nivis_ami_uri)
	if err != nil {
		return err
	}
	defer c.Close()

	connbuf := bufio.NewReader(c)
	data := make(map[string]string)
	for {
		str, err := connbuf.ReadString('\n')
		str = strings.TrimSpace(str)
		if len(str) > 0 {
			r := strings.SplitN(str, ":", 2)
			if len(r) == 2 {
				data[r[0]] = r[1]
			}
		} else {
			events <- Event{time.Now().Unix(), data}
			data = make(map[string]string)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func defaultBrokerUri() string {
	brokerUri := os.Getenv("BROKER_URI")

	if len(brokerUri) == 0 {
		brokerUri = "amqp://guest:guest@localhost/"
	}

	return brokerUri
}

func main() {
	var amiURI, amqpURI, exchange, topic string

	flag.StringVar(&amiURI, "amiuri", "ami://user:pass@host", "AMI uri")
	flag.StringVar(&amqpURI, "amqpuri", defaultBrokerUri(), "AMQP connection uri")
	flag.StringVar(&exchange, "exchange", "events", "AMQP exchange name")
	flag.StringVar(&topic, "topic", "astevents", "topic")
	flag.Parse()

	events := make(chan (Event), 1)
	go func() {
		operation := func() error {
			return receiveEvents(amiURI, events)
		}

		err := backoff.Retry(operation, backoff.NewExponentialBackOff())
		if err != nil {
			log.Panic("Error", err)
			return
		}
	}()

	amqpPublisher := simpleamqp.NewAmqpPublisher(amqpURI, exchange)
	for e := range events {
		jsonSerialized, _ := json.Marshal(e)
		fmt.Println("Event", string(jsonSerialized))
		amqpPublisher.Publish(topic, []byte(jsonSerialized))
	}

	fmt.Println("E4")

}
<commit_msg>Log communication problems<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"time"

	"encoding/json"
	"net/url"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/cenkalti/backoff"
)

func connectToManager(nivis_ami_uri string) (net.Conn, error) {
	u, err := url.Parse(nivis_ami_uri)
	if err != nil {
		return nil, err
	}
	password, _ := u.User.Password()
	user := u.User.Username()
	hostPort := fmt.Sprintf("%s:%d", u.Host, 5038)

	c, err := net.Dial("tcp", hostPort)
	if err != nil {
		return c, err
	}
	fmt.Fprintf(c, "Action: login\r\n")
	fmt.Fprintf(c, "Username: %s\r\n", user)
	fmt.Fprintf(c, "Secret: %s\r\n", password)
	fmt.Fprintf(c, "\r\n")

	return c, err
}

type Event struct {
	Timestamp int64
	Data      map[string]string
}

func receiveEvents(nivis_ami_uri string, events chan (Event)) error {
	c, err := connectToManager(nivis_ami_uri)
	if err != nil {
		log.Println("Error", err)
		return err
	}

	defer c.Close()

	connbuf := bufio.NewReader(c)
	data := make(map[string]string)
	for {
		str, err := connbuf.ReadString('\n')
		str = strings.TrimSpace(str)
		if len(str) > 0 {
			r := strings.SplitN(str, ":", 2)
			if len(r) == 2 {
				data[r[0]] = r[1]
			}
		} else {
			events <- Event{time.Now().Unix(), data}
			data = make(map[string]string)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func defaultBrokerUri() string {
	brokerUri := os.Getenv("BROKER_URI")

	if len(brokerUri) == 0 {
		brokerUri = "amqp://guest:guest@localhost/"
	}

	return brokerUri
}

func main() {
	var amiURI, amqpURI, exchange, topic string

	flag.StringVar(&amiURI, "amiuri", "ami://user:pass@host", "AMI uri")
	flag.StringVar(&amqpURI, "amqpuri", defaultBrokerUri(), "AMQP connection uri")
	flag.StringVar(&exchange, "exchange", "events", "AMQP exchange name")
	flag.StringVar(&topic, "topic", "astevents", "topic")
	flag.Parse()

	events := make(chan (Event), 1)
	go func() {
		operation := func() error {
			return receiveEvents(amiURI, events)
		}

		err := backoff.Retry(operation, backoff.NewExponentialBackOff())
		if err != nil {
			log.Panic("Error", err)
			return
		}
	}()

	amqpPublisher := simpleamqp.NewAmqpPublisher(amqpURI, exchange)
	for e := range events {
		jsonSerialized, _ := json.Marshal(e)
		fmt.Println("Event", string(jsonSerialized))
		amqpPublisher.Publish(topic, []byte(jsonSerialized))
	}

	fmt.Println("E4")

}
<|endoftext|>


<commit_before>package kubedeploy

import (
	"fmt"
	"log"
	"os"
	"time"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/errors"
	"k8s.io/client-go/pkg/api/v1"
	metav1 "k8s.io/client-go/pkg/apis/meta/v1"
	"k8s.io/client-go/pkg/util/intstr"
	"k8s.io/client-go/tools/clientcmd"

	"strings"

	"github.com/checkr/codeflow/server/agent"
	"github.com/checkr/codeflow/server/plugins"
	"github.com/spf13/viper"
)

func (x *KubeDeploy) sendLBResponse(e agent.Event, service plugins.Service, state plugins.State, failureMessage string, dnsName string) {
	payload := e.Payload.(plugins.LoadBalancer)
	payload.Action = plugins.Status
	payload.Service = service
	payload.StateMessage = failureMessage
	payload.DNSName = dnsName
	payload.State = state
	event := e.NewEvent(payload, nil)
	x.events <- event
}

func (x *KubeDeploy) doDeleteLoadBalancer(e agent.Event) error {
	// Codeflow will load the kube config from a file, specified by KUBECONFIG environment variable
	kubeconfig := os.Getenv("KUBECONFIG")
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)

	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Println("Error getting cluster config.")
	}

	payload := e.Payload.(plugins.LoadBalancer)
	coreInterface := clientset.Core()

	namespace := genNamespaceName(payload.Environment, payload.Project.Slug)

	_, svcGetErr := coreInterface.Services(namespace).Get(payload.Name, metav1.GetOptions{})
	if svcGetErr == nil {
		// Service was found, ready to delete
		svcDeleteErr := coreInterface.Services(namespace).Delete(payload.Name, &v1.DeleteOptions{})
		if svcDeleteErr != nil {
			failMessage := fmt.Sprintf("Error '%s' deleting service %s", svcDeleteErr, payload.Name)
			log.Printf("ERROR managing loadbalancer %s: %s", payload.Service.Name, failMessage)
			x.sendLBResponse(e, payload.Service, plugins.Failed, failMessage, "")
			return nil
		}
		x.sendLBResponse(e, payload.Service, plugins.Deleted, "", "")
	} else {
		// Send failure message that we couldn't find the service to delete
		failMessage := fmt.Sprintf("Error finding %s service: '%s'", payload.Name, svcGetErr)
		log.Printf("ERROR managing loadbalancer %s: %s", payload.Service.Name, failMessage)
		x.sendLBResponse(e, payload.Service, plugins.Failed, failMessage, "")
	}
	return nil
}

// Make changes to kubernetes services (aka load balancers)
func (x *KubeDeploy) doLoadBalancer(e agent.Event) error {
	// Codeflow will load the kube config from a file, specified by KUBECONFIG environment variable
	kubeconfig := os.Getenv("KUBECONFIG")
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)

	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Println("Error getting cluster config.")
	}

	payload := e.Payload.(plugins.LoadBalancer)
	coreInterface := clientset.Core()
	deploymentName := genDeploymentName(payload.Project.Slug, payload.Service.Name)

	var serviceType v1.ServiceType
	var servicePorts []v1.ServicePort
	serviceAnnotations := make(map[string]string)

	namespace := genNamespaceName(payload.Environment, payload.Project.Slug)
	createNamespaceErr := x.createNamespaceIfNotExists(namespace, coreInterface)
	if createNamespaceErr != nil {
		x.sendLBResponse(e, payload.Service, plugins.Failed, createNamespaceErr.Error(), "")
		return nil
	}

	// Begin create
	switch payload.Type {
	case plugins.Internal:
		serviceType = v1.ServiceTypeClusterIP
	case plugins.External:
		serviceType = v1.ServiceTypeLoadBalancer
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled"] = "true"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout"] = "300"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled"] = "true"
		if viper.IsSet("plugins.kubedeploy.access_log_s3_bucket") {
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-enabled"] = "true"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name"] = viper.GetString("plugins.kubedeploy.access_log_s3_bucket")
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix"] = fmt.Sprintf("%s/%s", payload.Project.Slug, payload.Service.Name)
		}
	case plugins.Office:
		serviceType = v1.ServiceTypeLoadBalancer
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-internal"] = "0.0.0.0/0"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled"] = "true"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout"] = "300"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled"] = "true"
		if viper.IsSet("plugins.kubedeploy.access_log_s3_bucket") {
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-enabled"] = "true"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name"] = viper.GetString("plugins.kubedeploy.access_log_s3_bucket")
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix"] = fmt.Sprintf("%s/%s", payload.Project.Slug, payload.Service.Name)
		}
	}
	var sslPorts []string
	for _, p := range payload.ListenerPairs {
		var realProto string
		switch p.Destination.Protocol {
		case "HTTPS":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "http"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"] = "*"
			realProto = "TCP"
		case "SSL":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "tcp"
			realProto = "TCP"
		case "HTTP":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "http"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"] = "*"
			realProto = "TCP"
		case "TCP":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "tcp"
			realProto = "TCP"
		case "UDP":
			realProto = "UDP"
		}
		convPort := intstr.IntOrString{
			IntVal: p.Destination.Port,
		}
		newPort := v1.ServicePort{
			Name:       fmt.Sprintf("%d-%s", p.Source.Port, strings.ToLower(realProto)),
			Port:       p.Source.Port,
			TargetPort: convPort,
			Protocol:   v1.Protocol(realProto),
		}
		if p.Destination.Protocol == "HTTPS" || p.Destination.Protocol == "SSL" {
			sslPorts = append(sslPorts, fmt.Sprintf("%d", p.Source.Port))
		}
		servicePorts = append(servicePorts, newPort)
	}
	if len(sslPorts) > 0 {
		sslPortsCombined := strings.Join(sslPorts, ",")
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-ssl-ports"] = sslPortsCombined
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-ssl-cert"] = viper.GetString("plugins.kubedeploy.ssl_cert_arn")
	}
	serviceSpec := v1.ServiceSpec{
		Selector: map[string]string{"app": deploymentName},
		Type:     serviceType,
		Ports:    servicePorts,
	}
	serviceParams := v1.Service{
		TypeMeta: metav1.TypeMeta{
			Kind:       "service",
			APIVersion: "v1",
		},
		ObjectMeta: v1.ObjectMeta{
			Name:        payload.Name,
			Annotations: serviceAnnotations,
		},
		Spec: serviceSpec,
	}

	// Implement service update-or-create semantics.
	service := coreInterface.Services(namespace)
	svc, err := service.Get(payload.Name, metav1.GetOptions{})
	switch {
	case err == nil:
		serviceParams.ObjectMeta.ResourceVersion = svc.ObjectMeta.ResourceVersion
		serviceParams.Spec.ClusterIP = svc.Spec.ClusterIP
		_, err = service.Update(&serviceParams)
		if err != nil {
			x.sendLBResponse(e, payload.Service, plugins.Failed, fmt.Sprintf("Error: failed to update service: %s", err.Error()), "")
			return nil
		}
		log.Printf("Service updated: %s", payload.Name)
	case errors.IsNotFound(err):
		_, err = service.Create(&serviceParams)
		if err != nil {
			x.sendLBResponse(e, payload.Service, plugins.Failed, fmt.Sprintf("Error: failed to create service: %s", err.Error()), "")
			return nil
		}
		log.Printf("Service created: %s", payload.Name)
	default:
		x.sendLBResponse(e, payload.Service, plugins.Failed, fmt.Sprintf("Unexpected error: %s", err.Error()), "")
		return nil
	}

	// If ELB grab the DNS name for the response
	var ELBDNSName string
	if payload.Type == plugins.External || payload.Type == plugins.Office {
		log.Printf("Waiting for ELB address for %s", payload.Name)
		// Timeout waiting for ELB DNS name after 600 seconds
		timeout := 600
		for {
			elbResult, elbErr := coreInterface.Services(namespace).Get(payload.Name, metav1.GetOptions{})
			if elbErr != nil {
				log.Printf("Error '%s' describing service %s", elbErr, payload.Name)
			} else {
				ingressList := elbResult.Status.LoadBalancer.Ingress
				if len(ingressList) > 0 {
					ELBDNSName = ingressList[0].Hostname
					break
				}
				if timeout <= 0 {
					failMessage := fmt.Sprintf("Error: timeout waiting for ELB DNS name for: %s", payload.Name)
					x.sendLBResponse(e, payload.Service, plugins.Failed, failMessage, "")
					return nil
				}
			}
			time.Sleep(time.Second * 5)
			timeout -= 5
		}
	} else {
		ELBDNSName = fmt.Sprintf("%s.%s", payload.Name, genNamespaceName(payload.Environment, payload.Project.Slug))
	}
	x.sendLBResponse(e, payload.Service, plugins.Complete, "", ELBDNSName)

	return nil
}
<commit_msg>setting emit interval for access logs<commit_after>package kubedeploy

import (
	"fmt"
	"log"
	"os"
	"time"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/errors"
	"k8s.io/client-go/pkg/api/v1"
	metav1 "k8s.io/client-go/pkg/apis/meta/v1"
	"k8s.io/client-go/pkg/util/intstr"
	"k8s.io/client-go/tools/clientcmd"

	"strings"

	"github.com/checkr/codeflow/server/agent"
	"github.com/checkr/codeflow/server/plugins"
	"github.com/spf13/viper"
)

func (x *KubeDeploy) sendLBResponse(e agent.Event, service plugins.Service, state plugins.State, failureMessage string, dnsName string) {
	payload := e.Payload.(plugins.LoadBalancer)
	payload.Action = plugins.Status
	payload.Service = service
	payload.StateMessage = failureMessage
	payload.DNSName = dnsName
	payload.State = state
	event := e.NewEvent(payload, nil)
	x.events <- event
}

func (x *KubeDeploy) doDeleteLoadBalancer(e agent.Event) error {
	// Codeflow will load the kube config from a file, specified by KUBECONFIG environment variable
	kubeconfig := os.Getenv("KUBECONFIG")
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)

	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Println("Error getting cluster config.")
	}

	payload := e.Payload.(plugins.LoadBalancer)
	coreInterface := clientset.Core()

	namespace := genNamespaceName(payload.Environment, payload.Project.Slug)

	_, svcGetErr := coreInterface.Services(namespace).Get(payload.Name, metav1.GetOptions{})
	if svcGetErr == nil {
		// Service was found, ready to delete
		svcDeleteErr := coreInterface.Services(namespace).Delete(payload.Name, &v1.DeleteOptions{})
		if svcDeleteErr != nil {
			failMessage := fmt.Sprintf("Error '%s' deleting service %s", svcDeleteErr, payload.Name)
			log.Printf("ERROR managing loadbalancer %s: %s", payload.Service.Name, failMessage)
			x.sendLBResponse(e, payload.Service, plugins.Failed, failMessage, "")
			return nil
		}
		x.sendLBResponse(e, payload.Service, plugins.Deleted, "", "")
	} else {
		// Send failure message that we couldn't find the service to delete
		failMessage := fmt.Sprintf("Error finding %s service: '%s'", payload.Name, svcGetErr)
		log.Printf("ERROR managing loadbalancer %s: %s", payload.Service.Name, failMessage)
		x.sendLBResponse(e, payload.Service, plugins.Failed, failMessage, "")
	}
	return nil
}

// Make changes to kubernetes services (aka load balancers)
func (x *KubeDeploy) doLoadBalancer(e agent.Event) error {
	// Codeflow will load the kube config from a file, specified by KUBECONFIG environment variable
	kubeconfig := os.Getenv("KUBECONFIG")
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)

	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Println("Error getting cluster config.")
	}

	payload := e.Payload.(plugins.LoadBalancer)
	coreInterface := clientset.Core()
	deploymentName := genDeploymentName(payload.Project.Slug, payload.Service.Name)

	var serviceType v1.ServiceType
	var servicePorts []v1.ServicePort
	serviceAnnotations := make(map[string]string)

	namespace := genNamespaceName(payload.Environment, payload.Project.Slug)
	createNamespaceErr := x.createNamespaceIfNotExists(namespace, coreInterface)
	if createNamespaceErr != nil {
		x.sendLBResponse(e, payload.Service, plugins.Failed, createNamespaceErr.Error(), "")
		return nil
	}

	// Begin create
	switch payload.Type {
	case plugins.Internal:
		serviceType = v1.ServiceTypeClusterIP
	case plugins.External:
		serviceType = v1.ServiceTypeLoadBalancer
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled"] = "true"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout"] = "300"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled"] = "true"
		if viper.IsSet("plugins.kubedeploy.access_log_s3_bucket") {
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval"] = "5"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-enabled"] = "true"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name"] = viper.GetString("plugins.kubedeploy.access_log_s3_bucket")
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix"] = fmt.Sprintf("%s/%s", payload.Project.Slug, payload.Service.Name)
		}
	case plugins.Office:
		serviceType = v1.ServiceTypeLoadBalancer
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-internal"] = "0.0.0.0/0"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled"] = "true"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout"] = "300"
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled"] = "true"
		if viper.IsSet("plugins.kubedeploy.access_log_s3_bucket") {
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval"] = "5"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-enabled"] = "true"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name"] = viper.GetString("plugins.kubedeploy.access_log_s3_bucket")
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix"] = fmt.Sprintf("%s/%s", payload.Project.Slug, payload.Service.Name)
		}
	}
	var sslPorts []string
	for _, p := range payload.ListenerPairs {
		var realProto string
		switch p.Destination.Protocol {
		case "HTTPS":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "http"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"] = "*"
			realProto = "TCP"
		case "SSL":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "tcp"
			realProto = "TCP"
		case "HTTP":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "http"
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"] = "*"
			realProto = "TCP"
		case "TCP":
			serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] = "tcp"
			realProto = "TCP"
		case "UDP":
			realProto = "UDP"
		}
		convPort := intstr.IntOrString{
			IntVal: p.Destination.Port,
		}
		newPort := v1.ServicePort{
			Name:       fmt.Sprintf("%d-%s", p.Source.Port, strings.ToLower(realProto)),
			Port:       p.Source.Port,
			TargetPort: convPort,
			Protocol:   v1.Protocol(realProto),
		}
		if p.Destination.Protocol == "HTTPS" || p.Destination.Protocol == "SSL" {
			sslPorts = append(sslPorts, fmt.Sprintf("%d", p.Source.Port))
		}
		servicePorts = append(servicePorts, newPort)
	}
	if len(sslPorts) > 0 {
		sslPortsCombined := strings.Join(sslPorts, ",")
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-ssl-ports"] = sslPortsCombined
		serviceAnnotations["service.beta.kubernetes.io/aws-load-balancer-ssl-cert"] = viper.GetString("plugins.kubedeploy.ssl_cert_arn")
	}
	serviceSpec := v1.ServiceSpec{
		Selector: map[string]string{"app": deploymentName},
		Type:     serviceType,
		Ports:    servicePorts,
	}
	serviceParams := v1.Service{
		TypeMeta: metav1.TypeMeta{
			Kind:       "service",
			APIVersion: "v1",
		},
		ObjectMeta: v1.ObjectMeta{
			Name:        payload.Name,
			Annotations: serviceAnnotations,
		},
		Spec: serviceSpec,
	}

	// Implement service update-or-create semantics.
	service := coreInterface.Services(namespace)
	svc, err := service.Get(payload.Name, metav1.GetOptions{})
	switch {
	case err == nil:
		serviceParams.ObjectMeta.ResourceVersion = svc.ObjectMeta.ResourceVersion
		serviceParams.Spec.ClusterIP = svc.Spec.ClusterIP
		_, err = service.Update(&serviceParams)
		if err != nil {
			x.sendLBResponse(e, payload.Service, plugins.Failed, fmt.Sprintf("Error: failed to update service: %s", err.Error()), "")
			return nil
		}
		log.Printf("Service updated: %s", payload.Name)
	case errors.IsNotFound(err):
		_, err = service.Create(&serviceParams)
		if err != nil {
			x.sendLBResponse(e, payload.Service, plugins.Failed, fmt.Sprintf("Error: failed to create service: %s", err.Error()), "")
			return nil
		}
		log.Printf("Service created: %s", payload.Name)
	default:
		x.sendLBResponse(e, payload.Service, plugins.Failed, fmt.Sprintf("Unexpected error: %s", err.Error()), "")
		return nil
	}

	// If ELB grab the DNS name for the response
	var ELBDNSName string
	if payload.Type == plugins.External || payload.Type == plugins.Office {
		log.Printf("Waiting for ELB address for %s", payload.Name)
		// Timeout waiting for ELB DNS name after 600 seconds
		timeout := 600
		for {
			elbResult, elbErr := coreInterface.Services(namespace).Get(payload.Name, metav1.GetOptions{})
			if elbErr != nil {
				log.Printf("Error '%s' describing service %s", elbErr, payload.Name)
			} else {
				ingressList := elbResult.Status.LoadBalancer.Ingress
				if len(ingressList) > 0 {
					ELBDNSName = ingressList[0].Hostname
					break
				}
				if timeout <= 0 {
					failMessage := fmt.Sprintf("Error: timeout waiting for ELB DNS name for: %s", payload.Name)
					x.sendLBResponse(e, payload.Service, plugins.Failed, failMessage, "")
					return nil
				}
			}
			time.Sleep(time.Second * 5)
			timeout -= 5
		}
	} else {
		ELBDNSName = fmt.Sprintf("%s.%s", payload.Name, genNamespaceName(payload.Environment, payload.Project.Slug))
	}
	x.sendLBResponse(e, payload.Service, plugins.Complete, "", ELBDNSName)

	return nil
}
<|endoftext|>


<commit_before>package chunk

import (
	"errors"
	"fmt"
	"os"
	"sync"
	// . "github.com/claudetech/loggo/default"
)

// ErrTimeout is a timeout error
var ErrTimeout = errors.New("timeout")

// Storage is a chunk storage
type Storage struct {
	ChunkPath string
	ChunkSize int64
	MaxChunks int
	// queue      chan *Item
	chunks map[string][]byte
	lock   sync.RWMutex
	// toc        map[string]error
	// tocLock    sync.RWMutex
	// stack *Stack
}

// Item represents a chunk in RAM
type Item struct {
	id    string
	bytes []byte
}

// NewStorage creates a new storage
func NewStorage(chunkPath string, chunkSize int64, maxChunks int) *Storage {
	storage := Storage{
		ChunkPath: chunkPath,
		ChunkSize: chunkSize,
		MaxChunks: maxChunks,
		// queue:     make(chan *Item, 100),
		chunks: make(map[string][]byte),
		// toc:    make(map[string]error),
		// stack: NewStack(),
	}

	// go storage.thread()

	return &storage
}

// Clear removes all old chunks on disk (will be called on each program start)
func (s *Storage) Clear() error {
	if err := os.RemoveAll(s.ChunkPath); nil != err {
		return fmt.Errorf("Could not clear old chunks from disk")
	}
	return nil
}

// LoadOrCreate loads a chunk from ram or creates it
func (s *Storage) LoadOrCreate(id string) ([]byte, bool) {
	s.lock.Lock()
	if chunk, exists := s.chunks[id]; exists {
		s.lock.Unlock()
		return chunk, true
	}
	s.chunks[id] = nil
	s.lock.Unlock()
	return nil, false
}

// Store stores a chunk in the RAM and adds it to the disk storage queue
func (s *Storage) Store(id string, bytes []byte) error {
	s.lock.Lock()
	s.chunks[id] = bytes
	s.lock.Unlock()

	return nil
}

// Error is called to remove an item from the index if there has been an issue downloading the chunk
func (s *Storage) Error(id string) {
	s.lock.Lock()
	delete(s.chunks, id)
	s.lock.Unlock()
}

// func (s *Storage) thread() {
// 	for {
// 		item := <-s.queue
// 		if err := s.storeToDisk(item.id, item.bytes); nil != err {
// 			Log.Warningf("%v", err)
// 		}
// 	}
// }

// func (s *Storage) deleteFromToc(id string) {
// 	s.tocLock.Lock()
// 	delete(s.toc, id)
// 	s.tocLock.Unlock()
// }

// func (s *Storage) loadFromRAM(id string, offset, size int64) ([]byte, bool) {
// 	s.chunksLock.RLock()
// 	bytes, exists := s.chunks[id]
// 	s.chunksLock.RUnlock()
// 	if !exists {
// 		return nil, false
// 	}

// 	sOffset := int64(math.Min(float64(len(bytes)), float64(offset)))
// 	eOffset := int64(math.Min(float64(len(bytes)), float64(offset+size)))
// 	return bytes[sOffset:eOffset], true
// }

// func (s *Storage) loadFromDisk(id string, offset, size int64) ([]byte, bool) {
// 	filename := filepath.Join(s.ChunkPath, id)

// 	f, err := os.Open(filename)
// 	if nil != err {
// 		Log.Tracef("%v", err)
// 		return nil, false
// 	}
// 	defer f.Close()

// 	buf := make([]byte, size)
// 	n, err := f.ReadAt(buf, offset)
// 	if n > 0 && (nil == err || io.EOF == err || io.ErrUnexpectedEOF == err) {
// 		s.stack.Touch(id)

// 		eOffset := int64(math.Min(float64(size), float64(n)))
// 		return buf[:eOffset], true
// 	}

// 	Log.Tracef("%v", err)
// 	return nil, false
// }

// func (s *Storage) storeToDisk(id string, bytes []byte) error {
// 	filename := filepath.Join(s.ChunkPath, id)

// 	if s.stack.Len() >= s.MaxChunks {
// 		deleteID := s.stack.Pop()

// 		if "" != deleteID {
// 			filename := filepath.Join(s.ChunkPath, deleteID)

// 			Log.Debugf("Deleting chunk %v", filename)
// 			if err := os.Remove(filename); nil != err {
// 				Log.Debugf("%v", err)
// 				Log.Warningf("Could not delete chunk %v", filename)
// 			}

// 			s.tocLock.Lock()
// 			delete(s.toc, deleteID)
// 			s.tocLock.Unlock()
// 		}
// 	}

// 	if _, err := os.Stat(s.ChunkPath); os.IsNotExist(err) {
// 		if err := os.MkdirAll(s.ChunkPath, 0777); nil != err {
// 			Log.Debugf("%v", err)
// 			return fmt.Errorf("Could not create chunk temp path %v", s.ChunkPath)
// 		}
// 	}

// 	if _, err := os.Stat(filename); os.IsNotExist(err) {
// 		if err := ioutil.WriteFile(filename, bytes, 0777); nil != err {
// 			Log.Debugf("%v", err)
// 			return fmt.Errorf("Could not write chunk temp file %v", filename)
// 		}

// 		s.stack.Push(id)
// 	}

// 	s.chunksLock.Lock()
// 	delete(s.chunks, id)
// 	s.chunksLock.Unlock()

// 	return nil
// }
<commit_msg>added chunk removal<commit_after>package chunk

import (
	"errors"
	"fmt"
	"os"
	"sync"

	. "github.com/claudetech/loggo/default"
)

// ErrTimeout is a timeout error
var ErrTimeout = errors.New("timeout")

// Storage is a chunk storage
type Storage struct {
	ChunkPath string
	ChunkSize int64
	MaxChunks int
	chunks    map[string][]byte
	stack     []string
	lock      sync.RWMutex
}

// Item represents a chunk in RAM
type Item struct {
	id    string
	bytes []byte
}

// NewStorage creates a new storage
func NewStorage(chunkPath string, chunkSize int64, maxChunks int) *Storage {
	storage := Storage{
		ChunkPath: chunkPath,
		ChunkSize: chunkSize,
		MaxChunks: maxChunks,
		chunks:    make(map[string][]byte),
		stack:     make([]string, maxChunks),
	}

	return &storage
}

// Clear removes all old chunks on disk (will be called on each program start)
func (s *Storage) Clear() error {
	if err := os.RemoveAll(s.ChunkPath); nil != err {
		return fmt.Errorf("Could not clear old chunks from disk")
	}
	return nil
}

// LoadOrCreate loads a chunk from ram or creates it
func (s *Storage) LoadOrCreate(id string) ([]byte, bool) {
	s.lock.Lock()
	if chunk, exists := s.chunks[id]; exists {
		s.lock.Unlock()
		return chunk, true
	}
	s.chunks[id] = nil
	s.lock.Unlock()
	return nil, false
}

// Store stores a chunk in the RAM and adds it to the disk storage queue
func (s *Storage) Store(id string, bytes []byte) error {
	s.lock.Lock()
	s.stack = append(s.stack, id)
	if len(s.stack) > s.MaxChunks {
		deleteID := s.stack[0]
		if "" != deleteID {
			s.stack = s.stack[1:]
			Log.Debugf("Deleting chunk %v", deleteID)
			delete(s.chunks, deleteID)
		}
	}
	s.chunks[id] = bytes
	s.lock.Unlock()

	return nil
}

// Error is called to remove an item from the index if there has been an issue downloading the chunk
func (s *Storage) Error(id string) {
	s.lock.Lock()
	delete(s.chunks, id)
	s.lock.Unlock()
}
<|endoftext|>


<commit_before>package chyle

import (
	"srcd.works/go-git.v4/plumbing/object"
)

// process represents all configuration operations defined
// needed to create a changelog
type process struct {
	matchers   *[]matcher
	extractors *[]extracter
	decorators *map[string][]decorater
	senders    *[]sender
}

// buildProcess creates process entity from defined configuration
func buildProcess() *process {
	matchers := &[]matcher{}
	extractors := &[]extracter{}
	decorators := &map[string][]decorater{}
	senders := &[]sender{}

	if chyleConfig.FEATURES.HASMATCHERS {
		matchers = createMatchers()
	}

	if chyleConfig.FEATURES.HASEXTRACTORS {
		extractors = createExtractors()
	}

	if chyleConfig.FEATURES.HASDECORATORS {
		decorators = createDecorators()
	}

	if chyleConfig.FEATURES.HASSENDERS {
		senders = createSenders()
	}

	return &process{
		matchers,
		extractors,
		decorators,
		senders,
	}
}

// proceed extracts datas from a set of commits
func proceed(process *process, commits *[]object.Commit) error {
	changelog, err := extract(process.extractors, transformCommitsToMap(filter(process.matchers, commits)))

	if err != nil {

		return err
	}

	changelog, err = decorate(process.decorators, changelog)

	if err != nil {
		return err
	}

	return Send(process.senders, changelog)
}
<commit_msg>style(chyle/process) : remove extra newline<commit_after>package chyle

import (
	"srcd.works/go-git.v4/plumbing/object"
)

// process represents all configuration operations defined
// needed to create a changelog
type process struct {
	matchers   *[]matcher
	extractors *[]extracter
	decorators *map[string][]decorater
	senders    *[]sender
}

// buildProcess creates process entity from defined configuration
func buildProcess() *process {
	matchers := &[]matcher{}
	extractors := &[]extracter{}
	decorators := &map[string][]decorater{}
	senders := &[]sender{}

	if chyleConfig.FEATURES.HASMATCHERS {
		matchers = createMatchers()
	}

	if chyleConfig.FEATURES.HASEXTRACTORS {
		extractors = createExtractors()
	}

	if chyleConfig.FEATURES.HASDECORATORS {
		decorators = createDecorators()
	}

	if chyleConfig.FEATURES.HASSENDERS {
		senders = createSenders()
	}

	return &process{
		matchers,
		extractors,
		decorators,
		senders,
	}
}

// proceed extracts datas from a set of commits
func proceed(process *process, commits *[]object.Commit) error {
	changelog, err := extract(process.extractors, transformCommitsToMap(filter(process.matchers, commits)))

	if err != nil {
		return err
	}

	changelog, err = decorate(process.decorators, changelog)

	if err != nil {
		return err
	}

	return Send(process.senders, changelog)
}
<|endoftext|>


<commit_before>/*
 Copyright 2021 The GoPlus Authors (goplus.org)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package cl

import (
	"go/constant"
	"go/types"
	"path/filepath"
	"strings"

	goast "go/ast"

	"github.com/goplus/gop/ast"
	"github.com/goplus/gop/parser"
	"github.com/goplus/gop/token"
	"github.com/goplus/gox"
)

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

type gmxInfo struct {
	extSpx   string
	pkgPaths []string
}

var (
	gmxTypes = map[string]gmxInfo{
		".gmx": {".spx", []string{"github.com/goplus/spx", "math"}},
		".spc": {"", []string{"github.com/qbox/spc", "github.com/goplus/spx", "math"}},
		// TODO: dynamic register
	}
)

// RegisterClassFileType registers Go+ class file types.
func RegisterClassFileType(extGmx, extSpx string, pkgPaths ...string) {
	if pkgPaths == nil {
		panic("RegisterClassFileType: no pkgPath specified")
	}
	parser.RegisterFileType(extGmx, ast.FileTypeGmx)
	if extSpx != "" {
		parser.RegisterFileType(extSpx, ast.FileTypeSpx)
	}
	if _, ok := gmxTypes[extGmx]; !ok {
		gmxTypes[extGmx] = gmxInfo{extSpx, pkgPaths}
	}
}

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

type gmxSettings struct {
	gameClass  string
	extSpx     string
	game       gox.Ref
	sprite     gox.Ref
	scheds     []string
	schedStmts []goast.Stmt // nil or len(scheds) == 2 (delayload)
	pkgImps    []*gox.PkgRef
	pkgPaths   []string
	hasScheds  bool
	gameIsPtr  bool
}

func (p *gmxSettings) getScheds(cb *gox.CodeBuilder) []goast.Stmt {
	if !p.hasScheds {
		return nil
	}
	if p.schedStmts == nil {
		p.schedStmts = make([]goast.Stmt, 2)
		for i, v := range p.scheds {
			fn := cb.Val(spxLookup(p.pkgImps, v)).Call(0).InternalStack().Pop().Val
			p.schedStmts[i] = &goast.ExprStmt{X: fn}
		}
		if len(p.scheds) < 2 {
			p.schedStmts[1] = p.schedStmts[0]
		}
	}
	return p.schedStmts
}

func newGmx(pkg *gox.Package, file string) *gmxSettings {
	_, name := filepath.Split(file)
	ext := filepath.Ext(name)
	if idx := strings.Index(name, "."); idx > 0 {
		name = name[:idx]
		if name == "main" {
			name = "_main"
		}
	}
	gt := gmxTypes[ext]
	pkgPaths := gt.pkgPaths
	p := &gmxSettings{extSpx: gt.extSpx, gameClass: name, pkgPaths: pkgPaths}
	p.pkgImps = make([]*gox.PkgRef, len(pkgPaths))
	for i, pkgPath := range pkgPaths {
		p.pkgImps[i] = pkg.Import(pkgPath)
	}
	spx := p.pkgImps[0]
	p.game, p.gameIsPtr = spxRef(spx, "Gop_game", "Game")
	if gt.extSpx != "" {
		p.sprite, _ = spxRef(spx, "Gop_sprite", "Sprite")
	}
	if x := getStringConst(spx, "Gop_sched"); x != "" {
		p.scheds, p.hasScheds = strings.SplitN(x, ",", 2), true
	}
	return p
}

func spxLookup(pkgImps []*gox.PkgRef, name string) gox.Ref {
	for _, pkg := range pkgImps {
		if o := pkg.TryRef(name); o != nil {
			return o
		}
	}
	panic("spxLookup: symbol not found - " + name)
}

func getDefaultClass(file string) string {
	_, name := filepath.Split(file)
	if idx := strings.Index(name, "."); idx > 0 {
		name = name[:idx]
	}
	return name
}

func spxRef(spx *gox.PkgRef, name, typ string) (obj gox.Ref, isPtr bool) {
	if v := getStringConst(spx, name); v != "" {
		typ = v
		if strings.HasPrefix(typ, "*") {
			typ, isPtr = typ[1:], true
		}
	}
	obj = spx.Ref(typ)
	return
}

func getStringConst(spx *gox.PkgRef, name string) string {
	if o := spx.TryRef(name); o != nil {
		if c, ok := o.(*types.Const); ok {
			return constant.StringVal(c.Val())
		}
	}
	return ""
}

func getFields(ctx *blockCtx, f *ast.File) (specs []ast.Spec) {
	decls := f.Decls
	i, n := 0, len(decls)
	for i < n {
		g, ok := decls[i].(*ast.GenDecl)
		if !ok {
			break
		}
		if g.Tok != token.IMPORT && g.Tok != token.CONST {
			if g.Tok == token.VAR {
				specs, g.Specs = g.Specs, nil
			}
			break
		}
		i++ // skip import, if any
	}
	return
}

func setBodyHandler(ctx *blockCtx) {
	if ctx.fileType > 0 { // in a Go+ class file
		if scheds := ctx.getScheds(ctx.cb); scheds != nil {
			ctx.cb.SetBodyHandler(func(body *goast.BlockStmt, kind int) {
				idx := 0
				if len(body.List) == 0 {
					idx = 1
				}
				gox.InsertStmtFront(body, scheds[idx])
			})
		}
	}
}

func gmxMainFunc(p *gox.Package, ctx *pkgCtx) {
	if o := p.Types.Scope().Lookup(ctx.gameClass); o != nil && hasMethod(o, "MainEntry") {
		// new(Game).Main()
		p.NewFunc(nil, "main", nil, nil, false).BodyStart(p).
			Val(p.Builtin().Ref("new")).Val(o).Call(1).
			MemberVal("Main").Call(0).EndStmt().
			End()
	}
}

// -----------------------------------------------------------------------------
<commit_msg>github.com/qbox/spc => github.com/qbox/gopla/spc<commit_after>/*
 Copyright 2021 The GoPlus Authors (goplus.org)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package cl

import (
	"go/constant"
	"go/types"
	"path/filepath"
	"strings"

	goast "go/ast"

	"github.com/goplus/gop/ast"
	"github.com/goplus/gop/parser"
	"github.com/goplus/gop/token"
	"github.com/goplus/gox"
)

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

type gmxInfo struct {
	extSpx   string
	pkgPaths []string
}

var (
	gmxTypes = map[string]gmxInfo{
		".gmx": {".spx", []string{"github.com/goplus/spx", "math"}},
		".spc": {"", []string{"github.com/qbox/gopla/spc", "github.com/goplus/spx", "math"}},
		// TODO: dynamic register
	}
)

// RegisterClassFileType registers Go+ class file types.
func RegisterClassFileType(extGmx, extSpx string, pkgPaths ...string) {
	if pkgPaths == nil {
		panic("RegisterClassFileType: no pkgPath specified")
	}
	parser.RegisterFileType(extGmx, ast.FileTypeGmx)
	if extSpx != "" {
		parser.RegisterFileType(extSpx, ast.FileTypeSpx)
	}
	if _, ok := gmxTypes[extGmx]; !ok {
		gmxTypes[extGmx] = gmxInfo{extSpx, pkgPaths}
	}
}

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

type gmxSettings struct {
	gameClass  string
	extSpx     string
	game       gox.Ref
	sprite     gox.Ref
	scheds     []string
	schedStmts []goast.Stmt // nil or len(scheds) == 2 (delayload)
	pkgImps    []*gox.PkgRef
	pkgPaths   []string
	hasScheds  bool
	gameIsPtr  bool
}

func (p *gmxSettings) getScheds(cb *gox.CodeBuilder) []goast.Stmt {
	if !p.hasScheds {
		return nil
	}
	if p.schedStmts == nil {
		p.schedStmts = make([]goast.Stmt, 2)
		for i, v := range p.scheds {
			fn := cb.Val(spxLookup(p.pkgImps, v)).Call(0).InternalStack().Pop().Val
			p.schedStmts[i] = &goast.ExprStmt{X: fn}
		}
		if len(p.scheds) < 2 {
			p.schedStmts[1] = p.schedStmts[0]
		}
	}
	return p.schedStmts
}

func newGmx(pkg *gox.Package, file string) *gmxSettings {
	_, name := filepath.Split(file)
	ext := filepath.Ext(name)
	if idx := strings.Index(name, "."); idx > 0 {
		name = name[:idx]
		if name == "main" {
			name = "_main"
		}
	}
	gt := gmxTypes[ext]
	pkgPaths := gt.pkgPaths
	p := &gmxSettings{extSpx: gt.extSpx, gameClass: name, pkgPaths: pkgPaths}
	p.pkgImps = make([]*gox.PkgRef, len(pkgPaths))
	for i, pkgPath := range pkgPaths {
		p.pkgImps[i] = pkg.Import(pkgPath)
	}
	spx := p.pkgImps[0]
	p.game, p.gameIsPtr = spxRef(spx, "Gop_game", "Game")
	if gt.extSpx != "" {
		p.sprite, _ = spxRef(spx, "Gop_sprite", "Sprite")
	}
	if x := getStringConst(spx, "Gop_sched"); x != "" {
		p.scheds, p.hasScheds = strings.SplitN(x, ",", 2), true
	}
	return p
}

func spxLookup(pkgImps []*gox.PkgRef, name string) gox.Ref {
	for _, pkg := range pkgImps {
		if o := pkg.TryRef(name); o != nil {
			return o
		}
	}
	panic("spxLookup: symbol not found - " + name)
}

func getDefaultClass(file string) string {
	_, name := filepath.Split(file)
	if idx := strings.Index(name, "."); idx > 0 {
		name = name[:idx]
	}
	return name
}

func spxRef(spx *gox.PkgRef, name, typ string) (obj gox.Ref, isPtr bool) {
	if v := getStringConst(spx, name); v != "" {
		typ = v
		if strings.HasPrefix(typ, "*") {
			typ, isPtr = typ[1:], true
		}
	}
	obj = spx.Ref(typ)
	return
}

func getStringConst(spx *gox.PkgRef, name string) string {
	if o := spx.TryRef(name); o != nil {
		if c, ok := o.(*types.Const); ok {
			return constant.StringVal(c.Val())
		}
	}
	return ""
}

func getFields(ctx *blockCtx, f *ast.File) (specs []ast.Spec) {
	decls := f.Decls
	i, n := 0, len(decls)
	for i < n {
		g, ok := decls[i].(*ast.GenDecl)
		if !ok {
			break
		}
		if g.Tok != token.IMPORT && g.Tok != token.CONST {
			if g.Tok == token.VAR {
				specs, g.Specs = g.Specs, nil
			}
			break
		}
		i++ // skip import, if any
	}
	return
}

func setBodyHandler(ctx *blockCtx) {
	if ctx.fileType > 0 { // in a Go+ class file
		if scheds := ctx.getScheds(ctx.cb); scheds != nil {
			ctx.cb.SetBodyHandler(func(body *goast.BlockStmt, kind int) {
				idx := 0
				if len(body.List) == 0 {
					idx = 1
				}
				gox.InsertStmtFront(body, scheds[idx])
			})
		}
	}
}

func gmxMainFunc(p *gox.Package, ctx *pkgCtx) {
	if o := p.Types.Scope().Lookup(ctx.gameClass); o != nil && hasMethod(o, "MainEntry") {
		// new(Game).Main()
		p.NewFunc(nil, "main", nil, nil, false).BodyStart(p).
			Val(p.Builtin().Ref("new")).Val(o).Call(1).
			MemberVal("Main").Call(0).EndStmt().
			End()
	}
}

// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>// +build windows

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

package main

import (
	"bytes"
	"os"
	"strings"
	"testing"
)

func TestUNCPaths(t *testing.T) {
	var testCases = []struct {
		objName string
		pass    bool
	}{
		{"/abcdef", true},
		{"/a/b/c/d/e/f/g", true},
		{string(bytes.Repeat([]byte("界"), 85)), true},
		{string(bytes.Repeat([]byte("界"), 100)), false},
		{`\\p\q\r\s\t`, true},
	}
	var err error
	err = os.Mkdir("c:\\testdisk", 0700)
	defer os.RemoveAll("c:\\testdisk")
	var fs StorageAPI
	fs, err = newPosix("c:\\testdisk")
	if err != nil {
		t.Fatal(err)
	}

	err = fs.MakeVol("voldir")
	if err != nil {
		t.Fatal(err)
	}

	for _, test := range testCases {
		err = fs.AppendFile("voldir", test.objName, []byte("hello"))
		if err != nil && test.pass {
			t.Error(err)
		} else if err == nil && !test.pass {
			t.Error(err)
		}

		fs.DeleteFile("voldir", test.objName)
	}
}

func TestUNCPathENOTDIR(t *testing.T) {
	var err error
	err = os.Mkdir("c:\\testdisk", 0700)
	defer os.RemoveAll("c:\\testdisk")
	var fs StorageAPI
	fs, err = newPosix("c:\\testdisk")
	if err != nil {
		t.Fatal(err)
	}

	err = fs.MakeVol("voldir")
	if err != nil {
		t.Fatal(err)
	}

	err = fs.AppendFile("voldir", "/file", []byte("hello"))
	if err != nil {
		t.Fatal(err)
	}

	err = fs.AppendFile("voldir", "/file/obj1", []byte("hello"))
	winErr := "The system cannot find the path specified."
	if !strings.Contains(err.Error(), winErr) {
		t.Errorf("expected to recieve %s, but received %s", winErr, err.Error())
	}
}
<commit_msg>Added tests to validate disk name length near MAX_PATH<commit_after>// +build windows

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

package main

import (
	"bytes"
	"os"
	"strings"
	"testing"
)

// Test if various paths work as expected when converted to UNC form
func TestUNCPaths(t *testing.T) {
	var testCases = []struct {
		objName string
		pass    bool
	}{
		{"/abcdef", true},
		{"/a/b/c/d/e/f/g", true},
		{string(bytes.Repeat([]byte("界"), 85)), true},
		// Each path component must be <= 255 bytes long.
		{string(bytes.Repeat([]byte("界"), 100)), false},
		{`\\p\q\r\s\t`, true},
	}
	// Instantiate posix object to manage a disk
	var err error
	err = os.Mkdir("c:\\testdisk", 0700)

	// Cleanup on exit of test
	defer os.RemoveAll("c:\\testdisk")

	var fs StorageAPI
	fs, err = newPosix("c:\\testdisk")
	if err != nil {
		t.Fatal(err)
	}

	// Create volume to use in conjunction with other StorageAPI's file API(s)
	err = fs.MakeVol("voldir")
	if err != nil {
		t.Fatal(err)
	}

	for _, test := range testCases {
		err = fs.AppendFile("voldir", test.objName, []byte("hello"))
		if err != nil && test.pass {
			t.Error(err)
		} else if err == nil && !test.pass {
			t.Error(err)
		}

		fs.DeleteFile("voldir", test.objName)
	}
}

// Test to validate posix behaviour on windows when a non-final path component is a file.
func TestUNCPathENOTDIR(t *testing.T) {
	var err error
	// Instantiate posix object to manage a disk
	err = os.Mkdir("c:\\testdisk", 0700)

	// Cleanup on exit of test
	defer os.RemoveAll("c:\\testdisk")
	var fs StorageAPI
	fs, err = newPosix("c:\\testdisk")
	if err != nil {
		t.Fatal(err)
	}

	// Create volume to use in conjunction with other StorageAPI's file API(s)
	err = fs.MakeVol("voldir")
	if err != nil {
		t.Fatal(err)
	}

	err = fs.AppendFile("voldir", "/file", []byte("hello"))
	if err != nil {
		t.Fatal(err)
	}

	// Try to create a file that includes a file in its path components.
	// In *nix, this returns syscall.ENOTDIR while in windows we receive the following error.
	err = fs.AppendFile("voldir", "/file/obj1", []byte("hello"))
	winErr := "The system cannot find the path specified."
	if !strings.Contains(err.Error(), winErr) {
		t.Errorf("expected to recieve %s, but received %s", winErr, err.Error())
	}
}

// Test to validate that path name in UNC form works
func TestUNCPathDiskName(t *testing.T) {
	var err error
	// Instantiate posix object to manage a disk
	longPathDisk := `\\?\c:\testdisk`
	err = mkdirAll(longPathDisk, 0700)
	if err != nil {
		t.Fatal(err)
	}
	// Cleanup on exit of test
	defer removeAll(longPathDisk)
	var fs StorageAPI
	fs, err = newPosix(longPathDisk)
	if err != nil {
		t.Fatal(err)
	}

	// Create volume to use in conjunction with other StorageAPI's file API(s)
	err = fs.MakeVol("voldir")
	if err != nil {
		t.Fatal(err)
	}
}

// Test to validate 32k path works on windows platform
func Test32kUNCPath(t *testing.T) {
	var err error
	// Instantiate posix object to manage a disk
	longDiskName := `\\?\c:`
	for {
		compt := strings.Repeat("a", 255)
		if len(compt)+len(longDiskName)+1 > 32767 {
			break
		}
		longDiskName = longDiskName + `\` + compt
	}

	if len(longDiskName) < 32767 {
		// The following calculation was derived empirically. It is not exactly MAX_PATH - len(longDiskName)
		// possibly due to expansion rules as mentioned here -
		// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
		remaining := 32767 - 25 - len(longDiskName)
		longDiskName = longDiskName + `\` + strings.Repeat("a", remaining)
	}
	err = mkdirAll(longDiskName, 0700)
	if err != nil {
		t.Fatal(err)
	}

	// Cleanup on exit of test
	defer removeAll(longDiskName)
	_, err = newPosix(longDiskName)
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package tarball

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/containers/image/v5/transports"
	"github.com/containers/image/v5/types"
)

const (
	transportName = "tarball"
	separator     = ":"
)

var (
	// Transport implements the types.ImageTransport interface for "tarball:" images,
	// which are makeshift images constructed using one or more possibly-compressed tar
	// archives.
	Transport = &tarballTransport{}
)

type tarballTransport struct {
}

func (t *tarballTransport) Name() string {
	return transportName
}

func (t *tarballTransport) ParseReference(reference string) (types.ImageReference, error) {
	var stdin []byte
	var err error
	filenames := strings.Split(reference, separator)
	for _, filename := range filenames {
		if filename == "-" {
			stdin, err = ioutil.ReadAll(os.Stdin)
			if err != nil {
				return nil, fmt.Errorf("error buffering stdin: %v", err)
			}
			continue
		}
		f, err := os.Open(filename)
		if err != nil {
			return nil, fmt.Errorf("error opening %q: %v", filename, err)
		}
		f.Close()
	}
	ref := &tarballReference{
		filenames: filenames,
		stdin:     stdin,
	}
	return ref, nil
}

func (t *tarballTransport) ValidatePolicyConfigurationScope(scope string) error {
	// See the explanation in daemonReference.PolicyConfigurationIdentity.
	return errors.New(`tarball: does not support any scopes except the default "" one`)
}

func init() {
	transports.Register(Transport)
}
<commit_msg>Add tarball.NewReference<commit_after>package tarball

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/containers/image/v5/transports"
	"github.com/containers/image/v5/types"
)

const (
	transportName = "tarball"
	separator     = ":"
)

var (
	// Transport implements the types.ImageTransport interface for "tarball:" images,
	// which are makeshift images constructed using one or more possibly-compressed tar
	// archives.
	Transport = &tarballTransport{}
)

type tarballTransport struct {
}

func (t *tarballTransport) Name() string {
	return transportName
}

func (t *tarballTransport) ParseReference(reference string) (types.ImageReference, error) {
	var stdin []byte
	var err error
	filenames := strings.Split(reference, separator)
	for _, filename := range filenames {
		if filename == "-" {
			stdin, err = ioutil.ReadAll(os.Stdin)
			if err != nil {
				return nil, fmt.Errorf("error buffering stdin: %v", err)
			}
			continue
		}
		f, err := os.Open(filename)
		if err != nil {
			return nil, fmt.Errorf("error opening %q: %v", filename, err)
		}
		f.Close()
	}
	return NewReference(filenames, stdin)
}

// NewReference creates a new "tarball:" reference for the listed fileNames.
// If any of the fileNames is "-", the contents of stdin are used instead.
func NewReference(fileNames []string, stdin []byte) (types.ImageReference, error) {
	for _, path := range fileNames {
		if strings.Contains(path, separator) {
			return nil, fmt.Errorf("Invalid path %q: paths including the separator %q are not supported", path, separator)
		}
	}
	return &tarballReference{
		filenames: fileNames,
		stdin:     stdin,
	}, nil
}

func (t *tarballTransport) ValidatePolicyConfigurationScope(scope string) error {
	// See the explanation in daemonReference.PolicyConfigurationIdentity.
	return errors.New(`tarball: does not support any scopes except the default "" one`)
}

func init() {
	transports.Register(Transport)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"math/rand"
	"time"

	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

func main() {
	p := mpb.New()

	total := 100
	bar := p.Add(int64(total), nil,
		mpb.BarExtender(nlBarFiller(mpb.NewBarFiller("╢▌▌░╟", false))),
		// mpb.BarExtender(nlBarFiller(mpb.NewBarFiller("", false))),
		mpb.PrependDecorators(
			decor.Name("Percentage: "),
			decor.NewPercentage("%d"),
		),
		mpb.AppendDecorators(
			decor.Name("ETA: "),
			decor.OnComplete(
				decor.AverageETA(decor.ET_STYLE_GO), "done",
			),
		),
	)
	// simulating some work
	max := 100 * time.Millisecond
	for i := 0; i < total; i++ {
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
		bar.Increment()
	}
	// wait for our bar to complete and flush
	p.Wait()
}

func nlBarFiller(filler mpb.BarFiller) mpb.BarFiller {
	return mpb.BarFillerFunc(func(w io.Writer, reqWidth int, s decor.Statistics) {
		filler.Fill(w, reqWidth, s)
		w.Write([]byte("\n"))
	})
}
<commit_msg>drop code comment<commit_after>package main

import (
	"io"
	"math/rand"
	"time"

	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

func main() {
	p := mpb.New()

	total := 100
	bar := p.Add(int64(total), nil,
		mpb.BarExtender(nlBarFiller(mpb.NewBarFiller("╢▌▌░╟", false))),
		mpb.PrependDecorators(
			decor.Name("Percentage: "),
			decor.NewPercentage("%d"),
		),
		mpb.AppendDecorators(
			decor.Name("ETA: "),
			decor.OnComplete(
				decor.AverageETA(decor.ET_STYLE_GO), "done",
			),
		),
	)
	// simulating some work
	max := 100 * time.Millisecond
	for i := 0; i < total; i++ {
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
		bar.Increment()
	}
	// wait for our bar to complete and flush
	p.Wait()
}

func nlBarFiller(filler mpb.BarFiller) mpb.BarFiller {
	return mpb.BarFillerFunc(func(w io.Writer, reqWidth int, s decor.Statistics) {
		filler.Fill(w, reqWidth, s)
		w.Write([]byte("\n"))
	})
}
<|endoftext|>


<commit_before>package discharger

import (
	"fmt"
	"time"

	services "v.io/core/veyron/services/security"
	"v.io/core/veyron2/ipc"
	"v.io/core/veyron2/security"
	"v.io/core/veyron2/vdl/vdlutil"
)

// dischargerd issues discharges for all caveats present in the current
// namespace with no additional caveats iff the caveat is valid.
type dischargerd struct{}

// TODO(andreser,ataly): make it easier for third party public key caveats to specify the caveats on their discharges

func (dischargerd) Discharge(ctx ipc.ServerContext, caveatAny vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
	caveat, ok := caveatAny.(security.ThirdPartyCaveat)
	if !ok {
		return nil, fmt.Errorf("type %T does not implement security.ThirdPartyCaveat", caveatAny)
	}
	if err := caveat.Dischargeable(ctx); err != nil {
		return nil, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", caveat, err)
	}
	expiry, err := security.ExpiryCaveat(time.Now().Add(time.Minute))
	if err != nil {
		return nil, fmt.Errorf("unable to create expiration caveat on the discharge: %v", err)
	}
	return ctx.LocalPrincipal().MintDischarge(caveat, expiry)
}

// NewDischarger returns a discharger service implementation that grants discharges using the MintDischarge
// on the principal receiving the RPC.
func NewDischarger() services.DischargerServerMethods {
	return dischargerd{}
}
<commit_msg>veyron/services/security/discharger: Increase validity period of a discharge.<commit_after>package discharger

import (
	"fmt"
	"time"

	services "v.io/core/veyron/services/security"
	"v.io/core/veyron2/ipc"
	"v.io/core/veyron2/security"
	"v.io/core/veyron2/vdl/vdlutil"
)

// dischargerd issues discharges for all caveats present in the current
// namespace with no additional caveats iff the caveat is valid.
type dischargerd struct{}

func (dischargerd) Discharge(ctx ipc.ServerContext, caveatAny vdlutil.Any, _ security.DischargeImpetus) (vdlutil.Any, error) {
	caveat, ok := caveatAny.(security.ThirdPartyCaveat)
	if !ok {
		return nil, fmt.Errorf("type %T does not implement security.ThirdPartyCaveat", caveatAny)
	}
	if err := caveat.Dischargeable(ctx); err != nil {
		return nil, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", caveat, err)
	}
	expiry, err := security.ExpiryCaveat(time.Now().Add(15 * time.Minute))
	if err != nil {
		return nil, fmt.Errorf("unable to create expiration caveat on the discharge: %v", err)
	}
	return ctx.LocalPrincipal().MintDischarge(caveat, expiry)
}

// NewDischarger returns a discharger service implementation that grants
// discharges using the MintDischarge on the principal receiving the RPC.
//
// Discharges are valid for 15 minutes.
// TODO(ashankar,ataly): Parameterize this? Make it easier for clients to add
// caveats on the discharge?
func NewDischarger() services.DischargerServerMethods {
	return dischargerd{}
}
<|endoftext|>


<commit_before>package scans

import (
	"time"
)

// ScanSummary is an Ion Channel representation of the summary produced by an
// individual scan on a project.  It contains all the details the Ion Channel
// platform discovers for that scan.
type ScanSummary struct {
	ID          string             `json:"id" xml:"id"`
	TeamID      string             `json:"team_id" xml:"team_id"`
	ProjectID   string             `json:"project_id" xml:"project_id"`
	AnalysisID  string             `json:"analysis_id" xml:"analysis_id"`
	Summary     string             `json:"summary" xml:"summary"`
	Results     ScanSummaryResults `json:"results"`
	UpdatedAt   time.Time          `json:"updated_at" xml:"updated_at"`
	CreatedAt   time.Time          `json:"created_at" xml:"created_at"`
	Duration    float64            `json:"duration" xml:"duration"`
	Passed      bool               `json:"passed" xml:"passed"`
	Risk        string             `json:"risk" xml:"risk"`
	Name        string             `json:"name" xml:"name"`
	Description string             `json:"description" xml:"description"`
	Type        string             `json:"type" xml:"type"`
}

// ScanSummaryResults is an Ion Channel representation of the results from a scan summary.  It contains what thype of results and the data pertaining to the results.
type ScanSummaryResults struct {
	Type string      `json:"type" xml:"type"`
	Data interface{} `json:"data" xml:"data"`
}
<commit_msg>correcting typo and formatting comment<commit_after>package scans

import (
	"time"
)

// ScanSummary is an Ion Channel representation of the summary produced by an
// individual scan on a project.  It contains all the details the Ion Channel
// platform discovers for that scan.
type ScanSummary struct {
	ID          string             `json:"id" xml:"id"`
	TeamID      string             `json:"team_id" xml:"team_id"`
	ProjectID   string             `json:"project_id" xml:"project_id"`
	AnalysisID  string             `json:"analysis_id" xml:"analysis_id"`
	Summary     string             `json:"summary" xml:"summary"`
	Results     ScanSummaryResults `json:"results"`
	UpdatedAt   time.Time          `json:"updated_at" xml:"updated_at"`
	CreatedAt   time.Time          `json:"created_at" xml:"created_at"`
	Duration    float64            `json:"duration" xml:"duration"`
	Passed      bool               `json:"passed" xml:"passed"`
	Risk        string             `json:"risk" xml:"risk"`
	Name        string             `json:"name" xml:"name"`
	Description string             `json:"description" xml:"description"`
	Type        string             `json:"type" xml:"type"`
}

// ScanSummaryResults is an Ion Channel representation of the results from a
// scan summary.  It contains what type of results and the data pertaining to
// the results.
type ScanSummaryResults struct {
	Type string      `json:"type" xml:"type"`
	Data interface{} `json:"data" xml:"data"`
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| encoding/interface_decoder.go                            |
|                                                          |
| LastModified: Jun 15, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"fmt"
	"math"
	"math/big"
	"reflect"

	"github.com/modern-go/reflect2"
)

func (dec *Decoder) decodeInterface(t reflect.Type, tag byte) interface{} {
	if i := intDigits[tag]; i != invalidDigit {
		return int(i)
	}
	switch tag {
	case TagNull:
		return nil
	case TagEmpty:
		return ""
	case TagFalse:
		return false
	case TagTrue:
		return true
	case TagInteger:
		return dec.ReadInt()
	case TagLong:
		switch dec.LongType {
		case LongTypeInt64:
			return dec.ReadInt64()
		case LongTypeUint64:
			return dec.ReadUint64()
		default:
			return dec.ReadBigInt()
		}
	case TagNaN:
		switch dec.RealType {
		case RealTypeFloat32:
			return float32(math.NaN())
		case RealTypeFloat64:
			return math.NaN()
		default:
			dec.Error = DecodeError("hprose/encoding: can not parse NaN to *big.Float")
		}
	case TagInfinity:
		var f float64
		if dec.NextByte() == TagNeg {
			f = math.Inf(-1)
		} else {
			f = math.Inf(1)
		}
		switch dec.RealType {
		case RealTypeFloat32:
			return float32(f)
		case RealTypeFloat64:
			return f
		default:
			return big.NewFloat(f)
		}
	case TagDouble:
		switch dec.RealType {
		case RealTypeFloat32:
			return dec.ReadFloat32()
		case RealTypeFloat64:
			return dec.ReadFloat64()
		default:
			return dec.ReadBigFloat()
		}
	case TagUTF8Char:
		return dec.readSafeString(1)
	case TagString:
		return dec.ReadString()
	case TagBytes:
		return dec.ReadBytes()
	}
	if dec.Error == nil {
		dec.Error = DecodeError(fmt.Sprintf("hprose/encoding: invalid tag '%s'(0x%x)", string(tag), tag))
	}
	return nil
}

func (dec *Decoder) decodeInterfacePtr(t reflect.Type, tag byte) *interface{} {
	if tag == TagNull {
		return nil
	}
	i := dec.decodeInterface(t, tag)
	return &i
}

// interfaceDecoder is the implementation of ValueDecoder for interface{}.
type interfaceDecoder struct {
	t reflect.Type
}

func (valdec interfaceDecoder) Decode(dec *Decoder, p interface{}, tag byte) {
	*(*interface{})(reflect2.PtrOf(p)) = dec.decodeInterface(valdec.t, tag)
}

func (valdec interfaceDecoder) Type() reflect.Type {
	return valdec.t
}

// interfacePtrDecoder is the implementation of ValueDecoder for *interface{}.
type interfacePtrDecoder struct {
	t reflect.Type
}

func (valdec interfacePtrDecoder) Decode(dec *Decoder, p interface{}, tag byte) {
	*(**interface{})(reflect2.PtrOf(p)) = dec.decodeInterfacePtr(valdec.t, tag)
}

func (valdec interfacePtrDecoder) Type() reflect.Type {
	return valdec.t
}
<commit_msg>Update interface_deocder.go<commit_after>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| encoding/interface_decoder.go                            |
|                                                          |
| LastModified: Jun 21, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"fmt"
	"math"
	"math/big"
	"reflect"

	"github.com/modern-go/reflect2"
)

func (dec *Decoder) decodeInterface(t reflect.Type, tag byte) interface{} {
	if i := intDigits[tag]; i != invalidDigit {
		return int(i)
	}
	switch tag {
	case TagNull:
		return nil
	case TagEmpty:
		return ""
	case TagFalse:
		return false
	case TagTrue:
		return true
	case TagInteger:
		return dec.ReadInt()
	case TagLong:
		switch dec.LongType {
		case LongTypeInt64:
			return dec.ReadInt64()
		case LongTypeUint64:
			return dec.ReadUint64()
		default:
			return dec.ReadBigInt()
		}
	case TagNaN:
		switch dec.RealType {
		case RealTypeFloat32:
			return float32(math.NaN())
		case RealTypeFloat64:
			return math.NaN()
		default:
			dec.Error = DecodeError("hprose/encoding: can not parse NaN to *big.Float")
		}
	case TagInfinity:
		var f float64
		if dec.NextByte() == TagNeg {
			f = math.Inf(-1)
		} else {
			f = math.Inf(1)
		}
		switch dec.RealType {
		case RealTypeFloat32:
			return float32(f)
		case RealTypeFloat64:
			return f
		default:
			return big.NewFloat(f)
		}
	case TagDouble:
		switch dec.RealType {
		case RealTypeFloat32:
			return dec.ReadFloat32()
		case RealTypeFloat64:
			return dec.ReadFloat64()
		default:
			return dec.ReadBigFloat()
		}
	case TagUTF8Char:
		return dec.readSafeString(1)
	case TagString:
		return dec.ReadString()
	case TagBytes:
		return dec.ReadBytes()
	case TagList:
		var result []interface{}
		ifsdec.Decode(dec, &result, tag)
		return result
	case TagMap:
		switch dec.MapType {
		case MapTypeIIMap:
			var result map[interface{}]interface{}
			ififmdec.Decode(dec, &result, tag)
			return result
		default:
			var result map[string]interface{}
			sifmdec.Decode(dec, &result, tag)
			return result
		}
	}
	if dec.Error == nil {
		dec.Error = DecodeError(fmt.Sprintf("hprose/encoding: invalid tag '%s'(0x%x)", string(tag), tag))
	}
	return nil
}

func (dec *Decoder) decodeInterfacePtr(t reflect.Type, tag byte) *interface{} {
	if tag == TagNull {
		return nil
	}
	i := dec.decodeInterface(t, tag)
	return &i
}

// interfaceDecoder is the implementation of ValueDecoder for interface{}.
type interfaceDecoder struct {
	t reflect.Type
}

func (valdec interfaceDecoder) Decode(dec *Decoder, p interface{}, tag byte) {
	*(*interface{})(reflect2.PtrOf(p)) = dec.decodeInterface(valdec.t, tag)
}

func (valdec interfaceDecoder) Type() reflect.Type {
	return valdec.t
}

// interfacePtrDecoder is the implementation of ValueDecoder for *interface{}.
type interfacePtrDecoder struct {
	t reflect.Type
}

func (valdec interfacePtrDecoder) Decode(dec *Decoder, p interface{}, tag byte) {
	*(**interface{})(reflect2.PtrOf(p)) = dec.decodeInterfacePtr(valdec.t, tag)
}

func (valdec interfacePtrDecoder) Type() reflect.Type {
	return valdec.t
}
<|endoftext|>


<commit_before>package hoverfly_test

import (
	"bytes"
	"github.com/dghubble/sling"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"strings"
)

var _ = Describe("Interacting with the API", func() {

	var (
		jsonRequestResponsePair1 *bytes.Buffer
		jsonRequestResponsePair2 *bytes.Buffer
	)

	BeforeEach(func() {
		jsonRequestResponsePair1 = bytes.NewBufferString(`{"data":[{"request": {"path": "/path1", "method": "method1", "destination": "destination1", "scheme": "scheme1", "query": "query1", "body": "body1", "headers": {"Header": ["value1"]}}, "response": {"status": 201, "encodedBody": false, "body": "body1", "headers": {"Header": ["value1"]}}}]}`)
		jsonRequestResponsePair2 = bytes.NewBufferString(`{"data":[{"request": {"path": "/path2", "method": "method2", "destination": "destination2", "scheme": "scheme2", "query": "query2", "body": "body2", "headers": {"Header": ["value2"]}}, "response": {"status": 202, "encodedBody": false, "body": "body2", "headers": {"Header": ["value2"]}}}]}`)

		hoverflyCmd = startHoverfly(adminPort, proxyPort)
	})

	AfterEach(func() {
		stopHoverfly()
	})

	Context("GET /api/v2/hoverfly/destination", func() {

		It("Should get the mode", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/destination")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"destination":"."}`)))
		})
	})

	Context("PUT /api/v2/hoverfly/destination", func() {

		It("Should put the mode", func() {
			req := sling.New().Put(hoverflyAdminUrl + "/api/v2/hoverfly/destination")
			req.Body(strings.NewReader(`{"destination":"test.com"}`))
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"destination":"test.com"}`)))

			req = sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/destination")
			res = DoRequest(req)
			modeJson, err = ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"destination":"test.com"}`)))
		})

	})

	Context("GET /api/v2/hoverfly/mode", func() {

		It("Should get the mode", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/mode")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"mode":"simulate"}`)))
		})
	})

	Context("PUT /api/v2/hoverfly/mode", func() {

		It("Should put the mode", func() {
			req := sling.New().Put(hoverflyAdminUrl + "/api/v2/hoverfly/mode")
			req.Body(strings.NewReader(`{"mode":"capture"}`))
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"mode":"capture"}`)))

			req = sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/mode")
			res = DoRequest(req)
			modeJson, err = ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"mode":"capture"}`)))
		})

	})

	Context("GET /api/v2/hoverfly/middleware", func() {

		It("Should get the middleware which should be blank", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/middleware")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"middleware":""}`)))
		})
	})

	Context("PUT /api/v2/hoverfly/middleware", func() {

		It("Should put the middleware", func() {
			req := sling.New().Put(hoverflyAdminUrl + "/api/v2/hoverfly/middleware")
			req.Body(strings.NewReader(`{"middleware":"cat"}`))
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"middleware":"cat"}`)))

			req = sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/middleware")
			res = DoRequest(req)
			modeJson, err = ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"middleware":"cat"}`)))
		})

	})

	Context("GET /api/v2/hoverfly/usage", func() {

		It("Should get the usage counters", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":0,"modify":0,"simulate":0,"synthesize":0}}}`)))
		})

		It("Should get the usage counters with 1 capture request when a request has been made", func() {
			proxyReq := sling.New().Get("http://www.google.com")
			DoRequestThroughProxy(proxyReq)
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":0,"modify":0,"simulate":1,"synthesize":0}}}`)))
		})
	})

	Context("GET /api/records", func() {

		BeforeEach(func() {
			ImportHoverflyRecords(jsonRequestResponsePair1)
			ImportHoverflyRecords(jsonRequestResponsePair2)
		})

		It("Should retrieve the records", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/records")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			recordsJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair1.String()))
			Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair2.String()))
		})
	})

	Context("DELETE /api/records", func() {

		BeforeEach(func() {
			ImportHoverflyRecords(jsonRequestResponsePair1)
			ImportHoverflyRecords(jsonRequestResponsePair2)
		})

		It("Should delete the records", func() {
			reqPost := sling.New().Delete(hoverflyAdminUrl + "/api/records")
			resPost := DoRequest(reqPost)
			Expect(resPost.StatusCode).To(Equal(200))
			responseMessage, err := ioutil.ReadAll(resPost.Body)
			Expect(err).To(BeNil())

			Expect(string(responseMessage)).To(ContainSubstring("Proxy cache deleted successfuly"))

			reqGet := sling.New().Get(hoverflyAdminUrl + "/api/records")
			resGet := DoRequest(reqGet)
			Expect(resGet.StatusCode).To(Equal(200))
			recordsJson, err := ioutil.ReadAll(resGet.Body)
			Expect(err).To(BeNil())
			Expect(recordsJson).To(MatchJSON(
				`{
				  "data": null
				}`))
		})
	})

	Context("POST /api/records", func() {

		Context("When no records exist", func() {
			It("Should create the records", func() {
				res := DoRequest(sling.New().Post(hoverflyAdminUrl + "/api/records").Body(jsonRequestResponsePair1))
				Expect(res.StatusCode).To(Equal(200))

				reqGet := sling.New().Get(hoverflyAdminUrl + "/api/records")
				resGet := DoRequest(reqGet)

				Expect(resGet.StatusCode).To(Equal(200))

				recordsJson, err := ioutil.ReadAll(resGet.Body)
				Expect(err).To(BeNil())
				Expect(recordsJson).To(MatchJSON(
					`{
					  "data": [
					    {
					      "response": {
						"status": 201,
						"body": "body1",
						"encodedBody": false,
						"headers": {
						  "Header": [
						    "value1"
						  ]
						}
					      },
					      "request": {
					      	"requestType": "recording",
						"path": "/path1",
						"method": "method1",
						"destination": "destination1",
						"scheme": "scheme1",
						"query": "query1",
						"body": "body1",
						"headers": {
						  "Content-Type": [
						    "text/plain; charset=utf-8"
						  ],
						  "Header": [
						    "value1"
						  ]
						}
					      }
					    }
					  ]
					}`))
			})
		})

		Context("When a record already exists", func() {

			BeforeEach(func() {
				ImportHoverflyRecords(jsonRequestResponsePair1)
			})

			It("Should append the records to the existing ones", func() {
				res := DoRequest(sling.New().Post(hoverflyAdminUrl+"/api/records").Set("Content-Type", "application/json").Body(jsonRequestResponsePair2))
				Expect(res.StatusCode).To(Equal(200))

				reqGet := sling.New().Get(hoverflyAdminUrl + "/api/records")
				resGet := DoRequest(reqGet)

				Expect(resGet.StatusCode).To(Equal(200))

				recordsJson, err := ioutil.ReadAll(resGet.Body)
				Expect(err).To(BeNil())
				Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair1.String()))
				Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair2.String()))
			})
		})
	})
})
<commit_msg>Added a few more functional tests to make sure all the individual counters work<commit_after>package hoverfly_test

import (
	"bytes"
	"github.com/dghubble/sling"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"strings"
)

var _ = Describe("Interacting with the API", func() {

	var (
		jsonRequestResponsePair1 *bytes.Buffer
		jsonRequestResponsePair2 *bytes.Buffer
	)

	BeforeEach(func() {
		jsonRequestResponsePair1 = bytes.NewBufferString(`{"data":[{"request": {"path": "/path1", "method": "method1", "destination": "destination1", "scheme": "scheme1", "query": "query1", "body": "body1", "headers": {"Header": ["value1"]}}, "response": {"status": 201, "encodedBody": false, "body": "body1", "headers": {"Header": ["value1"]}}}]}`)
		jsonRequestResponsePair2 = bytes.NewBufferString(`{"data":[{"request": {"path": "/path2", "method": "method2", "destination": "destination2", "scheme": "scheme2", "query": "query2", "body": "body2", "headers": {"Header": ["value2"]}}, "response": {"status": 202, "encodedBody": false, "body": "body2", "headers": {"Header": ["value2"]}}}]}`)

		hoverflyCmd = startHoverfly(adminPort, proxyPort)
	})

	AfterEach(func() {
		stopHoverfly()
	})

	Context("GET /api/v2/hoverfly/destination", func() {

		It("Should get the mode", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/destination")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"destination":"."}`)))
		})
	})

	Context("PUT /api/v2/hoverfly/destination", func() {

		It("Should put the mode", func() {
			req := sling.New().Put(hoverflyAdminUrl + "/api/v2/hoverfly/destination")
			req.Body(strings.NewReader(`{"destination":"test.com"}`))
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"destination":"test.com"}`)))

			req = sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/destination")
			res = DoRequest(req)
			modeJson, err = ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"destination":"test.com"}`)))
		})

	})

	Context("GET /api/v2/hoverfly/mode", func() {

		It("Should get the mode", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/mode")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"mode":"simulate"}`)))
		})
	})

	Context("PUT /api/v2/hoverfly/mode", func() {

		It("Should put the mode", func() {
			req := sling.New().Put(hoverflyAdminUrl + "/api/v2/hoverfly/mode")
			req.Body(strings.NewReader(`{"mode":"capture"}`))
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"mode":"capture"}`)))

			req = sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/mode")
			res = DoRequest(req)
			modeJson, err = ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"mode":"capture"}`)))
		})

	})

	Context("GET /api/v2/hoverfly/middleware", func() {

		It("Should get the middleware which should be blank", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/middleware")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"middleware":""}`)))
		})
	})

	Context("PUT /api/v2/hoverfly/middleware", func() {

		It("Should put the middleware", func() {
			req := sling.New().Put(hoverflyAdminUrl + "/api/v2/hoverfly/middleware")
			req.Body(strings.NewReader(`{"middleware":"cat"}`))
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"middleware":"cat"}`)))

			req = sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/middleware")
			res = DoRequest(req)
			modeJson, err = ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"middleware":"cat"}`)))
		})

	})

	Context("GET /api/v2/hoverfly/usage", func() {

		It("Should get the usage counters", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":0,"modify":0,"simulate":0,"synthesize":0}}}`)))
		})

		It("Should get the usage counters with 1 simulate request when a request has been made", func() {
			proxyReq := sling.New().Get("http://www.google.com")
			DoRequestThroughProxy(proxyReq)
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":0,"modify":0,"simulate":1,"synthesize":0}}}`)))
		})

		It("Should get the usage counters with 1 capture request when a request has been made", func() {
			SetHoverflyMode("capture")

			proxyReq := sling.New().Get("http://www.google.com")
			DoRequestThroughProxy(proxyReq)
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":1,"modify":0,"simulate":0,"synthesize":0}}}`)))
		})

		It("Should get the usage counters with 1 modify request when a request has been made", func() {
			SetHoverflyMode("modify")

			proxyReq := sling.New().Get("http://www.google.com")
			DoRequestThroughProxy(proxyReq)
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":0,"modify":1,"simulate":0,"synthesize":0}}}`)))
		})

		It("Should get the usage counters with 1 modify request when a request has been made", func() {
			SetHoverflyMode("synthesize")

			proxyReq := sling.New().Get("http://www.google.com")
			DoRequestThroughProxy(proxyReq)
			req := sling.New().Get(hoverflyAdminUrl + "/api/v2/hoverfly/usage")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			modeJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(modeJson).To(Equal([]byte(`{"usage":{"counters":{"capture":0,"modify":0,"simulate":0,"synthesize":1}}}`)))
		})
	})

	Context("GET /api/records", func() {

		BeforeEach(func() {
			ImportHoverflyRecords(jsonRequestResponsePair1)
			ImportHoverflyRecords(jsonRequestResponsePair2)
		})

		It("Should retrieve the records", func() {
			req := sling.New().Get(hoverflyAdminUrl + "/api/records")
			res := DoRequest(req)
			Expect(res.StatusCode).To(Equal(200))
			recordsJson, err := ioutil.ReadAll(res.Body)
			Expect(err).To(BeNil())
			Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair1.String()))
			Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair2.String()))
		})
	})

	Context("DELETE /api/records", func() {

		BeforeEach(func() {
			ImportHoverflyRecords(jsonRequestResponsePair1)
			ImportHoverflyRecords(jsonRequestResponsePair2)
		})

		It("Should delete the records", func() {
			reqPost := sling.New().Delete(hoverflyAdminUrl + "/api/records")
			resPost := DoRequest(reqPost)
			Expect(resPost.StatusCode).To(Equal(200))
			responseMessage, err := ioutil.ReadAll(resPost.Body)
			Expect(err).To(BeNil())

			Expect(string(responseMessage)).To(ContainSubstring("Proxy cache deleted successfuly"))

			reqGet := sling.New().Get(hoverflyAdminUrl + "/api/records")
			resGet := DoRequest(reqGet)
			Expect(resGet.StatusCode).To(Equal(200))
			recordsJson, err := ioutil.ReadAll(resGet.Body)
			Expect(err).To(BeNil())
			Expect(recordsJson).To(MatchJSON(
				`{
				  "data": null
				}`))
		})
	})

	Context("POST /api/records", func() {

		Context("When no records exist", func() {
			It("Should create the records", func() {
				res := DoRequest(sling.New().Post(hoverflyAdminUrl + "/api/records").Body(jsonRequestResponsePair1))
				Expect(res.StatusCode).To(Equal(200))

				reqGet := sling.New().Get(hoverflyAdminUrl + "/api/records")
				resGet := DoRequest(reqGet)

				Expect(resGet.StatusCode).To(Equal(200))

				recordsJson, err := ioutil.ReadAll(resGet.Body)
				Expect(err).To(BeNil())
				Expect(recordsJson).To(MatchJSON(
					`{
					  "data": [
					    {
					      "response": {
						"status": 201,
						"body": "body1",
						"encodedBody": false,
						"headers": {
						  "Header": [
						    "value1"
						  ]
						}
					      },
					      "request": {
					      	"requestType": "recording",
						"path": "/path1",
						"method": "method1",
						"destination": "destination1",
						"scheme": "scheme1",
						"query": "query1",
						"body": "body1",
						"headers": {
						  "Content-Type": [
						    "text/plain; charset=utf-8"
						  ],
						  "Header": [
						    "value1"
						  ]
						}
					      }
					    }
					  ]
					}`))
			})
		})

		Context("When a record already exists", func() {

			BeforeEach(func() {
				ImportHoverflyRecords(jsonRequestResponsePair1)
			})

			It("Should append the records to the existing ones", func() {
				res := DoRequest(sling.New().Post(hoverflyAdminUrl+"/api/records").Set("Content-Type", "application/json").Body(jsonRequestResponsePair2))
				Expect(res.StatusCode).To(Equal(200))

				reqGet := sling.New().Get(hoverflyAdminUrl + "/api/records")
				resGet := DoRequest(reqGet)

				Expect(resGet.StatusCode).To(Equal(200))

				recordsJson, err := ioutil.ReadAll(resGet.Body)
				Expect(err).To(BeNil())
				Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair1.String()))
				Expect(recordsJson).To(ContainSubstring(jsonRequestResponsePair2.String()))
			})
		})
	})
})
<|endoftext|>