<commit_before>package appfs

import (
	"bytes"
	"compress/gzip"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/andybalholm/brotli"
	"github.com/cozy/cozy-stack/pkg/consts"
	web_utils "github.com/cozy/cozy-stack/pkg/utils"
	"github.com/ncw/swift"
	"github.com/spf13/afero"
)

// FileServer interface defines a way to access and serve the application's
// data files.
type FileServer interface {
	Open(slug, version, shasum, file string) (io.ReadCloser, error)
	FilesList(slug, version, shasum string) ([]string, error)
	ServeFileContent(w http.ResponseWriter, req *http.Request,
		slug, version, shasum, file string) error
}

type swiftServer struct {
	c         *swift.Connection
	container string
}

type aferoServer struct {
	mkPath func(slug, version, shasum, file string) string
	fs     afero.Fs
}

type brotliReadCloser struct {
	br *brotli.Reader
	cl io.Closer
}

// brotli.Reader has no Close method. This little wrapper adds a method to
// close the underlying reader.
func newBrotliReadCloser(r io.ReadCloser) (io.ReadCloser, error) {
	br := brotli.NewReader(r)
	return brotliReadCloser{br: br, cl: r}, nil
}

func (r brotliReadCloser) Read(b []byte) (int, error) {
	return r.br.Read(b)
}

func (r brotliReadCloser) Close() error {
	return r.cl.Close()
}

type gzipReadCloser struct {
	gr *gzip.Reader
	cl io.Closer
}

// The Close method of gzip.Reader does not closes the underlying reader. This
// little wrapper does the closing.
func newGzipReadCloser(r io.ReadCloser) (io.ReadCloser, error) {
	gr, err := gzip.NewReader(r)
	if err != nil {
		return nil, err
	}
	return gzipReadCloser{gr: gr, cl: r}, nil
}

func (g gzipReadCloser) Read(b []byte) (int, error) {
	return g.gr.Read(b)
}

func (g gzipReadCloser) Close() error {
	err1 := g.gr.Close()
	err2 := g.cl.Close()
	if err1 != nil {
		return err1
	}
	if err2 != nil {
		return err2
	}
	return nil
}

// NewSwiftFileServer returns provides the apps.FileServer implementation
// using the swift backend as file server.
func NewSwiftFileServer(conn *swift.Connection, appsType consts.AppType) FileServer {
	return &swiftServer{
		c:         conn,
		container: containerName(appsType),
	}
}

func (s *swiftServer) Open(slug, version, shasum, file string) (io.ReadCloser, error) {
	objName := s.makeObjectName(slug, version, shasum, file)
	f, h, err := s.c.ObjectOpen(s.container, objName, false, nil)
	if err != nil {
		return nil, wrapSwiftErr(err)
	}
	o := h.ObjectMetadata()
	contentEncoding := o["content-encoding"]
	if contentEncoding == "br" {
		return newBrotliReadCloser(f)
	} else if contentEncoding == "gzip" {
		return newGzipReadCloser(f)
	}
	return f, nil
}

func (s *swiftServer) ServeFileContent(w http.ResponseWriter, req *http.Request, slug, version, shasum, file string) error {
	objName := s.makeObjectName(slug, version, shasum, file)
	f, h, err := s.c.ObjectOpen(s.container, objName, false, nil)
	if err != nil {
		return wrapSwiftErr(err)
	}
	defer f.Close()

	if checkETag := req.Header.Get("Cache-Control") == ""; checkETag {
		etag := fmt.Sprintf(`"%s"`, h["Etag"][:10])
		if web_utils.CheckPreconditions(w, req, etag) {
			return nil
		}
		w.Header().Set("Etag", etag)
	}

	var r io.Reader = f
	contentLength := h["Content-Length"]
	contentType := h["Content-Type"]
	o := h.ObjectMetadata()
	contentEncoding := o["content-encoding"]
	if contentEncoding == "br" {
		if acceptBrotliEncoding(req) {
			w.Header().Set("Content-Encoding", "br")
		} else {
			contentLength = o["original-content-length"]
			r = brotli.NewReader(f)
		}
	} else if contentEncoding == "gzip" {
		if acceptGzipEncoding(req) {
			w.Header().Set("Content-Encoding", "gzip")
		} else {
			contentLength = o["original-content-length"]
			var gr *gzip.Reader
			gr, err = gzip.NewReader(f)
			if err != nil {
				return err
			}
			defer gr.Close()
			r = gr
		}
	}

	ext := path.Ext(file)
	if contentType == "" {
		contentType = mime.TypeByExtension(ext)
	}
	if contentType == "text/xml" && ext == ".svg" {
		// override for files with text/xml content because of leading <?xml tag
		contentType = "image/svg+xml"
	}

	size, _ := strconv.ParseInt(contentLength, 10, 64)
	web_utils.ServeContent(w, req, contentType, size, r)
	return nil
}

func (s *swiftServer) makeObjectName(slug, version, shasum, file string) string {
	basepath := path.Join(slug, version)
	if shasum != "" {
		basepath += "-" + shasum
	}
	return path.Join(basepath, file)
}

func (s *swiftServer) FilesList(slug, version, shasum string) ([]string, error) {
	prefix := s.makeObjectName(slug, version, shasum, "") + "/"
	names, err := s.c.ObjectNamesAll(s.container, &swift.ObjectsOpts{
		Prefix: prefix,
	})
	if err != nil {
		return nil, err
	}
	filtered := names[:0]
	for _, n := range names {
		n = strings.TrimPrefix(n, prefix)
		if n != "" {
			filtered = append(filtered, n)
		}
	}
	return filtered, nil
}

// NewAferoFileServer returns a simple wrapper of the afero.Fs interface that
// provides the apps.FileServer interface.
//
// You can provide a makePath method to define how the file name should be
// created from the application's slug, version and file name. If not provided,
// the standard VFS concatenation (starting with vfs.WebappsDirName) is used.
func NewAferoFileServer(fs afero.Fs, makePath func(slug, version, shasum, file string) string) FileServer {
	if makePath == nil {
		makePath = defaultMakePath
	}
	return &aferoServer{
		mkPath: makePath,
		fs:     fs,
	}
}

const (
	uncompressed = iota + 1
	gzipped
	brotlied
)

// openFile opens the give filepath. By default, it is a file compressed with
// brotli (.br), but it can be a file compressed with gzip (.gz, for apps that
// were installed before brotli compression was enabled), or uncompressed (for
// app development with cozy-stack serve --appdir).
func (s *aferoServer) openFile(filepath string) (afero.File, int, error) {
	compression := brotlied
	f, err := s.fs.Open(filepath + ".br")
	if os.IsNotExist(err) {
		compression = gzipped
		f, err = s.fs.Open(filepath + ".gz")
	}
	if os.IsNotExist(err) {
		compression = uncompressed
		f, err = s.fs.Open(filepath)
	}
	return f, compression, err
}

func (s *aferoServer) Open(slug, version, shasum, file string) (io.ReadCloser, error) {
	filepath := s.mkPath(slug, version, shasum, file)
	f, compression, err := s.openFile(filepath)
	if err != nil {
		return nil, err
	}
	switch compression {
	case uncompressed:
		return f, nil
	case gzipped:
		return newGzipReadCloser(f)
	case brotlied:
		return newBrotliReadCloser(f)
	default:
		panic(fmt.Errorf("Unknown compression type: %v", compression))
	}
}

func (s *aferoServer) ServeFileContent(w http.ResponseWriter, req *http.Request, slug, version, shasum, file string) error {
	filepath := s.mkPath(slug, version, shasum, file)
	return s.serveFileContent(w, req, filepath)
}

func (s *aferoServer) serveFileContent(w http.ResponseWriter, req *http.Request, filepath string) error {
	f, compression, err := s.openFile(filepath)
	if err != nil {
		return err
	}
	defer f.Close()

	var content io.Reader
	var size int64
	if checkEtag := req.Header.Get("Cache-Control") == ""; checkEtag {
		var b []byte
		h := md5.New()
		b, err = ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		etag := fmt.Sprintf(`"%s"`, hex.EncodeToString(h.Sum(nil)))
		if web_utils.CheckPreconditions(w, req, etag) {
			return nil
		}
		w.Header().Set("Etag", etag)
		size = int64(len(b))
		content = bytes.NewReader(b)
	} else {
		size, err = f.Seek(0, io.SeekEnd)
		if err != nil {
			return err
		}
		content = f
	}

	switch compression {
	case uncompressed:
		// Nothing to do
	case gzipped:
		if acceptGzipEncoding(req) {
			w.Header().Set("Content-Encoding", "gzip")
		} else {
			var gr *gzip.Reader
			var b []byte
			gr, err = gzip.NewReader(content)
			if err != nil {
				return err
			}
			defer gr.Close()
			b, err = ioutil.ReadAll(gr)
			if err != nil {
				return err
			}
			size = int64(len(b))
			content = bytes.NewReader(b)
		}
	case brotlied:
		if acceptBrotliEncoding(req) {
			w.Header().Set("Content-Encoding", "br")
		} else {
			var b []byte
			br := brotli.NewReader(content)
			b, err = ioutil.ReadAll(br)
			if err != nil {
				return err
			}
			size = int64(len(b))
			content = bytes.NewReader(b)
		}
	default:
		panic(fmt.Errorf("Unknown compression type: %v", compression))
	}

	contentType := mime.TypeByExtension(path.Ext(filepath))
	web_utils.ServeContent(w, req, contentType, size, content)
	return nil
}

func (s *aferoServer) FilesList(slug, version, shasum string) ([]string, error) {
	var names []string
	rootPath := s.mkPath(slug, version, shasum, "")
	err := afero.Walk(s.fs, rootPath, func(path string, infos os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !infos.IsDir() {
			name := strings.TrimPrefix(path, rootPath)
			name = strings.TrimSuffix(name, ".br")
			names = append(names, name)
		}
		return nil
	})
	return names, err
}

func defaultMakePath(slug, version, shasum, file string) string {
	basepath := path.Join("/", slug, version)
	if shasum != "" {
		basepath += "-" + shasum
	}
	filepath := path.Join("/", file)
	return path.Join(basepath, filepath)
}

func acceptBrotliEncoding(req *http.Request) bool {
	return strings.Contains(req.Header.Get("Accept-Encoding"), "br")
}

func acceptGzipEncoding(req *http.Request) bool {
	return strings.Contains(req.Header.Get("Accept-Encoding"), "gzip")
}

func containerName(appsType consts.AppType) string {
	switch appsType {
	case consts.WebappType:
		return "apps-web"
	case consts.KonnectorType:
		return "apps-konnectors"
	}
	panic("Unknown AppType")
}

func wrapSwiftErr(err error) error {
	if err == swift.ObjectNotFound || err == swift.ContainerNotFound {
		return os.ErrNotExist
	}
	return err
}
<commit_msg>Fix serving apps with devtools (#2914)<commit_after>package appfs

import (
	"bytes"
	"compress/gzip"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/andybalholm/brotli"
	"github.com/cozy/cozy-stack/pkg/consts"
	web_utils "github.com/cozy/cozy-stack/pkg/utils"
	"github.com/ncw/swift"
	"github.com/spf13/afero"
)

// FileServer interface defines a way to access and serve the application's
// data files.
type FileServer interface {
	Open(slug, version, shasum, file string) (io.ReadCloser, error)
	FilesList(slug, version, shasum string) ([]string, error)
	ServeFileContent(w http.ResponseWriter, req *http.Request,
		slug, version, shasum, file string) error
}

type swiftServer struct {
	c         *swift.Connection
	container string
}

type aferoServer struct {
	mkPath func(slug, version, shasum, file string) string
	fs     afero.Fs
}

type brotliReadCloser struct {
	br *brotli.Reader
	cl io.Closer
}

// brotli.Reader has no Close method. This little wrapper adds a method to
// close the underlying reader.
func newBrotliReadCloser(r io.ReadCloser) (io.ReadCloser, error) {
	br := brotli.NewReader(r)
	return brotliReadCloser{br: br, cl: r}, nil
}

func (r brotliReadCloser) Read(b []byte) (int, error) {
	return r.br.Read(b)
}

func (r brotliReadCloser) Close() error {
	return r.cl.Close()
}

type gzipReadCloser struct {
	gr *gzip.Reader
	cl io.Closer
}

// The Close method of gzip.Reader does not closes the underlying reader. This
// little wrapper does the closing.
func newGzipReadCloser(r io.ReadCloser) (io.ReadCloser, error) {
	gr, err := gzip.NewReader(r)
	if err != nil {
		return nil, err
	}
	return gzipReadCloser{gr: gr, cl: r}, nil
}

func (g gzipReadCloser) Read(b []byte) (int, error) {
	return g.gr.Read(b)
}

func (g gzipReadCloser) Close() error {
	err1 := g.gr.Close()
	err2 := g.cl.Close()
	if err1 != nil {
		return err1
	}
	if err2 != nil {
		return err2
	}
	return nil
}

// NewSwiftFileServer returns provides the apps.FileServer implementation
// using the swift backend as file server.
func NewSwiftFileServer(conn *swift.Connection, appsType consts.AppType) FileServer {
	return &swiftServer{
		c:         conn,
		container: containerName(appsType),
	}
}

func (s *swiftServer) Open(slug, version, shasum, file string) (io.ReadCloser, error) {
	objName := s.makeObjectName(slug, version, shasum, file)
	f, h, err := s.c.ObjectOpen(s.container, objName, false, nil)
	if err != nil {
		return nil, wrapSwiftErr(err)
	}
	o := h.ObjectMetadata()
	contentEncoding := o["content-encoding"]
	if contentEncoding == "br" {
		return newBrotliReadCloser(f)
	} else if contentEncoding == "gzip" {
		return newGzipReadCloser(f)
	}
	return f, nil
}

func (s *swiftServer) ServeFileContent(w http.ResponseWriter, req *http.Request, slug, version, shasum, file string) error {
	objName := s.makeObjectName(slug, version, shasum, file)
	f, h, err := s.c.ObjectOpen(s.container, objName, false, nil)
	if err != nil {
		return wrapSwiftErr(err)
	}
	defer f.Close()

	if checkETag := req.Header.Get("Cache-Control") == ""; checkETag {
		etag := fmt.Sprintf(`"%s"`, h["Etag"][:10])
		if web_utils.CheckPreconditions(w, req, etag) {
			return nil
		}
		w.Header().Set("Etag", etag)
	}

	var r io.Reader = f
	contentLength := h["Content-Length"]
	contentType := h["Content-Type"]
	o := h.ObjectMetadata()
	contentEncoding := o["content-encoding"]
	if contentEncoding == "br" {
		if acceptBrotliEncoding(req) {
			w.Header().Set("Content-Encoding", "br")
		} else {
			contentLength = o["original-content-length"]
			r = brotli.NewReader(f)
		}
	} else if contentEncoding == "gzip" {
		if acceptGzipEncoding(req) {
			w.Header().Set("Content-Encoding", "gzip")
		} else {
			contentLength = o["original-content-length"]
			var gr *gzip.Reader
			gr, err = gzip.NewReader(f)
			if err != nil {
				return err
			}
			defer gr.Close()
			r = gr
		}
	}

	ext := path.Ext(file)
	if contentType == "" {
		contentType = mime.TypeByExtension(ext)
	}
	if contentType == "text/xml" && ext == ".svg" {
		// override for files with text/xml content because of leading <?xml tag
		contentType = "image/svg+xml"
	}

	size, _ := strconv.ParseInt(contentLength, 10, 64)
	web_utils.ServeContent(w, req, contentType, size, r)
	return nil
}

func (s *swiftServer) makeObjectName(slug, version, shasum, file string) string {
	basepath := path.Join(slug, version)
	if shasum != "" {
		basepath += "-" + shasum
	}
	return path.Join(basepath, file)
}

func (s *swiftServer) FilesList(slug, version, shasum string) ([]string, error) {
	prefix := s.makeObjectName(slug, version, shasum, "") + "/"
	names, err := s.c.ObjectNamesAll(s.container, &swift.ObjectsOpts{
		Prefix: prefix,
	})
	if err != nil {
		return nil, err
	}
	filtered := names[:0]
	for _, n := range names {
		n = strings.TrimPrefix(n, prefix)
		if n != "" {
			filtered = append(filtered, n)
		}
	}
	return filtered, nil
}

// NewAferoFileServer returns a simple wrapper of the afero.Fs interface that
// provides the apps.FileServer interface.
//
// You can provide a makePath method to define how the file name should be
// created from the application's slug, version and file name. If not provided,
// the standard VFS concatenation (starting with vfs.WebappsDirName) is used.
func NewAferoFileServer(fs afero.Fs, makePath func(slug, version, shasum, file string) string) FileServer {
	if makePath == nil {
		makePath = defaultMakePath
	}
	return &aferoServer{
		mkPath: makePath,
		fs:     fs,
	}
}

const (
	uncompressed = iota + 1
	gzipped
	brotlied
)

// openFile opens the give filepath. By default, it is a file compressed with
// brotli (.br), but it can be a file compressed with gzip (.gz, for apps that
// were installed before brotli compression was enabled), or uncompressed (for
// app development with cozy-stack serve --appdir).
func (s *aferoServer) openFile(filepath string) (afero.File, int, error) {
	compression := brotlied
	f, err := s.fs.Open(filepath + ".br")
	if os.IsNotExist(err) {
		compression = gzipped
		f, err = s.fs.Open(filepath + ".gz")
	}
	if os.IsNotExist(err) {
		compression = uncompressed
		f, err = s.fs.Open(filepath)
	}
	return f, compression, err
}

func (s *aferoServer) Open(slug, version, shasum, file string) (io.ReadCloser, error) {
	filepath := s.mkPath(slug, version, shasum, file)
	f, compression, err := s.openFile(filepath)
	if err != nil {
		return nil, err
	}
	switch compression {
	case uncompressed:
		return f, nil
	case gzipped:
		return newGzipReadCloser(f)
	case brotlied:
		return newBrotliReadCloser(f)
	default:
		panic(fmt.Errorf("Unknown compression type: %v", compression))
	}
}

func (s *aferoServer) ServeFileContent(w http.ResponseWriter, req *http.Request, slug, version, shasum, file string) error {
	filepath := s.mkPath(slug, version, shasum, file)
	return s.serveFileContent(w, req, filepath)
}

func (s *aferoServer) serveFileContent(w http.ResponseWriter, req *http.Request, filepath string) error {
	f, compression, err := s.openFile(filepath)
	if err != nil {
		return err
	}
	defer f.Close()

	var content io.Reader
	var size int64
	if checkEtag := req.Header.Get("Cache-Control") == ""; checkEtag {
		var b []byte
		h := md5.New()
		b, err = ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		etag := fmt.Sprintf(`"%s"`, hex.EncodeToString(h.Sum(nil)))
		if web_utils.CheckPreconditions(w, req, etag) {
			return nil
		}
		w.Header().Set("Etag", etag)
		size = int64(len(b))
		content = bytes.NewReader(b)
	} else {
		size, err = f.Seek(0, io.SeekEnd)
		if err != nil {
			return err
		}
		_, err = f.Seek(0, io.SeekStart)
		if err != nil {
			return err
		}
		content = f
	}

	switch compression {
	case uncompressed:
		// Nothing to do
	case gzipped:
		if acceptGzipEncoding(req) {
			w.Header().Set("Content-Encoding", "gzip")
		} else {
			var gr *gzip.Reader
			var b []byte
			gr, err = gzip.NewReader(content)
			if err != nil {
				return err
			}
			defer gr.Close()
			b, err = ioutil.ReadAll(gr)
			if err != nil {
				return err
			}
			size = int64(len(b))
			content = bytes.NewReader(b)
		}
	case brotlied:
		if acceptBrotliEncoding(req) {
			w.Header().Set("Content-Encoding", "br")
		} else {
			var b []byte
			br := brotli.NewReader(content)
			b, err = ioutil.ReadAll(br)
			if err != nil {
				return err
			}
			size = int64(len(b))
			content = bytes.NewReader(b)
		}
	default:
		panic(fmt.Errorf("Unknown compression type: %v", compression))
	}

	contentType := mime.TypeByExtension(path.Ext(filepath))
	web_utils.ServeContent(w, req, contentType, size, content)
	return nil
}

func (s *aferoServer) FilesList(slug, version, shasum string) ([]string, error) {
	var names []string
	rootPath := s.mkPath(slug, version, shasum, "")
	err := afero.Walk(s.fs, rootPath, func(path string, infos os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !infos.IsDir() {
			name := strings.TrimPrefix(path, rootPath)
			name = strings.TrimSuffix(name, ".br")
			names = append(names, name)
		}
		return nil
	})
	return names, err
}

func defaultMakePath(slug, version, shasum, file string) string {
	basepath := path.Join("/", slug, version)
	if shasum != "" {
		basepath += "-" + shasum
	}
	filepath := path.Join("/", file)
	return path.Join(basepath, filepath)
}

func acceptBrotliEncoding(req *http.Request) bool {
	return strings.Contains(req.Header.Get("Accept-Encoding"), "br")
}

func acceptGzipEncoding(req *http.Request) bool {
	return strings.Contains(req.Header.Get("Accept-Encoding"), "gzip")
}

func containerName(appsType consts.AppType) string {
	switch appsType {
	case consts.WebappType:
		return "apps-web"
	case consts.KonnectorType:
		return "apps-konnectors"
	}
	panic("Unknown AppType")
}

func wrapSwiftErr(err error) error {
	if err == swift.ObjectNotFound || err == swift.ContainerNotFound {
		return os.ErrNotExist
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2018 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

// Package camo provides an HTTP proxy server with content type
// restrictions as well as regex host allow list support.
package camo

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

// Namespace used for Prometheus metrics.
const MetricNamespace = "camo"
const proxySubsystem = "proxy"

var (
	contentLengthExceeded = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: MetricNamespace,
			Subsystem: proxySubsystem,
			Name:      "content_length_exceeded_total",
			Help:      "The number of requests where the content length was exceeded.",
		},
	)
	responseFailed = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: MetricNamespace,
			Subsystem: proxySubsystem,
			Name:      "reponses_failed_total",
			Help:      "The number of responses that failed to send to the client.",
		},
	)
	responseTruncated = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: MetricNamespace,
			Subsystem: proxySubsystem,
			Name:      "reponses_truncated_total",
			Help:      "The number of responess that were too large to send.",
		},
	)
)
<commit_msg>rename vars<commit_after>// Copyright (c) 2012-2018 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

// Package camo provides an HTTP proxy server with content type
// restrictions as well as regex host allow list support.
package camo

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

// Namespace used for Prometheus metrics.
const MetricNamespace = "camo"
const MetricSubsystem = "proxy"

var (
	contentLengthExceeded = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: MetricNamespace,
			Subsystem: MetricSubsystem,
			Name:      "content_length_exceeded_total",
			Help:      "The number of requests where the content length was exceeded.",
		},
	)
	responseFailed = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: MetricNamespace,
			Subsystem: MetricSubsystem,
			Name:      "reponses_failed_total",
			Help:      "The number of responses that failed to send to the client.",
		},
	)
	responseTruncated = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: MetricNamespace,
			Subsystem: MetricSubsystem,
			Name:      "reponses_truncated_total",
			Help:      "The number of responess that were too large to send.",
		},
	)
)
<|endoftext|>


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

package dns

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/minio/minio-go/pkg/set"

	"github.com/coredns/coredns/plugin/etcd/msg"
	etcd "github.com/coreos/etcd/clientv3"
)

// ErrNoEntriesFound - Indicates no entries were found for the given key (directory)
var ErrNoEntriesFound = errors.New("No entries found for this key")

// create a new coredns service record for the bucket.
func newCoreDNSMsg(bucket, ip string, port int, ttl uint32) ([]byte, error) {
	return json.Marshal(&SrvRecord{
		Host:         ip,
		Port:         port,
		TTL:          ttl,
		CreationDate: time.Now().UTC(),
	})
}

// Retrieves list of DNS entries for the domain.
func (c *coreDNS) List() ([]SrvRecord, error) {
	key := msg.Path(fmt.Sprintf("%s.", c.domainName), defaultPrefixPath)
	return c.list(key)
}

// Retrieves DNS records for a bucket.
func (c *coreDNS) Get(bucket string) ([]SrvRecord, error) {
	key := msg.Path(fmt.Sprintf("%s.%s.", bucket, c.domainName), defaultPrefixPath)
	return c.list(key)
}

// Retrieves list of entries under the key passed.
// Note that this method fetches entries upto only two levels deep.
func (c *coreDNS) list(key string) ([]SrvRecord, error) {
	ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
	r, err := c.etcdClient.Get(ctx, key, etcd.WithPrefix())
	defer cancel()
	if err != nil {
		return nil, err
	}
	if r.Count == 0 {
		key = strings.TrimSuffix(key, "/")
		r, err = c.etcdClient.Get(ctx, key)
		if err != nil {
			return nil, err
		}
		if r.Count == 0 {
			return nil, ErrNoEntriesFound
		}
	}

	var srvRecords []SrvRecord
	for _, n := range r.Kvs {
		var srvRecord SrvRecord
		if err = json.Unmarshal([]byte(n.Value), &srvRecord); err != nil {
			return nil, err
		}
		srvRecord.Key = strings.TrimPrefix(string(n.Key), key)
		srvRecord.Key = strings.TrimSuffix(srvRecord.Key, srvRecord.Host)
		srvRecords = append(srvRecords, srvRecord)

	}
	if srvRecords != nil {
		sort.Slice(srvRecords, func(i int, j int) bool {
			return srvRecords[i].Key < srvRecords[j].Key
		})
	} else {
		return nil, ErrNoEntriesFound
	}
	return srvRecords, nil
}

// Adds DNS entries into etcd endpoint in CoreDNS etcd message format.
func (c *coreDNS) Put(bucket string) error {
	for ip := range c.domainIPs {
		bucketMsg, err := newCoreDNSMsg(bucket, ip, c.domainPort, defaultTTL)
		if err != nil {
			return err
		}
		key := msg.Path(fmt.Sprintf("%s.%s", bucket, c.domainName), defaultPrefixPath)
		key = key + "/" + ip
		ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
		_, err = c.etcdClient.Put(ctx, key, string(bucketMsg))
		defer cancel()
		if err != nil {
			ctx, cancel = context.WithTimeout(context.Background(), defaultContextTimeout)
			c.etcdClient.Delete(ctx, key)
			defer cancel()
			return err
		}
	}
	return nil
}

// Removes DNS entries added in Put().
func (c *coreDNS) Delete(bucket string) error {
	key := msg.Path(fmt.Sprintf("%s.%s.", bucket, c.domainName), defaultPrefixPath)
	ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
	_, err := c.etcdClient.Delete(ctx, key)
	defer cancel()
	return err
}

// CoreDNS - represents dns config for coredns server.
type coreDNS struct {
	domainName string
	domainIPs  set.StringSet
	domainPort int
	etcdClient *etcd.Client
}

// NewCoreDNS - initialize a new coreDNS set/unset values.
func NewCoreDNS(domainName string, domainIPs set.StringSet, domainPort string, etcdClient *etcd.Client) (Config, error) {
	if domainName == "" || domainIPs.IsEmpty() {
		return nil, errors.New("invalid argument")
	}

	port, err := strconv.Atoi(domainPort)
	if err != nil {
		return nil, err
	}

	return &coreDNS{
		domainName: domainName,
		domainIPs:  domainIPs,
		domainPort: port,
		etcdClient: etcdClient,
	}, nil
}
<commit_msg>List exact DNS entries for a requested bucketName (#6936)<commit_after>/*
 * Minio Cloud Storage, (C) 2018 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dns

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/minio/minio-go/pkg/set"

	"github.com/coredns/coredns/plugin/etcd/msg"
	etcd "github.com/coreos/etcd/clientv3"
)

// ErrNoEntriesFound - Indicates no entries were found for the given key (directory)
var ErrNoEntriesFound = errors.New("No entries found for this key")

// create a new coredns service record for the bucket.
func newCoreDNSMsg(bucket, ip string, port int, ttl uint32) ([]byte, error) {
	return json.Marshal(&SrvRecord{
		Host:         ip,
		Port:         port,
		TTL:          ttl,
		CreationDate: time.Now().UTC(),
	})
}

// Retrieves list of DNS entries for the domain.
func (c *coreDNS) List() ([]SrvRecord, error) {
	key := msg.Path(fmt.Sprintf("%s.", c.domainName), defaultPrefixPath)
	return c.list(key)
}

// Retrieves DNS records for a bucket.
func (c *coreDNS) Get(bucket string) ([]SrvRecord, error) {
	key := msg.Path(fmt.Sprintf("%s.%s.", bucket, c.domainName), defaultPrefixPath)
	return c.list(key)
}

// Retrieves list of entries under the key passed.
// Note that this method fetches entries upto only two levels deep.
func (c *coreDNS) list(key string) ([]SrvRecord, error) {
	ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
	r, err := c.etcdClient.Get(ctx, key, etcd.WithPrefix())
	defer cancel()
	if err != nil {
		return nil, err
	}
	if r.Count == 0 {
		key = strings.TrimSuffix(key, "/")
		r, err = c.etcdClient.Get(ctx, key)
		if err != nil {
			return nil, err
		}
		if r.Count == 0 {
			return nil, ErrNoEntriesFound
		}
	}

	var srvRecords []SrvRecord
	for _, n := range r.Kvs {
		var srvRecord SrvRecord
		if err = json.Unmarshal([]byte(n.Value), &srvRecord); err != nil {
			return nil, err
		}
		srvRecord.Key = strings.TrimPrefix(string(n.Key), key)
		srvRecord.Key = strings.TrimSuffix(srvRecord.Key, srvRecord.Host)
		// SRV records are stored in the following form
		// /skydns/net/miniocloud/bucket1, so this function serves multiple
		// purposes basically when we do a Get(bucketName) this function
		// should return a single DNS record for any input 'bucketName'.
		//
		// In all other situations when we want to list all DNS records,
		// which is handled in the else clause.
		if key != msg.Path(fmt.Sprintf(".%s.", c.domainName), defaultPrefixPath) {
			if srvRecord.Key == "/" {
				srvRecords = append(srvRecords, srvRecord)
			}
		} else {
			srvRecords = append(srvRecords, srvRecord)
		}

	}
	if len(srvRecords) == 0 {
		return nil, ErrNoEntriesFound
	}
	sort.Slice(srvRecords, func(i int, j int) bool {
		return srvRecords[i].Key < srvRecords[j].Key
	})
	return srvRecords, nil
}

// Adds DNS entries into etcd endpoint in CoreDNS etcd message format.
func (c *coreDNS) Put(bucket string) error {
	for ip := range c.domainIPs {
		bucketMsg, err := newCoreDNSMsg(bucket, ip, c.domainPort, defaultTTL)
		if err != nil {
			return err
		}
		key := msg.Path(fmt.Sprintf("%s.%s", bucket, c.domainName), defaultPrefixPath)
		key = key + "/" + ip
		ctx, cancel := context.WithTimeout(context.Background(), defaultContextTimeout)
		_, err = c.etcdClient.Put(ctx, key, string(bucketMsg))
		defer cancel()
		if err != nil {
			ctx, cancel = context.WithTimeout(context.Background(), defaultContextTimeout)
			c.etcdClient.Delete(ctx, key)
			defer cancel()
			return err
		}
	}
	return nil
}

// Removes DNS entries added in Put().
func (c *coreDNS) Delete(bucket string) error {
	key := msg.Path(fmt.Sprintf("%s.%s.", bucket, c.domainName), defaultPrefixPath)
	srvRecords, err := c.list(key)
	if err != nil {
		return err
	}
	for _, record := range srvRecords {
		dctx, dcancel := context.WithTimeout(context.Background(), defaultContextTimeout)
		if _, err = c.etcdClient.Delete(dctx, key+"/"+record.Host); err != nil {
			dcancel()
			return err
		}
		dcancel()
	}
	return err
}

// CoreDNS - represents dns config for coredns server.
type coreDNS struct {
	domainName string
	domainIPs  set.StringSet
	domainPort int
	etcdClient *etcd.Client
}

// NewCoreDNS - initialize a new coreDNS set/unset values.
func NewCoreDNS(domainName string, domainIPs set.StringSet, domainPort string, etcdClient *etcd.Client) (Config, error) {
	if domainName == "" || domainIPs.IsEmpty() {
		return nil, errors.New("invalid argument")
	}

	port, err := strconv.Atoi(domainPort)
	if err != nil {
		return nil, err
	}

	return &coreDNS{
		domainName: domainName,
		domainIPs:  domainIPs,
		domainPort: port,
		etcdClient: etcdClient,
	}, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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 version

// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// The "-dev" suffix in the version info indicates that fact, and it means the
// current build is from a version greater that version. For example, v0.7-dev
// means version > 0.7 and < 0.8. (There's exceptions to this rule, see
// docs/releasing.md for more details.)
//
// When releasing a new Kubernetes version, this file should be updated to
// reflect the new version, and then a git annotated tag (using format vX.Y
// where X == Major version and Y == Minor version) should be created to point
// to the commit that updates pkg/version/base.go

var (
	// TODO: Deprecate gitMajor and gitMinor, use only gitVersion instead.
	gitMajor     string = "0"              // major version, always numeric
	gitMinor     string = "9.1+"           // minor version, numeric possibly followed by "+"
	gitVersion   string = "v0.9.1-dev"     // version from git, output of $(git describe)
	gitCommit    string = ""               // sha1 from git, output of $(git rev-parse HEAD)
	gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"
)
<commit_msg>Kubernetes version v0.9.2<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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 version

// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// The "-dev" suffix in the version info indicates that fact, and it means the
// current build is from a version greater that version. For example, v0.7-dev
// means version > 0.7 and < 0.8. (There's exceptions to this rule, see
// docs/releasing.md for more details.)
//
// When releasing a new Kubernetes version, this file should be updated to
// reflect the new version, and then a git annotated tag (using format vX.Y
// where X == Major version and Y == Minor version) should be created to point
// to the commit that updates pkg/version/base.go

var (
	// TODO: Deprecate gitMajor and gitMinor, use only gitVersion instead.
	gitMajor     string = "0"              // major version, always numeric
	gitMinor     string = "9.2"            // minor version, numeric possibly followed by "+"
	gitVersion   string = "v0.9.2"         // version from git, output of $(git describe)
	gitCommit    string = ""               // sha1 from git, output of $(git rev-parse HEAD)
	gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"
)
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package signal_test

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

func ExampleNotify() {
	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	// Block until a signal is received.
	s := <-c
	fmt.Println("Got signal:", s)
}
<commit_msg>os/signal: don't expect to be notified for os.Kill<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package signal_test

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

func ExampleNotify() {
	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	// Block until a signal is received.
	s := <-c
	fmt.Println("Got signal:", s)
}
<|endoftext|>


<commit_before>// Package boltdbresumer provides a Resumer implementation that uses a Bolt database file as storage.
package boltdbresumer

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

	"github.com/boltdb/bolt"
	"github.com/cenkalti/rain/internal/resumer"
)

var (
	infoHashKey        = []byte("info_hash")
	portKey            = []byte("port")
	nameKey            = []byte("name")
	trackersKey        = []byte("trackers")
	destKey            = []byte("dest")
	infoKey            = []byte("info")
	bitfieldKey        = []byte("bitfield")
	addedAtKey         = []byte("added_at")
	bytesDownloadedKey = []byte("bytes_downloaded")
	bytesUploadedKey   = []byte("bytes_uploaded")
	bytesWastedKey     = []byte("bytes_wasted")
	seededForKey       = []byte("seeded_for")
)

type Resumer struct {
	db                    *bolt.DB
	mainBucket, subBucket []byte
}

var _ resumer.Resumer = (*Resumer)(nil)

func New(db *bolt.DB, mainBucket, subBucket []byte) (*Resumer, error) {
	err := db.Update(func(tx *bolt.Tx) error {
		_, err2 := tx.CreateBucketIfNotExists(mainBucket)
		return err2
	})
	if err != nil {
		return nil, err
	}
	return &Resumer{
		db:         db,
		mainBucket: mainBucket,
		subBucket:  subBucket,
	}, nil
}

func (r *Resumer) Write(spec *Spec) error {
	port := strconv.Itoa(spec.Port)
	trackers, err := json.Marshal(spec.Trackers)
	if err != nil {
		return err
	}
	return r.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.Bucket(r.mainBucket).CreateBucketIfNotExists(r.subBucket)
		if err != nil {
			return err
		}
		b.Put(infoHashKey, spec.InfoHash)
		b.Put(portKey, []byte(port))
		b.Put(nameKey, []byte(spec.Name))
		b.Put(destKey, []byte(spec.Dest))
		b.Put(trackersKey, trackers)
		b.Put(infoKey, spec.Info)
		b.Put(bitfieldKey, spec.Bitfield)
		b.Put(addedAtKey, []byte(spec.AddedAt.Format(time.RFC3339)))
		b.Put(bytesDownloadedKey, []byte(strconv.FormatInt(spec.BytesDownloaded, 10)))
		b.Put(bytesUploadedKey, []byte(strconv.FormatInt(spec.BytesUploaded, 10)))
		b.Put(bytesWastedKey, []byte(strconv.FormatInt(spec.BytesWasted, 10)))
		return nil
	})
}

func (r *Resumer) WriteInfo(value []byte) error {
	return r.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return nil
		}
		return b.Put(infoKey, value)
	})
}

func (r *Resumer) WriteBitfield(value []byte) error {
	return r.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return nil
		}
		return b.Put(bitfieldKey, value)
	})
}

func (r *Resumer) WriteStats(s resumer.Stats) error {
	return r.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return nil
		}
		b.Put(bytesDownloadedKey, []byte(strconv.FormatInt(s.BytesDownloaded, 10)))
		b.Put(bytesUploadedKey, []byte(strconv.FormatInt(s.BytesUploaded, 10)))
		b.Put(bytesWastedKey, []byte(strconv.FormatInt(s.BytesWasted, 10)))
		b.Put(seededForKey, []byte(s.SeededFor.String()))
		return nil
	})
}

func (r *Resumer) Read() (*Spec, error) {
	var spec *Spec
	err := r.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return fmt.Errorf("bucket not found: %q", string(r.subBucket))
		}

		value := b.Get(infoHashKey)
		if value == nil {
			return fmt.Errorf("key not found: %q", string(infoHashKey))
		}

		spec = new(Spec)
		spec.InfoHash = make([]byte, len(value))
		copy(spec.InfoHash, value)

		var err error
		value = b.Get(portKey)
		spec.Port, err = strconv.Atoi(string(value))
		if err != nil {
			return err
		}

		value = b.Get(nameKey)
		if value != nil {
			spec.Name = string(value)
		}

		value = b.Get(trackersKey)
		if value != nil {
			err = json.Unmarshal(value, &spec.Trackers)
			if err != nil {
				return err
			}
		}

		value = b.Get(destKey)
		spec.Dest = string(value)

		value = b.Get(infoKey)
		if value != nil {
			spec.Info = make([]byte, len(value))
			copy(spec.Info, value)
		}

		value = b.Get(bitfieldKey)
		if value != nil {
			spec.Bitfield = make([]byte, len(value))
			copy(spec.Bitfield, value)
		}

		value = b.Get(addedAtKey)
		if value != nil {
			spec.AddedAt, err = time.Parse(time.RFC3339, string(value))
			if err != nil {
				return err
			}
		}

		value = b.Get(bytesDownloadedKey)
		if value != nil {
			spec.BytesDownloaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(bytesUploadedKey)
		if value != nil {
			spec.BytesUploaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(bytesWastedKey)
		if value != nil {
			spec.BytesWasted, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(seededForKey)
		if value != nil {
			spec.SeededFor, err = time.ParseDuration(string(value))
			if err != nil {
				return err
			}
		}

		return nil
	})
	return spec, err
}
<commit_msg>define keys in struct<commit_after>// Package boltdbresumer provides a Resumer implementation that uses a Bolt database file as storage.
package boltdbresumer

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

	"github.com/boltdb/bolt"
	"github.com/cenkalti/rain/internal/resumer"
)

var Keys = struct {
	InfoHash        []byte
	Port            []byte
	Name            []byte
	Trackers        []byte
	Dest            []byte
	Info            []byte
	Bitfield        []byte
	AddedAt         []byte
	BytesDownloaded []byte
	BytesUploaded   []byte
	BytesWasted     []byte
	SeededFor       []byte
}{
	InfoHash:        []byte("info_hash"),
	Port:            []byte("port"),
	Name:            []byte("name"),
	Trackers:        []byte("trackers"),
	Dest:            []byte("dest"),
	Info:            []byte("info"),
	Bitfield:        []byte("bitfield"),
	AddedAt:         []byte("added_at"),
	BytesDownloaded: []byte("bytes_downloaded"),
	BytesUploaded:   []byte("bytes_uploaded"),
	BytesWasted:     []byte("bytes_wasted"),
	SeededFor:       []byte("seeded_for"),
}

type Resumer struct {
	db                    *bolt.DB
	mainBucket, subBucket []byte
}

var _ resumer.Resumer = (*Resumer)(nil)

func New(db *bolt.DB, mainBucket, subBucket []byte) (*Resumer, error) {
	err := db.Update(func(tx *bolt.Tx) error {
		_, err2 := tx.CreateBucketIfNotExists(mainBucket)
		return err2
	})
	if err != nil {
		return nil, err
	}
	return &Resumer{
		db:         db,
		mainBucket: mainBucket,
		subBucket:  subBucket,
	}, nil
}

func (r *Resumer) Write(spec *Spec) error {
	port := strconv.Itoa(spec.Port)
	trackers, err := json.Marshal(spec.Trackers)
	if err != nil {
		return err
	}
	return r.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.Bucket(r.mainBucket).CreateBucketIfNotExists(r.subBucket)
		if err != nil {
			return err
		}
		b.Put(Keys.InfoHash, spec.InfoHash)
		b.Put(Keys.Port, []byte(port))
		b.Put(Keys.Name, []byte(spec.Name))
		b.Put(Keys.Dest, []byte(spec.Dest))
		b.Put(Keys.Trackers, trackers)
		b.Put(Keys.Info, spec.Info)
		b.Put(Keys.Bitfield, spec.Bitfield)
		b.Put(Keys.AddedAt, []byte(spec.AddedAt.Format(time.RFC3339)))
		b.Put(Keys.BytesDownloaded, []byte(strconv.FormatInt(spec.BytesDownloaded, 10)))
		b.Put(Keys.BytesUploaded, []byte(strconv.FormatInt(spec.BytesUploaded, 10)))
		b.Put(Keys.SeededFor, []byte(strconv.FormatInt(spec.BytesWasted, 10)))
		return nil
	})
}

func (r *Resumer) WriteInfo(value []byte) error {
	return r.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return nil
		}
		return b.Put(Keys.Info, value)
	})
}

func (r *Resumer) WriteBitfield(value []byte) error {
	return r.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return nil
		}
		return b.Put(Keys.Bitfield, value)
	})
}

func (r *Resumer) WriteStats(s resumer.Stats) error {
	return r.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return nil
		}
		b.Put(Keys.BytesDownloaded, []byte(strconv.FormatInt(s.BytesDownloaded, 10)))
		b.Put(Keys.BytesUploaded, []byte(strconv.FormatInt(s.BytesUploaded, 10)))
		b.Put(Keys.BytesWasted, []byte(strconv.FormatInt(s.BytesWasted, 10)))
		b.Put(Keys.SeededFor, []byte(time.Duration(s.SeededFor).String()))
		return nil
	})
}

func (r *Resumer) Read() (*Spec, error) {
	var spec *Spec
	err := r.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(r.mainBucket).Bucket(r.subBucket)
		if b == nil {
			return fmt.Errorf("bucket not found: %q", string(r.subBucket))
		}

		value := b.Get(Keys.InfoHash)
		if value == nil {
			return fmt.Errorf("key not found: %q", string(Keys.InfoHash))
		}

		spec = new(Spec)
		spec.InfoHash = make([]byte, len(value))
		copy(spec.InfoHash, value)

		var err error
		value = b.Get(Keys.Port)
		spec.Port, err = strconv.Atoi(string(value))
		if err != nil {
			return err
		}

		value = b.Get(Keys.Name)
		if value != nil {
			spec.Name = string(value)
		}

		value = b.Get(Keys.Trackers)
		if value != nil {
			err = json.Unmarshal(value, &spec.Trackers)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.Dest)
		spec.Dest = string(value)

		value = b.Get(Keys.Info)
		if value != nil {
			spec.Info = make([]byte, len(value))
			copy(spec.Info, value)
		}

		value = b.Get(Keys.Bitfield)
		if value != nil {
			spec.Bitfield = make([]byte, len(value))
			copy(spec.Bitfield, value)
		}

		value = b.Get(Keys.AddedAt)
		if value != nil {
			spec.AddedAt, err = time.Parse(time.RFC3339, string(value))
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesDownloaded)
		if value != nil {
			spec.BytesDownloaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesUploaded)
		if value != nil {
			spec.BytesUploaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesWasted)
		if value != nil {
			spec.BytesWasted, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.SeededFor)
		if value != nil {
			spec.SeededFor, err = time.ParseDuration(string(value))
			if err != nil {
				return err
			}
		}

		return nil
	})
	return spec, err
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stdscript

import (
	"bytes"
	"testing"

	"github.com/decred/dcrd/txscript/v4"
)

// complexScriptV0 is a version 0 script comprised of half as many opcodes as
// the maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
var complexScriptV0 = func() []byte {
	const (
		maxScriptSize        = txscript.MaxScriptSize
		maxScriptElementSize = txscript.MaxScriptElementSize
	)
	var scriptLen int
	builder := txscript.NewScriptBuilder()
	for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
		builder.AddOp(txscript.OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
	for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
		builder.AddData(maxData)
	}
	script, err := builder.Script()
	if err != nil {
		panic(err)
	}
	return script
}()

// makeBenchmarks constructs a slice of tests to use in the benchmarks as
// follows:
// - Start with a version 0 complex non standard script
// - Add all tests for which the provided filter function returns true
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
	benches := make([]scriptTest, 0, 5)
	benches = append(benches, scriptTest{
		name:    "v0 complex non standard",
		version: 0,
		script:  complexScriptV0,
	})
	for _, test := range scriptV0Tests {
		if filterFn(test) {
			benches = append(benches, test)
		}
	}
	return benches
}

// benchIsX is a convenience function that runs benchmarks for the entries that
// match the provided filter function using the given script type determination
// function and ensures the result matches the expected one.
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
	b.Helper()

	benches := makeBenchmarks(filterFn)
	for _, bench := range benches {
		want := filterFn(bench)
		b.Run(bench.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := isXFn(bench.version, bench.script)
				if got != want {
					b.Fatalf("%q: unexpected result -- got %v, want %v",
						bench.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyScript)
}

// BenchmarkIsPubKeyEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEd25519
	}
	benchIsX(b, filterFn, IsPubKeyEd25519Script)
}

// BenchmarkIsPubKeySchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeySchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeySchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeySchnorrSecp256k1Script)
}

// BenchmarkIsPubKeyHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashScript)
}

// BenchmarkIsPubKeyHashEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyHashEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEd25519
	}
	benchIsX(b, filterFn, IsPubKeyHashEd25519Script)
}

// BenchmarkIsPubKeyHashSchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeyHashSchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashSchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashSchnorrSecp256k1Script)
}

// BenchmarkIsScriptHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2sh scripts.
func BenchmarkIsScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STScriptHash
	}
	benchIsX(b, filterFn, IsScriptHashScript)
}

// BenchmarkIsMultiSigScript benchmarks the performance of analyzing various
// public key scripts to determine if they are multisignature scripts.
func BenchmarkIsMultiSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && !test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigScript)
}

// BenchmarkIsMultiSigSigScript benchmarks the performance of analyzing various
// signature scripts to determine if they are likely to be multisignature redeem
// scripts.
func BenchmarkIsMultiSigSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigSigScript)
}
<commit_msg>stdscript: Add extract v0 multisig redeem benchmark.<commit_after>// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stdscript

import (
	"bytes"
	"testing"

	"github.com/decred/dcrd/txscript/v4"
)

// complexScriptV0 is a version 0 script comprised of half as many opcodes as
// the maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
var complexScriptV0 = func() []byte {
	const (
		maxScriptSize        = txscript.MaxScriptSize
		maxScriptElementSize = txscript.MaxScriptElementSize
	)
	var scriptLen int
	builder := txscript.NewScriptBuilder()
	for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
		builder.AddOp(txscript.OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
	for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
		builder.AddData(maxData)
	}
	script, err := builder.Script()
	if err != nil {
		panic(err)
	}
	return script
}()

// makeBenchmarks constructs a slice of tests to use in the benchmarks as
// follows:
// - Start with a version 0 complex non standard script
// - Add all tests for which the provided filter function returns true
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
	benches := make([]scriptTest, 0, 5)
	benches = append(benches, scriptTest{
		name:    "v0 complex non standard",
		version: 0,
		script:  complexScriptV0,
	})
	for _, test := range scriptV0Tests {
		if filterFn(test) {
			benches = append(benches, test)
		}
	}
	return benches
}

// benchIsX is a convenience function that runs benchmarks for the entries that
// match the provided filter function using the given script type determination
// function and ensures the result matches the expected one.
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
	b.Helper()

	benches := makeBenchmarks(filterFn)
	for _, bench := range benches {
		want := filterFn(bench)
		b.Run(bench.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := isXFn(bench.version, bench.script)
				if got != want {
					b.Fatalf("%q: unexpected result -- got %v, want %v",
						bench.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyScript)
}

// BenchmarkIsPubKeyEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEd25519
	}
	benchIsX(b, filterFn, IsPubKeyEd25519Script)
}

// BenchmarkIsPubKeySchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeySchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeySchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeySchnorrSecp256k1Script)
}

// BenchmarkIsPubKeyHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pkh-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashScript)
}

// BenchmarkIsPubKeyHashEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyHashEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashEd25519
	}
	benchIsX(b, filterFn, IsPubKeyHashEd25519Script)
}

// BenchmarkIsPubKeyHashSchnorrSecp256k1Script benchmarks the performance of
// analyzing various public key scripts to determine if they are
// p2pkh-schnorr-secp256k1 scripts.
func BenchmarkIsPubKeyHashSchnorrSecp256k1Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyHashSchnorrSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyHashSchnorrSecp256k1Script)
}

// BenchmarkIsScriptHashScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2sh scripts.
func BenchmarkIsScriptHashScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STScriptHash
	}
	benchIsX(b, filterFn, IsScriptHashScript)
}

// BenchmarkIsMultiSigScript benchmarks the performance of analyzing various
// public key scripts to determine if they are multisignature scripts.
func BenchmarkIsMultiSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && !test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigScript)
}

// BenchmarkIsMultiSigSigScript benchmarks the performance of analyzing various
// signature scripts to determine if they are likely to be multisignature redeem
// scripts.
func BenchmarkIsMultiSigSigScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STMultiSig && test.isSig
	}
	benchIsX(b, filterFn, IsMultiSigSigScript)
}

// BenchmarkMultiSigRedeemScriptFromScriptSigV0 benchmarks the performance of
// extracting the redeem script from various version 0 signature scripts.
func BenchmarkMultiSigRedeemScriptFromScriptSigV0(b *testing.B) {
	for _, test := range scriptV0Tests {
		if test.version != 0 || test.wantType != STMultiSig || !test.isSig {
			continue
		}
		want := test.wantData.([]byte)

		b.Run(test.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := MultiSigRedeemScriptFromScriptSigV0(test.script)
				if !bytes.Equal(got, want) {
					b.Fatalf("%q: unexpected result -- got %x, want %x",
						test.name, got, want)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>// Package notification handles all notifications for a job. This includes
// build and deployment notifications.
package notification

// Map of all available templates.
// Key = identifier used by LeeroyCI, value = template string.
var templates = map[string]string{
	KindBuild: templateBuild,
}

// Template for build notifications.
var templateBuild = "Repository: {{.Repo}} Branch: {{.Branch}} by {{.Name}} <{{.Email}}> -> Build {{if .Status}}success{{else}}failed{{end}}\nDetails: {{.URL}}"
<commit_msg>add deploy notifications<commit_after>// Package notification handles all notifications for a job. This includes
// build and deployment notifications.
package notification

// Map of all available templates.
// Key = identifier used by LeeroyCI, value = template string.
var templates = map[string]string{
	KindBuild:       templateBuild,
	KindDeployStart: templateDeployStart,
	KindDeployDone:  templateDeployDone,
}

// Template for build notifications.
var templateBuild = "Repository: {{.Repo}} Branch: {{.Branch}} by {{.Name}} <{{.Email}}> -> Build {{if .Status}}success{{else}}failed{{end}}\nDetails: {{.URL}}"

// Template before a deployment task starts.
var templateDeployStart = "Deploying {{.Branch}} for {{.Repo}}"

// Template after a deployment task finished.
var templateDeployDone = "Deployment {{if .Deploy}}successful{{else}}failed{{end}} {{.Branch}} for {{.Repo}}\nDetails: {{.URL}}"
<|endoftext|>


<commit_before>package constants

const (
	HOST = "0.0.0.0" // All host names
	PORT = "9000"

	LENGTH_HEADER_SIZE = 3 // Measured in bytes

	// Packet constants for plug communication
	HEAD = "@H\n"
	ACK  = "\x06\n"
	OKAY = "@K\n"

	READ_TIME_LIMIT = 5 // Measured in seconds

	HEADER_REGEX = "^(?:THS)(\\d+)(?:t\\d+X)$"

	// Database
	DB_SOCKET   = "/var/run/postgresql/.s.PGSQL.5433"
	DB_PORT     = 5433
	DB_USER     = "seads"
	DB_NAME     = "seads"
	DB_PASSWORD = ""
)
<commit_msg>Fixed Postgres socket path error.<commit_after>package constants

const (
	HOST = "0.0.0.0" // All host names
	PORT = "9000"

	LENGTH_HEADER_SIZE = 3 // Measured in bytes

	// Packet constants for plug communication
	HEAD = "@H\n"
	ACK  = "\x06\n"
	OKAY = "@K\n"

	READ_TIME_LIMIT = 5 // Measured in seconds

	HEADER_REGEX = "^(?:THS)(\\d+)(?:t\\d+X)$"

	// Database
	DB_SOCKET   = "/var/run/postgresql"
	DB_PORT     = 5433
	DB_USER     = "seads"
	DB_NAME     = "seads"
	DB_PASSWORD = ""
)
<|endoftext|>


<commit_before>package securitygroup_test

import (
	"github.com/cloudfoundry/cli/cf/api/fakes"
	test_org "github.com/cloudfoundry/cli/cf/api/organizations/fakes"
	testapi "github.com/cloudfoundry/cli/cf/api/security_groups/fakes"
	zoidberg "github.com/cloudfoundry/cli/cf/api/security_groups/spaces/fakes"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/errors"
	"github.com/cloudfoundry/cli/cf/models"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/cf/commands/securitygroup"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("bind-security-group command", func() {
	var (
		ui                    *testterm.FakeUI
		cmd                   BindSecurityGroup
		configRepo            core_config.ReadWriter
		fakeSecurityGroupRepo *testapi.FakeSecurityGroupRepo
		requirementsFactory   *testreq.FakeReqFactory
		fakeSpaceRepo         *fakes.FakeSpaceRepository
		fakeOrgRepo           *test_org.FakeOrganizationRepository
		fakeSpaceBinder       *zoidberg.FakeSecurityGroupSpaceBinder
	)

	BeforeEach(func() {
		ui = &testterm.FakeUI{}
		fakeOrgRepo = &test_org.FakeOrganizationRepository{}
		fakeSpaceRepo = &fakes.FakeSpaceRepository{}
		requirementsFactory = &testreq.FakeReqFactory{}
		fakeSecurityGroupRepo = &testapi.FakeSecurityGroupRepo{}
		configRepo = testconfig.NewRepositoryWithDefaults()
		fakeSpaceBinder = &zoidberg.FakeSecurityGroupSpaceBinder{}
		cmd = NewBindSecurityGroup(ui, configRepo, fakeSecurityGroupRepo, fakeSpaceRepo, fakeOrgRepo, fakeSpaceBinder)
	})

	runCommand := func(args ...string) {
		testcmd.RunCommand(cmd, args, requirementsFactory)
	}

	Describe("requirements", func() {
		It("fails when the user is not logged in", func() {
			runCommand("my-craaaaaazy-security-group", "my-org", "my-space")

			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})

		It("succeeds when the user is logged in", func() {
			requirementsFactory.LoginSuccess = true
			runCommand("my-craaaaaazy-security-group", "my-org", "my-space")

			Expect(testcmd.CommandDidPassRequirements).To(BeTrue())
		})

		It("fails with usage when not provided the name of a security group, org, and space", func() {
			requirementsFactory.LoginSuccess = true
			runCommand("one fish", "two fish", "three fish", "purple fish")

			Expect(ui.FailedWithUsage).To(BeTrue())
		})
	})

	Context("when the user is logged in and provides the name of a security group", func() {
		BeforeEach(func() {
			requirementsFactory.LoginSuccess = true
		})

		Context("when a security group with that name does not exist", func() {
			BeforeEach(func() {
				fakeSecurityGroupRepo.ReadReturns(models.SecurityGroup{}, errors.NewModelNotFoundError("security group", "my-nonexistent-security-group"))
			})

			It("fails and tells the user", func() {
				runCommand("my-nonexistent-security-group", "my-org", "my-space")

				Expect(fakeSecurityGroupRepo.ReadArgsForCall(0)).To(Equal("my-nonexistent-security-group"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"security group", "my-nonexistent-security-group", "not found"},
				))
			})
		})

		Context("when the org does not exist", func() {
			BeforeEach(func() {
				fakeOrgRepo.FindByNameReturns(models.Organization{}, errors.New("Org org not found"))
			})

			It("fails and tells the user", func() {
				runCommand("sec group", "org", "space")

				Expect(fakeOrgRepo.FindByNameArgsForCall(0)).To(Equal("org"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"Org", "org", "not found"},
				))
			})
		})

		Context("when the space does not exist", func() {
			BeforeEach(func() {
				org := models.Organization{}
				org.Name = "org-name"
				org.Guid = "org-guid"
				fakeOrgRepo.ListOrgsReturns([]models.Organization{org}, nil)
				fakeOrgRepo.FindByNameReturns(org, nil)
				fakeSpaceRepo.FindByNameInOrgError = errors.NewModelNotFoundError("Space", "space-name")
			})

			It("fails and tells the user", func() {
				runCommand("sec group", "org-name", "space-name")

				Expect(fakeSpaceRepo.FindByNameInOrgName).To(Equal("space-name"))
				Expect(fakeSpaceRepo.FindByNameInOrgOrgGuid).To(Equal("org-guid"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"Space", "space-name", "not found"},
				))
			})
		})

		Context("everything is hunky dory", func() {
			BeforeEach(func() {
				org := models.Organization{}
				org.Name = "org-name"
				org.Guid = "org-guid"
				fakeOrgRepo.ListOrgsReturns([]models.Organization{org}, nil)

				space := models.Space{}
				space.Name = "space-name"
				space.Guid = "space-guid"
				fakeSpaceRepo.FindByNameInOrgSpace = space

				securityGroup := models.SecurityGroup{}
				securityGroup.Name = "security-group"
				securityGroup.Guid = "security-group-guid"
				fakeSecurityGroupRepo.ReadReturns(securityGroup, nil)
			})

			JustBeforeEach(func() {
				runCommand("security-group", "org-name", "space-name")
			})

			It("assigns the security group to the space", func() {
				secGroupGuid, spaceGuid := fakeSpaceBinder.BindSpaceArgsForCall(0)
				Expect(secGroupGuid).To(Equal("security-group-guid"))
				Expect(spaceGuid).To(Equal("space-guid"))
			})

			It("describes what it is doing for the user's benefit", func() {
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Assigning", "security-group", "space-name", "org-name", "my-user"},
					[]string{"OK"},
					[]string{"TIP: Changes will not apply to existing running applications until they are restarted."},
				))
			})
		})
	})
})
<commit_msg>Improve test coverage for bind security group output<commit_after>package securitygroup_test

import (
	"github.com/cloudfoundry/cli/cf/api/fakes"
	test_org "github.com/cloudfoundry/cli/cf/api/organizations/fakes"
	testapi "github.com/cloudfoundry/cli/cf/api/security_groups/fakes"
	zoidberg "github.com/cloudfoundry/cli/cf/api/security_groups/spaces/fakes"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/errors"
	"github.com/cloudfoundry/cli/cf/models"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/cf/commands/securitygroup"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("bind-security-group command", func() {
	var (
		ui                    *testterm.FakeUI
		cmd                   BindSecurityGroup
		configRepo            core_config.ReadWriter
		fakeSecurityGroupRepo *testapi.FakeSecurityGroupRepo
		requirementsFactory   *testreq.FakeReqFactory
		fakeSpaceRepo         *fakes.FakeSpaceRepository
		fakeOrgRepo           *test_org.FakeOrganizationRepository
		fakeSpaceBinder       *zoidberg.FakeSecurityGroupSpaceBinder
	)

	BeforeEach(func() {
		ui = &testterm.FakeUI{}
		fakeOrgRepo = &test_org.FakeOrganizationRepository{}
		fakeSpaceRepo = &fakes.FakeSpaceRepository{}
		requirementsFactory = &testreq.FakeReqFactory{}
		fakeSecurityGroupRepo = &testapi.FakeSecurityGroupRepo{}
		configRepo = testconfig.NewRepositoryWithDefaults()
		fakeSpaceBinder = &zoidberg.FakeSecurityGroupSpaceBinder{}
		cmd = NewBindSecurityGroup(ui, configRepo, fakeSecurityGroupRepo, fakeSpaceRepo, fakeOrgRepo, fakeSpaceBinder)
	})

	runCommand := func(args ...string) {
		testcmd.RunCommand(cmd, args, requirementsFactory)
	}

	Describe("requirements", func() {
		It("fails when the user is not logged in", func() {
			runCommand("my-craaaaaazy-security-group", "my-org", "my-space")

			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})

		It("succeeds when the user is logged in", func() {
			requirementsFactory.LoginSuccess = true
			runCommand("my-craaaaaazy-security-group", "my-org", "my-space")

			Expect(testcmd.CommandDidPassRequirements).To(BeTrue())
		})

		It("fails with usage when not provided the name of a security group, org, and space", func() {
			requirementsFactory.LoginSuccess = true
			runCommand("one fish", "two fish", "three fish", "purple fish")

			Expect(ui.FailedWithUsage).To(BeTrue())
		})
	})

	Context("when the user is logged in and provides the name of a security group", func() {
		BeforeEach(func() {
			requirementsFactory.LoginSuccess = true
		})

		Context("when a security group with that name does not exist", func() {
			BeforeEach(func() {
				fakeSecurityGroupRepo.ReadReturns(models.SecurityGroup{}, errors.NewModelNotFoundError("security group", "my-nonexistent-security-group"))
			})

			It("fails and tells the user", func() {
				runCommand("my-nonexistent-security-group", "my-org", "my-space")

				Expect(fakeSecurityGroupRepo.ReadArgsForCall(0)).To(Equal("my-nonexistent-security-group"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"security group", "my-nonexistent-security-group", "not found"},
				))
			})
		})

		Context("when the org does not exist", func() {
			BeforeEach(func() {
				fakeOrgRepo.FindByNameReturns(models.Organization{}, errors.New("Org org not found"))
			})

			It("fails and tells the user", func() {
				runCommand("sec group", "org", "space")

				Expect(fakeOrgRepo.FindByNameArgsForCall(0)).To(Equal("org"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"Org", "org", "not found"},
				))
			})
		})

		Context("when the space does not exist", func() {
			BeforeEach(func() {
				org := models.Organization{}
				org.Name = "org-name"
				org.Guid = "org-guid"
				fakeOrgRepo.ListOrgsReturns([]models.Organization{org}, nil)
				fakeOrgRepo.FindByNameReturns(org, nil)
				fakeSpaceRepo.FindByNameInOrgError = errors.NewModelNotFoundError("Space", "space-name")
			})

			It("fails and tells the user", func() {
				runCommand("sec group", "org-name", "space-name")

				Expect(fakeSpaceRepo.FindByNameInOrgName).To(Equal("space-name"))
				Expect(fakeSpaceRepo.FindByNameInOrgOrgGuid).To(Equal("org-guid"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"FAILED"},
					[]string{"Space", "space-name", "not found"},
				))
			})
		})

		Context("everything is hunky dory", func() {
			BeforeEach(func() {
				org := models.Organization{}
				org.Name = "org-name"
				org.Guid = "org-guid"
				fakeOrgRepo.ListOrgsReturns([]models.Organization{org}, nil)

				space := models.Space{}
				space.Name = "space-name"
				space.Guid = "space-guid"
				fakeSpaceRepo.FindByNameInOrgSpace = space

				securityGroup := models.SecurityGroup{}
				securityGroup.Name = "security-group"
				securityGroup.Guid = "security-group-guid"
				fakeSecurityGroupRepo.ReadReturns(securityGroup, nil)
			})

			JustBeforeEach(func() {
				runCommand("security-group", "org-name", "space-name")
			})

			It("assigns the security group to the space", func() {
				secGroupGuid, spaceGuid := fakeSpaceBinder.BindSpaceArgsForCall(0)
				Expect(secGroupGuid).To(Equal("security-group-guid"))
				Expect(spaceGuid).To(Equal("space-guid"))
			})

			It("describes what it is doing for the user's benefit", func() {
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Assigning security group security-group to space space-name in org org-name as my-user"},
					[]string{"OK"},
					[]string{"TIP: Changes will not apply to existing running applications until they are restarted."},
				))
			})
		})
	})
})
<|endoftext|>


<commit_before>/* Mozilla InvestiGator Agent

Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (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.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Initial Developer of the Original Code is
Mozilla Corporation
Portions created by the Initial Developer are Copyright (C) 2014
the Initial Developer. All Rights Reserved.

Contributor(s):
Julien Vehent jvehent@mozilla.com [:ulfr]

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
*/

package main

import (
	"bytes"
	"fmt"
	"mig"
	"os/exec"
	"runtime"
	"strings"
)

func findHostname(orig_ctx Context) (ctx Context, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{Desc: "leaving findHostname()"}.Debug()
	}()

	// get the hostname
	out, err := exec.Command("hostname").Output()
	if err != nil {
		panic(err)
	}
	// remove trailing newline
	ctx.Agent.Hostname = fmt.Sprintf("%s", out[0:len(out)-1])
	return
}

func findOSInfo(orig_ctx Context) (ctx Context, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findOSInfo() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{Desc: "leaving findOSInfo()"}.Debug()
	}()
	ctx.Agent.OS = runtime.GOOS
	ctx.Agent.Env.Arch = runtime.GOARCH
	hostname, domain, osname, osversion, err := getSysInfo()
	if err != nil {
		panic(err)
	}
	ctx.Agent.Hostname = hostname + "." + domain
	ctx.Agent.Env.Ident = osname + " " + osversion
	ctx.Agent.Env.Init = "windows"
	return
}

// getSysInfo call systeminfo and returns the OS version
func getSysInfo() (hostname, domain, osname, osversion string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getSysInfo() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{Desc: "leaving getSysInfo()"}.Debug()
	}()
	// get data from the systeminfo
	out, err := exec.Command("systeminfo").Output()
	if err != nil {
		panic(err)
	}
	buf := bytes.NewBuffer(out)
	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			goto exit
		}
		// chomp
		if line[len(line)-1] == '\n' {
			line = line[0 : len(line)-1]
		}
		if strings.Contains(line, "OS Name:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				osname = out[1]
			}
			osname = cleanString(osname)
		} else if strings.Contains(line, "OS Version:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				osversion = out[1]
			}
			osversion = cleanString(osversion)
		} else if strings.Contains(line, "Domain:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				domain = out[1]
			}
			domain = cleanString(domain)
		} else if strings.Contains(line, "Host Name:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				hostname = out[1]
			}
			hostname = cleanString(hostname)
		}
	}
exit:
	return
}

func getRunDir() string {
	return "%appdata%/mig/"
}
<commit_msg>[minor] agent env_windows stricter systeminfo command<commit_after>/* Mozilla InvestiGator Agent

Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (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.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Initial Developer of the Original Code is
Mozilla Corporation
Portions created by the Initial Developer are Copyright (C) 2014
the Initial Developer. All Rights Reserved.

Contributor(s):
Julien Vehent jvehent@mozilla.com [:ulfr]

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
*/

package main

import (
	"bytes"
	"fmt"
	"mig"
	"os/exec"
	"runtime"
	"strings"
)

func findHostname(orig_ctx Context) (ctx Context, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{Desc: "leaving findHostname()"}.Debug()
	}()

	// get the hostname
	out, err := exec.Command("hostname").Output()
	if err != nil {
		panic(err)
	}
	// remove trailing newline
	ctx.Agent.Hostname = fmt.Sprintf("%s", out[0:len(out)-1])
	return
}

func findOSInfo(orig_ctx Context) (ctx Context, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findOSInfo() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{Desc: "leaving findOSInfo()"}.Debug()
	}()
	ctx.Agent.OS = runtime.GOOS
	ctx.Agent.Env.Arch = runtime.GOARCH
	hostname, domain, osname, osversion, err := getSysInfo()
	if err != nil {
		panic(err)
	}
	ctx.Agent.Hostname = hostname + "." + domain
	ctx.Agent.Env.Ident = osname + " " + osversion
	ctx.Agent.Env.Init = "windows"
	return
}

// getSysInfo call systeminfo and returns the OS version
func getSysInfo() (hostname, domain, osname, osversion string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getSysInfo() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{Desc: "leaving getSysInfo()"}.Debug()
	}()
	// get data from the systeminfo
	out, err := exec.Command("systeminfo.exe", "/FO", "LIST").Output()
	if err != nil {
		panic(err)
	}
	buf := bytes.NewBuffer(out)
	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			goto exit
		}
		// chomp
		if line[len(line)-1] == '\n' {
			line = line[0 : len(line)-1]
		}
		if strings.Contains(line, "OS Name:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				osname = out[1]
			}
			osname = cleanString(osname)
		} else if strings.Contains(line, "OS Version:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				osversion = out[1]
			}
			osversion = cleanString(osversion)
		} else if strings.Contains(line, "Domain:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				domain = out[1]
			}
			domain = cleanString(domain)
		} else if strings.Contains(line, "Host Name:") {
			out := strings.SplitN(line, ":", 2)
			if len(out) == 2 {
				hostname = out[1]
			}
			hostname = cleanString(hostname)
		}
	}
exit:
	return
}

func getRunDir() string {
	return "%appdata%/mig/"
}
<|endoftext|>


<commit_before>// +build windows

package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wav"
	"github.com/moutend/go-wca"
)

var version = "latest"
var revision = "latest"

type FilenameFlag struct {
	Value string
}

func (f *FilenameFlag) Set(value string) (err error) {
	if !strings.HasSuffix(value, ".wav") {
		err = fmt.Errorf("specify WAVE audio file (*.wav)")
		return
	}
	f.Value = value
	return
}

func (f *FilenameFlag) String() string {
	return f.Value
}

func main() {
	var err error
	if err = run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) (err error) {
	var filenameFlag FilenameFlag
	var versionFlag bool
	var audio = &wav.File{}
	var file []byte

	f := flag.NewFlagSet(args[0], flag.ExitOnError)
	f.Var(&filenameFlag, "input", "Specify WAVE format audio (e.g. music.wav)")
	f.Var(&filenameFlag, "i", "Alias of --input")
	f.BoolVar(&versionFlag, "version", false, "Show version")
	f.Parse(args[1:])

	if versionFlag {
		fmt.Printf("%s-%s\n", version, revision)
		return
	}
	if filenameFlag.Value == "" {
		return
	}
	if file, err = ioutil.ReadFile(filenameFlag.Value); err != nil {
		return
	}
	if err = wav.Unmarshal(file, audio); err != nil {
		return
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-signalChan:
			fmt.Println("Interrupted by SIGINT")
			cancel()
		}
		return
	}()

	if err = renderSharedTimerDriven(ctx, audio); err != nil {
		return
	}
	fmt.Println("Successfully done")
	return
}

func renderSharedTimerDriven(ctx context.Context, audio *wav.File) (err error) {
	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		return
	}
	defer ole.CoUninitialize()

	var de *wca.IMMDeviceEnumerator
	if err = wca.CoCreateInstance(wca.CLSID_MMDeviceEnumerator, 0, wca.CLSCTX_ALL, wca.IID_IMMDeviceEnumerator, &de); err != nil {
		return
	}
	defer de.Release()

	var mmd *wca.IMMDevice
	if err = de.GetDefaultAudioEndpoint(wca.ERender, wca.EConsole, &mmd); err != nil {
		return
	}
	defer mmd.Release()

	var ps *wca.IPropertyStore
	if err = mmd.OpenPropertyStore(wca.STGM_READ, &ps); err != nil {
		return
	}
	defer ps.Release()

	var pv wca.PROPVARIANT
	if err = ps.GetValue(&wca.PKEY_Device_FriendlyName, &pv); err != nil {
		return
	}
	fmt.Printf("Rendering audio to: %s\n", pv.String())

	var ac *wca.IAudioClient
	if err = mmd.Activate(wca.IID_IAudioClient, wca.CLSCTX_ALL, nil, &ac); err != nil {
		return
	}
	defer ac.Release()

	var wfx *wca.WAVEFORMATEX
	if err = ac.GetMixFormat(&wfx); err != nil {
		return
	}
	defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(wfx)))

	wfx.WFormatTag = 1
	wfx.NSamplesPerSec = uint32(audio.SamplesPerSec())
	wfx.WBitsPerSample = uint16(audio.BitsPerSample())
	wfx.NChannels = uint16(audio.Channels())
	wfx.NBlockAlign = uint16(audio.BlockAlign())
	wfx.NAvgBytesPerSec = uint32(audio.AvgBytesPerSec())
	wfx.CbSize = 0

	fmt.Println("--------")
	fmt.Printf("Format: PCM %d bit signed integer\n", wfx.WBitsPerSample)
	fmt.Printf("Rate: %d Hz\n", wfx.NSamplesPerSec)
	fmt.Printf("Channels: %d\n", wfx.NChannels)
	fmt.Println("--------")

	var latency time.Duration
	var defaultPeriod wca.REFERENCE_TIME
	var minimumPeriod wca.REFERENCE_TIME
	if err = ac.GetDevicePeriod(&defaultPeriod, &minimumPeriod); err != nil {
		return
	}
	latency = time.Duration(int(minimumPeriod) * 100)
	fmt.Println("Default period: ", defaultPeriod)
	fmt.Println("Minimum period: ", minimumPeriod)
	fmt.Println("Latency: ", latency)

	if err = ac.Initialize(wca.AUDCLNT_SHAREMODE_EXCLUSIVE, 0, minimumPeriod, 0, wfx, nil); err != nil {
		return
	}

	var bufferFrameSize uint32
	if err = ac.GetBufferSize(&bufferFrameSize); err != nil {
		return
	}
	fmt.Printf("Allocated buffer size: %d\n", bufferFrameSize)

	var arc *wca.IAudioRenderClient
	if err = ac.GetService(wca.IID_IAudioRenderClient, &arc); err != nil {
		return
	}
	defer arc.Release()

	if err = ac.Start(); err != nil {
		return
	}

	fmt.Println("Start rendering with exclusive timer driven mode")
	fmt.Println("Press Ctrl-C to quit")

	time.Sleep(latency)

	var input = audio.Bytes()
	var data *byte
	var offset int
	var padding uint32
	var availableFrameSize uint32
	var b *byte
	var isPlaying bool = true

	for {
		if !isPlaying {
			break
		}
		select {
		case <-ctx.Done():
			isPlaying = false
			break
		default:
			if offset >= audio.Length() {
				isPlaying = false
				break
			}
			if err = ac.GetCurrentPadding(&padding); err != nil {
				return
			}
			availableFrameSize = bufferFrameSize - padding
			if availableFrameSize == 0 {
				continue
			}
			if err = arc.GetBuffer(availableFrameSize, &data); err != nil {
				return
			}

			start := unsafe.Pointer(data)
			lim := int(availableFrameSize) * int(wfx.NBlockAlign)
			remaining := audio.Length() - offset
			if remaining < lim {
				lim = remaining
			}
			for n := 0; n < lim; n++ {
				b = (*byte)(unsafe.Pointer(uintptr(start) + uintptr(n)))
				*b = input[offset+n]
			}
			offset += lim
			if err = arc.ReleaseBuffer(availableFrameSize, 0); err != nil {
				return
			}
			time.Sleep(latency)
		}
	}
	return ac.Stop()
}
<commit_msg>Refactor<commit_after>// +build windows

package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wav"
	"github.com/moutend/go-wca"
)

var version = "latest"
var revision = "latest"

type FilenameFlag struct {
	Value string
}

func (f *FilenameFlag) Set(value string) (err error) {
	if !strings.HasSuffix(value, ".wav") {
		err = fmt.Errorf("specify WAVE audio file (*.wav)")
		return
	}
	f.Value = value
	return
}

func (f *FilenameFlag) String() string {
	return f.Value
}

func main() {
	var err error
	if err = run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) (err error) {
	var filenameFlag FilenameFlag
	var versionFlag bool
	var audio = &wav.File{}
	var file []byte

	f := flag.NewFlagSet(args[0], flag.ExitOnError)
	f.Var(&filenameFlag, "input", "Specify WAVE format audio (e.g. music.wav)")
	f.Var(&filenameFlag, "i", "Alias of --input")
	f.BoolVar(&versionFlag, "version", false, "Show version")
	f.Parse(args[1:])

	if versionFlag {
		fmt.Printf("%s-%s\n", version, revision)
		return
	}
	if filenameFlag.Value == "" {
		return
	}
	if file, err = ioutil.ReadFile(filenameFlag.Value); err != nil {
		return
	}
	if err = wav.Unmarshal(file, audio); err != nil {
		return
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-signalChan:
			fmt.Println("Interrupted by SIGINT")
			cancel()
		}
		return
	}()

	if err = renderSharedTimerDriven(ctx, audio); err != nil {
		return
	}
	fmt.Println("Successfully done")
	return
}

func renderSharedTimerDriven(ctx context.Context, audio *wav.File) (err error) {
	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		return
	}
	defer ole.CoUninitialize()

	var de *wca.IMMDeviceEnumerator
	if err = wca.CoCreateInstance(wca.CLSID_MMDeviceEnumerator, 0, wca.CLSCTX_ALL, wca.IID_IMMDeviceEnumerator, &de); err != nil {
		return
	}
	defer de.Release()

	var mmd *wca.IMMDevice
	if err = de.GetDefaultAudioEndpoint(wca.ERender, wca.EConsole, &mmd); err != nil {
		return
	}
	defer mmd.Release()

	var ps *wca.IPropertyStore
	if err = mmd.OpenPropertyStore(wca.STGM_READ, &ps); err != nil {
		return
	}
	defer ps.Release()

	var pv wca.PROPVARIANT
	if err = ps.GetValue(&wca.PKEY_Device_FriendlyName, &pv); err != nil {
		return
	}
	fmt.Printf("Rendering audio to: %s\n", pv.String())

	var ac *wca.IAudioClient
	if err = mmd.Activate(wca.IID_IAudioClient, wca.CLSCTX_ALL, nil, &ac); err != nil {
		return
	}
	defer ac.Release()

	var wfx *wca.WAVEFORMATEX
	if err = ac.GetMixFormat(&wfx); err != nil {
		return
	}
	defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(wfx)))

	wfx.WFormatTag = 1
	wfx.NSamplesPerSec = uint32(audio.SamplesPerSec())
	wfx.WBitsPerSample = uint16(audio.BitsPerSample())
	wfx.NChannels = uint16(audio.Channels())
	wfx.NBlockAlign = uint16(audio.BlockAlign())
	wfx.NAvgBytesPerSec = uint32(audio.AvgBytesPerSec())
	wfx.CbSize = 0

	fmt.Println("--------")
	fmt.Printf("Format: PCM %d bit signed integer\n", wfx.WBitsPerSample)
	fmt.Printf("Rate: %d Hz\n", wfx.NSamplesPerSec)
	fmt.Printf("Channels: %d\n", wfx.NChannels)
	fmt.Println("--------")

	var defaultPeriod wca.REFERENCE_TIME
	var minimumPeriod wca.REFERENCE_TIME
	var latency time.Duration
	if err = ac.GetDevicePeriod(&defaultPeriod, &minimumPeriod); err != nil {
		return
	}
	latency = time.Duration(int(minimumPeriod) * 100)

	fmt.Println("Default period: ", defaultPeriod)
	fmt.Println("Minimum period: ", minimumPeriod)
	fmt.Println("Latency: ", latency)

	if err = ac.Initialize(wca.AUDCLNT_SHAREMODE_EXCLUSIVE, 0, minimumPeriod, 0, wfx, nil); err != nil {
		return
	}

	var bufferFrameSize uint32
	if err = ac.GetBufferSize(&bufferFrameSize); err != nil {
		return
	}
	fmt.Printf("Allocated buffer size: %d\n", bufferFrameSize)

	var arc *wca.IAudioRenderClient
	if err = ac.GetService(wca.IID_IAudioRenderClient, &arc); err != nil {
		return
	}
	defer arc.Release()

	if err = ac.Start(); err != nil {
		return
	}

	fmt.Println("Start rendering with exclusive timer driven mode")
	fmt.Println("Press Ctrl-C to quit")

	var input = audio.Bytes()
	var data *byte
	var offset int
	var padding uint32
	var availableFrameSize uint32
	var b *byte
	var isPlaying bool = true

	for {
		if !isPlaying {
			break
		}
		select {
		case <-ctx.Done():
			isPlaying = false
			break
		default:
			if offset >= audio.Length() {
				isPlaying = false
				break
			}
			if err = ac.GetCurrentPadding(&padding); err != nil {
				return
			}
			availableFrameSize = bufferFrameSize - padding
			if availableFrameSize == 0 {
				continue
			}
			if err = arc.GetBuffer(availableFrameSize, &data); err != nil {
				return
			}

			start := unsafe.Pointer(data)
			lim := int(availableFrameSize) * int(wfx.NBlockAlign)
			remaining := audio.Length() - offset
			if remaining < lim {
				lim = remaining
			}
			for n := 0; n < lim; n++ {
				b = (*byte)(unsafe.Pointer(uintptr(start) + uintptr(n)))
				*b = input[offset+n]
			}
			offset += lim
			if err = arc.ReleaseBuffer(availableFrameSize, 0); err != nil {
				return
			}
			time.Sleep(latency)
		}
	}

	// Render samples remaining in buffer.
	time.Sleep(latency)

	return ac.Stop()
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"log"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/hashicorp/packer/template/interpolate"
)

// AccessConfig is for common configuration related to AWS access
type AccessConfig struct {
	AccessKey         string `mapstructure:"access_key"`
	CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
	MFACode           string `mapstructure:"mfa_code"`
	ProfileName       string `mapstructure:"profile"`
	RawRegion         string `mapstructure:"region"`
	SecretKey         string `mapstructure:"secret_key"`
	SkipValidation    bool   `mapstructure:"skip_region_validation"`
	Token             string `mapstructure:"token"`
	session           *session.Session
}

// Config returns a valid aws.Config object for access to AWS services, or
// an error if the authentication and region couldn't be resolved
func (c *AccessConfig) Session() (*session.Session, error) {
	if c.session != nil {
		return c.session, nil
	}

	region, err := c.Region()
	if err != nil {
		return nil, err
	}

	if c.ProfileName != "" {
		if err := os.Setenv("AWS_PROFILE", c.ProfileName); err != nil {
			log.Printf("Set env error: %s", err)
		}
	}

	config := aws.NewConfig().WithRegion(region).WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)

	if c.CustomEndpointEc2 != "" {
		config = config.WithEndpoint(c.CustomEndpointEc2)
	}

	if c.AccessKey != "" {
		creds := credentials.NewChainCredentials(
			[]credentials.Provider{
				&credentials.StaticProvider{
					Value: credentials.Value{
						AccessKeyID:     c.AccessKey,
						SecretAccessKey: c.SecretKey,
						SessionToken:    c.Token,
					},
				},
			})
		config = config.WithCredentials(creds)
	}

	opts := session.Options{
		SharedConfigState: session.SharedConfigEnable,
		Config:            *config,
	}
	if c.MFACode != "" {
		opts.AssumeRoleTokenProvider = func() (string, error) {
			return c.MFACode, nil
		}
	}
	c.session, err = session.NewSessionWithOptions(opts)
	if err != nil {
		return nil, err
	}

	return c.session, nil
}

// Region returns the aws.Region object for access to AWS services, requesting
// the region from the instance metadata if possible.
func (c *AccessConfig) Region() (string, error) {
	if c.RawRegion != "" {
		if !c.SkipValidation {
			if valid := ValidateRegion(c.RawRegion); !valid {
				return "", fmt.Errorf("Not a valid region: %s", c.RawRegion)
			}
		}
		return c.RawRegion, nil
	}

	sess := session.New()
	ec2meta := ec2metadata.New(sess)
	identity, err := ec2meta.GetInstanceIdentityDocument()
	if err != nil {
		return "", err
	}
	return identity.Region, nil
}

func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
	var errs []error
	if c.RawRegion != "" && !c.SkipValidation {
		if valid := ValidateRegion(c.RawRegion); !valid {
			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
		}
	}

	if len(errs) > 0 {
		return errs
	}

	return nil
}
<commit_msg>we don't need to look for region in metadata.<commit_after>package common

import (
	"fmt"
	"log"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/hashicorp/packer/template/interpolate"
)

// AccessConfig is for common configuration related to AWS access
type AccessConfig struct {
	AccessKey         string `mapstructure:"access_key"`
	CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
	MFACode           string `mapstructure:"mfa_code"`
	ProfileName       string `mapstructure:"profile"`
	RawRegion         string `mapstructure:"region"`
	SecretKey         string `mapstructure:"secret_key"`
	SkipValidation    bool   `mapstructure:"skip_region_validation"`
	Token             string `mapstructure:"token"`
	session           *session.Session
}

// Config returns a valid aws.Config object for access to AWS services, or
// an error if the authentication and region couldn't be resolved
func (c *AccessConfig) Session() (*session.Session, error) {
	if c.session != nil {
		return c.session, nil
	}

	region, err := c.Region()
	if err != nil {
		return nil, err
	}

	if c.ProfileName != "" {
		if err := os.Setenv("AWS_PROFILE", c.ProfileName); err != nil {
			log.Printf("Set env error: %s", err)
		}
	}

	config := aws.NewConfig().WithRegion(region).WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)

	if c.CustomEndpointEc2 != "" {
		config = config.WithEndpoint(c.CustomEndpointEc2)
	}

	if c.AccessKey != "" {
		creds := credentials.NewChainCredentials(
			[]credentials.Provider{
				&credentials.StaticProvider{
					Value: credentials.Value{
						AccessKeyID:     c.AccessKey,
						SecretAccessKey: c.SecretKey,
						SessionToken:    c.Token,
					},
				},
			})
		config = config.WithCredentials(creds)
	}

	opts := session.Options{
		SharedConfigState: session.SharedConfigEnable,
		Config:            *config,
	}
	if c.MFACode != "" {
		opts.AssumeRoleTokenProvider = func() (string, error) {
			return c.MFACode, nil
		}
	}
	c.session, err = session.NewSessionWithOptions(opts)
	if err != nil {
		return nil, err
	}

	return c.session, nil
}

// Region returns the aws.Region object for access to AWS services, requesting
// the region from the instance metadata if possible.
func (c *AccessConfig) Region() (string, error) {
	if c.RawRegion != "" {
		if !c.SkipValidation {
			if valid := ValidateRegion(c.RawRegion); !valid {
				return "", fmt.Errorf("Not a valid region: %s", c.RawRegion)
			}
		}
		return c.RawRegion, nil
	}

	return "", nil
}

func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
	var errs []error
	if c.RawRegion != "" && !c.SkipValidation {
		if valid := ValidateRegion(c.RawRegion); !valid {
			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
		}
	}

	if len(errs) > 0 {
		return errs
	}

	return nil
}
<|endoftext|>