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

package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/cactus/go-statsd-client/v4/statsd"
	flags "github.com/jessevdk/go-flags"
)

func main() {

	// command line flags
	var opts struct {
		HostPort  string        `long:"host" default:"127.0.0.1:8125" description:"host:port of statsd server"`
		Prefix    string        `long:"prefix" default:"test-client" description:"Statsd prefix"`
		StatType  string        `long:"type" default:"count" description:"stat type to send. Can be one of: timing, count, gauge"`
		StatValue int64         `long:"value" default:"1" description:"Value to send"`
		Name      string        `short:"n" long:"name" default:"counter" description:"stat name"`
		Rate      float32       `short:"r" long:"rate" default:"1.0" description:"sample rate"`
		Volume    int           `short:"c" long:"count" default:"1000" description:"Number of stats to send. Volume."`
		Nil       bool          `long:"nil" description:"Use nil client"`
		Buffered  bool          `long:"buffered" description:"Use a buffered client"`
		Duration  time.Duration `short:"d" long:"duration" default:"10s" description:"How long to spread the volume across. For each second of duration, volume/seconds events will be sent."`
	}

	// parse said flags
	_, err := flags.Parse(&opts)
	if err != nil {
		if e, ok := err.(*flags.Error); ok {
			if e.Type == flags.ErrHelp {
				os.Exit(0)
			}
		}
		fmt.Printf("Error: %+v\n", err)
		os.Exit(1)
	}

	if opts.Nil && opts.Buffered {
		fmt.Printf("Specifying both nil and buffered together is invalid\n")
		os.Exit(1)
	}

	if opts.Name == "" || statsd.CheckName(opts.Name) != nil {
		fmt.Printf("Stat name contains invalid characters\n")
		os.Exit(1)
	}

	if statsd.CheckName(opts.Prefix) != nil {
		fmt.Printf("Stat prefix contains invalid characters\n")
		os.Exit(1)
	}

	config := &statsd.ClientConfig{
		Address:     opts.HostPort,
		Prefix:      opts.Prefix,
		ResInterval: time.Duration(0),
	}

	var client statsd.Statter = (*statsd.Client)(nil)
	if !opts.Nil {
		if opts.Buffered {
			config.UseBuffered = true
			config.FlushInterval = opts.Duration / time.Duration(4)
			config.FlushBytes = 0
		}

		client, err = statsd.NewClientWithConfig(config)
		if err != nil {
			log.Fatal(err)
		}
		defer client.Close()
	}

	var stat func(stat string, value int64, rate float32) error
	switch opts.StatType {
	case "count":
		stat = func(stat string, value int64, rate float32) error {
			return client.Inc(stat, value, rate)
		}
	case "gauge":
		stat = func(stat string, value int64, rate float32) error {
			return client.Gauge(stat, value, rate)
		}
	case "timing":
		stat = func(stat string, value int64, rate float32) error {
			return client.Timing(stat, value, rate)
		}
	default:
		log.Fatal("Unsupported state type")
	}

	pertick := opts.Volume / int(opts.Duration.Seconds()) / 10
	// add some extra time, because the first tick takes a while
	ender := time.After(opts.Duration + 100*time.Millisecond)
	c := time.Tick(time.Second / 10)
	count := 0
	for {
		select {
		case <-c:
			for x := 0; x < pertick; x++ {
				err := stat(opts.Name, opts.StatValue, opts.Rate)
				if err != nil {
					log.Printf("Got Error: %+v\n", err)
					break
				}
				count++
			}
		case <-ender:
			log.Printf("%d events called\n", count)
			return
		}
	}
}
<commit_msg>fix test-client import<commit_after>// Copyright (c) 2012-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/cactus/go-statsd-client/v5/statsd"
	flags "github.com/jessevdk/go-flags"
)

func main() {

	// command line flags
	var opts struct {
		HostPort  string        `long:"host" default:"127.0.0.1:8125" description:"host:port of statsd server"`
		Prefix    string        `long:"prefix" default:"test-client" description:"Statsd prefix"`
		StatType  string        `long:"type" default:"count" description:"stat type to send. Can be one of: timing, count, gauge"`
		StatValue int64         `long:"value" default:"1" description:"Value to send"`
		Name      string        `short:"n" long:"name" default:"counter" description:"stat name"`
		Rate      float32       `short:"r" long:"rate" default:"1.0" description:"sample rate"`
		Volume    int           `short:"c" long:"count" default:"1000" description:"Number of stats to send. Volume."`
		Nil       bool          `long:"nil" description:"Use nil client"`
		Buffered  bool          `long:"buffered" description:"Use a buffered client"`
		Duration  time.Duration `short:"d" long:"duration" default:"10s" description:"How long to spread the volume across. For each second of duration, volume/seconds events will be sent."`
	}

	// parse said flags
	_, err := flags.Parse(&opts)
	if err != nil {
		if e, ok := err.(*flags.Error); ok {
			if e.Type == flags.ErrHelp {
				os.Exit(0)
			}
		}
		fmt.Printf("Error: %+v\n", err)
		os.Exit(1)
	}

	if opts.Nil && opts.Buffered {
		fmt.Printf("Specifying both nil and buffered together is invalid\n")
		os.Exit(1)
	}

	if opts.Name == "" || statsd.CheckName(opts.Name) != nil {
		fmt.Printf("Stat name contains invalid characters\n")
		os.Exit(1)
	}

	if statsd.CheckName(opts.Prefix) != nil {
		fmt.Printf("Stat prefix contains invalid characters\n")
		os.Exit(1)
	}

	config := &statsd.ClientConfig{
		Address:     opts.HostPort,
		Prefix:      opts.Prefix,
		ResInterval: time.Duration(0),
	}

	var client statsd.Statter = (*statsd.Client)(nil)
	if !opts.Nil {
		if opts.Buffered {
			config.UseBuffered = true
			config.FlushInterval = opts.Duration / time.Duration(4)
			config.FlushBytes = 0
		}

		client, err = statsd.NewClientWithConfig(config)
		if err != nil {
			log.Fatal(err)
		}
		defer client.Close()
	}

	var stat func(stat string, value int64, rate float32) error
	switch opts.StatType {
	case "count":
		stat = func(stat string, value int64, rate float32) error {
			return client.Inc(stat, value, rate)
		}
	case "gauge":
		stat = func(stat string, value int64, rate float32) error {
			return client.Gauge(stat, value, rate)
		}
	case "timing":
		stat = func(stat string, value int64, rate float32) error {
			return client.Timing(stat, value, rate)
		}
	default:
		log.Fatal("Unsupported state type")
	}

	pertick := opts.Volume / int(opts.Duration.Seconds()) / 10
	// add some extra time, because the first tick takes a while
	ender := time.After(opts.Duration + 100*time.Millisecond)
	c := time.Tick(time.Second / 10)
	count := 0
	for {
		select {
		case <-c:
			for x := 0; x < pertick; x++ {
				err := stat(opts.Name, opts.StatValue, opts.Rate)
				if err != nil {
					log.Printf("Got Error: %+v\n", err)
					break
				}
				count++
			}
		case <-ender:
			log.Printf("%d events called\n", count)
			return
		}
	}
}
<|endoftext|>


<commit_before>package securitygroup

import (
	"encoding/json"

	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_metadata"
	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/flag_helpers"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/codegangsta/cli"
)

type CreateSecurityGroup struct {
	ui                   terminal.UI
	appSecurityGroupRepo api.SecurityGroupRepo
	spaceRepo            api.SpaceRepository
	configRepo           configuration.Reader
}

func NewCreateSecurityGroup(ui terminal.UI, configRepo configuration.Reader, appSecurityGroupRepo api.SecurityGroupRepo, spaceRepo api.SpaceRepository) CreateSecurityGroup {
	return CreateSecurityGroup{
		ui:                   ui,
		configRepo:           configRepo,
		appSecurityGroupRepo: appSecurityGroupRepo,
		spaceRepo:            spaceRepo,
	}
}

func (cmd CreateSecurityGroup) Metadata() command_metadata.CommandMetadata {
	return command_metadata.CommandMetadata{
		Name:        "create-security-group",
		Description: "<<< description goes here >>>",
		Usage:       "CF_NAME create-security-group NAME",
		Flags: []cli.Flag{
			flag_helpers.NewStringFlag("rules", "Create Rules Everything Around Me"),
			flag_helpers.NewStringSliceFlag("space", "BOOM A SPACE IS HERE"),
		},
	}
}

func (cmd CreateSecurityGroup) GetRequirements(requirementsFactory requirements.Factory, context *cli.Context) ([]requirements.Requirement, error) {
	if len(context.Args()) != 1 {
		cmd.ui.FailWithUsage(context)
	}

	requirements := []requirements.Requirement{requirementsFactory.NewLoginRequirement()}
	return requirements, nil
}

func (cmd CreateSecurityGroup) Run(context *cli.Context) {
	name := context.Args()[0]
	rules := context.String("rules")
	spaces := context.StringSlice("space")
	spaceGuids := []string{}
	for _, spaceName := range spaces {
		space, err := cmd.spaceRepo.FindByName(spaceName)

		if err != nil {
			cmd.ui.Failed("Could not find space named '%s'", spaceName)
		}

		spaceGuids = append(spaceGuids, space.Guid)
	}

	ruleMaps := []map[string]string{}
	err := json.Unmarshal([]byte(rules), &ruleMaps)
	if err != nil {
		cmd.ui.Failed("Incorrect json format: %s", err.Error())
	}

	cmd.ui.Say("Creating application security group '%s' as '%s', applying to %d spaces", name, cmd.configRepo.Username(), len(spaceGuids))

	err = cmd.appSecurityGroupRepo.Create(name, ruleMaps, spaceGuids)
	if err != nil {
		cmd.ui.Failed(err.Error())
	}

	cmd.ui.Ok()
}
<commit_msg>Only parse rules if the user supplied any<commit_after>package securitygroup

import (
	"encoding/json"

	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_metadata"
	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/flag_helpers"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/codegangsta/cli"
)

type CreateSecurityGroup struct {
	ui                   terminal.UI
	appSecurityGroupRepo api.SecurityGroupRepo
	spaceRepo            api.SpaceRepository
	configRepo           configuration.Reader
}

func NewCreateSecurityGroup(ui terminal.UI, configRepo configuration.Reader, appSecurityGroupRepo api.SecurityGroupRepo, spaceRepo api.SpaceRepository) CreateSecurityGroup {
	return CreateSecurityGroup{
		ui:                   ui,
		configRepo:           configRepo,
		appSecurityGroupRepo: appSecurityGroupRepo,
		spaceRepo:            spaceRepo,
	}
}

func (cmd CreateSecurityGroup) Metadata() command_metadata.CommandMetadata {
	return command_metadata.CommandMetadata{
		Name:        "create-security-group",
		Description: "<<< description goes here >>>",
		Usage:       "CF_NAME create-security-group NAME",
		Flags: []cli.Flag{
			flag_helpers.NewStringFlag("rules", "Create Rules Everything Around Me"),
			flag_helpers.NewStringSliceFlag("space", "BOOM A SPACE IS HERE"),
		},
	}
}

func (cmd CreateSecurityGroup) GetRequirements(requirementsFactory requirements.Factory, context *cli.Context) ([]requirements.Requirement, error) {
	if len(context.Args()) != 1 {
		cmd.ui.FailWithUsage(context)
	}

	requirements := []requirements.Requirement{requirementsFactory.NewLoginRequirement()}
	return requirements, nil
}

func (cmd CreateSecurityGroup) Run(context *cli.Context) {
	name := context.Args()[0]
	rules := context.String("rules")
	spaces := context.StringSlice("space")
	spaceGuids := []string{}
	for _, spaceName := range spaces {
		space, err := cmd.spaceRepo.FindByName(spaceName)

		if err != nil {
			cmd.ui.Failed("Could not find space named '%s'", spaceName)
		}

		spaceGuids = append(spaceGuids, space.Guid)
	}

	ruleMaps := []map[string]string{}
	if rules != "" {
		err := json.Unmarshal([]byte(rules), &ruleMaps)
		if err != nil {
			cmd.ui.Failed("Incorrect json format: %s", err.Error())
		}
	}

	cmd.ui.Say("Creating application security group '%s' as '%s', applying to %d spaces", name, cmd.configRepo.Username(), len(spaceGuids))

	err := cmd.appSecurityGroupRepo.Create(name, ruleMaps, spaceGuids)
	if err != nil {
		cmd.ui.Failed(err.Error())
	}

	cmd.ui.Ok()
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"path/filepath"
)

const (
	CT_USER                  = "chrome-bot"
	NUM_WORKERS          int = 100
	WORKER_NAME_TEMPLATE     = "build%d-m5"
	GS_BUCKET_NAME           = "cluster-telemetry"
	GS_HTTP_LINK             = "https://storage.cloud.google.com/"
	LOGS_LINK_PREFIX         = "http://chromegw.corp.google.com/i/skia-ct-worker"

	// File names and dir names.
	TIMESTAMP_FILE_NAME             = "TIMESTAMP"
	CHROMIUM_BUILDS_DIR_NAME        = "chromium_builds"
	PAGESETS_DIR_NAME               = "page_sets"
	WEB_ARCHIVES_DIR_NAME           = "webpage_archives"
	SKPS_DIR_NAME                   = "skps"
	STORAGE_DIR_NAME                = "storage"
	REPO_DIR_NAME                   = "skia-repo"
	TASKS_DIR_NAME                  = "tasks"
	LUA_TASKS_DIR_NAME              = "lua_runs"
	BENCHMARK_TASKS_DIR_NAME        = "benchmark_runs"
	SKIA_CORRECTNESS_TASKS_DIR_NAME = "skia_correctness_runs"
	CHROMIUM_PERF_TASKS_DIR_NAME    = "chromium_perf_runs"
	FIX_ARCHIVE_TASKS_DIR_NAME      = "fix_archive_runs"

	// Limit the number of times CT tries to get a remote file before giving up.
	MAX_URI_GET_TRIES = 4

	// Activity constants.
	ACTIVITY_CREATING_PAGESETS        = "CREATING_PAGESETS"
	ACTIVITY_CAPTURING_ARCHIVES       = "CAPTURING_ARCHIVES"
	ACTIVITY_RUNNING_BENCHMARKS       = "RUNNING_BENCHMARKS"
	ACTIVITY_RUNNING_LUA_SCRIPTS      = "RUNNING_LUA_SCRIPTS"
	ACTIVITY_RUNNING_CHROMIUM_PERF    = "RUNNING_CHROMIUM_PERF"
	ACTIVITY_RUNNING_SKIA_CORRECTNESS = "RUNNING_SKIA_CORRECTNESS"
	ACTIVITY_FIXING_ARCHIVES          = "FIXING_ARCHIVES"

	// Pageset types supported by CT.
	PAGESET_TYPE_ALL        = "All"
	PAGESET_TYPE_10k        = "10k"
	PAGESET_TYPE_MOBILE_10k = "Mobile10k"
	PAGESET_TYPE_DUMMY_1k   = "Dummy1k" // Used for testing.

	// Names of binaries executed by CT.
	BINARY_CHROME          = "chrome"
	BINARY_RECORD_WPR      = "record_wpr"
	BINARY_RUN_BENCHMARK   = "ct_run_benchmark"
	BINARY_GCLIENT         = "gclient"
	BINARY_MAKE            = "make"
	BINARY_LUA_PICTURES    = "lua_pictures"
	BINARY_ADB             = "adb"
	BINARY_GIT             = "git"
	BINARY_RENDER_PICTURES = "render_pictures"
	BINARY_MAIL            = "mail"
	BINARY_LUA             = "lua"

	// Platforms supported by CT.
	PLATFORM_ANDROID = "Android"
	PLATFORM_LINUX   = "Linux"

	// Benchmarks supported by CT.
	BENCHMARK_DRAW_PROPERTIES   = "draw_properties"
	BENCHMARK_SKPICTURE_PRINTER = "skpicture_printer"
	BENCHMARK_RR                = "rasterize_and_record_micro"
	BENCHMARK_REPAINT           = "repaint"
	BENCHMARK_SMOOTHNESS        = "smoothness"

	// Webapp constants.
	WEBAPP_ROOT = "https://skia-tree-status.appspot.com/skia-telemetry/"

	// Logserver links. These are only accessible from Google corp.
	MASTER_LOGSERVER_LINK  = "http://chromegw.corp.google.com/i/skia-ct-master/"
	WORKERS_LOGSERVER_LINK = "http://chromegw.corp.google.com/i/skia-ct-master/all_logs"
)

type PagesetTypeInfo struct {
	NumPages                   int
	CSVSource                  string
	UserAgent                  string
	CaptureArchivesTimeoutSecs int
	CreatePagesetsTimeoutSecs  int
	RunBenchmarksTimeoutSecs   int
	RunChromiumPerfTimeoutSecs int
}

var (
	Master = fmt.Sprintf(WORKER_NAME_TEMPLATE, 101)
	Slaves = GetCTWorkers()

	// Email address of cluster telemetry admins. They will be notified everytime
	// a task has started and completed.
	CtAdmins = []string{"rmistry@google.com"}

	// Names of local directories and files.
	StorageDir           = filepath.Join("/", "b", STORAGE_DIR_NAME)
	RepoDir              = filepath.Join("/", "b", REPO_DIR_NAME)
	ChromiumBuildsDir    = filepath.Join(StorageDir, CHROMIUM_BUILDS_DIR_NAME)
	ChromiumSrcDir       = filepath.Join(StorageDir, "chromium", "src")
	TelemetryBinariesDir = filepath.Join(ChromiumSrcDir, "tools", "perf")
	TelemetrySrcDir      = filepath.Join(ChromiumSrcDir, "tools", "telemetry")
	TaskFileDir          = filepath.Join(StorageDir, "current_task")
	GSTokenPath          = filepath.Join(StorageDir, "google_storage_token.data")
	EmailTokenPath       = filepath.Join(StorageDir, "email.data")
	WebappPasswordPath   = filepath.Join(StorageDir, "webapp.data")
	PagesetsDir          = filepath.Join(StorageDir, PAGESETS_DIR_NAME)
	WebArchivesDir       = filepath.Join(StorageDir, WEB_ARCHIVES_DIR_NAME)
	SkpsDir              = filepath.Join(StorageDir, SKPS_DIR_NAME)
	GLogDir              = filepath.Join(StorageDir, "glog")
	ApkName              = "ChromeShell.apk"
	SkiaTreeDir          = filepath.Join(RepoDir, "trunk")
	CtTreeDir            = filepath.Join(RepoDir, "go", "src", "go.skia.org", "infra", "ct")

	// Names of remote directories and files.
	LuaRunsDir             = filepath.Join(TASKS_DIR_NAME, LUA_TASKS_DIR_NAME)
	BenchmarkRunsDir       = filepath.Join(TASKS_DIR_NAME, BENCHMARK_TASKS_DIR_NAME)
	SkiaCorrectnessRunsDir = filepath.Join(TASKS_DIR_NAME, SKIA_CORRECTNESS_TASKS_DIR_NAME)
	ChromiumPerfRunsDir    = filepath.Join(TASKS_DIR_NAME, CHROMIUM_PERF_TASKS_DIR_NAME)
	FixArchivesRunsDir     = filepath.Join(TASKS_DIR_NAME, FIX_ARCHIVE_TASKS_DIR_NAME)

	// Webapp subparts.
	AdminTasksWebapp                 = WEBAPP_ROOT + "admin_tasks"
	UpdateAdminTasksWebapp           = WEBAPP_ROOT + "update_admin_task"
	LuaTasksWebapp                   = WEBAPP_ROOT + "lua_script"
	UpdateLuaTasksWebapp             = WEBAPP_ROOT + "update_lua_task"
	BenchmarkTasksWebapp             = WEBAPP_ROOT
	UpdateBenchmarkTasksWebapp       = WEBAPP_ROOT + "update_telemetry_task"
	ChromiumPerfTasksWebapp          = WEBAPP_ROOT + "chromium_try"
	UpdateChromiumPerfTasksWebapp    = WEBAPP_ROOT + "update_chromium_try_tasks"
	SkiaCorrectnessTasksWebapp       = WEBAPP_ROOT + "skia_try"
	UpdateSkiaCorrectnessTasksWebapp = WEBAPP_ROOT + "update_skia_try_task"
	ChromiumBuildTasksWebapp         = WEBAPP_ROOT + "chromium_builds"
	UpdateChromiumBuildTasksWebapp   = WEBAPP_ROOT + "update_chromium_build_tasks"

	// Information about the different CT benchmarks.
	BenchmarksToPagesetName = map[string]string{
		BENCHMARK_DRAW_PROPERTIES:   "DrawPropertiesCTPages",
		BENCHMARK_SKPICTURE_PRINTER: "SkpicturePrinter",
		BENCHMARK_RR:                "RasterizeAndRecordMicroCTPages",
		BENCHMARK_REPAINT:           "RepaintCTPages",
		BENCHMARK_SMOOTHNESS:        "SmoothnessCTPages",
	}

	// Information about the different CT pageset types.
	PagesetTypeToInfo = map[string]*PagesetTypeInfo{
		PAGESET_TYPE_ALL: &PagesetTypeInfo{
			NumPages:                   1000000,
			CSVSource:                  "csv/top-1m.csv",
			UserAgent:                  "desktop",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
		PAGESET_TYPE_10k: &PagesetTypeInfo{
			NumPages:                   10000,
			CSVSource:                  "csv/top-1m.csv",
			UserAgent:                  "desktop",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
		PAGESET_TYPE_MOBILE_10k: &PagesetTypeInfo{
			NumPages:                   10000,
			CSVSource:                  "csv/android-top-1m.csv",
			UserAgent:                  "mobile",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
		PAGESET_TYPE_DUMMY_1k: &PagesetTypeInfo{
			NumPages:                   1000,
			CSVSource:                  "csv/android-top-1m.csv",
			UserAgent:                  "mobile",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
	}
)
<commit_msg>Use uberchromegw for CT logs<commit_after>package util

import (
	"fmt"
	"path/filepath"
)

const (
	CT_USER                  = "chrome-bot"
	NUM_WORKERS          int = 100
	WORKER_NAME_TEMPLATE     = "build%d-m5"
	GS_BUCKET_NAME           = "cluster-telemetry"
	GS_HTTP_LINK             = "https://storage.cloud.google.com/"
	LOGS_LINK_PREFIX         = "http://uberchromegw.corp.google.com/i/skia-ct-worker"

	// File names and dir names.
	TIMESTAMP_FILE_NAME             = "TIMESTAMP"
	CHROMIUM_BUILDS_DIR_NAME        = "chromium_builds"
	PAGESETS_DIR_NAME               = "page_sets"
	WEB_ARCHIVES_DIR_NAME           = "webpage_archives"
	SKPS_DIR_NAME                   = "skps"
	STORAGE_DIR_NAME                = "storage"
	REPO_DIR_NAME                   = "skia-repo"
	TASKS_DIR_NAME                  = "tasks"
	LUA_TASKS_DIR_NAME              = "lua_runs"
	BENCHMARK_TASKS_DIR_NAME        = "benchmark_runs"
	SKIA_CORRECTNESS_TASKS_DIR_NAME = "skia_correctness_runs"
	CHROMIUM_PERF_TASKS_DIR_NAME    = "chromium_perf_runs"
	FIX_ARCHIVE_TASKS_DIR_NAME      = "fix_archive_runs"

	// Limit the number of times CT tries to get a remote file before giving up.
	MAX_URI_GET_TRIES = 4

	// Activity constants.
	ACTIVITY_CREATING_PAGESETS        = "CREATING_PAGESETS"
	ACTIVITY_CAPTURING_ARCHIVES       = "CAPTURING_ARCHIVES"
	ACTIVITY_RUNNING_BENCHMARKS       = "RUNNING_BENCHMARKS"
	ACTIVITY_RUNNING_LUA_SCRIPTS      = "RUNNING_LUA_SCRIPTS"
	ACTIVITY_RUNNING_CHROMIUM_PERF    = "RUNNING_CHROMIUM_PERF"
	ACTIVITY_RUNNING_SKIA_CORRECTNESS = "RUNNING_SKIA_CORRECTNESS"
	ACTIVITY_FIXING_ARCHIVES          = "FIXING_ARCHIVES"

	// Pageset types supported by CT.
	PAGESET_TYPE_ALL        = "All"
	PAGESET_TYPE_10k        = "10k"
	PAGESET_TYPE_MOBILE_10k = "Mobile10k"
	PAGESET_TYPE_DUMMY_1k   = "Dummy1k" // Used for testing.

	// Names of binaries executed by CT.
	BINARY_CHROME          = "chrome"
	BINARY_RECORD_WPR      = "record_wpr"
	BINARY_RUN_BENCHMARK   = "ct_run_benchmark"
	BINARY_GCLIENT         = "gclient"
	BINARY_MAKE            = "make"
	BINARY_LUA_PICTURES    = "lua_pictures"
	BINARY_ADB             = "adb"
	BINARY_GIT             = "git"
	BINARY_RENDER_PICTURES = "render_pictures"
	BINARY_MAIL            = "mail"
	BINARY_LUA             = "lua"

	// Platforms supported by CT.
	PLATFORM_ANDROID = "Android"
	PLATFORM_LINUX   = "Linux"

	// Benchmarks supported by CT.
	BENCHMARK_DRAW_PROPERTIES   = "draw_properties"
	BENCHMARK_SKPICTURE_PRINTER = "skpicture_printer"
	BENCHMARK_RR                = "rasterize_and_record_micro"
	BENCHMARK_REPAINT           = "repaint"
	BENCHMARK_SMOOTHNESS        = "smoothness"

	// Webapp constants.
	WEBAPP_ROOT = "https://skia-tree-status.appspot.com/skia-telemetry/"

	// Logserver links. These are only accessible from Google corp.
	MASTER_LOGSERVER_LINK  = "http://uberchromegw.corp.google.com/i/skia-ct-master/"
	WORKERS_LOGSERVER_LINK = "http://uberchromegw.corp.google.com/i/skia-ct-master/all_logs"
)

type PagesetTypeInfo struct {
	NumPages                   int
	CSVSource                  string
	UserAgent                  string
	CaptureArchivesTimeoutSecs int
	CreatePagesetsTimeoutSecs  int
	RunBenchmarksTimeoutSecs   int
	RunChromiumPerfTimeoutSecs int
}

var (
	Master = fmt.Sprintf(WORKER_NAME_TEMPLATE, 101)
	Slaves = GetCTWorkers()

	// Email address of cluster telemetry admins. They will be notified everytime
	// a task has started and completed.
	CtAdmins = []string{"rmistry@google.com"}

	// Names of local directories and files.
	StorageDir           = filepath.Join("/", "b", STORAGE_DIR_NAME)
	RepoDir              = filepath.Join("/", "b", REPO_DIR_NAME)
	ChromiumBuildsDir    = filepath.Join(StorageDir, CHROMIUM_BUILDS_DIR_NAME)
	ChromiumSrcDir       = filepath.Join(StorageDir, "chromium", "src")
	TelemetryBinariesDir = filepath.Join(ChromiumSrcDir, "tools", "perf")
	TelemetrySrcDir      = filepath.Join(ChromiumSrcDir, "tools", "telemetry")
	TaskFileDir          = filepath.Join(StorageDir, "current_task")
	GSTokenPath          = filepath.Join(StorageDir, "google_storage_token.data")
	EmailTokenPath       = filepath.Join(StorageDir, "email.data")
	WebappPasswordPath   = filepath.Join(StorageDir, "webapp.data")
	PagesetsDir          = filepath.Join(StorageDir, PAGESETS_DIR_NAME)
	WebArchivesDir       = filepath.Join(StorageDir, WEB_ARCHIVES_DIR_NAME)
	SkpsDir              = filepath.Join(StorageDir, SKPS_DIR_NAME)
	GLogDir              = filepath.Join(StorageDir, "glog")
	ApkName              = "ChromeShell.apk"
	SkiaTreeDir          = filepath.Join(RepoDir, "trunk")
	CtTreeDir            = filepath.Join(RepoDir, "go", "src", "go.skia.org", "infra", "ct")

	// Names of remote directories and files.
	LuaRunsDir             = filepath.Join(TASKS_DIR_NAME, LUA_TASKS_DIR_NAME)
	BenchmarkRunsDir       = filepath.Join(TASKS_DIR_NAME, BENCHMARK_TASKS_DIR_NAME)
	SkiaCorrectnessRunsDir = filepath.Join(TASKS_DIR_NAME, SKIA_CORRECTNESS_TASKS_DIR_NAME)
	ChromiumPerfRunsDir    = filepath.Join(TASKS_DIR_NAME, CHROMIUM_PERF_TASKS_DIR_NAME)
	FixArchivesRunsDir     = filepath.Join(TASKS_DIR_NAME, FIX_ARCHIVE_TASKS_DIR_NAME)

	// Webapp subparts.
	AdminTasksWebapp                 = WEBAPP_ROOT + "admin_tasks"
	UpdateAdminTasksWebapp           = WEBAPP_ROOT + "update_admin_task"
	LuaTasksWebapp                   = WEBAPP_ROOT + "lua_script"
	UpdateLuaTasksWebapp             = WEBAPP_ROOT + "update_lua_task"
	BenchmarkTasksWebapp             = WEBAPP_ROOT
	UpdateBenchmarkTasksWebapp       = WEBAPP_ROOT + "update_telemetry_task"
	ChromiumPerfTasksWebapp          = WEBAPP_ROOT + "chromium_try"
	UpdateChromiumPerfTasksWebapp    = WEBAPP_ROOT + "update_chromium_try_tasks"
	SkiaCorrectnessTasksWebapp       = WEBAPP_ROOT + "skia_try"
	UpdateSkiaCorrectnessTasksWebapp = WEBAPP_ROOT + "update_skia_try_task"
	ChromiumBuildTasksWebapp         = WEBAPP_ROOT + "chromium_builds"
	UpdateChromiumBuildTasksWebapp   = WEBAPP_ROOT + "update_chromium_build_tasks"

	// Information about the different CT benchmarks.
	BenchmarksToPagesetName = map[string]string{
		BENCHMARK_DRAW_PROPERTIES:   "DrawPropertiesCTPages",
		BENCHMARK_SKPICTURE_PRINTER: "SkpicturePrinter",
		BENCHMARK_RR:                "RasterizeAndRecordMicroCTPages",
		BENCHMARK_REPAINT:           "RepaintCTPages",
		BENCHMARK_SMOOTHNESS:        "SmoothnessCTPages",
	}

	// Information about the different CT pageset types.
	PagesetTypeToInfo = map[string]*PagesetTypeInfo{
		PAGESET_TYPE_ALL: &PagesetTypeInfo{
			NumPages:                   1000000,
			CSVSource:                  "csv/top-1m.csv",
			UserAgent:                  "desktop",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
		PAGESET_TYPE_10k: &PagesetTypeInfo{
			NumPages:                   10000,
			CSVSource:                  "csv/top-1m.csv",
			UserAgent:                  "desktop",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
		PAGESET_TYPE_MOBILE_10k: &PagesetTypeInfo{
			NumPages:                   10000,
			CSVSource:                  "csv/android-top-1m.csv",
			UserAgent:                  "mobile",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
		PAGESET_TYPE_DUMMY_1k: &PagesetTypeInfo{
			NumPages:                   1000,
			CSVSource:                  "csv/android-top-1m.csv",
			UserAgent:                  "mobile",
			CreatePagesetsTimeoutSecs:  60,
			CaptureArchivesTimeoutSecs: 300,
			RunBenchmarksTimeoutSecs:   300,
			RunChromiumPerfTimeoutSecs: 150,
		},
	}
)
<|endoftext|>


<commit_before>package qy

import (
	"strings"

	"github.com/bigwhite/gowechat/pb"
)

const (
	sendURL = "https://qyapi.weixin.qq.com/cgi-bin/message/send"
)

type SendMsgTextPkg struct {
	pb.SendMsgTextPkg
	ToParty string `json:"toparty,omitempty"`
	ToTag   string `json:"totag,omitempty"`
	AgentID string `json:"agentid"`
	Safe    string `json:"safe,omitempty"`
}

type SendMsgImagePkg struct {
	pb.SendMsgImagePkg
	ToParty string `json:"toparty,omitempty"`
	ToTag   string `json:"totag,omitempty"`
	AgentID string `json:"agentid"`
	Safe    string `json:"safe,omitempty"`
}

type Artical struct {
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	Url         string `json:"url,omitempty"`
	PicUrl      string `json:"picurl,omitempty"`
}

type SendMsgNewsPkg struct {
	ToUserName string    `json:"touser"`
	ToParty    string    `json:"toparty,omitempty"`
	ToTag      string    `json:"totag,omitempty"`
	MsgType    string    `json:"msgtype"`
	AgentID    string    `json:"agentid"`
	Articals   []Artical `json:"articals"`
}

func SendMsg(accessToken string, pkg interface{}) error {
	r := strings.Join([]string{sendURL, "?access_token=", accessToken}, "")
	return pb.SendMsg(r, pkg)
}
<commit_msg>fix bug in send news msg of qy<commit_after>package qy

import (
	"strings"

	"github.com/bigwhite/gowechat/pb"
)

const (
	sendURL = "https://qyapi.weixin.qq.com/cgi-bin/message/send"
)

type SendMsgTextPkg struct {
	pb.SendMsgTextPkg
	ToParty string `json:"toparty,omitempty"`
	ToTag   string `json:"totag,omitempty"`
	AgentID string `json:"agentid"`
	Safe    string `json:"safe,omitempty"`
}

type SendMsgImagePkg struct {
	pb.SendMsgImagePkg
	ToParty string `json:"toparty,omitempty"`
	ToTag   string `json:"totag,omitempty"`
	AgentID string `json:"agentid"`
	Safe    string `json:"safe,omitempty"`
}

type Artical struct {
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	Url         string `json:"url,omitempty"`
	PicUrl      string `json:"picurl,omitempty"`
}

type SendMsgNewsPkg struct {
	ToUserName string    `json:"touser"`
	ToParty    string    `json:"toparty,omitempty"`
	ToTag      string    `json:"totag,omitempty"`
	MsgType    string    `json:"msgtype"`
	AgentID    string    `json:"agentid"`
	News       []Artical `json:"news"`
}

func SendMsg(accessToken string, pkg interface{}) error {
	r := strings.Join([]string{sendURL, "?access_token=", accessToken}, "")
	return pb.SendMsg(r, pkg)
}
<|endoftext|>


<commit_before>package main

/*
#cgo CFLAGS: -I/usr/include
#cgo LDFLAGS: -lcwiid -Lcwiid/libcwiid/libcwiid.a
#include "racerwiigo.h"
#include <stdlib.h>
#include <cwiid.h>
#include <time.h>
#include <bluetooth/bluetooth.h>
*/
import "C"

import (
	"encoding/csv"
	"fmt"
	"html/template"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

var buttons = []_Ctype_uint16_t{ // only HOME and A buttons are used for this program
	C.CWIID_BTN_A,
	//C.CWIID_BTN_B,
	//C.CWIID_BTN_1,
	//C.CWIID_BTN_2,
	//C.CWIID_BTN_MINUS,
	C.CWIID_BTN_HOME,
	//C.CWIID_BTN_LEFT,
	//C.CWIID_BTN_RIGHT,
	//C.CWIID_BTN_DOWN,
	//C.CWIID_BTN_UP,
	//C.CWIID_BTN_PLUS,
}

var buttonStatus []bool

var buttonChan chan _Ctype_uint16_t
var exit chan bool
var callback = goCwiidCallback // so it's not garbage collected
var errCallback = goErrCallback
var start *time.Time
var entries map[uint]*Entry // map of Bib #s
var results []*Result
var raceResultsTemplate *template.Template
var useWiimote = false

type HumanDuration time.Duration

type Entry struct {
	Bib    uint
	Fname  string
	Lname  string
	Male   bool
	Age    uint
	Result *Result
}

type Result struct {
	Time  HumanDuration
	Place uint
	Entry *Entry
}

func (hd HumanDuration) String() string {
	seconds := time.Duration(hd).Seconds()
	seconds -= float64(time.Duration(hd) / time.Minute * 60)
	return fmt.Sprintf("%#02d:%#02d:%05.2f", time.Duration(hd)/time.Hour, time.Duration(hd)/time.Minute%60, seconds)
}

func (hd HumanDuration) Clock() string {
	return fmt.Sprintf("%#02d:%#02d:%02d", time.Duration(hd)/time.Hour, time.Duration(hd)/time.Minute%60, time.Duration(hd)/time.Second%60)
}

//export goCwiidCallback
func goCwiidCallback(wm unsafe.Pointer, a int, mesg *C.struct_cwiid_btn_mesg, tp unsafe.Pointer) {
	//defer C.free(unsafe.Pointer(mesg))
	var messages []C.struct_cwiid_btn_mesg
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&messages)))
	sliceHeader.Cap = a
	sliceHeader.Len = a
	sliceHeader.Data = uintptr(unsafe.Pointer(mesg))
	for _, m := range messages {
		if m._type != C.CWIID_MESG_BTN {
			exit <- true
			continue
		}
		//fmt.Printf("Received message - %#v\n", m)
		for x, button := range buttons {
			if m.buttons&button == button {
				if !buttonStatus[x] {
					buttonChan <- button
					buttonStatus[x] = true
				}
			} else {
				buttonStatus[x] = false
			}
		}
	}
}

//export goErrCallback
func goErrCallback(wm unsafe.Pointer, char *C.char, ap unsafe.Pointer) {
	//func goErrCallback(wm *C.cwiid_wiimote_t, char *C.char, ap C.va_list) {s
	str := C.GoString(char)
	switch str {
	case "No Bluetooth interface found":
		fallthrough
	case "no such device":
		fmt.Printf("No Bluetooth device found\n")
		os.Exit(1)
	case "Socket connect error (control channel)":
		fallthrough
	case "No wiimotes found":
		exit <- true
	default:
		fmt.Printf("Inside error calback - %s\n", str)
	}
}

func uploadRacers(w http.ResponseWriter, r *http.Request) {
	reader, err := r.MultipartReader()
	if err != nil {
		fmt.Fprintf(w, "Error getting Reader - %s", err)
		return
	}
	part, err := reader.NextPart()
	if err != nil {
		fmt.Fprintf(w, "Error getting Part - %s", err)
		return
	}
	csvIn := csv.NewReader(part)
	rawEntries, err := csvIn.ReadAll()
	if err != nil {
		fmt.Fprintf(w, "Error Reading CSV file - %s", err)
		return
	}
	if len(rawEntries) <= 1 {
		fmt.Fprintf(w, "Either blank file or only supplied the header row")
		return
	}
	// make the map and unlink all previous relationships (if any)
	entries = make(map[uint]*Entry)
	for _, result := range results {
		result.Entry = nil
	}
	for row := 1; row < len(rawEntries); row++ {
		entry := new(Entry)
		for col := range rawEntries[row] {
			switch rawEntries[0][col] {
			case "Fname":
				entry.Fname = rawEntries[row][col]
			case "Lname":
				entry.Lname = rawEntries[row][col]
			case "Age":
				tmpAge, _ := strconv.Atoi(rawEntries[row][col])
				entry.Age = uint(tmpAge)
			case "Gender":
				entry.Male = (rawEntries[row][col] == "M")
			case "Bib":
				tmpBib, _ := strconv.Atoi(rawEntries[row][col])
				entry.Bib = uint(tmpBib)
			default:
				fmt.Printf("Field %s not imported, dropping\n", rawEntries[0][col])
			}
		}
		fmt.Printf("Read entry - %v", entry)
		fmt.Printf("CSV Input = %v", rawEntries[row])
		if entry.Bib != 0 {
			entries[entry.Bib] = entry
		} else {
			fmt.Printf("Skipping due to no bib assigned - %v", entry)
		}
	}
	http.Redirect(w, r, "/admin", 301)
	return
}

func bibHandler(w http.ResponseWriter, r *http.Request) {
	next, err := strconv.Atoi(r.FormValue("next"))
	if err != nil || next > len(results) {
		fmt.Fprintf(w, "Error %s getting next", err)
		return
	}
	tempBib, err := strconv.Atoi(r.FormValue("bib"))
	if tempBib < 0 {
		fmt.Fprintf(w, "Cannot assign a negative bib number of %d", tempBib)
		return
	}
	bib := uint(tempBib)
	if err == nil {
		if _, ok := entries[bib]; ok {
			results[next-1].Entry = entries[bib]
			entries[bib].Result = results[next-1]
			fmt.Printf("Set bib for place %d to %d", next, bib)
		} else {
			fmt.Fprintf(w, "Bib number %d was not assigned to anyone.", bib)
			return
		}
	} else {
		fmt.Printf("Error %s setting bib for place %d to %d", err, next, bib)
	}
	http.Redirect(w, r, "/admin", 301)
	return
}

func handler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"Racers": results}
	if start != nil {
		diff := time.Since(*start)
		data["Start"] = start.Format("3:04:05")
		data["Time"] = HumanDuration(diff).Clock()
		data["Seconds"] = fmt.Sprintf("%.0f", diff.Seconds())
		data["NextUpdate"] = diff / time.Millisecond % 1000
		if strings.HasSuffix(r.RequestURI, "admin") {
			data["Admin"] = true
			for x := range results {
				if results[x].Entry == nil {
					data["Next"] = results[x].Place
					break
				}
			}
		}
	}
	raceResultsTemplate, err := template.ParseFiles("raceResults.template")
	if err != nil {
		fmt.Fprintf(w, "Error parsing template - %s", err)
	} else {
		err = raceResultsTemplate.Execute(w, data)
		if err != nil {
			fmt.Fprintf(w, "Error executing template - %s", err)
		}
	}
}

func main() {
	var err error
	raceResultsTemplate, err = template.ParseFiles("raceResults.template")
	if err != nil {
		fmt.Printf("Error parsing template! - %s\n", err)
		return
	}
	go raceFunc()
	http.HandleFunc("/", handler)
	http.HandleFunc("/admin", handler)
	http.HandleFunc("/bib", bibHandler)
	http.HandleFunc("/uploadRacers", uploadRacers)
	err = http.ListenAndServe(":80", nil)
	if err != nil {
		fmt.Printf("Error starting http server! - %s\n", err)
		err = http.ListenAndServe(":8080", nil)
		if err != nil {
			fmt.Printf("Error starting http server! - %s\n", err)
			return
		}
	}
}

func raceFunc() {
	buttonStatus = make([]bool, len(buttons))
	var bdaddr C.bdaddr_t
	var wm *C.struct_cwiid_wiimote_t
	buttonChan = make(chan _Ctype_uint16_t, 1)
	exit = make(chan bool, 1)
	ticker := time.NewTicker(time.Second)
	results = make([]*Result, 0, 1024)
	var err error
	if useWiimote {
		val, err := C.cwiid_set_err(C.getErrCallback())
		if val != 0 || err != nil {
			fmt.Printf("Error setting the callback to catch errors - %d - %v", val, err)
			os.Exit(1)
		}
	}
	for {
	outer:
		for {
			// clear both channels
			select {
			case <-buttonChan:
			case <-exit:
			default:
				break outer
			}
		}
		fmt.Println("Press 1&2 on the Wiimote now")
		if useWiimote {
			wm, err = C.cwiid_open(&bdaddr, 0)
			if err != nil {
				fmt.Errorf("cwiid_open: %v\n", err)
				continue
			}

			res, err := C.cwiid_command(wm, C.CWIID_CMD_RPT_MODE, C.CWIID_RPT_BTN)
			if res != 0 || err != nil {
				fmt.Printf("Result of command = %d - %v\n", res, err)
			}

			res, err = C.cwiid_set_mesg_callback(wm, C.getCwiidCallback())
			if res != 0 || err != nil {
				fmt.Printf("Result of callback = %d - %v\n", res, err)
			}
			res, err = C.cwiid_enable(wm, C.CWIID_FLAG_MESG_IFC)
			if res != 0 || err != nil {
				fmt.Printf("Result of enable = %d - %v\n", res, err)
			}

			res, err = C.cwiid_set_led(wm, C.CWIID_LED4_ON)
			if res != 0 || err != nil {
				fmt.Printf("Set led result = %d\n", res)
				fmt.Errorf("Err = %v", err)
			}
		} else { // simulate the pressing of the wiimote A button for testing
			go func() {
				simulButton := time.NewTicker(time.Second * 10)
				//buttonChan <- C.CWIID_BTN_A // start race immediately
				//buttonChan <- C.CWIID_BTN_A // first runner! :)
				for {
					select {
					case <-simulButton.C:
						buttonChan <- C.CWIID_BTN_A
					}
				}
			}()
		}
	loop:
		for {
			select {
			case <-exit:
				fmt.Println("Wiimote lost connection!")
				break loop
			case button := <-buttonChan:
				switch button {
				case C.CWIID_BTN_A:
					if start == nil {
						start = new(time.Time)
						*start = time.Now()
						fmt.Printf("Race started @ %s\n", start.Format("3:04:05"))
						results = results[:0]
					} else {
						place := len(results)
						results = append(results, &Result{Place: uint(place + 1), Time: HumanDuration(time.Now().Sub(*start))})
						fmt.Printf("#%d - %s\n", results[place].Place, results[place].Time)
					}
				//case C.CWIID_BTN_B:
				//	fmt.Println("B")
				//case C.CWIID_BTN_1:
				//	fmt.Println("1")
				//case C.CWIID_BTN_2:
				//	fmt.Println("2")
				//case C.CWIID_BTN_MINUS:
				//	fmt.Println("Minus")
				case C.CWIID_BTN_HOME:
					fmt.Println("Race finished!")
					return
					//case C.CWIID_BTN_LEFT:
					//	fmt.Println("Left")
					//case C.CWIID_BTN_RIGHT:
					//	fmt.Println("Right")
					//case C.CWIID_BTN_DOWN:
					//	fmt.Println("Down")
					//case C.CWIID_BTN_UP:
					//	fmt.Println("Up")
					//case C.CWIID_BTN_PLUS:
					//	fmt.Println("Plus")
				}
			case now := <-ticker.C:
				if start != nil {
					diff := HumanDuration(now.Sub(*start))
					fmt.Println(diff)
				}
				// update the clock
			}
		}
	}
}
<commit_msg>have the webserver run at www.raceresults.org for a captive portal<commit_after>package main

/*
#cgo CFLAGS: -I/usr/include
#cgo LDFLAGS: -lcwiid -Lcwiid/libcwiid/libcwiid.a
#include "racerwiigo.h"
#include <stdlib.h>
#include <cwiid.h>
#include <time.h>
#include <bluetooth/bluetooth.h>
*/
import "C"

import (
	"encoding/csv"
	"fmt"
	"html/template"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

var buttons = []_Ctype_uint16_t{ // only HOME and A buttons are used for this program
	C.CWIID_BTN_A,
	//C.CWIID_BTN_B,
	//C.CWIID_BTN_1,
	//C.CWIID_BTN_2,
	//C.CWIID_BTN_MINUS,
	C.CWIID_BTN_HOME,
	//C.CWIID_BTN_LEFT,
	//C.CWIID_BTN_RIGHT,
	//C.CWIID_BTN_DOWN,
	//C.CWIID_BTN_UP,
	//C.CWIID_BTN_PLUS,
}

var buttonStatus []bool

var buttonChan chan _Ctype_uint16_t
var exit chan bool
var callback = goCwiidCallback // so it's not garbage collected
var errCallback = goErrCallback
var start *time.Time
var entries map[uint]*Entry // map of Bib #s
var results []*Result
var raceResultsTemplate *template.Template
var useWiimote = false

type HumanDuration time.Duration

type Entry struct {
	Bib    uint
	Fname  string
	Lname  string
	Male   bool
	Age    uint
	Result *Result
}

type Result struct {
	Time  HumanDuration
	Place uint
	Entry *Entry
}

func (hd HumanDuration) String() string {
	seconds := time.Duration(hd).Seconds()
	seconds -= float64(time.Duration(hd) / time.Minute * 60)
	return fmt.Sprintf("%#02d:%#02d:%05.2f", time.Duration(hd)/time.Hour, time.Duration(hd)/time.Minute%60, seconds)
}

func (hd HumanDuration) Clock() string {
	return fmt.Sprintf("%#02d:%#02d:%02d", time.Duration(hd)/time.Hour, time.Duration(hd)/time.Minute%60, time.Duration(hd)/time.Second%60)
}

//export goCwiidCallback
func goCwiidCallback(wm unsafe.Pointer, a int, mesg *C.struct_cwiid_btn_mesg, tp unsafe.Pointer) {
	//defer C.free(unsafe.Pointer(mesg))
	var messages []C.struct_cwiid_btn_mesg
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&messages)))
	sliceHeader.Cap = a
	sliceHeader.Len = a
	sliceHeader.Data = uintptr(unsafe.Pointer(mesg))
	for _, m := range messages {
		if m._type != C.CWIID_MESG_BTN {
			exit <- true
			continue
		}
		//fmt.Printf("Received message - %#v\n", m)
		for x, button := range buttons {
			if m.buttons&button == button {
				if !buttonStatus[x] {
					buttonChan <- button
					buttonStatus[x] = true
				}
			} else {
				buttonStatus[x] = false
			}
		}
	}
}

//export goErrCallback
func goErrCallback(wm unsafe.Pointer, char *C.char, ap unsafe.Pointer) {
	//func goErrCallback(wm *C.cwiid_wiimote_t, char *C.char, ap C.va_list) {s
	str := C.GoString(char)
	switch str {
	case "No Bluetooth interface found":
		fallthrough
	case "no such device":
		fmt.Printf("No Bluetooth device found\n")
		os.Exit(1)
	case "Socket connect error (control channel)":
		fallthrough
	case "No wiimotes found":
		exit <- true
	default:
		fmt.Printf("Inside error calback - %s\n", str)
	}
}

func uploadRacers(w http.ResponseWriter, r *http.Request) {
	reader, err := r.MultipartReader()
	if err != nil {
		fmt.Fprintf(w, "Error getting Reader - %s", err)
		return
	}
	part, err := reader.NextPart()
	if err != nil {
		fmt.Fprintf(w, "Error getting Part - %s", err)
		return
	}
	csvIn := csv.NewReader(part)
	rawEntries, err := csvIn.ReadAll()
	if err != nil {
		fmt.Fprintf(w, "Error Reading CSV file - %s", err)
		return
	}
	if len(rawEntries) <= 1 {
		fmt.Fprintf(w, "Either blank file or only supplied the header row")
		return
	}
	// make the map and unlink all previous relationships (if any)
	entries = make(map[uint]*Entry)
	for _, result := range results {
		result.Entry = nil
	}
	for row := 1; row < len(rawEntries); row++ {
		entry := new(Entry)
		for col := range rawEntries[row] {
			switch rawEntries[0][col] {
			case "Fname":
				entry.Fname = rawEntries[row][col]
			case "Lname":
				entry.Lname = rawEntries[row][col]
			case "Age":
				tmpAge, _ := strconv.Atoi(rawEntries[row][col])
				entry.Age = uint(tmpAge)
			case "Gender":
				entry.Male = (rawEntries[row][col] == "M")
			case "Bib":
				tmpBib, _ := strconv.Atoi(rawEntries[row][col])
				entry.Bib = uint(tmpBib)
			default:
				fmt.Printf("Field %s not imported, dropping\n", rawEntries[0][col])
			}
		}
		fmt.Printf("Read entry - %v", entry)
		fmt.Printf("CSV Input = %v", rawEntries[row])
		if entry.Bib != 0 {
			entries[entry.Bib] = entry
		} else {
			fmt.Printf("Skipping due to no bib assigned - %v", entry)
		}
	}
	http.Redirect(w, r, "/admin", 301)
	return
}

func bibHandler(w http.ResponseWriter, r *http.Request) {
	next, err := strconv.Atoi(r.FormValue("next"))
	if err != nil || next > len(results) {
		fmt.Fprintf(w, "Error %s getting next", err)
		return
	}
	tempBib, err := strconv.Atoi(r.FormValue("bib"))
	if tempBib < 0 {
		fmt.Fprintf(w, "Cannot assign a negative bib number of %d", tempBib)
		return
	}
	bib := uint(tempBib)
	if err == nil {
		if _, ok := entries[bib]; ok {
			results[next-1].Entry = entries[bib]
			entries[bib].Result = results[next-1]
			fmt.Printf("Set bib for place %d to %d", next, bib)
		} else {
			fmt.Fprintf(w, "Bib number %d was not assigned to anyone.", bib)
			return
		}
	} else {
		fmt.Printf("Error %s setting bib for place %d to %d", err, next, bib)
	}
	http.Redirect(w, r, "/admin", 301)
	return
}

func handler(w http.ResponseWriter, r *http.Request) {
	data := map[string]interface{}{"Racers": results}
	if start != nil {
		diff := time.Since(*start)
		data["Start"] = start.Format("3:04:05")
		data["Time"] = HumanDuration(diff).Clock()
		data["Seconds"] = fmt.Sprintf("%.0f", diff.Seconds())
		data["NextUpdate"] = diff / time.Millisecond % 1000
		if strings.HasSuffix(r.RequestURI, "admin") {
			data["Admin"] = true
			for x := range results {
				if results[x].Entry == nil {
					data["Next"] = results[x].Place
					break
				}
			}
		}
	}
	raceResultsTemplate, err := template.ParseFiles("raceResults.template")
	if err != nil {
		fmt.Fprintf(w, "Error parsing template - %s", err)
	} else {
		err = raceResultsTemplate.Execute(w, data)
		if err != nil {
			fmt.Fprintf(w, "Error executing template - %s", err)
		}
	}
}

func main() {
	var err error
	raceResultsTemplate, err = template.ParseFiles("raceResults.template")
	if err != nil {
		fmt.Printf("Error parsing template! - %s\n", err)
		return
	}
	go raceFunc()
	http.HandleFunc("www.raceresults.org/", handler)
	http.HandleFunc("www.raceresults.org/admin", handler)
	http.HandleFunc("www.raceresults.org/bib", bibHandler)
	http.HandleFunc("www.raceresults.org/uploadRacers", uploadRacers)
	http.Handle("/", http.RedirectHandler("http://www.raceresults.org/", 307))
	err = http.ListenAndServe(":80", nil)
	if err != nil {
		fmt.Printf("Error starting http server! - %s\n", err)
		err = http.ListenAndServe(":8080", nil)
		if err != nil {
			fmt.Printf("Error starting http server! - %s\n", err)
			return
		}
	}
}

func raceFunc() {
	buttonStatus = make([]bool, len(buttons))
	var bdaddr C.bdaddr_t
	var wm *C.struct_cwiid_wiimote_t
	buttonChan = make(chan _Ctype_uint16_t, 1)
	exit = make(chan bool, 1)
	ticker := time.NewTicker(time.Second)
	results = make([]*Result, 0, 1024)
	var err error
	if useWiimote {
		val, err := C.cwiid_set_err(C.getErrCallback())
		if val != 0 || err != nil {
			fmt.Printf("Error setting the callback to catch errors - %d - %v", val, err)
			os.Exit(1)
		}
	}
	for {
	outer:
		for {
			// clear both channels
			select {
			case <-buttonChan:
			case <-exit:
			default:
				break outer
			}
		}
		fmt.Println("Press 1&2 on the Wiimote now")
		if useWiimote {
			wm, err = C.cwiid_open(&bdaddr, 0)
			if err != nil {
				fmt.Errorf("cwiid_open: %v\n", err)
				continue
			}

			res, err := C.cwiid_command(wm, C.CWIID_CMD_RPT_MODE, C.CWIID_RPT_BTN)
			if res != 0 || err != nil {
				fmt.Printf("Result of command = %d - %v\n", res, err)
			}

			res, err = C.cwiid_set_mesg_callback(wm, C.getCwiidCallback())
			if res != 0 || err != nil {
				fmt.Printf("Result of callback = %d - %v\n", res, err)
			}
			res, err = C.cwiid_enable(wm, C.CWIID_FLAG_MESG_IFC)
			if res != 0 || err != nil {
				fmt.Printf("Result of enable = %d - %v\n", res, err)
			}

			res, err = C.cwiid_set_led(wm, C.CWIID_LED4_ON)
			if res != 0 || err != nil {
				fmt.Printf("Set led result = %d\n", res)
				fmt.Errorf("Err = %v", err)
			}
		} else { // simulate the pressing of the wiimote A button for testing
			go func() {
				simulButton := time.NewTicker(time.Second * 10)
				buttonChan <- C.CWIID_BTN_A // start race immediately
				//buttonChan <- C.CWIID_BTN_A // first runner! :)
				for {
					select {
					case <-simulButton.C:
						buttonChan <- C.CWIID_BTN_A
					}
				}
			}()
		}
	loop:
		for {
			select {
			case <-exit:
				fmt.Println("Wiimote lost connection!")
				break loop
			case button := <-buttonChan:
				switch button {
				case C.CWIID_BTN_A:
					if start == nil {
						start = new(time.Time)
						*start = time.Now()
						fmt.Printf("Race started @ %s\n", start.Format("3:04:05"))
						results = results[:0]
					} else {
						place := len(results)
						results = append(results, &Result{Place: uint(place + 1), Time: HumanDuration(time.Now().Sub(*start))})
						fmt.Printf("#%d - %s\n", results[place].Place, results[place].Time)
					}
				//case C.CWIID_BTN_B:
				//	fmt.Println("B")
				//case C.CWIID_BTN_1:
				//	fmt.Println("1")
				//case C.CWIID_BTN_2:
				//	fmt.Println("2")
				//case C.CWIID_BTN_MINUS:
				//	fmt.Println("Minus")
				case C.CWIID_BTN_HOME:
					fmt.Println("Race finished!")
					return
					//case C.CWIID_BTN_LEFT:
					//	fmt.Println("Left")
					//case C.CWIID_BTN_RIGHT:
					//	fmt.Println("Right")
					//case C.CWIID_BTN_DOWN:
					//	fmt.Println("Down")
					//case C.CWIID_BTN_UP:
					//	fmt.Println("Up")
					//case C.CWIID_BTN_PLUS:
					//	fmt.Println("Plus")
				}
			case now := <-ticker.C:
				if start != nil {
					diff := HumanDuration(now.Sub(*start))
					fmt.Println(diff)
				}
				// update the clock
			}
		}
	}
}
<|endoftext|>


<commit_before>// Package raft implements raft.
package raft

import "code.google.com/p/go.net/context"

type stateResp struct {
	state       State
	ents, cents []Entry
	msgs        []Message
}

type Node struct {
	ctx    context.Context
	propc  chan []byte
	recvc  chan Message
	statec chan stateResp
	tickc  chan struct{}
}

func Start(ctx context.Context, name string, election, heartbeat int) *Node {
	n := &Node{
		ctx:    ctx,
		propc:  make(chan []byte),
		recvc:  make(chan Message),
		statec: make(chan stateResp),
		tickc:  make(chan struct{}),
	}
	r := &raft{
		name:      name,
		election:  election,
		heartbeat: heartbeat,
	}
	go n.run(r)
	return n
}

func (n *Node) run(r *raft) {
	propc := n.propc

	for {
		if r.hasLeader() {
			propc = n.propc
		} else {
			// We cannot accept proposals because we don't know who
			// to send them to, so we'll apply back-pressure and
			// block senders.
			propc = nil
		}

		sr := stateResp{
			r.State,
			r.raftLog.unstableEnts(),
			r.raftLog.nextEnts(),
			r.msgs,
		}

		select {
		case p := <-propc:
			r.propose(p)
		case m := <-n.recvc:
			r.Step(m) // raft never returns an error
		case <-n.tickc:
			// r.tick()
		case n.statec <- sr:
			r.raftLog.resetNextEnts()
			r.raftLog.resetUnstable()
			r.msgs = nil
		case <-n.ctx.Done():
			return
		}
	}
}

func (n *Node) Tick() error {
	select {
	case n.tickc <- struct{}{}:
		return nil
	case <-n.ctx.Done():
		return n.ctx.Err()
	}
}

// Propose proposes data be appended to the log.
func (n *Node) Propose(data []byte) error {
	select {
	case n.propc <- data:
		return nil
	case <-n.ctx.Done():
		return n.ctx.Err()
	}
}

// Step advances the state machine using m.
func (n *Node) Step(m Message) error {
	select {
	case n.recvc <- m:
		return nil
	case <-n.ctx.Done():
		return n.ctx.Err()
	}
}

// ReadState returns the current point-in-time state.
func (n *Node) ReadState() (st State, ents, cents []Entry, msgs []Message, err error) {
	select {
	case sr := <-n.statec:
		return sr.state, sr.ents, sr.cents, sr.msgs, nil
	case <-n.ctx.Done():
		return State{}, nil, nil, nil, n.ctx.Err()
	}
}
<commit_msg>raft: block ReadState until state updates<commit_after>// Package raft implements raft.
package raft

import "code.google.com/p/go.net/context"

type stateResp struct {
	state       State
	ents, cents []Entry
	msgs        []Message
}

func (sr stateResp) containsUpdates(prev stateResp) bool {
	return !prev.state.Equal(sr.state) || len(sr.ents) > 0 || len(sr.cents) > 0 || len(sr.msgs) > 0
}

type Node struct {
	ctx    context.Context
	propc  chan []byte
	recvc  chan Message
	statec chan stateResp
	tickc  chan struct{}
}

func Start(ctx context.Context, name string, election, heartbeat int) *Node {
	n := &Node{
		ctx:    ctx,
		propc:  make(chan []byte),
		recvc:  make(chan Message),
		statec: make(chan stateResp),
		tickc:  make(chan struct{}),
	}
	r := &raft{
		name:      name,
		election:  election,
		heartbeat: heartbeat,
	}
	go n.run(r)
	return n
}

func (n *Node) run(r *raft) {
	propc := n.propc
	statec := n.statec

	var prev stateResp
	for {
		if r.hasLeader() {
			propc = n.propc
		} else {
			// We cannot accept proposals because we don't know who
			// to send them to, so we'll apply back-pressure and
			// block senders.
			propc = nil
		}

		sr := stateResp{
			r.State,
			r.raftLog.unstableEnts(),
			r.raftLog.nextEnts(),
			r.msgs,
		}

		if sr.containsUpdates(prev) {
			statec = n.statec
		} else {
			statec = nil
		}

		select {
		case p := <-propc:
			r.propose(p)
		case m := <-n.recvc:
			r.Step(m) // raft never returns an error
		case <-n.tickc:
			// r.tick()
		case statec <- sr:
			r.raftLog.resetNextEnts()
			r.raftLog.resetUnstable()
			r.msgs = nil
		case <-n.ctx.Done():
			return
		}
	}
}

func (n *Node) Tick() error {
	select {
	case n.tickc <- struct{}{}:
		return nil
	case <-n.ctx.Done():
		return n.ctx.Err()
	}
}

// Propose proposes data be appended to the log.
func (n *Node) Propose(data []byte) error {
	select {
	case n.propc <- data:
		return nil
	case <-n.ctx.Done():
		return n.ctx.Err()
	}
}

// Step advances the state machine using m.
func (n *Node) Step(m Message) error {
	select {
	case n.recvc <- m:
		return nil
	case <-n.ctx.Done():
		return n.ctx.Err()
	}
}

// ReadState returns the current point-in-time state.
func (n *Node) ReadState() (st State, ents, cents []Entry, msgs []Message, err error) {
	select {
	case sr := <-n.statec:
		return sr.state, sr.ents, sr.cents, sr.msgs, nil
	case <-n.ctx.Done():
		return State{}, nil, nil, nil, n.ctx.Err()
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 The CUE 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 load

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"testing"

	build "cuelang.org/go/cue/build"
	"cuelang.org/go/internal/str"
)

// TestLoad is an end-to-end test.
func TestLoad(t *testing.T) {
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err)
	}
	args := str.StringList
	testCases := []struct {
		args []string
		want string
		err  string
	}{{
		args: nil,
		want: "test: test.cue (1 files)",
	}, {
		args: args("."),
		want: "test: test.cue (1 files)",
	}, {
		args: args("./other/..."),
		want: `
main: other/main.cue (1 files)
	file: other/file/file.cue (1 files);main: other/main.cue (1 files)
	file: other/file/file.cue (1 files)`,
	}, {
		args: args("./anon"),
		want: ":  (0 files)",
		err:  "build constraints exclude all CUE files",
	}, {
		args: args("./other"),
		want: `
main: other/main.cue (1 files)
	file: other/file/file.cue (1 files)`,
	}, {
		args: args("./hello"),
		want: "test: test.cue hello/test.cue (2 files)",
	}, {
		args: args("./anon.cue", "./other/anon.cue"),
		want: ": ./anon.cue ./other/anon.cue (2 files)",
	}, {
		// Absolute file is normalized.
		args: args(filepath.Join(cwd, "testdata", "anon.cue")),
		want: ": ./anon.cue (1 files)",
	}, {
		args: args("non-existing"),
		want: ":  (0 files)",
		err:  `cannot find package "non-existing"`,
	}, {
		args: args("./empty"),
		want: ":  (0 files)",
		err:  `no CUE files in ./empty`,
	}, {
		args: args("./imports"),
		want: `
imports: imports/imports.cue (1 files)
	catch: pkg/acme.com/catch/catch.cue (1 files)`,
		err: ``,
	}}
	for i, tc := range testCases {
		t.Run(strconv.Itoa(i)+"/"+strings.Join(tc.args, ":"), func(t *testing.T) {
			c := &Config{Dir: filepath.Join(cwd, testdata)}
			pkgs := Instances(tc.args, c)

			var errs, data []string
			for _, p := range pkgs {
				if p.Err != nil {
					errs = append(errs, p.Err.Error())
				}
				got := strings.TrimSpace(pkgInfo(pkgs[0]))
				data = append(data, got)
			}

			if err := strings.Join(errs, ";"); err == "" != (tc.err == "") ||
				err != "" && !strings.Contains(err, tc.err) {
				t.Errorf("error:\n got: %v\nwant: %v", err, tc.err)
			}
			got := strings.Join(data, ";")
			want := strings.TrimSpace(tc.want)
			if got != want {
				t.Errorf("got:\n%v\nwant:\n%v", got, want)
			}
		})
	}
}

func pkgInfo(p *build.Instance) string {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "%s: %s (%d files)\n",
		p.PkgName, strings.Join(p.CUEFiles, " "), len(p.Files))
	for _, p := range p.Imports {
		fmt.Fprintf(b, "\t%s\n", pkgInfo(p))
	}
	return b.String()
}
<commit_msg>cue/load: make test OS-independent<commit_after>// Copyright 2018 The CUE 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 load

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"testing"

	build "cuelang.org/go/cue/build"
	"cuelang.org/go/internal/str"
)

// TestLoad is an end-to-end test.
func TestLoad(t *testing.T) {
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err)
	}
	args := str.StringList
	testCases := []struct {
		args []string
		want string
		err  string
	}{{
		args: nil,
		want: "test: test.cue (1 files)",
	}, {
		args: args("."),
		want: "test: test.cue (1 files)",
	}, {
		args: args("./other/..."),
		want: `
main: other/main.cue (1 files)
	file: other/file/file.cue (1 files);main: other/main.cue (1 files)
	file: other/file/file.cue (1 files)`,
	}, {
		args: args("./anon"),
		want: ":  (0 files)",
		err:  "build constraints exclude all CUE files",
	}, {
		args: args("./other"),
		want: `
main: other/main.cue (1 files)
	file: other/file/file.cue (1 files)`,
	}, {
		args: args("./hello"),
		want: "test: test.cue hello/test.cue (2 files)",
	}, {
		args: args("./anon.cue", "./other/anon.cue"),
		want: ": ./anon.cue ./other/anon.cue (2 files)",
	}, {
		// Absolute file is normalized.
		args: args(filepath.Join(cwd, "testdata", "anon.cue")),
		want: ": ./anon.cue (1 files)",
	}, {
		args: args("non-existing"),
		want: ":  (0 files)",
		err:  `cannot find package "non-existing"`,
	}, {
		args: args("./empty"),
		want: ":  (0 files)",
		err:  `no CUE files in ./empty`,
	}, {
		args: args("./imports"),
		want: `
imports: imports/imports.cue (1 files)
	catch: pkg/acme.com/catch/catch.cue (1 files)`,
		err: ``,
	}}
	for i, tc := range testCases {
		t.Run(strconv.Itoa(i)+"/"+strings.Join(tc.args, ":"), func(t *testing.T) {
			c := &Config{Dir: filepath.Join(cwd, testdata)}
			pkgs := Instances(tc.args, c)

			var errs, data []string
			for _, p := range pkgs {
				if p.Err != nil {
					errs = append(errs, p.Err.Error())
				}
				got := strings.TrimSpace(pkgInfo(pkgs[0]))
				data = append(data, got)
			}

			if err := strings.Join(errs, ";"); err == "" != (tc.err == "") ||
				err != "" && !strings.Contains(err, tc.err) {
				t.Errorf("error:\n got: %v\nwant: %v", err, tc.err)
			}
			got := strings.Join(data, ";")
			// Make test work with Windows.
			got = strings.Replace(got, string(filepath.Separator), "/", -1)
			want := strings.TrimSpace(tc.want)
			if got != want {
				t.Errorf("got:\n%v\nwant:\n%v", got, want)
			}
		})
	}
}

func pkgInfo(p *build.Instance) string {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "%s: %s (%d files)\n",
		p.PkgName, strings.Join(p.CUEFiles, " "), len(p.Files))
	for _, p := range p.Imports {
		fmt.Fprintf(b, "\t%s\n", pkgInfo(p))
	}
	return b.String()
}
<|endoftext|>


<commit_before>package v6

import (
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/translatableerror"
)

type CreateUserProvidedServiceCommand struct {
	RequiredArgs    flag.ServiceInstance `positional-args:"yes"`
	SyslogDrainURL  string               `short:"l" description:"URL to which logs for bound applications will be streamed"`
	Credentials     string               `short:"p" description:"Credentials, provided inline or in a file, to be exposed in the VCAP_SERVICES environment variable for bound applications"`
	RouteServiceURL string               `short:"r" description:"URL to which requests for bound routes will be forwarded. Scheme for this URL must be https"`
	Tags            string               `short:"t" description:"User provided tags"`
	usage           interface{}          `usage:"CF_NAME create-user-provided-service SERVICE_INSTANCE [-p CREDENTIALS] [-l SYSLOG_DRAIN_URL] [-r ROUTE_SERVICE_URL] [-t TAGS]\n\n   Pass comma separated credential parameter names to enable interactive mode:\n   CF_NAME create-user-provided-service SERVICE_INSTANCE -p \"comma, separated, parameter, names\"\n\n   Pass credential parameters as JSON to create a service non-interactively:\n   CF_NAME create-user-provided-service SERVICE_INSTANCE -p '{\"key1\":\"value1\",\"key2\":\"value2\"}'\n\n   Specify a path to a file containing JSON:\n   CF_NAME create-user-provided-service SERVICE_INSTANCE -p PATH_TO_FILE\n\nEXAMPLES:\n   CF_NAME create-user-provided-service my-db-mine -p \"username, password\"\n   CF_NAME create-user-provided-service my-db-mine -p /path/to/credentials.json\n   CF_NAME create-user-provided-service my-db-mine -t \"list, of, tags\"\n   CF_NAME create-user-provided-service my-drain-service -l syslog://example.com\n   CF_NAME create-user-provided-service my-route-service -r https://example.com\n\n   Linux/Mac:\n      CF_NAME create-user-provided-service my-db-mine -p '{\"username\":\"admin\",\"password\":\"pa55woRD\"}'\n\n   Windows Command Line:\n      CF_NAME create-user-provided-service my-db-mine -p \"{\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\"pa55woRD\\\"}\"\n\n   Windows PowerShell:\n      CF_NAME create-user-provided-service my-db-mine -p '{\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\"pa55woRD\\\"}'"`
	relatedCommands interface{}          `related_commands:"bind-service, services"`
}

func (CreateUserProvidedServiceCommand) Setup(config command.Config, ui command.UI) error {
	return nil
}

func (CreateUserProvidedServiceCommand) Execute(args []string) error {
	return translatableerror.UnrefactoredCommandError{}
}
<commit_msg>Remove v6 create-user-provided-service<commit_after><|endoftext|>


<commit_before>package v2_test

import (
	"errors"

	"code.cloudfoundry.org/cli/actors/v2actions"
	"code.cloudfoundry.org/cli/commands/commandsfakes"
	"code.cloudfoundry.org/cli/commands/v2"
	"code.cloudfoundry.org/cli/commands/v2/common"
	"code.cloudfoundry.org/cli/commands/v2/v2fakes"
	"code.cloudfoundry.org/cli/utils/configv3"
	"code.cloudfoundry.org/cli/utils/ui"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
)

var _ = Describe("DeletedOrphanedRoutes Command", func() {
	var (
		cmd        v2.DeleteOrphanedRoutesCommand
		fakeUI     *ui.UI
		fakeActor  *v2fakes.FakeDeleteOrphanedRoutesActor
		fakeConfig *commandsfakes.FakeConfig
		input      *Buffer
		executeErr error
	)

	BeforeEach(func() {
		input = NewBuffer()
		out := NewBuffer()
		fakeUI = ui.NewTestUI(input, out, out)
		fakeActor = new(v2fakes.FakeDeleteOrphanedRoutesActor)
		fakeConfig = new(commandsfakes.FakeConfig)
		fakeConfig.ExperimentalReturns(true)

		cmd = v2.DeleteOrphanedRoutesCommand{
			UI:     fakeUI,
			Actor:  fakeActor,
			Config: fakeConfig,
		}
	})

	JustBeforeEach(func() {
		executeErr = cmd.Execute(nil)
	})

	It("Displays the experimental warning message", func() {
		Expect(fakeUI.Out).To(Say(v2.ExperimentalWarning))
	})

	Context("when checking that the api endpoint is set, the user is logged in, and an org and space are targeted", func() {
		BeforeEach(func() {
			fakeConfig.BinaryNameReturns("faceman")
		})

		It("returns an error if the check fails", func() {
			Expect(executeErr).To(MatchError(common.NoAPISetError{
				BinaryName: "faceman",
			}))
		})
	})

	Context("when the api endpoint is set, the user is logged in, and an org and space are targeted", func() {
		BeforeEach(func() {
			fakeConfig.TargetReturns("some-url")
			fakeConfig.AccessTokenReturns("some-access-token")
			fakeConfig.RefreshTokenReturns("some-refresh-token")
			fakeConfig.TargetedOrganizationReturns(configv3.Organization{
				GUID: "some-org-guid",
				Name: "some-org",
			})
			fakeConfig.TargetedSpaceReturns(configv3.Space{
				GUID: "some-space-guid",
				Name: "some-space",
			})
		})

		Context("when the '-f' flag is provided", func() {
			BeforeEach(func() {
				cmd.Force = true
			})

			It("does not prompt for user confirmation", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(fakeUI.Out).ToNot(Say("Really delete orphaned routes\\?>> \\[yN\\]:"))
			})
		})

		Context("when the '-f' flag is not provided", func() {
			Context("when user is prompted for confirmation", func() {
				BeforeEach(func() {
					input.Write([]byte("\n"))
				})

				It("displays the interactive prompt", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeUI.Out).To(Say("Really delete orphaned routes\\?>> \\[yN\\]:"))
				})
			})

			Context("when the user inputs no", func() {
				BeforeEach(func() {
					input.Write([]byte("n\n"))
				})

				It("does not delete orphaned routes", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeActor.GetOrphanedRoutesBySpaceCallCount()).To(Equal(0))
					Expect(fakeActor.DeleteRouteByGUIDCallCount()).To(Equal(0))
				})
			})

			Context("when the user inputs yes", func() {
				var routes []v2actions.Route

				BeforeEach(func() {
					fakeConfig.CurrentUserReturns(configv3.User{
						Name: "some-user",
					}, nil)

					input.Write([]byte("y\n"))

					routes = []v2actions.Route{
						{
							GUID:   "route-1-guid",
							Host:   "route-1",
							Domain: "bosh-lite.com",
							Path:   "path",
						},
						{
							GUID:   "route-2-guid",
							Host:   "route-2",
							Domain: "bosh-lite.com",
						},
					}

					fakeActor.GetOrphanedRoutesBySpaceReturns(routes, nil, nil)
				})

				Context("when getting the current user returns an error", func() {
					var err error

					BeforeEach(func() {
						err = errors.New("getting current user error")
						fakeConfig.CurrentUserReturns(configv3.User{}, err)
					})

					It("returns the error", func() {
						Expect(executeErr).To(MatchError(err))
					})
				})

				It("displays getting routes message", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeUI.Out).To(Say("Getting routes as some-user ...\n"))
				})

				It("deletes the routes and displays that they are deleted", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeActor.GetOrphanedRoutesBySpaceCallCount()).To(Equal(1))
					Expect(fakeActor.GetOrphanedRoutesBySpaceArgsForCall(0)).To(Equal("some-space-guid"))
					Expect(fakeActor.DeleteRouteByGUIDCallCount()).To(Equal(2))
					Expect(fakeActor.DeleteRouteByGUIDArgsForCall(0)).To(Equal(routes[0].GUID))
					Expect(fakeActor.DeleteRouteByGUIDArgsForCall(1)).To(Equal(routes[1].GUID))

					Expect(fakeUI.Out).To(Say("Deleting route route-1.bosh-lite.com/path..."))
					Expect(fakeUI.Out).To(Say("Deleting route route-2.bosh-lite.com..."))
					Expect(fakeUI.Out).To(Say("OK"))
				})

				Context("when there are warnings", func() {
					BeforeEach(func() {
						fakeActor.GetOrphanedRoutesBySpaceReturns([]v2actions.Route{
							{GUID: "some-route-guid"},
						}, []string{"foo", "bar"}, nil)
						fakeActor.DeleteRouteByGUIDReturns([]string{"baz"}, nil)
					})

					It("displays the warnings", func() {
						Expect(executeErr).ToNot(HaveOccurred())

						Expect(fakeUI.Err).To(Say("foo"))
						Expect(fakeUI.Err).To(Say("bar"))
						Expect(fakeUI.Err).To(Say("baz"))
					})
				})

				Context("when getting the routes returns an error", func() {
					var expectedErr error

					BeforeEach(func() {
						expectedErr = errors.New("getting orphaned routes error")
						fakeActor.GetOrphanedRoutesBySpaceReturns(nil, nil, expectedErr)
					})

					It("returns the error", func() {
						Expect(executeErr).To(MatchError(expectedErr))
					})
				})

				Context("when deleting a route returns an error", func() {
					var expectedErr error

					BeforeEach(func() {
						expectedErr = errors.New("deleting route error")
						fakeActor.GetOrphanedRoutesBySpaceReturns([]v2actions.Route{
							{GUID: "some-route-guid"},
						}, nil, nil)
						fakeActor.DeleteRouteByGUIDReturns(nil, expectedErr)
					})

					It("returns the error", func() {
						Expect(executeErr).To(MatchError(expectedErr))
					})
				})
			})
		})
	})
})
<commit_msg>update the delete-orphaned-routes tests after rebase with master<commit_after>package v2_test

import (
	"errors"

	"code.cloudfoundry.org/cli/actors/v2actions"
	"code.cloudfoundry.org/cli/commands/commandsfakes"
	"code.cloudfoundry.org/cli/commands/v2"
	"code.cloudfoundry.org/cli/commands/v2/common"
	"code.cloudfoundry.org/cli/commands/v2/v2fakes"
	"code.cloudfoundry.org/cli/utils/configv3"
	"code.cloudfoundry.org/cli/utils/ui"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
)

var _ = Describe("DeletedOrphanedRoutes Command", func() {
	var (
		cmd        v2.DeleteOrphanedRoutesCommand
		fakeUI     *ui.UI
		fakeActor  *v2fakes.FakeDeleteOrphanedRoutesActor
		fakeConfig *commandsfakes.FakeConfig
		input      *Buffer
		executeErr error
	)

	BeforeEach(func() {
		input = NewBuffer()
		out := NewBuffer()
		fakeUI = ui.NewTestUI(input, out, out)
		fakeActor = new(v2fakes.FakeDeleteOrphanedRoutesActor)
		fakeConfig = new(commandsfakes.FakeConfig)
		fakeConfig.ExperimentalReturns(true)

		cmd = v2.DeleteOrphanedRoutesCommand{
			UI:     fakeUI,
			Actor:  fakeActor,
			Config: fakeConfig,
		}
	})

	JustBeforeEach(func() {
		executeErr = cmd.Execute(nil)
	})

	It("Displays the experimental warning message", func() {
		Expect(fakeUI.Out).To(Say(v2.ExperimentalWarning))
	})

	Context("when checking that the user is logged in, and org and space are targeted", func() {
		BeforeEach(func() {
			fakeConfig.BinaryNameReturns("faceman")
		})

		It("returns an error if the check fails", func() {
			Expect(executeErr).To(MatchError(common.NotLoggedInError{
				BinaryName: "faceman",
			}))
		})
	})

	Context("when the user is logged in, and org and space are targeted", func() {
		BeforeEach(func() {
			fakeConfig.TargetReturns("some-url")
			fakeConfig.AccessTokenReturns("some-access-token")
			fakeConfig.RefreshTokenReturns("some-refresh-token")
			fakeConfig.TargetedOrganizationReturns(configv3.Organization{
				GUID: "some-org-guid",
				Name: "some-org",
			})
			fakeConfig.TargetedSpaceReturns(configv3.Space{
				GUID: "some-space-guid",
				Name: "some-space",
			})
		})

		Context("when the '-f' flag is provided", func() {
			BeforeEach(func() {
				cmd.Force = true
			})

			It("does not prompt for user confirmation", func() {
				Expect(executeErr).ToNot(HaveOccurred())

				Expect(fakeUI.Out).ToNot(Say("Really delete orphaned routes\\?>> \\[yN\\]:"))
			})
		})

		Context("when the '-f' flag is not provided", func() {
			Context("when user is prompted for confirmation", func() {
				BeforeEach(func() {
					input.Write([]byte("\n"))
				})

				It("displays the interactive prompt", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeUI.Out).To(Say("Really delete orphaned routes\\?>> \\[yN\\]:"))
				})
			})

			Context("when the user inputs no", func() {
				BeforeEach(func() {
					input.Write([]byte("n\n"))
				})

				It("does not delete orphaned routes", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeActor.GetOrphanedRoutesBySpaceCallCount()).To(Equal(0))
					Expect(fakeActor.DeleteRouteByGUIDCallCount()).To(Equal(0))
				})
			})

			Context("when the user inputs yes", func() {
				var routes []v2actions.Route

				BeforeEach(func() {
					fakeConfig.CurrentUserReturns(configv3.User{
						Name: "some-user",
					}, nil)

					input.Write([]byte("y\n"))

					routes = []v2actions.Route{
						{
							GUID:   "route-1-guid",
							Host:   "route-1",
							Domain: "bosh-lite.com",
							Path:   "path",
						},
						{
							GUID:   "route-2-guid",
							Host:   "route-2",
							Domain: "bosh-lite.com",
						},
					}

					fakeActor.GetOrphanedRoutesBySpaceReturns(routes, nil, nil)
				})

				Context("when getting the current user returns an error", func() {
					var err error

					BeforeEach(func() {
						err = errors.New("getting current user error")
						fakeConfig.CurrentUserReturns(configv3.User{}, err)
					})

					It("returns the error", func() {
						Expect(executeErr).To(MatchError(err))
					})
				})

				It("displays getting routes message", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeUI.Out).To(Say("Getting routes as some-user ...\n"))
				})

				It("deletes the routes and displays that they are deleted", func() {
					Expect(executeErr).ToNot(HaveOccurred())

					Expect(fakeActor.GetOrphanedRoutesBySpaceCallCount()).To(Equal(1))
					Expect(fakeActor.GetOrphanedRoutesBySpaceArgsForCall(0)).To(Equal("some-space-guid"))
					Expect(fakeActor.DeleteRouteByGUIDCallCount()).To(Equal(2))
					Expect(fakeActor.DeleteRouteByGUIDArgsForCall(0)).To(Equal(routes[0].GUID))
					Expect(fakeActor.DeleteRouteByGUIDArgsForCall(1)).To(Equal(routes[1].GUID))

					Expect(fakeUI.Out).To(Say("Deleting route route-1.bosh-lite.com/path..."))
					Expect(fakeUI.Out).To(Say("Deleting route route-2.bosh-lite.com..."))
					Expect(fakeUI.Out).To(Say("OK"))
				})

				Context("when there are warnings", func() {
					BeforeEach(func() {
						fakeActor.GetOrphanedRoutesBySpaceReturns([]v2actions.Route{
							{GUID: "some-route-guid"},
						}, []string{"foo", "bar"}, nil)
						fakeActor.DeleteRouteByGUIDReturns([]string{"baz"}, nil)
					})

					It("displays the warnings", func() {
						Expect(executeErr).ToNot(HaveOccurred())

						Expect(fakeUI.Err).To(Say("foo"))
						Expect(fakeUI.Err).To(Say("bar"))
						Expect(fakeUI.Err).To(Say("baz"))
					})
				})

				Context("when getting the routes returns an error", func() {
					var expectedErr error

					BeforeEach(func() {
						expectedErr = errors.New("getting orphaned routes error")
						fakeActor.GetOrphanedRoutesBySpaceReturns(nil, nil, expectedErr)
					})

					It("returns the error", func() {
						Expect(executeErr).To(MatchError(expectedErr))
					})
				})

				Context("when deleting a route returns an error", func() {
					var expectedErr error

					BeforeEach(func() {
						expectedErr = errors.New("deleting route error")
						fakeActor.GetOrphanedRoutesBySpaceReturns([]v2actions.Route{
							{GUID: "some-route-guid"},
						}, nil, nil)
						fakeActor.DeleteRouteByGUIDReturns(nil, expectedErr)
					})

					It("returns the error", func() {
						Expect(executeErr).To(MatchError(expectedErr))
					})
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package rubberneck

import (
	"fmt"
	"reflect"
	"regexp"
	"strings"
)

var (
	expr *regexp.Regexp
)

const (
	AddLineFeed = iota
	NoAddLineFeed = iota
)

func init() {
	expr = regexp.MustCompile("^[a-z]")
}

// Conforms to the signature used by fmt.Printf and log.Printf among
// many functions available in other packages.
type printerFunc func(format string, v ...interface{})

// Printer defines the signature of a function that can be
// used to display the configuration. This signature is used
// by fmt.Printf, log.Printf, various logging output levels
// from the logrus package, and others.
type Printer struct {
	Show  printerFunc
}

func addLineFeed(fn printerFunc) printerFunc {
	return func(format string, v ...interface{}) {
		format = format + "\n"
		fn(format, v...)
	}
}

// NewDefaultPrinter returns a Printer configured to write to stdout.
func NewDefaultPrinter() *Printer {
	return &Printer{
		Show: func(format string, v ...interface{}) {
			fmt.Printf(format+"\n", v...)
		},
	}
}

// NewPrinter returns a Printer configured to use the supplied function
// to output to the supplied function.
func NewPrinter(fn printerFunc, lineFeed int) *Printer {
	p := &Printer{Show: fn}

	if lineFeed == AddLineFeed {
		p.Show = addLineFeed(fn)
	}

	return p
}

// Print attempts to pretty print the contents of obj in a format suitable
// for displaying the configuration of an application on startup.
func (p *Printer) Print(obj interface{}) {
	p.Show("Settings %s", strings.Repeat("=", 40))
	p.processOne(reflect.ValueOf(obj), 0)
	p.Show("%s", strings.Repeat("=", 49))
}

func (p *Printer) processOne(value reflect.Value, indent int) {
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	t := value.Type()

	for i := 0; i < value.NumField(); i++ {
		name := t.Field(i).Name

		// Other methods of detecting unexported fields seem unreliable
		// or different between Go versions and Go compilers (gc vs gccgo)
		if expr.MatchString(name) {
			continue
		}

		field := value.Field(i)

		if field.Kind() == reflect.Ptr {
			field = field.Elem()
		}

		switch field.Kind() {
		case reflect.Struct:
			p.Show("%s * %s:", strings.Repeat("  ", indent), name)
			p.processOne(reflect.ValueOf(field.Interface()), indent+1)
		default:
			p.Show("%s * %s: %v", strings.Repeat("  ", indent), name, field.Interface())
		}
	}
}

// Print configures a default printer to output to stdout and
// then prints the object.
func Print(obj interface{}) {
	NewDefaultPrinter().Print(obj)
}
<commit_msg>Add PrintWithLabel<commit_after>package rubberneck

import (
	"fmt"
	"reflect"
	"regexp"
	"strings"
)

var (
	expr *regexp.Regexp
)

const (
	AddLineFeed = iota
	NoAddLineFeed = iota
)

func init() {
	expr = regexp.MustCompile("^[a-z]")
}

// Conforms to the signature used by fmt.Printf and log.Printf among
// many functions available in other packages.
type printerFunc func(format string, v ...interface{})

// Printer defines the signature of a function that can be
// used to display the configuration. This signature is used
// by fmt.Printf, log.Printf, various logging output levels
// from the logrus package, and others.
type Printer struct {
	Show  printerFunc
}

func addLineFeed(fn printerFunc) printerFunc {
	return func(format string, v ...interface{}) {
		format = format + "\n"
		fn(format, v...)
	}
}

// NewDefaultPrinter returns a Printer configured to write to stdout.
func NewDefaultPrinter() *Printer {
	return &Printer{
		Show: func(format string, v ...interface{}) {
			fmt.Printf(format+"\n", v...)
		},
	}
}

// NewPrinter returns a Printer configured to use the supplied function
// to output to the supplied function.
func NewPrinter(fn printerFunc, lineFeed int) *Printer {
	p := &Printer{Show: fn}

	if lineFeed == AddLineFeed {
		p.Show = addLineFeed(fn)
	}

	return p
}

// Print attempts to pretty print the contents of each obj in a format suitable
// for displaying the configuration of an application on startup. It uses a
// default label of 'Settings' for the output.
func (p *Printer) Print(objs ...interface{}) {
	// Add some protection against accidentally providing this method with
	// a label.
	if len(objs) > 0 {
		switch objs[0].(type) {
		case string:
			p.Show(" *** Expected to print a struct, got: '%s' ***", objs[0])
			return
		}
	}
	p.PrintWithLabel("Settings", objs...)
}

// PrintWithLabel attempts to pretty print the contents of each obj in a format
// suitable for displaying the configuration of an application on startup. It
// takes a label argument which is a string to be printed into the title bar in
// the output.
func (p *Printer) PrintWithLabel(label string, objs ...interface{}) {
	p.Show("%s %s", label, strings.Repeat("-", 50 - len(label) - 1))
	for _, obj := range objs {
		p.processOne(reflect.ValueOf(obj), 0)
	}
	p.Show("%s", strings.Repeat("-", 50))

}

func (p *Printer) processOne(value reflect.Value, indent int) {
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	t := value.Type()

	for i := 0; i < value.NumField(); i++ {
		name := t.Field(i).Name

		// Other methods of detecting unexported fields seem unreliable
		// or different between Go versions and Go compilers (gc vs gccgo)
		if expr.MatchString(name) {
			continue
		}

		field := value.Field(i)

		if field.Kind() == reflect.Ptr {
			field = field.Elem()
		}

		switch field.Kind() {
		case reflect.Struct:
			p.Show(" %s * %s:", strings.Repeat("  ", indent), name)
			p.processOne(reflect.ValueOf(field.Interface()), indent+1)
		default:
			p.Show(" %s * %s: %v", strings.Repeat("  ", indent), name, field.Interface())
		}
	}
}

// Print configures a default printer to output to stdout and
// then prints the object.
func Print(obj interface{}) {
	NewDefaultPrinter().Print(obj)
}
<|endoftext|>


<commit_before>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libpages

import (
	"net"
	"strings"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

const (
	keybasePagesPrefix = "kbp="
)

// ErrKeybasePagesRecordNotFound is returned when a domain requested doesn't
// have a kbp= record configured.
type ErrKeybasePagesRecordNotFound struct{}

// Error implements the error interface.
func (ErrKeybasePagesRecordNotFound) Error() string {
	return "no TXT record is found for " + keybasePagesPrefix
}

// ErrKeybasePagesRecordTooMany is returned when a domain requested has more
// than one kbp= record configured.
type ErrKeybasePagesRecordTooMany struct{}

// Error implements the error interface.
func (ErrKeybasePagesRecordTooMany) Error() string {
	return "more than 1 TXT record are found for " + keybasePagesPrefix
}

// LoadRootFromDNS loads the root path configured for domain by looking for
// a "kbp=" DNS TXT record on the domain, parse it as Root and return it.
//
// There should be exactly one "kbp=" TXT record configured for domain. If more
// than one exists, an ErrKeybasePagesRecordTooMany{} is returned. If none is
// found, an ErrKeybasePagesRecordNotFound{} is returned.
//
// Examples:
//
// static.keybase.io TXT "kbp=/keybase/team/keybase.bots/static.keybase.io"
// meatball.gao.io   TXT "kbp=/keybase/public/songgao/meatball/"
// song.gao.io       TXT "kbp=/keybase/private/songgao,kb_bot/blah"
// blah.strib.io     TXT "kbp=/keybase/private/strib#kb_bot/blahblahb" "lah/blah/"
// kbp.jzila.com     TXT "kbp=git-keybase://private/jzila,kb_bot/kbp.git"
func LoadRootFromDNS(log *zap.Logger, domain string) (root Root, err error) {
	var rootPath string

	defer func() {
		zapFields := []zapcore.Field{
			zap.String("domain", domain),
			zap.String("root_path", rootPath),
		}
		if err == nil {
			log.Info("LoadRootFromDNS", zapFields...)
		} else {
			log.Warn("LoadRootFromDNS", append(zapFields, zap.Error(err))...)
		}
	}()

	txtRecords, err := net.LookupTXT(domain)
	if err != nil {
		return Root{}, err
	}

	for _, r := range txtRecords {
		r = strings.TrimSpace(r)

		if strings.HasPrefix(r, keybasePagesPrefix) {
			if len(rootPath) != 0 {
				return Root{}, ErrKeybasePagesRecordTooMany{}
			}
			rootPath = r[len(keybasePagesPrefix):]
		}
	}

	if len(rootPath) == 0 {
		return Root{}, ErrKeybasePagesRecordNotFound{}
	}

	return ParseRoot(rootPath)
}
<commit_msg>use _keybase_pages. prefixed domain for kbp= path<commit_after>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libpages

import (
	"net"
	"strings"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

const (
	keybasePagesPrefix = "kbp="
)

// ErrKeybasePagesRecordNotFound is returned when a domain requested doesn't
// have a kbp= record configured.
type ErrKeybasePagesRecordNotFound struct{}

// Error implements the error interface.
func (ErrKeybasePagesRecordNotFound) Error() string {
	return "no TXT record is found for " + keybasePagesPrefix
}

// ErrKeybasePagesRecordTooMany is returned when a domain requested has more
// than one kbp= record configured.
type ErrKeybasePagesRecordTooMany struct{}

// Error implements the error interface.
func (ErrKeybasePagesRecordTooMany) Error() string {
	return "more than 1 TXT record are found for " + keybasePagesPrefix
}

const kbpRecordPrefix = "_keybase_pages."

// LoadRootFromDNS loads the root path configured for domain, with following
// steps:
//   1. Construct a domain name by prefixing the `domain` parameter with
//      "_keybase_pages.". So for example, "static.keybase.io" turns into
//      "_keybase_pages.static.keybase.io".
//   2. Load TXT record(s) from the domain constructed in step 1, and look for
//      one starting with "kbp=". If exactly one exists, parse it into a `Root`
//      and return it.
//
// There must be exactly one "kbp=" TXT record configured for domain. If more
// than one exists, an ErrKeybasePagesRecordTooMany{} is returned. If none is
// found, an ErrKeybasePagesRecordNotFound{} is returned. In case user has some
// configuration that requires other records that we can't foresee for now,
// other records (TXT or not) can co-exist with the "kbp=" record (as long as
// no CNAME record exists on the "_keybase_pages." prefixed domain of course).
//
// If the given domain is invalid, it would cause the domain name constructed
// in step will be invalid too, which causes Go's DNS resolver to return a
// net.DNSError typed "no such host" error.
//
// Examples for "static.keybase.io", "meatball.gao.io", "song.gao.io",
// "blah.strib.io", and "kbp.jzila.com" respectively:
//
// _keybase_pages.static.keybase.io TXT "kbp=/keybase/team/keybase.bots/static.keybase.io"
// _keybase_pages.meatball.gao.io   TXT "kbp=/keybase/public/songgao/meatball/"
// _keybase_pages.song.gao.io       TXT "kbp=/keybase/private/songgao,kb_bot/blah"
// _keybase_pages.blah.strib.io     TXT "kbp=/keybase/private/strib#kb_bot/blahblahb" "lah/blah/"
// _keybase_pages.kbp.jzila.com     TXT "kbp=git-keybase://private/jzila,kb_bot/kbp.git"
func LoadRootFromDNS(log *zap.Logger, domain string) (root Root, err error) {
	var rootPath string

	defer func() {
		zapFields := []zapcore.Field{
			zap.String("domain", domain),
			zap.String("root_path", rootPath),
		}
		if err == nil {
			log.Info("LoadRootFromDNS", zapFields...)
		} else {
			log.Warn("LoadRootFromDNS", append(zapFields, zap.Error(err))...)
		}
	}()

	txtRecords, err := net.LookupTXT(kbpRecordPrefix + domain)
	if err != nil {
		return Root{}, err
	}

	for _, r := range txtRecords {
		r = strings.TrimSpace(r)

		if strings.HasPrefix(r, keybasePagesPrefix) {
			if len(rootPath) != 0 {
				return Root{}, ErrKeybasePagesRecordTooMany{}
			}
			rootPath = r[len(keybasePagesPrefix):]
		}
	}

	if len(rootPath) == 0 {
		return Root{}, ErrKeybasePagesRecordNotFound{}
	}

	return ParseRoot(rootPath)
}
<|endoftext|>


<commit_before>package linux

import (
	"context"
	"log"

	"github.com/pkg/errors"

	"github.com/currantlabs/ble"
	"github.com/currantlabs/ble/linux/att"
	"github.com/currantlabs/ble/linux/gatt"
	"github.com/currantlabs/ble/linux/hci"
)

// NewDevice returns the default HCI device.
func NewDevice() (*Device, error) {
	return NewDeviceWithName("Gopher")
}

// NewDeviceWithName returns the default HCI device.
func NewDeviceWithName(name string) (*Device, error) {
	dev, err := hci.NewHCI()
	if err != nil {
		return nil, errors.Wrap(err, "can't create hci")
	}
	if err = dev.Init(); err != nil {
		return nil, errors.Wrap(err, "can't init hci")
	}

	s, err := gatt.NewServerWithName(name)
	if err != nil {
		return nil, errors.Wrap(err, "can't create server")
	}

	mtu := ble.DefaultMTU
	mtu = ble.MaxMTU // TODO: get this from user using Option.
	if mtu > ble.MaxMTU {
		return nil, errors.Wrapf(err, "maximum ATT_MTU is %d", ble.MaxMTU)
	}

	go func() {
		for {
			l2c, err := dev.Accept()
			if err != nil {
				log.Printf("can't accept: %s", err)
				return
			}

			// Initialize the per-connection cccd values.
			l2c.SetContext(context.WithValue(l2c.Context(), "ccc", make(map[uint16]uint16)))
			l2c.SetRxMTU(mtu)

			s.Lock()
			as, err := att.NewServer(s.DB(), l2c)
			s.Unlock()
			if err != nil {
				log.Printf("can't create ATT server: %s", err)
				continue

			}
			go as.Loop()
		}
	}()
	return &Device{HCI: dev, Server: s}, nil
}

// Device ...
type Device struct {
	HCI    *hci.HCI
	Server *gatt.Server
}

// AddService adds a service to database.
func (d *Device) AddService(svc *ble.Service) error {
	return d.Server.AddService(svc)
}

// RemoveAllServices removes all services that are currently in the database.
func (d *Device) RemoveAllServices() error {
	return d.Server.RemoveAllServices()
}

// SetServices set the specified service to the database.
// It removes all currently added services, if any.
func (d *Device) SetServices(svcs []*ble.Service) error {
	return d.Server.SetServices(svcs)
}

// Stop stops gatt server.
func (d *Device) Stop() error {
	return d.HCI.Close()
}

// AdvertiseNameAndServices advertises device name, and specified service UUIDs.
// It tres to fit the UUIDs in the advertising packet as much as possible.
// If name doesn't fit in the advertising packet, it will be put in scan response.
func (d *Device) AdvertiseNameAndServices(ctx context.Context, name string, uuids ...ble.UUID) error {
	if err := d.HCI.AdvertiseNameAndServices(name, uuids...); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseMfgData avertises the given manufacturer data.
func (d *Device) AdvertiseMfgData(ctx context.Context, id uint16, b []byte) error {
	if err := d.HCI.AdvertiseMfgData(id, b); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseServiceData16 advertises data associated with a 16bit service uuid
func (d *Device) AdvertiseServiceData16(ctx context.Context, id uint16, b []byte) error {
	if err := d.HCI.AdvertiseServiceData16(id, b); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseIBeaconData advertise iBeacon with given manufacturer data.
func (d *Device) AdvertiseIBeaconData(ctx context.Context, b []byte) error {
	if err := d.HCI.AdvertiseIBeaconData(b); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseIBeacon advertises iBeacon with specified parameters.
func (d *Device) AdvertiseIBeacon(ctx context.Context, u ble.UUID, major, minor uint16, pwr int8) error {
	if err := d.HCI.AdvertiseIBeacon(u, major, minor, pwr); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// Scan starts scanning. Duplicated advertisements will be filtered out if allowDup is set to false.
func (d *Device) Scan(ctx context.Context, allowDup bool, h ble.AdvHandler) error {
	if err := d.HCI.SetAdvHandler(h); err != nil {
		return err
	}
	if err := d.HCI.Scan(allowDup); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopScanning()
	return ctx.Err()
}

// Dial ...
func (d *Device) Dial(ctx context.Context, a ble.Addr) (ble.Client, error) {
	// d.HCI.Dial is a blocking call, although most of time it should return immediately.
	// But in case passing wrong device address or the device went non-connectable, it blocks.
	cln, err := d.HCI.Dial(ctx, a)
	return cln, errors.Wrap(err, "can't dial")
}

// Address returns the listener's device address.
func (d *Device) Address() ble.Addr {
	return d.HCI.Addr()
}
<commit_msg>Move linux device loop to seperate function<commit_after>package linux

import (
	"context"
	"log"

	"github.com/pkg/errors"

	"github.com/currantlabs/ble"
	"github.com/currantlabs/ble/linux/att"
	"github.com/currantlabs/ble/linux/gatt"
	"github.com/currantlabs/ble/linux/hci"
)

// NewDevice returns the default HCI device.
func NewDevice() (*Device, error) {
	return NewDeviceWithName("Gopher")
}

// NewDeviceWithName returns the default HCI device.
func NewDeviceWithName(name string) (*Device, error) {
	dev, err := hci.NewHCI()
	if err != nil {
		return nil, errors.Wrap(err, "can't create hci")
	}
	if err = dev.Init(); err != nil {
		return nil, errors.Wrap(err, "can't init hci")
	}

	srv, err := gatt.NewServerWithName(name)
	if err != nil {
		return nil, errors.Wrap(err, "can't create server")
	}

	// mtu := ble.DefaultMTU
	mtu := ble.MaxMTU // TODO: get this from user using Option.
	if mtu > ble.MaxMTU {
		return nil, errors.Wrapf(err, "maximum ATT_MTU is %d", ble.MaxMTU)
	}

	go loop(dev, srv, mtu)

	return &Device{HCI: dev, Server: srv}, nil
}

func loop(dev *hci.HCI, s *gatt.Server, mtu int) {
	for {
		l2c, err := dev.Accept()
		if err != nil {
			log.Printf("can't accept: %s", err)
			return
		}

		// Initialize the per-connection cccd values.
		l2c.SetContext(context.WithValue(l2c.Context(), "ccc", make(map[uint16]uint16)))
		l2c.SetRxMTU(mtu)

		s.Lock()
		as, err := att.NewServer(s.DB(), l2c)
		s.Unlock()
		if err != nil {
			log.Printf("can't create ATT server: %s", err)
			continue

		}
		go as.Loop()
	}
}

// Device ...
type Device struct {
	HCI    *hci.HCI
	Server *gatt.Server
}

// AddService adds a service to database.
func (d *Device) AddService(svc *ble.Service) error {
	return d.Server.AddService(svc)
}

// RemoveAllServices removes all services that are currently in the database.
func (d *Device) RemoveAllServices() error {
	return d.Server.RemoveAllServices()
}

// SetServices set the specified service to the database.
// It removes all currently added services, if any.
func (d *Device) SetServices(svcs []*ble.Service) error {
	return d.Server.SetServices(svcs)
}

// Stop stops gatt server.
func (d *Device) Stop() error {
	return d.HCI.Close()
}

// AdvertiseNameAndServices advertises device name, and specified service UUIDs.
// It tres to fit the UUIDs in the advertising packet as much as possible.
// If name doesn't fit in the advertising packet, it will be put in scan response.
func (d *Device) AdvertiseNameAndServices(ctx context.Context, name string, uuids ...ble.UUID) error {
	if err := d.HCI.AdvertiseNameAndServices(name, uuids...); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseMfgData avertises the given manufacturer data.
func (d *Device) AdvertiseMfgData(ctx context.Context, id uint16, b []byte) error {
	if err := d.HCI.AdvertiseMfgData(id, b); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseServiceData16 advertises data associated with a 16bit service uuid
func (d *Device) AdvertiseServiceData16(ctx context.Context, id uint16, b []byte) error {
	if err := d.HCI.AdvertiseServiceData16(id, b); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseIBeaconData advertise iBeacon with given manufacturer data.
func (d *Device) AdvertiseIBeaconData(ctx context.Context, b []byte) error {
	if err := d.HCI.AdvertiseIBeaconData(b); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// AdvertiseIBeacon advertises iBeacon with specified parameters.
func (d *Device) AdvertiseIBeacon(ctx context.Context, u ble.UUID, major, minor uint16, pwr int8) error {
	if err := d.HCI.AdvertiseIBeacon(u, major, minor, pwr); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopAdvertising()
	return ctx.Err()
}

// Scan starts scanning. Duplicated advertisements will be filtered out if allowDup is set to false.
func (d *Device) Scan(ctx context.Context, allowDup bool, h ble.AdvHandler) error {
	if err := d.HCI.SetAdvHandler(h); err != nil {
		return err
	}
	if err := d.HCI.Scan(allowDup); err != nil {
		return err
	}
	<-ctx.Done()
	d.HCI.StopScanning()
	return ctx.Err()
}

// Dial ...
func (d *Device) Dial(ctx context.Context, a ble.Addr) (ble.Client, error) {
	// d.HCI.Dial is a blocking call, although most of time it should return immediately.
	// But in case passing wrong device address or the device went non-connectable, it blocks.
	cln, err := d.HCI.Dial(ctx, a)
	return cln, errors.Wrap(err, "can't dial")
}

// Address returns the listener's device address.
func (d *Device) Address() ble.Addr {
	return d.HCI.Addr()
}
<|endoftext|>