<commit_before>package shells

import (
	"bufio"
	"bytes"
	"fmt"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"io"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

type BashShell struct {
	AbstractShell
}

func (b *BashShell) GetName() string {
	return "bash"
}

func (b *BashShell) GetFeatures(features *common.FeaturesInfo) {
	features.Artifacts = true
	features.Cache = true
}

func (b *BashShell) executeCommand(w io.Writer, cmd string, arguments ...string) {
	list := []string{
		helpers.ShellEscape(cmd),
	}

	for _, argument := range arguments {
		list = append(list, strconv.Quote(argument))
	}

	io.WriteString(w, strings.Join(list, " ")+"\n")
}

func (b *BashShell) executeCommandFormat(w io.Writer, format string, arguments ...interface{}) {
	io.WriteString(w, fmt.Sprintf(format+"\n", arguments...))
}

func (b *BashShell) echoColored(w io.Writer, text string) {
	coloredText := helpers.ANSI_BOLD_GREEN + text + helpers.ANSI_RESET
	b.executeCommandFormat(w, "echo %s", helpers.ShellEscape(coloredText))
}

func (b *BashShell) echoWarning(w io.Writer, text string) {
	coloredText := helpers.ANSI_BOLD_YELLOW + text + helpers.ANSI_RESET
	b.executeCommandFormat(w, "echo %s", helpers.ShellEscape(coloredText))
}

func (b *BashShell) echoColoredFormat(w io.Writer, format string, a ...interface{}) {
	b.echoColored(w, fmt.Sprintf(format, a...))
}

func (b *BashShell) writeIfDirectory(w io.Writer, directory string) {
	b.executeCommandFormat(w, "if [[ -d %q ]]; then", directory)
}

func (b *BashShell) writeIfFile(w io.Writer, directory string) {
	b.executeCommandFormat(w, "if [[ -e %q ]]; then", directory)
}

func (b *BashShell) writeElse(w io.Writer) {
	b.executeCommandFormat(w, "else")
}

func (b *BashShell) writeEndIf(w io.Writer) {
	b.executeCommandFormat(w, "fi")
}

func (b *BashShell) writeCloneCmd(w io.Writer, build *common.Build, projectDir string) {
	b.echoColoredFormat(w, "Cloning repository...")
	b.executeCommand(w, "rm", "-rf", projectDir)
	b.executeCommand(w, "mkdir", "-p", projectDir)
	b.executeCommand(w, "git", "clone", build.RepoURL, projectDir)
	b.executeCommand(w, "cd", projectDir)
}

func (b *BashShell) writeFetchCmd(w io.Writer, build *common.Build, projectDir string, gitDir string) {
	b.writeIfDirectory(w, gitDir)
	b.echoColoredFormat(w, "Fetching changes...")
	b.executeCommand(w, "cd", projectDir)
	b.executeCommand(w, "git", "clean", "-ffdx")
	b.executeCommand(w, "git", "reset", "--hard")
	b.executeCommand(w, "git", "remote", "set-url", "origin", build.RepoURL)
	b.executeCommand(w, "git", "fetch", "origin")
	b.writeElse(w)
	b.writeCloneCmd(w, build, projectDir)
	b.writeEndIf(w)
}

func (b *BashShell) writeCheckoutCmd(w io.Writer, build *common.Build) {
	b.echoColoredFormat(w, "Checking out %s as %s...", build.Sha[0:8], build.RefName)
	b.executeCommand(w, "git", "checkout", build.Sha)
}

func (b *BashShell) writeCdBuildDir(w io.Writer, info common.ShellScriptInfo) {
	b.executeCommand(w, "cd", b.fullProjectDir(info))
}

func (b *BashShell) writeExport(w io.Writer, variable common.BuildVariable) {
	b.executeCommandFormat(w, "export %s=%s", helpers.ShellEscape(variable.Key), helpers.ShellEscape(variable.Value))
}

func (b *BashShell) fullProjectDir(info common.ShellScriptInfo) string {
	projectDir := info.Build.FullProjectDir()
	return helpers.ToSlash(projectDir)
}

func (b *BashShell) writeExports(w io.Writer, info common.ShellScriptInfo) {
	for _, variable := range info.Build.GetAllVariables() {
		b.writeExport(w, variable)
	}
}

func (b *BashShell) generatePreBuildScript(info common.ShellScriptInfo) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	b.writeExports(w, info)

	if len(info.Build.Hostname) != 0 {
		b.executeCommandFormat(w, "echo %q", "Running on $(hostname) via "+info.Build.Hostname+"...")
	} else {
		b.executeCommandFormat(w, "echo %q", "Running on $(hostname)...")
	}

	build := info.Build
	projectDir := b.fullProjectDir(info)
	gitDir := filepath.Join(projectDir, ".git")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir, gitDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)

	cacheFile := info.Build.CacheFile()
	cacheFile2 := info.Build.CacheFileForRef("master")
	if cacheFile == "" {
		cacheFile = cacheFile2
		cacheFile2 = ""
	}

	// Try to restore from main cache, if not found cache for master
	if cacheFile != "" {
		// If we have cache, restore it
		b.writeIfFile(w, cacheFile)
		b.echoColored(w, "Restoring cache...")
		b.executeCommand(w, "tar", "-zxf", cacheFile)
		if cacheFile2 != "" {
			b.writeElse(w)

			// If we have cache, restore it
			b.writeIfFile(w, cacheFile2)
			b.echoColored(w, "Restoring cache...")
			b.executeCommand(w, "tar", "-zxf", cacheFile2)
			b.writeEndIf(w)
		}
		b.writeEndIf(w)
	}

	w.Flush()

	return b.finalize(buffer.String())
}

func (b *BashShell) generateCommands(info common.ShellScriptInfo) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	commands := info.Build.Commands
	commands = strings.TrimSpace(commands)
	for _, command := range strings.Split(commands, "\n") {
		command = strings.TrimSpace(command)
		if !helpers.BoolOrDefault(info.Build.Runner.DisableVerbose, false) {
			if command != "" {
				b.echoColored(w, "$ "+command)
			} else {
				b.executeCommand(w, "echo")
			}
		}
		io.WriteString(w, command+"\n")
	}

	w.Flush()

	return b.finalize(buffer.String())
}

func (b *BashShell) archiveFiles(w io.Writer, list interface{}, runnerCommand, archiveType, archivePath string) {
	hash, ok := list.(map[string]interface{})
	if !ok {
		return
	}

	args := []string{
		"archive",
		"--silent",
		"--output",
		archivePath,
	}

	// Collect paths
	if paths, ok := hash["paths"].([]interface{}); ok {
		for _, artifactPath := range paths {
			if file, ok := artifactPath.(string); ok {
				args = append(args, "--path", file)
			}
		}
	}

	// Archive also untracked files
	if untracked, ok := hash["untracked"].(bool); ok && untracked {
		args = append(args, "--untracked")
	}

	// Skip creating archive
	if len(args) <= 3 {
		return
	}

	// Execute archive command
	b.echoColoredFormat(w, "Archiving %s...", archiveType)
	if runnerCommand == "" {
		runnerCommand = "gitlab-runner"
	}
	b.executeCommand(w, runnerCommand, args...)
}

func (b *BashShell) generatePostBuildScript(info common.ShellScriptInfo) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	// Find cached files and archive them
	if cacheFile := info.Build.CacheFile(); cacheFile != "" {
		b.archiveFiles(w, info.Build.Options["cache"], info.RunnerCommand, "cache", cacheFile)
	}

	// Find artifacts
	b.archiveFiles(w, info.Build.Options["artifacts"], info.RunnerCommand, "artifacts", "artifacts.tgz")

	// If archive is created upload it
	b.writeIfFile(w, "artifacts.tgz")
	b.echoColored(w, "Uploading artifacts...")
	b.executeCommand(w, "du", "-h", "artifacts.tgz")
	b.executeCommand(w, "curl", "-s", "-S", "--fail", "--retry", "3", "-X", "POST",
		"-#",
		"-o", "artifacts.upload.log",
		"-H", "BUILD-TOKEN: "+info.Build.Token,
		"-F", "file=@artifacts.tgz",
		info.Build.Network.GetArtifactsUploadURL(info.Build.Runner.RunnerCredentials, info.Build.ID))
	b.executeCommand(w, "rm", "-f", "artifacts.tgz")
	b.writeEndIf(w)

	w.Flush()

	return b.finalize(buffer.String())
}

func (b *BashShell) finalize(script string) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)
	io.WriteString(w, "#!/usr/bin/env bash\n\n")
	io.WriteString(w, "set -eo pipefail\n")
	io.WriteString(w, ": | eval "+helpers.ShellEscape(script)+"\n")
	w.Flush()
	return buffer.String()
}

func (b *BashShell) GenerateScript(info common.ShellScriptInfo) (*common.ShellScript, error) {
	script := common.ShellScript{
		PreScript:   b.generatePreBuildScript(info),
		BuildScript: b.generateCommands(info),
		PostScript:  b.generatePostBuildScript(info),
		Environment: b.GetVariables(info),
	}

	// su
	if info.User != nil {
		script.Command = "su"
		if info.Type == common.LoginShell {
			script.Arguments = []string{"--shell", "/bin/bash", "--login", *info.User}
		} else {
			script.Arguments = []string{"--shell", "/bin/bash", *info.User}
		}
	} else {
		script.Command = "bash"
		if info.Type == common.LoginShell {
			script.Arguments = []string{"--login"}
		}
	}

	return &script, nil
}

func (b *BashShell) IsDefault() bool {
	return runtime.GOOS != "windows"
}

func init() {
	common.RegisterShell(&BashShell{
		AbstractShell: AbstractShell{
			SupportedOptions: []string{"artifacts", "cache"},
		},
	})
}
<commit_msg>tweak: Switch to using runner for cache decompression<commit_after>package shells

import (
	"bufio"
	"bytes"
	"fmt"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"io"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

type BashShell struct {
	AbstractShell
}

func (b *BashShell) GetName() string {
	return "bash"
}

func (b *BashShell) GetFeatures(features *common.FeaturesInfo) {
	features.Artifacts = true
	features.Cache = true
}

func (b *BashShell) executeCommand(w io.Writer, cmd string, arguments ...string) {
	list := []string{
		helpers.ShellEscape(cmd),
	}

	for _, argument := range arguments {
		list = append(list, strconv.Quote(argument))
	}

	io.WriteString(w, strings.Join(list, " ")+"\n")
}

func (b *BashShell) executeCommandFormat(w io.Writer, format string, arguments ...interface{}) {
	io.WriteString(w, fmt.Sprintf(format+"\n", arguments...))
}

func (b *BashShell) echoColored(w io.Writer, text string) {
	coloredText := helpers.ANSI_BOLD_GREEN + text + helpers.ANSI_RESET
	b.executeCommandFormat(w, "echo %s", helpers.ShellEscape(coloredText))
}

func (b *BashShell) echoWarning(w io.Writer, text string) {
	coloredText := helpers.ANSI_BOLD_YELLOW + text + helpers.ANSI_RESET
	b.executeCommandFormat(w, "echo %s", helpers.ShellEscape(coloredText))
}

func (b *BashShell) echoColoredFormat(w io.Writer, format string, a ...interface{}) {
	b.echoColored(w, fmt.Sprintf(format, a...))
}

func (b *BashShell) writeIfDirectory(w io.Writer, directory string) {
	b.executeCommandFormat(w, "if [[ -d %q ]]; then", directory)
}

func (b *BashShell) writeIfFile(w io.Writer, directory string) {
	b.executeCommandFormat(w, "if [[ -e %q ]]; then", directory)
}

func (b *BashShell) writeElse(w io.Writer) {
	b.executeCommandFormat(w, "else")
}

func (b *BashShell) writeEndIf(w io.Writer) {
	b.executeCommandFormat(w, "fi")
}

func (b *BashShell) writeCloneCmd(w io.Writer, build *common.Build, projectDir string) {
	b.echoColoredFormat(w, "Cloning repository...")
	b.executeCommand(w, "rm", "-rf", projectDir)
	b.executeCommand(w, "mkdir", "-p", projectDir)
	b.executeCommand(w, "git", "clone", build.RepoURL, projectDir)
	b.executeCommand(w, "cd", projectDir)
}

func (b *BashShell) writeFetchCmd(w io.Writer, build *common.Build, projectDir string, gitDir string) {
	b.writeIfDirectory(w, gitDir)
	b.echoColoredFormat(w, "Fetching changes...")
	b.executeCommand(w, "cd", projectDir)
	b.executeCommand(w, "git", "clean", "-ffdx")
	b.executeCommand(w, "git", "reset", "--hard")
	b.executeCommand(w, "git", "remote", "set-url", "origin", build.RepoURL)
	b.executeCommand(w, "git", "fetch", "origin")
	b.writeElse(w)
	b.writeCloneCmd(w, build, projectDir)
	b.writeEndIf(w)
}

func (b *BashShell) writeCheckoutCmd(w io.Writer, build *common.Build) {
	b.echoColoredFormat(w, "Checking out %s as %s...", build.Sha[0:8], build.RefName)
	b.executeCommand(w, "git", "checkout", build.Sha)
}

func (b *BashShell) writeCdBuildDir(w io.Writer, info common.ShellScriptInfo) {
	b.executeCommand(w, "cd", b.fullProjectDir(info))
}

func (b *BashShell) writeExport(w io.Writer, variable common.BuildVariable) {
	b.executeCommandFormat(w, "export %s=%s", helpers.ShellEscape(variable.Key), helpers.ShellEscape(variable.Value))
}

func (b *BashShell) fullProjectDir(info common.ShellScriptInfo) string {
	projectDir := info.Build.FullProjectDir()
	return helpers.ToSlash(projectDir)
}

func (b *BashShell) writeExports(w io.Writer, info common.ShellScriptInfo) {
	for _, variable := range info.Build.GetAllVariables() {
		b.writeExport(w, variable)
	}
}

func (b *BashShell) generatePreBuildScript(info common.ShellScriptInfo) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	b.writeExports(w, info)

	if len(info.Build.Hostname) != 0 {
		b.executeCommandFormat(w, "echo %q", "Running on $(hostname) via "+info.Build.Hostname+"...")
	} else {
		b.executeCommandFormat(w, "echo %q", "Running on $(hostname)...")
	}

	build := info.Build
	projectDir := b.fullProjectDir(info)
	gitDir := filepath.Join(projectDir, ".git")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir, gitDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)

	cacheFile := info.Build.CacheFile()
	cacheFile2 := info.Build.CacheFileForRef("master")
	if cacheFile == "" {
		cacheFile = cacheFile2
		cacheFile2 = ""
	}

	// Try to restore from main cache, if not found cache for master
	if cacheFile != "" {
		// If we have cache, restore it
		b.writeIfFile(w, cacheFile)
		b.echoColored(w, "Restoring cache...")
		b.extractFiles(w, info.RunnerCommand, "cache", cacheFile)
		if cacheFile2 != "" {
			b.writeElse(w)

			// If we have cache, restore it
			b.writeIfFile(w, cacheFile2)
			b.echoColored(w, "Restoring cache...")
			b.extractFiles(w, info.RunnerCommand, "cache", cacheFile2)
			b.writeEndIf(w)
		}
		b.writeEndIf(w)
	}

	w.Flush()

	return b.finalize(buffer.String())
}

func (b *BashShell) generateCommands(info common.ShellScriptInfo) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	commands := info.Build.Commands
	commands = strings.TrimSpace(commands)
	for _, command := range strings.Split(commands, "\n") {
		command = strings.TrimSpace(command)
		if !helpers.BoolOrDefault(info.Build.Runner.DisableVerbose, false) {
			if command != "" {
				b.echoColored(w, "$ "+command)
			} else {
				b.executeCommand(w, "echo")
			}
		}
		io.WriteString(w, command+"\n")
	}

	w.Flush()

	return b.finalize(buffer.String())
}

func (b *BashShell) extractFiles(w io.Writer, runnerCommand, archiveType, archivePath string) {
	args := []string{
		"extract",
		"--silent",
		"--input",
		archivePath,
	}

	// Execute extract command
	b.echoColoredFormat(w, "Extracting %s...", archiveType)
	if runnerCommand == "" {
		runnerCommand = "gitlab-runner"
	}
	b.executeCommand(w, runnerCommand, args...)
}

func (b *BashShell) archiveFiles(w io.Writer, list interface{}, runnerCommand, archiveType, archivePath string) {
	hash, ok := list.(map[string]interface{})
	if !ok {
		return
	}

	args := []string{
		"archive",
		"--silent",
		"--output",
		archivePath,
	}

	// Collect paths
	if paths, ok := hash["paths"].([]interface{}); ok {
		for _, artifactPath := range paths {
			if file, ok := artifactPath.(string); ok {
				args = append(args, "--path", file)
			}
		}
	}

	// Archive also untracked files
	if untracked, ok := hash["untracked"].(bool); ok && untracked {
		args = append(args, "--untracked")
	}

	// Skip creating archive
	if len(args) <= 3 {
		return
	}

	// Execute archive command
	b.echoColoredFormat(w, "Archiving %s...", archiveType)
	if runnerCommand == "" {
		runnerCommand = "gitlab-runner"
	}
	b.executeCommand(w, runnerCommand, args...)
}

func (b *BashShell) generatePostBuildScript(info common.ShellScriptInfo) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	b.writeExports(w, info)
	b.writeCdBuildDir(w, info)

	// Find cached files and archive them
	if cacheFile := info.Build.CacheFile(); cacheFile != "" {
		b.archiveFiles(w, info.Build.Options["cache"], info.RunnerCommand, "cache", cacheFile)
	}

	// Find artifacts
	b.archiveFiles(w, info.Build.Options["artifacts"], info.RunnerCommand, "artifacts", "artifacts.tgz")

	// If archive is created upload it
	b.writeIfFile(w, "artifacts.tgz")
	b.echoColored(w, "Uploading artifacts...")
	b.executeCommand(w, "du", "-h", "artifacts.tgz")
	b.executeCommand(w, "curl", "-s", "-S", "--fail", "--retry", "3", "-X", "POST",
		"-#",
		"-o", "artifacts.upload.log",
		"-H", "BUILD-TOKEN: "+info.Build.Token,
		"-F", "file=@artifacts.tgz",
		info.Build.Network.GetArtifactsUploadURL(info.Build.Runner.RunnerCredentials, info.Build.ID))
	b.executeCommand(w, "rm", "-f", "artifacts.tgz")
	b.writeEndIf(w)

	w.Flush()

	return b.finalize(buffer.String())
}

func (b *BashShell) finalize(script string) string {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)
	io.WriteString(w, "#!/usr/bin/env bash\n\n")
	io.WriteString(w, "set -eo pipefail\n")
	io.WriteString(w, ": | eval "+helpers.ShellEscape(script)+"\n")
	w.Flush()
	return buffer.String()
}

func (b *BashShell) GenerateScript(info common.ShellScriptInfo) (*common.ShellScript, error) {
	script := common.ShellScript{
		PreScript:   b.generatePreBuildScript(info),
		BuildScript: b.generateCommands(info),
		PostScript:  b.generatePostBuildScript(info),
		Environment: b.GetVariables(info),
	}

	// su
	if info.User != nil {
		script.Command = "su"
		if info.Type == common.LoginShell {
			script.Arguments = []string{"--shell", "/bin/bash", "--login", *info.User}
		} else {
			script.Arguments = []string{"--shell", "/bin/bash", *info.User}
		}
	} else {
		script.Command = "bash"
		if info.Type == common.LoginShell {
			script.Arguments = []string{"--login"}
		}
	}

	return &script, nil
}

func (b *BashShell) IsDefault() bool {
	return runtime.GOOS != "windows"
}

func init() {
	common.RegisterShell(&BashShell{
		AbstractShell: AbstractShell{
			SupportedOptions: []string{"artifacts", "cache"},
		},
	})
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rsa"
	"crypto/tls"
	"github.com/realglobe-Inc/edo/driver"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"time"
)

type system struct {
	priKeyCont driver.KeyValueStore

	taId     string
	hashName string // 署名に使うハッシュ関数。

	sessCont   driver.TimeLimitedKeyValueStore
	sessMargin time.Duration // 有効期限ギリギリのセッションを避けるための遊び。

	cliCont    driver.TimeLimitedKeyValueStore
	cliExpiDur time.Duration

	threSize int // セッションを事前に検査するボディサイズの下限。

	noVerify bool // SSL 証明書を検証するか。
}

func newSystem(priKeyCont driver.KeyValueStore, taId string, hashName string, sessMargin, cliExpiDur time.Duration, threSize int, noVerify bool) *system {
	return &system{
		priKeyCont: priKeyCont,
		taId:       taId,
		hashName:   hashName,
		sessCont:   driver.NewMemoryTimeLimitedKeyValueStore(0),
		sessMargin: sessMargin,
		cliCont:    driver.NewMemoryTimeLimitedKeyValueStore(0),
		cliExpiDur: cliExpiDur,
		threSize:   threSize,
		noVerify:   noVerify,
	}
}

type session struct {
	id   string
	host string
	taId string
}

func (sys *system) session(uri, taId string, caStmp *driver.Stamp) (sess *session, newCaStmp *driver.Stamp, err error) {
	value, newCaStmp, err := sys.sessCont.Get(uri+"<>"+taId, caStmp)
	if err != nil {
		return nil, nil, erro.Wrap(err)
	} else if value == nil {
		return nil, newCaStmp, nil
	}
	return value.(*session), newCaStmp, nil
}

func (sys *system) addSession(sess *session, expiDate time.Time) (newCaStmp *driver.Stamp, err error) {
	return sys.sessCont.Put(sess.host+"<>"+sess.taId, sess, expiDate)
}

func (sys *system) removeSession(sess *session) (err error) {
	return sys.sessCont.Remove(sess.host + "<>" + sess.taId)
}

func (sys *system) privateKey(taId string, caStmp *driver.Stamp) (priKey *rsa.PrivateKey, newCaStmp *driver.Stamp, err error) {
	value, newCaStmp, err := sys.priKeyCont.Get(taId, caStmp)
	if err != nil {
		return nil, nil, erro.Wrap(err)
	} else if value == nil {
		return nil, newCaStmp, nil
	}

	return value.(*rsa.PrivateKey), newCaStmp, nil
}

var noVerifyTr = &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
}

func (sys *system) client(host string) (cli *http.Client, err error) {
	value, _, err := sys.cliCont.Get(host, nil)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	if value == nil {
		if sys.noVerify {
			cli = &http.Client{Transport: noVerifyTr}
		} else {
			cli = &http.Client{}
		}
	} else {
		cli = value.(*http.Client)
	}
	// 有効期限の更新。
	if _, err = sys.cliCont.Put(host, cli, time.Now().Add(sys.cliExpiDur)); err != nil {
		return nil, erro.Wrap(err)
	}
	return cli, nil
}
<commit_msg>真偽値が逆だったので修正<commit_after>package main

import (
	"crypto/rsa"
	"crypto/tls"
	"github.com/realglobe-Inc/edo/driver"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"time"
)

type system struct {
	priKeyCont driver.KeyValueStore

	taId     string
	hashName string // 署名に使うハッシュ関数。

	sessCont   driver.TimeLimitedKeyValueStore
	sessMargin time.Duration // 有効期限ギリギリのセッションを避けるための遊び。

	cliCont    driver.TimeLimitedKeyValueStore
	cliExpiDur time.Duration

	threSize int // セッションを事前に検査するボディサイズの下限。

	noVerify bool // SSL 証明書を検証するか。
}

func newSystem(priKeyCont driver.KeyValueStore, taId string, hashName string, sessMargin, cliExpiDur time.Duration, threSize int, noVerify bool) *system {
	return &system{
		priKeyCont: priKeyCont,
		taId:       taId,
		hashName:   hashName,
		sessCont:   driver.NewMemoryTimeLimitedKeyValueStore(0),
		sessMargin: sessMargin,
		cliCont:    driver.NewMemoryTimeLimitedKeyValueStore(0),
		cliExpiDur: cliExpiDur,
		threSize:   threSize,
		noVerify:   noVerify,
	}
}

type session struct {
	id   string
	host string
	taId string
}

func (sys *system) session(uri, taId string, caStmp *driver.Stamp) (sess *session, newCaStmp *driver.Stamp, err error) {
	value, newCaStmp, err := sys.sessCont.Get(uri+"<>"+taId, caStmp)
	if err != nil {
		return nil, nil, erro.Wrap(err)
	} else if value == nil {
		return nil, newCaStmp, nil
	}
	return value.(*session), newCaStmp, nil
}

func (sys *system) addSession(sess *session, expiDate time.Time) (newCaStmp *driver.Stamp, err error) {
	return sys.sessCont.Put(sess.host+"<>"+sess.taId, sess, expiDate)
}

func (sys *system) removeSession(sess *session) (err error) {
	return sys.sessCont.Remove(sess.host + "<>" + sess.taId)
}

func (sys *system) privateKey(taId string, caStmp *driver.Stamp) (priKey *rsa.PrivateKey, newCaStmp *driver.Stamp, err error) {
	value, newCaStmp, err := sys.priKeyCont.Get(taId, caStmp)
	if err != nil {
		return nil, nil, erro.Wrap(err)
	} else if value == nil {
		return nil, newCaStmp, nil
	}

	return value.(*rsa.PrivateKey), newCaStmp, nil
}

var noVerifyTr = &http.Transport{
	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

func (sys *system) client(host string) (cli *http.Client, err error) {
	value, _, err := sys.cliCont.Get(host, nil)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	if value == nil {
		if sys.noVerify {
			cli = &http.Client{Transport: noVerifyTr}
		} else {
			cli = &http.Client{}
		}
	} else {
		cli = value.(*http.Client)
	}
	// 有効期限の更新。
	if _, err = sys.cliCont.Put(host, cli, time.Now().Add(sys.cliExpiDur)); err != nil {
		return nil, erro.Wrap(err)
	}
	return cli, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

type SystemClient interface {
	EnvironmentDirs() ([]string, error)
	EnsureEnvironmentDir(envName string, keys SSHKey) (string, error)
	RemoveEnvironmentDir(envName string) error
	EnsureSSHKey() (SSHKey, error)
	Username() string
	UID() int
	GID() int
}

type RealSystemClient struct {
	user      string
	uid       int
	gid       int
	baseDir   string
	envRegexp *regexp.Regexp
}

type SSHKey struct {
	privatePath string
	publicPath  string
}

func (rsc *RealSystemClient) EnvironmentDirs() ([]string, error) {
	files, err := ioutil.ReadDir(rsc.baseDir)
	if err != nil {
		return nil, err
	}

	dirs := make([]string, 0)
	for _, file := range files {
		if file.IsDir() {
			dirs = append(dirs, file.Name())
		}
	}

	return dirs, nil
}

func (rsc *RealSystemClient) Username() string {
	return rsc.user
}

func (rsc *RealSystemClient) UID() int {
	return rsc.uid
}

func (rsc *RealSystemClient) GID() int {
	return rsc.gid
}

func (rsc *RealSystemClient) EnsureEnvironmentDir(envName string, keys SSHKey) (string, error) {

	envPath := filepath.Join(rsc.baseDir, envName)
	err := os.MkdirAll(envPath, 0755)
	if err != nil {
		return "", err
	}

	sshPath := filepath.Join(envPath, ".ssh")
	err = os.MkdirAll(sshPath, 0700)
	if err != nil {
		return "", err
	}

	akPath := filepath.Join(sshPath, "authorized_keys")
	data, err := ioutil.ReadFile(keys.publicPath)
	if err != nil {
		return "", err
	}
	err = ioutil.WriteFile(akPath, data, 0700)
	if err != nil {
		return "", err
	}

	return envPath, nil
}

func (rsc *RealSystemClient) RemoveEnvironmentDir(envName string) error {

	envPath := filepath.Join(rsc.baseDir, envName)
	err := os.RemoveAll(envPath)
	if err != nil {
		return err
	}

	return nil
}

func (rsc *RealSystemClient) EnsureSSHKey() (SSHKey, error) {
	privPath := filepath.Join(rsc.baseDir, "ddc_key")
	pubPath := filepath.Join(rsc.baseDir, "ddc_key.pub")

	if _, err := os.Stat(privPath); os.IsNotExist(err) {

		cmd := exec.Command("ssh-keygen", "-q", "-t", "rsa", "-N", "", "-C", "ddc key", "-f", privPath)
		err := cmd.Run()
		if err != nil {
			return SSHKey{}, err
		}
	}

	return SSHKey{privPath, pubPath}, nil
}

func NewSystemClient() (*RealSystemClient, error) {

	var home string
	if home = os.Getenv("HOME"); len(home) == 0 {
		return nil, fmt.Errorf("$HOME environment variable not found")
	}

	return NewSystemClientWithBase(filepath.Join(home, "envs"))
}

func NewSystemClientWithBase(baseDir string) (*RealSystemClient, error) {

	var user string

	if user = os.Getenv("USER"); len(user) == 0 {
		return nil, fmt.Errorf("$USER environment variable not found")
	}

	systemClient := RealSystemClient{
		user:      user,
		uid:       os.Getuid(),
		gid:       os.Getgid(),
		baseDir:   baseDir,
		envRegexp: regexp.MustCompile(fmt.Sprintf("%s/(.*)dev", user)),
	}

	err := os.MkdirAll(baseDir, 0700)
	if err != nil {
		return nil, err
	}

	return &systemClient, nil
}
<commit_msg>attempt to detect running in docker-machine<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

type SystemClient interface {
	EnvironmentDirs() ([]string, error)
	EnsureEnvironmentDir(envName string, keys SSHKey) (string, error)
	RemoveEnvironmentDir(envName string) error
	EnsureSSHKey() (SSHKey, error)
	Username() string
	UID() int
	GID() int
}

type RealSystemClient struct {
	user      string
	uid       int
	gid       int
	baseDir   string
	envRegexp *regexp.Regexp
}

type SSHKey struct {
	privatePath string
	publicPath  string
}

func (rsc *RealSystemClient) EnvironmentDirs() ([]string, error) {
	files, err := ioutil.ReadDir(rsc.baseDir)
	if err != nil {
		return nil, err
	}

	dirs := make([]string, 0)
	for _, file := range files {
		if file.IsDir() {
			dirs = append(dirs, file.Name())
		}
	}

	return dirs, nil
}

func (rsc *RealSystemClient) Username() string {
	return rsc.user
}

func (rsc *RealSystemClient) UID() int {
	return rsc.uid
}

func (rsc *RealSystemClient) GID() int {
	return rsc.gid
}

func (rsc *RealSystemClient) EnsureEnvironmentDir(envName string, keys SSHKey) (string, error) {

	envPath := filepath.Join(rsc.baseDir, envName)
	err := os.MkdirAll(envPath, 0755)
	if err != nil {
		return "", err
	}

	sshPath := filepath.Join(envPath, ".ssh")
	err = os.MkdirAll(sshPath, 0700)
	if err != nil {
		return "", err
	}

	akPath := filepath.Join(sshPath, "authorized_keys")
	data, err := ioutil.ReadFile(keys.publicPath)
	if err != nil {
		return "", err
	}
	err = ioutil.WriteFile(akPath, data, 0700)
	if err != nil {
		return "", err
	}

	return envPath, nil
}

func (rsc *RealSystemClient) RemoveEnvironmentDir(envName string) error {

	envPath := filepath.Join(rsc.baseDir, envName)
	err := os.RemoveAll(envPath)
	if err != nil {
		return err
	}

	return nil
}

func (rsc *RealSystemClient) EnsureSSHKey() (SSHKey, error) {
	privPath := filepath.Join(rsc.baseDir, "ddc_key")
	pubPath := filepath.Join(rsc.baseDir, "ddc_key.pub")

	if _, err := os.Stat(privPath); os.IsNotExist(err) {

		cmd := exec.Command("ssh-keygen", "-q", "-t", "rsa", "-N", "", "-C", "ddc key", "-f", privPath)
		err := cmd.Run()
		if err != nil {
			return SSHKey{}, err
		}
	}

	return SSHKey{privPath, pubPath}, nil
}

func NewSystemClient() (*RealSystemClient, error) {

	var home string
	if home = os.Getenv("HOME"); len(home) == 0 {
		return nil, fmt.Errorf("$HOME environment variable not found")
	}

	return NewSystemClientWithBase(filepath.Join(home, "envs"))
}

func NewSystemClientWithBase(baseDir string) (*RealSystemClient, error) {

	var user string

	if user = os.Getenv("USER"); len(user) == 0 {
		return nil, fmt.Errorf("$USER environment variable not found")
	}

	var uid int
	if env_endpoint := os.Getenv("DOCKER_MACHINE_NAME"); len(env_endpoint) > 0 {
		uid = 1000
	} else {
		uid = os.Getuid()
	}

	systemClient := RealSystemClient{
		user:      user,
		uid:       uid,
		gid:       os.Getgid(),
		baseDir:   baseDir,
		envRegexp: regexp.MustCompile(fmt.Sprintf("%s/(.*)dev", user)),
	}

	err := os.MkdirAll(baseDir, 0700)
	if err != nil {
		return nil, err
	}

	return &systemClient, nil
}
<|endoftext|>


<commit_before>// +build examples

/*
Copyright 2020 The Tekton Authors

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

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

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

package test

import (
	"errors"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	knativetest "knative.dev/pkg/test"
)

var (
	pipelineRunTimeout = 10 * time.Minute
)

const (
	DEFAULT_KO_DOCKER_REPO = `gcr.io\/christiewilson-catfactory`
	DEFAULT_NAMESPACE      = `namespace: default`
)

// GetCreatedTektonCrd parses output of an external ko invocation provided as
// input, as is the kind of Tekton CRD to search for (ie. taskrun)
func GetCreatedTektonCrd(input []byte, kind string) (string, error) {
	re := regexp.MustCompile(kind + `.tekton.dev\/(.+) created`)
	submatch := re.FindSubmatch(input)
	if submatch == nil || len(submatch) < 2 {
		return "", nil
	}
	return string(submatch[1]), nil
}

func waitValidatePipelineRunDone(t *testing.T, c *clients, pipelineRunName string) {
	err := WaitForPipelineRunState(c, pipelineRunName, pipelineRunTimeout, Succeed(pipelineRunName), pipelineRunName)

	if err != nil {
		t.Fatalf("Failed waiting for pipeline run done: %v", err)
	}
	return
}

func waitValidateTaskRunDone(t *testing.T, c *clients, taskRunName string) {
	// Per test basis
	err := WaitForTaskRunState(c, taskRunName, Succeed(taskRunName), taskRunName)

	if err != nil {
		t.Fatalf("Failed waiting for task run done: %v", err)
	}
	return
}

// SubstituteEnv substitutes docker repos and bucket paths from the system
// environment for input to allow tests on local clusters. It also updates the
// namespace for ServiceAccounts so that they work under test
func SubstituteEnv(input []byte, namespace string) ([]byte, error) {
	val, ok := os.LookupEnv("KO_DOCKER_REPO")
	var output []byte
	if ok {
		re := regexp.MustCompile(DEFAULT_KO_DOCKER_REPO)
		output = re.ReplaceAll(input, []byte(val))
	} else {
		return nil, errors.New("KO_DOCKER_REPO is not set")
	}

	re := regexp.MustCompile(DEFAULT_NAMESPACE)
	output = re.ReplaceAll(output, []byte(strings.ReplaceAll(DEFAULT_NAMESPACE, "default", namespace)))
	return output, nil
}

// KoCreate wraps the ko binary and invokes `ko create` for input within
// namespace
func KoCreate(input []byte, namespace string) ([]byte, error) {
	cmd := exec.Command("ko", "create", "-n", namespace, "-f", "-")
	cmd.Stdin = strings.NewReader(string(input))

	out, err := cmd.CombinedOutput()
	return out, err
}

// DeleteClusterTask removes a single clustertask by name using provided
// clientset. Test state is used for logging. DeleteClusterTask does not wait
// for the clustertask to be deleted, so it is still possible to have name
// conflicts during test
func DeleteClusterTask(t *testing.T, c *clients, name string) {
	t.Logf("Deleting clustertask %s", name)
	err := c.ClusterTaskClient.Delete(name, &metav1.DeleteOptions{})
	if err != nil {
		t.Fatalf("Failed to delete clustertask: %v", err)
	}
}

type waitFunc func(t *testing.T, c *clients, name string)

func exampleTest(path string, waitValidateFunc waitFunc, kind string) func(t *testing.T) {
	return func(t *testing.T) {
		t.Parallel()

		// Setup unique namespaces for each test so they can run in complete
		// isolation
		c, namespace := setup(t)

		knativetest.CleanupOnInterrupt(func() { tearDown(t, c, namespace) }, t.Logf)
		defer tearDown(t, c, namespace)

		inputExample, err := ioutil.ReadFile(path)

		if err != nil {
			t.Fatalf("Error reading file: %v", err)
		}

		subbedInput, err := SubstituteEnv(inputExample, namespace)
		if err != nil {
			t.Skipf("Couldn't substitute environment: %v", err)
		}

		out, err := KoCreate(subbedInput, namespace)
		if err != nil {
			t.Fatalf("%s Output: %s", err, out)
		}

		// Parse from KoCreate for now
		name, err := GetCreatedTektonCrd(out, kind)
		if name == "" {
			// Nothing to check from ko create, this is not a taskrun or pipeline
			// run. Some examples in the directory do not directly output a TaskRun
			// or PipelineRun (ie. task-result.yaml).
			t.Skipf("pipelinerun or taskrun not created for %s", path)
		} else if err != nil {
			t.Fatalf("Failed to get created Tekton CRD of kind %s: %v", kind, err)
		}

		// NOTE: If an example creates more than one clustertask, they will not all
		// be cleaned up
		clustertask, err := GetCreatedTektonCrd(out, "clustertask")
		if clustertask != "" {
			knativetest.CleanupOnInterrupt(func() { DeleteClusterTask(t, c, clustertask) }, t.Logf)
			defer DeleteClusterTask(t, c, clustertask)
		} else if err != nil {
			t.Fatalf("Failed to get created clustertask: %v", err)
		}

		waitValidateFunc(t, c, name)
	}
}

func getExamplePaths(t *testing.T, dir string) []string {
	var examplePaths []string

	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			t.Fatalf("couldn't walk path %s: %v", path, err)
		}
		// Do not append root and any other folders named "examples"
		if info.Name() == "examples" && info.IsDir() {
			return nil
		}
		if info.Name() == "no-ci" && info.IsDir() {
			return filepath.SkipDir
		}
		if info.IsDir() == false && filepath.Ext(info.Name()) == ".yaml" {
			// Ignore test matching the regexp in the TEST_EXAMPLES_IGNORES
			// environement variable.
			val, ok := os.LookupEnv("TEST_EXAMPLES_IGNORES")
			if ok {
				re := regexp.MustCompile(val)
				submatch := re.FindSubmatch([]byte(path))
				if submatch != nil {
					t.Logf("Skipping test %s", path)
					return nil
				}
			}
			t.Logf("Adding test %s", path)
			examplePaths = append(examplePaths, path)
			return nil
		}
		return nil
	})
	if err != nil {
		t.Fatalf("couldn't walk example directory %s: %v", dir, err)
	}

	return examplePaths
}

func extractTestName(baseDir string, path string) string {
	re := regexp.MustCompile(baseDir + "/(.+).yaml")
	submatch := re.FindSubmatch([]byte(path))
	if submatch == nil {
		return path
	}
	return string(submatch[1])
}

func TestExamples(t *testing.T) {
	baseDir := "../examples"

	t.Parallel()
	for _, path := range getExamplePaths(t, baseDir) {
		testName := extractTestName(baseDir, path)
		waitValidateFunc := waitValidatePipelineRunDone
		kind := "pipelinerun"

		if strings.Contains(path, "/taskruns/") {
			waitValidateFunc = waitValidateTaskRunDone
			kind = "taskrun"
		}

		t.Run(testName, exampleTest(path, waitValidateFunc, kind))
	}
}
<commit_msg>Clean up examples_test.go<commit_after>// +build examples

/*
Copyright 2020 The Tekton Authors

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

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

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

package test

import (
	"bytes"
	"errors"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	knativetest "knative.dev/pkg/test"
)

const pipelineRunTimeout = 10 * time.Minute

var (
	defaultKoDockerRepoRE = regexp.MustCompile("gcr.io/christiewilson-catfactory")
	defaultNamespaceRE    = regexp.MustCompile("namespace: default")
)

// getCreatedTektonCRD parses output of an external ko invocation provided as
// input, as is the kind of Tekton CRD to search for (ie. taskrun)
func getCreatedTektonCRD(input []byte, kind string) (string, error) {
	re := regexp.MustCompile(kind + `.tekton.dev\/(.+) created`)
	submatch := re.FindSubmatch(input)
	if submatch == nil || len(submatch) < 2 {
		return "", nil
	}
	return string(submatch[1]), nil
}

func waitValidatePipelineRunDone(t *testing.T, c *clients, pipelineRunName string) {
	if err := WaitForPipelineRunState(c, pipelineRunName, pipelineRunTimeout, Succeed(pipelineRunName), pipelineRunName); err != nil {
		t.Fatalf("Failed waiting for pipeline run done: %v", err)
	}
}

func waitValidateTaskRunDone(t *testing.T, c *clients, taskRunName string) {
	// Per test basis
	if err := WaitForTaskRunState(c, taskRunName, Succeed(taskRunName), taskRunName); err != nil {
		t.Fatalf("Failed waiting for task run done: %v", err)
	}
}

// substituteEnv substitutes docker repos and bucket paths from the system
// environment for input to allow tests on local clusters. It also unsets the
// namespace for ServiceAccounts so that they work under test.
func substituteEnv(input []byte, namespace string) ([]byte, error) {
	// Replace the placeholder image repo with the value of the
	// KO_DOCKER_REPO env var.
	val, ok := os.LookupEnv("KO_DOCKER_REPO")
	if !ok {
		return nil, errors.New("KO_DOCKER_REPO is not set")
	}
	output := defaultKoDockerRepoRE.ReplaceAll(input, []byte(val))

	// Strip any "namespace: default"s, all resources will be created in
	// the test namespace using `ko create -n`
	output = defaultNamespaceRE.ReplaceAll(output, []byte("namespace: "+namespace))

	return output, nil
}

// koCreate wraps the ko binary and invokes `ko create` for input within
// namespace
func koCreate(input []byte, namespace string) ([]byte, error) {
	cmd := exec.Command("ko", "create", "-n", namespace, "-f", "-")
	cmd.Stdin = bytes.NewReader(input)
	return cmd.CombinedOutput()
}

// deleteClusterTask removes a single clustertask by name using provided
// clientset. Test state is used for logging. deleteClusterTask does not wait
// for the clustertask to be deleted, so it is still possible to have name
// conflicts during test
func deleteClusterTask(t *testing.T, c *clients, name string) {
	t.Logf("Deleting clustertask %s", name)
	if err := c.ClusterTaskClient.Delete(name, &metav1.DeleteOptions{}); err != nil {
		t.Fatalf("Failed to delete clustertask: %v", err)
	}
}

type waitFunc func(t *testing.T, c *clients, name string)

func exampleTest(path string, waitValidateFunc waitFunc, kind string) func(t *testing.T) {
	return func(t *testing.T) {
		t.Parallel()

		// Setup unique namespaces for each test so they can run in complete
		// isolation
		c, namespace := setup(t)

		knativetest.CleanupOnInterrupt(func() { tearDown(t, c, namespace) }, t.Logf)
		defer tearDown(t, c, namespace)

		inputExample, err := ioutil.ReadFile(path)
		if err != nil {
			t.Fatalf("Error reading file: %v", err)
		}

		subbedInput, err := substituteEnv(inputExample, namespace)
		if err != nil {
			t.Skipf("Couldn't substitute environment: %v", err)
		}

		out, err := koCreate(subbedInput, namespace)
		if err != nil {
			t.Fatalf("%s Output: %s", err, out)
		}

		// Parse from koCreate for now
		name, err := getCreatedTektonCRD(out, kind)
		if name == "" {
			// Nothing to check from ko create, this is not a taskrun or pipeline
			// run. Some examples in the directory do not directly output a TaskRun
			// or PipelineRun (ie. task-result.yaml).
			t.Skipf("pipelinerun or taskrun not created for %s", path)
		} else if err != nil {
			t.Fatalf("Failed to get created Tekton CRD of kind %s: %v", kind, err)
		}

		// NOTE: If an example creates more than one clustertask, they will not all
		// be cleaned up
		clustertask, err := getCreatedTektonCRD(out, "clustertask")
		if clustertask != "" {
			knativetest.CleanupOnInterrupt(func() { deleteClusterTask(t, c, clustertask) }, t.Logf)
			defer deleteClusterTask(t, c, clustertask)
		} else if err != nil {
			t.Fatalf("Failed to get created clustertask: %v", err)
		}

		waitValidateFunc(t, c, name)
	}
}

func getExamplePaths(t *testing.T, dir string) []string {
	var examplePaths []string

	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			t.Fatalf("couldn't walk path %s: %v", path, err)
		}
		// Do not append root and any other folders named "examples"
		if info.Name() == "examples" && info.IsDir() {
			return nil
		}
		if info.Name() == "no-ci" && info.IsDir() {
			return filepath.SkipDir
		}
		if info.IsDir() == false && filepath.Ext(info.Name()) == ".yaml" {
			// Ignore test matching the regexp in the TEST_EXAMPLES_IGNORES
			// environement variable.
			val, ok := os.LookupEnv("TEST_EXAMPLES_IGNORES")
			if ok {
				re := regexp.MustCompile(val)
				submatch := re.FindSubmatch([]byte(path))
				if submatch != nil {
					t.Logf("Skipping test %s", path)
					return nil
				}
			}
			t.Logf("Adding test %s", path)
			examplePaths = append(examplePaths, path)
			return nil
		}
		return nil
	})
	if err != nil {
		t.Fatalf("couldn't walk example directory %s: %v", dir, err)
	}

	return examplePaths
}

func extractTestName(baseDir string, path string) string {
	re := regexp.MustCompile(baseDir + "/(.+).yaml")
	submatch := re.FindSubmatch([]byte(path))
	if submatch == nil {
		return path
	}
	return string(submatch[1])
}

func TestExamples(t *testing.T) {
	baseDir := "../examples"

	t.Parallel()
	for _, path := range getExamplePaths(t, baseDir) {
		testName := extractTestName(baseDir, path)
		waitValidateFunc := waitValidatePipelineRunDone
		kind := "pipelinerun"

		if strings.Contains(path, "/taskruns/") {
			waitValidateFunc = waitValidateTaskRunDone
			kind = "taskrun"
		}

		t.Run(testName, exampleTest(path, waitValidateFunc, kind))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net"
	"strconv"
	"net/http"
	"strings"
	"fmt"
	"github.com/ogier/pflag"
	"time"
)

func main() {

	var port *int = pflag.IntP("port", "p", 8888, "The port to listen on")
	var timeout *int = pflag.IntP("timeout", "t", 10, "Seconds to wait before giving up")
	pflag.Parse()

	fmt.Printf("Listening on port %d...\n", *port)
	s := service{}
	s.port = *port
	s.timeout = *timeout
	s.listen()
}

type service struct {
	port int
	timeout int
}

func (s service) listen() {
	http.HandleFunc("/", s.handleRequest)
	http.ListenAndServe(":" + strconv.Itoa(s.port), nil)
}

func (s service) handleRequest(w http.ResponseWriter, r *http.Request) {

	if len(r.RequestURI[1:]) == 0 {
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	}

	pathComponents := strings.Split(r.RequestURI[1:], "/")
	if len(pathComponents) != 2 {
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	}

	host := pathComponents[0]
	port, err := strconv.Atoi(pathComponents[1])
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	isUp := s.testConnection(host, port)
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, "{\"success\": %t}", isUp)
}

func (s service) testConnection(host string, port int) (bool) {

	timeout := time.Duration(s.timeout) * time.Second

	conn, err := net.DialTimeout("tcp", host + ":" + strconv.Itoa(port), timeout)
	if err != nil {
		return false
	}
	conn.Close()
	return true
}
<commit_msg>Add the timeout as a request parameter<commit_after>package main

import (
	"net"
	"strconv"
	"net/http"
	"fmt"
	"github.com/ogier/pflag"
	"github.com/gorilla/mux"
	"time"
)

func main() {

	var port *int = pflag.IntP("port", "p", 8888, "The port to listen on")
	var timeout *int = pflag.IntP("defaul-timeout", "t", 10, "Seconds to wait before giving up on the request")
	pflag.Parse()

	s := service{}
	s.port = *port
	s.timeout = *timeout
	s.listen()
}

type service struct {
	port int
	timeout int
}

func (s service) listen() {
	router := mux.NewRouter()
	router.HandleFunc("/{host}/{port:[0-9]+}", s.handleRequest).Methods("GET")

	fmt.Printf("Listening on port %d with a default timeout of %d seconds...\n", s.port, s.timeout)
	http.Handle("/", router)
	err := http.ListenAndServe(":" + strconv.Itoa(s.port), nil)
	if err == nil {
		fmt.Println(err)
	}
}

func (s service) handleRequest(w http.ResponseWriter, r *http.Request) {

	params := mux.Vars(r)
	host := params["host"]
	timeout := s.timeout

	if r.FormValue("timeout") != "" {
		timeout, _ = strconv.Atoi(r.FormValue("timeout"))
	}

	port, err := strconv.Atoi(params["port"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	isUp := s.testConnection(host, port, timeout)
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, "{\"success\": %t}", isUp)
}

func (s service) testConnection(host string, port int, timeout int) (bool) {

	timeout_duration := time.Duration(timeout) * time.Second

	conn, err := net.DialTimeout("tcp", host + ":" + strconv.Itoa(port), timeout_duration)
	if err != nil {
		return false
	}
	conn.Close()
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"SimpleReader"
	"SimpleReader/models/global"
	"SimpleReader/models/storage"
	"github.com/go-martini/martini"
	"log"
	"os"
	"os/signal"
	"syscall"
  "runtime"
)

func catchExitSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGABRT, syscall.SIGKILL, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
	log.Println("Catch signals")
	for sig := range c {
		log.Println("Signal to exit:", sig)
		return
	}
}

func main() {
      runtime.GOMAXPROCS(4)
	host := ""
	port := "9000"
	chdir := "/home/yourok/Dropbox/Projects/BooksReader/SimpleReader" //os.Getenv("OPENSHIFT_DATA_DIR")

	if len(os.Args) >= 2 {
		host = os.Args[1]
	}

	if len(os.Args) >= 3 {
		port = os.Args[2]
	}

	if len(os.Args) >= 4 {
		chdir = os.Args[3]
	}

	os.Chdir(chdir)
	martini.Root = chdir
	log.Println("SR run with:", host, port, chdir)
	go SimpleReader.Start(host, port)
	catchExitSignals()
	global.Stoping = true
	storage.GetStorage().Exit()
       log.Println("Exit")
}
<commit_msg>some changes<commit_after>package main

import (
	"SimpleReader"
	"SimpleReader/models/global"
	"SimpleReader/models/storage"
	"github.com/go-martini/martini"
	"log"
	"os"
	"os/signal"
	"runtime"
	"syscall"
)

func catchExitSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGABRT, syscall.SIGKILL, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
	log.Println("Catch signals")
	for sig := range c {
		log.Println("Signal to exit:", sig)
		return
	}
}

func main() {
	runtime.GOMAXPROCS(4)
	host := ""
	port := "9000"
	chdir := "/home/yourok/sr" //os.Getenv("OPENSHIFT_DATA_DIR")

	if len(os.Args) >= 2 {
		host = os.Args[1]
	}

	if len(os.Args) >= 3 {
		port = os.Args[2]
	}

	if len(os.Args) >= 4 {
		chdir = os.Args[3]
	}

	os.Chdir(chdir)
	martini.Root = chdir
	log.Println("SR run with:", host, port, chdir)
	go SimpleReader.Start(host, port)
	catchExitSignals()
	global.Stoping = true
	storage.GetStorage().Exit()
	log.Println("Exit")
}
<|endoftext|>


<commit_before>package config

import (
	"crypto/tls"
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/service/sqs"
)

var (
	// Start with sensible default values
	defaultCnf = &Config{
		Broker:          "amqp://guest:guest@localhost:5672/",
		DefaultQueue:    "machinery_tasks",
		ResultBackend:   "amqp://guest:guest@localhost:5672/",
		ResultsExpireIn: 3600,
		AMQP: &AMQPConfig{
			Exchange:      "machinery_exchange",
			ExchangeType:  "direct",
			BindingKey:    "machinery_task",
			PrefetchCount: 3,
		},
		DynamoDB: &DynamoDBConfig{
			TaskStatesTable: "task_states",
			GroupMetasTable: "group_metas",
		},
		Redis: &RedisConfig{
			MaxIdle:                3,
			IdleTimeout:            240,
			ReadTimeout:            15,
			WriteTimeout:           15,
			ConnectTimeout:         15,
			DelayedTasksPollPeriod: 20,
		},
	}

	reloadDelay = time.Second * 10
)

// Config holds all configuration for our program
type Config struct {
	Broker          string       `yaml:"broker" envconfig:"BROKER"`
	DefaultQueue    string       `yaml:"default_queue" envconfig:"DEFAULT_QUEUE"`
	ResultBackend   string       `yaml:"result_backend" envconfig:"RESULT_BACKEND"`
	ResultsExpireIn int          `yaml:"results_expire_in" envconfig:"RESULTS_EXPIRE_IN"`
	AMQP            *AMQPConfig  `yaml:"amqp"`
	SQS             *SQSConfig   `yaml:"sqs"`
	Redis           *RedisConfig `yaml:"redis"`
	TLSConfig       *tls.Config
	//NoUnixSignals when set disables signal handling in machinery
	NoUnixSignals bool            `yaml:"no_unix_signals" envconfig:"NO_UNIX_SIGNALS"`
	DynamoDB      *DynamoDBConfig `yaml:"dynamodb"`
}

// QueueBindingArgs arguments which are used when binding to the exchange
type QueueBindingArgs map[string]interface{}

// AMQPConfig wraps RabbitMQ related configuration
type AMQPConfig struct {
	Exchange         string           `yaml:"exchange" envconfig:"AMQP_EXCHANGE"`
	ExchangeType     string           `yaml:"exchange_type" envconfig:"AMQP_EXCHANGE_TYPE"`
	QueueBindingArgs QueueBindingArgs `yaml:"queue_binding_args" envconfig:"AMQP_QUEUE_BINDING_ARGS"`
	BindingKey       string           `yaml:"binding_key" envconfig:"AMQP_BINDING_KEY"`
	PrefetchCount    int              `yaml:"prefetch_count" envconfig:"AMQP_PREFETCH_COUNT"`
}

// DynamoDBConfig wraps DynamoDB related configuration
type DynamoDBConfig struct {
	TaskStatesTable string `yaml:"task_states_table" envconfig:"TASK_STATES_TABLE"`
	GroupMetasTable string `yaml:"group_metas_table" envconfig:"GROUP_METAS_TABLE"`
}

// SQSConfig wraps SQS related configuration
type SQSConfig struct {
	Client          *sqs.SQS
	WaitTimeSeconds int `yaml:"receive_wait_time_seconds" envconfig:"SQS_WAIT_TIME_SECONDS"`
	// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
	// visibility timeout should default to nil to use the overall visibility timeout for the queue
	VisibilityTimeout *int `yaml:"receive_visibility_timeout" envconfig:"SQS_VISIBILITY_TIMEOUT"`
}

type RedisConfig struct {
	// Maximum number of idle connections in the pool.
	MaxIdle int `yaml:"max_idle" envconfig:"REDIS_MAX_IDLE"`

	// Maximum number of connections allocated by the pool at a given time.
	// When zero, there is no limit on the number of connections in the pool.
	MaxActive int `yaml:"max_active" envconfig:"REDIS_MAX_ACTIVE"`

	// Close connections after remaining idle for this duration in seconds. If the value
	// is zero, then idle connections are not closed. Applications should set
	// the timeout to a value less than the server's timeout.
	IdleTimeout int `yaml:"max_idle_timeout" envconfig:"REDIS_IDLE_TIMEOUT"`

	// If Wait is true and the pool is at the MaxActive limit, then Get() waits
	// for a connection to be returned to the pool before returning.
	Wait bool `yaml:"wait" envconfig:"REDIS_WAIT"`

	// ReadTimeout specifies the timeout in seconds for reading a single command reply.
	ReadTimeout int `yaml:"read_timeout" envconfig:"REDIS_READ_TIMEOUT"`

	// WriteTimeout specifies the timeout in seconds for writing a single command.
	WriteTimeout int `yaml:"write_timeout" envconfig:"REDIS_WRITE_TIMEOUT"`

	// ConnectTimeout specifies the timeout in seconds for connecting to the Redis server when
	// no DialNetDial option is specified.
	ConnectTimeout int `yaml:"connect_timeout" envconfig:"REDIS_CONNECT_TIMEOUT"`

	// DelayedTasksPollPeriod specifies the period in milliseconds when polling redis for delayed tasks
	DelayedTasksPollPeriod int
}

// Decode from yaml to map (any field whose type or pointer-to-type implements
// envconfig.Decoder can control its own deserialization)
func (args *QueueBindingArgs) Decode(value string) error {
	pairs := strings.Split(value, ",")
	mp := make(map[string]interface{}, len(pairs))
	for _, pair := range pairs {
		kvpair := strings.Split(pair, ":")
		if len(kvpair) != 2 {
			return fmt.Errorf("invalid map item: %q", pair)
		}
		mp[kvpair[0]] = kvpair[1]
	}
	*args = QueueBindingArgs(mp)
	return nil
}
<commit_msg>Small config update<commit_after>package config

import (
	"crypto/tls"
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/service/sqs"
)

var (
	// Start with sensible default values
	defaultCnf = &Config{
		Broker:          "amqp://guest:guest@localhost:5672/",
		DefaultQueue:    "machinery_tasks",
		ResultBackend:   "amqp://guest:guest@localhost:5672/",
		ResultsExpireIn: 3600,
		AMQP: &AMQPConfig{
			Exchange:      "machinery_exchange",
			ExchangeType:  "direct",
			BindingKey:    "machinery_task",
			PrefetchCount: 3,
		},
		DynamoDB: &DynamoDBConfig{
			TaskStatesTable: "task_states",
			GroupMetasTable: "group_metas",
		},
		Redis: &RedisConfig{
			MaxIdle:                3,
			IdleTimeout:            240,
			ReadTimeout:            15,
			WriteTimeout:           15,
			ConnectTimeout:         15,
			DelayedTasksPollPeriod: 20,
		},
	}

	reloadDelay = time.Second * 10
)

// Config holds all configuration for our program
type Config struct {
	Broker          string       `yaml:"broker" envconfig:"BROKER"`
	DefaultQueue    string       `yaml:"default_queue" envconfig:"DEFAULT_QUEUE"`
	ResultBackend   string       `yaml:"result_backend" envconfig:"RESULT_BACKEND"`
	ResultsExpireIn int          `yaml:"results_expire_in" envconfig:"RESULTS_EXPIRE_IN"`
	AMQP            *AMQPConfig  `yaml:"amqp"`
	SQS             *SQSConfig   `yaml:"sqs"`
	Redis           *RedisConfig `yaml:"redis"`
	TLSConfig       *tls.Config
	// NoUnixSignals - when set disables signal handling in machinery
	NoUnixSignals bool            `yaml:"no_unix_signals" envconfig:"NO_UNIX_SIGNALS"`
	DynamoDB      *DynamoDBConfig `yaml:"dynamodb"`
}

// QueueBindingArgs arguments which are used when binding to the exchange
type QueueBindingArgs map[string]interface{}

// AMQPConfig wraps RabbitMQ related configuration
type AMQPConfig struct {
	Exchange         string           `yaml:"exchange" envconfig:"AMQP_EXCHANGE"`
	ExchangeType     string           `yaml:"exchange_type" envconfig:"AMQP_EXCHANGE_TYPE"`
	QueueBindingArgs QueueBindingArgs `yaml:"queue_binding_args" envconfig:"AMQP_QUEUE_BINDING_ARGS"`
	BindingKey       string           `yaml:"binding_key" envconfig:"AMQP_BINDING_KEY"`
	PrefetchCount    int              `yaml:"prefetch_count" envconfig:"AMQP_PREFETCH_COUNT"`
}

// DynamoDBConfig wraps DynamoDB related configuration
type DynamoDBConfig struct {
	TaskStatesTable string `yaml:"task_states_table" envconfig:"TASK_STATES_TABLE"`
	GroupMetasTable string `yaml:"group_metas_table" envconfig:"GROUP_METAS_TABLE"`
}

// SQSConfig wraps SQS related configuration
type SQSConfig struct {
	Client          *sqs.SQS
	WaitTimeSeconds int `yaml:"receive_wait_time_seconds" envconfig:"SQS_WAIT_TIME_SECONDS"`
	// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
	// visibility timeout should default to nil to use the overall visibility timeout for the queue
	VisibilityTimeout *int `yaml:"receive_visibility_timeout" envconfig:"SQS_VISIBILITY_TIMEOUT"`
}

type RedisConfig struct {
	// Maximum number of idle connections in the pool.
	MaxIdle int `yaml:"max_idle" envconfig:"REDIS_MAX_IDLE"`

	// Maximum number of connections allocated by the pool at a given time.
	// When zero, there is no limit on the number of connections in the pool.
	MaxActive int `yaml:"max_active" envconfig:"REDIS_MAX_ACTIVE"`

	// Close connections after remaining idle for this duration in seconds. If the value
	// is zero, then idle connections are not closed. Applications should set
	// the timeout to a value less than the server's timeout.
	IdleTimeout int `yaml:"max_idle_timeout" envconfig:"REDIS_IDLE_TIMEOUT"`

	// If Wait is true and the pool is at the MaxActive limit, then Get() waits
	// for a connection to be returned to the pool before returning.
	Wait bool `yaml:"wait" envconfig:"REDIS_WAIT"`

	// ReadTimeout specifies the timeout in seconds for reading a single command reply.
	ReadTimeout int `yaml:"read_timeout" envconfig:"REDIS_READ_TIMEOUT"`

	// WriteTimeout specifies the timeout in seconds for writing a single command.
	WriteTimeout int `yaml:"write_timeout" envconfig:"REDIS_WRITE_TIMEOUT"`

	// ConnectTimeout specifies the timeout in seconds for connecting to the Redis server when
	// no DialNetDial option is specified.
	ConnectTimeout int `yaml:"connect_timeout" envconfig:"REDIS_CONNECT_TIMEOUT"`

	// DelayedTasksPollPeriod specifies the period in milliseconds when polling redis for delayed tasks
	DelayedTasksPollPeriod int `yaml:"delayed_tasks_poll_period" envconfig:"REDIS_DELAYED_TASKS_POLL_PERIOD"`
}

// Decode from yaml to map (any field whose type or pointer-to-type implements
// envconfig.Decoder can control its own deserialization)
func (args *QueueBindingArgs) Decode(value string) error {
	pairs := strings.Split(value, ",")
	mp := make(map[string]interface{}, len(pairs))
	for _, pair := range pairs {
		kvpair := strings.Split(pair, ":")
		if len(kvpair) != 2 {
			return fmt.Errorf("invalid map item: %q", pair)
		}
		mp[kvpair[0]] = kvpair[1]
	}
	*args = QueueBindingArgs(mp)
	return nil
}
<|endoftext|>


<commit_before>// main_test.go
package main

import (
	"reflect"
	"testing"
)

func TestGetKeymapFromOutput(t *testing.T) {
	var buf []byte
	var keymap map[uint8]string

	const test1 = "keycode  19 = 0 parenright 0 parenright\n" +
		"keycode  20 = minus underscore minus underscore\n" +
		"keycode  21 = equal plus equal plus"
	result1 := map[uint8]string{19: "0", 20: "minus", 21: "equal"}

	const test2 = "keycode 119 = Delete NoSymbol Delete\n" +
		"keycode 120 =\n" +
		"keycode 121 = XF86AudioMute NoSymbol XF86AudioMute"
	result2 := map[uint8]string{119: "Delete", 121: "XF86AudioMute"}

	// Test1. Simple
	buf = []byte(test1)
	keymap = GetKeymapFromOutput(buf)
	if !reflect.DeepEqual(keymap, result1) {
		t.Fail()
	}

	// Test2. With empty keys
	buf = []byte(test2)
	keymap = GetKeymapFromOutput(buf)
	if !reflect.DeepEqual(keymap, result2) {
		t.Fail()
	}
}

func TestGetKeyNumsFromOutput(t *testing.T) {
	var buf []byte
	var keyNums []uint8

	const test1 = "key press 36\nkey release 41\nkey press   41"
	var result1 = []uint8{36, 41}

	const test2 = ""
	var result2 = []uint8{}

	// Test1. Simple
	buf = []byte(test1)
	keyNums = GetKeyNumsFromOutput(buf)
	if !reflect.DeepEqual(keyNums, result1) {
		t.Fail()
	}

	// Test2. Clear
	buf = []byte(test2)
	keyNums = GetKeyNumsFromOutput(buf)
	if !reflect.DeepEqual(keyNums, result2) {
		t.Fail()
	}
}

func TestGetFileType(t *testing.T) {
	tests := map[string]string{
		"":                                "",
		"out.csv":                         "csv",
		"out.jsl":                         "jsl",
		"out.json":                        "json",
		"//sfd.dsf//.f./out.out.csv":      "csv",
		"..\\data.all.jsl.gz":             "jsl.gz",
		"../full.csv/first.data.json":     "json",
		"//sfd.dsf//.f./WhiteBear.csv.Gz": "csv.gz",
		"out.JsL":                         "jsl",
		"////////":                        "",
		"\\\\\\":                          "",
		"file1.Json.gz":                   "json.gz",
		"out.csv.json.jsl":                "jsl",
		"out.jsl.json.csv":                "csv",
	}
	for test, res := range tests {
		if GetFileType(test) != res {
			t.Log("On test ", test, " result is ", GetFileType(test), " but right is ", res, "")
			t.Fail()
		}
	}
}
<commit_msg>Added new test<commit_after>// main_test.go
package main

import (
	"reflect"
	"testing"
)

func TestGetKeymapFromOutput(t *testing.T) {
	var buf []byte
	var keymap map[uint8]string

	const test1 = "keycode  19 = 0 parenright 0 parenright\n" +
		"keycode  20 = minus underscore minus underscore\n" +
		"keycode  21 = equal plus equal plus"
	result1 := map[uint8]string{19: "0", 20: "minus", 21: "equal"}

	const test2 = "keycode 119 = Delete NoSymbol Delete\n" +
		"keycode 120 =\n" +
		"keycode 121 = XF86AudioMute NoSymbol XF86AudioMute"
	result2 := map[uint8]string{119: "Delete", 121: "XF86AudioMute"}

	// Test1. Simple
	buf = []byte(test1)
	keymap = GetKeymapFromOutput(buf)
	if !reflect.DeepEqual(keymap, result1) {
		t.Fail()
	}

	// Test2. With empty keys
	buf = []byte(test2)
	keymap = GetKeymapFromOutput(buf)
	if !reflect.DeepEqual(keymap, result2) {
		t.Fail()
	}
}

func TestGetKeyNumsFromOutput(t *testing.T) {
	var buf []byte
	var keyNums []uint8

	const test1 = "key press 36\nkey release 41\nkey press   41"
	var result1 = []uint8{36, 41}

	const test2 = ""
	var result2 = []uint8{}

	// Test1. Simple
	buf = []byte(test1)
	keyNums = GetKeyNumsFromOutput(buf)
	if !reflect.DeepEqual(keyNums, result1) {
		t.Fail()
	}

	// Test2. Clear
	buf = []byte(test2)
	keyNums = GetKeyNumsFromOutput(buf)
	if !reflect.DeepEqual(keyNums, result2) {
		t.Fail()
	}
}

func TestGetFileType(t *testing.T) {
	tests := map[string]string{
		"":                                "",
		"out.csv":                         "csv",
		"out.jsl":                         "jsl",
		"out.json":                        "json",
		"//sfd.dsf//.f./out.out.csv":      "csv",
		"..\\data.all.jsl.gz":             "jsl.gz",
		"../full.csv/first.data.json":     "json",
		"//sfd.dsf//.f./WhiteBear.csv.Gz": "csv.gz",
		"out.JsL":                         "jsl",
		"////////":                        "",
		"\\\\\\":                          "",
		"file1.Json.gz":                   "json.gz",
		"out.csv.json.jsl":                "jsl",
		"out.jsl.json.csv":                "csv",
		"stuff.gz":                        "",
	}
	for test, res := range tests {
		if GetFileType(test) != res {
			t.Log("On test ", test, " result is ", GetFileType(test), " but right is ", res, "")
			t.Fail()
		}
	}
}
<|endoftext|>


<commit_before>package sia

import (
	//"errors"
	"net"
	"strconv"
	"time"
)

const (
	timeout   = time.Second * 5
	maxMsgLen = 1 << 16
)

// A NetAddress contains the information needed to contact a peer over TCP.
type NetAddress struct {
	Host string
	Port uint16
}

func (na *NetAddress) String() string {
	return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port)))
}

// TODO: add Dial
// takes fn as an arg??

// TBD
var BootstrapPeers = []NetAddress{}

// A TCPServer sends and receives messages. It also maintains an address book
// of peers to broadcast to and make requests of.
type TCPServer struct {
	net.Listener
	myAddr      NetAddress
	addressbook map[NetAddress]struct{}
}

func NewTCPServer(port uint16) (tcps *TCPServer, err error) {
	tcpServ, err := net.Listen("tcp", ":"+strconv.Itoa(int(port)))
	if err != nil {
		return
	}
	tcps = &TCPServer{
		Listener:    tcpServ,
		addressbook: make(map[NetAddress]struct{}),
	}
	go tcps.listen()
	return
}

// listen runs in the background, accepting incoming connections and serving
// them. listen will return after TCPServer.Close() is called, because the
// Accept() call will fail.
func (tcps *TCPServer) listen() {
	for {
		conn, err := tcps.Accept()
		if err != nil {
			return
		}
		// it is the handler's responsibility to close the connection
		go tcps.handleConn(conn)
	}
}

// handleConn reads header data from a connection, unmarshals the data
// structures it contains, and routes the data to other functions for
// processing.
func (tcps *TCPServer) handleConn(conn net.Conn) {
	defer conn.Close()
	var (
		msgType   []byte = make([]byte, 1)
		msgLenBuf []byte = make([]byte, 4)
		msgData   []byte // length determined by msgLen
	)
	// TODO: make this DRYer?
	if n, err := conn.Read(msgType); err != nil || n != 1 {
		// TODO: log error
		return
	}
	if n, err := conn.Read(msgLenBuf); err != nil || n != 4 {
		// TODO: log error
		return
	}
	msgLen := DecUint64(msgLenBuf)
	if msgLen > maxMsgLen {
		// TODO: log error
		return
	}
	msgData = make([]byte, msgLen)
	if n, err := conn.Read(msgData); err != nil || uint64(n) != msgLen {
		// TODO: log error
		return
	}

	switch msgType[0] {
	// Hostname discovery
	case 'H':
		_, err := conn.Write([]byte(conn.RemoteAddr().String()))
		if err != nil {
			// TODO: log error
			return
		}

	// Peer discovery
	case 'P':
		if msgLen != 1 {
			// TODO: log error
			return
		}
		tcps.sharePeers(conn, msgData[0])

	// Block
	case 'B':
		var b Block
		if err := Unmarshal(msgData, &b); err != nil {
			// TODO: log error
			return
		}
		//state.ProcessBlock(b)?

	// Transaction
	case 'T':
		var t Transaction
		if err := Unmarshal(msgData, &t); err != nil {
			// TODO: log error
			return
		}
		//state.ProcessTransaction(t)?

	// Unknown
	default:
		// TODO: log error
	}
	return
}

// Ping returns whether a NetAddress is reachable. It accomplishes this by
// initiating a TCP connection and immediately closes it. This is pretty
// unsophisticated. I'll add a Pong later.
func (tcps *TCPServer) Ping(addr NetAddress) bool {
	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		return false
	}
	conn.Close()
	return true
}

// send initiates a TCP connection and writes a message to it.
// TODO: add timeout
func (tcps *TCPServer) send(msg []byte, addr NetAddress) (err error) {
	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		return
	}
	_, err = conn.Write(msg)
	return
}

// learnHostname learns the external IP of the TCPServer.
func (tcps *TCPServer) learnHostname(addr NetAddress) (err error) {
	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		return
	}
	defer conn.Close()
	// send hostname request
	if _, err = conn.Write([]byte{'H', 0}); err != nil {
		return
	}
	// read response
	buf = make([]byte, 128)
	n, err := conn.Read(buf)
	if err != nil {
		return
	}
	// TODO: try to ping ourselves?
	host, portStr, err := net.SplitHostPort(string(buf[:n]))
	if err != nil {
		return
	}
	port, err := strconv.Atoi(portStr)
	if err != nil {
		return
	}
	tcps.myAddr = NetAddress{host, uint16(port)}
	return
}

// sharePeers transmits at most 'num' peers over the connection.
// TODO: choose random peers?
func (tcps *TCPServer) sharePeers(conn net.Conn, num uint8) {
	var addrs []NetAddress
	for addr := range tcps.addressbook {
		if num == 0 {
			break
		}
		addrs = append(addrs, addr)
		num--
	}
	conn.Write(Marshal(addrs))
	// log error?
}

// requestPeers queries a peer for additional peers, and adds any new peers to
// the address book.
func (tcps *TCPServer) requestPeers(addr NetAddress) (err error) {
	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		return
	}
	defer conn.Close()
	// request 10 peers
	if _, err = conn.Write([]byte{'P', 1, 10}); err != nil {
		return
	}
	// read response
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		return
	}
	var addrs []NetAddress
	if err = Unmarshal(buf[:n], &addrs); err != nil {
		return
	}
	// add peers
	// TODO: make sure we don't add ourself
	for _, addr := range addrs {
		if tcps.Ping(addr) {
			tcps.addressbook[addr] = struct{}{}
		}
	}
	return
}

// Bootstrap discovers the external IP of the TCPServer, requests peers from
// the initial peer list, and announces itself to those peers.
func (tcps *TCPServer) Bootstrap() (err error) {
	// populate initial peer list
	for _, addr := range BootstrapPeers {
		if tcps.Ping(addr) {
			tcps.addressbook[addr] = struct{}{}
		}
	}

	// learn hostname
	for addr := range tcps.addressbook {
		if tcps.learnHostname() == nil {
			break
		}
	}
	// request peers
	// TODO: maybe iterate until we have enough new peers?
	for addr := range tcps.addressbook {
		tcps.requestPeers(addr)
	}
	// TODO: announce ourselves to new peers
	return
}
<commit_msg>simplify requests with NetAddress.Call<commit_after>package sia

import (
	//"errors"
	"net"
	"strconv"
	"time"
)

const (
	timeout   = time.Second * 5
	maxMsgLen = 1 << 16
)

// A NetAddress contains the information needed to contact a peer over TCP.
type NetAddress struct {
	Host string
	Port uint16
}

// String returns the NetAddress as a string, concatentating the hostname and
// port number.
func (na *NetAddress) String() string {
	return net.JoinHostPort(na.Host, strconv.Itoa(int(na.Port)))
}

// call establishes a TCP connection to the NetAddress, calls the provided
// function on it, and closes the connection.
func (na *NetAddress) Call(fn func(net.Conn) error) error {
	conn, err := net.Dial("tcp", na.String())
	if err != nil {
		return err
	}
	defer conn.Close()
	return fn(conn)
}

// TBD
var BootstrapPeers = []NetAddress{}

// A TCPServer sends and receives messages. It also maintains an address book
// of peers to broadcast to and make requests of.
type TCPServer struct {
	net.Listener
	myAddr      NetAddress
	addressbook map[NetAddress]struct{}
}

func NewTCPServer(port uint16) (tcps *TCPServer, err error) {
	tcpServ, err := net.Listen("tcp", ":"+strconv.Itoa(int(port)))
	if err != nil {
		return
	}
	tcps = &TCPServer{
		Listener:    tcpServ,
		addressbook: make(map[NetAddress]struct{}),
	}
	go tcps.listen()
	return
}

// listen runs in the background, accepting incoming connections and serving
// them. listen will return after TCPServer.Close() is called, because the
// Accept() call will fail.
func (tcps *TCPServer) listen() {
	for {
		conn, err := tcps.Accept()
		if err != nil {
			return
		}
		// it is the handler's responsibility to close the connection
		go tcps.handleConn(conn)
	}
}

// handleConn reads header data from a connection, unmarshals the data
// structures it contains, and routes the data to other functions for
// processing.
func (tcps *TCPServer) handleConn(conn net.Conn) {
	defer conn.Close()
	var (
		msgType   []byte = make([]byte, 1)
		msgLenBuf []byte = make([]byte, 4)
		msgData   []byte // length determined by msgLen
	)
	// TODO: make this DRYer?
	if n, err := conn.Read(msgType); err != nil || n != 1 {
		// TODO: log error
		return
	}
	if n, err := conn.Read(msgLenBuf); err != nil || n != 4 {
		// TODO: log error
		return
	}
	msgLen := DecUint64(msgLenBuf)
	if msgLen > maxMsgLen {
		// TODO: log error
		return
	}
	msgData = make([]byte, msgLen)
	if n, err := conn.Read(msgData); err != nil || uint64(n) != msgLen {
		// TODO: log error
		return
	}

	switch msgType[0] {
	// Hostname discovery
	case 'H':
		_, err := conn.Write([]byte(conn.RemoteAddr().String()))
		if err != nil {
			// TODO: log error
			return
		}

	// Peer discovery
	case 'P':
		if msgLen != 1 {
			// TODO: log error
			return
		}
		tcps.sharePeers(conn, msgData[0])

	// Block
	case 'B':
		var b Block
		if err := Unmarshal(msgData, &b); err != nil {
			// TODO: log error
			return
		}
		//state.AcceptBlock(b)
		// TODO: log error

	// Transaction
	case 'T':
		var t Transaction
		if err := Unmarshal(msgData, &t); err != nil {
			// TODO: log error
			return
		}
		//state.AcceptTransaction(&t)
		// TODO: log error

	// Unknown
	default:
		// TODO: log error
	}
	return
}

// sharePeers transmits at most 'num' peers over the connection.
// TODO: choose random peers?
func (tcps *TCPServer) sharePeers(conn net.Conn, num uint8) {
	var addrs []NetAddress
	for addr := range tcps.addressbook {
		if num == 0 {
			break
		}
		addrs = append(addrs, addr)
		num--
	}
	conn.Write(Marshal(addrs))
	// log error?
}

// Ping returns whether a NetAddress is reachable. It accomplishes this by
// initiating a TCP connection and immediately closes it. This is pretty
// unsophisticated. I'll add a Pong later.
func (tcps *TCPServer) Ping(addr NetAddress) bool {
	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		return false
	}
	conn.Close()
	return true
}

// learnHostname learns the external IP of the TCPServer.
func (tcps *TCPServer) learnHostname(conn net.Conn) (err error) {
	// send hostname request
	if _, err = conn.Write([]byte{'H', 0}); err != nil {
		return
	}
	// read response
	buf := make([]byte, 128)
	n, err := conn.Read(buf)
	if err != nil {
		return
	}
	// TODO: try to ping ourselves?
	host, portStr, err := net.SplitHostPort(string(buf[:n]))
	if err != nil {
		return
	}
	port, err := strconv.Atoi(portStr)
	if err != nil {
		return
	}
	tcps.myAddr = NetAddress{host, uint16(port)}
	return
}

// requestPeers queries a peer for additional peers, and adds any new peers to
// the address book.
func (tcps *TCPServer) requestPeers(conn net.Conn) (err error) {
	// request 10 peers
	if _, err = conn.Write([]byte{'P', 1, 10}); err != nil {
		return
	}
	// read response
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		return
	}
	var addrs []NetAddress
	if err = Unmarshal(buf[:n], &addrs); err != nil {
		return
	}
	// add peers
	// TODO: make sure we don't add ourself
	for _, addr := range addrs {
		if tcps.Ping(addr) {
			tcps.addressbook[addr] = struct{}{}
		}
	}
	return
}

// Bootstrap discovers the external IP of the TCPServer, requests peers from
// the initial peer list, and announces itself to those peers.
func (tcps *TCPServer) Bootstrap() (err error) {
	// populate initial peer list
	for _, addr := range BootstrapPeers {
		if tcps.Ping(addr) {
			tcps.addressbook[addr] = struct{}{}
		}
	}

	// learn hostname
	for addr := range tcps.addressbook {
		if addr.Call(tcps.learnHostname) == nil {
			break
		}
	}
	// request peers
	// TODO: maybe iterate until we have enough new peers?
	for addr := range tcps.addressbook {
		addr.Call(tcps.requestPeers)
	}
	// TODO: announce ourselves to new peers
	return
}
<|endoftext|>


<commit_before>package towerfall

import (
	"sort"
	"time"
)

type CompleteSnapshot map[string]*Snapshot

type Snapshot struct {
	Person *Person         `json:"person"`
	Total  *PlayerSnapshot `json:"total"`
	Rank   int             `json:"rank"`
	// The Tournaments map contains the same data structure, but
	// separated per tournament
	Tournaments map[string]*PlayerSnapshot `json:"tournaments"`
}

// A PlayerSnapshot is a sum of all total stats about a player
type PlayerSnapshot struct {
	Shots    int           `json:"shots"`
	Sweeps   int           `json:"sweeps"`
	Kills    int           `json:"kills"`
	Self     int           `json:"self"`
	Matches  int           `json:"matches"`
	Rounds   int           `json:"rounds"`
	Score    int           `json:"score"`
	Playtime time.Duration `json:"playtime"`
	Wins     int           `json:"wins"`
}

// NewSnapshot returns a full snapshot
func NewSnapshot(s *Server) CompleteSnapshot {
	ss := make(map[string]*Snapshot)
	s.DB.LoadPeople()
	for _, p := range s.DB.People {
		ss[p.ID] = &Snapshot{
			Person:      p,
			Tournaments: make(map[string]*PlayerSnapshot),
		}
	}

	// Calculate the per-tournament data points
	for _, t := range s.DB.Tournaments {
		tid := t.ID
		for _, m := range t.Matches {
			for _, p := range m.Players {
				pid := p.Person.ID
				if _, ok := ss[pid].Tournaments[tid]; !ok {
					ss[pid].Tournaments[tid] = &PlayerSnapshot{}
				}

				ss[pid].Tournaments[tid].Matches++
				ss[pid].Tournaments[tid].Rounds += len(m.Rounds)
				ss[pid].Tournaments[tid].Shots += p.Shots
				ss[pid].Tournaments[tid].Sweeps += p.Sweeps
				ss[pid].Tournaments[tid].Kills += p.Kills
				ss[pid].Tournaments[tid].Self += p.Self
				ss[pid].Tournaments[tid].Score += p.Score()
				ss[pid].Tournaments[tid].Playtime += m.Duration()
			}

		}

		// Only do the winner calculations if someone actually won
		if !t.Ended.IsZero() && len(t.Winners) > 0 {
			winner := t.Winners[0].Person.ID
			ss[winner].Tournaments[tid].Wins++
		}
	}

	// Summarize the per-tournament data points into the totals
	for pid := range ss {
		if ss[pid].Total == nil {
			ss[pid].Total = &PlayerSnapshot{}
		}

		for tid := range ss[pid].Tournaments {
			t := ss[pid].Tournaments[tid]

			ss[pid].Total.Matches += t.Matches
			ss[pid].Total.Rounds += t.Rounds
			ss[pid].Total.Shots += t.Shots
			ss[pid].Total.Sweeps += t.Sweeps
			ss[pid].Total.Kills += t.Kills
			ss[pid].Total.Self += t.Self
			ss[pid].Total.Score += t.Score
			ss[pid].Total.Playtime += t.Playtime
		}
	}

	// Add the Rank attribute to all the players
	ranked := make([]*Snapshot, len(ss))
	x := 0
	for _, p := range ss {
		ranked[x] = p
		x++
	}
	for x, p := range SortByRank(ranked) {
		ss[p.Person.ID].Rank = x + 1 // The +1 fixes zero-index.
	}

	return CompleteSnapshot(ss)
}

// ByRank is a sort.Interface that sorts players by tournament wins
// and then by total score.
type ByRank []*Snapshot

func (b ByRank) Len() int {
	return len(b)
}

func (b ByRank) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func (b ByRank) Less(i, j int) bool {
	// If a person is not actively playing, they are definitely less.
	if b[i].Person.Disabled != b[j].Person.Disabled {
		return b[j].Person.Disabled
	}

	if b[i].Total.Wins == b[j].Total.Wins {
		return b[i].Total.Score > b[j].Total.Score
	}

	return b[i].Total.Wins > b[j].Total.Wins
}

func SortByRank(ps []*Snapshot) []*Snapshot {
	sort.Sort(ByRank(ps))
	return ps
}
<commit_msg>Quick fix<commit_after>package towerfall

import (
	"fmt"
	"sort"
	"time"
)

type CompleteSnapshot map[string]*Snapshot

type Snapshot struct {
	Person *Person         `json:"person"`
	Total  *PlayerSnapshot `json:"total"`
	Rank   int             `json:"rank"`
	// The Tournaments map contains the same data structure, but
	// separated per tournament
	Tournaments map[string]*PlayerSnapshot `json:"tournaments"`
}

// A PlayerSnapshot is a sum of all total stats about a player
type PlayerSnapshot struct {
	Shots    int           `json:"shots"`
	Sweeps   int           `json:"sweeps"`
	Kills    int           `json:"kills"`
	Self     int           `json:"self"`
	Matches  int           `json:"matches"`
	Rounds   int           `json:"rounds"`
	Score    int           `json:"score"`
	Playtime time.Duration `json:"playtime"`
	Wins     int           `json:"wins"`
}

// NewSnapshot returns a full snapshot
func NewSnapshot(s *Server) CompleteSnapshot {
	ss := make(map[string]*Snapshot)
	s.DB.LoadPeople()
	for _, p := range s.DB.People {
		ss[p.ID] = &Snapshot{
			Person:      p,
			Tournaments: make(map[string]*PlayerSnapshot),
		}
	}

	// Calculate the per-tournament data points
	for _, t := range s.DB.Tournaments {
		tid := t.ID
		for _, m := range t.Matches {
			for _, p := range m.Players {
				pid := p.Person.ID
				if _, ok := ss[pid]; !ok {
					fmt.Println("Snapshot not set for player", p.Person)
					ss[p.Person.ID] = &Snapshot{
						Person:      p.Person,
						Tournaments: make(map[string]*PlayerSnapshot),
					}
				}
				if _, ok := ss[pid].Tournaments[tid]; !ok {
					ss[pid].Tournaments[tid] = &PlayerSnapshot{}
				}

				ss[pid].Tournaments[tid].Matches++
				ss[pid].Tournaments[tid].Rounds += len(m.Rounds)
				ss[pid].Tournaments[tid].Shots += p.Shots
				ss[pid].Tournaments[tid].Sweeps += p.Sweeps
				ss[pid].Tournaments[tid].Kills += p.Kills
				ss[pid].Tournaments[tid].Self += p.Self
				ss[pid].Tournaments[tid].Score += p.Score()
				ss[pid].Tournaments[tid].Playtime += m.Duration()
			}

		}

		// Only do the winner calculations if someone actually won
		if !t.Ended.IsZero() && len(t.Winners) > 0 {
			winner := t.Winners[0].Person.ID
			ss[winner].Tournaments[tid].Wins++
		}
	}

	// Summarize the per-tournament data points into the totals
	for pid := range ss {
		if ss[pid].Total == nil {
			ss[pid].Total = &PlayerSnapshot{}
		}

		for tid := range ss[pid].Tournaments {
			t := ss[pid].Tournaments[tid]

			ss[pid].Total.Matches += t.Matches
			ss[pid].Total.Rounds += t.Rounds
			ss[pid].Total.Shots += t.Shots
			ss[pid].Total.Sweeps += t.Sweeps
			ss[pid].Total.Kills += t.Kills
			ss[pid].Total.Self += t.Self
			ss[pid].Total.Score += t.Score
			ss[pid].Total.Playtime += t.Playtime
		}
	}

	// Add the Rank attribute to all the players
	ranked := make([]*Snapshot, len(ss))
	x := 0
	for _, p := range ss {
		ranked[x] = p
		x++
	}
	for x, p := range SortByRank(ranked) {
		ss[p.Person.ID].Rank = x + 1 // The +1 fixes zero-index.
	}

	return CompleteSnapshot(ss)
}

// ByRank is a sort.Interface that sorts players by tournament wins
// and then by total score.
type ByRank []*Snapshot

func (b ByRank) Len() int {
	return len(b)
}

func (b ByRank) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func (b ByRank) Less(i, j int) bool {
	// If a person is not actively playing, they are definitely less.
	if b[i].Person.Disabled != b[j].Person.Disabled {
		return b[j].Person.Disabled
	}

	if b[i].Total.Wins == b[j].Total.Wins {
		return b[i].Total.Score > b[j].Total.Score
	}

	return b[i].Total.Wins > b[j].Total.Wins
}

func SortByRank(ps []*Snapshot) []*Snapshot {
	sort.Sort(ByRank(ps))
	return ps
}
<|endoftext|>


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

package trace

import (
	"fmt"
	"time"
)

type (
	// TraceID is a 16-byte identifier for a set of spans.
	TraceID [16]byte
	// SpanID is an 8-byte identifier for a single span.
	SpanID [8]byte
)

func (t TraceID) String() string {
	return fmt.Sprintf("%02x", [16]byte(t))
}

func (s SpanID) String() string {
	return fmt.Sprintf("%02x", [8]byte(s))
}

// Annotation represents a text annotation with a set of attributes and a timestamp.
type Annotation struct {
	time.Time
	Message    string
	Attributes map[string]interface{}
}

// Attribute is an interface for attributes;
// it is implemented by BoolAttribute, IntAttribute, and StringAttribute.
type Attribute interface {
	isAttribute()
}

// BoolAttribute represents a bool-valued attribute.
type BoolAttribute struct {
	Key   string
	Value bool
}

func (b BoolAttribute) isAttribute() {}

// Int64Attribute represents an int64-valued attribute.
type Int64Attribute struct {
	Key   string
	Value int64
}

func (i Int64Attribute) isAttribute() {}

// StringAttribute represents a string-valued attribute.
type StringAttribute struct {
	Key   string
	Value string
}

func (s StringAttribute) isAttribute() {}

// LinkType specifies the relationship between the span that had the link
// added, and the linked span.
type LinkType int32

// LinkType values.
const (
	LinkTypeUnspecified LinkType = iota // The relationship of the two spans is unknown.
	LinkTypeChild                       // The current span is a child of the linked span.
	LinkTypeParent                      // The current span is the parent of the linked span.
)

// Link represents a reference from one span to another span.
type Link struct {
	TraceID
	SpanID
	Type LinkType
	// Attributes is a set of attributes on the link.
	Attributes map[string]interface{}
}

// MessageEventType specifies the type of message event.
type MessageEventType int32

// MessageEventType values.
const (
	MessageEventTypeUnspecified MessageEventType = iota // Unknown event type.
	MessageEventTypeSent                                // Indicates a sent RPC message.
	MessageEventTypeRecv                                // Indicates a received RPC message.
)

// MessageEvent represents an event describing a message sent or received on the network.
type MessageEvent struct {
	time.Time
	EventType            MessageEventType
	MessageID            int64
	UncompressedByteSize int64
	CompressedByteSize   int64
}

// Status is the status of a Span.
type Status struct {
	// Code is a status code.  Zero indicates success.
	//
	// If Code will be propagated to Google APIs, it ideally should be a value from
	// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto .
	Code    int32
	Message string
}
<commit_msg>trace: avoid excessive embedding (#320)<commit_after>// Copyright 2017, OpenCensus Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package trace

import (
	"fmt"
	"time"
)

type (
	// TraceID is a 16-byte identifier for a set of spans.
	TraceID [16]byte
	// SpanID is an 8-byte identifier for a single span.
	SpanID [8]byte
)

func (t TraceID) String() string {
	return fmt.Sprintf("%02x", [16]byte(t))
}

func (s SpanID) String() string {
	return fmt.Sprintf("%02x", [8]byte(s))
}

// Annotation represents a text annotation with a set of attributes and a timestamp.
type Annotation struct {
	Time       time.Time
	Message    string
	Attributes map[string]interface{}
}

// Attribute is an interface for attributes;
// it is implemented by BoolAttribute, IntAttribute, and StringAttribute.
type Attribute interface {
	isAttribute()
}

// BoolAttribute represents a bool-valued attribute.
type BoolAttribute struct {
	Key   string
	Value bool
}

func (b BoolAttribute) isAttribute() {}

// Int64Attribute represents an int64-valued attribute.
type Int64Attribute struct {
	Key   string
	Value int64
}

func (i Int64Attribute) isAttribute() {}

// StringAttribute represents a string-valued attribute.
type StringAttribute struct {
	Key   string
	Value string
}

func (s StringAttribute) isAttribute() {}

// LinkType specifies the relationship between the span that had the link
// added, and the linked span.
type LinkType int32

// LinkType values.
const (
	LinkTypeUnspecified LinkType = iota // The relationship of the two spans is unknown.
	LinkTypeChild                       // The current span is a child of the linked span.
	LinkTypeParent                      // The current span is the parent of the linked span.
)

// Link represents a reference from one span to another span.
type Link struct {
	TraceID TraceID
	SpanID  SpanID
	Type    LinkType
	// Attributes is a set of attributes on the link.
	Attributes map[string]interface{}
}

// MessageEventType specifies the type of message event.
type MessageEventType int32

// MessageEventType values.
const (
	MessageEventTypeUnspecified MessageEventType = iota // Unknown event type.
	MessageEventTypeSent                                // Indicates a sent RPC message.
	MessageEventTypeRecv                                // Indicates a received RPC message.
)

// MessageEvent represents an event describing a message sent or received on the network.
type MessageEvent struct {
	Time                 time.Time
	EventType            MessageEventType
	MessageID            int64
	UncompressedByteSize int64
	CompressedByteSize   int64
}

// Status is the status of a Span.
type Status struct {
	// Code is a status code.  Zero indicates success.
	//
	// If Code will be propagated to Google APIs, it ideally should be a value from
	// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto .
	Code    int32
	Message string
}
<|endoftext|>


<commit_before>// Package transfer provides the /transfers APIs
package transfer

import (
	"net/http"

	stripe "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/form"
)

// Client is used to invoke /transfers APIs.
type Client struct {
	B   stripe.Backend
	Key string
}

// New creates a new transfer.
func New(params *stripe.TransferParams) (*stripe.Transfer, error) {
	return getC().New(params)
}

// New creates a new transfer.
func (c Client) New(params *stripe.TransferParams) (*stripe.Transfer, error) {
	transfer := &stripe.Transfer{}
	err := c.B.Call(http.MethodPost, "/v1/transfers", c.Key, params, transfer)
	return transfer, err
}

// Get returns the details of a transfer.
func Get(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	return getC().Get(id, params)
}

// Get returns the details of a transfer.
func (c Client) Get(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	path := stripe.FormatURLPath("/v1/transfers/%s", id)
	transfer := &stripe.Transfer{}
	err := c.B.Call(http.MethodGet, path, c.Key, params, transfer)
	return transfer, err
}

// Update updates a transfer's properties.
func Update(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	return getC().Update(id, params)
}

// Update updates a transfer's properties.
func (c Client) Update(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	path := stripe.FormatURLPath("/v1/transfers/%s", id)
	transfer := &stripe.Transfer{}
	err := c.B.Call(http.MethodPost, path, c.Key, params, transfer)
	return transfer, err
}

// List returns a list of transfers.
func List(params *stripe.TransferListParams) *Iter {
	return getC().List(params)
}

// List returns a list of transfers.
func (c Client) List(listParams *stripe.TransferListParams) *Iter {
	return &Iter{stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListMeta, error) {
		list := &stripe.TransferList{}
		err := c.B.CallRaw(http.MethodGet, "/v1/transfers", c.Key, b, p, list)

		ret := make([]interface{}, len(list.Data))
		for i, v := range list.Data {
			ret[i] = v
		}

		return ret, list.ListMeta, err
	})}
}

// Iter is an iterator for transfers.
type Iter struct {
	*stripe.Iter
}

// Transfer returns the transfer which the iterator is currently pointing to.
func (i *Iter) Transfer() *stripe.Transfer {
	return i.Current().(*stripe.Transfer)
}

func getC() Client {
	return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key}
}
<commit_msg>CMCOM-2432 Fixing internal dependencies<commit_after>// Package transfer provides the /transfers APIs
package transfer

import (
	"net/http"

	stripe "github.com/channelmeter/stripe-go"
	"github.com/stripe/stripe-go/form"
)

// Client is used to invoke /transfers APIs.
type Client struct {
	B   stripe.Backend
	Key string
}

// New creates a new transfer.
func New(params *stripe.TransferParams) (*stripe.Transfer, error) {
	return getC().New(params)
}

// New creates a new transfer.
func (c Client) New(params *stripe.TransferParams) (*stripe.Transfer, error) {
	transfer := &stripe.Transfer{}
	err := c.B.Call(http.MethodPost, "/v1/transfers", c.Key, params, transfer)
	return transfer, err
}

// Get returns the details of a transfer.
func Get(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	return getC().Get(id, params)
}

// Get returns the details of a transfer.
func (c Client) Get(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	path := stripe.FormatURLPath("/v1/transfers/%s", id)
	transfer := &stripe.Transfer{}
	err := c.B.Call(http.MethodGet, path, c.Key, params, transfer)
	return transfer, err
}

// Update updates a transfer's properties.
func Update(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	return getC().Update(id, params)
}

// Update updates a transfer's properties.
func (c Client) Update(id string, params *stripe.TransferParams) (*stripe.Transfer, error) {
	path := stripe.FormatURLPath("/v1/transfers/%s", id)
	transfer := &stripe.Transfer{}
	err := c.B.Call(http.MethodPost, path, c.Key, params, transfer)
	return transfer, err
}

// List returns a list of transfers.
func List(params *stripe.TransferListParams) *Iter {
	return getC().List(params)
}

// List returns a list of transfers.
func (c Client) List(listParams *stripe.TransferListParams) *Iter {
	return &Iter{stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListMeta, error) {
		list := &stripe.TransferList{}
		err := c.B.CallRaw(http.MethodGet, "/v1/transfers", c.Key, b, p, list)

		ret := make([]interface{}, len(list.Data))
		for i, v := range list.Data {
			ret[i] = v
		}

		return ret, list.ListMeta, err
	})}
}

// Iter is an iterator for transfers.
type Iter struct {
	*stripe.Iter
}

// Transfer returns the transfer which the iterator is currently pointing to.
func (i *Iter) Transfer() *stripe.Transfer {
	return i.Current().(*stripe.Transfer)
}

func getC() Client {
	return Client{stripe.GetBackend(stripe.APIBackend), stripe.Key}
}
<|endoftext|>