<commit_before>/*
Copyright 2018 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 config

import (
	"fmt"
	"io/ioutil"
	"math"
	"math/rand"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
	"time"

	"gopkg.in/yaml.v2"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

// GetFuncs returns map of names to functions, that are supported by template provider.
func GetFuncs() template.FuncMap {
	return template.FuncMap{
		"AddFloat":      addFloat,
		"AddInt":        addInt,
		"DefaultParam":  defaultParam,
		"DivideFloat":   divideFloat,
		"DivideInt":     divideInt,
		"IfThenElse":    ifThenElse,
		"IncludeFile":   includeFile,
		"MaxFloat":      maxFloat,
		"MaxInt":        maxInt,
		"MinFloat":      minFloat,
		"MinInt":        minInt,
		"Mod":           mod,
		"MultiplyFloat": multiplyFloat,
		"MultiplyInt":   multiplyInt,
		"RandInt":       randInt,
		"RandIntRange":  randIntRange,
		"Seq":           seq,
		"SubtractFloat": subtractFloat,
		"SubtractInt":   subtractInt,
		"YamlQuote":     yamlQuote,
	}
}

func seq(size interface{}) []int {
	return make([]int, int(toFloat64(size)))
}

func toFloat64(val interface{}) float64 {
	switch i := val.(type) {
	case float64:
		return i
	case float32:
		return float64(i)
	case int64:
		return float64(i)
	case int32:
		return float64(i)
	case int:
		return float64(i)
	case uint64:
		return float64(i)
	case uint32:
		return float64(i)
	case uint:
		return float64(i)
	case string:
		f, err := strconv.ParseFloat(i, 64)
		if err == nil {
			return f
		}
	}
	panic(fmt.Sprintf("cannot cast %v to float64", val))
}

// randInt returns pseudo-random int in [0, i].
func randInt(i interface{}) int {
	typedI := int(toFloat64(i))
	return rand.Intn(typedI + 1)
}

// randIntRange returns pseudo-random int in [i, j].
// If i >= j then i is returned.
func randIntRange(i, j interface{}) int {
	typedI := int(toFloat64(i))
	typedJ := int(toFloat64(j))
	if typedI >= typedJ {
		return typedI
	}
	return typedI + rand.Intn(typedJ-typedI+1)
}

func addInt(numbers ...interface{}) int {
	return int(addFloat(numbers...))
}

func subtractInt(i, j interface{}) int {
	return int(subtractFloat(i, j))
}

func multiplyInt(numbers ...interface{}) int {
	return int(multiplyFloat(numbers...))
}

func divideInt(i, j interface{}) int {
	return int(divideFloat(i, j))
}

func addFloat(numbers ...interface{}) float64 {
	sum := 0.0
	for _, number := range numbers {
		sum += toFloat64(number)
	}
	return sum
}

func subtractFloat(i, j interface{}) float64 {
	typedI := toFloat64(i)
	typedJ := toFloat64(j)
	return typedI - typedJ
}

func multiplyFloat(numbers ...interface{}) float64 {
	product := 1.0
	for _, number := range numbers {
		product *= toFloat64(number)
	}
	return product
}

func divideFloat(i, j interface{}) float64 {
	typedI := toFloat64(i)
	typedJ := toFloat64(j)
	if typedJ == 0 {
		panic("division by zero")
	}
	return typedI / typedJ
}

func maxInt(numbers ...interface{}) int {
	return int(maxFloat(numbers...))
}

func minInt(numbers ...interface{}) int {
	return int(minFloat(numbers...))
}

func maxFloat(numbers ...interface{}) float64 {
	if len(numbers) == 0 {
		panic("maximum undefined")
	}
	max := toFloat64(numbers[0])
	for _, number := range numbers {
		max = math.Max(max, toFloat64(number))
	}
	return max
}

func minFloat(numbers ...interface{}) float64 {
	if len(numbers) == 0 {
		panic("minimum undefined")
	}
	min := toFloat64(numbers[0])
	for _, number := range numbers {
		min = math.Min(min, toFloat64(number))
	}
	return min
}

func mod(a interface{}, b interface{}) int {
	return int(toFloat64(a)) % int(toFloat64(b))
}

func defaultParam(param, defaultValue interface{}) interface{} {
	if param == nil {
		return defaultValue
	}
	return param
}

// includeFile reads file. 'file' is relative to ./clusterloader2 binary.
func includeFile(file interface{}) (string, error) {
	fileStr, ok := file.(string)
	if !ok {
		return "", fmt.Errorf("incorrect argument type: got: %T want: string", file)
	}

	ex, err := os.Executable()
	if err != nil {
		return "", fmt.Errorf("unable to determine executable path: %v", err)
	}

	path := filepath.Join(filepath.Dir(ex), fileStr)
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", fmt.Errorf("unable to read file: %v", err)
	}
	return string(data), nil
}

// yamlQuote quotes yaml string aligning each output lin by tabsInt.
func yamlQuote(strInt interface{}, tabsInt interface{}) (string, error) {
	str, ok := strInt.(string)
	if !ok {
		return "", fmt.Errorf("incorrect argument type: got: %T want: string", strInt)
	}
	tabs, ok := tabsInt.(int)
	if !ok {
		return "", fmt.Errorf("incorrect argument type: got: %T want: int", tabsInt)
	}
	tabsStr := strings.Repeat("  ", tabs)
	b, err := yaml.Marshal(&str)
	// TODO(oxddr): change back to strings.ReplaceAll once we figure out how to compile clusterloader2
	// with newer versions of go for tests against stable version of K8s
	return strings.Replace(string(b), "\n", "\n"+tabsStr, -1), err
}

func ifThenElse(conditionVal interface{}, thenVal interface{}, elseVal interface{}) (interface{}, error) {
	condition, ok := conditionVal.(bool)
	if !ok {
		return nil, fmt.Errorf("incorrect argument type: got: %T want: bool", conditionVal)
	}
	if condition {
		return thenVal, nil
	}
	return elseVal, nil
}
<commit_msg>[ClusterLoader2] change slice related Go template functions<commit_after>/*
Copyright 2018 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 config

import (
	"fmt"
	"io/ioutil"
	"math"
	"math/rand"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
	"time"

	"gopkg.in/yaml.v2"
	"k8s.io/klog"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

// GetFuncs returns map of names to functions, that are supported by template provider.
func GetFuncs() template.FuncMap {
	return template.FuncMap{
		"AddFloat":      addFloat,
		"AddInt":        addInt,
		"DefaultParam":  defaultParam,
		"DivideFloat":   divideFloat,
		"DivideInt":     divideInt,
		"IfThenElse":    ifThenElse,
		"IncludeFile":   includeFile,
		"Loop":          loop,
		"MaxFloat":      maxFloat,
		"MaxInt":        maxInt,
		"MinFloat":      minFloat,
		"MinInt":        minInt,
		"Mod":           mod,
		"MultiplyFloat": multiplyFloat,
		"MultiplyInt":   multiplyInt,
		"RandInt":       randInt,
		"RandIntRange":  randIntRange,
		"Seq":           seq,
		"SliceOfZeros":  sliceOfZeros,
		"SubtractFloat": subtractFloat,
		"SubtractInt":   subtractInt,
		"YamlQuote":     yamlQuote,
	}
}

// seq returns a slice of size 'size' filled with zeros.
// Deprecated: Naming generates confusion. Please use 'SliceOfZeros' for explicit zero values or 'Loop' for.
func seq(size interface{}) []int {
	klog.Warningf("Seq is deprecated. Instead please use 'SliceOfZeros' to replicate current behaviour or 'Loop' for simple incremential integer generation.")
	return sliceOfZeros(size)
}

func toFloat64(val interface{}) float64 {
	switch i := val.(type) {
	case float64:
		return i
	case float32:
		return float64(i)
	case int64:
		return float64(i)
	case int32:
		return float64(i)
	case int:
		return float64(i)
	case uint64:
		return float64(i)
	case uint32:
		return float64(i)
	case uint:
		return float64(i)
	case string:
		f, err := strconv.ParseFloat(i, 64)
		if err == nil {
			return f
		}
	}
	panic(fmt.Sprintf("cannot cast %v to float64", val))
}

// randInt returns pseudo-random int in [0, i].
func randInt(i interface{}) int {
	typedI := int(toFloat64(i))
	return rand.Intn(typedI + 1)
}

// randIntRange returns pseudo-random int in [i, j].
// If i >= j then i is returned.
func randIntRange(i, j interface{}) int {
	typedI := int(toFloat64(i))
	typedJ := int(toFloat64(j))
	if typedI >= typedJ {
		return typedI
	}
	return typedI + rand.Intn(typedJ-typedI+1)
}

func addInt(numbers ...interface{}) int {
	return int(addFloat(numbers...))
}

func subtractInt(i, j interface{}) int {
	return int(subtractFloat(i, j))
}

func multiplyInt(numbers ...interface{}) int {
	return int(multiplyFloat(numbers...))
}

func divideInt(i, j interface{}) int {
	return int(divideFloat(i, j))
}

func addFloat(numbers ...interface{}) float64 {
	sum := 0.0
	for _, number := range numbers {
		sum += toFloat64(number)
	}
	return sum
}

func subtractFloat(i, j interface{}) float64 {
	typedI := toFloat64(i)
	typedJ := toFloat64(j)
	return typedI - typedJ
}

func multiplyFloat(numbers ...interface{}) float64 {
	product := 1.0
	for _, number := range numbers {
		product *= toFloat64(number)
	}
	return product
}

func divideFloat(i, j interface{}) float64 {
	typedI := toFloat64(i)
	typedJ := toFloat64(j)
	if typedJ == 0 {
		panic("division by zero")
	}
	return typedI / typedJ
}

func maxInt(numbers ...interface{}) int {
	return int(maxFloat(numbers...))
}

func minInt(numbers ...interface{}) int {
	return int(minFloat(numbers...))
}

func maxFloat(numbers ...interface{}) float64 {
	if len(numbers) == 0 {
		panic("maximum undefined")
	}
	max := toFloat64(numbers[0])
	for _, number := range numbers {
		max = math.Max(max, toFloat64(number))
	}
	return max
}

func minFloat(numbers ...interface{}) float64 {
	if len(numbers) == 0 {
		panic("minimum undefined")
	}
	min := toFloat64(numbers[0])
	for _, number := range numbers {
		min = math.Min(min, toFloat64(number))
	}
	return min
}

func mod(a interface{}, b interface{}) int {
	return int(toFloat64(a)) % int(toFloat64(b))
}

func defaultParam(param, defaultValue interface{}) interface{} {
	if param == nil {
		return defaultValue
	}
	return param
}

// includeFile reads file. 'file' is relative to ./clusterloader2 binary.
func includeFile(file interface{}) (string, error) {
	fileStr, ok := file.(string)
	if !ok {
		return "", fmt.Errorf("incorrect argument type: got: %T want: string", file)
	}

	ex, err := os.Executable()
	if err != nil {
		return "", fmt.Errorf("unable to determine executable path: %v", err)
	}

	path := filepath.Join(filepath.Dir(ex), fileStr)
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", fmt.Errorf("unable to read file: %v", err)
	}
	return string(data), nil
}

// yamlQuote quotes yaml string aligning each output lin by tabsInt.
func yamlQuote(strInt interface{}, tabsInt interface{}) (string, error) {
	str, ok := strInt.(string)
	if !ok {
		return "", fmt.Errorf("incorrect argument type: got: %T want: string", strInt)
	}
	tabs, ok := tabsInt.(int)
	if !ok {
		return "", fmt.Errorf("incorrect argument type: got: %T want: int", tabsInt)
	}
	tabsStr := strings.Repeat("  ", tabs)
	b, err := yaml.Marshal(&str)
	// TODO(oxddr): change back to strings.ReplaceAll once we figure out how to compile clusterloader2
	// with newer versions of go for tests against stable version of K8s
	return strings.Replace(string(b), "\n", "\n"+tabsStr, -1), err
}

func ifThenElse(conditionVal interface{}, thenVal interface{}, elseVal interface{}) (interface{}, error) {
	condition, ok := conditionVal.(bool)
	if !ok {
		return nil, fmt.Errorf("incorrect argument type: got: %T want: bool", conditionVal)
	}
	if condition {
		return thenVal, nil
	}
	return elseVal, nil
}

// sliceOfZeros returns a slice of a constant size all filed with zero.
//
// In-place replacement for deprecated 'Seq'.
func sliceOfZeros(size interface{}) []int {
	return make([]int, int(toFloat64(size)))
}

// loop returns a slice with incremential values starting from zero.
func loop(size interface{}) []int {
	sizeInt := int(toFloat64(size))
	slice := make([]int, sizeInt)
	for i := range slice {
		slice[i] = i
	}
	return slice
}
<|endoftext|>


<commit_before>// Copyright 2009 Thomas Jager <mail@jager.no>  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package irc

import (
	"crypto/tls"
	"log"
	"net"
	"sync"
	"time"
)

type Connection struct {
	sync.WaitGroup
	Debug     bool
	Error     chan error
	Password  string
	UseTLS    bool
	TLSConfig *tls.Config
	Version   string
	Timeout   time.Duration
	PingFreq  time.Duration
	KeepAlive time.Duration
	Server      string

	socket net.Conn
	pwrite chan string
	end    chan struct{}

	nick        string //The nickname we want.
	nickcurrent string //The nickname we currently have.
	user        string
	registered  bool
	events      map[string]map[string]func(*Event)

	lastMessage time.Time

	VerboseCallbackHandler bool
	Log                    *log.Logger

	stopped bool
}

// A struct to represent an event.
type Event struct {
	Code       string
	Raw        string
	Nick       string //<nick>
	Host       string //<nick>!<usr>@<host>
	Source     string //<host>
	User       string //<usr>
	Arguments  []string
	Connection *Connection
}

// Retrieve the last message from Event arguments.
// This function  leaves the arguments untouched and
// returns an empty string if there are none.
func (e *Event) Message() string {
	if len(e.Arguments) == 0 {
		return ""
	}
	return e.Arguments[len(e.Arguments)-1]
}
<commit_msg>Fix ident<commit_after>// Copyright 2009 Thomas Jager <mail@jager.no>  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package irc

import (
	"crypto/tls"
	"log"
	"net"
	"sync"
	"time"
)

type Connection struct {
	sync.WaitGroup
	Debug     bool
	Error     chan error
	Password  string
	UseTLS    bool
	TLSConfig *tls.Config
	Version   string
	Timeout   time.Duration
	PingFreq  time.Duration
	KeepAlive time.Duration
	Server    string

	socket net.Conn
	pwrite chan string
	end    chan struct{}

	nick        string //The nickname we want.
	nickcurrent string //The nickname we currently have.
	user        string
	registered  bool
	events      map[string]map[string]func(*Event)

	lastMessage time.Time

	VerboseCallbackHandler bool
	Log                    *log.Logger

	stopped bool
}

// A struct to represent an event.
type Event struct {
	Code       string
	Raw        string
	Nick       string //<nick>
	Host       string //<nick>!<usr>@<host>
	Source     string //<host>
	User       string //<usr>
	Arguments  []string
	Connection *Connection
}

// Retrieve the last message from Event arguments.
// This function  leaves the arguments untouched and
// returns an empty string if there are none.
func (e *Event) Message() string {
	if len(e.Arguments) == 0 {
		return ""
	}
	return e.Arguments[len(e.Arguments)-1]
}
<|endoftext|>


<commit_before>package myaws

import (
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/pkg/errors"
)

// AutoScalingSetInstanceProtectionOptions customizes the behavior of the Attach command.
type AutoScalingSetInstanceProtectionOptions struct {
	AsgName              string
	InstanceIds          []*string
	ProtectedFromScaleIn bool
}

// AutoScalingSetInstanceProtection protects from termination when scale in your autoscaling group.
func (client *Client) AutoScalingSetInstanceProtection(options AutoScalingSetInstanceProtectionOptions) error {
	if len(options.InstanceIds) > 0 {
		if err := client.autoScalingSetInstanceProtectionInstances(options.AsgName, options.InstanceIds, options.ProtectedFromScaleIn); err != nil {
			return err
		}
	}
	return nil
}

func (client *Client) autoScalingSetInstanceProtectionInstances(asgName string, instanceIds []*string, protectedFromScaleIn bool) error {
	params := &autoscaling.SetInstanceProtectionInput{
		AutoScalingGroupName: &asgName,
		InstanceIds:          instanceIds,
		ProtectedFromScaleIn: &protectedFromScaleIn,
	}

	if _, err := client.AutoScaling.SetInstanceProtection(params); err != nil {
		return errors.Wrap(err, "SetInstanceProtection failed:")
	}

	return nil
}
<commit_msg>set AutoScalingInstanceProtection every 19 instances.<commit_after>package myaws

import (
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/pkg/errors"
	"math"
)

// AutoScalingSetInstanceProtectionOptions customizes the behavior of the Attach command.
type AutoScalingSetInstanceProtectionOptions struct {
	AsgName              string
	InstanceIds          []*string
	ProtectedFromScaleIn bool
}

// AutoScalingSetInstanceProtection protects from termination when scale in your autoscaling group.
func (client *Client) AutoScalingSetInstanceProtection(options AutoScalingSetInstanceProtectionOptions) error {
	// the number of maximum InstanceIds is limited to 19.
	// https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_SetInstanceProtection.html
	maxInstanceIDCount := 19
	var maxIteration = int(math.Ceil(float64(len(options.InstanceIds)) / float64(maxInstanceIDCount)))
	for i := 0; i < maxIteration; i++ { // set AutoScalingInstanceProtection every 19 instances.
		firstIndex := maxInstanceIDCount * i
		lastIndex := maxInstanceIDCount * (i + 1)
		if i == maxIteration-1 { // last iteration
			lastIndex = len(options.InstanceIds)
		}
		instanceIds := options.InstanceIds[firstIndex:lastIndex]
		if err := client.autoScalingSetInstanceProtectionInstances(options.AsgName, instanceIds, options.ProtectedFromScaleIn); err != nil {
			return err
		}
	}
	return nil
}

func (client *Client) autoScalingSetInstanceProtectionInstances(asgName string, instanceIds []*string, protectedFromScaleIn bool) error {
	params := &autoscaling.SetInstanceProtectionInput{
		AutoScalingGroupName: &asgName,
		InstanceIds:          instanceIds,
		ProtectedFromScaleIn: &protectedFromScaleIn,
	}

	if _, err := client.AutoScaling.SetInstanceProtection(params); err != nil {
		return errors.Wrap(err, "SetInstanceProtection failed:")
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 The Go Cloud 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
//
//     https://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 azureblob_test

import (
	"context"
	"io"

	"github.com/Azure/azure-storage-blob-go/azblob"
	"gocloud.dev/blob"
	"gocloud.dev/blob/azureblob"
)

func Example() {
	ctx := context.Background()

	accountName, accountKey := "", ""
	bucketName := "my-bucket"
	key := "my-file.json"

	// Initializes an azblob.ServiceURL which represents the Azure Storage Account using Shared Key authorization
	serviceURL, _ := azureblob.ServiceURLFromAccountKey(accountName, accountKey)

	// Credential represents the authorizer for SignedURL
	creds, _ := azblob.NewSharedKeyCredential(accountName, accountKey)
	azureOpts := azureblob.Options{
		Credential: creds,
	}

	// Creates a *blob.Bucket backed by Azure Storage Account
	b, _ := azureblob.OpenBucket(ctx, serviceURL, bucketName, &azureOpts)

	// Obtain the native blob attributes
	var nativeAttrs azblob.BlobGetPropertiesResponse
	attr, _ := b.Attributes(ctx, key)
	if attr.As(&nativeAttrs) {
		// Use the native SDK object
	}

	// Obtain the Azure SDK type for container which represents a go-cloud bucket
	var nativeBucket azblob.ContainerURL
	if b.As(&nativeBucket) {
		// Use the native SDK object
	}

	// Write data to a new blob
	opts := &blob.WriterOptions{
		ContentType: "application/json",
	}
	w, _ := b.NewWriter(ctx, key, opts)
	w.Write([]byte("{"))
	w.Write([]byte(" message: 'hello' "))
	w.Write([]byte("}"))
	w.Close()

	// Read data from a blob
	r, _ := b.NewRangeReader(ctx, key, 0, -1, nil)
	got := make([]byte, 100)
	r.Read(got)

	// Obtain the Azure SDK type for blockblob
	var nativeReader azblob.BlockBlobURL
	if r.As(&nativeReader) {
		// Use the native SDK object
	}

	// Iterate through a virtual directory
	iter := b.List(&blob.ListOptions{Prefix: "blob-for-delimiters", Delimiter: "/"})
	for {
		if p, err := iter.Next(ctx); err == io.EOF {
			break
		} else if err == nil {
			if p.IsDir {
				var nativeDirObj azblob.BlobPrefix
				if p.As(&nativeDirObj) {
					// Use the native SDK object
				}
			} else {
				var nativeBlobObj azblob.BlobItem
				if p.As(&nativeBlobObj) {
					// Use the native SDK object
				}
			}
		}
	}
}
<commit_msg>blob/azureblob: update example test (#1071)<commit_after>// Copyright 2018 The Go Cloud 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
//
//     https://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 azureblob_test

import (
	"context"
	"encoding/base64"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/Azure/azure-storage-blob-go/azblob"
	"gocloud.dev/blob"
	"gocloud.dev/blob/azureblob"
)

func Example() {
	ctx := context.Background()
	// Set a fake key which must be base64 encoded. The Azure Storage Access Keys are already base64 encoded.
	accountName, accountKey := "gocloudblobtests", base64.StdEncoding.EncodeToString([]byte("FAKECREDS"))
	bucketName := "my-bucket"

	// Initializes an azblob.ServiceURL which represents the Azure Storage Account using Shared Key authorization.
	serviceURL, err := azureblob.ServiceURLFromAccountKey(accountName, accountKey)
	if err != nil {
		log.Fatal(err)
		return
	}

	// Credential represents the authorizer for SignedURL.
	creds, err := azblob.NewSharedKeyCredential(accountName, accountKey)
	if err != nil {
		log.Fatal(err)
		return
	}

	// Override the default retry policy so calls can return promptly for this test. Please review the timeout guidelines and set accordingly.
	// See https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-blob-service-operations for more information.
	opts := azblob.PipelineOptions{
		Retry: azblob.RetryOptions{
			Policy:        azblob.RetryPolicyFixed,
			TryTimeout:    5 * time.Second,
			MaxTries:      1,
			RetryDelay:    0 * time.Second,
			MaxRetryDelay: 0 * time.Second,
		},
	}
	p := azblob.NewPipeline(creds, opts)
	*serviceURL = serviceURL.WithPipeline(p)

	if err != nil {
		// This is expected since accountName and accountKey is empty.
		log.Fatal(err)
		return
	}

	// Set credential for the SignedURL operation.
	azureOpts := azureblob.Options{
		Credential: creds,
	}

	// Create a *blob.Bucket.
	b, err := azureblob.OpenBucket(ctx, serviceURL, bucketName, &azureOpts)
	if err != nil {
		log.Fatal(err)
		return
	}

	_, err = b.ReadAll(ctx, "my-key")
	if err != nil {
		// This is expected due to the fake credentials we used above.
		fmt.Println("ReadAll failed due to invalid credentials")
	}

	// Output:
	// ReadAll failed due to invalid credentials
}

func Example_open() {

	// Open creates a *Bucket from a URL.
	// Example URL: azblob://my-bucket?cred_path=replace-with-path-to-credentials-file
	// The schema "azblob" represents the provider for Azure Blob (Azure Storage Account).
	// The host "my-bucket" represents the blob bucket (Azure Storage Account's Container).
	// The queryString "cred_path: represents the credentials file in JSON format. See the package documentation for credentials file schema.

	_, err := blob.Open(context.Background(), "azblob://my-bucket?cred_path=replace-with-path-to-credentials-file")
	if err != nil {
		// This is expected due to the invalid cred_path argument used above.
		fmt.Println("blob.Open failed due to invalid creds_path argument")
	}
	// Output:
	// blob.Open failed due to invalid creds_path argument
}

func Example_as() {

	ctx := context.Background()
	// Set a fake key which must be base64 encoded. The Azure Storage Access Keys are already base64 encoded.
	accountName, accountKey := "gocloudblobtests", base64.StdEncoding.EncodeToString([]byte("FAKECREDS"))
	bucketName, key := "my-bucket", "my-key"

	// Initializes an azblob.ServiceURL which represents the Azure Storage Account using Shared Key authorization.
	serviceURL, err := azureblob.ServiceURLFromAccountKey(accountName, accountKey)
	if err != nil {
		log.Fatal(err)
		return
	}

	// Credential represents the authorizer for SignedURL.
	creds, err := azblob.NewSharedKeyCredential(accountName, accountKey)
	if err != nil {
		log.Fatal(err)
		return
	}

	// Override the default retry policy so calls can return promptly for this test. Please review the timeout guidelines and set accordingly.
	// See https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-blob-service-operations for more information.
	pipelineOpts := azblob.PipelineOptions{
		Retry: azblob.RetryOptions{
			Policy:        azblob.RetryPolicyFixed,
			TryTimeout:    5 * time.Second,
			MaxTries:      1,
			RetryDelay:    0 * time.Second,
			MaxRetryDelay: 0 * time.Second,
		},
	}
	p := azblob.NewPipeline(creds, pipelineOpts)
	*serviceURL = serviceURL.WithPipeline(p)

	// Set credential for the SignedURL operation.
	azureOpts := azureblob.Options{
		Credential: creds,
	}

	// Create a *blob.Bucket.
	b, err := azureblob.OpenBucket(ctx, serviceURL, bucketName, &azureOpts)
	if err != nil {
		log.Fatal(err)
		return
	}

	// Create a *blob.Reader.
	r, err := b.NewReader(ctx, key, &blob.ReaderOptions{})
	if err != nil {
		fmt.Println("ReadAll failed due to invalid credentials")

		// IMPORTANT: Due to the fake credentials used above, this test terminates here.
		return
	}

	// IMPORTANT: The calls below are intended to show how to use As() to obtain the Azure Blob Storage SDK types.
	// Due to the fake credentials used above, below calls are not executed.

	// Use Reader.As to obtain SDK type azblob.DownloadResponse.
	// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#DownloadResponse for more information.
	var nativeReader azblob.DownloadResponse
	if r.As(&nativeReader) {

	}

	// Use Attribute.As to obtain SDK type azblob.BlobGetPropertiesResponse.
	// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#BlobGetPropertiesResponse for more information.
	var nativeAttrs azblob.BlobGetPropertiesResponse
	attr, _ := b.Attributes(ctx, key)
	if attr.As(&nativeAttrs) {

	}

	// Use Bucket.As to obtain SDK type azblob.ContainerURL.
	// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob for more information.
	var nativeBucket *azblob.ContainerURL
	if b.As(&nativeBucket) {

	}

	// Use WriterOptions.BeforeWrite to obtain SDK type azblob.UploadStreamToBlockBlobOptions.
	// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#UploadStreamToBlockBlobOptions for more information.
	beforeWrite := func(as func(i interface{}) bool) error {
		var nativeWriteOptions *azblob.UploadStreamToBlockBlobOptions
		if as(&nativeWriteOptions) {

		}
		return nil
	}
	opts := &blob.WriterOptions{
		ContentType: "application/json",
		BeforeWrite: beforeWrite,
	}
	// Create a *blob.Writer.
	w, _ := b.NewWriter(ctx, key, opts)
	w.Write([]byte("{"))
	w.Write([]byte(" message: 'hello' "))
	w.Write([]byte("}"))
	w.Close()

	// Use ListOptions.BeforeList to obtain SDK type azblob.ListBlobsSegmentOptions.
	// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#ListBlobsSegmentOptions for more information.
	beforeList := func(as func(i interface{}) bool) error {
		var nativeListOptions *azblob.ListBlobsSegmentOptions
		if as(&nativeListOptions) {

		}
		return nil
	}

	// Iterate through a virtual directory.
	iter := b.List(&blob.ListOptions{Prefix: "blob-for-delimiters", Delimiter: "/", BeforeList: beforeList})
	for {
		if p, err := iter.Next(ctx); err == io.EOF {
			break
		} else if err == nil {
			if p.IsDir {
				// Use ListObject.As to obtain SDK type azblob.BlobPrefix.
				// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#BlobPrefix for more information.
				var nativeDirObj azblob.BlobPrefix
				if p.As(&nativeDirObj) {

				}
			} else {
				// Use ListObject.As to obtain SDK type azblob.BlobItem.
				// See https://godoc.org/github.com/Azure/azure-storage-blob-go/azblob#BlobItem for more information.
				var nativeBlobObj azblob.BlobItem
				if p.As(&nativeBlobObj) {

				}
			}
		}
	}

	// Output:
	// ReadAll failed due to invalid credentials
}
<|endoftext|>


<commit_before>package tas

import (
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"
)

import (
	"github.com/chango/tas/tree"
	"github.com/pebbe/zmq3"
)

type TASServer struct {
	config  *TASConfig
	pfdTree *tree.Tree
	socket  *zmq3.Socket
	closing bool
}

// Returns a new TAS server that is running in the background
func NewTASServer(config *TASConfig) (t *TASServer, err error) {
	t = &TASServer{
		config:  config,
		pfdTree: tree.MakeTree(),
	}
	t.socket, err = zmq3.NewSocket(zmq3.PULL)
	if err != nil {
		err = fmt.Errorf("Could not create ZMQ socket: %v", err)
		return
	}
	zmqAddress := fmt.Sprintf("tcp://%s:%s", t.config.ZMQAddress, t.config.ZMQPort)
	err = t.socket.Bind(zmqAddress)
	if err != nil {
		err = fmt.Errorf("Could not bind ZMQ socket: %v", err)
		return
	}
	go t.gcAgent()
	go t.receiver()
	go t.httpServer()
	return
}

// Blocking runner that traps SIGINT and SIGTERM to gracefully shutdown
// the TAS server.
func (t *TASServer) Run() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	select {
	case <-c:
		tasLog.Info("[tas] Stopping server")
		t.close()
		break
	}
	tasLog.Info("[tas] Server stopped")
}

// ZMQ Receiver
func (t *TASServer) receiver() {
	var data interface{}
	var rawMessage string

	defer func() {
		if r := recover(); r != nil {
			tasLog.Debug("TAS Panic", rawMessage, r)
		}
	}()

	tasLog.Info("[tas] Starting receiver")
	for {
		// incoming message format:
		// INCR/APPEND TS KEY VALUE
		if t.closing {
			return
		}
		rawMessage, err = t.socket.Recv(0)
		tasLog.Debug(rawMessage)
		if err != nil {
			tasLog.Info("[tas] ZMQ receive error ", err)
			continue
		}
		message := strings.SplitN(rawMessage, " ", 4)
		if message[0] == "INCR" {
			value, e := strconv.Atoi(message[3])
			if e == nil {
				t.pfdTree.AddData(message[2], value, message[1])
			}
		} else if message[0] == "APPEND" {
			e := json.Unmarshal([]byte(message[3]), &data)
			if e == nil {
				t.pfdTree.AddData(message[2], data, message[1])
			}
		}
	}
}

// Agent that runs a GC on all the child nodes every 4 seconds
func (t *TASServer) gcAgent() {
	log.Println("[tas] Starting gcAgent")
	roundToNearest := 5
	for {
		if t.closing {
			return
		}
		currentTime := time.Now().Unix()
		gcTime := roundToNearest*int(currentTime/int64(roundToNearest)) - 60
		gcTimeStr := strconv.Itoa(gcTime)
		if gcTime%8 == 0 {
			for _, c := range *t.pfdTree.Timestamps() {
				if c.Key < gcTimeStr {
					t.pfdTree.DoGC(c.Key)
				}
			}
		} else {
			t.pfdTree.DoGC(gcTimeStr)
		}
		time.Sleep(4 * time.Second)
	}
}

// The HTTP server
func (t *TASServer) httpServer() {
	var err error
	http.HandleFunc("/GET", func(w http.ResponseWriter, r *http.Request) {
		var tsList []string
		if r.FormValue("t") != "" {
			tsList = strings.Split(r.FormValue("t"), ",")
		}
		var intervalSeconds float64 = 5.0
		if r.FormValue("i") != "" {
			intervalSeconds, _ = strconv.ParseFloat(r.FormValue("i"), 32)
		}
		val := t.pfdTree.GetValue(strings.Split(r.FormValue("key"), "."), tsList, intervalSeconds)
		returnVal, e := json.Marshal(val)
		if e != nil {
			returnVal = []byte("{}")
		}
		fmt.Fprint(w, string(returnVal))
	})

	http.HandleFunc("/DIAG", func(w http.ResponseWriter, r *http.Request) {
		// Function called to get diagnostics

		//Create a map of all the diagnostics
		mapVal := map[string]interface{}{
			"oldest_timestamp": t.pfdTree.GetOldestTS(),
			"current_time":     time.Now().Unix(),
			"gc_running":       t.pfdTree.CheckGCRunning(),
			"num_leafs":        t.pfdTree.GetNumLeafs(),
			"ts_counts":        TSCounters(t.pfdTree.Timestamps()),
		}
		returnVal, e := json.Marshal(mapVal)
		if e != nil {
			returnVal = []byte("{}")
		}
		fmt.Fprint(w, string(returnVal))
	})

	http.HandleFunc("/TREE", func(w http.ResponseWriter, r *http.Request) {

		//Create a new template
		templ := template.New("Tree Structure")
		// define a child template which will hold the actual tree
		Tree := templ.New("Tree")

		//Parse the tree data to create a html version of the tree
		Tree, err = Tree.Parse(TreePrinter(t.pfdTree.DataNode))

		// Throw out error if any issue
		if err != nil {
			fmt.Fprint(w, err)
			return
		}

		//Parse files
		templ, err = templ.ParseFiles("html/tree-d3.html")

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing file: %v", err))
			return
		}

		//Execute the template and write it out
		err = templ.ExecuteTemplate(w, "tree-d3.html", t.pfdTree.DataNode)

		//Throw out error
		if err != nil {
			fmt.Fprint(w, err)
			return
		}
	})

	http.HandleFunc("/STATS", func(w http.ResponseWriter, r *http.Request) {

		ts_counts := TSCounters(t.pfdTree.Timestamps())

		// Create a new template
		templ := template.New("Timestamp Counts")
		// Define a child template which holds the timestamp counts
		Timestamps := templ.New("TS_COUNTS")

		// Parse the timestamp counts data to create a html version of the bar chart
		Timestamps, err = Timestamps.Parse(ts_counts)

		// Throw out error if any issue
		if err != nil {
			fmt.Fprint(w, err)
			return
		}

		//Parse files
		templ, err = templ.ParseFiles("html/ts-stats-d3.html")

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing file: %v", err))
			return
		}

		//Execute the template and write it out
		err = templ.ExecuteTemplate(w, "ts-stats-d3.html", ts_counts)

		//Throw out error
		if err != nil {
			fmt.Fprint(w, err)
			return
		}
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		templ := template.New("Main")
		templ, err := templ.ParseFiles("html/main.html")

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing file: %v", err))
			return
		}

		err = templ.ExecuteTemplate(w, "main.html", nil)

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing ex file: %v", err))
			return
		}
	})

	httpAddr := fmt.Sprintf("%s:%s", t.config.HTTPAddress, t.config.HTTPPort)
	log.Printf("[tas] HTTP listening on %s...", httpAddr)
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

// Gracefully close TAS and its subsequent connections
func (t *TASServer) close() {
	log.Println("[tas] Closing server connections")
	if !t.closing {
		t.closing = true
		t.socket.Close()
	}
}
<commit_msg>should print error every time<commit_after>package tas

import (
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"
)

import (
	"github.com/chango/tas/tree"
	"github.com/pebbe/zmq3"
)

type TASServer struct {
	config  *TASConfig
	pfdTree *tree.Tree
	socket  *zmq3.Socket
	closing bool
}

// Returns a new TAS server that is running in the background
func NewTASServer(config *TASConfig) (t *TASServer, err error) {
	t = &TASServer{
		config:  config,
		pfdTree: tree.MakeTree(),
	}
	t.socket, err = zmq3.NewSocket(zmq3.PULL)
	if err != nil {
		err = fmt.Errorf("Could not create ZMQ socket: %v", err)
		return
	}
	zmqAddress := fmt.Sprintf("tcp://%s:%s", t.config.ZMQAddress, t.config.ZMQPort)
	err = t.socket.Bind(zmqAddress)
	if err != nil {
		err = fmt.Errorf("Could not bind ZMQ socket: %v", err)
		return
	}
	go t.gcAgent()
	go t.receiver()
	go t.httpServer()
	return
}

// Blocking runner that traps SIGINT and SIGTERM to gracefully shutdown
// the TAS server.
func (t *TASServer) Run() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	select {
	case <-c:
		tasLog.Info("[tas] Stopping server")
		t.close()
		break
	}
	tasLog.Info("[tas] Server stopped")
}

// ZMQ Receiver
func (t *TASServer) receiver() {
	var data interface{}
	var rawMessage string

	defer func() {
		if r := recover(); r != nil {
			tasLog.Info("TAS Panic", rawMessage, r)
		}
	}()

	tasLog.Info("[tas] Starting receiver")
	for {
		// incoming message format:
		// INCR/APPEND TS KEY VALUE
		if t.closing {
			return
		}
		rawMessage, err = t.socket.Recv(0)
		tasLog.Debug(rawMessage)
		if err != nil {
			tasLog.Info("[tas] ZMQ receive error ", err)
			continue
		}
		message := strings.SplitN(rawMessage, " ", 4)
		if message[0] == "INCR" {
			value, e := strconv.Atoi(message[3])
			if e == nil {
				t.pfdTree.AddData(message[2], value, message[1])
			}
		} else if message[0] == "APPEND" {
			e := json.Unmarshal([]byte(message[3]), &data)
			if e == nil {
				t.pfdTree.AddData(message[2], data, message[1])
			}
		}
	}
}

// Agent that runs a GC on all the child nodes every 4 seconds
func (t *TASServer) gcAgent() {
	log.Println("[tas] Starting gcAgent")
	roundToNearest := 5
	for {
		if t.closing {
			return
		}
		currentTime := time.Now().Unix()
		gcTime := roundToNearest*int(currentTime/int64(roundToNearest)) - 60
		gcTimeStr := strconv.Itoa(gcTime)
		if gcTime%8 == 0 {
			for _, c := range *t.pfdTree.Timestamps() {
				if c.Key < gcTimeStr {
					t.pfdTree.DoGC(c.Key)
				}
			}
		} else {
			t.pfdTree.DoGC(gcTimeStr)
		}
		time.Sleep(4 * time.Second)
	}
}

// The HTTP server
func (t *TASServer) httpServer() {
	var err error
	http.HandleFunc("/GET", func(w http.ResponseWriter, r *http.Request) {
		var tsList []string
		if r.FormValue("t") != "" {
			tsList = strings.Split(r.FormValue("t"), ",")
		}
		var intervalSeconds float64 = 5.0
		if r.FormValue("i") != "" {
			intervalSeconds, _ = strconv.ParseFloat(r.FormValue("i"), 32)
		}
		val := t.pfdTree.GetValue(strings.Split(r.FormValue("key"), "."), tsList, intervalSeconds)
		returnVal, e := json.Marshal(val)
		if e != nil {
			returnVal = []byte("{}")
		}
		fmt.Fprint(w, string(returnVal))
	})

	http.HandleFunc("/DIAG", func(w http.ResponseWriter, r *http.Request) {
		// Function called to get diagnostics

		//Create a map of all the diagnostics
		mapVal := map[string]interface{}{
			"oldest_timestamp": t.pfdTree.GetOldestTS(),
			"current_time":     time.Now().Unix(),
			"gc_running":       t.pfdTree.CheckGCRunning(),
			"num_leafs":        t.pfdTree.GetNumLeafs(),
			"ts_counts":        TSCounters(t.pfdTree.Timestamps()),
		}
		returnVal, e := json.Marshal(mapVal)
		if e != nil {
			returnVal = []byte("{}")
		}
		fmt.Fprint(w, string(returnVal))
	})

	http.HandleFunc("/TREE", func(w http.ResponseWriter, r *http.Request) {

		//Create a new template
		templ := template.New("Tree Structure")
		// define a child template which will hold the actual tree
		Tree := templ.New("Tree")

		//Parse the tree data to create a html version of the tree
		Tree, err = Tree.Parse(TreePrinter(t.pfdTree.DataNode))

		// Throw out error if any issue
		if err != nil {
			fmt.Fprint(w, err)
			return
		}

		//Parse files
		templ, err = templ.ParseFiles("html/tree-d3.html")

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing file: %v", err))
			return
		}

		//Execute the template and write it out
		err = templ.ExecuteTemplate(w, "tree-d3.html", t.pfdTree.DataNode)

		//Throw out error
		if err != nil {
			fmt.Fprint(w, err)
			return
		}
	})

	http.HandleFunc("/STATS", func(w http.ResponseWriter, r *http.Request) {

		ts_counts := TSCounters(t.pfdTree.Timestamps())

		// Create a new template
		templ := template.New("Timestamp Counts")
		// Define a child template which holds the timestamp counts
		Timestamps := templ.New("TS_COUNTS")

		// Parse the timestamp counts data to create a html version of the bar chart
		Timestamps, err = Timestamps.Parse(ts_counts)

		// Throw out error if any issue
		if err != nil {
			fmt.Fprint(w, err)
			return
		}

		//Parse files
		templ, err = templ.ParseFiles("html/ts-stats-d3.html")

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing file: %v", err))
			return
		}

		//Execute the template and write it out
		err = templ.ExecuteTemplate(w, "ts-stats-d3.html", ts_counts)

		//Throw out error
		if err != nil {
			fmt.Fprint(w, err)
			return
		}
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		templ := template.New("Main")
		templ, err := templ.ParseFiles("html/main.html")

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing file: %v", err))
			return
		}

		err = templ.ExecuteTemplate(w, "main.html", nil)

		//Throw out error
		if err != nil {
			fmt.Fprint(w, fmt.Sprintf("Error parsing ex file: %v", err))
			return
		}
	})

	httpAddr := fmt.Sprintf("%s:%s", t.config.HTTPAddress, t.config.HTTPPort)
	log.Printf("[tas] HTTP listening on %s...", httpAddr)
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

// Gracefully close TAS and its subsequent connections
func (t *TASServer) close() {
	log.Println("[tas] Closing server connections")
	if !t.closing {
		t.closing = true
		t.socket.Close()
	}
}
<|endoftext|>


<commit_before>package femebe

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
)

type Flusher interface {
	Flush() error
}

// The minimum number of bytes required to make a new hybridMsg when
// calling Next().  If buffering and less than MSG_HEADER_SIZE remain
// in the buffer, the remaining bytes must be saved for the next
// invocation of Next().
const MSG_HEADER_MIN_SIZE = 5

// Startup packets longer than this are considered invalid.  Copied
// from the PostgreSQL source code.
const MAX_STARTUP_PACKET_LENGTH = 10000

func baseNewMessageStream(name string, rw io.ReadWriteCloser) *MessageStream {
	buf := bytes.NewBuffer(make([]byte, 0, 8192))

	return &MessageStream{
		Name:         name,
		rw:           rw,
		msgRemainder: *buf,
	}
}

type Config struct {
	Name    string
	Sslmode string
}

func NegotiateTLS(c net.Conn, sslmode string, config *tls.Config) (
	net.Conn, error) {
	if sslmode != "disable" {
		// send an SSLRequest message
		// length: int32(8)
		// code:   int32(80877103)
		c.Write([]byte{0x00, 0x00, 0x00, 0x08,
			0x04, 0xd2, 0x16, 0x2f})

		sslResponse := make([]byte, 1)
		bytesRead, err := io.ReadFull(c, sslResponse)
		if bytesRead != 1 || err != nil {
			return nil, errors.New("Could not read response to SSL Request")
		}

		if sslResponse[0] == 'S' {
			return tls.Client(c, config), nil
		} else if sslResponse[0] == 'N' && sslmode != "allow" &&
			sslmode != "prefer" {
			// reject; we require ssl
			return nil, errors.New("SSL required but declined by server.")
		} else {
			return c, nil
		}

		panic("Oh snap!")
	}

	return c, nil
}

func NewClientMessageStream(name string, rw io.ReadWriteCloser) *MessageStream {
	c := baseNewMessageStream(name, rw)
	c.state = CONN_STARTUP

	return c
}

func NewServerMessageStream(name string, rw io.ReadWriteCloser) (
	*MessageStream, error) {
	c := baseNewMessageStream(name, rw)
	c.state = CONN_NORMAL

	return c, nil
}

type ConnState int32

const (
	CONN_STARTUP ConnState = iota
	CONN_NORMAL
	CONN_ERR
)

type MessageStream struct {
	Name  string
	rw    io.ReadWriteCloser
	state ConnState
	err   error

	// Incomplete message headers that should be chained into
	// message parsing with the subsequent .Next() invocation.
	msgRemainder bytes.Buffer

	// To avoid allocation in inner loops
	scratchBuf [8192]byte
}

func (c *MessageStream) HasNext() bool {
	return c.msgRemainder.Len() >= MSG_HEADER_MIN_SIZE
}

func (c *MessageStream) Next(dst *Message) error {
	switch c.state {
	case CONN_STARTUP:
		msgSz, err := ReadUint32(c.rw)
		if err != nil {
			c.err = err
			c.state = CONN_ERR
			return err
		}

		remainingSz := msgSz - 4

		if remainingSz > MAX_STARTUP_PACKET_LENGTH {
			c.err = fmt.Errorf(
				"Rejecting oversized startup packet: got %v",
				msgSz)
			c.state = CONN_ERR
			return err
		} else if remainingSz < 4 {
			// We expect all initialization messages to
			// have at least a 4-byte header
			c.err = fmt.Errorf(
				"Expected message of at least 4 bytes; got %v",
				remainingSz)
			c.state = CONN_ERR
			return err
		}

		dst.InitPromise(MSG_TYPE_FIRST, msgSz, []byte{}, c.rw)
		if err := dst.Force(); err != nil {
			c.err = err
			c.state = CONN_ERR
			return err
		}

		c.state = CONN_NORMAL
		return nil

	case CONN_NORMAL:
	again:
		// Fast-path: if a message can be formed from the
		// buffer, do so immediately.
		if c.HasNext() {
			msgType := c.msgRemainder.Next(1)[0]
			msgSz := ReadUint32FromBuffer(&c.msgRemainder)

			remainingSz := msgSz - 4

			if remainingSz > uint32(c.msgRemainder.Len()) {
				// Handle messages that are only
				// partially buffered by creating a
				// Promise-mesage that hybridizes the
				// already-buffered data and the
				// network.
				//
				// Copy bytes in the buffer into new
				// memory as it is about to be
				// recycled, which would cause corrupt
				// state.
				trailing := make([]byte, c.msgRemainder.Len())
				c.msgRemainder.Read(trailing)
				dst.InitPromise(msgType, msgSz,
					trailing, c.rw)
				return nil
			} else {
				// The whole message is in the buffer.
				// Address it by-reference rather than
				// copying it.
				dst.InitFromBytes(msgType,
					c.msgRemainder.Next(int(remainingSz)))
				return nil
			}
		}

		// No more deliverable messages are buffered and an
		// error has been set in a previous iteration:
		// transition to CONN_ERR.
		if !c.HasNext() && c.err != nil {
			c.state = CONN_ERR
			return c.err
		}

		// Slow-path: need to grab a chunk of bytes from the
		// kernel, so get as many as feasible, but do insist
		// on least enough to form another message header
		// unless the underlying Reader returns with an error.
		for !c.HasNext() {
			newBytes := c.scratchBuf[:]
			n, err := c.rw.Read(newBytes)

			// Don't fail immediately, because a few valid
			// messages may have been received in addition
			// to an error.
			if err != nil {
				c.err = err
				goto again
			}

			// NB: errors from writing to the buffer is
			// ignored, because msgRemainder is a
			// bytes.Buffer and per specification it will
			// not ever fail to Write the full set of
			// bytes.  Beware if one is changing the type
			// of c.msgRemainder.
			c.msgRemainder.Write(newBytes[0:n])
		}

		// The buffer should be full enough to at least
		// deliver a Promise style message, so just try again.
		goto again

	case CONN_ERR:
		return c.err

	default:
		panic("Oh snap")
	}

	panic("Oh snap")
}

func (c *MessageStream) Send(msg *Message) (err error) {
	_, err = msg.WriteTo(c.rw)
	return err
}

func (c *MessageStream) Flush() error {
	if flushable, ok := c.rw.(Flusher); ok {
		return flushable.Flush()
	}

	return nil
}
<commit_msg>Clean up error return in making MessageStream<commit_after>package femebe

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
)

type Flusher interface {
	Flush() error
}

// The minimum number of bytes required to make a new hybridMsg when
// calling Next().  If buffering and less than MSG_HEADER_SIZE remain
// in the buffer, the remaining bytes must be saved for the next
// invocation of Next().
const MSG_HEADER_MIN_SIZE = 5

// Startup packets longer than this are considered invalid.  Copied
// from the PostgreSQL source code.
const MAX_STARTUP_PACKET_LENGTH = 10000

func baseNewMessageStream(name string, rw io.ReadWriteCloser) *MessageStream {
	buf := bytes.NewBuffer(make([]byte, 0, 8192))

	return &MessageStream{
		Name:         name,
		rw:           rw,
		msgRemainder: *buf,
	}
}

type Config struct {
	Name    string
	Sslmode string
}

func NegotiateTLS(c net.Conn, sslmode string, config *tls.Config) (
	net.Conn, error) {
	if sslmode != "disable" {
		// send an SSLRequest message
		// length: int32(8)
		// code:   int32(80877103)
		c.Write([]byte{0x00, 0x00, 0x00, 0x08,
			0x04, 0xd2, 0x16, 0x2f})

		sslResponse := make([]byte, 1)
		bytesRead, err := io.ReadFull(c, sslResponse)
		if bytesRead != 1 || err != nil {
			return nil, errors.New("Could not read response to SSL Request")
		}

		if sslResponse[0] == 'S' {
			return tls.Client(c, config), nil
		} else if sslResponse[0] == 'N' && sslmode != "allow" &&
			sslmode != "prefer" {
			// reject; we require ssl
			return nil, errors.New("SSL required but declined by server.")
		} else {
			return c, nil
		}

		panic("Oh snap!")
	}

	return c, nil
}

func NewClientMessageStream(name string, rw io.ReadWriteCloser) *MessageStream {
	c := baseNewMessageStream(name, rw)
	c.state = CONN_STARTUP

	return c
}

func NewServerMessageStream(name string, rw io.ReadWriteCloser) *MessageStream {
	c := baseNewMessageStream(name, rw)
	c.state = CONN_NORMAL

	return c
}

type ConnState int32

const (
	CONN_STARTUP ConnState = iota
	CONN_NORMAL
	CONN_ERR
)

type MessageStream struct {
	Name  string
	rw    io.ReadWriteCloser
	state ConnState
	err   error

	// Incomplete message headers that should be chained into
	// message parsing with the subsequent .Next() invocation.
	msgRemainder bytes.Buffer

	// To avoid allocation in inner loops
	scratchBuf [8192]byte
}

func (c *MessageStream) HasNext() bool {
	return c.msgRemainder.Len() >= MSG_HEADER_MIN_SIZE
}

func (c *MessageStream) Next(dst *Message) error {
	switch c.state {
	case CONN_STARTUP:
		msgSz, err := ReadUint32(c.rw)
		if err != nil {
			c.err = err
			c.state = CONN_ERR
			return err
		}

		remainingSz := msgSz - 4

		if remainingSz > MAX_STARTUP_PACKET_LENGTH {
			c.err = fmt.Errorf(
				"Rejecting oversized startup packet: got %v",
				msgSz)
			c.state = CONN_ERR
			return err
		} else if remainingSz < 4 {
			// We expect all initialization messages to
			// have at least a 4-byte header
			c.err = fmt.Errorf(
				"Expected message of at least 4 bytes; got %v",
				remainingSz)
			c.state = CONN_ERR
			return err
		}

		dst.InitPromise(MSG_TYPE_FIRST, msgSz, []byte{}, c.rw)
		if err := dst.Force(); err != nil {
			c.err = err
			c.state = CONN_ERR
			return err
		}

		c.state = CONN_NORMAL
		return nil

	case CONN_NORMAL:
	again:
		// Fast-path: if a message can be formed from the
		// buffer, do so immediately.
		if c.HasNext() {
			msgType := c.msgRemainder.Next(1)[0]
			msgSz := ReadUint32FromBuffer(&c.msgRemainder)

			remainingSz := msgSz - 4

			if remainingSz > uint32(c.msgRemainder.Len()) {
				// Handle messages that are only
				// partially buffered by creating a
				// Promise-mesage that hybridizes the
				// already-buffered data and the
				// network.
				//
				// Copy bytes in the buffer into new
				// memory as it is about to be
				// recycled, which would cause corrupt
				// state.
				trailing := make([]byte, c.msgRemainder.Len())
				c.msgRemainder.Read(trailing)
				dst.InitPromise(msgType, msgSz,
					trailing, c.rw)
				return nil
			} else {
				// The whole message is in the buffer.
				// Address it by-reference rather than
				// copying it.
				dst.InitFromBytes(msgType,
					c.msgRemainder.Next(int(remainingSz)))
				return nil
			}
		}

		// No more deliverable messages are buffered and an
		// error has been set in a previous iteration:
		// transition to CONN_ERR.
		if !c.HasNext() && c.err != nil {
			c.state = CONN_ERR
			return c.err
		}

		// Slow-path: need to grab a chunk of bytes from the
		// kernel, so get as many as feasible, but do insist
		// on least enough to form another message header
		// unless the underlying Reader returns with an error.
		for !c.HasNext() {
			newBytes := c.scratchBuf[:]
			n, err := c.rw.Read(newBytes)

			// Don't fail immediately, because a few valid
			// messages may have been received in addition
			// to an error.
			if err != nil {
				c.err = err
				goto again
			}

			// NB: errors from writing to the buffer is
			// ignored, because msgRemainder is a
			// bytes.Buffer and per specification it will
			// not ever fail to Write the full set of
			// bytes.  Beware if one is changing the type
			// of c.msgRemainder.
			c.msgRemainder.Write(newBytes[0:n])
		}

		// The buffer should be full enough to at least
		// deliver a Promise style message, so just try again.
		goto again

	case CONN_ERR:
		return c.err

	default:
		panic("Oh snap")
	}

	panic("Oh snap")
}

func (c *MessageStream) Send(msg *Message) (err error) {
	_, err = msg.WriteTo(c.rw)
	return err
}

func (c *MessageStream) Flush() error {
	if flushable, ok := c.rw.(Flusher); ok {
		return flushable.Flush()
	}

	return nil
}
<|endoftext|>


<commit_before>package asciidocgo

import (
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

var dm = new(Document).Monitor()
var dnm = new(Document)
var notMonitoredError = &NotMonitoredError{"test"}

func TestDocumentMonitor(t *testing.T) {
	Convey("A Document can be monitored", t, func() {
		Convey("By default, a Document is not monitored", func() {
			So(dnm.IsMonitored(), ShouldBeFalse)
		})
		Convey("A monitored Document is monitored", func() {
			So(dm.IsMonitored(), ShouldBeTrue)
		})
	})
	Convey("A non-monitored Document should return error when accessing times", t, func() {
		_, err := dnm.ReadTime()
		So(err, ShouldNotBeNil)
		So(err, ShouldHaveSameTypeAs, notMonitoredError)
		So(err.Error(), ShouldContainSubstring, "not monitored")
	})
	Convey("A monitored empty Document should return 0 when accessing times", t, func() {
		readTime, err := dm.ReadTime()
		So(err, ShouldBeNil)
		So(readTime, ShouldBeZeroValue)
	})
}
<commit_msg>Use reflect to test time access methods on Document<commit_after>package asciidocgo

import (
	"fmt"
	"reflect"
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

var dm = new(Document).Monitor()
var dnm = new(Document)
var notMonitoredError = &NotMonitoredError{"test"}
var monitorFNames = [1]string{"ReadTime"}

func TestDocumentMonitor(t *testing.T) {
	Convey("A Document can be monitored", t, func() {
		Convey("By default, a Document is not monitored", func() {
			So(dnm.IsMonitored(), ShouldBeFalse)
		})
		Convey("A monitored Document is monitored", func() {
			So(dm.IsMonitored(), ShouldBeTrue)
		})
	})
	Convey("A non-monitored Document should return error when accessing times", t, func() {
		_, err := dnm.ReadTime()
		So(err, ShouldNotBeNil)
		So(err, ShouldHaveSameTypeAs, notMonitoredError)
		So(err.Error(), ShouldContainSubstring, "not monitored")
	})
	Convey("A monitored empty Document should return 0 when accessing times", t, func() {
		dtype := reflect.ValueOf(dm)
		for _, fname := range monitorFNames {
			dfunc := dtype.MethodByName(fname)
			ret := dfunc.Call([]reflect.Value{})
			So(ret[1], shouldBeNilReflectValue)
			So(ret[0].Int(), ShouldBeZeroValue)
		}
	})
}

func shouldBeNilReflectValue(actual interface{}, expected ...interface{}) string {
	if actual.(reflect.Value).IsNil() {
		return ""
	}
	return "Value " + fmt.Sprintf("%v", actual) + " should be nil"
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/armon/consul-api"
	"testing"
	"time"
)

func TestBackoff(t *testing.T) {
	type val struct {
		fail   int
		expect time.Duration
	}
	inps := []val{
		{1, 3 * time.Second},
		{2, 6 * time.Second},
		{3, 12 * time.Second},
		{4, 24 * time.Second},
	}
	for _, inp := range inps {
		if out := backoff(3*time.Second, inp.fail); out != inp.expect {
			t.Fatalf("bad: %v %v", inp, out)
		}
	}
}

func TestFormatOutput(t *testing.T) {
	inp := map[string][]*consulapi.ServiceEntry{
		"foo": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "redis", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "redis", Port: 1234},
			},
		},
		"bar": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 80},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node4", Address: "127.0.0.4"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 10000},
			},
		},
	}

	output := formatOutput(inp)
	if len(output) != 2 {
		t.Fatalf("bad: %v", output)
	}
	foo := output["foo"]
	if len(foo) != 2 {
		t.Fatalf("bad: %v", foo)
	}
	if foo[0] != "server node1_redis 127.0.0.1:8000" {
		t.Fatalf("Bad: %v", foo)
	}
	if foo[1] != "server node3_redis 127.0.0.3:1234" {
		t.Fatalf("Bad: %v", foo)
	}

	bar := output["bar"]
	if len(bar) != 2 {
		t.Fatalf("bad: %v", bar)
	}
	if bar[0] != "server node2_memcache 127.0.0.2:80" {
		t.Fatalf("Bad: %v", bar)
	}
	if bar[1] != "server node4_memcache 127.0.0.4:10000" {
		t.Fatalf("Bad: %v", bar)
	}
}
<commit_msg>Testing<commit_after>package main

import (
	"github.com/armon/consul-api"
	"testing"
	"time"
)

func TestShouldStop(t *testing.T) {
	ch := make(chan struct{})
	if shouldStop(ch) {
		t.Fatalf("bad")
	}
	close(ch)
	if !shouldStop(ch) {
		t.Fatalf("bad")
	}
}

func TestAsyncNotify(t *testing.T) {
	ch := make(chan struct{}, 1)
	asyncNotify(ch)
	asyncNotify(ch)
	asyncNotify(ch)

	select {
	case <-ch:
	default:
		t.Fatalf("should work")
	}
	select {
	case <-ch:
		t.Fatalf("should not work")
	default:
	}

}

func TestMin(t *testing.T) {
	if min(1, 2) != 1 {
		t.Fatalf("Bad")
	}
	if min(2, 1) != 1 {
		t.Fatalf("Bad")
	}
}

func TestBackoff(t *testing.T) {
	type val struct {
		fail   int
		expect time.Duration
	}
	inps := []val{
		{1, 3 * time.Second},
		{2, 6 * time.Second},
		{3, 12 * time.Second},
		{4, 24 * time.Second},
	}
	for _, inp := range inps {
		if out := backoff(3*time.Second, inp.fail); out != inp.expect {
			t.Fatalf("bad: %v %v", inp, out)
		}
	}
}

func TestFormatOutput(t *testing.T) {
	inp := map[string][]*consulapi.ServiceEntry{
		"foo": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "redis", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "redis", Port: 1234},
			},
		},
		"bar": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 80},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node4", Address: "127.0.0.4"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 10000},
			},
		},
	}

	output := formatOutput(inp)
	if len(output) != 2 {
		t.Fatalf("bad: %v", output)
	}
	foo := output["foo"]
	if len(foo) != 2 {
		t.Fatalf("bad: %v", foo)
	}
	if foo[0] != "server node1_redis 127.0.0.1:8000" {
		t.Fatalf("Bad: %v", foo)
	}
	if foo[1] != "server node3_redis 127.0.0.3:1234" {
		t.Fatalf("Bad: %v", foo)
	}

	bar := output["bar"]
	if len(bar) != 2 {
		t.Fatalf("bad: %v", bar)
	}
	if bar[0] != "server node2_memcache 127.0.0.2:80" {
		t.Fatalf("Bad: %v", bar)
	}
	if bar[1] != "server node4_memcache 127.0.0.4:10000" {
		t.Fatalf("Bad: %v", bar)
	}
}
<|endoftext|>


<commit_before>// move related operations
package iris1

import "fmt"

const (
	// Move Operations
	MoveOpMove = iota
	MoveOpSwap
	MoveOpSet
	MoveOpLoad
	MoveOpStore
	MoveOpPush
	MoveOpPop
	MoveOpPeek
	MoveOpStoreCode
	MoveOpLoadCode
	// always last
	MoveOpCount
)

type MoveOp func(*Core, *DecodedInstruction) error

func (fn MoveOp) Invoke(core *Core, inst *DecodedInstruction) error {
	return fn(core, inst)

}

var unimplementedMoveOp = func(_ *Core, _ *DecodedInstruction) error { return fmt.Errorf("Unimplemented move operation!") }
var moveTable = [32]MoveOp{
	moveRegister,
	swapRegisters,
	moveOpSet,
	load,
	store,
	moveOpPush,
	moveOpPop,
	moveOpPeek,
	moveOpStoreCode,
	moveOpLoadCode,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
}

func init() {
	if MoveOpCount > 32 {
		panic("Too many move operations registered! Programmer Failure!")
	}
}
func moveOpStoreCode(core *Core, inst *DecodedInstruction) error {
	// this one is a little odd since we have to use the contents of two registers
	// build an instruction from lower and upper
	return core.SetCodeMemory(core.Register(inst.Data[0]), (Instruction(core.Register(inst.Data[1])) | (Instruction(core.Register(inst.Data[2])) << 16)))
}
func moveOpLoadCode(core *Core, inst *DecodedInstruction) error {
	// in this case we need to load an Instruction from memory and store it into the upper and lower
	// registers. The syntax is dest, src0 are lower and upper with src1 being dest
	idat := core.CodeMemory(core.Register(inst.Data[2]))
	// set the lower and upper halves
	lowerHalf, upperHalf := Word(idat), Word(idat>>16)
	if err := core.SetRegister(inst.Data[0], lowerHalf); err != nil {
		return err
	} else if err := core.SetRegister(inst.Data[1], upperHalf); err != nil {
		return err
	} else {
		return nil
	}
}

func moveRegister(core *Core, inst *DecodedInstruction) error {
	dest, src := inst.Data[0], core.Register(inst.Data[1])
	return core.SetRegister(dest, src)
}
func swapRegisters(core *Core, inst *DecodedInstruction) error {
	dest, src0 := inst.Data[0], inst.Data[1]
	r0, r1 := core.Register(dest), core.Register(src0)
	if err := core.SetRegister(src0, r0); err != nil {
		return err
	} else if err := core.SetRegister(dest, r1); err != nil {
		return err
	} else {
		return nil
	}
}
func moveOpSet(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	return core.SetRegister(dest, inst.Immediate())
}
func load(core *Core, inst *DecodedInstruction) error {
	var val Word
	dest, addr, seg := inst.Data[0], core.Register(inst.Data[1]), segment(inst.Data[2])
	switch seg {
	case dataSegment:
		val = core.DataMemory(addr)
	case microcodeSegment:
		val = core.MicrocodeMemory(addr)
	case stackSegment:
		val = core.StackMemory(addr)
	case callSegment:
		val = core.CallMemory(addr)
	case ioSegment:
		if q, err := core.IoMemory(addr); err != nil {
			return err
		} else {
			val = q
		}
	case codeSegment:
		return fmt.Errorf("Can't load from the code segment!")
	default:
		return fmt.Errorf("Attempted to load from illegal segment %d", seg)
	}
	return core.SetRegister(dest, val)
}

func store(core *Core, inst *DecodedInstruction) error {
	dest, src, seg := core.Register(inst.Data[0]), core.Register(inst.Data[1]), segment(inst.Data[2])
	switch segment(seg) {
	case dataSegment:
		return core.SetDataMemory(dest, src)
	case microcodeSegment:
		return core.SetMicrocodeMemory(dest, src)
	case stackSegment:
		return core.SetStackMemory(dest, src)
	case callSegment:
		return core.SetCallMemory(dest, src)
	case codeSegment:
		return fmt.Errorf("Can't write to code memory!")
	case ioSegment:
		return core.SetIoMemory(dest, src)
	default:
		return fmt.Errorf("Attempted to write to illegal segment %d", seg)
	}
}

func moveOpPush(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	core.Push(core.Register(dest))
	return nil
}

func moveOpPop(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	return core.SetRegister(dest, core.Pop())
}

func moveOpPeek(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	return core.SetRegister(dest, core.Peek())
}

func move(core *Core, inst *DecodedInstruction) error {
	return moveTable[inst.Op].Invoke(core, inst)
}
<commit_msg>Reversed the order code load<commit_after>// move related operations
package iris1

import "fmt"

const (
	// Move Operations
	MoveOpMove = iota
	MoveOpSwap
	MoveOpSet
	MoveOpLoad
	MoveOpStore
	MoveOpPush
	MoveOpPop
	MoveOpPeek
	MoveOpStoreCode
	MoveOpLoadCode
	// always last
	MoveOpCount
)

type MoveOp func(*Core, *DecodedInstruction) error

func (fn MoveOp) Invoke(core *Core, inst *DecodedInstruction) error {
	return fn(core, inst)

}

var unimplementedMoveOp = func(_ *Core, _ *DecodedInstruction) error { return fmt.Errorf("Unimplemented move operation!") }
var moveTable = [32]MoveOp{
	moveRegister,
	swapRegisters,
	moveOpSet,
	load,
	store,
	moveOpPush,
	moveOpPop,
	moveOpPeek,
	moveOpStoreCode,
	moveOpLoadCode,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
	unimplementedMoveOp,
}

func init() {
	if MoveOpCount > 32 {
		panic("Too many move operations registered! Programmer Failure!")
	}
}
func moveOpStoreCode(core *Core, inst *DecodedInstruction) error {
	// this one is a little odd since we have to use the contents of two registers
	// build an instruction from lower and upper
	return core.SetCodeMemory(core.Register(inst.Data[0]), (Instruction(core.Register(inst.Data[1])) | (Instruction(core.Register(inst.Data[2])) << 16)))
}
func moveOpLoadCode(core *Core, inst *DecodedInstruction) error {
	// in this case we need to load an Instruction from memory and store it into the upper and lower
	// registers. The syntax is dest, src0 are lower and upper with src1 being dest
	idat := core.CodeMemory(core.Register(inst.Data[0]))
	// set the lower and upper halves
	lowerHalf, upperHalf := Word(idat), Word(idat>>16)
	if err := core.SetRegister(inst.Data[1], lowerHalf); err != nil {
		return err
	} else if err := core.SetRegister(inst.Data[2], upperHalf); err != nil {
		return err
	} else {
		return nil
	}
}

func moveRegister(core *Core, inst *DecodedInstruction) error {
	dest, src := inst.Data[0], core.Register(inst.Data[1])
	return core.SetRegister(dest, src)
}
func swapRegisters(core *Core, inst *DecodedInstruction) error {
	dest, src0 := inst.Data[0], inst.Data[1]
	r0, r1 := core.Register(dest), core.Register(src0)
	if err := core.SetRegister(src0, r0); err != nil {
		return err
	} else if err := core.SetRegister(dest, r1); err != nil {
		return err
	} else {
		return nil
	}
}
func moveOpSet(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	return core.SetRegister(dest, inst.Immediate())
}
func load(core *Core, inst *DecodedInstruction) error {
	var val Word
	dest, addr, seg := inst.Data[0], core.Register(inst.Data[1]), segment(inst.Data[2])
	switch seg {
	case dataSegment:
		val = core.DataMemory(addr)
	case microcodeSegment:
		val = core.MicrocodeMemory(addr)
	case stackSegment:
		val = core.StackMemory(addr)
	case callSegment:
		val = core.CallMemory(addr)
	case ioSegment:
		if q, err := core.IoMemory(addr); err != nil {
			return err
		} else {
			val = q
		}
	case codeSegment:
		return fmt.Errorf("Can't load from the code segment!")
	default:
		return fmt.Errorf("Attempted to load from illegal segment %d", seg)
	}
	return core.SetRegister(dest, val)
}

func store(core *Core, inst *DecodedInstruction) error {
	dest, src, seg := core.Register(inst.Data[0]), core.Register(inst.Data[1]), segment(inst.Data[2])
	switch segment(seg) {
	case dataSegment:
		return core.SetDataMemory(dest, src)
	case microcodeSegment:
		return core.SetMicrocodeMemory(dest, src)
	case stackSegment:
		return core.SetStackMemory(dest, src)
	case callSegment:
		return core.SetCallMemory(dest, src)
	case codeSegment:
		return fmt.Errorf("Can't write to code memory!")
	case ioSegment:
		return core.SetIoMemory(dest, src)
	default:
		return fmt.Errorf("Attempted to write to illegal segment %d", seg)
	}
}

func moveOpPush(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	core.Push(core.Register(dest))
	return nil
}

func moveOpPop(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	return core.SetRegister(dest, core.Pop())
}

func moveOpPeek(core *Core, inst *DecodedInstruction) error {
	dest := inst.Data[0]
	return core.SetRegister(dest, core.Peek())
}

func move(core *Core, inst *DecodedInstruction) error {
	return moveTable[inst.Op].Invoke(core, inst)
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"fmt"
	pb "github.com/PomeloCloud/BFTRaft4go/proto/server"
	"sync"
	"time"
)

func RequestVoteRequestSignData(req *pb.RequestVoteRequest) []byte {
	return []byte(fmt.Sprint(req.Group, "-", req.Term, "-", req.LogIndex, "-", req.Term, "-", req.CandidateId))
}

func RequestVoteResponseSignData(res *pb.RequestVoteResponse) []byte {
	return []byte(fmt.Sprint(res.Group, "-", res.Term, "-", res.LogIndex, "-", res.Term, "-", res.CandidateId, "-", res.Granted))
}

func (s *BFTRaftServer) BecomeCandidate(meta *RTGroupMeta) {
	RefreshTimer(meta, 10)
	meta.Role = CANDIDATE
	group := meta.Group
	group.Term++
	term := group.Term
	s.SaveGroup(meta.Group)
	meta.Votes = []*pb.RequestVoteResponse{}
	meta.NewTerm = true
	lastEntry := s.LastLogEntry(group.Id)
	request := &pb.RequestVoteRequest{
		Group:       group.Id,
		Term:        term,
		LogIndex:    lastEntry.Index,
		LogTerm:     lastEntry.Term,
		CandidateId: meta.Peer,
		Signature:   []byte{},
	}
	request.Signature = s.Sign(RequestVoteRequestSignData(request))
	lock := sync.Mutex{}
	votes := 0
	voteReceived := make(chan *pb.RequestVoteResponse)
	adequateVotes := make(chan bool, 1)
	for _, peer := range meta.GroupPeers {
		nodeId := peer.Host
		if nodeId == s.Id {
			continue
		}
		node := s.GetNode(nodeId)
		go func() {
			if client, err := s.ClusterClients.Get(node.ServerAddr); err == nil {
				if voteResponse, err := client.rpc.RequestVote(context.Background(), request); err == nil {
					publicKey := s.GetNodePublicKey(nodeId)
					signData := RequestVoteResponseSignData(voteResponse)
					if VerifySign(publicKey, voteResponse.Signature, signData) == nil {
						lock.Lock()
						votes++
						voteReceived <- voteResponse
						lock.Unlock()
					}
				}
			}
		}()
	}
	go func() {
		// Here we can follow the rule of Raft by expecting majority votes
		// or follow the PBFT rule by expecting n - f votes
		// I will use the rule from Raft first
		expectedVotes := len(meta.GroupPeers) / 2 // ExpectedHonestPeers(s.GroupPeersSlice(group.Id))
		for vote, voted := <-voteReceived; voted; {
			if votes > expectedVotes {
				meta.Votes = append(meta.Votes, vote)
				adequateVotes <- true
				break
			}
		}
	}()
	go func() {
		select {
		case <-adequateVotes:
			s.BecomeLeader(meta)
		case <-time.After(5000 * time.Second):
			close(voteReceived)
		}
	}()
}

func (s *BFTRaftServer) BecomeLeader(meta *RTGroupMeta) {
	// when this peer become the leader of the group
	// it need to send it's vote to followers to claim it's authority
	// this only need to be done once in each term
	// so we just send the 'AppendEntry' request in this function
	// we can use a dedicated rpc protocol for this, but no bother
	meta.Role = LEADER
	s.SendFollowersHeartbeat(context.Background(), meta.Peer, meta.Group)
}
<commit_msg>strict vote verfication<commit_after>package server

import (
	"context"
	"fmt"
	pb "github.com/PomeloCloud/BFTRaft4go/proto/server"
	"sync"
	"time"
)

func RequestVoteRequestSignData(req *pb.RequestVoteRequest) []byte {
	return []byte(fmt.Sprint(req.Group, "-", req.Term, "-", req.LogIndex, "-", req.Term, "-", req.CandidateId))
}

func RequestVoteResponseSignData(res *pb.RequestVoteResponse) []byte {
	return []byte(fmt.Sprint(res.Group, "-", res.Term, "-", res.LogIndex, "-", res.Term, "-", res.CandidateId, "-", res.Granted))
}

func (s *BFTRaftServer) BecomeCandidate(meta *RTGroupMeta) {
	RefreshTimer(meta, 10)
	meta.Role = CANDIDATE
	group := meta.Group
	group.Term++
	term := group.Term
	s.SaveGroup(meta.Group)
	meta.Votes = []*pb.RequestVoteResponse{}
	meta.NewTerm = true
	lastEntry := s.LastLogEntry(group.Id)
	request := &pb.RequestVoteRequest{
		Group:       group.Id,
		Term:        term,
		LogIndex:    lastEntry.Index,
		LogTerm:     lastEntry.Term,
		CandidateId: meta.Peer,
		Signature:   []byte{},
	}
	request.Signature = s.Sign(RequestVoteRequestSignData(request))
	lock := sync.Mutex{}
	votes := 0
	voteReceived := make(chan *pb.RequestVoteResponse)
	adequateVotes := make(chan bool, 1)
	for _, peer := range meta.GroupPeers {
		nodeId := peer.Host
		if nodeId == s.Id {
			continue
		}
		node := s.GetNode(nodeId)
		go func() {
			if client, err := s.ClusterClients.Get(node.ServerAddr); err == nil {
				if voteResponse, err := client.rpc.RequestVote(context.Background(), request); err == nil {
					publicKey := s.GetNodePublicKey(nodeId)
					signData := RequestVoteResponseSignData(voteResponse)
					if VerifySign(publicKey, voteResponse.Signature, signData) == nil {
						if voteResponse.Granted && voteResponse.LogIndex <= lastEntry.Index {
							lock.Lock()
							votes++
							voteReceived <- voteResponse
							lock.Unlock()
						}
					}
				}
			}
		}()
	}
	go func() {
		// Here we can follow the rule of Raft by expecting majority votes
		// or follow the PBFT rule by expecting n - f votes
		// I will use the rule from Raft first
		expectedVotes := len(meta.GroupPeers) / 2 // ExpectedHonestPeers(s.GroupPeersSlice(group.Id))
		for vote, voted := <-voteReceived; voted; {
			if votes > expectedVotes {
				meta.Votes = append(meta.Votes, vote)
				adequateVotes <- true
				break
			}
		}
	}()
	go func() {
		select {
		case <-adequateVotes:
			s.BecomeLeader(meta)
		case <-time.After(5000 * time.Second):
			close(voteReceived)
		}
	}()
}

func (s *BFTRaftServer) BecomeLeader(meta *RTGroupMeta) {
	// when this peer become the leader of the group
	// it need to send it's vote to followers to claim it's authority
	// this only need to be done once in each term
	// so we just send the 'AppendEntry' request in this function
	// we can use a dedicated rpc protocol for this, but no bother
	meta.Role = LEADER
	s.SendFollowersHeartbeat(context.Background(), meta.Peer, meta.Group)
}
<|endoftext|>


<commit_before>package engineio

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"

	"github.com/googollee/go-engine.io/message"
	"github.com/googollee/go-engine.io/parser"
	"github.com/googollee/go-engine.io/transport"
)

type MessageType message.MessageType

const (
	MessageBinary MessageType = MessageType(message.MessageBinary)
	MessageText   MessageType = MessageType(message.MessageText)
)

// Conn is the connection object of engine.io.
type Conn interface {

	// Id returns the session id of connection.
	Id() string

	// Request returns the first http request when established connection.
	Request() *http.Request

	// Close closes the connection.
	Close() error

	// NextReader returns the next message type, reader. If no message received, it will block.
	NextReader() (MessageType, io.ReadCloser, error)

	// NextWriter returns the next message writer with given message type.
	NextWriter(messageType MessageType) (io.WriteCloser, error)
}

type transportCreaters map[string]transport.Creater

func (c transportCreaters) Get(name string) transport.Creater {
	return c[name]
}

type serverCallback interface {
	configure() config
	transports() transportCreaters
	onClose(sid string)
}

type state int

const (
	stateUnknow state = iota
	stateNormal
	stateUpgrading
	stateClosing
	stateClosed
)

type serverConn struct {
	id              string
	request         *http.Request
	callback        serverCallback
	writerLocker    sync.Mutex
	transportLocker sync.RWMutex
	currentName     string
	current         transport.Server
	upgradingName   string
	upgrading       transport.Server
	state           state
	stateLocker     sync.RWMutex
	readerChan      chan *connReader
	pingTimeout     time.Duration
	pingInterval    time.Duration
	pingChan        chan bool
}

var InvalidError = errors.New("invalid transport")

func newServerConn(id string, w http.ResponseWriter, r *http.Request, callback serverCallback) (*serverConn, error) {
	transportName := r.URL.Query().Get("transport")
	creater := callback.transports().Get(transportName)
	if creater.Name == "" {
		return nil, InvalidError
	}
	ret := &serverConn{
		id:           id,
		request:      r,
		callback:     callback,
		state:        stateNormal,
		readerChan:   make(chan *connReader),
		pingTimeout:  callback.configure().PingTimeout,
		pingInterval: callback.configure().PingInterval,
		pingChan:     make(chan bool),
	}
	transport, err := creater.Server(w, r, ret)
	if err != nil {
		return nil, err
	}
	ret.setCurrent(transportName, transport)
	if err := ret.onOpen(); err != nil {
		return nil, err
	}

	go ret.pingLoop()

	return ret, nil
}

func (c *serverConn) Id() string {
	return c.id
}

func (c *serverConn) Request() *http.Request {
	return c.request
}

func (c *serverConn) NextReader() (MessageType, io.ReadCloser, error) {
	if c.getState() == stateClosed {
		return MessageBinary, nil, io.EOF
	}
	ret := <-c.readerChan
	if ret == nil {
		return MessageBinary, nil, io.EOF
	}
	return MessageType(ret.MessageType()), ret, nil
}

func (c *serverConn) NextWriter(t MessageType) (io.WriteCloser, error) {
	switch c.getState() {
	case stateUpgrading:
		return nil, fmt.Errorf("upgrading")
	case stateNormal:
	default:
		return nil, io.EOF
	}
	ret, err := c.getCurrent().NextWriter(message.MessageType(t), parser.MESSAGE)
	return ret, err
}

func (c *serverConn) Close() error {
	if c.getState() != stateNormal && c.getState() != stateUpgrading {
		return nil
	}
	if c.upgrading != nil {
		c.upgrading.Close()
	}
	c.writerLocker.Lock()
	if w, err := c.getCurrent().NextWriter(message.MessageText, parser.CLOSE); err == nil {
		writer := newConnWriter(w, &c.writerLocker)
		writer.Close()
	} else {
		c.writerLocker.Unlock()
	}
	if err := c.getCurrent().Close(); err != nil {
		return err
	}
	c.setState(stateClosing)
	return nil
}

func (c *serverConn) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	transportName := r.URL.Query().Get("transport")
	if c.currentName != transportName {
		creater := c.callback.transports().Get(transportName)
		if creater.Name == "" {
			http.Error(w, fmt.Sprintf("invalid transport %s", transportName), http.StatusBadRequest)
			return
		}
		u, err := creater.Server(w, r, c)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		c.setUpgrading(creater.Name, u)
		return
	}
	c.current.ServeHTTP(w, r)
}

func (c *serverConn) OnPacket(r *parser.PacketDecoder) {
	switch r.Type() {
	case parser.OPEN:
	case parser.CLOSE:
		c.getCurrent().Close()
	case parser.PING:
		t := c.getCurrent()
		u := c.getUpgrade()
		newWriter := t.NextWriter
		if u != nil {
			if w, _ := t.NextWriter(message.MessageText, parser.NOOP); w != nil {
				w.Close()
			}
			newWriter = u.NextWriter
		}
		if w, _ := newWriter(message.MessageText, parser.PONG); w != nil {
			io.Copy(w, r)
			w.Close()
		}
		fallthrough
	case parser.PONG:
		c.pingChan <- true
	case parser.MESSAGE:
		closeChan := make(chan struct{})
		c.readerChan <- newConnReader(r, closeChan)
		<-closeChan
		close(closeChan)
		r.Close()
	case parser.UPGRADE:
		c.upgraded()
	case parser.NOOP:
	}
}

func (c *serverConn) OnClose(server transport.Server) {
	if server == c.getUpgrade() {
		c.setUpgrading("", nil)
		return
	}
	t := c.getCurrent()
	if server != t {
		return
	}
	t.Close()
	if t := c.getUpgrade(); t != nil {
		t.Close()
		c.setUpgrading("", nil)
	}
	c.setState(stateClosed)
	close(c.readerChan)
	close(c.pingChan)
	c.callback.onClose(c.id)
}

type connectionInfo struct {
	Sid          string        `json:"sid"`
	Upgrades     []string      `json:"upgrades"`
	PingInterval time.Duration `json:"pingInterval"`
	PingTimeout  time.Duration `json:"pingTimeout"`
}

func (s *serverConn) onOpen() error {
	var upgrades []string
	for name := range s.callback.transports() {
		if name == s.currentName {
			continue
		}
		upgrades = append(upgrades, name)
	}
	resp := connectionInfo{
		Sid:          s.Id(),
		Upgrades:     upgrades,
		PingInterval: s.callback.configure().PingInterval / time.Millisecond,
		PingTimeout:  s.callback.configure().PingTimeout / time.Millisecond,
	}
	w, err := s.getCurrent().NextWriter(message.MessageText, parser.OPEN)
	if err != nil {
		return err
	}
	encoder := json.NewEncoder(w)
	if err := encoder.Encode(resp); err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}
	return nil
}

func (c *serverConn) getCurrent() transport.Server {
	c.transportLocker.RLock()
	defer c.transportLocker.RUnlock()

	return c.current
}

func (c *serverConn) getUpgrade() transport.Server {
	c.transportLocker.RLock()
	defer c.transportLocker.RUnlock()

	return c.upgrading
}

func (c *serverConn) setCurrent(name string, s transport.Server) {
	c.transportLocker.Lock()
	defer c.transportLocker.Unlock()

	c.currentName = name
	c.current = s
}

func (c *serverConn) setUpgrading(name string, s transport.Server) {
	c.transportLocker.Lock()
	defer c.transportLocker.Unlock()

	c.upgradingName = name
	c.upgrading = s
	c.setState(stateUpgrading)
}

func (c *serverConn) upgraded() {
	c.transportLocker.Lock()

	current := c.current
	c.current = c.upgrading
	c.currentName = c.upgradingName
	c.upgrading = nil
	c.upgradingName = ""

	c.transportLocker.Unlock()

	current.Close()
	c.setState(stateNormal)
}

func (c *serverConn) getState() state {
	c.stateLocker.RLock()
	defer c.stateLocker.RUnlock()
	return c.state
}

func (c *serverConn) setState(state state) {
	c.stateLocker.Lock()
	defer c.stateLocker.Unlock()
	c.state = state
}

func (c *serverConn) pingLoop() {
	lastPing := time.Now()
	lastTry := lastPing
	for {
		now := time.Now()
		pingDiff := now.Sub(lastPing)
		tryDiff := now.Sub(lastTry)
		select {
		case ok := <-c.pingChan:
			if !ok {
				return
			}
			lastPing = time.Now()
			lastTry = lastPing
		case <-time.After(c.pingInterval - tryDiff):
			c.writerLocker.Lock()
			if w, _ := c.getCurrent().NextWriter(message.MessageText, parser.PING); w != nil {
				writer := newConnWriter(w, &c.writerLocker)
				writer.Close()
			} else {
				c.writerLocker.Unlock()
			}
			lastTry = time.Now()
		case <-time.After(c.pingTimeout - pingDiff):
			c.Close()
			return
		}
	}
}
<commit_msg>upgrades return [] instead of nil<commit_after>package engineio

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"

	"github.com/googollee/go-engine.io/message"
	"github.com/googollee/go-engine.io/parser"
	"github.com/googollee/go-engine.io/transport"
)

type MessageType message.MessageType

const (
	MessageBinary MessageType = MessageType(message.MessageBinary)
	MessageText   MessageType = MessageType(message.MessageText)
)

// Conn is the connection object of engine.io.
type Conn interface {

	// Id returns the session id of connection.
	Id() string

	// Request returns the first http request when established connection.
	Request() *http.Request

	// Close closes the connection.
	Close() error

	// NextReader returns the next message type, reader. If no message received, it will block.
	NextReader() (MessageType, io.ReadCloser, error)

	// NextWriter returns the next message writer with given message type.
	NextWriter(messageType MessageType) (io.WriteCloser, error)
}

type transportCreaters map[string]transport.Creater

func (c transportCreaters) Get(name string) transport.Creater {
	return c[name]
}

type serverCallback interface {
	configure() config
	transports() transportCreaters
	onClose(sid string)
}

type state int

const (
	stateUnknow state = iota
	stateNormal
	stateUpgrading
	stateClosing
	stateClosed
)

type serverConn struct {
	id              string
	request         *http.Request
	callback        serverCallback
	writerLocker    sync.Mutex
	transportLocker sync.RWMutex
	currentName     string
	current         transport.Server
	upgradingName   string
	upgrading       transport.Server
	state           state
	stateLocker     sync.RWMutex
	readerChan      chan *connReader
	pingTimeout     time.Duration
	pingInterval    time.Duration
	pingChan        chan bool
}

var InvalidError = errors.New("invalid transport")

func newServerConn(id string, w http.ResponseWriter, r *http.Request, callback serverCallback) (*serverConn, error) {
	transportName := r.URL.Query().Get("transport")
	creater := callback.transports().Get(transportName)
	if creater.Name == "" {
		return nil, InvalidError
	}
	ret := &serverConn{
		id:           id,
		request:      r,
		callback:     callback,
		state:        stateNormal,
		readerChan:   make(chan *connReader),
		pingTimeout:  callback.configure().PingTimeout,
		pingInterval: callback.configure().PingInterval,
		pingChan:     make(chan bool),
	}
	transport, err := creater.Server(w, r, ret)
	if err != nil {
		return nil, err
	}
	ret.setCurrent(transportName, transport)
	if err := ret.onOpen(); err != nil {
		return nil, err
	}

	go ret.pingLoop()

	return ret, nil
}

func (c *serverConn) Id() string {
	return c.id
}

func (c *serverConn) Request() *http.Request {
	return c.request
}

func (c *serverConn) NextReader() (MessageType, io.ReadCloser, error) {
	if c.getState() == stateClosed {
		return MessageBinary, nil, io.EOF
	}
	ret := <-c.readerChan
	if ret == nil {
		return MessageBinary, nil, io.EOF
	}
	return MessageType(ret.MessageType()), ret, nil
}

func (c *serverConn) NextWriter(t MessageType) (io.WriteCloser, error) {
	switch c.getState() {
	case stateUpgrading:
		return nil, fmt.Errorf("upgrading")
	case stateNormal:
	default:
		return nil, io.EOF
	}
	ret, err := c.getCurrent().NextWriter(message.MessageType(t), parser.MESSAGE)
	return ret, err
}

func (c *serverConn) Close() error {
	if c.getState() != stateNormal && c.getState() != stateUpgrading {
		return nil
	}
	if c.upgrading != nil {
		c.upgrading.Close()
	}
	c.writerLocker.Lock()
	if w, err := c.getCurrent().NextWriter(message.MessageText, parser.CLOSE); err == nil {
		writer := newConnWriter(w, &c.writerLocker)
		writer.Close()
	} else {
		c.writerLocker.Unlock()
	}
	if err := c.getCurrent().Close(); err != nil {
		return err
	}
	c.setState(stateClosing)
	return nil
}

func (c *serverConn) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	transportName := r.URL.Query().Get("transport")
	if c.currentName != transportName {
		creater := c.callback.transports().Get(transportName)
		if creater.Name == "" {
			http.Error(w, fmt.Sprintf("invalid transport %s", transportName), http.StatusBadRequest)
			return
		}
		u, err := creater.Server(w, r, c)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		c.setUpgrading(creater.Name, u)
		return
	}
	c.current.ServeHTTP(w, r)
}

func (c *serverConn) OnPacket(r *parser.PacketDecoder) {
	switch r.Type() {
	case parser.OPEN:
	case parser.CLOSE:
		c.getCurrent().Close()
	case parser.PING:
		t := c.getCurrent()
		u := c.getUpgrade()
		newWriter := t.NextWriter
		if u != nil {
			if w, _ := t.NextWriter(message.MessageText, parser.NOOP); w != nil {
				w.Close()
			}
			newWriter = u.NextWriter
		}
		if w, _ := newWriter(message.MessageText, parser.PONG); w != nil {
			io.Copy(w, r)
			w.Close()
		}
		fallthrough
	case parser.PONG:
		c.pingChan <- true
	case parser.MESSAGE:
		closeChan := make(chan struct{})
		c.readerChan <- newConnReader(r, closeChan)
		<-closeChan
		close(closeChan)
		r.Close()
	case parser.UPGRADE:
		c.upgraded()
	case parser.NOOP:
	}
}

func (c *serverConn) OnClose(server transport.Server) {
	if server == c.getUpgrade() {
		c.setUpgrading("", nil)
		return
	}
	t := c.getCurrent()
	if server != t {
		return
	}
	t.Close()
	if t := c.getUpgrade(); t != nil {
		t.Close()
		c.setUpgrading("", nil)
	}
	c.setState(stateClosed)
	close(c.readerChan)
	close(c.pingChan)
	c.callback.onClose(c.id)
}

func (s *serverConn) onOpen() error {
	upgrades := []string{}
	for name := range s.callback.transports() {
		if name == s.currentName {
			continue
		}
		upgrades = append(upgrades, name)
	}
	type connectionInfo struct {
		Sid          string        `json:"sid"`
		Upgrades     []string      `json:"upgrades"`
		PingInterval time.Duration `json:"pingInterval"`
		PingTimeout  time.Duration `json:"pingTimeout"`
	}
	resp := connectionInfo{
		Sid:          s.Id(),
		Upgrades:     upgrades,
		PingInterval: s.callback.configure().PingInterval / time.Millisecond,
		PingTimeout:  s.callback.configure().PingTimeout / time.Millisecond,
	}
	w, err := s.getCurrent().NextWriter(message.MessageText, parser.OPEN)
	if err != nil {
		return err
	}
	encoder := json.NewEncoder(w)
	if err := encoder.Encode(resp); err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}
	return nil
}

func (c *serverConn) getCurrent() transport.Server {
	c.transportLocker.RLock()
	defer c.transportLocker.RUnlock()

	return c.current
}

func (c *serverConn) getUpgrade() transport.Server {
	c.transportLocker.RLock()
	defer c.transportLocker.RUnlock()

	return c.upgrading
}

func (c *serverConn) setCurrent(name string, s transport.Server) {
	c.transportLocker.Lock()
	defer c.transportLocker.Unlock()

	c.currentName = name
	c.current = s
}

func (c *serverConn) setUpgrading(name string, s transport.Server) {
	c.transportLocker.Lock()
	defer c.transportLocker.Unlock()

	c.upgradingName = name
	c.upgrading = s
	c.setState(stateUpgrading)
}

func (c *serverConn) upgraded() {
	c.transportLocker.Lock()

	current := c.current
	c.current = c.upgrading
	c.currentName = c.upgradingName
	c.upgrading = nil
	c.upgradingName = ""

	c.transportLocker.Unlock()

	current.Close()
	c.setState(stateNormal)
}

func (c *serverConn) getState() state {
	c.stateLocker.RLock()
	defer c.stateLocker.RUnlock()
	return c.state
}

func (c *serverConn) setState(state state) {
	c.stateLocker.Lock()
	defer c.stateLocker.Unlock()
	c.state = state
}

func (c *serverConn) pingLoop() {
	lastPing := time.Now()
	lastTry := lastPing
	for {
		now := time.Now()
		pingDiff := now.Sub(lastPing)
		tryDiff := now.Sub(lastTry)
		select {
		case ok := <-c.pingChan:
			if !ok {
				return
			}
			lastPing = time.Now()
			lastTry = lastPing
		case <-time.After(c.pingInterval - tryDiff):
			c.writerLocker.Lock()
			if w, _ := c.getCurrent().NextWriter(message.MessageText, parser.PING); w != nil {
				writer := newConnWriter(w, &c.writerLocker)
				writer.Close()
			} else {
				c.writerLocker.Unlock()
			}
			lastTry = time.Now()
		case <-time.After(c.pingTimeout - pingDiff):
			c.Close()
			return
		}
	}
}
<|endoftext|>