<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

// Package gcsbackupstorage implements the BackupStorage interface
// for Google Cloud Storage.
package gcsbackupstorage

import (
	"flag"
	"fmt"
	"io"
	"sort"
	"strings"
	"sync"

	"cloud.google.com/go/storage"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"

	"vitess.io/vitess/go/trace"
	"vitess.io/vitess/go/vt/mysqlctl/backupstorage"
)

var (
	_ = flag.String("gcs_backup_storage_project", "", "This flag is unused and deprecated. It will be removed entirely in a future release.")

	// bucket is where the backups will go.
	bucket = flag.String("gcs_backup_storage_bucket", "", "Google Cloud Storage bucket to use for backups")

	// root is a prefix added to all object names.
	root = flag.String("gcs_backup_storage_root", "", "root prefix for all backup-related object names")
)

// GCSBackupHandle implements BackupHandle for Google Cloud Storage.
type GCSBackupHandle struct {
	client   *storage.Client
	bs       *GCSBackupStorage
	dir      string
	name     string
	readOnly bool
}

// Directory implements BackupHandle.
func (bh *GCSBackupHandle) Directory() string {
	return bh.dir
}

// Name implements BackupHandle.
func (bh *GCSBackupHandle) Name() string {
	return bh.name
}

// AddFile implements BackupHandle.
func (bh *GCSBackupHandle) AddFile(ctx context.Context, filename string, filesize int64) (io.WriteCloser, error) {
	if bh.readOnly {
		return nil, fmt.Errorf("AddFile cannot be called on read-only backup")
	}
	object := objName(bh.dir, bh.name, filename)
	return bh.client.Bucket(*bucket).Object(object).NewWriter(ctx), nil
}

// EndBackup implements BackupHandle.
func (bh *GCSBackupHandle) EndBackup(ctx context.Context) error {
	if bh.readOnly {
		return fmt.Errorf("EndBackup cannot be called on read-only backup")
	}
	return nil
}

// AbortBackup implements BackupHandle.
func (bh *GCSBackupHandle) AbortBackup(ctx context.Context) error {
	if bh.readOnly {
		return fmt.Errorf("AbortBackup cannot be called on read-only backup")
	}
	return bh.bs.RemoveBackup(ctx, bh.dir, bh.name)
}

// ReadFile implements BackupHandle.
func (bh *GCSBackupHandle) ReadFile(ctx context.Context, filename string) (io.ReadCloser, error) {
	if !bh.readOnly {
		return nil, fmt.Errorf("ReadFile cannot be called on read-write backup")
	}
	object := objName(bh.dir, bh.name, filename)
	return bh.client.Bucket(*bucket).Object(object).NewReader(ctx)
}

// GCSBackupStorage implements BackupStorage for Google Cloud Storage.
type GCSBackupStorage struct {
	// client is the instance of the Google Cloud Storage Go client.
	// Once this field is set, it must not be written again/unset to nil.
	_client *storage.Client
	// mu guards all fields.
	mu sync.Mutex
}

// ListBackups implements BackupStorage.
func (bs *GCSBackupStorage) ListBackups(ctx context.Context, dir string) ([]backupstorage.BackupHandle, error) {
	c, err := bs.client(ctx)
	if err != nil {
		return nil, err
	}

	// List prefixes that begin with dir (i.e. list subdirs).
	var subdirs []string
	searchPrefix := objName(dir, "" /* include trailing slash */)
	query := &storage.Query{
		Delimiter: "/",
		Prefix:    searchPrefix,
	}

	it := c.Bucket(*bucket).Objects(ctx, query)
	for {
		obj, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		// Each returned prefix is a subdir.
		// Strip parent dir from full path.
		if obj.Prefix != "" {
			subdir := strings.TrimPrefix(obj.Prefix, searchPrefix)
			subdir = strings.TrimSuffix(subdir, "/")
			subdirs = append(subdirs, subdir)
		}
	}

	// Backups must be returned in order, oldest first.
	sort.Strings(subdirs)

	result := make([]backupstorage.BackupHandle, 0, len(subdirs))
	for _, subdir := range subdirs {
		result = append(result, &GCSBackupHandle{
			client:   c,
			bs:       bs,
			dir:      dir,
			name:     subdir,
			readOnly: true,
		})
	}
	return result, nil
}

// StartBackup implements BackupStorage.
func (bs *GCSBackupStorage) StartBackup(ctx context.Context, dir, name string) (backupstorage.BackupHandle, error) {
	c, err := bs.client(ctx)
	if err != nil {
		return nil, err
	}

	return &GCSBackupHandle{
		client:   c,
		bs:       bs,
		dir:      dir,
		name:     name,
		readOnly: false,
	}, nil
}

// RemoveBackup implements BackupStorage.
func (bs *GCSBackupStorage) RemoveBackup(ctx context.Context, dir, name string) error {
	c, err := bs.client(ctx)
	if err != nil {
		return err
	}

	// Find all objects with the right prefix.
	query := &storage.Query{
		Prefix: objName(dir, name, "" /* include trailing slash */),
	}
	// Delete all the found objects.
	it := c.Bucket(*bucket).Objects(ctx, query)
	for {
		obj, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		if err := c.Bucket(*bucket).Object(obj.Name).Delete(ctx); err != nil {
			return fmt.Errorf("unable to delete %q from bucket %q: %v", obj.Name, *bucket, err)
		}
	}
	return nil
}

// Close implements BackupStorage.
func (bs *GCSBackupStorage) Close() error {
	bs.mu.Lock()
	defer bs.mu.Unlock()

	if bs._client != nil {
		// If client.Close() fails, we still clear bs._client,
		// so we know to create a new client the next time one
		// is needed.
		client := bs._client
		bs._client = nil
		if err := client.Close(); err != nil {
			return err
		}
	}
	return nil
}

// client returns the GCS Storage client instance.
// If there isn't one yet, it tries to create one.
func (bs *GCSBackupStorage) client(ctx context.Context) (*storage.Client, error) {
	bs.mu.Lock()
	defer bs.mu.Unlock()

	if bs._client == nil {
		// The context needs to be valid for longer than just
		// the creation context, so we create a new one, but
		// keep the span information.
		ctx = trace.CopySpan(context.Background(), ctx)
		authClient, err := google.DefaultClient(ctx)
		if err != nil {
			return nil, err
		}
		client, err := storage.NewClient(ctx, option.WithHTTPClient(authClient))
		if err != nil {
			return nil, err
		}
		bs._client = client
	}
	return bs._client, nil
}

// objName joins path parts into an object name.
// Unlike path.Join, it doesn't collapse ".." or strip trailing slashes.
// It also adds the value of the -gcs_backup_storage_root flag if set.
func objName(parts ...string) string {
	if *root != "" {
		return *root + "/" + strings.Join(parts, "/")
	}
	return strings.Join(parts, "/")
}

func init() {
	backupstorage.BackupStorageMap["gcs"] = &GCSBackupStorage{}
}
<commit_msg>Add scope to oauth token for gcs backup storage client<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

// Package gcsbackupstorage implements the BackupStorage interface
// for Google Cloud Storage.
package gcsbackupstorage

import (
	"flag"
	"fmt"
	"io"
	"sort"
	"strings"
	"sync"

	"cloud.google.com/go/storage"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"

	"vitess.io/vitess/go/trace"
	"vitess.io/vitess/go/vt/mysqlctl/backupstorage"
)

var (
	_ = flag.String("gcs_backup_storage_project", "", "This flag is unused and deprecated. It will be removed entirely in a future release.")

	// bucket is where the backups will go.
	bucket = flag.String("gcs_backup_storage_bucket", "", "Google Cloud Storage bucket to use for backups")

	// root is a prefix added to all object names.
	root = flag.String("gcs_backup_storage_root", "", "root prefix for all backup-related object names")
)

// GCSBackupHandle implements BackupHandle for Google Cloud Storage.
type GCSBackupHandle struct {
	client   *storage.Client
	bs       *GCSBackupStorage
	dir      string
	name     string
	readOnly bool
}

// Directory implements BackupHandle.
func (bh *GCSBackupHandle) Directory() string {
	return bh.dir
}

// Name implements BackupHandle.
func (bh *GCSBackupHandle) Name() string {
	return bh.name
}

// AddFile implements BackupHandle.
func (bh *GCSBackupHandle) AddFile(ctx context.Context, filename string, filesize int64) (io.WriteCloser, error) {
	if bh.readOnly {
		return nil, fmt.Errorf("AddFile cannot be called on read-only backup")
	}
	object := objName(bh.dir, bh.name, filename)
	return bh.client.Bucket(*bucket).Object(object).NewWriter(ctx), nil
}

// EndBackup implements BackupHandle.
func (bh *GCSBackupHandle) EndBackup(ctx context.Context) error {
	if bh.readOnly {
		return fmt.Errorf("EndBackup cannot be called on read-only backup")
	}
	return nil
}

// AbortBackup implements BackupHandle.
func (bh *GCSBackupHandle) AbortBackup(ctx context.Context) error {
	if bh.readOnly {
		return fmt.Errorf("AbortBackup cannot be called on read-only backup")
	}
	return bh.bs.RemoveBackup(ctx, bh.dir, bh.name)
}

// ReadFile implements BackupHandle.
func (bh *GCSBackupHandle) ReadFile(ctx context.Context, filename string) (io.ReadCloser, error) {
	if !bh.readOnly {
		return nil, fmt.Errorf("ReadFile cannot be called on read-write backup")
	}
	object := objName(bh.dir, bh.name, filename)
	return bh.client.Bucket(*bucket).Object(object).NewReader(ctx)
}

// GCSBackupStorage implements BackupStorage for Google Cloud Storage.
type GCSBackupStorage struct {
	// client is the instance of the Google Cloud Storage Go client.
	// Once this field is set, it must not be written again/unset to nil.
	_client *storage.Client
	// mu guards all fields.
	mu sync.Mutex
}

// ListBackups implements BackupStorage.
func (bs *GCSBackupStorage) ListBackups(ctx context.Context, dir string) ([]backupstorage.BackupHandle, error) {
	c, err := bs.client(ctx)
	if err != nil {
		return nil, err
	}

	// List prefixes that begin with dir (i.e. list subdirs).
	var subdirs []string
	searchPrefix := objName(dir, "" /* include trailing slash */)
	query := &storage.Query{
		Delimiter: "/",
		Prefix:    searchPrefix,
	}

	it := c.Bucket(*bucket).Objects(ctx, query)
	for {
		obj, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		// Each returned prefix is a subdir.
		// Strip parent dir from full path.
		if obj.Prefix != "" {
			subdir := strings.TrimPrefix(obj.Prefix, searchPrefix)
			subdir = strings.TrimSuffix(subdir, "/")
			subdirs = append(subdirs, subdir)
		}
	}

	// Backups must be returned in order, oldest first.
	sort.Strings(subdirs)

	result := make([]backupstorage.BackupHandle, 0, len(subdirs))
	for _, subdir := range subdirs {
		result = append(result, &GCSBackupHandle{
			client:   c,
			bs:       bs,
			dir:      dir,
			name:     subdir,
			readOnly: true,
		})
	}
	return result, nil
}

// StartBackup implements BackupStorage.
func (bs *GCSBackupStorage) StartBackup(ctx context.Context, dir, name string) (backupstorage.BackupHandle, error) {
	c, err := bs.client(ctx)
	if err != nil {
		return nil, err
	}

	return &GCSBackupHandle{
		client:   c,
		bs:       bs,
		dir:      dir,
		name:     name,
		readOnly: false,
	}, nil
}

// RemoveBackup implements BackupStorage.
func (bs *GCSBackupStorage) RemoveBackup(ctx context.Context, dir, name string) error {
	c, err := bs.client(ctx)
	if err != nil {
		return err
	}

	// Find all objects with the right prefix.
	query := &storage.Query{
		Prefix: objName(dir, name, "" /* include trailing slash */),
	}
	// Delete all the found objects.
	it := c.Bucket(*bucket).Objects(ctx, query)
	for {
		obj, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		if err := c.Bucket(*bucket).Object(obj.Name).Delete(ctx); err != nil {
			return fmt.Errorf("unable to delete %q from bucket %q: %v", obj.Name, *bucket, err)
		}
	}
	return nil
}

// Close implements BackupStorage.
func (bs *GCSBackupStorage) Close() error {
	bs.mu.Lock()
	defer bs.mu.Unlock()

	if bs._client != nil {
		// If client.Close() fails, we still clear bs._client,
		// so we know to create a new client the next time one
		// is needed.
		client := bs._client
		bs._client = nil
		if err := client.Close(); err != nil {
			return err
		}
	}
	return nil
}

// client returns the GCS Storage client instance.
// If there isn't one yet, it tries to create one.
func (bs *GCSBackupStorage) client(ctx context.Context) (*storage.Client, error) {
	bs.mu.Lock()
	defer bs.mu.Unlock()

	if bs._client == nil {
		// The context needs to be valid for longer than just
		// the creation context, so we create a new one, but
		// keep the span information.
		ctx = trace.CopySpan(context.Background(), ctx)
		authClient, err := google.DefaultClient(ctx, storage.ScopeFullControl)
		if err != nil {
			return nil, err
		}
		client, err := storage.NewClient(ctx, option.WithHTTPClient(authClient))
		if err != nil {
			return nil, err
		}
		bs._client = client
	}
	return bs._client, nil
}

// objName joins path parts into an object name.
// Unlike path.Join, it doesn't collapse ".." or strip trailing slashes.
// It also adds the value of the -gcs_backup_storage_root flag if set.
func objName(parts ...string) string {
	if *root != "" {
		return *root + "/" + strings.Join(parts, "/")
	}
	return strings.Join(parts, "/")
}

func init() {
	backupstorage.BackupStorageMap["gcs"] = &GCSBackupStorage{}
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "os"
    "os/exec"
    "log"
    "io"
    "io/ioutil"
    "encoding/json"
)

type UnlockRunnerConf struct {
    UnlockDirectory string
    PythonPathEnvVar string
    PythonPath string
    UnlockRuntime string
}

func ParseConf(runnerConfFile string) UnlockRunnerConf {
    log.Printf("Confile = "+runnerConfFile)
    file, e := ioutil.ReadFile(runnerConfFile)
    if e != nil {
        log.Fatalf("File error: %v\n", e)
    }
    var conf UnlockRunnerConf
    json.Unmarshal(file, &conf)
    return conf
}

func main() {
    logf, err := os.OpenFile(`unlock.log`, os.O_WRONLY|os.O_CREATE,0640)
    if err != nil {
        log.Fatalln(err)
    }
    log.SetOutput(io.MultiWriter(logf, os.Stdout))

    var runnerConf = UnlockRunnerConf {`C:\Unlock`,
            `C:\Python33;C:\Python33\Lib;C:\Python33\Lib\site-packages;C:\Python33\Lib\site-packages\unlock;C:\Python27\DLLs`,
            `C:\Python33\python.exe`,
            `C:\Python33\Lib\site-packages\unlock\unlock_runtime.py`}

    var confFile = flag.String("conf", "", "path to the configuration; if not set the default is used")
    var fullscreen = flag.Bool("fullscreen", false, "make unlock fullscreen; overrides conf file settings")
    var fps = flag.Bool("fps", false, "displays the frequence per second; overrides the conf file setting")
    var signal = flag.String("signal", "", "selects the signaling system; valid values are: random, mobilab, enobio; default value is random; overrides the config file setting")

    flag.Parse()
    var unlock_cmd = runnerConf.PythonPath + ` ` + runnerConf.UnlockRuntime + ` `

    if *confFile != `` {
        unlock_cmd += ` -c `+*confFile
    }

    if *fullscreen {
        unlock_cmd += ` -n `
    }

    if *fps {
        unlock_cmd += ` -f `
    }

    if *signal != `` {
        unlock_cmd += ` -s `+*signal
    }

    cmd, err := exec.Command("cmd", "/C", unlock_cmd).CombinedOutput()
    if len(cmd) > 0 {
        log.Printf("%s\n",cmd)
    }
    if err != nil {
        log.Fatalln(`FATAL: Unlock Runtime failed`)
    }
}
<commit_msg>Fixed file open to use append<commit_after>package main

import (
    "flag"
    "os"
    "os/exec"
    "log"
    "io"
    "io/ioutil"
    "encoding/json"
)

type UnlockRunnerConf struct {
    UnlockDirectory string
    PythonPathEnvVar string
    PythonPath string
    UnlockRuntime string
}

func ParseConf(runnerConfFile string) UnlockRunnerConf {
    log.Printf("Confile = "+runnerConfFile)
    file, e := ioutil.ReadFile(runnerConfFile)
    if e != nil {
        log.Fatalf("File error: %v\n", e)
    }
    var conf UnlockRunnerConf
    json.Unmarshal(file, &conf)
    return conf
}

func main() {

    logf, err := os.OpenFile(`unlock.log`, os.O_APPEND|os.O_CREATE,0640)
    if err != nil {
        log.Fatalln(err)
    }
    log.SetOutput(io.MultiWriter(logf, os.Stdout))

    var runnerConf = UnlockRunnerConf {`C:\Unlock`,
            `C:\Python33;C:\Python33\Lib;C:\Python33\Lib\site-packages;C:\Python33\Lib\site-packages\unlock;C:\Python27\DLLs`,
            `C:\Python33\python.exe`,
            `C:\Python33\Lib\site-packages\unlock\unlock_runtime.py`}

    var confFile = flag.String("conf", "", "path to the configuration; if not set the default is used")
    var fullscreen = flag.Bool("fullscreen", false, "make unlock fullscreen; overrides conf file settings")
    var fps = flag.Bool("fps", false, "displays the frequence per second; overrides the conf file setting")
    var signal = flag.String("signal", "", "selects the signaling system; valid values are: random, mobilab, enobio; default value is random; overrides the config file setting")

    flag.Parse()
    var unlock_cmd = runnerConf.PythonPath + ` ` + runnerConf.UnlockRuntime + ` `

    if *confFile != `` {
        unlock_cmd += ` -c `+*confFile
    }

    if *fullscreen {
        unlock_cmd += ` -n `
    }

    if *fps {
        unlock_cmd += ` -f `
    }

    if *signal != `` {
        unlock_cmd += ` -s `+*signal
    }

    cmd, err := exec.Command("cmd", "/C", unlock_cmd).CombinedOutput()
    if len(cmd) > 0 {
        log.Printf("%s\n",cmd)
    }
    if err != nil {
        log.Fatalln(`FATAL: Unlock Runtime failed`)
    }
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"time"
)

// type Annotation struct is defined in annotation.go

func addAnnotationHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\naddAnnotation-request: %v\n", req.URL)

	// get session
	cs, err := getClientSession(req.Header.Get(headerKeySessionKey))
	if err != nil {
		http.Error(rw, "error", http.StatusInternalServerError)
		return
	}
	defer cs.done()

	// get account
	acc := cs.account
	if acc == nil {
		http.Error(rw, "forbidden", http.StatusForbidden)
		return
	}

	body, _ := ioutil.ReadAll(req.Body)
	log.Printf("\n\nbody is %s\n", string(body))
	annot := &Annotation{}
	err = json.Unmarshal(body, annot)
	if err != nil {
		log.Printf("\n\nJSON unmarshal error %#v\n", err)
		http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
		return
	}

	// Set every other field to things we control.
	annot.ID = bson.NewObjectId()
	annot.AnnotatorUsername = acc.Username
	annot.Color = acc.Color
	annot.CreateDate = time.Now()
	annot.Comments = []Comment{}

	// Normalize the coordinates: X1,Y1 at top left, X2,Y2 as bottom right.
	for _, coord := range annot.Locations {
		coord.X1 = min(coord.X1, coord.X2)
		coord.X2 = max(coord.X1, coord.X2)
		coord.Y1 = min(coord.Y1, coord.Y2)
		coord.Y2 = max(coord.Y1, coord.Y2)
	}

	log.Printf("\n\nAnnotation to insert is: %#v\n", *annot)

	err = insertAnnotation(annot)
	if err != nil {
		log.Printf("Error inserting annotation: error %#v\n", err)
		http.Error(rw, "error inserting annotation", http.StatusInternalServerError) // 500
		return
	}

	// marshal and write out.
	j, err := json.Marshal(annot)
	if err != nil {
		log.Printf("Error marshalling results: error %#v\n", err)
		http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
		return
	}
	rw.WriteHeader(200)
	rw.Write(j)
	return
}

// AddCommentParams holds comment parameters
type AddCommentParams struct {
	//DocumentID bson.ObjectId
	AnnotationID bson.ObjectId
	// Parent bson.ObjectId
	CommentText string
}

// Add a comment to an annotation (non threaded for now)
func addCommentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\naddComment-request: %v\n", req)

	// get session
	cs, err := getClientSession(req.Header.Get(headerKeySessionKey))
	if err != nil {
		http.Error(rw, "error", http.StatusInternalServerError)
		return
	}
	defer cs.done()

	// get account
	acc := cs.account
	if acc == nil {
		http.Error(rw, "forbidden", http.StatusForbidden)
		return
	}

	body, _ := ioutil.ReadAll(req.Body)
	log.Printf("\n\nbody is %s\n", string(body))
	params := &AddCommentParams{}
	err = json.Unmarshal(body, params)
	if err != nil {
		log.Printf("\n\nJSON unmarshal error %#v\n", err)
		http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
		return
	}
	comment := Comment{
		ID:                bson.NewObjectId(),
		CommenterUsername: acc.Username,
		Color:             acc.Color,
		CreateDate:        time.Now(),
		CommentText:       params.CommentText,
		Comments:          []Comment{},
	}
	log.Printf("\n\ncomment to add is: %#v\n", comment)

	err = updateAnnotationID(params.AnnotationID, bson.M{"$push": bson.M{"comments": comment}})
	if err != nil {
		log.Printf("Error adding comment to annotation: error %#v\n", err)
		http.Error(rw, "error adding comment to annotation", http.StatusInternalServerError) // 500
		return
	}

	// marshal and write out.
	j, err := json.Marshal(comment)
	if err != nil {
		log.Printf("Error marshalling results: error %#v\n", err)
		http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
		return
	}
	rw.WriteHeader(200)
	rw.Write(j)
	return
}

// Because package Math doesn't have Max and Min for float32...
func min(a, b float32) float32 {
	if a < b {
		return a
	} else {
		return b
	}
}

func max(a, b float32) float32 {
	if a > b {
		return a
	} else {
		return b
	}
}
<commit_msg>Now the highlights show where you expect them.<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"time"
)

// type Annotation struct is defined in annotation.go

func addAnnotationHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\naddAnnotation-request: %v\n", req.URL)

	// get session
	cs, err := getClientSession(req.Header.Get(headerKeySessionKey))
	if err != nil {
		http.Error(rw, "error", http.StatusInternalServerError)
		return
	}
	defer cs.done()

	// get account
	acc := cs.account
	if acc == nil {
		http.Error(rw, "forbidden", http.StatusForbidden)
		return
	}

	body, _ := ioutil.ReadAll(req.Body)
	log.Printf("\n\nbody is %s\n", string(body))
	annot := &Annotation{}
	err = json.Unmarshal(body, annot)
	if err != nil {
		log.Printf("\n\nJSON unmarshal error %#v\n", err)
		http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
		return
	}

	// Set every other field to things we control.
	annot.ID = bson.NewObjectId()
	annot.AnnotatorUsername = acc.Username
	annot.Color = acc.Color
	annot.CreateDate = time.Now()
	annot.Comments = []Comment{}

	// Normalize the coordinates: X1,Y1 at top left, X2,Y2 as bottom right.
	for i, coord := range annot.Locations {
		coord.X1, coord.X2 = min(coord.X1, coord.X2), max(coord.X1, coord.X2)
		coord.Y1, coord.Y2 = min(coord.Y1, coord.Y2), max(coord.Y1, coord.Y2)
		annot.Locations[i] = coord // set it, as range gives a copy.
	}

	log.Printf("\n\nAnnotation to insert is: %#v\n", *annot)

	err = insertAnnotation(annot)
	if err != nil {
		log.Printf("Error inserting annotation: error %#v\n", err)
		http.Error(rw, "error inserting annotation", http.StatusInternalServerError) // 500
		return
	}

	// marshal and write out.
	j, err := json.Marshal(annot)
	if err != nil {
		log.Printf("Error marshalling results: error %#v\n", err)
		http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
		return
	}
	rw.WriteHeader(200)
	rw.Write(j)
	return
}

// AddCommentParams holds comment parameters
type AddCommentParams struct {
	//DocumentID bson.ObjectId
	AnnotationID bson.ObjectId
	// Parent bson.ObjectId
	CommentText string
}

// Add a comment to an annotation (non threaded for now)
func addCommentHandler(rw http.ResponseWriter, req *http.Request) {
	log.Printf("\n\naddComment-request: %v\n", req)

	// get session
	cs, err := getClientSession(req.Header.Get(headerKeySessionKey))
	if err != nil {
		http.Error(rw, "error", http.StatusInternalServerError)
		return
	}
	defer cs.done()

	// get account
	acc := cs.account
	if acc == nil {
		http.Error(rw, "forbidden", http.StatusForbidden)
		return
	}

	body, _ := ioutil.ReadAll(req.Body)
	log.Printf("\n\nbody is %s\n", string(body))
	params := &AddCommentParams{}
	err = json.Unmarshal(body, params)
	if err != nil {
		log.Printf("\n\nJSON unmarshal error %#v\n", err)
		http.Error(rw, "JSON unmarshal error", http.StatusBadRequest) // 400
		return
	}
	comment := Comment{
		ID:                bson.NewObjectId(),
		CommenterUsername: acc.Username,
		Color:             acc.Color,
		CreateDate:        time.Now(),
		CommentText:       params.CommentText,
		Comments:          []Comment{},
	}
	log.Printf("\n\ncomment to add is: %#v\n", comment)

	err = updateAnnotationID(params.AnnotationID, bson.M{"$push": bson.M{"comments": comment}})
	if err != nil {
		log.Printf("Error adding comment to annotation: error %#v\n", err)
		http.Error(rw, "error adding comment to annotation", http.StatusInternalServerError) // 500
		return
	}

	// marshal and write out.
	j, err := json.Marshal(comment)
	if err != nil {
		log.Printf("Error marshalling results: error %#v\n", err)
		http.Error(rw, "Marshaling error", http.StatusInternalServerError) // 500
		return
	}
	rw.WriteHeader(200)
	rw.Write(j)
	return
}

// Because package Math doesn't have Max and Min for float32...
func min(a, b float32) float32 {
	if a < b {
		return a
	} else {
		return b
	}
}

func max(a, b float32) float32 {
	if a > b {
		return a
	} else {
		return b
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Google LLC
//
// 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 logging contains a Stackdriver Logging client suitable for writing logs.
For reading logs, and working with sinks, metrics and monitored resources,
see package cloud.google.com/go/logging/logadmin.

This client uses Logging API v2.
See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.

Note: This package is in beta.  Some backwards-incompatible changes may occur.

Creating a Client

Use a Client to interact with the Stackdriver Logging API.

	// Create a Client
	ctx := context.Background()
	client, err := logging.NewClient(ctx, "my-project")
	if err != nil {
		// TODO: Handle error.
	}

Basic Usage

For most use cases, you'll want to add log entries to a buffer to be periodically
flushed (automatically and asynchronously) to the Stackdriver Logging service.

	// Initialize a logger
	lg := client.Logger("my-log")

	// Add entry to log buffer
	lg.Log(logging.Entry{Payload: "something happened!"})

Closing your Client

You should call Client.Close before your program exits to flush any buffered log entries to the Stackdriver Logging service.

	// Close the client when finished.
	err = client.Close()
	if err != nil {
		// TODO: Handle error.
	}

Synchronous Logging

For critical errors, you may want to send your log entries immediately.
LogSync is slow and will block until the log entry has been sent, so it is
not recommended for normal use.

	lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"})

Payloads

An entry payload can be a string, as in the examples above. It can also be any value
that can be marshaled to a JSON object, like a map[string]interface{} or a struct:

	type MyEntry struct {
		Name  string
		Count int
	}
	lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}})

If you have a []byte of JSON, wrap it in json.RawMessage:

	j := []byte(`{"Name": "Bob", "Count": 3}`)
	lg.Log(logging.Entry{Payload: json.RawMessage(j)})

The Standard Logger Interface

You may want use a standard log.Logger in your program.

	// stdlg implements log.Logger
	stdlg := lg.StandardLogger(logging.Info)
	stdlg.Println("some info")

Log Levels

An Entry may have one of a number of severity levels associated with it.

	logging.Entry{
		Payload: "something terrible happened!",
		Severity: logging.Critical,
	}

Viewing Logs

You can view Stackdriver logs for projects at
https://console.cloud.google.com/logs/viewer. Use the dropdown at the top left. When
running from a Google Cloud Platform VM, select "GCE VM Instance". Otherwise, select
"Google Project" and then the project ID. Logs for organizations, folders and billing
accounts can be viewed on the command line with the "gcloud logging read" command.

*/
package logging // import "cloud.google.com/go/logging"
<commit_msg>logging: document per-request logging<commit_after>// Copyright 2016 Google LLC
//
// 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 logging contains a Stackdriver Logging client suitable for writing logs.
For reading logs, and working with sinks, metrics and monitored resources,
see package cloud.google.com/go/logging/logadmin.

This client uses Logging API v2.
See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.

Note: This package is in beta.  Some backwards-incompatible changes may occur.

Creating a Client

Use a Client to interact with the Stackdriver Logging API.

	// Create a Client
	ctx := context.Background()
	client, err := logging.NewClient(ctx, "my-project")
	if err != nil {
		// TODO: Handle error.
	}

Basic Usage

For most use cases, you'll want to add log entries to a buffer to be periodically
flushed (automatically and asynchronously) to the Stackdriver Logging service.

	// Initialize a logger
	lg := client.Logger("my-log")

	// Add entry to log buffer
	lg.Log(logging.Entry{Payload: "something happened!"})

Closing your Client

You should call Client.Close before your program exits to flush any buffered log entries to the Stackdriver Logging service.

	// Close the client when finished.
	err = client.Close()
	if err != nil {
		// TODO: Handle error.
	}

Synchronous Logging

For critical errors, you may want to send your log entries immediately.
LogSync is slow and will block until the log entry has been sent, so it is
not recommended for normal use.

	lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"})

Payloads

An entry payload can be a string, as in the examples above. It can also be any value
that can be marshaled to a JSON object, like a map[string]interface{} or a struct:

	type MyEntry struct {
		Name  string
		Count int
	}
	lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}})

If you have a []byte of JSON, wrap it in json.RawMessage:

	j := []byte(`{"Name": "Bob", "Count": 3}`)
	lg.Log(logging.Entry{Payload: json.RawMessage(j)})

The Standard Logger Interface

You may want use a standard log.Logger in your program.

	// stdlg implements log.Logger
	stdlg := lg.StandardLogger(logging.Info)
	stdlg.Println("some info")

Log Levels

An Entry may have one of a number of severity levels associated with it.

	logging.Entry{
		Payload: "something terrible happened!",
		Severity: logging.Critical,
	}

Viewing Logs

You can view Stackdriver logs for projects at
https://console.cloud.google.com/logs/viewer. Use the dropdown at the top left. When
running from a Google Cloud Platform VM, select "GCE VM Instance". Otherwise, select
"Google Project" and then the project ID. Logs for organizations, folders and billing
accounts can be viewed on the command line with the "gcloud logging read" command.

Grouping Logs by Request

To group all the log entries written during a single HTTP request, create two
Loggers, a "parent" and a "child," with different log IDs. Both should be in the same
project, and have the same MonitoredResouce type and labels.

- Parent entries must have HTTPRequest.Request populated. (Strictly speaking, only the URL is necessary.)

- A child entry's timestamp must be within the time interval covered by the parent request (i.e., older
  than parent.Timestamp, and newer than parent.Timestamp - parent.HTTPRequest.Latency, assuming the
  parent timestamp marks the end of the request.

- The trace field must be populated in all of the entries and match exactly.

You should observe the child log entries grouped under the parent on the console. The
parent entry will not inherit the severity of its children; you must update the
parent severity yourself.
*/
package logging // import "cloud.google.com/go/logging"
<|endoftext|>


<commit_before>// Copyright 2016 Google LLC
//
// 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 logging contains a Stackdriver Logging client suitable for writing logs.
For reading logs, and working with sinks, metrics and monitored resources,
see package cloud.google.com/go/logging/logadmin.

This client uses Logging API v2.
See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.

Note: This package is in beta.  Some backwards-incompatible changes may occur.

Creating a Client

Use a Client to interact with the Stackdriver Logging API.

	// Create a Client
	ctx := context.Background()
	client, err := logging.NewClient(ctx, "my-project")
	if err != nil {
		// TODO: Handle error.
	}

Basic Usage

For most use cases, you'll want to add log entries to a buffer to be periodically
flushed (automatically and asynchronously) to the Stackdriver Logging service.

	// Initialize a logger
	lg := client.Logger("my-log")

	// Add entry to log buffer
	lg.Log(logging.Entry{Payload: "something happened!"})

Closing your Client

You should call Client.Close before your program exits to flush any buffered log entries to the Stackdriver Logging service.

	// Close the client when finished.
	err = client.Close()
	if err != nil {
		// TODO: Handle error.
	}

Synchronous Logging

For critical errors, you may want to send your log entries immediately.
LogSync is slow and will block until the log entry has been sent, so it is
not recommended for normal use.

	lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"})

Payloads

An entry payload can be a string, as in the examples above. It can also be any value
that can be marshaled to a JSON object, like a map[string]interface{} or a struct:

	type MyEntry struct {
		Name  string
		Count int
	}
	lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}})

If you have a []byte of JSON, wrap it in json.RawMessage:

	j := []byte(`{"Name": "Bob", "Count": 3}`)
	lg.Log(logging.Entry{Payload: json.RawMessage(j)})

The Standard Logger Interface

You may want use a standard log.Logger in your program.

	// stdlg implements log.Logger
	stdlg := lg.StandardLogger(logging.Info)
	stdlg.Println("some info")

Log Levels

An Entry may have one of a number of severity levels associated with it.

	logging.Entry{
		Payload: "something terrible happened!",
		Severity: logging.Critical,
	}

Viewing Logs

You can view Stackdriver logs for projects at
https://console.cloud.google.com/logs/viewer. Use the dropdown at the top left. When
running from a Google Cloud Platform VM, select "GCE VM Instance". Otherwise, select
"Google Project" and then the project ID. Logs for organizations, folders and billing
accounts can be viewed on the command line with the "gcloud logging read" command.

Grouping Logs by Request

To group all the log entries written during a single HTTP request, create two
Loggers, a "parent" and a "child," with different log IDs. Both should be in the same
project, and have the same MonitoredResouce type and labels.

- Parent entries must have HTTPRequest.Request populated. (Strictly speaking, only the URL is necessary.)

- A child entry's timestamp must be within the time interval covered by the parent request (i.e., older
than parent.Timestamp, and newer than parent.Timestamp - parent.HTTPRequest.Latency, assuming the
parent timestamp marks the end of the request.

- The trace field must be populated in all of the entries and match exactly.

You should observe the child log entries grouped under the parent on the console. The
parent entry will not inherit the severity of its children; you must update the
parent severity yourself.
*/
package logging // import "cloud.google.com/go/logging"
<commit_msg>logging: add err checking to docs<commit_after>// Copyright 2016 Google LLC
//
// 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 logging contains a Stackdriver Logging client suitable for writing logs.
For reading logs, and working with sinks, metrics and monitored resources,
see package cloud.google.com/go/logging/logadmin.

This client uses Logging API v2.
See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.

Note: This package is in beta.  Some backwards-incompatible changes may occur.

Creating a Client

Use a Client to interact with the Stackdriver Logging API.

	// Create a Client
	ctx := context.Background()
	client, err := logging.NewClient(ctx, "my-project")
	if err != nil {
		// TODO: Handle error.
	}

Basic Usage

For most use cases, you'll want to add log entries to a buffer to be periodically
flushed (automatically and asynchronously) to the Stackdriver Logging service.

	// Initialize a logger
	lg := client.Logger("my-log")

	// Add entry to log buffer
	lg.Log(logging.Entry{Payload: "something happened!"})

Closing your Client

You should call Client.Close before your program exits to flush any buffered log entries to the Stackdriver Logging service.

	// Close the client when finished.
	err = client.Close()
	if err != nil {
		// TODO: Handle error.
	}

Synchronous Logging

For critical errors, you may want to send your log entries immediately.
LogSync is slow and will block until the log entry has been sent, so it is
not recommended for normal use.

	err = lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"})
	if err != nil {
		// TODO: Handle error.
	}

Payloads

An entry payload can be a string, as in the examples above. It can also be any value
that can be marshaled to a JSON object, like a map[string]interface{} or a struct:

	type MyEntry struct {
		Name  string
		Count int
	}
	lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}})

If you have a []byte of JSON, wrap it in json.RawMessage:

	j := []byte(`{"Name": "Bob", "Count": 3}`)
	lg.Log(logging.Entry{Payload: json.RawMessage(j)})

The Standard Logger Interface

You may want use a standard log.Logger in your program.

	// stdlg implements log.Logger
	stdlg := lg.StandardLogger(logging.Info)
	stdlg.Println("some info")

Log Levels

An Entry may have one of a number of severity levels associated with it.

	logging.Entry{
		Payload: "something terrible happened!",
		Severity: logging.Critical,
	}

Viewing Logs

You can view Stackdriver logs for projects at
https://console.cloud.google.com/logs/viewer. Use the dropdown at the top left. When
running from a Google Cloud Platform VM, select "GCE VM Instance". Otherwise, select
"Google Project" and then the project ID. Logs for organizations, folders and billing
accounts can be viewed on the command line with the "gcloud logging read" command.

Grouping Logs by Request

To group all the log entries written during a single HTTP request, create two
Loggers, a "parent" and a "child," with different log IDs. Both should be in the same
project, and have the same MonitoredResouce type and labels.

- Parent entries must have HTTPRequest.Request populated. (Strictly speaking, only the URL is necessary.)

- A child entry's timestamp must be within the time interval covered by the parent request (i.e., older
than parent.Timestamp, and newer than parent.Timestamp - parent.HTTPRequest.Latency, assuming the
parent timestamp marks the end of the request.

- The trace field must be populated in all of the entries and match exactly.

You should observe the child log entries grouped under the parent on the console. The
parent entry will not inherit the severity of its children; you must update the
parent severity yourself.
*/
package logging // import "cloud.google.com/go/logging"
<|endoftext|>


<commit_before>package storage

import (
	"bytes"
	"io"
	"testing"
)

func TestJsonPackerUnpacker(t *testing.T) {
	e := []Entry{
		Entry{
			Type:    SegmentType,
			Payload: []byte("how"),
		},
		Entry{
			Type:    SegmentType,
			Payload: []byte("y'all"),
		},
		Entry{
			Type:    FileType,
			Name:    "./hurr.txt",
			Payload: []byte("deadbeef"),
		},
		Entry{
			Type:    SegmentType,
			Payload: []byte("doin"),
		},
	}

	buf := []byte{}
	b := bytes.NewBuffer(buf)

	func() {
		jp := NewJsonPacker(b)
		for i := range e {
			if _, err := jp.AddEntry(e[i]); err != nil {
				t.Error(err)
			}
		}
	}()

	b = bytes.NewBuffer(b.Bytes())
	entries := Entries{}
	func() {
		jup := NewJsonUnpacker(b)
		for {
			entry, err := jup.Next()
			if err != nil {
				if err == io.EOF {
					break
				}
				t.Error(err)
			}
			entries = append(entries, *entry)
			t.Logf("got %#v", entry)
		}
	}()
	if len(entries) != len(e) {
		t.Errorf("expected %d entries, got %d", len(e), len(entries))
	}

}
<commit_msg>tar/storage: show gzip usage in a test<commit_after>package storage

import (
	"bytes"
	"compress/gzip"
	"io"
	"testing"
)

func TestJsonPackerUnpacker(t *testing.T) {
	e := []Entry{
		Entry{
			Type:    SegmentType,
			Payload: []byte("how"),
		},
		Entry{
			Type:    SegmentType,
			Payload: []byte("y'all"),
		},
		Entry{
			Type:    FileType,
			Name:    "./hurr.txt",
			Payload: []byte("deadbeef"),
		},
		Entry{
			Type:    SegmentType,
			Payload: []byte("doin"),
		},
	}

	buf := []byte{}
	b := bytes.NewBuffer(buf)

	func() {
		jp := NewJsonPacker(b)
		for i := range e {
			if _, err := jp.AddEntry(e[i]); err != nil {
				t.Error(err)
			}
		}
	}()

	// >> packer_test.go:43: uncompressed: 266
	//t.Errorf("uncompressed: %d", len(b.Bytes()))

	b = bytes.NewBuffer(b.Bytes())
	entries := Entries{}
	func() {
		jup := NewJsonUnpacker(b)
		for {
			entry, err := jup.Next()
			if err != nil {
				if err == io.EOF {
					break
				}
				t.Error(err)
			}
			entries = append(entries, *entry)
			t.Logf("got %#v", entry)
		}
	}()
	if len(entries) != len(e) {
		t.Errorf("expected %d entries, got %d", len(e), len(entries))
	}
}

// you can use a compress Reader/Writer and make nice savings.
//
// For these two tests that are using the same set, it the difference of 266
// bytes uncompressed vs 138 bytes compressed.
func TestGzip(t *testing.T) {
	e := []Entry{
		Entry{
			Type:    SegmentType,
			Payload: []byte("how"),
		},
		Entry{
			Type:    SegmentType,
			Payload: []byte("y'all"),
		},
		Entry{
			Type:    FileType,
			Name:    "./hurr.txt",
			Payload: []byte("deadbeef"),
		},
		Entry{
			Type:    SegmentType,
			Payload: []byte("doin"),
		},
	}

	buf := []byte{}
	b := bytes.NewBuffer(buf)
	gzW := gzip.NewWriter(b)
	jp := NewJsonPacker(gzW)
	for i := range e {
		if _, err := jp.AddEntry(e[i]); err != nil {
			t.Error(err)
		}
	}
	gzW.Close()

	// >> packer_test.go:99: compressed: 138
	//t.Errorf("compressed: %d", len(b.Bytes()))

	b = bytes.NewBuffer(b.Bytes())
	gzR, err := gzip.NewReader(b)
	if err != nil {
		t.Fatal(err)
	}
	entries := Entries{}
	func() {
		jup := NewJsonUnpacker(gzR)
		for {
			entry, err := jup.Next()
			if err != nil {
				if err == io.EOF {
					break
				}
				t.Error(err)
			}
			entries = append(entries, *entry)
			t.Logf("got %#v", entry)
		}
	}()
	if len(entries) != len(e) {
		t.Errorf("expected %d entries, got %d", len(e), len(entries))
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package logger

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	logging "github.com/keybase/go-logging"
	"golang.org/x/net/context"

	keybase1 "github.com/keybase/client/go/protocol"
)

const permDir os.FileMode = 0700

// Map from module name to whether SetLevel() has been called for that
// module.
var initLoggingSetLevelCalled = map[string]struct{}{}

// Protects access to initLoggingSetLevelCalled and the actual
// SetLevel call.
var initLoggingSetLevelMutex sync.Mutex

// CtxStandardLoggerKey is a type defining context keys used by the
// Standard logger.
type CtxStandardLoggerKey int

const (
	// CtxLogTagsKey defines a context key that can associate with a map of
	// context keys (key -> descriptive-name), the mapped values of which should
	// be logged by a Standard logger if one of those keys is seen in a context
	// during a log call.
	CtxLogTagsKey CtxStandardLoggerKey = iota
)

type CtxLogTags map[interface{}]string

// NewContext returns a new Context that carries adds the given log
// tag mappings (context key -> display string).
func NewContextWithLogTags(
	ctx context.Context, logTagsToAdd CtxLogTags) context.Context {
	currTags, _ := LogTagsFromContext(ctx)
	newTags := make(CtxLogTags)
	// Make a copy to avoid races
	for key, tag := range currTags {
		newTags[key] = tag
	}
	for key, tag := range logTagsToAdd {
		newTags[key] = tag
	}
	return context.WithValue(ctx, CtxLogTagsKey, newTags)
}

// LogTagsFromContext returns the log tags being passed along with the
// given context.
func LogTagsFromContext(ctx context.Context) (CtxLogTags, bool) {
	logTags, ok := ctx.Value(CtxLogTagsKey).(CtxLogTags)
	return logTags, ok
}

type ExternalLogger interface {
	Log(level keybase1.LogLevel, format string, args []interface{})
}

type entry struct {
	level  keybase1.LogLevel
	format string
	args   []interface{}
}

type Standard struct {
	internal       *logging.Logger
	filename       string
	configureMutex sync.Mutex
	module         string

	externalHandler ExternalHandler
}

// Verify Standard fully implements the Logger interface.
var _ Logger = (*Standard)(nil)

// New creates a new Standard logger for module.
func New(module string) *Standard {
	return NewWithCallDepth(module, 0)
}

// NewWithCallDepth creates a new Standard logger for module, and when
// printing file names and line numbers, it goes extraCallDepth up the
// stack from where logger was invoked.
func NewWithCallDepth(module string, extraCallDepth int) *Standard {
	log := logging.MustGetLogger(module)
	log.ExtraCalldepth = 1 + extraCallDepth

	ret := &Standard{
		internal: log,
		module:   module,
	}
	ret.setLogLevelInfo()
	return ret
}

func (log *Standard) setLogLevelInfo() {
	initLoggingSetLevelMutex.Lock()
	defer initLoggingSetLevelMutex.Unlock()

	if _, found := initLoggingSetLevelCalled[log.module]; !found {
		logging.SetLevel(logging.INFO, log.module)
		initLoggingSetLevelCalled[log.module] = struct{}{}
	}
}

func prepareString(
	ctx context.Context, fmts string) string {
	if ctx == nil {
		return fmts
	}
	logTags, ok := LogTagsFromContext(ctx)
	if !ok || len(logTags) == 0 {
		return fmts
	}
	var tags []string
	for key, tag := range logTags {
		if v := ctx.Value(key); v != nil {
			tags = append(tags, fmt.Sprintf("%s=%s", tag, v))
		}
	}
	return fmts + " [tags:" + strings.Join(tags, ",") + "]"
}

func (log *Standard) Debug(fmt string, arg ...interface{}) {
	log.internal.Debugf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_DEBUG, fmt, arg)
	}
}

func (log *Standard) CDebugf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.DEBUG) {
		log.Debug(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Info(fmt string, arg ...interface{}) {
	log.internal.Infof(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_INFO, fmt, arg)
	}
}

func (log *Standard) CInfof(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.INFO) {
		log.Info(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Notice(fmt string, arg ...interface{}) {
	log.internal.Noticef(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_NOTICE, fmt, arg)
	}
}

func (log *Standard) CNoticef(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.NOTICE) {
		log.Notice(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Warning(fmt string, arg ...interface{}) {
	log.internal.Warningf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_WARN, fmt, arg)
	}
}

func (log *Standard) CWarningf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.WARNING) {
		log.Warning(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Error(fmt string, arg ...interface{}) {
	log.internal.Errorf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_ERROR, fmt, arg)
	}
}

func (log *Standard) Errorf(fmt string, arg ...interface{}) {
	log.Error(fmt, arg...)
}

func (log *Standard) CErrorf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.ERROR) {
		log.Error(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Critical(fmt string, arg ...interface{}) {
	log.internal.Criticalf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_CRITICAL, fmt, arg)
	}
}

func (log *Standard) CCriticalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.CRITICAL) {
		log.Critical(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Fatalf(fmt string, arg ...interface{}) {
	log.internal.Fatalf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_FATAL, fmt, arg)
	}
}

func (log *Standard) CFatalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	log.Fatalf(prepareString(ctx, fmt), arg...)
}

func (log *Standard) Profile(fmts string, arg ...interface{}) {
	log.Debug(fmts, arg...)
}

// Configure sets the style of the log file, whether debugging (verbose)
// is enabled and a filename. If a filename is provided here it will
// be used for logging straight away (this is a new feature).
// SetLogFileConfig provides a way to set the log file with more control on rotation.
func (log *Standard) Configure(style string, debug bool, filename string) {
	log.configureMutex.Lock()
	defer log.configureMutex.Unlock()

	log.filename = filename

	var logfmt string

	globalLock.Lock()
	isTerm := stderrIsTerminal
	globalLock.Unlock()

	// TODO: how should setting the log file after a Configure be handled?
	if isTerm {
		if debug {
			logfmt = fancyFormat
		} else {
			logfmt = defaultFormat
		}
	} else {
		logfmt = fileFormat
	}

	// Override the format above if an explicit style was specified.
	switch style {
	case "default":
		logfmt = defaultFormat // Default
	case "plain":
		logfmt = plainFormat // Plain
	case "file":
		logfmt = fileFormat // Good for logging to files
	case "fancy":
		logfmt = fancyFormat // Fancy, good for terminals with color
	}

	if debug {
		logging.SetLevel(logging.DEBUG, log.module)
	}

	logging.SetFormatter(logging.MustStringFormatter(logfmt))

}

func OpenLogFile(filename string) (name string, file *os.File, err error) {
	name = filename
	if err = MakeParentDirs(name); err != nil {
		return
	}
	file, err = os.OpenFile(name, (os.O_APPEND | os.O_WRONLY | os.O_CREATE), 0600)
	if err != nil {
		return
	}
	return
}

func FileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func MakeParentDirs(filename string) error {
	dir, _ := filepath.Split(filename)
	// If passed a plain file name as a path
	if dir == "" {
		return nil
	}
	exists, err := FileExists(dir)
	if err != nil {
		return err
	}

	if !exists {
		err = os.MkdirAll(dir, permDir)
		if err != nil {
			return err
		}
	}
	return nil
}

func PickFirstError(errors ...error) error {
	for _, e := range errors {
		if e != nil {
			return e
		}
	}
	return nil
}

func (log *Standard) CloneWithAddedDepth(depth int) Logger {
	clone := *log
	cloneInternal := *log.internal
	cloneInternal.ExtraCalldepth = log.internal.ExtraCalldepth + depth
	clone.internal = &cloneInternal
	return &clone
}

func (log *Standard) SetExternalHandler(handler ExternalHandler) {
	log.externalHandler = handler
}

type UnforwardedLogger Standard

func (log *Standard) GetUnforwardedLogger() *UnforwardedLogger {
	return (*UnforwardedLogger)(log)
}

func (log *UnforwardedLogger) Debug(s string, args ...interface{}) {
	log.internal.Debugf(s, args...)
}

func (log *UnforwardedLogger) Error(s string, args ...interface{}) {
	log.internal.Errorf(s, args...)
}

func (log *UnforwardedLogger) Errorf(s string, args ...interface{}) {
	log.internal.Errorf(s, args...)
}

func (log *UnforwardedLogger) Warning(s string, args ...interface{}) {
	log.internal.Warningf(s, args...)
}

func (log *UnforwardedLogger) Info(s string, args ...interface{}) {
	log.internal.Infof(s, args...)
}

func (log *UnforwardedLogger) Profile(s string, args ...interface{}) {
	log.internal.Debugf(s, args...)
}
<commit_msg>Fix sync.Mutex copy<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package logger

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	logging "github.com/keybase/go-logging"
	"golang.org/x/net/context"

	keybase1 "github.com/keybase/client/go/protocol"
)

const permDir os.FileMode = 0700

// Map from module name to whether SetLevel() has been called for that
// module.
var initLoggingSetLevelCalled = map[string]struct{}{}

// Protects access to initLoggingSetLevelCalled and the actual
// SetLevel call.
var initLoggingSetLevelMutex sync.Mutex

// CtxStandardLoggerKey is a type defining context keys used by the
// Standard logger.
type CtxStandardLoggerKey int

const (
	// CtxLogTagsKey defines a context key that can associate with a map of
	// context keys (key -> descriptive-name), the mapped values of which should
	// be logged by a Standard logger if one of those keys is seen in a context
	// during a log call.
	CtxLogTagsKey CtxStandardLoggerKey = iota
)

type CtxLogTags map[interface{}]string

// NewContext returns a new Context that carries adds the given log
// tag mappings (context key -> display string).
func NewContextWithLogTags(
	ctx context.Context, logTagsToAdd CtxLogTags) context.Context {
	currTags, _ := LogTagsFromContext(ctx)
	newTags := make(CtxLogTags)
	// Make a copy to avoid races
	for key, tag := range currTags {
		newTags[key] = tag
	}
	for key, tag := range logTagsToAdd {
		newTags[key] = tag
	}
	return context.WithValue(ctx, CtxLogTagsKey, newTags)
}

// LogTagsFromContext returns the log tags being passed along with the
// given context.
func LogTagsFromContext(ctx context.Context) (CtxLogTags, bool) {
	logTags, ok := ctx.Value(CtxLogTagsKey).(CtxLogTags)
	return logTags, ok
}

type ExternalLogger interface {
	Log(level keybase1.LogLevel, format string, args []interface{})
}

type entry struct {
	level  keybase1.LogLevel
	format string
	args   []interface{}
}

type Standard struct {
	internal       *logging.Logger
	filename       string
	configureMutex sync.Mutex
	module         string

	externalHandler ExternalHandler
}

// Verify Standard fully implements the Logger interface.
var _ Logger = (*Standard)(nil)

// New creates a new Standard logger for module.
func New(module string) *Standard {
	return NewWithCallDepth(module, 0)
}

// NewWithCallDepth creates a new Standard logger for module, and when
// printing file names and line numbers, it goes extraCallDepth up the
// stack from where logger was invoked.
func NewWithCallDepth(module string, extraCallDepth int) *Standard {
	log := logging.MustGetLogger(module)
	log.ExtraCalldepth = 1 + extraCallDepth

	ret := &Standard{
		internal: log,
		module:   module,
	}
	ret.setLogLevelInfo()
	return ret
}

func (log *Standard) setLogLevelInfo() {
	initLoggingSetLevelMutex.Lock()
	defer initLoggingSetLevelMutex.Unlock()

	if _, found := initLoggingSetLevelCalled[log.module]; !found {
		logging.SetLevel(logging.INFO, log.module)
		initLoggingSetLevelCalled[log.module] = struct{}{}
	}
}

func prepareString(
	ctx context.Context, fmts string) string {
	if ctx == nil {
		return fmts
	}
	logTags, ok := LogTagsFromContext(ctx)
	if !ok || len(logTags) == 0 {
		return fmts
	}
	var tags []string
	for key, tag := range logTags {
		if v := ctx.Value(key); v != nil {
			tags = append(tags, fmt.Sprintf("%s=%s", tag, v))
		}
	}
	return fmts + " [tags:" + strings.Join(tags, ",") + "]"
}

func (log *Standard) Debug(fmt string, arg ...interface{}) {
	log.internal.Debugf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_DEBUG, fmt, arg)
	}
}

func (log *Standard) CDebugf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.DEBUG) {
		log.Debug(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Info(fmt string, arg ...interface{}) {
	log.internal.Infof(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_INFO, fmt, arg)
	}
}

func (log *Standard) CInfof(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.INFO) {
		log.Info(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Notice(fmt string, arg ...interface{}) {
	log.internal.Noticef(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_NOTICE, fmt, arg)
	}
}

func (log *Standard) CNoticef(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.NOTICE) {
		log.Notice(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Warning(fmt string, arg ...interface{}) {
	log.internal.Warningf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_WARN, fmt, arg)
	}
}

func (log *Standard) CWarningf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.WARNING) {
		log.Warning(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Error(fmt string, arg ...interface{}) {
	log.internal.Errorf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_ERROR, fmt, arg)
	}
}

func (log *Standard) Errorf(fmt string, arg ...interface{}) {
	log.Error(fmt, arg...)
}

func (log *Standard) CErrorf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.ERROR) {
		log.Error(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Critical(fmt string, arg ...interface{}) {
	log.internal.Criticalf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_CRITICAL, fmt, arg)
	}
}

func (log *Standard) CCriticalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.CRITICAL) {
		log.Critical(prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Fatalf(fmt string, arg ...interface{}) {
	log.internal.Fatalf(fmt, arg...)
	if log.externalHandler != nil {
		log.externalHandler.Log(keybase1.LogLevel_FATAL, fmt, arg)
	}
}

func (log *Standard) CFatalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	log.Fatalf(prepareString(ctx, fmt), arg...)
}

func (log *Standard) Profile(fmts string, arg ...interface{}) {
	log.Debug(fmts, arg...)
}

// Configure sets the style of the log file, whether debugging (verbose)
// is enabled and a filename. If a filename is provided here it will
// be used for logging straight away (this is a new feature).
// SetLogFileConfig provides a way to set the log file with more control on rotation.
func (log *Standard) Configure(style string, debug bool, filename string) {
	log.configureMutex.Lock()
	defer log.configureMutex.Unlock()

	log.filename = filename

	var logfmt string

	globalLock.Lock()
	isTerm := stderrIsTerminal
	globalLock.Unlock()

	// TODO: how should setting the log file after a Configure be handled?
	if isTerm {
		if debug {
			logfmt = fancyFormat
		} else {
			logfmt = defaultFormat
		}
	} else {
		logfmt = fileFormat
	}

	// Override the format above if an explicit style was specified.
	switch style {
	case "default":
		logfmt = defaultFormat // Default
	case "plain":
		logfmt = plainFormat // Plain
	case "file":
		logfmt = fileFormat // Good for logging to files
	case "fancy":
		logfmt = fancyFormat // Fancy, good for terminals with color
	}

	if debug {
		logging.SetLevel(logging.DEBUG, log.module)
	}

	logging.SetFormatter(logging.MustStringFormatter(logfmt))

}

func OpenLogFile(filename string) (name string, file *os.File, err error) {
	name = filename
	if err = MakeParentDirs(name); err != nil {
		return
	}
	file, err = os.OpenFile(name, (os.O_APPEND | os.O_WRONLY | os.O_CREATE), 0600)
	if err != nil {
		return
	}
	return
}

func FileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func MakeParentDirs(filename string) error {
	dir, _ := filepath.Split(filename)
	// If passed a plain file name as a path
	if dir == "" {
		return nil
	}
	exists, err := FileExists(dir)
	if err != nil {
		return err
	}

	if !exists {
		err = os.MkdirAll(dir, permDir)
		if err != nil {
			return err
		}
	}
	return nil
}

func PickFirstError(errors ...error) error {
	for _, e := range errors {
		if e != nil {
			return e
		}
	}
	return nil
}

func (log *Standard) CloneWithAddedDepth(depth int) Logger {
	clone := Standard{
		filename:        log.filename,
		module:          log.module,
		externalHandler: log.externalHandler,
	}
	cloneInternal := *log.internal
	clone.internal = &cloneInternal
	clone.internal.ExtraCalldepth = log.internal.ExtraCalldepth + depth

	return &clone
}

func (log *Standard) SetExternalHandler(handler ExternalHandler) {
	log.externalHandler = handler
}

type UnforwardedLogger Standard

func (log *Standard) GetUnforwardedLogger() *UnforwardedLogger {
	return (*UnforwardedLogger)(log)
}

func (log *UnforwardedLogger) Debug(s string, args ...interface{}) {
	log.internal.Debugf(s, args...)
}

func (log *UnforwardedLogger) Error(s string, args ...interface{}) {
	log.internal.Errorf(s, args...)
}

func (log *UnforwardedLogger) Errorf(s string, args ...interface{}) {
	log.internal.Errorf(s, args...)
}

func (log *UnforwardedLogger) Warning(s string, args ...interface{}) {
	log.internal.Warningf(s, args...)
}

func (log *UnforwardedLogger) Info(s string, args ...interface{}) {
	log.internal.Infof(s, args...)
}

func (log *UnforwardedLogger) Profile(s string, args ...interface{}) {
	log.internal.Debugf(s, args...)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

package stats

import (
	"bytes"
	"fmt"

	"vitess.io/vitess/go/sync2"
)

// Histogram tracks counts and totals while
// splitting the counts under different buckets
// using specified cutoffs.
type Histogram struct {
	help       string
	labelName  string
	cutoffs    []int64
	labels     []string
	countLabel string
	totalLabel string
	hook       func(int64)

	buckets []sync2.AtomicInt64
	total   sync2.AtomicInt64
}

// NewHistogram creates a histogram with auto-generated labels
// based on the cutoffs. The buckets are categorized using the
// following criterion: cutoff[i-1] < value <= cutoff[i]. Anything
// higher than the highest cutoff is labeled as "inf".
func NewHistogram(name, help string, cutoffs []int64) *Histogram {
	labels := make([]string, len(cutoffs)+1)
	for i, v := range cutoffs {
		labels[i] = fmt.Sprintf("%d", v)
	}
	labels[len(labels)-1] = "inf"
	return NewGenericHistogram(name, help, cutoffs, labels, "Count", "Total")
}

// NewGenericHistogram creates a histogram where all the labels are
// supplied by the caller. The number of labels has to be one more than
// the number of cutoffs because the last label captures everything that
// exceeds the highest cutoff.
func NewGenericHistogram(name, help string, cutoffs []int64, labels []string, countLabel, totalLabel string) *Histogram {
	if len(cutoffs) != len(labels)-1 {
		panic("mismatched cutoff and label lengths")
	}
	h := &Histogram{
		help:       help,
		cutoffs:    cutoffs,
		labels:     labels,
		countLabel: countLabel,
		totalLabel: totalLabel,
		buckets:    make([]sync2.AtomicInt64, len(labels)),
	}
	if name != "" {
		publish(name, h)
	}
	return h
}

// Add adds a new measurement to the Histogram.
func (h *Histogram) Add(value int64) {
	for i := range h.labels {
		if i == len(h.labels)-1 || value <= h.cutoffs[i] {
			h.buckets[i].Add(1)
			h.total.Add(value)
			break
		}
	}
	if h.hook != nil {
		h.hook(value)
	}
}

// String returns a string representation of the Histogram.
// Note that sum of all buckets may not be equal to the total temporarily,
// because Add() increments bucket and total with two atomic operations.
func (h *Histogram) String() string {
	b, _ := h.MarshalJSON()
	return string(b)
}

// MarshalJSON returns a JSON representation of the Histogram.
// Note that sum of all buckets may not be equal to the total temporarily,
// because Add() increments bucket and total with two atomic operations.
func (h *Histogram) MarshalJSON() ([]byte, error) {
	b := bytes.NewBuffer(make([]byte, 0, 4096))
	fmt.Fprintf(b, "{")
	totalCount := int64(0)
	for i, label := range h.labels {
		totalCount += h.buckets[i].Get()
		fmt.Fprintf(b, "\"%v\": %v, ", label, totalCount)
	}
	fmt.Fprintf(b, "\"%s\": %v, ", h.countLabel, totalCount)
	fmt.Fprintf(b, "\"%s\": %v", h.totalLabel, h.total.Get())
	fmt.Fprintf(b, "}")
	return b.Bytes(), nil
}

// Counts returns a map from labels to the current count in the Histogram for that label.
func (h *Histogram) Counts() map[string]int64 {
	counts := make(map[string]int64, len(h.labels))
	for i, label := range h.labels {
		counts[label] = h.buckets[i].Get()
	}
	return counts
}

// CountLabel returns the count label that was set when this Histogram was created.
func (h *Histogram) CountLabel() string {
	return h.countLabel
}

// Count returns the number of times Add has been called.
func (h *Histogram) Count() (count int64) {
	for i := range h.buckets {
		count += h.buckets[i].Get()
	}
	return
}

// TotalLabel returns the total label that was set when this Histogram was created.
func (h *Histogram) TotalLabel() string {
	return h.totalLabel
}

// Total returns the sum of all values that have been added to this Histogram.
func (h *Histogram) Total() (total int64) {
	return h.total.Get()
}

// Labels returns the labels that were set when this Histogram was created.
func (h *Histogram) Labels() []string {
	return h.labels
}

// Cutoffs returns the cutoffs that were set when this Histogram was created.
func (h *Histogram) Cutoffs() []int64 {
	return h.cutoffs
}

// Buckets returns a snapshot of the current values in all buckets.
func (h *Histogram) Buckets() []int64 {
	buckets := make([]int64, len(h.buckets))
	for i := range h.buckets {
		buckets[i] = h.buckets[i].Get()
	}
	return buckets
}

// Help returns the help string.
func (h *Histogram) Help() string {
	return h.help
}

// LabelName returns the label name.
func (h *Histogram) LabelName() string {
	return h.labelName
}
<commit_msg>remove the unused LabelName() from the Histogram<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

package stats

import (
	"bytes"
	"fmt"

	"vitess.io/vitess/go/sync2"
)

// Histogram tracks counts and totals while
// splitting the counts under different buckets
// using specified cutoffs.
type Histogram struct {
	help       string
	cutoffs    []int64
	labels     []string
	countLabel string
	totalLabel string
	hook       func(int64)

	buckets []sync2.AtomicInt64
	total   sync2.AtomicInt64
}

// NewHistogram creates a histogram with auto-generated labels
// based on the cutoffs. The buckets are categorized using the
// following criterion: cutoff[i-1] < value <= cutoff[i]. Anything
// higher than the highest cutoff is labeled as "inf".
func NewHistogram(name, help string, cutoffs []int64) *Histogram {
	labels := make([]string, len(cutoffs)+1)
	for i, v := range cutoffs {
		labels[i] = fmt.Sprintf("%d", v)
	}
	labels[len(labels)-1] = "inf"
	return NewGenericHistogram(name, help, cutoffs, labels, "Count", "Total")
}

// NewGenericHistogram creates a histogram where all the labels are
// supplied by the caller. The number of labels has to be one more than
// the number of cutoffs because the last label captures everything that
// exceeds the highest cutoff.
func NewGenericHistogram(name, help string, cutoffs []int64, labels []string, countLabel, totalLabel string) *Histogram {
	if len(cutoffs) != len(labels)-1 {
		panic("mismatched cutoff and label lengths")
	}
	h := &Histogram{
		help:       help,
		cutoffs:    cutoffs,
		labels:     labels,
		countLabel: countLabel,
		totalLabel: totalLabel,
		buckets:    make([]sync2.AtomicInt64, len(labels)),
	}
	if name != "" {
		publish(name, h)
	}
	return h
}

// Add adds a new measurement to the Histogram.
func (h *Histogram) Add(value int64) {
	for i := range h.labels {
		if i == len(h.labels)-1 || value <= h.cutoffs[i] {
			h.buckets[i].Add(1)
			h.total.Add(value)
			break
		}
	}
	if h.hook != nil {
		h.hook(value)
	}
}

// String returns a string representation of the Histogram.
// Note that sum of all buckets may not be equal to the total temporarily,
// because Add() increments bucket and total with two atomic operations.
func (h *Histogram) String() string {
	b, _ := h.MarshalJSON()
	return string(b)
}

// MarshalJSON returns a JSON representation of the Histogram.
// Note that sum of all buckets may not be equal to the total temporarily,
// because Add() increments bucket and total with two atomic operations.
func (h *Histogram) MarshalJSON() ([]byte, error) {
	b := bytes.NewBuffer(make([]byte, 0, 4096))
	fmt.Fprintf(b, "{")
	totalCount := int64(0)
	for i, label := range h.labels {
		totalCount += h.buckets[i].Get()
		fmt.Fprintf(b, "\"%v\": %v, ", label, totalCount)
	}
	fmt.Fprintf(b, "\"%s\": %v, ", h.countLabel, totalCount)
	fmt.Fprintf(b, "\"%s\": %v", h.totalLabel, h.total.Get())
	fmt.Fprintf(b, "}")
	return b.Bytes(), nil
}

// Counts returns a map from labels to the current count in the Histogram for that label.
func (h *Histogram) Counts() map[string]int64 {
	counts := make(map[string]int64, len(h.labels))
	for i, label := range h.labels {
		counts[label] = h.buckets[i].Get()
	}
	return counts
}

// CountLabel returns the count label that was set when this Histogram was created.
func (h *Histogram) CountLabel() string {
	return h.countLabel
}

// Count returns the number of times Add has been called.
func (h *Histogram) Count() (count int64) {
	for i := range h.buckets {
		count += h.buckets[i].Get()
	}
	return
}

// TotalLabel returns the total label that was set when this Histogram was created.
func (h *Histogram) TotalLabel() string {
	return h.totalLabel
}

// Total returns the sum of all values that have been added to this Histogram.
func (h *Histogram) Total() (total int64) {
	return h.total.Get()
}

// Labels returns the labels that were set when this Histogram was created.
func (h *Histogram) Labels() []string {
	return h.labels
}

// Cutoffs returns the cutoffs that were set when this Histogram was created.
func (h *Histogram) Cutoffs() []int64 {
	return h.cutoffs
}

// Buckets returns a snapshot of the current values in all buckets.
func (h *Histogram) Buckets() []int64 {
	buckets := make([]int64, len(h.buckets))
	for i := range h.buckets {
		buckets[i] = h.buckets[i].Get()
	}
	return buckets
}

// Help returns the help string.
func (h *Histogram) Help() string {
	return h.help
}
<|endoftext|>


<commit_before>package gobson

import (
	"fmt"
	"testing"
)

var _ = fmt.Printf

type Data struct {
	N int
	S string
	A []byte
}

func TestGobson(t *testing.T) {

	length := 10
	a := make([]byte, length, length)

	putData := &Data{N: 1, S: "abc", A: a}

	data, err := Marshal(putData)
	if err != nil {
		t.Errorf("%v", err)
	}
	//fmt.Printf("%q\n", data)

	getData := &Data{}

	err = Unmarshal(data, getData)
	if err != nil {
		t.Errorf("%v", err)
	}

	if getData.N != putData.N || getData.S != putData.S {
		t.Errorf("Unmarshalled values doesn't equal to original values")
	}

	//fmt.Printf("%v\n", getData)
	for i := 0; i < length; i++ {
		if getData.A[i] != putData.A[i] {
			t.Errorf("Unmarshalled values doesn't equal to original values")
		}
	}

}
<commit_msg>finish gobson bench<commit_after>package gobson

import (
	"fmt"
	"testing"
)

var _ = fmt.Printf

type Data struct {
	N int
	S string
	A []byte
}

func TestGobson(t *testing.T) {

	length := 10
	a := make([]byte, length, length)

	putData := &Data{N: 1, S: "abc", A: a}

	data, err := Marshal(putData)
	if err != nil {
		t.Errorf("%v", err)
	}

	getData := &Data{}

	err = Unmarshal(data, getData)
	if err != nil {
		t.Errorf("%v", err)
	}

	if getData.N != putData.N || getData.S != putData.S {
		t.Errorf("Unmarshalled values doesn't equal to original values")
	}

	for i := 0; i < length; i++ {
		if getData.A[i] != putData.A[i] {
			t.Errorf("Unmarshalled values doesn't equal to original values")
		}
	}

}

func BenchmarkGobson(b *testing.B) {
	length := 10
	a := make([]byte, length, length)

	putData := &Data{N: 1, S: "abc", A: a}
	getData := &Data{}

	for i := 0; i < b.N; i++ {
		data, _ := Marshal(putData)
		Unmarshal(data, getData)
	}
}
<|endoftext|>


<commit_before>// Pixbufs
//
// A GdkPixbuf represents an image, normally in RGB or RGBA format.
// Pixbufs are normally used to load files from disk and perform
// image scaling.
//
// This demo is not all that educational, but looks cool. It was written
// by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows
// off how to use GtkDrawingArea to do a simple animation.
//
// Look at the Image demo for additional pixbuf usage examples.
package pixbufs

import "gobject/gtk-3.0"
import "gobject/gdk-3.0"
import "gobject/gdkpixbuf-2.0"
import "gobject/cairo-1.0"
import "runtime"
import "math"
import "time"
import "./common"

const frame_delay = 50
const background_name = "background.jpg"

var image_names = []string{
	"apple-red.png",
	"gnome-applets.png",
	"gnome-calendar.png",
	"gnome-foot.png",
	"gnome-gmush.png",
	"gnome-gimp.png",
	"gnome-gsame.png",
	"gnu-keys.png",
}

var window *gtk.Window
var background *gdkpixbuf.Pixbuf
var images []*gdkpixbuf.Pixbuf
var back_width int
var back_height int

var frame *gdkpixbuf.Pixbuf
var da *gtk.DrawingArea

func load_pixbufs() error {
	if background != nil {
		return nil // already loaded earlier
	}

	var err error
	background, err = gdkpixbuf.NewPixbufFromFile(common.FindFile(background_name))
	if err != nil {
		return err
	}

	back_width = background.GetWidth()
	back_height = background.GetHeight()

	images = make([]*gdkpixbuf.Pixbuf, len(image_names))
	for i, name := range image_names {
		images[i], err = gdkpixbuf.NewPixbufFromFile(common.FindFile(name))
		if err != nil {
			return err
		}
	}

	return nil
}

// Expose callback for the drawing area
func draw_cb(widget *gtk.Widget, cr *cairo.Context) bool {
	gdk.CairoSetSourcePixbuf(cr, frame, 0, 0)
	cr.Paint()

	// without this call it leaks like crazy
	runtime.GC()
	return true
}

const cycle_len = 60
var frame_num int

func draw_one_frame() {
	background.CopyArea(0, 0, back_width, back_height, frame, 0, 0)
	f := float64(frame_num % cycle_len) / cycle_len
	xmid := float64(back_width) / 2
	ymid := float64(back_height) / 2
	radius := math.Min(xmid, ymid) / 2

	for i, image := range images {
		ang := 2 * math.Pi * float64(i) / float64(len(images)) - f * 2 * math.Pi

		iw := image.GetWidth()
		ih := image.GetHeight()

		r := radius + (radius / 3) * math.Sin(f * 2 * math.Pi)

		xpos := math.Floor(xmid + r * math.Cos(ang) - float64(iw) / 2 + 0.5)
		ypos := math.Floor(ymid + r * math.Sin(ang) - float64(ih) / 2 + 0.5)

		var k, alpha float64
		if i & 1 != 0 {
			k = math.Sin(f * 2 * math.Pi)
			alpha = math.Max(127, math.Abs(255 * math.Sin(f * 2 * math.Pi)))
		} else {
			k = math.Cos(f * 2 * math.Pi)
			alpha = math.Max(127, math.Abs(255 * math.Cos(f * 2 * math.Pi)))
		}
		k = 2 * k * k
		k = math.Max(0.25, k)

		r1 := cairo.RectangleInt{
			int32(xpos), int32(ypos),
			int32(float64(iw) * k), int32(float64(ih) * k),
		}
		r2 := cairo.RectangleInt{
			0, 0,
			int32(back_width), int32(back_height),
		}

		if dest, ok := gdk.RectangleIntersect(&r1, &r2); ok {
			image.Composite(frame,
				int(dest.X), int(dest.Y), int(dest.Width), int(dest.Height),
				xpos, ypos, k, k,
				gdkpixbuf.InterpTypeNearest, int(alpha))
		}
	}

}

func drawing_loop(cancel chan int) {
	ticker := time.NewTicker(frame_delay * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			draw_one_frame()

			gdk.ThreadsEnter()
			da.QueueDraw()
			gdk.ThreadsLeave()

			frame_num++
		case <-cancel:
			ticker.Stop()
			cancel <- 1
			return
		}
	}
}

func Do(mainwin *gtk.Window) *gtk.Window {
	if window == nil {
		cancel := make(chan int)
		window = gtk.NewWindow(gtk.WindowTypeToplevel)
		window.SetScreen(mainwin.GetScreen())
		window.SetTitle("Pixbufs")
		window.SetResizable(false)
		window.Connect("destroy", func() {
			window = nil
			frame = nil
			da = nil

		})

		if err := load_pixbufs(); err != nil {
			dialog := gtk.NewMessageDialog(mainwin, gtk.DialogFlagsDestroyWithParent,
				gtk.MessageTypeError, gtk.ButtonsTypeClose,
				"Failed to load an image: %s", err)

			dialog.Connect("response", func() { dialog.Destroy() })
			dialog.Show()
			goto done
		}

		window.SetSizeRequest(back_width, back_height)
		frame = gdkpixbuf.NewPixbuf(gdkpixbuf.ColorspaceRGB, false, 8, back_width, back_height)
		da = gtk.NewDrawingArea()
		da.Connect("draw", draw_cb)
		window.Add(da)

		go drawing_loop(cancel)
		window.Connect("destroy", func() {
			// stop drawing loop
			cancel <- 1
			<-cancel
		})
	}

done:
	if !window.GetVisible() {
		window.ShowAll()
	} else {
		window.Destroy()
	}
	return window
}<commit_msg>Race condition?<commit_after>// Pixbufs
//
// A GdkPixbuf represents an image, normally in RGB or RGBA format.
// Pixbufs are normally used to load files from disk and perform
// image scaling.
//
// This demo is not all that educational, but looks cool. It was written
// by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows
// off how to use GtkDrawingArea to do a simple animation.
//
// Look at the Image demo for additional pixbuf usage examples.
package pixbufs

import "gobject/gtk-3.0"
import "gobject/gdk-3.0"
import "gobject/gdkpixbuf-2.0"
import "gobject/cairo-1.0"
import "runtime"
import "math"
import "time"
import "sync"
import "./common"

const frame_delay = 50
const background_name = "background.jpg"

var image_names = []string{
	"apple-red.png",
	"gnome-applets.png",
	"gnome-calendar.png",
	"gnome-foot.png",
	"gnome-gmush.png",
	"gnome-gimp.png",
	"gnome-gsame.png",
	"gnu-keys.png",
}

var window *gtk.Window
var background *gdkpixbuf.Pixbuf
var images []*gdkpixbuf.Pixbuf
var back_width int
var back_height int

var frame_lock sync.Mutex
var frame *gdkpixbuf.Pixbuf
var da *gtk.DrawingArea

func load_pixbufs() error {
	if background != nil {
		return nil // already loaded earlier
	}

	var err error
	background, err = gdkpixbuf.NewPixbufFromFile(common.FindFile(background_name))
	if err != nil {
		return err
	}

	back_width = background.GetWidth()
	back_height = background.GetHeight()

	images = make([]*gdkpixbuf.Pixbuf, len(image_names))
	for i, name := range image_names {
		images[i], err = gdkpixbuf.NewPixbufFromFile(common.FindFile(name))
		if err != nil {
			return err
		}
	}

	return nil
}

// Expose callback for the drawing area
func draw_cb(widget *gtk.Widget, cr *cairo.Context) bool {
	frame_lock.Lock()
	gdk.CairoSetSourcePixbuf(cr, frame, 0, 0)
	cr.Paint()
	frame_lock.Unlock()

	// without this call it leaks like crazy
	runtime.GC()
	return true
}

const cycle_len = 60
var frame_num int

func draw_one_frame() {
	background.CopyArea(0, 0, back_width, back_height, frame, 0, 0)
	f := float64(frame_num % cycle_len) / cycle_len
	xmid := float64(back_width) / 2
	ymid := float64(back_height) / 2
	radius := math.Min(xmid, ymid) / 2

	for i, image := range images {
		ang := 2 * math.Pi * float64(i) / float64(len(images)) - f * 2 * math.Pi

		iw := image.GetWidth()
		ih := image.GetHeight()

		r := radius + (radius / 3) * math.Sin(f * 2 * math.Pi)

		xpos := math.Floor(xmid + r * math.Cos(ang) - float64(iw) / 2 + 0.5)
		ypos := math.Floor(ymid + r * math.Sin(ang) - float64(ih) / 2 + 0.5)

		var k, alpha float64
		if i & 1 != 0 {
			k = math.Sin(f * 2 * math.Pi)
			alpha = math.Max(127, math.Abs(255 * math.Sin(f * 2 * math.Pi)))
		} else {
			k = math.Cos(f * 2 * math.Pi)
			alpha = math.Max(127, math.Abs(255 * math.Cos(f * 2 * math.Pi)))
		}
		k = 2 * k * k
		k = math.Max(0.25, k)

		r1 := cairo.RectangleInt{
			int32(xpos), int32(ypos),
			int32(float64(iw) * k), int32(float64(ih) * k),
		}
		r2 := cairo.RectangleInt{
			0, 0,
			int32(back_width), int32(back_height),
		}

		if dest, ok := gdk.RectangleIntersect(&r1, &r2); ok {
			frame_lock.Lock()
			image.Composite(frame,
				int(dest.X), int(dest.Y), int(dest.Width), int(dest.Height),
				xpos, ypos, k, k,
				gdkpixbuf.InterpTypeNearest, int(alpha))
			frame_lock.Unlock()
		}
	}

}

func drawing_loop(cancel chan int) {
	ticker := time.NewTicker(frame_delay * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			draw_one_frame()

			gdk.ThreadsEnter()
			da.QueueDraw()
			gdk.ThreadsLeave()

			frame_num++
		case <-cancel:
			ticker.Stop()
			cancel <- 1
			return
		}
	}
}

func Do(mainwin *gtk.Window) *gtk.Window {
	if window == nil {
		cancel := make(chan int)
		window = gtk.NewWindow(gtk.WindowTypeToplevel)
		window.SetScreen(mainwin.GetScreen())
		window.SetTitle("Pixbufs")
		window.SetResizable(false)
		window.Connect("destroy", func() {
			window = nil
			frame = nil
			da = nil

		})

		if err := load_pixbufs(); err != nil {
			dialog := gtk.NewMessageDialog(mainwin, gtk.DialogFlagsDestroyWithParent,
				gtk.MessageTypeError, gtk.ButtonsTypeClose,
				"Failed to load an image: %s", err)

			dialog.Connect("response", func() { dialog.Destroy() })
			dialog.Show()
			goto done
		}

		window.SetSizeRequest(back_width, back_height)
		frame = gdkpixbuf.NewPixbuf(gdkpixbuf.ColorspaceRGB, false, 8, back_width, back_height)
		da = gtk.NewDrawingArea()
		da.Connect("draw", draw_cb)
		window.Add(da)

		go drawing_loop(cancel)
		window.Connect("destroy", func() {
			// stop drawing loop
			cancel <- 1
			<-cancel
		})
	}

done:
	if !window.GetVisible() {
		window.ShowAll()
	} else {
		window.Destroy()
	}
	return window
}<|endoftext|>


<commit_before>package self_test

import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"time"

	quic "github.com/lucas-clemente/quic-go"
	quicproxy "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	"github.com/lucas-clemente/quic-go/internal/utils"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Timeout tests", func() {
	checkTimeoutError := func(err error) {
		ExpectWithOffset(1, err).To(HaveOccurred())
		nerr, ok := err.(net.Error)
		ExpectWithOffset(1, ok).To(BeTrue())
		ExpectWithOffset(1, nerr.Timeout()).To(BeTrue())
	}

	It("returns net.Error timeout errors when dialing", func() {
		errChan := make(chan error)
		go func() {
			_, err := quic.DialAddr(
				"localhost:12345",
				&tls.Config{RootCAs: testdata.GetRootCA()},
				&quic.Config{HandshakeTimeout: 10 * time.Millisecond},
			)
			errChan <- err
		}()
		var err error
		Eventually(errChan).Should(Receive(&err))
		checkTimeoutError(err)
	})

	It("returns the context error when the context expires", func() {
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
		defer cancel()
		errChan := make(chan error)
		go func() {
			_, err := quic.DialAddrContext(
				ctx,
				"localhost:12345",
				&tls.Config{RootCAs: testdata.GetRootCA()},
				nil,
			)
			errChan <- err
		}()
		var err error
		Eventually(errChan).Should(Receive(&err))
		// This is not a net.Error timeout error
		Expect(err).To(MatchError(context.DeadlineExceeded))
	})

	It("returns net.Error timeout errors when an idle timeout occurs", func() {
		const idleTimeout = 100 * time.Millisecond

		server, err := quic.ListenAddr(
			"localhost:0",
			testdata.GetTLSConfig(),
			nil,
		)
		Expect(err).ToNot(HaveOccurred())
		defer server.Close()

		go func() {
			defer GinkgoRecover()
			sess, err := server.Accept()
			Expect(err).ToNot(HaveOccurred())
			str, err := sess.OpenStream()
			Expect(err).ToNot(HaveOccurred())
			_, err = str.Write([]byte("foobar"))
			Expect(err).ToNot(HaveOccurred())
		}()

		drop := utils.AtomicBool{}

		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
			RemoteAddr: fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
			DropPacket: func(d quicproxy.Direction, p uint64) bool {
				return drop.Get()
			},
		})
		Expect(err).ToNot(HaveOccurred())
		defer proxy.Close()

		sess, err := quic.DialAddr(
			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
			&tls.Config{RootCAs: testdata.GetRootCA()},
			&quic.Config{IdleTimeout: idleTimeout},
		)
		Expect(err).ToNot(HaveOccurred())
		strIn, err := sess.AcceptStream()
		Expect(err).ToNot(HaveOccurred())
		strOut, err := sess.OpenStream()
		Expect(err).ToNot(HaveOccurred())
		_, err = strIn.Read(make([]byte, 6))
		Expect(err).ToNot(HaveOccurred())

		drop.Set(true)
		time.Sleep(2 * idleTimeout)
		_, err = strIn.Write([]byte("test"))
		checkTimeoutError(err)
		_, err = strIn.Read([]byte{0})
		checkTimeoutError(err)
		_, err = strOut.Write([]byte("test"))
		checkTimeoutError(err)
		_, err = strOut.Read([]byte{0})
		checkTimeoutError(err)
		_, err = sess.OpenStream()
		checkTimeoutError(err)
		_, err = sess.OpenUniStream()
		checkTimeoutError(err)
		_, err = sess.AcceptStream()
		checkTimeoutError(err)
		_, err = sess.AcceptUniStream()
		checkTimeoutError(err)
	})
})
<commit_msg>add an integration test for the duration of the idle timeout<commit_after>package self_test

import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"os"
	"strconv"
	"time"

	quic "github.com/lucas-clemente/quic-go"
	quicproxy "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	"github.com/lucas-clemente/quic-go/internal/utils"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Timeout tests", func() {
	checkTimeoutError := func(err error) {
		ExpectWithOffset(1, err).To(HaveOccurred())
		nerr, ok := err.(net.Error)
		ExpectWithOffset(1, ok).To(BeTrue())
		ExpectWithOffset(1, nerr.Timeout()).To(BeTrue())
	}

	It("returns net.Error timeout errors when dialing", func() {
		errChan := make(chan error)
		go func() {
			_, err := quic.DialAddr(
				"localhost:12345",
				&tls.Config{RootCAs: testdata.GetRootCA()},
				&quic.Config{HandshakeTimeout: 10 * time.Millisecond},
			)
			errChan <- err
		}()
		var err error
		Eventually(errChan).Should(Receive(&err))
		checkTimeoutError(err)
	})

	It("returns the context error when the context expires", func() {
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
		defer cancel()
		errChan := make(chan error)
		go func() {
			_, err := quic.DialAddrContext(
				ctx,
				"localhost:12345",
				&tls.Config{RootCAs: testdata.GetRootCA()},
				nil,
			)
			errChan <- err
		}()
		var err error
		Eventually(errChan).Should(Receive(&err))
		// This is not a net.Error timeout error
		Expect(err).To(MatchError(context.DeadlineExceeded))
	})

	It("returns net.Error timeout errors when an idle timeout occurs", func() {
		const idleTimeout = 100 * time.Millisecond

		server, err := quic.ListenAddr(
			"localhost:0",
			testdata.GetTLSConfig(),
			nil,
		)
		Expect(err).ToNot(HaveOccurred())
		defer server.Close()

		go func() {
			defer GinkgoRecover()
			sess, err := server.Accept()
			Expect(err).ToNot(HaveOccurred())
			str, err := sess.OpenStream()
			Expect(err).ToNot(HaveOccurred())
			_, err = str.Write([]byte("foobar"))
			Expect(err).ToNot(HaveOccurred())
		}()

		drop := utils.AtomicBool{}

		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
			RemoteAddr: fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
			DropPacket: func(d quicproxy.Direction, p uint64) bool {
				return drop.Get()
			},
		})
		Expect(err).ToNot(HaveOccurred())
		defer proxy.Close()

		sess, err := quic.DialAddr(
			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
			&tls.Config{RootCAs: testdata.GetRootCA()},
			&quic.Config{IdleTimeout: idleTimeout},
		)
		Expect(err).ToNot(HaveOccurred())
		strIn, err := sess.AcceptStream()
		Expect(err).ToNot(HaveOccurred())
		strOut, err := sess.OpenStream()
		Expect(err).ToNot(HaveOccurred())
		_, err = strIn.Read(make([]byte, 6))
		Expect(err).ToNot(HaveOccurred())

		drop.Set(true)
		time.Sleep(2 * idleTimeout)
		_, err = strIn.Write([]byte("test"))
		checkTimeoutError(err)
		_, err = strIn.Read([]byte{0})
		checkTimeoutError(err)
		_, err = strOut.Write([]byte("test"))
		checkTimeoutError(err)
		_, err = strOut.Read([]byte{0})
		checkTimeoutError(err)
		_, err = sess.OpenStream()
		checkTimeoutError(err)
		_, err = sess.OpenUniStream()
		checkTimeoutError(err)
		_, err = sess.AcceptStream()
		checkTimeoutError(err)
		_, err = sess.AcceptUniStream()
		checkTimeoutError(err)
	})

	Context("timing out at the right time", func() {
		var idleTimeout time.Duration

		scaleDuration := func(d time.Duration) time.Duration {
			scaleFactor := 1
			if f, err := strconv.Atoi(os.Getenv("TIMESCALE_FACTOR")); err == nil { // parsing "" errors, so this works fine if the env is not set
				scaleFactor = f
			}
			Expect(scaleFactor).ToNot(BeZero())
			return time.Duration(scaleFactor) * d
		}

		BeforeEach(func() {
			idleTimeout = scaleDuration(100 * time.Millisecond)
		})

		It("times out after inactivity", func() {
			server, err := quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), nil)
			Expect(err).ToNot(HaveOccurred())
			defer server.Close()

			serverSessionClosed := make(chan struct{})
			go func() {
				defer GinkgoRecover()
				sess, err := server.Accept()
				Expect(err).ToNot(HaveOccurred())
				sess.AcceptStream() // blocks until the session is closed
				close(serverSessionClosed)
			}()

			sess, err := quic.DialAddr(
				fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
				&tls.Config{RootCAs: testdata.GetRootCA()},
				&quic.Config{IdleTimeout: idleTimeout},
			)
			Expect(err).ToNot(HaveOccurred())
			startTime := time.Now()
			done := make(chan struct{})
			go func() {
				defer GinkgoRecover()
				_, err := sess.AcceptStream()
				checkTimeoutError(err)
				close(done)
			}()
			Eventually(done, 2*idleTimeout).Should(BeClosed())
			dur := time.Since(startTime)
			Expect(dur).To(And(
				BeNumerically(">=", idleTimeout),
				BeNumerically("<", idleTimeout*6/5),
			))
			Consistently(serverSessionClosed).ShouldNot(BeClosed())

			// make the go routine return
			Expect(server.Close()).To(Succeed())
			Eventually(serverSessionClosed).Should(BeClosed())
		})

		It("times out after sending a packet", func() {
			server, err := quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), nil)
			Expect(err).ToNot(HaveOccurred())
			defer server.Close()

			serverSessionClosed := make(chan struct{})
			go func() {
				defer GinkgoRecover()
				sess, err := server.Accept()
				Expect(err).ToNot(HaveOccurred())
				sess.AcceptStream() // blocks until the session is closed
				close(serverSessionClosed)
			}()

			sess, err := quic.DialAddr(
				fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
				&tls.Config{RootCAs: testdata.GetRootCA()},
				&quic.Config{IdleTimeout: idleTimeout},
			)
			Expect(err).ToNot(HaveOccurred())

			// wait half the idle timeout, then send a packet
			time.Sleep(idleTimeout / 2)
			str, err := sess.OpenUniStream()
			Expect(err).ToNot(HaveOccurred())
			_, err = str.Write([]byte("foobar"))
			Expect(err).ToNot(HaveOccurred())

			// now make sure that the idle timeout is based on this packet
			startTime := time.Now()
			done := make(chan struct{})
			go func() {
				defer GinkgoRecover()
				_, err := sess.AcceptStream()
				checkTimeoutError(err)
				close(done)
			}()
			Eventually(done, 2*idleTimeout).Should(BeClosed())
			dur := time.Since(startTime)
			Expect(dur).To(And(
				BeNumerically(">=", idleTimeout),
				BeNumerically("<", idleTimeout*12/10),
			))
			Consistently(serverSessionClosed).ShouldNot(BeClosed())

			// make the go routine return
			Expect(server.Close()).To(Succeed())
			Eventually(serverSessionClosed).Should(BeClosed())
		})
	})
})
<|endoftext|>