<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 (
	"flag"
	"time"

	"github.com/sirupsen/logrus"
	"k8s.io/test-infra/boskos/client"
	"k8s.io/test-infra/boskos/common"
)

var (
	rTypes    common.CommaSeparatedStrings
	boskosURL = flag.String("boskos-url", "http://boskos", "Boskos URL")
)

func init() {
	flag.Var(&rTypes, "resource-type", "comma-separated list of resources need to be reset")
}

func main() {
	logrus.SetFormatter(&logrus.JSONFormatter{})
	boskos := client.NewClient("Reaper", *boskosURL)
	logrus.Infof("Initialzied boskos client!")
	flag.Parse()

	if len(rTypes) == 0 {
		logrus.Fatal("--resource-type must not be empty!")
	}

	for range time.Tick(time.Minute * 5) {
		for _, r := range rTypes {
			sync(boskos, r)
		}
	}
}

func sync(c *client.Client, res string) {
	// kubetest busted
	if owners, err := c.Reset(res, common.Busy, 30*time.Minute, common.Dirty); err != nil {
		logrus.WithError(err).Error("Reset busy failed!")
	} else {
		logrus.Infof("Reset busy to dirty! Proj-owner: %v", owners)
	}

	// janitor, mason busted
	if owners, err := c.Reset(res, common.Cleaning, 30*time.Minute, common.Dirty); err != nil {
		logrus.WithError(err).Error("Reset cleaning failed!")
	} else {
		logrus.Infof("Reset cleaning to dirty! Proj-owner: %v", owners)
	}

	// mason busted
	if owners, err := c.Reset(res, common.Leased, 30*time.Minute, common.Dirty); err != nil {
		logrus.WithError(err).Error("Reset busy failed!")
	} else {
		logrus.Infof("Reset leased to dirty! Proj-owner: %v", owners)
	}
}
<commit_msg>Make reaper expiry duration configurable.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 (
	"flag"
	"time"

	"github.com/sirupsen/logrus"
	"k8s.io/test-infra/boskos/client"
	"k8s.io/test-infra/boskos/common"
)

var (
	rTypes         common.CommaSeparatedStrings
	boskosURL      = flag.String("boskos-url", "http://boskos", "Boskos URL")
	expiryDuration = flag.Int("expire", 30, "The expiry time (in minutes) after which reaper will reset resources.")
)

func init() {
	flag.Var(&rTypes, "resource-type", "comma-separated list of resources need to be reset")
}

func main() {
	logrus.SetFormatter(&logrus.JSONFormatter{})
	boskos := client.NewClient("Reaper", *boskosURL)
	logrus.Infof("Initialzied boskos client!")
	flag.Parse()

	if len(rTypes) == 0 {
		logrus.Fatal("--resource-type must not be empty!")
	}
	frequency := (*expiryDuration) / 6
	if frequency < 1 {
		frequency = 1
	}
	for range time.Tick(time.Duration(frequency) * time.Minute) {
		for _, r := range rTypes {
			sync(boskos, r)
		}
	}
}

func sync(c *client.Client, res string) {
	expire := time.Duration(*expiryDuration) * time.Minute
	// kubetest busted
	if owners, err := c.Reset(res, common.Busy, expire, common.Dirty); err != nil {
		logrus.WithError(err).Error("Reset busy failed!")
	} else {
		logrus.Infof("Reset busy to dirty! Proj-owner: %v", owners)
	}

	// janitor, mason busted
	if owners, err := c.Reset(res, common.Cleaning, expire, common.Dirty); err != nil {
		logrus.WithError(err).Error("Reset cleaning failed!")
	} else {
		logrus.Infof("Reset cleaning to dirty! Proj-owner: %v", owners)
	}

	// mason busted
	if owners, err := c.Reset(res, common.Leased, expire, common.Dirty); err != nil {
		logrus.WithError(err).Error("Reset busy failed!")
	} else {
		logrus.Infof("Reset leased to dirty! Proj-owner: %v", owners)
	}
}
<|endoftext|>


<commit_before>package transloadit

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"time"
)

type Assembly struct {
	client     *Client
	NotifyUrl  string
	TemplateId string
	Blocking   bool
	steps      map[string]map[string]interface{}
	readers    []*upload
}

type upload struct {
	Field  string
	Name   string
	Reader io.Reader
}

type AssemblyReplay struct {
	assemblyId      string
	client          *Client
	NotifyUrl       string
	Blocking        bool
	reparseTemplate bool
	steps           map[string]map[string]interface{}
}

type AssemblyList struct {
	Assemblies []*AssemblyListItem `json:"items"`
	Count      int                 `json:"count"`
}

type AssemblyListItem struct {
	AssemblyId        string    `json:"id"`
	AccountId         string    `json:"account_id"`
	TemplateId        string    `json:"template_id"`
	Instance          string    `json:"instance"`
	NotifyUrl         string    `json:"notify_url"`
	RedirectUrl       string    `json:"redirect_url"`
	ExecutionDuration float32   `json:"execution_duration"`
	ExecutionStart    time.Time `json:"execution_start"`
	Created           time.Time `json:"created"`
	Ok                string    `json:"ok"`
	Error             string    `json:"error"`
	Files             string    `json:"files"`
}

type AssemblyInfo struct {
	AssemblyId             string                 `json:"assembly_id"`
	ParentId               string                 `json:"parent_id"`
	AssemblyUrl            string                 `json:"assembly_url"`
	AssemblySslUrl         string                 `json:"assembly_ssl_url"`
	BytesReceived          int                    `json:"bytes_received"`
	BytesExpected          int                    `json:"bytes_expected"`
	ClientAgent            string                 `json:"client_agent"`
	ClientIp               string                 `json:"client_ip"`
	ClientReferer          string                 `json:"client_referer"`
	StartDate              string                 `json:"start_date"`
	IsInfinite             bool                   `json:"is_infinite"`
	HasDupeJobs            bool                   `json:"has_dupe_jobs"`
	UploadDuration         float32                `json:"upload_duration"`
	NotifyUrl              string                 `json:"notify_url"`
	NotifyStart            string                 `json:"notify_start"`
	NotifyStatus           string                 `json:"notify_status"`
	NotifyDuation          float32                `json:"notify_duration"`
	LastJobCompleted       string                 `json:"last_job_completed"`
	ExecutionDuration      float32                `json:"execution_duration"`
	ExecutionStart         string                 `json:"execution_start"`
	Created                string                 `json:"created"`
	Ok                     string                 `json:"ok"`
	Message                string                 `json:"message"`
	Files                  string                 `json:"files"`
	Fields                 map[string]interface{} `json:"fields"`
	BytesUsage             int                    `json:"bytes_usage"`
	FilesToStoreOnS3       int                    `json:"files_to_store_on_s3"`
	QueuedFilesToStoreOnS3 int                    `json:"queued_files_to_store_on_s3"`
	ExecutingJobs          []interface{}          `json:"executing_jobs"`
	StartedJobs            []interface{}          `json:"started_jobs"`
	ParentAssemblyStatus   *AssemblyInfo          `json:"parent_assembly_status"`
	Uploads                []*FileInfo            `json:"uploads"`
	Results                map[string][]*FileInfo `json:"results"`
	Params                 string                 `json:"params"`
	Error                  string                 `json:"error"`
}

type FileInfo struct {
	Id               string                 `json:"id"`
	Name             string                 `json:"name"`
	Basename         string                 `json:"basename"`
	Ext              string                 `json:"ext"`
	Size             int                    `json:"size"`
	Mime             string                 `json:"mime"`
	Type             string                 `json:"type"`
	Field            string                 `json:"field"`
	Md5Hash          string                 `json:"md5hash"`
	OriginalMd5Hash  string                 `json:"original_md5hash"`
	OriginalId       string                 `json:"original_id"`
	OriginalBasename string                 `json:"original_basename"`
	Url              string                 `json:"url"`
	SslUrl           string                 `json:"ssl_url"`
	Meta             map[string]interface{} `json:"meta"`
}

// Create a new assembly instance which can be executed later.
func (client *Client) CreateAssembly() *Assembly {
	return &Assembly{
		client:  client,
		steps:   make(map[string]map[string]interface{}),
		readers: make([]*upload, 0),
	}
}

// Add another reader to upload later.
func (assembly *Assembly) AddReader(field, name string, reader io.Reader) {
	assembly.readers = append(assembly.readers, &upload{
		Field:  field,
		Name:   name,
		Reader: reader,
	})
}

// Add a step to the assembly.
func (assembly *Assembly) AddStep(name string, details map[string]interface{}) {
	assembly.steps[name] = details
}

// Start the assembly and upload all files.
func (assembly *Assembly) Upload() (*AssemblyInfo, error) {
	req, err := assembly.makeRequest()
	if err != nil {
		return nil, fmt.Errorf("failed to create assembly: %s", err)
	}

	var info AssemblyInfo
	_, err = assembly.client.doRequest(req, &info)

	if info.Error != "" {
		return &info, nil
	}

	if !assembly.Blocking {
		return &info, err
	}

	watcher := assembly.client.WaitForAssembly(info.AssemblyUrl)

	select {
	case res := <-watcher.Response:
		// Assembly completed
		return res, nil
	case err := <-watcher.Error:
		// Error appeared
		return nil, err
	}

}

func (assembly *Assembly) makeRequest() (*http.Request, error) {

	// Get bored instance to upload files to
	bored, err := assembly.client.getBoredInstance()
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}
	url := "http://api2-" + bored + "/assemblies"

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// Add files to upload
	for _, reader := range assembly.readers {

		part, err := writer.CreateFormFile(reader.Field, reader.Name)
		if err != nil {
			return nil, fmt.Errorf("unable to create upload request: %s", err)
		}

		_, err = io.Copy(part, reader.Reader)
		if err != nil {
			return nil, fmt.Errorf("unable to create upload request: %s", err)
		}
	}

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

	if len(assembly.steps) != 0 {
		options["steps"] = assembly.steps
	}

	if assembly.TemplateId != "" {
		options["template_id"] = assembly.TemplateId
	}

	if assembly.NotifyUrl != "" {
		options["notify_url"] = assembly.NotifyUrl
	}

	params, signature, err := assembly.client.sign(options)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	// Add additional keys and values
	err = writer.WriteField("params", params)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}
	err = writer.WriteField("signature", signature)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	// Close multipart writer
	err = writer.Close()
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	// Create HTTP request
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	req.Header.Set("Content-Type", writer.FormDataContentType())

	return req, nil

}

// Get information about an assembly using its url.
func (client *Client) GetAssembly(assemblyUrl string) (*AssemblyInfo, error) {

	var info AssemblyInfo
	_, err := client.request("GET", assemblyUrl, nil, &info)
	return &info, err

}

// Cancel an assembly using its url.
func (client *Client) CancelAssembly(assemblyUrl string) (Response, error) {

	return client.request("DELETE", assemblyUrl, nil, nil)

}

// Create a new AssemblyReplay instance.
func (client *Client) ReplayAssembly(assemblyId string) *AssemblyReplay {
	return &AssemblyReplay{
		client:     client,
		steps:      make(map[string]map[string]interface{}),
		assemblyId: assemblyId,
	}
}

// Add a step to override the original ones.
func (assembly *AssemblyReplay) AddStep(name string, details map[string]interface{}) {
	assembly.steps[name] = details
}

// Reparse the template when replaying. Useful if the template has changed since the orignal assembly was created.
func (assembly *AssemblyReplay) ReparseTemplate() {
	assembly.reparseTemplate = true
}

// Start the assembly replay.
func (assembly *AssemblyReplay) Start() (*AssemblyInfo, error) {

	options := map[string]interface{}{
		"steps": assembly.steps,
	}

	if assembly.reparseTemplate {
		options["reparse_template"] = 1
	}

	if assembly.NotifyUrl != "" {
		options["notify_url"] = assembly.NotifyUrl
	}

	var info AssemblyInfo
	_, err := assembly.client.request("POST", "assemblies/"+assembly.assemblyId+"/replay", options, &info)

	if info.Error != "" {
		return &info, nil
	}

	if !assembly.Blocking {
		return &info, err
	}

	// Assembly replay response doesn't contains assembly url
	assemblyUrl := assembly.client.config.Endpoint + "/assemblies/" + info.AssemblyId

	watcher := assembly.client.WaitForAssembly(assemblyUrl)

	select {
	case res := <-watcher.Response:
		// Assembly completed
		return res, nil
	case err := <-watcher.Error:
		// Error appeared
		return nil, err
	}

}

// List all assemblies matching the criterias.
func (client *Client) ListAssemblies(options *ListOptions) (*AssemblyList, error) {

	var assemblies AssemblyList
	_, err := client.listRequest("assemblies", options, &assemblies)
	return &assemblies, err
}
<commit_msg>Close reader after copy<commit_after>package transloadit

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"time"
)

type Assembly struct {
	client     *Client
	NotifyUrl  string
	TemplateId string
	Blocking   bool
	steps      map[string]map[string]interface{}
	readers    []*upload
}

type upload struct {
	Field  string
	Name   string
	Reader io.ReadCloser
}

type AssemblyReplay struct {
	assemblyId      string
	client          *Client
	NotifyUrl       string
	Blocking        bool
	reparseTemplate bool
	steps           map[string]map[string]interface{}
}

type AssemblyList struct {
	Assemblies []*AssemblyListItem `json:"items"`
	Count      int                 `json:"count"`
}

type AssemblyListItem struct {
	AssemblyId        string    `json:"id"`
	AccountId         string    `json:"account_id"`
	TemplateId        string    `json:"template_id"`
	Instance          string    `json:"instance"`
	NotifyUrl         string    `json:"notify_url"`
	RedirectUrl       string    `json:"redirect_url"`
	ExecutionDuration float32   `json:"execution_duration"`
	ExecutionStart    time.Time `json:"execution_start"`
	Created           time.Time `json:"created"`
	Ok                string    `json:"ok"`
	Error             string    `json:"error"`
	Files             string    `json:"files"`
}

type AssemblyInfo struct {
	AssemblyId             string                 `json:"assembly_id"`
	ParentId               string                 `json:"parent_id"`
	AssemblyUrl            string                 `json:"assembly_url"`
	AssemblySslUrl         string                 `json:"assembly_ssl_url"`
	BytesReceived          int                    `json:"bytes_received"`
	BytesExpected          int                    `json:"bytes_expected"`
	ClientAgent            string                 `json:"client_agent"`
	ClientIp               string                 `json:"client_ip"`
	ClientReferer          string                 `json:"client_referer"`
	StartDate              string                 `json:"start_date"`
	IsInfinite             bool                   `json:"is_infinite"`
	HasDupeJobs            bool                   `json:"has_dupe_jobs"`
	UploadDuration         float32                `json:"upload_duration"`
	NotifyUrl              string                 `json:"notify_url"`
	NotifyStart            string                 `json:"notify_start"`
	NotifyStatus           string                 `json:"notify_status"`
	NotifyDuation          float32                `json:"notify_duration"`
	LastJobCompleted       string                 `json:"last_job_completed"`
	ExecutionDuration      float32                `json:"execution_duration"`
	ExecutionStart         string                 `json:"execution_start"`
	Created                string                 `json:"created"`
	Ok                     string                 `json:"ok"`
	Message                string                 `json:"message"`
	Files                  string                 `json:"files"`
	Fields                 map[string]interface{} `json:"fields"`
	BytesUsage             int                    `json:"bytes_usage"`
	FilesToStoreOnS3       int                    `json:"files_to_store_on_s3"`
	QueuedFilesToStoreOnS3 int                    `json:"queued_files_to_store_on_s3"`
	ExecutingJobs          []interface{}          `json:"executing_jobs"`
	StartedJobs            []interface{}          `json:"started_jobs"`
	ParentAssemblyStatus   *AssemblyInfo          `json:"parent_assembly_status"`
	Uploads                []*FileInfo            `json:"uploads"`
	Results                map[string][]*FileInfo `json:"results"`
	Params                 string                 `json:"params"`
	Error                  string                 `json:"error"`
}

type FileInfo struct {
	Id               string                 `json:"id"`
	Name             string                 `json:"name"`
	Basename         string                 `json:"basename"`
	Ext              string                 `json:"ext"`
	Size             int                    `json:"size"`
	Mime             string                 `json:"mime"`
	Type             string                 `json:"type"`
	Field            string                 `json:"field"`
	Md5Hash          string                 `json:"md5hash"`
	OriginalMd5Hash  string                 `json:"original_md5hash"`
	OriginalId       string                 `json:"original_id"`
	OriginalBasename string                 `json:"original_basename"`
	Url              string                 `json:"url"`
	SslUrl           string                 `json:"ssl_url"`
	Meta             map[string]interface{} `json:"meta"`
}

// Create a new assembly instance which can be executed later.
func (client *Client) CreateAssembly() *Assembly {
	return &Assembly{
		client:  client,
		steps:   make(map[string]map[string]interface{}),
		readers: make([]*upload, 0),
	}
}

// Add another reader to upload later.
func (assembly *Assembly) AddReader(field, name string, reader io.ReadCloser) {
	assembly.readers = append(assembly.readers, &upload{
		Field:  field,
		Name:   name,
		Reader: reader,
	})
}

// Add a step to the assembly.
func (assembly *Assembly) AddStep(name string, details map[string]interface{}) {
	assembly.steps[name] = details
}

// Start the assembly and upload all files.
func (assembly *Assembly) Upload() (*AssemblyInfo, error) {
	req, err := assembly.makeRequest()
	if err != nil {
		return nil, fmt.Errorf("failed to create assembly: %s", err)
	}

	var info AssemblyInfo
	_, err = assembly.client.doRequest(req, &info)

	if info.Error != "" {
		return &info, nil
	}

	if !assembly.Blocking {
		return &info, err
	}

	watcher := assembly.client.WaitForAssembly(info.AssemblyUrl)

	select {
	case res := <-watcher.Response:
		// Assembly completed
		return res, nil
	case err := <-watcher.Error:
		// Error appeared
		return nil, err
	}

}

func (assembly *Assembly) makeRequest() (*http.Request, error) {

	// Get bored instance to upload files to
	bored, err := assembly.client.getBoredInstance()
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}
	url := "http://api2-" + bored + "/assemblies"

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	// Add files to upload
	for _, reader := range assembly.readers {

		part, err := writer.CreateFormFile(reader.Field, reader.Name)
		if err != nil {
			return nil, fmt.Errorf("unable to create upload request: %s", err)
		}

		_, err = io.Copy(part, reader.Reader)
		if err != nil {
			return nil, fmt.Errorf("unable to create upload request: %s", err)
		}

		err = reader.Reader.Close()
		if err != nil {
			return nil, fmt.Errorf("unable to create upload request: %s", err)
		}
	}

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

	if len(assembly.steps) != 0 {
		options["steps"] = assembly.steps
	}

	if assembly.TemplateId != "" {
		options["template_id"] = assembly.TemplateId
	}

	if assembly.NotifyUrl != "" {
		options["notify_url"] = assembly.NotifyUrl
	}

	params, signature, err := assembly.client.sign(options)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	// Add additional keys and values
	err = writer.WriteField("params", params)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}
	err = writer.WriteField("signature", signature)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	// Close multipart writer
	err = writer.Close()
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	// Create HTTP request
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, fmt.Errorf("unable to create upload request: %s", err)
	}

	req.Header.Set("Content-Type", writer.FormDataContentType())

	return req, nil

}

// Get information about an assembly using its url.
func (client *Client) GetAssembly(assemblyUrl string) (*AssemblyInfo, error) {

	var info AssemblyInfo
	_, err := client.request("GET", assemblyUrl, nil, &info)
	return &info, err

}

// Cancel an assembly using its url.
func (client *Client) CancelAssembly(assemblyUrl string) (Response, error) {

	return client.request("DELETE", assemblyUrl, nil, nil)

}

// Create a new AssemblyReplay instance.
func (client *Client) ReplayAssembly(assemblyId string) *AssemblyReplay {
	return &AssemblyReplay{
		client:     client,
		steps:      make(map[string]map[string]interface{}),
		assemblyId: assemblyId,
	}
}

// Add a step to override the original ones.
func (assembly *AssemblyReplay) AddStep(name string, details map[string]interface{}) {
	assembly.steps[name] = details
}

// Reparse the template when replaying. Useful if the template has changed since the orignal assembly was created.
func (assembly *AssemblyReplay) ReparseTemplate() {
	assembly.reparseTemplate = true
}

// Start the assembly replay.
func (assembly *AssemblyReplay) Start() (*AssemblyInfo, error) {

	options := map[string]interface{}{
		"steps": assembly.steps,
	}

	if assembly.reparseTemplate {
		options["reparse_template"] = 1
	}

	if assembly.NotifyUrl != "" {
		options["notify_url"] = assembly.NotifyUrl
	}

	var info AssemblyInfo
	_, err := assembly.client.request("POST", "assemblies/"+assembly.assemblyId+"/replay", options, &info)

	if info.Error != "" {
		return &info, nil
	}

	if !assembly.Blocking {
		return &info, err
	}

	// Assembly replay response doesn't contains assembly url
	assemblyUrl := assembly.client.config.Endpoint + "/assemblies/" + info.AssemblyId

	watcher := assembly.client.WaitForAssembly(assemblyUrl)

	select {
	case res := <-watcher.Response:
		// Assembly completed
		return res, nil
	case err := <-watcher.Error:
		// Error appeared
		return nil, err
	}

}

// List all assemblies matching the criterias.
func (client *Client) ListAssemblies(options *ListOptions) (*AssemblyList, error) {

	var assemblies AssemblyList
	_, err := client.listRequest("assemblies", options, &assemblies)
	return &assemblies, err
}
<|endoftext|>


<commit_before>package headers

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

func Add(headers []string, req *http.Request) error {
	for _, header := range headers {
		parts := strings.Split(header, "=")
		if len(parts) != 2 {
			return fmt.Errorf("Invalid header [%s]. Should be [key=value]", header)
		}

		req.Header.Add(parts[0], parts[1])
	}

	return nil
}
<commit_msg>Better split<commit_after>package headers

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

func Add(headers []string, req *http.Request) error {
	for _, header := range headers {
		parts := strings.SplitN(header, "=", 2)
		if len(parts) != 2 {
			return fmt.Errorf("Invalid header [%s]. Should be [key=value]", header)
		}

		req.Header.Add(parts[0], parts[1])
	}

	return nil
}
<|endoftext|>


<commit_before>package authentication

import (
	"testing"

	configv1 "github.com/openshift/api/config/v1"
	"k8s.io/apimachinery/pkg/util/validation/field"
)

func TestFailValidateAuthenticationSpec(t *testing.T) {
	errorCases := map[string]struct {
		spec       configv1.AuthenticationSpec
		errorType  field.ErrorType
		errorField string
	}{
		"invalid authn type": {
			spec: configv1.AuthenticationSpec{
				Type: "MyCoolOAuthSrv",
			},
			errorType:  field.ErrorTypeNotSupported,
			errorField: "spec.type",
		},
		"invalid metadata ref": {
			spec: configv1.AuthenticationSpec{
				Type: "",
				OAuthMetadata: configv1.ConfigMapNameReference{
					Name: "../shadow",
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "spec.oauthMetadata.name",
		},
		"invalid webhook ref": {
			spec: configv1.AuthenticationSpec{
				WebhookTokenAuthenticators: []configv1.WebhookTokenAuthenticator{
					{KubeConfig: configv1.SecretNameReference{Name: "this+that"}},
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "spec.webhookTokenAuthenticators[0].kubeConfig.name",
		},
		"invalid webhook ref - multiple webhooks": {
			spec: configv1.AuthenticationSpec{
				WebhookTokenAuthenticators: []configv1.WebhookTokenAuthenticator{
					{KubeConfig: configv1.SecretNameReference{Name: "that.now"}},
					{KubeConfig: configv1.SecretNameReference{Name: "this+that"}},
					{KubeConfig: configv1.SecretNameReference{Name: "this.then"}},
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "spec.webhookTokenAuthenticators[1].kubeConfig.name",
		},
		"empty webhook name": {
			spec: configv1.AuthenticationSpec{
				WebhookTokenAuthenticators: []configv1.WebhookTokenAuthenticator{
					{KubeConfig: configv1.SecretNameReference{Name: ""}},
				},
			},
			errorType:  field.ErrorTypeRequired,
			errorField: "spec.webhookTokenAuthenticators[0].kubeConfig.name",
		},
	}

	for tcName, tc := range errorCases {
		errs := validateAuthenticationSpec(tc.spec)
		if len(errs) == 0 {
			t.Errorf("'%s': should have failed but did not", tcName)
		}

		for _, e := range errs {
			if e.Type != tc.errorType {
				t.Errorf("'%s': expected errors of type '%s', got %v:", tcName, tc.errorType, e)
			}

			if e.Field != tc.errorField {
				t.Errorf("'%s': expected errors in field '%s', got %v:", tcName, tc.errorField, e)
			}
		}
	}
}

func TestSucceedValidateAuthenticationSpec(t *testing.T) {
	successCases := map[string]configv1.AuthenticationSpec{
		"integrated oauth authn type": {
			Type: "IntegratedOAuth",
		},
		"_none_ authn type": {
			Type: "None",
		},
		"empty authn type": {
			Type: "",
		},
		"integrated oauth + oauth metadata": {
			OAuthMetadata: configv1.ConfigMapNameReference{
				Name: "configmapwithmetadata",
			},
		},
		"webhook set": {
			WebhookTokenAuthenticators: []configv1.WebhookTokenAuthenticator{
				{KubeConfig: configv1.SecretNameReference{Name: "wheniwaslittleiwantedtobecomeawebhook"}},
			},
		},
		"some webhooks": {
			WebhookTokenAuthenticators: []configv1.WebhookTokenAuthenticator{
				{KubeConfig: configv1.SecretNameReference{Name: "whatacoolnameforasecret"}},
				{KubeConfig: configv1.SecretNameReference{Name: "whatacoolnameforasecret2"}},
				{KubeConfig: configv1.SecretNameReference{Name: "thisalsoisacoolname"}},
				{KubeConfig: configv1.SecretNameReference{Name: "letsnotoverdoit"}},
			},
		},
		"all fields set": {
			Type: "IntegratedOAuth",
			OAuthMetadata: configv1.ConfigMapNameReference{
				Name: "suchname",
			},
			WebhookTokenAuthenticators: []configv1.WebhookTokenAuthenticator{
				{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook"}},
				{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook2"}},
				{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook33"}},
			},
		},
	}

	for tcName, s := range successCases {
		errs := validateAuthenticationSpec(s)
		if len(errs) != 0 {
			t.Errorf("'%s': expected success, but failed: %v", tcName, errs.ToAggregate().Error())
		}
	}
}

func TestFailValidateAuthenticationStatus(t *testing.T) {
	errorCases := map[string]struct {
		status     configv1.AuthenticationStatus
		errorType  field.ErrorType
		errorField string
	}{
		"wrong reference name": {
			status: configv1.AuthenticationStatus{
				IntegratedOAuthMetadata: configv1.ConfigMapNameReference{
					Name: "something_wrong",
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "status.integratedOAuthMetadata.name",
		},
	}

	for tcName, tc := range errorCases {
		errs := validateAuthenticationStatus(tc.status)
		if len(errs) == 0 {
			t.Errorf("'%s': should have failed but did not", tcName)
		}

		for _, e := range errs {
			if e.Type != tc.errorType {
				t.Errorf("'%s': expected errors of type '%s', got %v:", tcName, tc.errorType, e)
			}

			if e.Field != tc.errorField {
				t.Errorf("'%s': expected errors in field '%s', got %v:", tcName, tc.errorField, e)
			}
		}
	}
}

func TestSucceedValidateAuthenticationStatus(t *testing.T) {
	successCases := map[string]configv1.AuthenticationStatus{
		"basic case": {
			IntegratedOAuthMetadata: configv1.ConfigMapNameReference{
				Name: "hey-there",
			},
		},
		"empty reference": {
			IntegratedOAuthMetadata: configv1.ConfigMapNameReference{
				Name: "",
			},
		},
		"empty status": {},
	}

	for tcName, s := range successCases {
		errs := validateAuthenticationStatus(s)
		if len(errs) != 0 {
			t.Errorf("'%s': expected success, but failed: %v", tcName, errs.ToAggregate().Error())
		}
	}

}
<commit_msg>UPSTREAM: <carry>: update authentication tests to use DeprecatedWebhookTokenAuthenticator<commit_after>package authentication

import (
	"testing"

	configv1 "github.com/openshift/api/config/v1"
	"k8s.io/apimachinery/pkg/util/validation/field"
)

func TestFailValidateAuthenticationSpec(t *testing.T) {
	errorCases := map[string]struct {
		spec       configv1.AuthenticationSpec
		errorType  field.ErrorType
		errorField string
	}{
		"invalid authn type": {
			spec: configv1.AuthenticationSpec{
				Type: "MyCoolOAuthSrv",
			},
			errorType:  field.ErrorTypeNotSupported,
			errorField: "spec.type",
		},
		"invalid metadata ref": {
			spec: configv1.AuthenticationSpec{
				Type: "",
				OAuthMetadata: configv1.ConfigMapNameReference{
					Name: "../shadow",
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "spec.oauthMetadata.name",
		},
		"invalid webhook ref": {
			spec: configv1.AuthenticationSpec{
				WebhookTokenAuthenticators: []configv1.DeprecatedWebhookTokenAuthenticator{
					{KubeConfig: configv1.SecretNameReference{Name: "this+that"}},
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "spec.webhookTokenAuthenticators[0].kubeConfig.name",
		},
		"invalid webhook ref - multiple webhooks": {
			spec: configv1.AuthenticationSpec{
				WebhookTokenAuthenticators: []configv1.DeprecatedWebhookTokenAuthenticator{
					{KubeConfig: configv1.SecretNameReference{Name: "that.now"}},
					{KubeConfig: configv1.SecretNameReference{Name: "this+that"}},
					{KubeConfig: configv1.SecretNameReference{Name: "this.then"}},
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "spec.webhookTokenAuthenticators[1].kubeConfig.name",
		},
		"empty webhook name": {
			spec: configv1.AuthenticationSpec{
				WebhookTokenAuthenticators: []configv1.DeprecatedWebhookTokenAuthenticator{
					{KubeConfig: configv1.SecretNameReference{Name: ""}},
				},
			},
			errorType:  field.ErrorTypeRequired,
			errorField: "spec.webhookTokenAuthenticators[0].kubeConfig.name",
		},
	}

	for tcName, tc := range errorCases {
		errs := validateAuthenticationSpec(tc.spec)
		if len(errs) == 0 {
			t.Errorf("'%s': should have failed but did not", tcName)
		}

		for _, e := range errs {
			if e.Type != tc.errorType {
				t.Errorf("'%s': expected errors of type '%s', got %v:", tcName, tc.errorType, e)
			}

			if e.Field != tc.errorField {
				t.Errorf("'%s': expected errors in field '%s', got %v:", tcName, tc.errorField, e)
			}
		}
	}
}

func TestSucceedValidateAuthenticationSpec(t *testing.T) {
	successCases := map[string]configv1.AuthenticationSpec{
		"integrated oauth authn type": {
			Type: "IntegratedOAuth",
		},
		"_none_ authn type": {
			Type: "None",
		},
		"empty authn type": {
			Type: "",
		},
		"integrated oauth + oauth metadata": {
			OAuthMetadata: configv1.ConfigMapNameReference{
				Name: "configmapwithmetadata",
			},
		},
		"webhook set": {
			WebhookTokenAuthenticators: []configv1.DeprecatedWebhookTokenAuthenticator{
				{KubeConfig: configv1.SecretNameReference{Name: "wheniwaslittleiwantedtobecomeawebhook"}},
			},
		},
		"some webhooks": {
			WebhookTokenAuthenticators: []configv1.DeprecatedWebhookTokenAuthenticator{
				{KubeConfig: configv1.SecretNameReference{Name: "whatacoolnameforasecret"}},
				{KubeConfig: configv1.SecretNameReference{Name: "whatacoolnameforasecret2"}},
				{KubeConfig: configv1.SecretNameReference{Name: "thisalsoisacoolname"}},
				{KubeConfig: configv1.SecretNameReference{Name: "letsnotoverdoit"}},
			},
		},
		"all fields set": {
			Type: "IntegratedOAuth",
			OAuthMetadata: configv1.ConfigMapNameReference{
				Name: "suchname",
			},
			WebhookTokenAuthenticators: []configv1.DeprecatedWebhookTokenAuthenticator{
				{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook"}},
				{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook2"}},
				{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook33"}},
			},
		},
	}

	for tcName, s := range successCases {
		errs := validateAuthenticationSpec(s)
		if len(errs) != 0 {
			t.Errorf("'%s': expected success, but failed: %v", tcName, errs.ToAggregate().Error())
		}
	}
}

func TestFailValidateAuthenticationStatus(t *testing.T) {
	errorCases := map[string]struct {
		status     configv1.AuthenticationStatus
		errorType  field.ErrorType
		errorField string
	}{
		"wrong reference name": {
			status: configv1.AuthenticationStatus{
				IntegratedOAuthMetadata: configv1.ConfigMapNameReference{
					Name: "something_wrong",
				},
			},
			errorType:  field.ErrorTypeInvalid,
			errorField: "status.integratedOAuthMetadata.name",
		},
	}

	for tcName, tc := range errorCases {
		errs := validateAuthenticationStatus(tc.status)
		if len(errs) == 0 {
			t.Errorf("'%s': should have failed but did not", tcName)
		}

		for _, e := range errs {
			if e.Type != tc.errorType {
				t.Errorf("'%s': expected errors of type '%s', got %v:", tcName, tc.errorType, e)
			}

			if e.Field != tc.errorField {
				t.Errorf("'%s': expected errors in field '%s', got %v:", tcName, tc.errorField, e)
			}
		}
	}
}

func TestSucceedValidateAuthenticationStatus(t *testing.T) {
	successCases := map[string]configv1.AuthenticationStatus{
		"basic case": {
			IntegratedOAuthMetadata: configv1.ConfigMapNameReference{
				Name: "hey-there",
			},
		},
		"empty reference": {
			IntegratedOAuthMetadata: configv1.ConfigMapNameReference{
				Name: "",
			},
		},
		"empty status": {},
	}

	for tcName, s := range successCases {
		errs := validateAuthenticationStatus(s)
		if len(errs) != 0 {
			t.Errorf("'%s': expected success, but failed: %v", tcName, errs.ToAggregate().Error())
		}
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build !js,!windows

package audio

import (
	"fmt"
	"io"
	"runtime"
	"sync"
	"time"

	"golang.org/x/mobile/exp/audio/al"
)

// alSourceCacheEntry represents a source.
// In some environments, too many calls of alGenSources and alGenBuffers could cause errors.
// To avoid this error, al.Source and al.Buffer are reused.
type alSourceCacheEntry struct {
	source     al.Source
	buffers    []al.Buffer
	sampleRate int
	isClosed   bool
}

const maxSourceNum = 32

var alSourceCache = []*alSourceCacheEntry{}

type player struct {
	alSource   al.Source
	alBuffers  []al.Buffer
	source     io.ReadSeeker
	sampleRate int
}

var m sync.Mutex

func newAlSource(sampleRate int) (al.Source, []al.Buffer, error) {
	for _, e := range alSourceCache {
		if e.sampleRate != sampleRate {
			continue
		}
		if !e.isClosed {
			continue
		}
		e.isClosed = false
		return e.source, e.buffers, nil
	}
	if maxSourceNum <= len(alSourceCache) {
		return 0, nil, ErrTooManyPlayers
	}
	s := al.GenSources(1)
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: al.GenSources error: %d", err))
	}
	e := &alSourceCacheEntry{
		source:     s[0],
		buffers:    []al.Buffer{},
		sampleRate: sampleRate,
	}
	alSourceCache = append(alSourceCache, e)
	return s[0], e.buffers, nil
}

func newPlayer(src io.ReadSeeker, sampleRate int) (*Player, error) {
	m.Lock()
	if e := al.OpenDevice(); e != nil {
		m.Unlock()
		return nil, fmt.Errorf("audio: OpenAL initialization failed: %v", e)
	}
	s, b, err := newAlSource(sampleRate)
	if err != nil {
		m.Unlock()
		return nil, err
	}
	m.Unlock()
	p := &player{
		alSource:   s,
		alBuffers:  b,
		source:     src,
		sampleRate: sampleRate,
	}
	runtime.SetFinalizer(p, (*player).close)
	return &Player{p}, nil
}

const bufferSize = 1024

func (p *player) proceed() error {
	m.Lock()
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: before proceed: %d", err))
	}
	processedNum := p.alSource.BuffersProcessed()
	if 0 < processedNum {
		bufs := make([]al.Buffer, processedNum)
		p.alSource.UnqueueBuffers(bufs...)
		if err := al.Error(); err != 0 {
			panic(fmt.Sprintf("audio: Unqueue in process: %d", err))
		}
		p.alBuffers = append(p.alBuffers, bufs...)
	}
	m.Unlock()
	for 0 < len(p.alBuffers) {
		b := make([]byte, bufferSize)
		n, err := p.source.Read(b)
		if 0 < n {
			m.Lock()
			buf := p.alBuffers[0]
			p.alBuffers = p.alBuffers[1:]
			buf.BufferData(al.FormatStereo16, b[:n], int32(p.sampleRate))
			p.alSource.QueueBuffers(buf)
			if err := al.Error(); err != 0 {
				panic(fmt.Sprintf("audio: Queue in process: %d", err))
			}
			m.Unlock()
		}
		if err != nil {
			return err
		}
	}
	m.Lock()
	if p.alSource.State() == al.Stopped {
		al.RewindSources(p.alSource)
		al.PlaySources(p.alSource)
		if err := al.Error(); err != 0 {
			panic(fmt.Sprintf("audio: PlaySource in process: %d", err))
		}
	}
	m.Unlock()

	return nil
}

func (p *player) play() error {
	const bufferMaxNum = 8
	// TODO: What if play is already called?
	m.Lock()
	n := bufferMaxNum - int(p.alSource.BuffersQueued()) - len(p.alBuffers)
	if 0 < n {
		p.alBuffers = append(p.alBuffers, al.GenBuffers(n)...)
	}
	if 0 < len(p.alBuffers) {
		emptyBytes := make([]byte, bufferSize)
		for _, buf := range p.alBuffers {
			// Note that the third argument of only the first buffer is used.
			buf.BufferData(al.FormatStereo16, emptyBytes, int32(p.sampleRate))
			p.alSource.QueueBuffers(buf)
		}
		p.alBuffers = []al.Buffer{}
	}
	al.PlaySources(p.alSource)
	m.Unlock()
	go func() {
		defer p.close()
		for {
			err := p.proceed()
			if err == io.EOF {
				break
			}
			if err != nil {
				// TODO: Record the last error
				panic(err)
			}
			time.Sleep(1)
		}
	}()
	return nil
}

func (p *player) close() error {
	m.Lock()
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: error before closing: %d", err))
	}
	s := p.alSource
	if p.alSource != 0 {
		var bs []al.Buffer
		al.RewindSources(p.alSource)
		al.StopSources(p.alSource)
		n := p.alSource.BuffersQueued()
		if 0 < n {
			bs = make([]al.Buffer, n)
			p.alSource.UnqueueBuffers(bs...)
			p.alBuffers = append(p.alBuffers, bs...)
		}
		p.alSource = 0
	}
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: closing error: %d", err))
	}
	if s != 0 {
		found := false
		for _, e := range alSourceCache {
			if e.source != s {
				continue
			}
			if e.isClosed {
				panic("audio: cache state is invalid: source is already closed?")
			}
			e.buffers = p.alBuffers
			e.isClosed = true
			found = true
			break
		}
		if !found {
			panic("audio: cache state is invalid: source is not cached?")
		}
	}
	m.Unlock()
	runtime.SetFinalizer(p, nil)
	return nil
}
<commit_msg>audio: Refactoring: Remove alSourceCache and add playerCache instead<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build !js,!windows

package audio

import (
	"fmt"
	"io"
	"runtime"
	"sync"
	"time"

	"golang.org/x/mobile/exp/audio/al"
)

const (
	maxSourceNum = 32
	maxBufferNum = 8
)

var totalBufferNum = 0

var playerCache = []*player{}

type player struct {
	alSource   al.Source
	alBuffers  []al.Buffer
	source     io.ReadSeeker
	sampleRate int
	isClosed   bool
}

var m sync.Mutex

func newPlayerFromCache(src io.ReadSeeker, sampleRate int) (*player, error) {
	for _, p := range playerCache {
		if p.sampleRate != sampleRate {
			continue
		}
		if !p.isClosed {
			continue
		}
		p.source = src
		p.isClosed = false
		return p, nil
	}
	if maxSourceNum <= len(playerCache) {
		return nil, ErrTooManyPlayers
	}
	s := al.GenSources(1)
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: al.GenSources error: %d", err))
	}
	p := &player{
		alSource:   s[0],
		alBuffers:  []al.Buffer{},
		source:     src,
		sampleRate: sampleRate,
	}
	runtime.SetFinalizer(p, (*player).close)
	playerCache = append(playerCache, p)
	return p, nil
}

func newPlayer(src io.ReadSeeker, sampleRate int) (*Player, error) {
	m.Lock()
	defer m.Unlock()

	if e := al.OpenDevice(); e != nil {
		m.Unlock()
		return nil, fmt.Errorf("audio: OpenAL initialization failed: %v", e)
	}
	p, err := newPlayerFromCache(src, sampleRate)
	if err != nil {
		return nil, err
	}
	return &Player{p}, nil
}

const bufferSize = 1024

func (p *player) proceed() error {
	m.Lock()
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: before proceed: %d", err))
	}
	processedNum := p.alSource.BuffersProcessed()
	if 0 < processedNum {
		bufs := make([]al.Buffer, processedNum)
		p.alSource.UnqueueBuffers(bufs...)
		if err := al.Error(); err != 0 {
			panic(fmt.Sprintf("audio: Unqueue in process: %d", err))
		}
		p.alBuffers = append(p.alBuffers, bufs...)
	}
	m.Unlock()

	for 0 < len(p.alBuffers) {
		b := make([]byte, bufferSize)
		n, err := p.source.Read(b)
		if 0 < n {
			m.Lock()
			buf := p.alBuffers[0]
			p.alBuffers = p.alBuffers[1:]
			buf.BufferData(al.FormatStereo16, b[:n], int32(p.sampleRate))
			p.alSource.QueueBuffers(buf)
			if err := al.Error(); err != 0 {
				panic(fmt.Sprintf("audio: Queue in process: %d", err))
			}
			m.Unlock()
		}
		if err != nil {
			return err
		}
	}

	m.Lock()
	if p.alSource.State() == al.Stopped {
		al.RewindSources(p.alSource)
		al.PlaySources(p.alSource)
		if err := al.Error(); err != 0 {
			panic(fmt.Sprintf("audio: PlaySource in process: %d", err))
		}
	}
	m.Unlock()

	return nil
}

func (p *player) play() error {
	// TODO: What if play is already called?
	m.Lock()
	n := maxBufferNum - int(p.alSource.BuffersQueued()) - len(p.alBuffers)
	if 0 < n {
		p.alBuffers = append(p.alBuffers, al.GenBuffers(n)...)
		totalBufferNum += n
		if maxSourceNum*maxBufferNum < totalBufferNum {
			panic("audio: too many buffers are created")
		}
	}
	if 0 < len(p.alBuffers) {
		emptyBytes := make([]byte, bufferSize)
		for _, buf := range p.alBuffers {
			// Note that the third argument of only the first buffer is used.
			buf.BufferData(al.FormatStereo16, emptyBytes, int32(p.sampleRate))
			p.alSource.QueueBuffers(buf)
		}
		p.alBuffers = []al.Buffer{}
	}
	al.PlaySources(p.alSource)
	m.Unlock()

	go func() {
		defer p.close()
		for {
			err := p.proceed()
			if err == io.EOF {
				break
			}
			if err != nil {
				// TODO: Record the last error
				panic(err)
			}
			time.Sleep(1)
		}
	}()
	return nil
}

func (p *player) close() error {
	m.Lock()
	defer m.Unlock()

	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: error before closing: %d", err))
	}
	if p.isClosed {
		return nil
	}
	var bs []al.Buffer
	al.RewindSources(p.alSource)
	al.StopSources(p.alSource)
	n := p.alSource.BuffersQueued()
	if 0 < n {
		bs = make([]al.Buffer, n)
		p.alSource.UnqueueBuffers(bs...)
		p.alBuffers = append(p.alBuffers, bs...)
	}
	p.isClosed = true
	if err := al.Error(); err != 0 {
		panic(fmt.Sprintf("audio: error after closing: %d", err))
	}
	runtime.SetFinalizer(p, nil)
	return nil
}
<|endoftext|>


<commit_before>package immortal

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"syscall"

	"github.com/nbari/violetear"
)

// HandleSignals send signals to the current process
func (d *Daemon) HandleSignal(w http.ResponseWriter, r *http.Request) {
	var err error

	// get signal from request params
	params := r.Context().Value(violetear.ParamsKey).(violetear.Params)
	signal := params["*"].(string)

	switch signal {
	// a: Alarm. Send the service an ALRM signal.
	case "a", "alrm":
		err = d.process.Signal(syscall.SIGALRM)

	// c: Continue. Send the service a CONT signal.
	case "c", "cont":
		err = d.process.Signal(syscall.SIGCONT)

	// d: Down. If the service is running, send it a TERM signal. After it stops, do not restart it.
	case "d", "down":
		d.lockOnce = 1
		err = d.process.Signal(syscall.SIGTERM)

	// h: Hangup. Send the service a HUP signal.
	case "h", "hup":
		err = d.process.Signal(syscall.SIGHUP)

	// i: Interrupt. Send the service an INT signal.
	case "i", "int":
		err = d.process.Signal(syscall.SIGINT)

	// in: TTIN. Send the service a TTIN signal.
	case "in", "TTIN":
		err = d.process.Signal(syscall.SIGTTIN)

	// k: Kill. Send the service a KILL signal.
	case "k", "kill":
		err = d.process.Kill()

	// o: Once. If the service is not running, start it. Do not restart it if it stops.
	case "o", "once":
		d.lockOnce = 1

	// ou: TTOU. Send the service a TTOU signal.
	case "ou", "out", "TTOU":
		err = d.process.Signal(syscall.SIGTTOU)

	// p: Pause. Send the service a STOP signal.
	case "p", "pause", "s", "stop":
		err = d.process.Signal(syscall.SIGSTOP)

	// q: QUIT. Send the service a QUIT signal.
	case "q", "quit":
		err = d.process.Signal(syscall.SIGQUIT)

	// t: Terminate. Send the service a TERM signal.
	case "t", "term":
		err = d.process.Signal(syscall.SIGTERM)

	// u: Up. If the service is not running, start it. If the service stops, restart it.
	case "u", "up":
		d.lock = 0
		d.lockOnce = 0
		d.run <- struct{}{}

	// 1: USR1. Send the service a USR1 signal.
	case "1", "usr1":
		err = d.process.Signal(syscall.SIGUSR1)

	// 2: USR2. Send the service a USR2 signal.
	case "2", "usr2":
		err = d.process.Signal(syscall.SIGUSR2)

	// w: WINCH. Send the service a WINCH signal.
	case "w", "winch":
		err = d.process.Signal(syscall.SIGWINCH)

	// x: Exit. If you use this option on a stable system, you're doing something wrong; supervise is designed to run forever.
	case "x", "exit":
		close(d.quit)

	default:
		err = fmt.Errorf("Unknown signal: %s", signal)
	}

	// Response struct to return the error in json format
	type Response struct {
		Err string
	}

	res := &Response{}

	if err != nil {
		res.Err = err.Error()
		log.Print(err)
	}

	// return the error on the Response json encoded
	if err := json.NewEncoder(w).Encode(res); err != nil {
		log.Println(err)
	}
}
<commit_msg>fixed signal up to avoid starting multiple process<commit_after>package immortal

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync/atomic"
	"syscall"

	"github.com/nbari/violetear"
)

// HandleSignals send signals to the current process
func (d *Daemon) HandleSignal(w http.ResponseWriter, r *http.Request) {
	var err error

	// get signal from request params
	params := r.Context().Value(violetear.ParamsKey).(violetear.Params)
	signal := params["*"].(string)

	switch signal {
	// a: Alarm. Send the service an ALRM signal.
	case "a", "alrm":
		err = d.process.Signal(syscall.SIGALRM)

	// c: Continue. Send the service a CONT signal.
	case "c", "cont":
		err = d.process.Signal(syscall.SIGCONT)

	// d: Down. If the service is running, send it a TERM signal. After it stops, do not restart it.
	case "d", "down":
		d.lockOnce = 1
		err = d.process.Signal(syscall.SIGTERM)

	// h: Hangup. Send the service a HUP signal.
	case "h", "hup":
		err = d.process.Signal(syscall.SIGHUP)

	// i: Interrupt. Send the service an INT signal.
	case "i", "int":
		err = d.process.Signal(syscall.SIGINT)

	// in: TTIN. Send the service a TTIN signal.
	case "in", "TTIN":
		err = d.process.Signal(syscall.SIGTTIN)

	// k: Kill. Send the service a KILL signal.
	case "k", "kill":
		err = d.process.Kill()

	// o: Once. If the service is not running, start it. Do not restart it if it stops.
	case "o", "once":
		d.lockOnce = 1

	// ou: TTOU. Send the service a TTOU signal.
	case "ou", "out", "TTOU":
		err = d.process.Signal(syscall.SIGTTOU)

	// p: Pause. Send the service a STOP signal.
	case "p", "pause", "s", "stop":
		err = d.process.Signal(syscall.SIGSTOP)

	// q: QUIT. Send the service a QUIT signal.
	case "q", "quit":
		err = d.process.Signal(syscall.SIGQUIT)

	// t: Terminate. Send the service a TERM signal.
	case "t", "term":
		err = d.process.Signal(syscall.SIGTERM)

	// u: Up. If the service is not running, start it. If the service stops, restart it.
	case "u", "up":
		if lock := atomic.LoadUint32(&d.lockOnce); lock != 0 {
			d.lock = 0
			d.lockOnce = 0
			d.run <- struct{}{}
		} else {
			err = fmt.Errorf("Process is up, PID: %d", d.process.Pid())
		}

	// 1: USR1. Send the service a USR1 signal.
	case "1", "usr1":
		err = d.process.Signal(syscall.SIGUSR1)

	// 2: USR2. Send the service a USR2 signal.
	case "2", "usr2":
		err = d.process.Signal(syscall.SIGUSR2)

	// w: WINCH. Send the service a WINCH signal.
	case "w", "winch":
		err = d.process.Signal(syscall.SIGWINCH)

	// x: Exit. If you use this option on a stable system, you're doing something wrong; supervise is designed to run forever.
	case "x", "exit":
		close(d.quit)

	default:
		err = fmt.Errorf("Unknown signal: %s", signal)
	}

	// Response struct to return the error in json format
	type Response struct {
		Err string
	}

	res := &Response{}

	if err != nil {
		res.Err = err.Error()
		log.Print(err)
	}

	// return the error on the Response json encoded
	if err := json.NewEncoder(w).Encode(res); err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>package gomol

import (
	"github.com/spaolacci/murmur3"

	"fmt"
	"sync"
)

type Attrs struct {
	attrs map[uint32]interface{}
}

// NewAttrs will create a new Attrs struct with an empty set of attributes.
func NewAttrs() *Attrs {
	return &Attrs{
		attrs: make(map[uint32]interface{}),
	}
}

// NewAttrsFromMap will create a new Attrs struct with the given attributes pre-populated
func NewAttrsFromMap(attrs map[string]interface{}) *Attrs {
	newAttrs := NewAttrs()
	for attrKey, attrVal := range attrs {
		newAttrs.SetAttr(attrKey, attrVal)
	}
	return newAttrs
}

// MergeAttrs accepts another existing Attrs and merges the attributes into its own.
func (a *Attrs) MergeAttrs(attrs *Attrs) {
	if attrs == nil {
		return
	}
	for hash, val := range attrs.attrs {
		a.attrs[hash] = val
	}
}

func (a *Attrs) clone() *Attrs {
	attrs := NewAttrs()
	for hash, val := range a.attrs {
		attrs.attrs[hash] = val
	}
	return attrs
}

func (a *Attrs) SetAttr(key string, value interface{}) *Attrs {
	hash := getAttrHash(key)
	a.attrs[hash] = value
	return a
}

func (a *Attrs) GetAttr(key string) interface{} {
	return a.attrs[getAttrHash(key)]
}

func (a *Attrs) RemoveAttr(key string) {
	delete(a.attrs, getAttrHash(key))
}

func (a *Attrs) Attrs() map[string]interface{} {
	attrs := make(map[string]interface{})
	for hash, val := range a.attrs {
		key, _ := getHashAttr(hash)
		attrs[key] = val
	}
	return attrs
}

type logAttr struct {
	Name  string
	Value interface{}
}

var hashMutex sync.RWMutex
var attrHashes = make(map[string]uint32)
var hashAttrs = make(map[uint32]string)

func getAttrHash(attr string) uint32 {
	// First try to acquire a read lock to see if we even need to hash
	// the string at all
	hashMutex.RLock()
	if hash, ok := attrHashes[attr]; ok {
		hashMutex.RUnlock()
		return hash
	}

	// We do need to hash it so release the read lock and acquire a write lock
	hashMutex.RUnlock()

	hashMutex.Lock()
	defer hashMutex.Unlock()
	if hash, ok := attrHashes[attr]; ok {
		return hash
	}

	hasher := murmur3.New32()
	hasher.Write([]byte(attr))

	hash := hasher.Sum32()
	hashAttrs[hash] = attr
	attrHashes[attr] = hash

	return hash
}

func getHashAttr(hash uint32) (string, error) {
	hashMutex.RLock()
	defer hashMutex.RUnlock()

	if attr, ok := hashAttrs[hash]; ok {
		return attr, nil
	}

	return "", fmt.Errorf("Could not find attr for hash %v", hash)
}
<commit_msg>Add lock around attrs modifications<commit_after>package gomol

import (
	"github.com/spaolacci/murmur3"

	"fmt"
	"sync"
)

type Attrs struct {
	attrs     map[uint32]interface{}
	attrsLock sync.RWMutex
}

// NewAttrs will create a new Attrs struct with an empty set of attributes.
func NewAttrs() *Attrs {
	return &Attrs{
		attrs: make(map[uint32]interface{}),
	}
}

// NewAttrsFromMap will create a new Attrs struct with the given attributes pre-populated
func NewAttrsFromMap(attrs map[string]interface{}) *Attrs {
	newAttrs := NewAttrs()
	for attrKey, attrVal := range attrs {
		newAttrs.SetAttr(attrKey, attrVal)
	}
	return newAttrs
}

// MergeAttrs accepts another existing Attrs and merges the attributes into its own.
func (a *Attrs) MergeAttrs(attrs *Attrs) {
	if attrs == nil {
		return
	}
	a.attrsLock.Lock()
	defer a.attrsLock.Unlock()
	for hash, val := range attrs.attrs {
		a.attrs[hash] = val
	}
}

func (a *Attrs) clone() *Attrs {
	attrs := NewAttrs()
	for hash, val := range a.attrs {
		attrs.attrs[hash] = val
	}
	return attrs
}

func (a *Attrs) SetAttr(key string, value interface{}) *Attrs {
	a.attrsLock.Lock()
	defer a.attrsLock.Unlock()

	hash := getAttrHash(key)
	a.attrs[hash] = value
	return a
}

func (a *Attrs) GetAttr(key string) interface{} {
	a.attrsLock.RLock()
	defer a.attrsLock.RUnlock()

	return a.attrs[getAttrHash(key)]
}

func (a *Attrs) RemoveAttr(key string) {
	a.attrsLock.Lock()
	defer a.attrsLock.Unlock()

	delete(a.attrs, getAttrHash(key))
}

func (a *Attrs) Attrs() map[string]interface{} {
	a.attrsLock.RLock()
	defer a.attrsLock.RUnlock()

	attrs := make(map[string]interface{})
	for hash, val := range a.attrs {
		key, _ := getHashAttr(hash)
		attrs[key] = val
	}
	return attrs
}

type logAttr struct {
	Name  string
	Value interface{}
}

var hashMutex sync.RWMutex
var attrHashes = make(map[string]uint32)
var hashAttrs = make(map[uint32]string)

func getAttrHash(attr string) uint32 {
	// First try to acquire a read lock to see if we even need to hash
	// the string at all
	hashMutex.RLock()
	if hash, ok := attrHashes[attr]; ok {
		hashMutex.RUnlock()
		return hash
	}

	// We do need to hash it so release the read lock and acquire a write lock
	hashMutex.RUnlock()

	hashMutex.Lock()
	defer hashMutex.Unlock()
	if hash, ok := attrHashes[attr]; ok {
		return hash
	}

	hasher := murmur3.New32()
	hasher.Write([]byte(attr))

	hash := hasher.Sum32()
	hashAttrs[hash] = attr
	attrHashes[attr] = hash

	return hash
}

func getHashAttr(hash uint32) (string, error) {
	hashMutex.RLock()
	defer hashMutex.RUnlock()

	if attr, ok := hashAttrs[hash]; ok {
		return attr, nil
	}

	return "", fmt.Errorf("Could not find attr for hash %v", hash)
}
<|endoftext|>


<commit_before>package get_queue_attributes

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"strings"

	"github.com/vburenin/firempq/pqueue"
	"github.com/vburenin/firempq/server/sqsproto/sqs_response"
	"github.com/vburenin/firempq/server/sqsproto/urlutils"
)

type QAttr struct {
	Name  string      `xml:"Name"`
	Value interface{} `xml:"Value"`
}

type GetQueueAttributesResponse struct {
	XMLName    xml.Name `xml:"http://queue.amazonaws.com/doc/2012-11-05/ GetQueueAttributesResponse"`
	Attributes []*QAttr `xml:"GetQueueAttributesResult>Attribute,omitempty"`
	RequestId  string   `xml:"ResponseMetadata>RequestId"`
}

func (r *GetQueueAttributesResponse) HttpCode() int { return http.StatusOK }
func (r *GetQueueAttributesResponse) XmlDocument() string {
	return sqs_response.EncodeXml(r)
}
func (r *GetQueueAttributesResponse) BatchResult(docId string) interface{} { return nil }

const (
	AttrAll                                   = "All"
	AttrApproximateNumberOfMessages           = "ApproximateNumberOfMessages"
	AttrApproximateNumberOfMessagesNotVisible = "ApproximateNumberOfMessagesNotVisible"
	AttrApproximateNumberOfMessagesDelayed    = "ApproximateNumberOfMessagesDelayed"

	AttrVisibilityTimeout     = "VisibilityTimeout"
	AttrDelaySeconds          = "DelaySeconds"
	AttrCreatedTimestamp      = "CreatedTimestamp"
	AttrLastModifiedTimestamp = "LastModifiedTimestamp"

	AttrMaximumMessageSize            = "MaximumMessageSize"
	AttrMessageRetentionPeriod        = "MessageRetentionPeriod"
	AttrReceiveMessageWaitTimeSeconds = "ReceiveMessageWaitTimeSeconds"
	AttrQueueArn                      = "QueueArn"
	AttrRedrivePolicy                 = "RedrivePolicy"

	// Not used attribute.
	// AttrPolicy                                = "Policy"
)

func makeQueueArn(name string) string {
	return "arn:aws:sqs:us-west-2:123456789:" + name
}

func GetQueueAttributes(pq *pqueue.PQueue, sqsQuery *urlutils.SQSQuery) sqs_response.SQSResponse {

	paramsLen := len(sqsQuery.ParamsList) - 1

	pqCfg := pq.Config()
	pqDesc := pq.Description()

	resp := &GetQueueAttributesResponse{
		RequestId: "reqId",
	}
	for i := 0; i < paramsLen; i += 2 {
		allAttr := false
		if strings.HasPrefix(sqsQuery.ParamsList[i], "AttributeName.") {
			attrName := sqsQuery.ParamsList[i+1]
			if attrName == AttrAll {
				allAttr = true
				resp.Attributes = make([]*QAttr, 0, 13) // 13 total attributes
			}
			if allAttr || attrName == AttrApproximateNumberOfMessages {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrApproximateNumberOfMessages,
					Value: pq.Info().Size,
				})
			}
			if allAttr || attrName == AttrApproximateNumberOfMessagesNotVisible {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrApproximateNumberOfMessagesNotVisible,
					Value: pq.LockedCount(),
				})
			}
			if allAttr || attrName == AttrVisibilityTimeout {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrVisibilityTimeout,
					Value: pqCfg.PopLockTimeout / 1000,
				})
			}
			if allAttr || attrName == AttrCreatedTimestamp {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrCreatedTimestamp,
					Value: pqDesc.CreateTs / 1000,
				})
			}
			if allAttr || attrName == AttrLastModifiedTimestamp {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrLastModifiedTimestamp,
					Value: pqCfg.LastUpdateTs / 1000,
				})
			}
			if allAttr || attrName == AttrMaximumMessageSize {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrMaximumMessageSize,
					Value: pqCfg.MaxMsgSize,
				})
			}
			if allAttr || attrName == AttrMessageRetentionPeriod {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrMessageRetentionPeriod,
					Value: pqCfg.MsgTtl / 1000,
				})
			}
			if allAttr || attrName == AttrQueueArn {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrQueueArn,
					Value: makeQueueArn(pqDesc.Name),
				})
			}
			if allAttr || attrName == AttrApproximateNumberOfMessagesDelayed {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrApproximateNumberOfMessagesDelayed,
					Value: pq.DelayedCount(),
				})
			}
			if allAttr || attrName == AttrDelaySeconds {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrDelaySeconds,
					Value: pqCfg.DeliveryDelay / 1000,
				})
			}
			if allAttr || attrName == AttrReceiveMessageWaitTimeSeconds {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrReceiveMessageWaitTimeSeconds,
					Value: pqCfg.PopWaitTimeout / 1000,
				})
			}
			if allAttr || attrName == AttrRedrivePolicy {
				if pqCfg.PopLimitQueueName != "" {
					resp.Attributes = append(resp.Attributes, &QAttr{
						Name: AttrRedrivePolicy,
						Value: fmt.Sprintf(`{"deadLetterTargetArn":"%s","maxReceiveCount":%d}`,
							makeQueueArn(pqCfg.PopLimitQueueName), pqCfg.PopCountLimit),
					})
				}
			}

			if allAttr {
				break
			}
		}
	}
	return resp
}
<commit_msg>Adopted attribute name parser to handle wrong cases.<commit_after>package get_queue_attributes

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"strings"

	"github.com/vburenin/firempq/pqueue"
	"github.com/vburenin/firempq/server/sqsproto/sqs_response"
	"github.com/vburenin/firempq/server/sqsproto/urlutils"
)

type QAttr struct {
	Name  string      `xml:"Name"`
	Value interface{} `xml:"Value"`
}

type GetQueueAttributesResponse struct {
	XMLName    xml.Name `xml:"http://queue.amazonaws.com/doc/2012-11-05/ GetQueueAttributesResponse"`
	Attributes []*QAttr `xml:"GetQueueAttributesResult>Attribute,omitempty"`
	RequestId  string   `xml:"ResponseMetadata>RequestId"`
}

func (r *GetQueueAttributesResponse) HttpCode() int { return http.StatusOK }
func (r *GetQueueAttributesResponse) XmlDocument() string {
	return sqs_response.EncodeXml(r)
}
func (r *GetQueueAttributesResponse) BatchResult(docId string) interface{} { return nil }

const (
	AttrAll                                   = "All"
	AttrApproximateNumberOfMessages           = "ApproximateNumberOfMessages"
	AttrApproximateNumberOfMessagesNotVisible = "ApproximateNumberOfMessagesNotVisible"
	AttrApproximateNumberOfMessagesDelayed    = "ApproximateNumberOfMessagesDelayed"

	AttrVisibilityTimeout     = "VisibilityTimeout"
	AttrDelaySeconds          = "DelaySeconds"
	AttrCreatedTimestamp      = "CreatedTimestamp"
	AttrLastModifiedTimestamp = "LastModifiedTimestamp"

	AttrMaximumMessageSize            = "MaximumMessageSize"
	AttrMessageRetentionPeriod        = "MessageRetentionPeriod"
	AttrReceiveMessageWaitTimeSeconds = "ReceiveMessageWaitTimeSeconds"
	AttrQueueArn                      = "QueueArn"
	AttrRedrivePolicy                 = "RedrivePolicy"

	// Not used attribute.
	// AttrPolicy                                = "Policy"
)

func makeQueueArn(name string) string {
	return "arn:aws:sqs:us-west-2:123456789:" + name
}

func GetQueueAttributes(pq *pqueue.PQueue, sqsQuery *urlutils.SQSQuery) sqs_response.SQSResponse {
	paramsLen := len(sqsQuery.ParamsList) - 1

	pqCfg := pq.Config()
	pqDesc := pq.Description()

	resp := &GetQueueAttributesResponse{
		RequestId: "reqId",
	}

	for i := 0; i < paramsLen; i += 2 {
		allAttr := false
		if strings.HasPrefix(sqsQuery.ParamsList[i], "AttributeName") {
			attrName := sqsQuery.ParamsList[i+1]
			if attrName == AttrAll {
				allAttr = true
				resp.Attributes = make([]*QAttr, 0, 13) // 13 total attributes
			}
			if allAttr || attrName == AttrApproximateNumberOfMessages {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrApproximateNumberOfMessages,
					Value: pq.Info().Size,
				})
			}
			if allAttr || attrName == AttrApproximateNumberOfMessagesNotVisible {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrApproximateNumberOfMessagesNotVisible,
					Value: pq.LockedCount(),
				})
			}
			if allAttr || attrName == AttrVisibilityTimeout {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrVisibilityTimeout,
					Value: pqCfg.PopLockTimeout / 1000,
				})
			}
			if allAttr || attrName == AttrCreatedTimestamp {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrCreatedTimestamp,
					Value: pqDesc.CreateTs / 1000,
				})
			}
			if allAttr || attrName == AttrLastModifiedTimestamp {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrLastModifiedTimestamp,
					Value: pqCfg.LastUpdateTs / 1000,
				})
			}
			if allAttr || attrName == AttrMaximumMessageSize {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrMaximumMessageSize,
					Value: pqCfg.MaxMsgSize,
				})
			}
			if allAttr || attrName == AttrMessageRetentionPeriod {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrMessageRetentionPeriod,
					Value: pqCfg.MsgTtl / 1000,
				})
			}
			if allAttr || attrName == AttrQueueArn {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrQueueArn,
					Value: makeQueueArn(pqDesc.Name),
				})
			}
			if allAttr || attrName == AttrApproximateNumberOfMessagesDelayed {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrApproximateNumberOfMessagesDelayed,
					Value: pq.DelayedCount(),
				})
			}
			if allAttr || attrName == AttrDelaySeconds {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrDelaySeconds,
					Value: pqCfg.DeliveryDelay / 1000,
				})
			}
			if allAttr || attrName == AttrReceiveMessageWaitTimeSeconds {
				resp.Attributes = append(resp.Attributes, &QAttr{
					Name:  AttrReceiveMessageWaitTimeSeconds,
					Value: pqCfg.PopWaitTimeout / 1000,
				})
			}
			if allAttr || attrName == AttrRedrivePolicy {
				if pqCfg.PopLimitQueueName != "" {
					resp.Attributes = append(resp.Attributes, &QAttr{
						Name: AttrRedrivePolicy,
						Value: fmt.Sprintf(`{"deadLetterTargetArn":"%s","maxReceiveCount":%d}`,
							makeQueueArn(pqCfg.PopLimitQueueName), pqCfg.PopCountLimit),
					})
				}
			}

			if allAttr {
				break
			}
		}
	}
	return resp
}
<|endoftext|>


<commit_before>package siprocket

import "strings"

/*
 RFC 3261 - https://www.ietf.org/rfc/rfc3261.txt - 8.1.1.5 CSeq

  The CSeq header field serves as a way to identify and order
  transactions.  It consists of a sequence number and a method.  The
  method MUST match that of the request.

  Example:

     CSeq: 4711 INVITE

*/

type sipCseq struct {
	Id     []byte // Cseq ID
	Method []byte // Cseq Method
	Src    []byte // Full source if needed
}

func parseSipCseq(v []byte, out *sipCseq) {

	pos := 0
	state := 0

	// Init the output area
	out.Id = nil
	out.Method = nil
	out.Src = nil

	// Keep the source line if needed
	if keep_src {
		out.Src = v
	}

	// Loop through the bytes making up the line
	for pos < len(v) {
		// FSM
		//fmt.Println("POS:", pos, "CHR:", string(v[pos]), "STATE:", state)
		switch state {
		case FIELD_NULL:
			if strings.ToLower(string(v[pos:pos+5])) == "cseq:" {
				state = FIELD_BASE
				pos = pos + 5
				continue
			}

		case FIELD_BASE:
			if v[pos] == ' ' {
				state = FIELD_ID
				pos++
				continue
			}

		case FIELD_ID:
			if v[pos] == ' ' {
				state = FIELD_METHOD
				pos++
				continue
			}
			out.Id = append(out.Id, v[pos])

		case FIELD_METHOD:
			out.Method = append(out.Method, v[pos])
		}
		pos++
	}
}
<commit_msg>Update sipCseq.go<commit_after>package siprocket

import "strings"

/*
 RFC 3261 - https://www.ietf.org/rfc/rfc3261.txt - 8.1.1.5 CSeq

  The CSeq header field serves as a way to identify and order
  transactions.  It consists of a sequence number and a method.  The
  method MUST match that of the request.

  Example:

     CSeq: 4711 INVITE

*/

type sipCseq struct {
	Id     []byte // Cseq ID
	Method []byte // Cseq Method
	Src    []byte // Full source if needed
}

func parseSipCseq(v []byte, out *sipCseq) {

	pos := 0
	state := FIELD_BASE

	// Init the output area
	out.Id = nil
	out.Method = nil
	out.Src = nil

	// Keep the source line if needed
	if keep_src {
		out.Src = v
	}

	// Loop through the bytes making up the line
	for pos < len(v) {
		// FSM
		//fmt.Println("POS:", pos, "CHR:", string(v[pos]), "STATE:", state)
		switch state {
		case FIELD_BASE:
			if v[pos] == ' ' {
				state = FIELD_ID
				pos++
				continue
			}

		case FIELD_ID:
			if v[pos] == ' ' {
				state = FIELD_METHOD
				pos++
				continue
			}
			out.Id = append(out.Id, v[pos])

		case FIELD_METHOD:
			out.Method = append(out.Method, v[pos])
		}
		pos++
	}
}
<|endoftext|>


<commit_before>package somaproto

type Filter struct {
	Bucket      *BucketFilter      `json:"bucket, omitempty"`
	Capability  *CapabilityFilter  `json:"capability, omitempty"`
	CheckConfig *CheckConfigFilter `json:"checkConfig, omitempty"`
	Cluster     *ClusterFilter     `json:"cluster, omitempty"`
	Group       *GroupFilter       `json:"group, omitempty"`
	Metric      *MetricFilter      `json:"metric, omitempty"`
	Monitoring  *MonitoringFilter  `json:"monitoring, omitempty"`
	Node        *NodeFilter        `json:"node, omitempty"`
	Oncall      *OncallFilter      `json:"oncall, omitempty"`
	Property    *PropertyFilter    `json:"property, omitempty"`
	Provider    *ProviderFilter    `json:"provider, omitempty"`
	Repository  *RepositoryFilter  `json:"repository, omitempty"`
	Server      *ServerFilter      `json:"server, omitempty"`
	Team        *TeamFilter        `json:"team, omitempty"`
	Unit        *UnitFilter        `json:"unit, omitempty"`
	User        *UserFilter        `json:"user, omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Add missing Filter.Level field<commit_after>package somaproto

type Filter struct {
	Bucket      *BucketFilter      `json:"bucket, omitempty"`
	Capability  *CapabilityFilter  `json:"capability, omitempty"`
	CheckConfig *CheckConfigFilter `json:"checkConfig, omitempty"`
	Cluster     *ClusterFilter     `json:"cluster, omitempty"`
	Group       *GroupFilter       `json:"group, omitempty"`
	Level       *LevelFilter       `json:"level, omitempty"`
	Metric      *MetricFilter      `json:"metric, omitempty"`
	Monitoring  *MonitoringFilter  `json:"monitoring, omitempty"`
	Node        *NodeFilter        `json:"node, omitempty"`
	Oncall      *OncallFilter      `json:"oncall, omitempty"`
	Property    *PropertyFilter    `json:"property, omitempty"`
	Provider    *ProviderFilter    `json:"provider, omitempty"`
	Repository  *RepositoryFilter  `json:"repository, omitempty"`
	Server      *ServerFilter      `json:"server, omitempty"`
	Team        *TeamFilter        `json:"team, omitempty"`
	Unit        *UnitFilter        `json:"unit, omitempty"`
	User        *UserFilter        `json:"user, omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
)

var (
	//Trace logger
	Trace *log.Logger
	//Info logger for Info logs
	Info *log.Logger
	//Warning logger for warning logs
	Warning *log.Logger
	//Error logger for error logs
	Error *log.Logger
	// ifaceString
	output *string
)

func fetchAllIfaces() (*string, error) {
	result := "Hello World!\n"

	ifaces, err := net.Interfaces()
	if err != nil {
		return &result, err
	}

	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			return &result, err
		}

		for _, addr := range addrs {
			result = fmt.Sprint(result, addr.String()+"\n")
		}
	}

	return &result, nil
}

//Init all different logger
func Init(
	traceHandle io.Writer,
	infoHandle io.Writer,
	warningHandle io.Writer,
	errorHandle io.Writer) {

	Trace = log.New(traceHandle,
		"TRACE: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(infoHandle,
		"INFO: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Warning = log.New(warningHandle,
		"WARNING: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(errorHandle,
		"ERROR: ",
		log.Ldate|log.Ltime|log.Lshortfile)
}

func responseWithIPs(w http.ResponseWriter, r *http.Request) {
	Info.Printf("Got %q Request on %q", r.Method, r.Host)
	io.WriteString(w, "Hello my addresses are the following:\n")
	io.WriteString(w, *output)
}

func healthCheck(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Alive")
}

func main() {
	Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
	var err error
	output, err = fetchAllIfaces()
	if err != nil {
		log.Fatal(err)
	}

	Info.Println("Started")
	http.HandleFunc("/", responseWithIPs)
	http.HandleFunc("/health", healthCheck)
	http.ListenAndServe(":8000", nil)
}
<commit_msg>Test knative<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
)

var (
	//Trace logger
	Trace *log.Logger
	//Info logger for Info logs
	Info *log.Logger
	//Warning logger for warning logs
	Warning *log.Logger
	//Error logger for error logs
	Error *log.Logger
	// ifaceString
	output *string
)

func fetchAllIfaces() (*string, error) {
	result := "Hello Knative!!!\n"

	ifaces, err := net.Interfaces()
	if err != nil {
		return &result, err
	}

	for _, i := range ifaces {
		addrs, err := i.Addrs()
		if err != nil {
			return &result, err
		}

		for _, addr := range addrs {
			result = fmt.Sprint(result, addr.String()+"\n")
		}
	}

	return &result, nil
}

//Init all different logger
func Init(
	traceHandle io.Writer,
	infoHandle io.Writer,
	warningHandle io.Writer,
	errorHandle io.Writer) {

	Trace = log.New(traceHandle,
		"TRACE: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(infoHandle,
		"INFO: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Warning = log.New(warningHandle,
		"WARNING: ",
		log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(errorHandle,
		"ERROR: ",
		log.Ldate|log.Ltime|log.Lshortfile)
}

func responseWithIPs(w http.ResponseWriter, r *http.Request) {
	Info.Printf("Got %q Request on %q", r.Method, r.Host)
	io.WriteString(w, "Hello my addresses are the following:\n")
	io.WriteString(w, *output)
}

func healthCheck(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Alive")
}

func main() {
	Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
	var err error
	output, err = fetchAllIfaces()
	if err != nil {
		log.Fatal(err)
	}

	Info.Println("Started")
	http.HandleFunc("/", responseWithIPs)
	http.HandleFunc("/health", healthCheck)
	http.ListenAndServe(":8000", nil)
}
<|endoftext|>


<commit_before>package job

import (
	"errors"
	"fmt"
)

var (
	ErrUnknownJobType = errors.New("unknown job type")
	ErrJobNotFound    = errors.New("job not found")
	ErrNilJob         = errors.New("nil job")
	ErrConnectTimeout = errors.New("connect timeout")
	ErrRunTimeout     = errors.New("run timeout")
)

type ErrArgNotSet struct {
	Arg string
}

func (e ErrArgNotSet) Error() string {
	return fmt.Sprintf("%s not set in job args", e.Arg)
}

type ErrDataNotSet struct {
	Key string
}

func (e ErrDataNotSet) Error() string {
	return fmt.Sprintf("%s not set in job data", e.Key)
}
<commit_msg>Add job.ErrWrongDataType<commit_after>package job

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

var (
	ErrUnknownJobType = errors.New("unknown job type")
	ErrJobNotFound    = errors.New("job not found")
	ErrNilJob         = errors.New("nil job")
	ErrConnectTimeout = errors.New("connect timeout")
	ErrRunTimeout     = errors.New("run timeout")
)

type ErrArgNotSet struct {
	Arg string
}

func (e ErrArgNotSet) Error() string {
	return fmt.Sprintf("%s not set in job args", e.Arg)
}

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

type ErrDataNotSet struct {
	Key string
}

func (e ErrDataNotSet) Error() string {
	return fmt.Sprintf("%s not set in job data", e.Key)
}

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

type ErrWrongDataType struct {
	Key        string
	GotType    reflect.Type
	ExpectType reflect.Type
}

func NewErrWrongDataType(key string, got, expect interface{}) ErrWrongDataType {
	return ErrWrongDataType{
		Key:        key,
		GotType:    reflect.TypeOf(got),
		ExpectType: reflect.TypeOf(expect),
	}
}

func (e ErrWrongDataType) Error() string {
	return fmt.Sprintf("%s in job data is type %s, expected type %s", e.GotType, e.ExpectType)
}
<|endoftext|>


<commit_before>package job

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"os/exec"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/mattn/go-shellwords"
)

type JobRunner struct {
	job  *Job
	meta Metadata

	numberOfAttempts uint
	currentRetries   uint
	currentStat      *JobStat
}

var (
	ErrJobDisabled    = errors.New("Job cannot run, as it is disabled")
	ErrCmdIsEmpty     = errors.New("Job Command is empty.")
	ErrJobTypeInvalid = errors.New("Job Type is not valid.")
)

// Run calls the appropriate run function, collects metadata around the success
// or failure of the Job's execution, and schedules the next run.
func (j *JobRunner) Run(cache JobCache) (*JobStat, Metadata, error) {
	j.job.lock.RLock()
	defer j.job.lock.RUnlock()

	j.meta.LastAttemptedRun = time.Now()

	if j.job.Disabled {
		log.Infof("Job %s tried to run, but exited early because its disabled.", j.job.Name)
		return nil, j.meta, ErrJobDisabled
	}

	log.Infof("Job %s:%s started.", j.job.Name, j.job.Id)

	j.runSetup()

	for {
		var err error
		if j.job.JobType == LocalJob {
			err = j.LocalRun()
		} else if j.job.JobType == RemoteJob {
			err = j.RemoteRun()
		} else {
			err = ErrJobTypeInvalid
		}

		if err != nil {
			// Log Error in Metadata
			// TODO - Error Reporting, email error
			log.Errorln("Error running job:", j.currentStat.JobId)
			log.Errorln(err)

			j.meta.ErrorCount++
			j.meta.LastError = time.Now()

			// Handle retrying
			if j.shouldRetry() {
				j.currentRetries--
				continue
			}

			j.collectStats(false)
			j.meta.NumberOfFinishedRuns++

			// TODO: Wrap error into something better.
			return j.currentStat, j.meta, err
		} else {
			break
		}
	}

	log.Infof("Job %s:%s finished.", j.job.Name, j.job.Id)
	j.meta.SuccessCount++
	j.meta.NumberOfFinishedRuns++
	j.meta.LastSuccess = time.Now()

	j.collectStats(true)

	// Run Dependent Jobs
	if len(j.job.DependentJobs) != 0 {
		for _, id := range j.job.DependentJobs {
			newJob, err := cache.Get(id)
			if err != nil {
				log.Errorf("Error retrieving dependent job with id of %s", id)
			} else {
				newJob.Run(cache)
			}
		}
	}

	return j.currentStat, j.meta, nil
}

// LocalRun executes the Job's local shell command
func (j *JobRunner) LocalRun() error {
	return j.runCmd()
}

// RemoteRun sends a http request, and checks if the response is valid in time,
func (j *JobRunner) RemoteRun() error {
	// Calculate a response timeout
	timeout := j.responseTimeout()

	httpClient := http.Client{
		Timeout: timeout,
	}

	// Normalize the method passed by the user
	method := strings.ToUpper(j.job.RemoteProperties.Method)
	bodyBuffer := bytes.NewBufferString(j.job.RemoteProperties.Body)
	req, err := http.NewRequest(method, j.job.RemoteProperties.Url, bodyBuffer)
	if err != nil {
		return err
	}

	// Set default or user's passed headers
	j.setHeaders(req)

	// Do the request
	res, err := httpClient.Do(req)
	if err != nil {
		return err
	}

	// Check if we got any of the status codes the user asked for
	if j.checkExpected(res.StatusCode) {
		return nil
	} else {
		return errors.New(res.Status)
	}
}

func initShParser() *shellwords.Parser {
	shParser := shellwords.NewParser()
	shParser.ParseEnv = true
	shParser.ParseBacktick = true
	return shParser
}

func (j *JobRunner) runCmd() error {
	j.numberOfAttempts++

	// Execute command
	shParser := initShParser()
	args, err := shParser.Parse(j.job.Command)
	if err != nil {
		return err
	}
	if len(args) == 0 {
		return ErrCmdIsEmpty
	}

	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s: %s", err, strings.TrimSpace(string(out)))
	}
	return nil
}

func (j *JobRunner) shouldRetry() bool {
	// Check number of retries left
	if j.currentRetries == 0 {
		return false
	}

	// Check Epsilon
	if j.job.Epsilon != "" {
		if j.job.epsilonDuration.ToDuration() != 0 {
			timeSinceStart := time.Now().Sub(j.job.NextRunAt)
			timeLeftToRetry := j.job.epsilonDuration.ToDuration() - timeSinceStart
			if timeLeftToRetry < 0 {
				return false
			}
		}
	}

	return true
}

func (j *JobRunner) runSetup() {
	// Setup Job Stat
	j.currentStat = NewJobStat(j.job.Id)

	// Init retries
	j.currentRetries = j.job.Retries
}

func (j *JobRunner) collectStats(success bool) {
	j.currentStat.ExecutionDuration = time.Now().Sub(j.currentStat.RanAt)
	j.currentStat.Success = success
	j.currentStat.NumberOfRetries = j.job.Retries - j.currentRetries
}

func (j *JobRunner) checkExpected(statusCode int) bool {
	// If no expected response codes passed, add 200 status code as expected
	if len(j.job.RemoteProperties.ExpectedResponseCodes) == 0 {
		j.job.RemoteProperties.ExpectedResponseCodes = append(j.job.RemoteProperties.ExpectedResponseCodes, 200)
	}
	for _, expected := range j.job.RemoteProperties.ExpectedResponseCodes {
		if expected == statusCode {
			return true
		}
	}

	return false
}

// responseTimeout sets a default timeout if none specified
func (j *JobRunner) responseTimeout() time.Duration {
	responseTimeout := j.job.RemoteProperties.Timeout
	if responseTimeout == 0 {

		// set default to 30 seconds
		responseTimeout = 30
	}
	return time.Duration(responseTimeout) * time.Second
}

// setHeaders sets default and user specific headers to the http request
func (j *JobRunner) setHeaders(req *http.Request) {
	// A valid assumption is that the user is sending something in json cause we're past 2017
	if j.job.RemoteProperties.Headers["Content-Type"] == nil {
		jsonContentType := "application/json"

		// Set in the request header we are sending to remote host the newly header
		req.Header.Set("Content-Type", jsonContentType)

		// Create a new header for our job properties and set the default header
		j.job.RemoteProperties.Headers = http.Header{"Content-Type": []string{jsonContentType}}
	} else {
		req.Header = j.job.RemoteProperties.Headers
	}
}
<commit_msg>Fix #200<commit_after>package job

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"os/exec"
	"strings"
	"time"

	"github.com/mattn/go-shellwords"
	log "github.com/sirupsen/logrus"
)

type JobRunner struct {
	job  *Job
	meta Metadata

	numberOfAttempts uint
	currentRetries   uint
	currentStat      *JobStat
}

var (
	ErrJobDisabled    = errors.New("Job cannot run, as it is disabled")
	ErrCmdIsEmpty     = errors.New("Job Command is empty.")
	ErrJobTypeInvalid = errors.New("Job Type is not valid.")
)

// Run calls the appropriate run function, collects metadata around the success
// or failure of the Job's execution, and schedules the next run.
func (j *JobRunner) Run(cache JobCache) (*JobStat, Metadata, error) {
	j.job.lock.RLock()
	defer j.job.lock.RUnlock()

	j.meta.LastAttemptedRun = time.Now()

	if j.job.Disabled {
		log.Infof("Job %s tried to run, but exited early because its disabled.", j.job.Name)
		return nil, j.meta, ErrJobDisabled
	}

	log.Infof("Job %s:%s started.", j.job.Name, j.job.Id)

	j.runSetup()

	for {
		var err error
		if j.job.JobType == LocalJob {
			err = j.LocalRun()
		} else if j.job.JobType == RemoteJob {
			err = j.RemoteRun()
		} else {
			err = ErrJobTypeInvalid
		}

		if err != nil {
			// Log Error in Metadata
			// TODO - Error Reporting, email error
			log.Errorln("Error running job:", j.currentStat.JobId)
			log.Errorln(err)

			j.meta.ErrorCount++
			j.meta.LastError = time.Now()

			// Handle retrying
			if j.shouldRetry() {
				j.currentRetries--
				continue
			}

			j.collectStats(false)
			j.meta.NumberOfFinishedRuns++

			// TODO: Wrap error into something better.
			return j.currentStat, j.meta, err
		} else {
			break
		}
	}

	log.Infof("Job %s:%s finished.", j.job.Name, j.job.Id)
	j.meta.SuccessCount++
	j.meta.NumberOfFinishedRuns++
	j.meta.LastSuccess = time.Now()

	j.collectStats(true)

	// Run Dependent Jobs
	if len(j.job.DependentJobs) != 0 {
		for _, id := range j.job.DependentJobs {
			newJob, err := cache.Get(id)
			if err != nil {
				log.Errorf("Error retrieving dependent job with id of %s", id)
			} else {
				newJob.Run(cache)
			}
		}
	}

	return j.currentStat, j.meta, nil
}

// LocalRun executes the Job's local shell command
func (j *JobRunner) LocalRun() error {
	return j.runCmd()
}

// RemoteRun sends a http request, and checks if the response is valid in time,
func (j *JobRunner) RemoteRun() error {
	// Calculate a response timeout
	timeout := j.responseTimeout()

	httpClient := http.Client{
		Timeout: timeout,
	}

	// Normalize the method passed by the user
	method := strings.ToUpper(j.job.RemoteProperties.Method)
	bodyBuffer := bytes.NewBufferString(j.job.RemoteProperties.Body)
	req, err := http.NewRequest(method, j.job.RemoteProperties.Url, bodyBuffer)
	if err != nil {
		return err
	}

	// Set default or user's passed headers
	j.setHeaders(req)

	// Do the request
	res, err := httpClient.Do(req)
	if err != nil {
		return err
	}

	// Check if we got any of the status codes the user asked for
	if j.checkExpected(res.StatusCode) {
		return nil
	} else {
		return errors.New(res.Status)
	}
}

func initShParser() *shellwords.Parser {
	shParser := shellwords.NewParser()
	shParser.ParseEnv = true
	shParser.ParseBacktick = true
	return shParser
}

func (j *JobRunner) runCmd() error {
	j.numberOfAttempts++

	// Execute command
	shParser := initShParser()
	args, err := shParser.Parse(j.job.Command)
	if err != nil {
		return err
	}
	if len(args) == 0 {
		return ErrCmdIsEmpty
	}

	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s: %s", err, strings.TrimSpace(string(out)))
	}
	return nil
}

func (j *JobRunner) shouldRetry() bool {
	// Check number of retries left
	if j.currentRetries == 0 {
		return false
	}

	// Check Epsilon
	if j.job.Epsilon != "" && j.job.Schedule != "" {
		if j.job.epsilonDuration.ToDuration() != 0 {
			timeSinceStart := time.Now().Sub(j.job.NextRunAt)
			timeLeftToRetry := j.job.epsilonDuration.ToDuration() - timeSinceStart
			if timeLeftToRetry < 0 {
				return false
			}
		}
	}

	return true
}

func (j *JobRunner) runSetup() {
	// Setup Job Stat
	j.currentStat = NewJobStat(j.job.Id)

	// Init retries
	j.currentRetries = j.job.Retries
}

func (j *JobRunner) collectStats(success bool) {
	j.currentStat.ExecutionDuration = time.Now().Sub(j.currentStat.RanAt)
	j.currentStat.Success = success
	j.currentStat.NumberOfRetries = j.job.Retries - j.currentRetries
}

func (j *JobRunner) checkExpected(statusCode int) bool {
	// If no expected response codes passed, add 200 status code as expected
	if len(j.job.RemoteProperties.ExpectedResponseCodes) == 0 {
		j.job.RemoteProperties.ExpectedResponseCodes = append(j.job.RemoteProperties.ExpectedResponseCodes, 200)
	}
	for _, expected := range j.job.RemoteProperties.ExpectedResponseCodes {
		if expected == statusCode {
			return true
		}
	}

	return false
}

// responseTimeout sets a default timeout if none specified
func (j *JobRunner) responseTimeout() time.Duration {
	responseTimeout := j.job.RemoteProperties.Timeout
	if responseTimeout == 0 {

		// set default to 30 seconds
		responseTimeout = 30
	}
	return time.Duration(responseTimeout) * time.Second
}

// setHeaders sets default and user specific headers to the http request
func (j *JobRunner) setHeaders(req *http.Request) {
	// A valid assumption is that the user is sending something in json cause we're past 2017
	if j.job.RemoteProperties.Headers["Content-Type"] == nil {
		jsonContentType := "application/json"

		// Set in the request header we are sending to remote host the newly header
		req.Header.Set("Content-Type", jsonContentType)

		// Create a new header for our job properties and set the default header
		j.job.RemoteProperties.Headers = http.Header{"Content-Type": []string{jsonContentType}}
	} else {
		req.Header = j.job.RemoteProperties.Headers
	}
}
<|endoftext|>


<commit_before>// helper.go
// Helper routines for tinkerforge
// Author: Tim Scheuermann (https://github.com/noxer)
//
// License:
// Copyright (c) 2014, Tim Scheuermann
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package helpers

import (
	"fmt"
	"strings"

	"github.com/noxer/tinkerforge"
)

type Version [3]byte

func NewVersion(main, sub, patch byte) Version {
	return Version{main, sub, patch}
}

func (v Version) String() string {
	return fmt.Sprintf("%d.%d.%d", v[0], v[1], v[2])
}

var (
	DeviceIdentifiers = map[uint16]string{
		11:  "Brick DC",
		13:  "Brick Master",
		14:  "Brick Servo",
		15:  "Brick Stepper",
		16:  "Brick IMU",
		17:  "Brick RED",
		21:  "Bricklet Ambient Light",
		23:  "Bricklet Current12",
		24:  "Bricklet Current25",
		25:  "Bricklet Distance IR",
		26:  "Bricklet Dual Relay",
		27:  "Bricklet Humidity",
		28:  "Bricklet IO-16",
		29:  "Bricklet IO-4",
		210: "Bricklet Joystick",
		211: "Bricklet LCD 16x2",
		212: "Bricklet LCD 20x4",
		213: "Bricklet Linear Poti",
		214: "Bricklet Piezo Buzzer",
		215: "Bricklet Rotary Poti",
		216: "Bricklet Temperature",
		217: "Bricklet Temperature IR",
		218: "Bricklet Voltage",
		219: "Bricklet Analog In",
		220: "Bricklet Analog Out",
		221: "Bricklet Barometer",
		222: "Bricklet GPS",
		223: "Bricklet Industrial Digital In 4",
		224: "Bricklet Industrial Digital Out 4",
		225: "Bricklet Industrial Quad Relay",
		226: "Bricklet PTC",
		227: "Bricklet Voltage/Current",
		228: "Bricklet Industrial Dual 0-20mA",
		229: "Bricklet Distance US",
		230: "Bricklet Dual Button",
		231: "Bricklet LED Strip",
		232: "Bricklet Moisture",
		233: "Bricklet Motion Detector",
		234: "Bricklet Multi Touch",
		235: "Bricklet Remote Switch",
		236: "Bricklet Rotary Encoder",
		237: "Bricklet Segment Display 4x7",
		238: "Bricklet Sound Intensity",
		239: "Bricklet Tilt",
		240: "Bricklet Hall Effect",
		241: "Bricklet Line",
		242: "Bricklet Piezo Speaker",
		243: "Bricklet Color",
		244: "Bricklet Solid State Relay",
		245: "Bricklet Heart Rate",
		246: "Bricklet NFC/RFID",
	}
)

// Provides identity inforation for a bricklet
type BrickletIdentity struct {
	UID              string
	ConnectedUID     string
	Position         byte
	HardwareVersion  Version
	FirmwareVersion  Version
	DeviceIdentifier uint16
}

func GetIdenitity(t tinkerforge.Tinkerforge, uid uint32) (*BrickletIdentity, error) {

	p, err := tinkerforge.NewPacket(uid, 255, true)
	if err != nil {
		return nil, err
	}

	res, err := t.Send(p)
	if err != nil {
		return nil, err
	}

	i := &BrickletIdentity{}
	displayUID := make([]byte, 8)
	connectedDisplayUID := make([]byte, 8)

	if err = res.Decode(&displayUID, &connectedDisplayUID, &i.Position, &i.HardwareVersion, &i.FirmwareVersion, &i.DeviceIdentifier); err != nil {
		return nil, err
	}

	i.UID = strings.TrimSpace(string(displayUID))
	i.ConnectedUID = strings.TrimSpace(string(connectedDisplayUID))

	return i, nil
}

func (i *BrickletIdentity) DeviceName() string {
	return DeviceIdentifiers[i.DeviceIdentifier]
}
<commit_msg>Update helpers.go<commit_after>// helper.go
// Helper routines for tinkerforge
// Author: Tim Scheuermann (https://github.com/noxer)
//
// License:
// Copyright (c) 2014, Tim Scheuermann
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package helpers

import (
	"fmt"
	"strings"

	"github.com/noxer/tinkerforge"
)

type Version [3]byte

func NewVersion(main, sub, patch byte) Version {
	return Version{main, sub, patch}
}

func (v Version) String() string {
	return fmt.Sprintf("%d.%d.%d", v[0], v[1], v[2])
}

var (
	DeviceIdentifiers = map[uint16]string{
		11:  "Brick DC",
		13:  "Brick Master",
		14:  "Brick Servo",
		15:  "Brick Stepper",
		16:  "Brick IMU",
		17:  "Brick RED",
		21:  "Bricklet Ambient Light",
		23:  "Bricklet Current12",
		24:  "Bricklet Current25",
		25:  "Bricklet Distance IR",
		26:  "Bricklet Dual Relay",
		27:  "Bricklet Humidity",
		28:  "Bricklet IO-16",
		29:  "Bricklet IO-4",
		210: "Bricklet Joystick",
		211: "Bricklet LCD 16x2",
		212: "Bricklet LCD 20x4",
		213: "Bricklet Linear Poti",
		214: "Bricklet Piezo Buzzer",
		215: "Bricklet Rotary Poti",
		216: "Bricklet Temperature",
		217: "Bricklet Temperature IR",
		218: "Bricklet Voltage",
		219: "Bricklet Analog In",
		220: "Bricklet Analog Out",
		221: "Bricklet Barometer",
		222: "Bricklet GPS",
		223: "Bricklet Industrial Digital In 4",
		224: "Bricklet Industrial Digital Out 4",
		225: "Bricklet Industrial Quad Relay",
		226: "Bricklet PTC",
		227: "Bricklet Voltage/Current",
		228: "Bricklet Industrial Dual 0-20mA",
		229: "Bricklet Distance US",
		230: "Bricklet Dual Button",
		231: "Bricklet LED Strip",
		232: "Bricklet Moisture",
		233: "Bricklet Motion Detector",
		234: "Bricklet Multi Touch",
		235: "Bricklet Remote Switch",
		236: "Bricklet Rotary Encoder",
		237: "Bricklet Segment Display 4x7",
		238: "Bricklet Sound Intensity",
		239: "Bricklet Tilt",
		240: "Bricklet Hall Effect",
		241: "Bricklet Line",
		242: "Bricklet Piezo Speaker",
		243: "Bricklet Color",
		244: "Bricklet Solid State Relay",
		245: "Bricklet Heart Rate",
		246: "Bricklet NFC/RFID",
	}
)

// Provides identity information for a bricklet
type BrickletIdentity struct {
	UID              string
	ConnectedUID     string
	Position         byte
	HardwareVersion  Version
	FirmwareVersion  Version
	DeviceIdentifier uint16
}

func GetIdenitity(t tinkerforge.Tinkerforge, uid uint32) (*BrickletIdentity, error) {

	p, err := tinkerforge.NewPacket(uid, 255, true)
	if err != nil {
		return nil, err
	}

	res, err := t.Send(p)
	if err != nil {
		return nil, err
	}

	i := &BrickletIdentity{}
	displayUID := make([]byte, 8)
	connectedDisplayUID := make([]byte, 8)

	if err = res.Decode(&displayUID, &connectedDisplayUID, &i.Position, &i.HardwareVersion, &i.FirmwareVersion, &i.DeviceIdentifier); err != nil {
		return nil, err
	}

	i.UID = strings.TrimSpace(string(displayUID))
	i.ConnectedUID = strings.TrimSpace(string(connectedDisplayUID))

	return i, nil
}

func (i *BrickletIdentity) DeviceName() string {
	return DeviceIdentifiers[i.DeviceIdentifier]
}
<|endoftext|>