<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/open-lambda/open-lambda/worker/config"
	"github.com/open-lambda/open-lambda/worker/sandbox"
	"github.com/open-lambda/open-lambda/worker/server"
)

type Admin struct {
	client *docker.Client
	fns    map[string]AdminFn
}

type CmdArgs struct {
	flags   *flag.FlagSet
	cluster *string
}

func NewCmdArgs() *CmdArgs {
	args := CmdArgs{}
	args.flags = flag.NewFlagSet("flag", flag.ExitOnError)
	args.cluster = args.flags.String("cluster", "", "give a cluster directory")
	return &args
}

func (args *CmdArgs) Parse(require_cluster bool) {
	args.flags.Parse(os.Args[2:])

	if *args.cluster != "" {
		abscluster, err := filepath.Abs(*args.cluster)
		*args.cluster = abscluster
		if err != nil {
			log.Fatal("failed to get abs cluster dir: ", err)
		}
	} else if require_cluster {
		log.Fatal("please specify a cluster directory")
	}
}

func (args *CmdArgs) LogPath(name string) string {
	return path.Join(*args.cluster, "logs", name)
}

func (args *CmdArgs) PidPath(name string) string {
	return path.Join(*args.cluster, "logs", name+".pid")
}

func (args *CmdArgs) ConfigPath(name string) string {
	return path.Join(*args.cluster, "config", name+".json")
}

func (args *CmdArgs) TemplatePath() string {
	return args.ConfigPath("template")
}

func (args *CmdArgs) RegistryPath() string {
	return path.Join(*args.cluster, "registry")
}

type AdminFn func() error

func NewAdmin() *Admin {
	admin := Admin{fns: map[string]AdminFn{}}
	if client, err := docker.NewClientFromEnv(); err != nil {
		log.Fatal("failed to get docker client: ", err)
	} else {
		admin.client = client
	}

	admin.fns["help"] = admin.help
	admin.fns["new-cluster"] = admin.new_cluster
	admin.fns["status"] = admin.status
	admin.fns["rethinkdb"] = admin.rethinkdb
	admin.fns["worker"] = admin.worker
	admin.fns["workers"] = admin.workers
	admin.fns["kill"] = admin.kill
	return &admin
}

func (admin *Admin) command(cmd string) {
	fn := admin.fns[cmd]
	if fn == nil {
		admin.help()
		return
	}
	if err := fn(); err != nil {
		log.Fatalf("Failed to run %v, %v\n", cmd, err)
	}
}

func (admin *Admin) cluster_nodes(cluster string) (map[string]([]string), error) {
	client := admin.client
	nodes := map[string]([]string){}

	containers, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		if container.Labels[sandbox.DOCKER_LABEL_CLUSTER] == cluster {
			cid := container.ID
			type_label := container.Labels[sandbox.DOCKER_LABEL_TYPE]
			nodes[type_label] = append(nodes[type_label], cid)
		}
	}

	return nodes, nil
}

func (admin *Admin) help() error {
	fmt.Printf("Run %v <command> <args>\n", os.Args[0])
	fmt.Printf("\n")
	fmt.Printf("Commands:\n")
	cmds := make([]string, 0, len(admin.fns))
	for cmd := range admin.fns {
		cmds = append(cmds, cmd)
	}
	sort.Strings(cmds)

	for _, cmd := range cmds {
		fmt.Printf("  %v\n", cmd)
	}
	return nil
}

func (admin *Admin) new_cluster() error {
	args := NewCmdArgs()
	args.Parse(true)

	if err := os.Mkdir(*args.cluster, 0700); err != nil {
		return err
	}

	if err := os.Mkdir(path.Join(*args.cluster, "logs"), 0700); err != nil {
		return err
	}

	if err := os.Mkdir(args.RegistryPath(), 0700); err != nil {
		return err
	}

	// config dir and template
	if err := os.Mkdir(path.Join(*args.cluster, "config"), 0700); err != nil {
		return err
	}
	c := &config.Config{
		Worker_port:  "?",
		Cluster_name: *args.cluster,
		Registry:     "local",
		Reg_dir:      args.RegistryPath(),
	}
	if err := c.Defaults(); err != nil {
		return err
	}
	if err := c.Save(args.TemplatePath()); err != nil {
		return err
	}

	fmt.Printf("Cluster Directory: %s\n\n", *args.cluster)
	fmt.Printf("Worker Defaults: \n%s\n\n", c.DumpStr())
	fmt.Printf("You may now start a cluster using the \"workers\" command\n")

	return nil
}

func (admin *Admin) status() error {
	args := NewCmdArgs()
	args.Parse(false)

	containers1, err := admin.client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return err
	}

	if *args.cluster == "" {
		other := 0
		node_counts := map[string]int{}

		for _, containers2 := range containers1 {
			label := containers2.Labels[sandbox.DOCKER_LABEL_CLUSTER]
			if label != "" {
				node_counts[label] += 1
			} else {
				other += 1
			}
		}

		fmt.Printf("%d container(s) without OpenLambda labels\n\n", other)
		fmt.Printf("%d cluster(s):\n", len(node_counts))
		for cluster_name, count := range node_counts {
			fmt.Printf("  <%s> (%d nodes)\n", cluster_name, count)
		}
		fmt.Printf("\n")
		fmt.Printf("For info about a specific cluster, use -cluster=<cluster-name>\n")
	} else {
		fmt.Printf("Nodes in %s cluster:\n", *args.cluster)
		for _, containers2 := range containers1 {
			if containers2.Labels[sandbox.DOCKER_LABEL_CLUSTER] == *args.cluster {
				name := containers2.Names[0]
				oltype := containers2.Labels[sandbox.DOCKER_LABEL_TYPE]
				fmt.Printf("  <%s> (%s)\n", name, oltype)
			}
		}
	}

	return nil
}

func (admin *Admin) rethinkdb() error {
	args := NewCmdArgs()
	count := args.flags.Int("count", 1, "specify number of nodes to start")
	args.Parse(true)

	client := admin.client
	labels := map[string]string{}
	labels[sandbox.DOCKER_LABEL_CLUSTER] = *args.cluster
	labels[sandbox.DOCKER_LABEL_TYPE] = "db"

	var first_container *docker.Container

	for i := 0; i < *count; i++ {
		cmd := []string{"rethinkdb", "--bind", "all"}
		if first_container != nil {
			ip := first_container.NetworkSettings.IPAddress
			cmd = append(cmd, "--join", fmt.Sprintf("%s:%d", ip, 29015))
		}

		fmt.Printf("Starting shard: %s\n", strings.Join(cmd, " "))

		// create and start container
		container, err := client.CreateContainer(
			docker.CreateContainerOptions{
				Config: &docker.Config{
					Cmd:    cmd,
					Image:  "rethinkdb",
					Labels: labels,
				},
			},
		)
		if err != nil {
			return err
		}
		if err := client.StartContainer(container.ID, container.HostConfig); err != nil {
			return err
		}

		// get network assignments
		container, err = client.InspectContainer(container.ID)
		if err != nil {
			return err
		}

		if i == 0 {
			first_container = container
		}
	}

	return nil
}

func (admin *Admin) worker() error {
	flags := flag.NewFlagSet("flag", flag.ExitOnError)
	conf := flags.String("config", "", "give a json config file")
	flags.Parse(os.Args[2:])

	if *conf == "" {
		fmt.Printf("Please specify a json config file\n")
		return nil
	}

	server.Main(*conf)
	return nil
}

func (admin *Admin) workers() error {
	args := NewCmdArgs()
	foreach := args.flags.Bool("foreach", false, "start one worker per db instance")
	portbase := args.flags.Int("port", 8080, "port range [port, port+n) will be used for workers")
	n := args.flags.Int("n", 1, "specify number of workers to start")
	args.Parse(true)

	worker_confs := []*config.Config{}
	if *foreach {
		nodes, err := admin.cluster_nodes(*args.cluster)
		if err != nil {
			return err
		}

		// start one worker per db shard
		for _, cid := range nodes["db"] {
			container, err := admin.client.InspectContainer(cid)
			if err != nil {
				return err
			}

			fmt.Printf("DB node: %v\n", container.NetworkSettings.IPAddress)

			c, err := config.ParseConfig(args.TemplatePath())
			if err != nil {
				return err
			}
			worker_confs = append(worker_confs, c)
		}
	} else {
		for i := 0; i < *n; i++ {
			c, err := config.ParseConfig(args.TemplatePath())
			if err != nil {
				return err
			}
			worker_confs = append(worker_confs, c)
		}
	}

	for i, conf := range worker_confs {
		conf_path := args.ConfigPath(fmt.Sprintf("worker-%d", i))
		conf.Worker_port = fmt.Sprintf("%d", *portbase+i)
		if err := conf.Save(conf_path); err != nil {
			return err
		}

		// stdout+stderr both go to log
		log_path := args.LogPath(fmt.Sprintf("worker-%d.out", i))
		f, err := os.Create(log_path)
		if err != nil {
			return err
		}
		attr := os.ProcAttr{
			Files: []*os.File{nil, f, f},
		}
		cmd := []string{
			os.Args[0],
			"worker",
			"-config=" + conf_path,
		}
		proc, err := os.StartProcess(os.Args[0], cmd, &attr)
		if err != nil {
			return err
		}

		pidpath := args.PidPath(fmt.Sprintf("worker-%d", i))
		if err := ioutil.WriteFile(pidpath, []byte(fmt.Sprintf("%d", proc.Pid)), 0644); err != nil {
			return err
		}

		fmt.Printf("Started worker: pid %d, port %s, log at %s\n", proc.Pid, conf.Worker_port, log_path)
	}

	return nil
}

func (admin *Admin) kill() error {
	args := NewCmdArgs()
	args.Parse(true)

	client := admin.client
	containers1, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return err
	}

	for _, containers2 := range containers1 {
		if containers2.Labels[sandbox.DOCKER_LABEL_CLUSTER] == *args.cluster {
			cid := containers2.ID
			container, err := client.InspectContainer(cid)
			if err != nil {
				return err
			}
			if container.State.Paused {
				fmt.Printf("Unpause container %v\n", cid)
				if err := client.UnpauseContainer(cid); err != nil {
					return err
				}
			}

			fmt.Printf("Kill container %v\n", cid)
			opts := docker.KillContainerOptions{ID: cid}
			if err := client.KillContainer(opts); err != nil {
				return err
			}
		}
	}

	return nil
}

func main() {
	admin := NewAdmin()
	if len(os.Args) < 2 {
		admin.help()
		os.Exit(1)
	}
	admin.command(os.Args[1])
}
<commit_msg>kill worker processes as well as containers with admin tool<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/open-lambda/open-lambda/worker/config"
	"github.com/open-lambda/open-lambda/worker/sandbox"
	"github.com/open-lambda/open-lambda/worker/server"
)

type Admin struct {
	client *docker.Client
	fns    map[string]AdminFn
}

type CmdArgs struct {
	flags   *flag.FlagSet
	cluster *string
}

func NewCmdArgs() *CmdArgs {
	args := CmdArgs{}
	args.flags = flag.NewFlagSet("flag", flag.ExitOnError)
	args.cluster = args.flags.String("cluster", "", "give a cluster directory")
	return &args
}

func (args *CmdArgs) Parse(require_cluster bool) {
	args.flags.Parse(os.Args[2:])

	if *args.cluster != "" {
		abscluster, err := filepath.Abs(*args.cluster)
		*args.cluster = abscluster
		if err != nil {
			log.Fatal("failed to get abs cluster dir: ", err)
		}
	} else if require_cluster {
		log.Fatal("please specify a cluster directory")
	}
}

func (args *CmdArgs) LogPath(name string) string {
	return path.Join(*args.cluster, "logs", name)
}

func (args *CmdArgs) PidPath(name string) string {
	return path.Join(*args.cluster, "logs", name+".pid")
}

func (args *CmdArgs) ConfigPath(name string) string {
	return path.Join(*args.cluster, "config", name+".json")
}

func (args *CmdArgs) TemplatePath() string {
	return args.ConfigPath("template")
}

func (args *CmdArgs) RegistryPath() string {
	return path.Join(*args.cluster, "registry")
}

type AdminFn func() error

func NewAdmin() *Admin {
	admin := Admin{fns: map[string]AdminFn{}}
	if client, err := docker.NewClientFromEnv(); err != nil {
		log.Fatal("failed to get docker client: ", err)
	} else {
		admin.client = client
	}

	admin.fns["help"] = admin.help
	admin.fns["new-cluster"] = admin.new_cluster
	admin.fns["status"] = admin.status
	admin.fns["rethinkdb"] = admin.rethinkdb
	admin.fns["worker"] = admin.worker
	admin.fns["workers"] = admin.workers
	admin.fns["kill"] = admin.kill
	return &admin
}

func (admin *Admin) command(cmd string) {
	fn := admin.fns[cmd]
	if fn == nil {
		admin.help()
		return
	}
	if err := fn(); err != nil {
		log.Fatalf("Failed to run %v, %v\n", cmd, err)
	}
}

func (admin *Admin) cluster_nodes(cluster string) (map[string]([]string), error) {
	client := admin.client
	nodes := map[string]([]string){}

	containers, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		if container.Labels[sandbox.DOCKER_LABEL_CLUSTER] == cluster {
			cid := container.ID
			type_label := container.Labels[sandbox.DOCKER_LABEL_TYPE]
			nodes[type_label] = append(nodes[type_label], cid)
		}
	}

	return nodes, nil
}

func (admin *Admin) help() error {
	fmt.Printf("Run %v <command> <args>\n", os.Args[0])
	fmt.Printf("\n")
	fmt.Printf("Commands:\n")
	cmds := make([]string, 0, len(admin.fns))
	for cmd := range admin.fns {
		cmds = append(cmds, cmd)
	}
	sort.Strings(cmds)

	for _, cmd := range cmds {
		fmt.Printf("  %v\n", cmd)
	}
	return nil
}

func (admin *Admin) new_cluster() error {
	args := NewCmdArgs()
	args.Parse(true)

	if err := os.Mkdir(*args.cluster, 0700); err != nil {
		return err
	}

	if err := os.Mkdir(path.Join(*args.cluster, "logs"), 0700); err != nil {
		return err
	}

	if err := os.Mkdir(args.RegistryPath(), 0700); err != nil {
		return err
	}

	// config dir and template
	if err := os.Mkdir(path.Join(*args.cluster, "config"), 0700); err != nil {
		return err
	}
	c := &config.Config{
		Worker_port:  "?",
		Cluster_name: *args.cluster,
		Registry:     "local",
		Reg_dir:      args.RegistryPath(),
	}
	if err := c.Defaults(); err != nil {
		return err
	}
	if err := c.Save(args.TemplatePath()); err != nil {
		return err
	}

	fmt.Printf("Cluster Directory: %s\n\n", *args.cluster)
	fmt.Printf("Worker Defaults: \n%s\n\n", c.DumpStr())
	fmt.Printf("You may now start a cluster using the \"workers\" command\n")

	return nil
}

func (admin *Admin) status() error {
	args := NewCmdArgs()
	args.Parse(false)

	containers1, err := admin.client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return err
	}

	if *args.cluster == "" {
		other := 0
		node_counts := map[string]int{}

		for _, containers2 := range containers1 {
			label := containers2.Labels[sandbox.DOCKER_LABEL_CLUSTER]
			if label != "" {
				node_counts[label] += 1
			} else {
				other += 1
			}
		}

		fmt.Printf("%d container(s) without OpenLambda labels\n\n", other)
		fmt.Printf("%d cluster(s):\n", len(node_counts))
		for cluster_name, count := range node_counts {
			fmt.Printf("  <%s> (%d nodes)\n", cluster_name, count)
		}
		fmt.Printf("\n")
		fmt.Printf("For info about a specific cluster, use -cluster=<cluster-name>\n")
	} else {
		fmt.Printf("Nodes in %s cluster:\n", *args.cluster)
		for _, containers2 := range containers1 {
			if containers2.Labels[sandbox.DOCKER_LABEL_CLUSTER] == *args.cluster {
				name := containers2.Names[0]
				oltype := containers2.Labels[sandbox.DOCKER_LABEL_TYPE]
				fmt.Printf("  <%s> (%s)\n", name, oltype)
			}
		}
	}

	return nil
}

func (admin *Admin) rethinkdb() error {
	args := NewCmdArgs()
	count := args.flags.Int("count", 1, "specify number of nodes to start")
	args.Parse(true)

	client := admin.client
	labels := map[string]string{}
	labels[sandbox.DOCKER_LABEL_CLUSTER] = *args.cluster
	labels[sandbox.DOCKER_LABEL_TYPE] = "db"

	var first_container *docker.Container

	for i := 0; i < *count; i++ {
		cmd := []string{"rethinkdb", "--bind", "all"}
		if first_container != nil {
			ip := first_container.NetworkSettings.IPAddress
			cmd = append(cmd, "--join", fmt.Sprintf("%s:%d", ip, 29015))
		}

		fmt.Printf("Starting shard: %s\n", strings.Join(cmd, " "))

		// create and start container
		container, err := client.CreateContainer(
			docker.CreateContainerOptions{
				Config: &docker.Config{
					Cmd:    cmd,
					Image:  "rethinkdb",
					Labels: labels,
				},
			},
		)
		if err != nil {
			return err
		}
		if err := client.StartContainer(container.ID, container.HostConfig); err != nil {
			return err
		}

		// get network assignments
		container, err = client.InspectContainer(container.ID)
		if err != nil {
			return err
		}

		if i == 0 {
			first_container = container
		}
	}

	return nil
}

func (admin *Admin) worker() error {
	flags := flag.NewFlagSet("flag", flag.ExitOnError)
	conf := flags.String("config", "", "give a json config file")
	flags.Parse(os.Args[2:])

	if *conf == "" {
		fmt.Printf("Please specify a json config file\n")
		return nil
	}

	server.Main(*conf)
	return nil
}

func (admin *Admin) workers() error {
	args := NewCmdArgs()
	foreach := args.flags.Bool("foreach", false, "start one worker per db instance")
	portbase := args.flags.Int("port", 8080, "port range [port, port+n) will be used for workers")
	n := args.flags.Int("n", 1, "specify number of workers to start")
	args.Parse(true)

	worker_confs := []*config.Config{}
	if *foreach {
		nodes, err := admin.cluster_nodes(*args.cluster)
		if err != nil {
			return err
		}

		// start one worker per db shard
		for _, cid := range nodes["db"] {
			container, err := admin.client.InspectContainer(cid)
			if err != nil {
				return err
			}

			fmt.Printf("DB node: %v\n", container.NetworkSettings.IPAddress)

			c, err := config.ParseConfig(args.TemplatePath())
			if err != nil {
				return err
			}
			worker_confs = append(worker_confs, c)
		}
	} else {
		for i := 0; i < *n; i++ {
			c, err := config.ParseConfig(args.TemplatePath())
			if err != nil {
				return err
			}
			worker_confs = append(worker_confs, c)
		}
	}

	for i, conf := range worker_confs {
		conf_path := args.ConfigPath(fmt.Sprintf("worker-%d", i))
		conf.Worker_port = fmt.Sprintf("%d", *portbase+i)
		if err := conf.Save(conf_path); err != nil {
			return err
		}

		// stdout+stderr both go to log
		log_path := args.LogPath(fmt.Sprintf("worker-%d.out", i))
		f, err := os.Create(log_path)
		if err != nil {
			return err
		}
		attr := os.ProcAttr{
			Files: []*os.File{nil, f, f},
		}
		cmd := []string{
			os.Args[0],
			"worker",
			"-config=" + conf_path,
		}
		proc, err := os.StartProcess(os.Args[0], cmd, &attr)
		if err != nil {
			return err
		}

		pidpath := args.PidPath(fmt.Sprintf("worker-%d", i))
		if err := ioutil.WriteFile(pidpath, []byte(fmt.Sprintf("%d", proc.Pid)), 0644); err != nil {
			return err
		}

		fmt.Printf("Started worker: pid %d, port %s, log at %s\n", proc.Pid, conf.Worker_port, log_path)
	}

	return nil
}

func (admin *Admin) kill() error {
	args := NewCmdArgs()
	args.Parse(true)

	client := admin.client

	nodes, err := admin.cluster_nodes(*args.cluster)
	if err != nil {
		return err
	}

	// kill containers in cluster
	for typ, cids := range nodes {
		for _, cid := range cids {
			container, err := client.InspectContainer(cid)
			if err != nil {
				return err
			}

			if container.State.Paused {
				fmt.Printf("Unpause container %v (%s)\n", cid, typ)
				if err := client.UnpauseContainer(cid); err != nil {
					fmt.Printf("%s\n", err.Error())
					fmt.Printf("Failed to unpause container %v (%s).  May require manual cleanup.\n", cid, typ)
				}
			}

			fmt.Printf("Kill container %v (%s)\n", cid, typ)
			opts := docker.KillContainerOptions{ID: cid}
			if err := client.KillContainer(opts); err != nil {
				fmt.Printf("%s\n", err.Error())
				fmt.Printf("Failed to kill container %v (%s).  May require manual cleanup.\n", cid, typ)
			}
		}
	}

	// kill worker processes in cluster
	logs, err := ioutil.ReadDir(path.Join(*args.cluster, "logs"))
	if err != nil {
		return err
	}
	for _, fi := range logs {
		if strings.HasSuffix(fi.Name(), ".pid") {
			data, err := ioutil.ReadFile(args.LogPath(fi.Name()))
			if err != nil {
				return err
			}
			pidstr := string(data)
			pid, err := strconv.Atoi(pidstr)
			if err != nil {
				return err
			}
			fmt.Printf("Kill worker process with PID %d\n", pid)
			p, err := os.FindProcess(pid)
			if err != nil {
				fmt.Printf("%s\n", err.Error())
				fmt.Printf("Failed to find worker process with PID %d.  May require manual cleanup.\n", pid)
			}
			if err := p.Kill(); err != nil {
				fmt.Printf("%s\n", err.Error())
				fmt.Printf("Failed to kill process with PID %d.  May require manual cleanup.\n", pid)
			}
		}
	}

	return nil
}

func main() {
	admin := NewAdmin()
	if len(os.Args) < 2 {
		admin.help()
		os.Exit(1)
	}
	admin.command(os.Args[1])
}
<|endoftext|>


<commit_before>// Copyright 2021 The Ebiten 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 readerdriver

import (
	"io"
	"runtime"
	"sync"
	"time"

	"github.com/hajimehoshi/ebiten/v2/audio/internal/oboe"
)

func IsAvailable() bool {
	return true
}

type context struct {
	sampleRate      int
	channelNum      int
	bitDepthInBytes int
}

func NewContext(sampleRate int, channelNum int, bitDepthInBytes int) (Context, chan struct{}, error) {
	ready := make(chan struct{})
	close(ready)

	c := &context{
		sampleRate:      sampleRate,
		channelNum:      channelNum,
		bitDepthInBytes: bitDepthInBytes,
	}
	return c, ready, nil
}

func (c *context) NewPlayer(src io.Reader) Player {
	p := &player{
		context: c,
		src:     src,
		cond:    sync.NewCond(&sync.Mutex{}),
		volume:  1,
	}
	runtime.SetFinalizer(p, (*player).Close)
	return p
}

func (c *context) Suspend() error {
	return oboe.Suspend()
}

func (c *context) Resume() error {
	return oboe.Resume()
}

type player struct {
	context *context
	p       *oboe.Player
	src     io.Reader
	err     error
	cond    *sync.Cond
	closed  bool
	volume  float64
}

func (p *player) Pause() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.closed {
		return
	}
	if p.p == nil {
		return
	}
	if err := p.p.Pause(); err != nil {
		p.setErrorImpl(err)
		return
	}
	p.cond.Signal()
}

func (p *player) Play() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.p != nil && p.p.IsPlaying() {
		return
	}
	defer p.cond.Signal()
	var runLoop bool
	if p.p == nil {
		p.p = oboe.NewPlayer(p.context.sampleRate, p.context.channelNum, p.context.bitDepthInBytes, p.volume, func() {
			p.cond.Signal()
		})
		runLoop = true
	}

	buf := make([]byte, p.context.maxBufferSize())
	for p.p.UnplayedBufferSize() < p.context.maxBufferSize() {
		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setErrorImpl(err)
			return
		}
		p.p.AppendBuffer(buf[:n])
		if err == io.EOF {
			break
		}
	}

	if err := p.p.Play(); err != nil {
		p.setErrorImpl(err)
		return
	}
	if runLoop {
		go p.loop()
	}
}

func (p *player) IsPlaying() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	if p.p == nil {
		return false
	}
	return p.p.IsPlaying()
}

func (p *player) Reset() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.closed {
		return
	}
	if p.p == nil {
		return
	}
	if err := p.p.Close(); err != nil {
		p.setErrorImpl(err)
		return
	}
	p.p = nil
	p.cond.Signal()
}

func (p *player) Volume() float64 {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.volume
}

func (p *player) SetVolume(volume float64) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.volume = volume
	if p.p == nil {
		return
	}
	p.p.SetVolume(volume)
}

func (p *player) UnplayedBufferSize() int {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	if p.p == nil {
		return 0
	}
	return p.p.UnplayedBufferSize()
}

func (p *player) Err() error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.err
}

func (p *player) Close() error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.closeImpl()
}

func (p *player) closeImpl() error {
	defer p.cond.Signal()

	runtime.SetFinalizer(p, nil)
	p.closed = true
	if p.p == nil {
		return p.err
	}
	if err := p.p.Close(); err != nil && p.err == nil {
		// Do not call setErrorImpl, or this can cause infinite recursive.
		p.err = err
		return p.err
	}
	p.p = nil
	return p.err
}

func (p *player) setError(err error) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.setErrorImpl(err)
}

func (p *player) setErrorImpl(err error) {
	p.err = err
	p.closeImpl()
}

func (p *player) shouldWait() bool {
	if p.closed {
		return false
	}
	if p.p == nil {
		return false
	}
	if p.p.IsPlaying() {
		return p.p.UnplayedBufferSize() >= p.context.maxBufferSize()
	}
	return true
}

func (p *player) wait() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	for p.shouldWait() {
		p.cond.Wait()
	}
	return p.p != nil && p.p.IsPlaying()
}

func (p *player) write(buf []byte) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.closed {
		return
	}
	if p.p == nil {
		return
	}
	p.p.AppendBuffer(buf)
}

func (p *player) loop() {
	buf := make([]byte, 4096)
	for {
		if !p.wait() {
			return
		}

		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setError(err)
			return
		}
		p.write(buf[:n])

		// Now p.p.Reset() doesn't close the stream gracefully. Then buffer size check is necessary here.
		if err == io.EOF && p.UnplayedBufferSize() == 0 {
			// Even when the unplayed buffer size is 0, the audio data in the hardware might not be played yet (#1632).
			// Just wait for a while.
			time.Sleep(100 * time.Millisecond)
			p.Reset()
			return
		}
	}
}
<commit_msg>audio/internal/readerdriver: Disable the reader driver for Android temporarily<commit_after>// Copyright 2021 The Ebiten 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 readerdriver

import (
	"io"
	"runtime"
	"sync"
	"time"

	"github.com/hajimehoshi/ebiten/v2/audio/internal/oboe"
)

func IsAvailable() bool {
	// Disable the reader driver for Android temporarily (#1645).
	return false
}

type context struct {
	sampleRate      int
	channelNum      int
	bitDepthInBytes int
}

func NewContext(sampleRate int, channelNum int, bitDepthInBytes int) (Context, chan struct{}, error) {
	ready := make(chan struct{})
	close(ready)

	c := &context{
		sampleRate:      sampleRate,
		channelNum:      channelNum,
		bitDepthInBytes: bitDepthInBytes,
	}
	return c, ready, nil
}

func (c *context) NewPlayer(src io.Reader) Player {
	p := &player{
		context: c,
		src:     src,
		cond:    sync.NewCond(&sync.Mutex{}),
		volume:  1,
	}
	runtime.SetFinalizer(p, (*player).Close)
	return p
}

func (c *context) Suspend() error {
	return oboe.Suspend()
}

func (c *context) Resume() error {
	return oboe.Resume()
}

type player struct {
	context *context
	p       *oboe.Player
	src     io.Reader
	err     error
	cond    *sync.Cond
	closed  bool
	volume  float64
}

func (p *player) Pause() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.closed {
		return
	}
	if p.p == nil {
		return
	}
	if err := p.p.Pause(); err != nil {
		p.setErrorImpl(err)
		return
	}
	p.cond.Signal()
}

func (p *player) Play() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.p != nil && p.p.IsPlaying() {
		return
	}
	defer p.cond.Signal()
	var runLoop bool
	if p.p == nil {
		p.p = oboe.NewPlayer(p.context.sampleRate, p.context.channelNum, p.context.bitDepthInBytes, p.volume, func() {
			p.cond.Signal()
		})
		runLoop = true
	}

	buf := make([]byte, p.context.maxBufferSize())
	for p.p.UnplayedBufferSize() < p.context.maxBufferSize() {
		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setErrorImpl(err)
			return
		}
		p.p.AppendBuffer(buf[:n])
		if err == io.EOF {
			break
		}
	}

	if err := p.p.Play(); err != nil {
		p.setErrorImpl(err)
		return
	}
	if runLoop {
		go p.loop()
	}
}

func (p *player) IsPlaying() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	if p.p == nil {
		return false
	}
	return p.p.IsPlaying()
}

func (p *player) Reset() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.closed {
		return
	}
	if p.p == nil {
		return
	}
	if err := p.p.Close(); err != nil {
		p.setErrorImpl(err)
		return
	}
	p.p = nil
	p.cond.Signal()
}

func (p *player) Volume() float64 {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.volume
}

func (p *player) SetVolume(volume float64) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.volume = volume
	if p.p == nil {
		return
	}
	p.p.SetVolume(volume)
}

func (p *player) UnplayedBufferSize() int {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	if p.p == nil {
		return 0
	}
	return p.p.UnplayedBufferSize()
}

func (p *player) Err() error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.err
}

func (p *player) Close() error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.closeImpl()
}

func (p *player) closeImpl() error {
	defer p.cond.Signal()

	runtime.SetFinalizer(p, nil)
	p.closed = true
	if p.p == nil {
		return p.err
	}
	if err := p.p.Close(); err != nil && p.err == nil {
		// Do not call setErrorImpl, or this can cause infinite recursive.
		p.err = err
		return p.err
	}
	p.p = nil
	return p.err
}

func (p *player) setError(err error) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.setErrorImpl(err)
}

func (p *player) setErrorImpl(err error) {
	p.err = err
	p.closeImpl()
}

func (p *player) shouldWait() bool {
	if p.closed {
		return false
	}
	if p.p == nil {
		return false
	}
	if p.p.IsPlaying() {
		return p.p.UnplayedBufferSize() >= p.context.maxBufferSize()
	}
	return true
}

func (p *player) wait() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	for p.shouldWait() {
		p.cond.Wait()
	}
	return p.p != nil && p.p.IsPlaying()
}

func (p *player) write(buf []byte) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.closed {
		return
	}
	if p.p == nil {
		return
	}
	p.p.AppendBuffer(buf)
}

func (p *player) loop() {
	buf := make([]byte, 4096)
	for {
		if !p.wait() {
			return
		}

		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setError(err)
			return
		}
		p.write(buf[:n])

		// Now p.p.Reset() doesn't close the stream gracefully. Then buffer size check is necessary here.
		if err == io.EOF && p.UnplayedBufferSize() == 0 {
			// Even when the unplayed buffer size is 0, the audio data in the hardware might not be played yet (#1632).
			// Just wait for a while.
			time.Sleep(100 * time.Millisecond)
			p.Reset()
			return
		}
	}
}
<|endoftext|>


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

package gopmod

import (
	"bytes"
	"crypto/sha1"
	"log"
	"os"
	"path/filepath"
	"sort"

	"github.com/goplus/gop/cl"
	"github.com/goplus/gop/parser"
	"github.com/goplus/gop/token"
	"github.com/goplus/gox"
)

// -----------------------------------------------------------------------------

type gopFiles struct {
	files []string
}

func (p *Context) openFromGopFiles(files []string) (proj *Project, err error) {
	proj = &Project{
		Source:        &gopFiles{files: files},
		UseDefaultCtx: true,
	}
	return
}

func (p *gopFiles) Fingerp() [20]byte { // source code fingerprint
	files := make([]string, len(p.files))
	for i, file := range p.files {
		files[i], _ = filepath.Abs(file)
	}
	sort.Strings(files)
	var buf bytes.Buffer
	for _, file := range files {
		fi, err := os.Stat(file)
		if err != nil {
			log.Panicln(err)
		}
		buf.WriteString(file)
		buf.WriteByte('\t')
		buf.WriteString(fi.ModTime().UTC().String())
		buf.WriteByte('\n')
	}
	return sha1.Sum(buf.Bytes())
}

func (p *gopFiles) IsDirty(outFile string, temp bool) bool {
	if fi, err := os.Lstat(outFile); err == nil { // TODO: more strictly
		return fi.IsDir()
	}
	return true
}

const (
	parserMode = parser.ParseComments
)

func (p *gopFiles) GenGo(outFile, modFile string) error {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseFiles(fset, p.files, parserMode)
	if err != nil {
		return err
	}
	if len(pkgs) != 1 {
		log.Panicln("TODO: mutli packages -", len(pkgs))
	}
	mainPkg, ok := pkgs["main"]
	if !ok {
		panic("TODO: main package not found")
	}

	srcDir, _ := filepath.Split(outFile)
	modDir, _ := filepath.Split(modFile)
	conf := &cl.Config{
		Dir: modDir, TargetDir: srcDir, Fset: fset, CacheLoadPkgs: true, PersistLoadPkgs: true}
	out, err := cl.NewPackage("", mainPkg, conf)
	if err != nil {
		return err
	}
	err = gox.WriteFile(outFile, out, false)
	if err != nil {
		return err
	}
	conf.PkgsLoader.Save()
	return nil
}

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

package gopmod

import (
	"bytes"
	"crypto/sha1"
	"log"
	"os"
	"path/filepath"
	"sort"

	"github.com/goplus/gop/cl"
	"github.com/goplus/gop/parser"
	"github.com/goplus/gop/token"
	"github.com/goplus/gox"
)

// -----------------------------------------------------------------------------

type gopFiles struct {
	files []string
}

func (p *Context) openFromGopFiles(files []string) (proj *Project, err error) {
	proj = &Project{
		Source:        &gopFiles{files: files},
		UseDefaultCtx: true,
	}
	if len(files) == 1 {
		proj.FriendlyFname = filepath.Base(files[0])
	}
	return
}

func (p *gopFiles) Fingerp() [20]byte { // source code fingerprint
	files := make([]string, len(p.files))
	for i, file := range p.files {
		files[i], _ = filepath.Abs(file)
	}
	sort.Strings(files)
	var buf bytes.Buffer
	for _, file := range files {
		fi, err := os.Stat(file)
		if err != nil {
			log.Panicln(err)
		}
		buf.WriteString(file)
		buf.WriteByte('\t')
		buf.WriteString(fi.ModTime().UTC().String())
		buf.WriteByte('\n')
	}
	return sha1.Sum(buf.Bytes())
}

func (p *gopFiles) IsDirty(outFile string, temp bool) bool {
	if fi, err := os.Lstat(outFile); err == nil { // TODO: more strictly
		return fi.IsDir()
	}
	return true
}

const (
	parserMode = parser.ParseComments
)

func (p *gopFiles) GenGo(outFile, modFile string) error {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseFiles(fset, p.files, parserMode)
	if err != nil {
		return err
	}
	if len(pkgs) != 1 {
		log.Panicln("TODO: mutli packages -", len(pkgs))
	}
	mainPkg, ok := pkgs["main"]
	if !ok {
		panic("TODO: main package not found")
	}

	srcDir, _ := filepath.Split(outFile)
	modDir, _ := filepath.Split(modFile)
	conf := &cl.Config{
		Dir: modDir, TargetDir: srcDir, Fset: fset, CacheLoadPkgs: true, PersistLoadPkgs: true}
	out, err := cl.NewPackage("", mainPkg, conf)
	if err != nil {
		return err
	}
	err = gox.WriteFile(outFile, out, false)
	if err != nil {
		return err
	}
	conf.PkgsLoader.Save()
	return nil
}

// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// HelpForDebug outputs usage information for the debug command.
func (commands *CommandSet) HelpForDebug() {
	fmt.Println("bigv debug")
	fmt.Println()
	fmt.Println("Usage:")
	fmt.Println("    bigv debug GET <path>")
	fmt.Println("    bigv debug DELETE <path>")
	fmt.Println()
	fmt.Println("GET sends an HTTP GET request with a valid authorization header to the given path on the BigV endpoint and pretty-prints the received json.")
	fmt.Println()
}

// TODO(telyn): does the URL really have to start with /?

// Debug makes an HTTP <method> request to the URL specified in the arguments.
// command syntax: debug <method> <url>
// URL probably needs to start with a /
func (commands *CommandSet) Debug(args []string) {
	if len(args) < 1 {
		commands.HelpForDebug()
		return
	}

	switch args[0] {
	case "GET", "PUT", "POST", "DELETE":
		// TODO(telyn): add a flag to disable auth
		// TODO(telyn): add a flag to junk the token
		shouldAuth := true
		commands.EnsureAuth()
		body, err := commands.bigv.RequestAndRead(shouldAuth, args[0], args[1], "")
		if err != nil {
			exit(err)
		}

		buf := new(bytes.Buffer)
		json.Indent(buf, body, "", "    ")
		fmt.Printf("%s", buf)
	case "config":
		indented, _ := json.MarshalIndent(commands.config.GetAll(), "", "    ")
		fmt.Printf("%s", indented)
	default:
		commands.HelpForDebug()
	}
}
<commit_msg>Improved debug command: * --auth is now necessary to enable authentication * --junk-token wipes out the stored token * PUT and POSTs now read from stdin until eof.<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"strings"
)

// HelpForDebug outputs usage information for the debug command.
func (commands *CommandSet) HelpForDebug() {
	fmt.Println("bigv debug")
	fmt.Println()
	fmt.Println("Usage:")
	fmt.Println("    bigv debug [--junk-token] [--auth] GET <path>")
	fmt.Println("    bigv debug [--junk-token] [--auth] DELETE <path>")
	fmt.Println("    bigv debug [--junk-token] [--auth] PUT <path>")
	fmt.Println("    bigv debug [--junk-token] [--auth] POST <path>")
	fmt.Println()
	fmt.Println("GET sends an HTTP GET request with an optional valid authorization header to the given path on the BigV endpoint and pretty-prints the received json.")
	fmt.Println("The rest do similar, but PUT and POST")
	fmt.Println("The --junk-token flag sets the token to empty - useful if you want to ensure that credential-auth is working, or you want to do something as another user")
	fmt.Println("The --auth token tells the client to gain valid auth and send the auth header on that request.")
	fmt.Println()
}

// Debug makes an HTTP <method> request to the URL specified in the arguments.
// command syntax: debug <method> <url>
func (commands *CommandSet) Debug(args []string) {
	flags := MakeCommonFlagSet()
	junkToken := flags.Bool("junk-token", false, "")
	shouldAuth := flags.Bool("auth", false, "")
	flags.Parse(args)
	args = commands.config.ImportFlags(flags)

	if *junkToken {
		commands.config.Set("token", "", "FLAG junk-token")
	}

	if len(args) < 1 {
		commands.HelpForDebug()
		return
	}

	switch args[0] {
	case "GET", "PUT", "POST", "DELETE":
		if !strings.HasPrefix(args[1], "/") {
			args[1] = "/" + args[1]
		}
		if *shouldAuth {
			commands.EnsureAuth()
		}

		requestBody := ""
		err := error(nil)
		if args[0] == "PUT" || args[0] == "POST" {
			buf := bufio.NewReader(os.Stdin)
			requestBody, err = buf.ReadString(byte(uint8(14)))
			if err != nil {
				panic("Couldn't read from stdin")
			}
		}
		body, err := commands.bigv.RequestAndRead(*shouldAuth, args[0], args[1], requestBody)
		if err != nil {
			exit(err)
		}

		buf := new(bytes.Buffer)
		json.Indent(buf, body, "", "    ")
		fmt.Printf("%s", buf)
	case "config":
		indented, _ := json.MarshalIndent(commands.config.GetAll(), "", "    ")
		fmt.Printf("%s", indented)
	default:
		commands.HelpForDebug()
	}
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"sync"
	"time"

	"github.com/boltdb/bolt"

	"github.com/michaelorr/goodall/pkg/db"
	"github.com/michaelorr/goodall/pkg/metrics"
)

func Run() int {
	conn, err := db.Open()
	if err != nil {
		return 1
	}
	err = db.Init(conn)
	if err != nil {
		return 2
	}

	response := make(chan int)
	go GatherMetrics(conn, response)
	go CleanupMetrics(conn)
	return <-response
}

func CleanupMetrics(conn *bolt.DB) {
	for {
		conn.Update(func(tx *bolt.Tx) error {
			return tx.ForEach(func(name []byte, b *bolt.Bucket) error{
				c := b.Cursor()

				// TODO
				// Extract this to a better location
				min := []byte("2016-01-01T00:00:00Z")
				// TODO
				// Extract this to a better location
				// Make this configurable
				max := []byte(time.Now().UTC().Add(-1 * time.Minute).Format(time.RFC3339))

				for k, _ := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, _ = c.Next() {
					err := b.Delete(k)
					if err != nil {
						return err
					}
				}
				return nil
			})
		})

		time.Sleep(metrics.Interval)
	}
}

func GatherMetrics(conn *bolt.DB, response chan int) {
	for {
		var wg sync.WaitGroup
		now := time.Now().UTC().Format(time.RFC3339)
		results := make(chan *metrics.DataPoint, len(metrics.BucketMap))

		// spin off goroutines to fetch each metric
		for bucket, fetch_metric := range metrics.BucketMap {
			wg.Add(1)
			go fetch_metric(bucket, results)
		}

		// wait until all metrics goroutines complete before continuing
		go func() {
			wg.Wait()
			close(results)
		}()

		// gather the results
		for result := range results {
			// TODO do this in a separate goroutine in the connection package
			err := conn.Update(func(tx *bolt.Tx) error {
				b := tx.Bucket([]byte(result.BucketName))
				if b == nil {
					// TODO Bucket does not exist
				}
				val, err := db.Ftob(result.Value)
				// TODO error checking
				err = b.Put([]byte(now), val)
				return err
			})
			// TODO error checking
			_ = err

			wg.Done()
		}

		time.Sleep(metrics.Interval)
	}
}
<commit_msg>go fmt<commit_after>package client

import (
	"bytes"
	"sync"
	"time"

	"github.com/boltdb/bolt"

	"github.com/michaelorr/goodall/pkg/db"
	"github.com/michaelorr/goodall/pkg/metrics"
)

func Run() int {
	conn, err := db.Open()
	if err != nil {
		return 1
	}
	err = db.Init(conn)
	if err != nil {
		return 2
	}

	response := make(chan int)
	go GatherMetrics(conn, response)
	go CleanupMetrics(conn)
	return <-response
}

func CleanupMetrics(conn *bolt.DB) {
	for {
		conn.Update(func(tx *bolt.Tx) error {
			return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
				c := b.Cursor()

				// TODO
				// Extract this to a better location
				min := []byte("2016-01-01T00:00:00Z")
				// TODO
				// Extract this to a better location
				// Make this configurable
				max := []byte(time.Now().UTC().Add(-1 * time.Minute).Format(time.RFC3339))

				for k, _ := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, _ = c.Next() {
					err := b.Delete(k)
					if err != nil {
						return err
					}
				}
				return nil
			})
		})

		time.Sleep(metrics.Interval)
	}
}

func GatherMetrics(conn *bolt.DB, response chan int) {
	for {
		var wg sync.WaitGroup
		now := time.Now().UTC().Format(time.RFC3339)
		results := make(chan *metrics.DataPoint, len(metrics.BucketMap))

		// spin off goroutines to fetch each metric
		for bucket, fetch_metric := range metrics.BucketMap {
			wg.Add(1)
			go fetch_metric(bucket, results)
		}

		// wait until all metrics goroutines complete before continuing
		go func() {
			wg.Wait()
			close(results)
		}()

		// gather the results
		for result := range results {
			// TODO do this in a separate goroutine in the connection package
			err := conn.Update(func(tx *bolt.Tx) error {
				b := tx.Bucket([]byte(result.BucketName))
				if b == nil {
					// TODO Bucket does not exist
				}
				val, err := db.Ftob(result.Value)
				// TODO error checking
				err = b.Put([]byte(now), val)
				return err
			})
			// TODO error checking
			_ = err

			wg.Done()
		}

		time.Sleep(metrics.Interval)
	}
}
<|endoftext|>


<commit_before>package image

import (
	"fmt"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"

	"github.com/flant/werf/pkg/docker"
)

type base struct {
	name    string
	inspect *types.ImageInspect
}

func newBaseImage(name string) *base {
	image := &base{}
	image.name = name
	return image
}

func (i *base) Name() string {
	return i.name
}

func (i *base) MustGetId() (string, error) {
	if inspect, err := i.MustGetInspect(); err == nil {
		return inspect.ID, nil
	} else {
		return "", err
	}
}

func (i *base) MustGetInspect() (*types.ImageInspect, error) {
	if inspect, err := i.GetInspect(); err == nil && inspect != nil {
		return inspect, nil
	} else if err != nil {
		return nil, err
	} else {
		panic(fmt.Sprintf("runtime error: inspect must be (%s)", i.name))
	}
}

func (i *base) ResetInspect() error {
	i.unsetInspect()
	_, err := i.GetInspect()
	return err
}

func (i *base) GetInspect() (*types.ImageInspect, error) {
	if i.inspect == nil {
		if err := i.resetInspect(); err != nil {
			if client.IsErrNotFound(err) {
				return nil, nil
			} else {
				return nil, err
			}
		}
	}
	return i.inspect, nil
}

func (i *base) resetInspect() error {
	inspect, err := docker.ImageInspect(i.name)
	if err != nil {
		return err
	}

	i.inspect = inspect
	return nil
}

func (i *base) unsetInspect() {
	i.inspect = nil
}

func (i *base) Untag() error {
	if err := docker.CliRmi(i.name); err != nil {
		return err
	}

	i.unsetInspect()

	return nil
}
<commit_msg>[build] Force rmi invalid stage image (untag)<commit_after>package image

import (
	"fmt"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"

	"github.com/flant/werf/pkg/docker"
)

type base struct {
	name    string
	inspect *types.ImageInspect
}

func newBaseImage(name string) *base {
	image := &base{}
	image.name = name
	return image
}

func (i *base) Name() string {
	return i.name
}

func (i *base) MustGetId() (string, error) {
	if inspect, err := i.MustGetInspect(); err == nil {
		return inspect.ID, nil
	} else {
		return "", err
	}
}

func (i *base) MustGetInspect() (*types.ImageInspect, error) {
	if inspect, err := i.GetInspect(); err == nil && inspect != nil {
		return inspect, nil
	} else if err != nil {
		return nil, err
	} else {
		panic(fmt.Sprintf("runtime error: inspect must be (%s)", i.name))
	}
}

func (i *base) ResetInspect() error {
	i.unsetInspect()
	_, err := i.GetInspect()
	return err
}

func (i *base) GetInspect() (*types.ImageInspect, error) {
	if i.inspect == nil {
		if err := i.resetInspect(); err != nil {
			if client.IsErrNotFound(err) {
				return nil, nil
			} else {
				return nil, err
			}
		}
	}
	return i.inspect, nil
}

func (i *base) resetInspect() error {
	inspect, err := docker.ImageInspect(i.name)
	if err != nil {
		return err
	}

	i.inspect = inspect
	return nil
}

func (i *base) unsetInspect() {
	i.inspect = nil
}

func (i *base) Untag() error {
	if err := docker.CliRmi(i.name, "--force"); err != nil {
		return err
	}

	i.unsetInspect()

	return nil
}
<|endoftext|>


<commit_before>package rpc

import (
	"context"
	"encoding/json"
	"io"
	"net"
	"net/http"
	"net/url"
	"time"
)

// Client represents an RPC client interface
type Client interface {
	Query(endpoint, query string) Result
}

// SocketClient is a client that talks to a local socket
type SocketClient struct {
	socketPath string
}

// NewClient creates a new Client from a config
func NewClient(socketPath string) SocketClient {
	return SocketClient{
		socketPath: socketPath,
	}
}

// How long to wait before giving up on the backend
const socketTimeout = 100 * time.Millisecond

// Query executes a query against the RPC server.
//
// Returns a Result if the RPC call completed successfully, regardless of
// whether the ultimate value is ready or not.
func (sc SocketClient) Query(endpoint, query string) Result {
	var res Result

	if len(sc.socketPath) == 0 {
		return Result{Complete: true} // RPC isn't enabled, don't worry about it
	}

	httpClient := http.Client{
		Transport: &http.Transport{
			DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
				d := net.Dialer{}
				return d.DialContext(ctx, "unix", sc.socketPath)
			},
		},
		Timeout: socketTimeout,
	}

	u, err := url.Parse("http://gh-shorthand" + endpoint)
	if err != nil {
		res.Complete = true
		res.Error = "url parsing error: " + err.Error()
		return res
	}
	v := url.Values{}
	v.Set("q", query)
	u.RawQuery = v.Encode()

	resp, err := httpClient.Get(u.String())
	if err != nil {
		res.Error = "RPC service error: " + err.Error()
		res.Complete = true
		return res
	}
	if resp.StatusCode >= 400 {
		res.Error = "RPC service error: " + resp.Status
		res.Complete = true
		return res
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		res.Error = "RPC response error: " + err.Error()
		res.Complete = true
		return res
	}
	err = json.Unmarshal(body, &res)
	if err != nil {
		res.Error = "unmarshal error: " + err.Error()
		res.Complete = true
		return res
	}

	return res
}
<commit_msg>bump socket timeout<commit_after>package rpc

import (
	"context"
	"encoding/json"
	"io"
	"net"
	"net/http"
	"net/url"
	"time"
)

// Client represents an RPC client interface
type Client interface {
	Query(endpoint, query string) Result
}

// SocketClient is a client that talks to a local socket
type SocketClient struct {
	socketPath string
}

// NewClient creates a new Client from a config
func NewClient(socketPath string) SocketClient {
	return SocketClient{
		socketPath: socketPath,
	}
}

// How long to wait before giving up on the backend
const socketTimeout = 250 * time.Millisecond

// Query executes a query against the RPC server.
//
// Returns a Result if the RPC call completed successfully, regardless of
// whether the ultimate value is ready or not.
func (sc SocketClient) Query(endpoint, query string) Result {
	var res Result

	if len(sc.socketPath) == 0 {
		return Result{Complete: true} // RPC isn't enabled, don't worry about it
	}

	httpClient := http.Client{
		Transport: &http.Transport{
			DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
				d := net.Dialer{}
				return d.DialContext(ctx, "unix", sc.socketPath)
			},
		},
		Timeout: socketTimeout,
	}

	u, err := url.Parse("http://gh-shorthand" + endpoint)
	if err != nil {
		res.Complete = true
		res.Error = "url parsing error: " + err.Error()
		return res
	}
	v := url.Values{}
	v.Set("q", query)
	u.RawQuery = v.Encode()

	resp, err := httpClient.Get(u.String())
	if err != nil {
		res.Error = "RPC service error: " + err.Error()
		res.Complete = true
		return res
	}
	if resp.StatusCode >= 400 {
		res.Error = "RPC service error: " + resp.Status
		res.Complete = true
		return res
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		res.Error = "RPC response error: " + err.Error()
		res.Complete = true
		return res
	}
	err = json.Unmarshal(body, &res)
	if err != nil {
		res.Error = "unmarshal error: " + err.Error()
		res.Complete = true
		return res
	}

	return res
}
<|endoftext|>


<commit_before>// Copyright © 2017 The Things Network. Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package pktfwd

import (
	"context"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/TheThingsNetwork/go-utils/log"
	"github.com/TheThingsNetwork/packet_forwarder/util"
	"github.com/TheThingsNetwork/packet_forwarder/wrapper"
	"github.com/pkg/errors"
)

const (
	initUplinkPollingRate   = 100 * time.Microsecond
	stableUplinkPollingRate = 5 * time.Millisecond
	statusRoutineSleepRate  = 15 * time.Second
	gpsUpdateRate           = 5 * time.Millisecond
)

/* Manager struct manages the routines during runtime, once the gateways and network
configuration have been set up. It startes a routine, that it only stopped when the
users wants to close the program or that an error occurs. */
type Manager struct {
	ctx               log.Interface
	conf              util.Config
	netClient         NetworkClient
	statusMgr         StatusManager
	uplinkPollingRate time.Duration
	// Concentrator boot time
	bootTimeSetters     multipleBootTimeSetter
	foundBootTime       bool
	isGPS               bool
	ignoreCRC           bool
	downlinksSendMargin time.Duration
}

func NewManager(ctx log.Interface, conf util.Config, netClient NetworkClient, gpsPath string, runConfig TTNConfig) Manager {
	isGPS := gpsPath != ""
	statusMgr := NewStatusManager(ctx, netClient.FrequencyPlan(), runConfig.GatewayDescription, isGPS, netClient.DefaultLocation())

	bootTimeSetters := NewMultipleBootTimeSetter()
	bootTimeSetters.Add(statusMgr)

	return Manager{
		ctx:             ctx,
		conf:            conf,
		netClient:       netClient,
		statusMgr:       statusMgr,
		bootTimeSetters: bootTimeSetters,
		isGPS:           isGPS,
		// At the beginning, until we get our first uplinks, we keep a high polling rate to the concentrator
		uplinkPollingRate:   initUplinkPollingRate,
		downlinksSendMargin: runConfig.DownlinksSendMargin,
		ignoreCRC:           runConfig.IgnoreCRC,
	}
}

func (m *Manager) run() error {
	runStart := time.Now()
	m.ctx.WithField("DateTime", runStart).Info("Starting concentrator...")
	err := wrapper.StartLoRaGateway()
	if err != nil {
		return err
	}

	m.ctx.WithField("DateTime", time.Now()).Info("Concentrator started, packets can now be received and sent")
	err = m.handler(runStart)
	if shutdownErr := m.shutdown(); shutdownErr != nil {
		m.ctx.WithError(shutdownErr).Error("Couldn't stop concentrator gracefully")
	}
	return err
}

func (m *Manager) handler(runStart time.Time) (err error) {
	// First, we'll handle the case when the user wants to end the program
	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGABRT)

	// We'll start the routines, and attach them a context
	bgCtx, cancel := context.WithCancel(context.Background())
	defer cancel()
	var routinesErr = make(chan error)
	go m.startRoutines(bgCtx, routinesErr, runStart)

	// Finally, we'll listen to the different issues
	select {
	case sig := <-c:
		m.ctx.WithField("Signal", sig.String()).Info("Stopping packet forwarder")
	case err = <-routinesErr:
		m.ctx.Error("Program ended after one of the network links failed")
	}

	return err
}

func (m *Manager) findConcentratorBootTime(packets []wrapper.Packet, runStart time.Time) error {
	currentTime := time.Now()
	highestTimestamp := uint32(0)
	for _, p := range packets {
		if p.CountUS > highestTimestamp {
			highestTimestamp = p.CountUS
		}
	}
	if highestTimestamp == 0 {
		return nil
	}

	// Estimated boot time: highest timestamp (closest to current time) substracted to the current time
	highestTimestampDuration := time.Duration(highestTimestamp) * time.Microsecond
	bootTime := currentTime.Add(-highestTimestampDuration)
	if runStart.After(bootTime) || bootTime.After(time.Now()) {
		// Absurd timestamp
		return errors.New("Absurd uptime received by concentrator")
	}
	m.ctx.WithField("BootTime", bootTime).Info("Determined concentrator boot time")
	m.setBootTime(bootTime)
	return nil
}

func (m *Manager) setBootTime(bootTime time.Time) {
	m.bootTimeSetters.SetBootTime(bootTime)
	m.foundBootTime = true
	m.uplinkPollingRate = stableUplinkPollingRate
}

func (m *Manager) uplinkRoutine(bgCtx context.Context, runStart time.Time) chan error {
	errC := make(chan error)
	go func() {
		m.ctx.Info("Waiting for uplink packets")
		for {
			packets, err := wrapper.Receive()
			if err != nil {
				errC <- errors.Wrap(err, "Uplink packets retrieval error")
				return
			}
			if len(packets) == 0 { // Empty payload => we sleep, then reiterate.
				time.Sleep(m.uplinkPollingRate)
				continue
			}

			m.ctx.WithField("NbPackets", len(packets)).Info("Received uplink packets")
			if !m.foundBootTime {
				// First packets received => find concentrator boot time
				err = m.findConcentratorBootTime(packets, runStart)
				if err != nil {
					m.ctx.WithError(err).Warn("Error when computing concentrator boot time - using packet forwarder run start time")
					m.setBootTime(runStart)
				}
			}

			validPackets, err := wrapUplinkPayload(packets, m.ignoreCRC, m.netClient.GatewayID())
			if err != nil {
				continue
			}
			m.statusMgr.HandledRXBatch(len(validPackets), len(packets))
			if len(validPackets) == 0 {
				m.ctx.Warn("Packets received, but with invalid CRC - ignoring")
				time.Sleep(m.uplinkPollingRate)
				continue
			}

			m.ctx.WithField("NbValidPackets", len(validPackets)).Info("Received valid packets - sending them to the back-end")
			m.netClient.SendUplinks(validPackets)

			select {
			case <-bgCtx.Done():
				errC <- nil
				return
			default:
				continue
			}
		}
	}()
	return errC
}

func (m *Manager) gpsRoutine(bgCtx context.Context) chan error {
	errC := make(chan error)
	go func() {
		m.ctx.Info("Starting GPS update routine")
		for {
			select {
			case <-bgCtx.Done():
				return
			default:
				// The GPS time reference and coordinates are updated at `gpsUpdateRate`
				err := wrapper.UpdateGPSData(m.ctx)
				if err != nil {
					errC <- errors.Wrap(err, "GPS update error")
				}
			}
		}
	}()
	return errC
}

func (m *Manager) downlinkRoutine(bgCtx context.Context) {
	m.ctx.Info("Waiting for downlink messages")
	downlinkQueue := m.netClient.Downlinks()
	dManager := NewDownlinkManager(bgCtx, m.ctx, m.conf, m.statusMgr, m.downlinksSendMargin)
	m.bootTimeSetters.Add(dManager)
	for {
		select {
		case downlink := <-downlinkQueue:
			m.ctx.Info("Scheduling newly-received downlink packet")
			m.statusMgr.ReceivedTX()
			dManager.ScheduleDownlink(downlink)
		case <-bgCtx.Done():
			return
		}
	}
}

func (m *Manager) statusRoutine(bgCtx context.Context) chan error {
	errC := make(chan error)
	go func() {
		for {
			select {
			case <-time.After(statusRoutineSleepRate):
				rtt, err := m.netClient.Ping()
				if err != nil {
					errC <- errors.Wrap(err, "Network server health check error")
					continue
				}

				status, err := m.statusMgr.GenerateStatus(rtt)
				if err != nil {
					errC <- errors.Wrap(err, "Gateway status computation error")
					return
				}

				err = m.netClient.SendStatus(*status)
				if err != nil {
					errC <- errors.Wrap(err, "Gateway status transmission error")
					return
				}
			case <-bgCtx.Done():
				return
			}
		}
	}()
	return errC
}

func (m *Manager) networkRoutine(bgCtx context.Context) chan error {
	errC := make(chan error)
	go func() {
		if err := m.netClient.RefreshRoutine(bgCtx); err != nil {
			errC <- errors.Wrap(err, "Couldn't refresh account server token")
		}
	}()
	return errC
}

func (m *Manager) startRoutines(bgCtx context.Context, err chan error, runTime time.Time) {
	upCtx, upCancel := context.WithCancel(bgCtx)
	downCtx, downCancel := context.WithCancel(bgCtx)
	statusCtx, statusCancel := context.WithCancel(bgCtx)
	gpsCtx, gpsCancel := context.WithCancel(bgCtx)
	networkCtx, networkCancel := context.WithCancel(bgCtx)

	go m.downlinkRoutine(downCtx)
	uplinkErrors := m.uplinkRoutine(upCtx, runTime)
	statusErrors := m.statusRoutine(statusCtx)
	networkErrors := m.networkRoutine(networkCtx)
	var gpsErrors chan error
	if m.isGPS {
		gpsErrors = m.gpsRoutine(gpsCtx)
	}
	select {
	case uplinkError := <-uplinkErrors:
		err <- errors.Wrap(uplinkError, "Uplink routine error")
	case statusError := <-statusErrors:
		err <- errors.Wrap(statusError, "Status routine error")
	case networkError := <-networkErrors:
		err <- errors.Wrap(networkError, "Network routine error")
	case gpsError := <-gpsErrors:
		err <- errors.Wrap(gpsError, "GPS routine error")
	case <-bgCtx.Done():
		err <- nil
	}
	upCancel()
	gpsCancel()
	downCancel()
	statusCancel()
	networkCancel()
}

func (m *Manager) shutdown() error {
	m.netClient.Stop()
	return stopGateway(m.ctx)
}

func stopGateway(ctx log.Interface) error {
	err := wrapper.StopLoRaGateway()
	if err != nil {
		return err
	}

	ctx.Info("Concentrator stopped gracefully")
	return nil
}
<commit_msg>Closing channels at the end of routine<commit_after>// Copyright © 2017 The Things Network. Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package pktfwd

import (
	"context"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/TheThingsNetwork/go-utils/log"
	"github.com/TheThingsNetwork/packet_forwarder/util"
	"github.com/TheThingsNetwork/packet_forwarder/wrapper"
	"github.com/pkg/errors"
)

const (
	initUplinkPollingRate   = 100 * time.Microsecond
	stableUplinkPollingRate = 5 * time.Millisecond
	statusRoutineSleepRate  = 15 * time.Second
	gpsUpdateRate           = 5 * time.Millisecond
)

/* Manager struct manages the routines during runtime, once the gateways and network
configuration have been set up. It startes a routine, that it only stopped when the
users wants to close the program or that an error occurs. */
type Manager struct {
	ctx               log.Interface
	conf              util.Config
	netClient         NetworkClient
	statusMgr         StatusManager
	uplinkPollingRate time.Duration
	// Concentrator boot time
	bootTimeSetters     multipleBootTimeSetter
	foundBootTime       bool
	isGPS               bool
	ignoreCRC           bool
	downlinksSendMargin time.Duration
}

func NewManager(ctx log.Interface, conf util.Config, netClient NetworkClient, gpsPath string, runConfig TTNConfig) Manager {
	isGPS := gpsPath != ""
	statusMgr := NewStatusManager(ctx, netClient.FrequencyPlan(), runConfig.GatewayDescription, isGPS, netClient.DefaultLocation())

	bootTimeSetters := NewMultipleBootTimeSetter()
	bootTimeSetters.Add(statusMgr)

	return Manager{
		ctx:             ctx,
		conf:            conf,
		netClient:       netClient,
		statusMgr:       statusMgr,
		bootTimeSetters: bootTimeSetters,
		isGPS:           isGPS,
		// At the beginning, until we get our first uplinks, we keep a high polling rate to the concentrator
		uplinkPollingRate:   initUplinkPollingRate,
		downlinksSendMargin: runConfig.DownlinksSendMargin,
		ignoreCRC:           runConfig.IgnoreCRC,
	}
}

func (m *Manager) run() error {
	runStart := time.Now()
	m.ctx.WithField("DateTime", runStart).Info("Starting concentrator...")
	err := wrapper.StartLoRaGateway()
	if err != nil {
		return err
	}

	m.ctx.WithField("DateTime", time.Now()).Info("Concentrator started, packets can now be received and sent")
	err = m.handler(runStart)
	if shutdownErr := m.shutdown(); shutdownErr != nil {
		m.ctx.WithError(shutdownErr).Error("Couldn't stop concentrator gracefully")
	}
	return err
}

func (m *Manager) handler(runStart time.Time) (err error) {
	// First, we'll handle the case when the user wants to end the program
	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGABRT)

	// We'll start the routines, and attach them a context
	bgCtx, cancel := context.WithCancel(context.Background())
	defer cancel()
	var routinesErr = make(chan error)
	go m.startRoutines(bgCtx, routinesErr, runStart)

	// Finally, we'll listen to the different issues
	select {
	case sig := <-c:
		m.ctx.WithField("Signal", sig.String()).Info("Stopping packet forwarder")
	case err = <-routinesErr:
		m.ctx.Error("Program ended after one of the network links failed")
	}

	return err
}

func (m *Manager) findConcentratorBootTime(packets []wrapper.Packet, runStart time.Time) error {
	currentTime := time.Now()
	highestTimestamp := uint32(0)
	for _, p := range packets {
		if p.CountUS > highestTimestamp {
			highestTimestamp = p.CountUS
		}
	}
	if highestTimestamp == 0 {
		return nil
	}

	// Estimated boot time: highest timestamp (closest to current time) substracted to the current time
	highestTimestampDuration := time.Duration(highestTimestamp) * time.Microsecond
	bootTime := currentTime.Add(-highestTimestampDuration)
	if runStart.After(bootTime) || bootTime.After(time.Now()) {
		// Absurd timestamp
		return errors.New("Absurd uptime received by concentrator")
	}
	m.ctx.WithField("BootTime", bootTime).Info("Determined concentrator boot time")
	m.setBootTime(bootTime)
	return nil
}

func (m *Manager) setBootTime(bootTime time.Time) {
	m.bootTimeSetters.SetBootTime(bootTime)
	m.foundBootTime = true
	m.uplinkPollingRate = stableUplinkPollingRate
}

func (m *Manager) uplinkRoutine(bgCtx context.Context, runStart time.Time) chan error {
	errC := make(chan error)
	go func() {
		m.ctx.Info("Waiting for uplink packets")
		for {
			packets, err := wrapper.Receive()
			if err != nil {
				errC <- errors.Wrap(err, "Uplink packets retrieval error")
				return
			}
			if len(packets) == 0 { // Empty payload => we sleep, then reiterate.
				time.Sleep(m.uplinkPollingRate)
				continue
			}

			m.ctx.WithField("NbPackets", len(packets)).Info("Received uplink packets")
			if !m.foundBootTime {
				// First packets received => find concentrator boot time
				err = m.findConcentratorBootTime(packets, runStart)
				if err != nil {
					m.ctx.WithError(err).Warn("Error when computing concentrator boot time - using packet forwarder run start time")
					m.setBootTime(runStart)
				}
			}

			validPackets, err := wrapUplinkPayload(packets, m.ignoreCRC, m.netClient.GatewayID())
			if err != nil {
				continue

			}
			m.statusMgr.HandledRXBatch(len(validPackets), len(packets))
			if len(validPackets) == 0 {
				m.ctx.Warn("Packets received, but with invalid CRC - ignoring")
				time.Sleep(m.uplinkPollingRate)
				continue
			}

			m.ctx.WithField("NbValidPackets", len(validPackets)).Info("Received valid packets - sending them to the back-end")
			m.netClient.SendUplinks(validPackets)

			select {
			case <-bgCtx.Done():
				errC <- nil
				close(errC)
				return
			default:
				continue
			}
		}
	}()
	return errC
}

func (m *Manager) gpsRoutine(bgCtx context.Context) chan error {
	errC := make(chan error)
	go func() {
		m.ctx.Info("Starting GPS update routine")
		for {
			select {
			case <-bgCtx.Done():
				close(errC)
				return
			default:
				// The GPS time reference and coordinates are updated at `gpsUpdateRate`
				err := wrapper.UpdateGPSData(m.ctx)
				if err != nil {
					errC <- errors.Wrap(err, "GPS update error")
				}
			}
		}
	}()
	return errC
}

func (m *Manager) downlinkRoutine(bgCtx context.Context) {
	m.ctx.Info("Waiting for downlink messages")
	downlinkQueue := m.netClient.Downlinks()
	dManager := NewDownlinkManager(bgCtx, m.ctx, m.conf, m.statusMgr, m.downlinksSendMargin)
	m.bootTimeSetters.Add(dManager)
	for {
		select {
		case downlink := <-downlinkQueue:
			m.ctx.Info("Scheduling newly-received downlink packet")
			m.statusMgr.ReceivedTX()
			dManager.ScheduleDownlink(downlink)
		case <-bgCtx.Done():
			return
		}
	}
}

func (m *Manager) statusRoutine(bgCtx context.Context) chan error {
	errC := make(chan error)
	go func() {
		defer close(errC)
		for {
			select {
			case <-time.After(statusRoutineSleepRate):
				rtt, err := m.netClient.Ping()
				if err != nil {
					errC <- errors.Wrap(err, "Network server health check error")
					return
				}

				status, err := m.statusMgr.GenerateStatus(rtt)
				if err != nil {
					errC <- errors.Wrap(err, "Gateway status computation error")
					return
				}

				err = m.netClient.SendStatus(*status)
				if err != nil {
					errC <- errors.Wrap(err, "Gateway status transmission error")
					return
				}
			case <-bgCtx.Done():
				return
			}
		}
	}()
	return errC
}

func (m *Manager) networkRoutine(bgCtx context.Context) chan error {
	errC := make(chan error)
	go func() {
		if err := m.netClient.RefreshRoutine(bgCtx); err != nil {
			errC <- errors.Wrap(err, "Couldn't refresh account server token")
			close(errC)
			return
		}
	}()
	return errC
}

func (m *Manager) startRoutines(bgCtx context.Context, err chan error, runTime time.Time) {
	upCtx, upCancel := context.WithCancel(bgCtx)
	downCtx, downCancel := context.WithCancel(bgCtx)
	statusCtx, statusCancel := context.WithCancel(bgCtx)
	gpsCtx, gpsCancel := context.WithCancel(bgCtx)
	networkCtx, networkCancel := context.WithCancel(bgCtx)

	go m.downlinkRoutine(downCtx)
	uplinkErrors := m.uplinkRoutine(upCtx, runTime)
	statusErrors := m.statusRoutine(statusCtx)
	networkErrors := m.networkRoutine(networkCtx)
	var gpsErrors chan error
	if m.isGPS {
		gpsErrors = m.gpsRoutine(gpsCtx)
	}
	select {
	case uplinkError := <-uplinkErrors:
		err <- errors.Wrap(uplinkError, "Uplink routine error")
	case statusError := <-statusErrors:
		err <- errors.Wrap(statusError, "Status routine error")
	case networkError := <-networkErrors:
		err <- errors.Wrap(networkError, "Network routine error")
	case gpsError := <-gpsErrors:
		err <- errors.Wrap(gpsError, "GPS routine error")
	case <-bgCtx.Done():
		err <- nil
	}
	upCancel()
	gpsCancel()
	downCancel()
	statusCancel()
	networkCancel()
}

func (m *Manager) shutdown() error {
	m.netClient.Stop()
	return stopGateway(m.ctx)
}

func stopGateway(ctx log.Interface) error {
	err := wrapper.StopLoRaGateway()
	if err != nil {
		return err
	}

	ctx.Info("Concentrator stopped gracefully")
	return nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"regexp"
	"strconv"
	"testing"

	"github.com/aws/aws-sdk-go/service/organizations"
	"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func testAccAwsOrganizationsPolicy_basic(t *testing.T) {
	var policy organizations.Policy
	content1 := `{"Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "*", "Resource": "*"}}`
	content2 := `{"Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "s3:*", "Resource": "*"}}`
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName := "aws_organizations_policy.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfig_Required(rName, content1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(`^arn:[^:]+:organizations::[^:]+:policy/o-.+/service_control_policy/p-.+$`)),
					resource.TestCheckResourceAttr(resourceName, "content", content1),
					resource.TestCheckResourceAttr(resourceName, "description", ""),
					resource.TestCheckResourceAttr(resourceName, "name", rName),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeServiceControlPolicy),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Required(rName, content2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "content", content2),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/5073
func testAccAwsOrganizationsPolicy_concurrent(t *testing.T) {
	var policy1, policy2, policy3, policy4, policy5 organizations.Policy
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName1 := "aws_organizations_policy.test1"
	resourceName2 := "aws_organizations_policy.test2"
	resourceName3 := "aws_organizations_policy.test3"
	resourceName4 := "aws_organizations_policy.test4"
	resourceName5 := "aws_organizations_policy.test5"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfigConcurrent(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName1, &policy1),
					testAccCheckAwsOrganizationsPolicyExists(resourceName2, &policy2),
					testAccCheckAwsOrganizationsPolicyExists(resourceName3, &policy3),
					testAccCheckAwsOrganizationsPolicyExists(resourceName4, &policy4),
					testAccCheckAwsOrganizationsPolicyExists(resourceName5, &policy5),
				),
			},
		},
	})
}

func testAccAwsOrganizationsPolicy_description(t *testing.T) {
	var policy organizations.Policy
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName := "aws_organizations_policy.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfig_Description(rName, "description1"),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "description", "description1"),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Description(rName, "description2"),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "description", "description2"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccAwsOrganizationsPolicy_type(t *testing.T) {
	var policy organizations.Policy
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName := "aws_organizations_policy.test"

	serviceControlPolicyContent := `{"Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "*", "Resource": "*"}}`
	tagPolicyContent := `{ "tags": { "Product": { "tag_key": { "@@assign": "Product" }, "enforced_for": { "@@assign": [ "ec2:instance" ] } } } }`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfig_Type(rName, serviceControlPolicyContent, organizations.PolicyTypeServiceControlPolicy),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeServiceControlPolicy),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Type(rName, tagPolicyContent, organizations.PolicyTypeTagPolicy),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeTagPolicy),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Required(rName, serviceControlPolicyContent),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeServiceControlPolicy),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAwsOrganizationsPolicyDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).organizationsconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_organizations_policy" {
			continue
		}

		input := &organizations.DescribePolicyInput{
			PolicyId: &rs.Primary.ID,
		}

		resp, err := conn.DescribePolicy(input)

		if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") {
			continue
		}

		if isAWSErr(err, organizations.ErrCodePolicyNotFoundException, "") {
			continue
		}

		if err != nil {
			return err
		}

		if resp != nil && resp.Policy != nil {
			return fmt.Errorf("Policy %q still exists", rs.Primary.ID)
		}
	}

	return nil

}

func testAccCheckAwsOrganizationsPolicyExists(resourceName string, policy *organizations.Policy) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[resourceName]
		if !ok {
			return fmt.Errorf("Not found: %s", resourceName)
		}

		conn := testAccProvider.Meta().(*AWSClient).organizationsconn
		input := &organizations.DescribePolicyInput{
			PolicyId: &rs.Primary.ID,
		}

		resp, err := conn.DescribePolicy(input)

		if err != nil {
			return err
		}

		if resp == nil || resp.Policy == nil {
			return fmt.Errorf("Policy %q does not exist", rs.Primary.ID)
		}

		*policy = *resp.Policy

		return nil
	}
}

func testAccAwsOrganizationsPolicyConfig_Description(rName, description string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test" {
  content     = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Allow\", \"Action\": \"*\", \"Resource\": \"*\"}}"
  description = "%s"
  name        = "%s"

  depends_on = ["aws_organizations_organization.test"]
}
`, description, rName)
}

func testAccAwsOrganizationsPolicyConfig_Required(rName, content string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test" {
  content = %s
  name    = "%s"

  depends_on = ["aws_organizations_organization.test"]
}
`, strconv.Quote(content), rName)
}

func testAccAwsOrganizationsPolicyConfigConcurrent(rName string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test1" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"cloudtrail:StopLogging\", \"Resource\": \"*\"}}"
  name    = "%[1]s1"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test2" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"ec2:DeleteFlowLogs\", \"Resource\": \"*\"}}"
  name    = "%[1]s2"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test3" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"logs:DeleteLogGroup\", \"Resource\": \"*\"}}"
  name    = "%[1]s3"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test4" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"config:DeleteConfigRule\", \"Resource\": \"*\"}}"
  name    = "%[1]s4"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test5" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"iam:DeleteRolePermissionsBoundary\", \"Resource\": \"*\"}}"
  name    = "%[1]s5"

  depends_on = ["aws_organizations_organization.test"]
}
`, rName)
}

func testAccAwsOrganizationsPolicyConfig_Type(rName, content, policyType string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test" {
  content     = %s
  name        = "%s"
  type        = "%s"

  depends_on = ["aws_organizations_organization.test"]
}
`, strconv.Quote(content), rName, policyType)
}
<commit_msg>Updates Organizations acceptance tests to use ARN testing check functions<commit_after>package aws

import (
	"fmt"
	"regexp"
	"strconv"
	"testing"

	"github.com/aws/aws-sdk-go/service/organizations"
	"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func testAccAwsOrganizationsPolicy_basic(t *testing.T) {
	var policy organizations.Policy
	content1 := `{"Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "*", "Resource": "*"}}`
	content2 := `{"Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "s3:*", "Resource": "*"}}`
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName := "aws_organizations_policy.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfig_Required(rName, content1),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(`^arn:[^:]+:organizations::[^:]+:policy/o-.+/service_control_policy/p-.+$`)),
					testAccMatchResourceAttrGlobalARN(resourceName, "arn", "organizations", regexp.MustCompile("policy/o-.+/service_control_policy/p-.+$")),
					resource.TestCheckResourceAttr(resourceName, "content", content1),
					resource.TestCheckResourceAttr(resourceName, "description", ""),
					resource.TestCheckResourceAttr(resourceName, "name", rName),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeServiceControlPolicy),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Required(rName, content2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "content", content2),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/5073
func testAccAwsOrganizationsPolicy_concurrent(t *testing.T) {
	var policy1, policy2, policy3, policy4, policy5 organizations.Policy
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName1 := "aws_organizations_policy.test1"
	resourceName2 := "aws_organizations_policy.test2"
	resourceName3 := "aws_organizations_policy.test3"
	resourceName4 := "aws_organizations_policy.test4"
	resourceName5 := "aws_organizations_policy.test5"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfigConcurrent(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName1, &policy1),
					testAccCheckAwsOrganizationsPolicyExists(resourceName2, &policy2),
					testAccCheckAwsOrganizationsPolicyExists(resourceName3, &policy3),
					testAccCheckAwsOrganizationsPolicyExists(resourceName4, &policy4),
					testAccCheckAwsOrganizationsPolicyExists(resourceName5, &policy5),
				),
			},
		},
	})
}

func testAccAwsOrganizationsPolicy_description(t *testing.T) {
	var policy organizations.Policy
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName := "aws_organizations_policy.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfig_Description(rName, "description1"),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "description", "description1"),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Description(rName, "description2"),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "description", "description2"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccAwsOrganizationsPolicy_type(t *testing.T) {
	var policy organizations.Policy
	rName := acctest.RandomWithPrefix("tf-acc-test")
	resourceName := "aws_organizations_policy.test"

	serviceControlPolicyContent := `{"Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "*", "Resource": "*"}}`
	tagPolicyContent := `{ "tags": { "Product": { "tag_key": { "@@assign": "Product" }, "enforced_for": { "@@assign": [ "ec2:instance" ] } } } }`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsOrganizationsPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsOrganizationsPolicyConfig_Type(rName, serviceControlPolicyContent, organizations.PolicyTypeServiceControlPolicy),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeServiceControlPolicy),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Type(rName, tagPolicyContent, organizations.PolicyTypeTagPolicy),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeTagPolicy),
				),
			},
			{
				Config: testAccAwsOrganizationsPolicyConfig_Required(rName, serviceControlPolicyContent),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsOrganizationsPolicyExists(resourceName, &policy),
					resource.TestCheckResourceAttr(resourceName, "type", organizations.PolicyTypeServiceControlPolicy),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAwsOrganizationsPolicyDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).organizationsconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_organizations_policy" {
			continue
		}

		input := &organizations.DescribePolicyInput{
			PolicyId: &rs.Primary.ID,
		}

		resp, err := conn.DescribePolicy(input)

		if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") {
			continue
		}

		if isAWSErr(err, organizations.ErrCodePolicyNotFoundException, "") {
			continue
		}

		if err != nil {
			return err
		}

		if resp != nil && resp.Policy != nil {
			return fmt.Errorf("Policy %q still exists", rs.Primary.ID)
		}
	}

	return nil

}

func testAccCheckAwsOrganizationsPolicyExists(resourceName string, policy *organizations.Policy) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[resourceName]
		if !ok {
			return fmt.Errorf("Not found: %s", resourceName)
		}

		conn := testAccProvider.Meta().(*AWSClient).organizationsconn
		input := &organizations.DescribePolicyInput{
			PolicyId: &rs.Primary.ID,
		}

		resp, err := conn.DescribePolicy(input)

		if err != nil {
			return err
		}

		if resp == nil || resp.Policy == nil {
			return fmt.Errorf("Policy %q does not exist", rs.Primary.ID)
		}

		*policy = *resp.Policy

		return nil
	}
}

func testAccAwsOrganizationsPolicyConfig_Description(rName, description string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test" {
  content     = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Allow\", \"Action\": \"*\", \"Resource\": \"*\"}}"
  description = "%s"
  name        = "%s"

  depends_on = ["aws_organizations_organization.test"]
}
`, description, rName)
}

func testAccAwsOrganizationsPolicyConfig_Required(rName, content string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test" {
  content = %s
  name    = "%s"

  depends_on = ["aws_organizations_organization.test"]
}
`, strconv.Quote(content), rName)
}

func testAccAwsOrganizationsPolicyConfigConcurrent(rName string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test1" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"cloudtrail:StopLogging\", \"Resource\": \"*\"}}"
  name    = "%[1]s1"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test2" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"ec2:DeleteFlowLogs\", \"Resource\": \"*\"}}"
  name    = "%[1]s2"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test3" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"logs:DeleteLogGroup\", \"Resource\": \"*\"}}"
  name    = "%[1]s3"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test4" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"config:DeleteConfigRule\", \"Resource\": \"*\"}}"
  name    = "%[1]s4"

  depends_on = ["aws_organizations_organization.test"]
}

resource "aws_organizations_policy" "test5" {
  content = "{\"Version\": \"2012-10-17\", \"Statement\": { \"Effect\": \"Deny\", \"Action\": \"iam:DeleteRolePermissionsBoundary\", \"Resource\": \"*\"}}"
  name    = "%[1]s5"

  depends_on = ["aws_organizations_organization.test"]
}
`, rName)
}

func testAccAwsOrganizationsPolicyConfig_Type(rName, content, policyType string) string {
	return fmt.Sprintf(`
resource "aws_organizations_organization" "test" {}

resource "aws_organizations_policy" "test" {
  content     = %s
  name        = "%s"
  type        = "%s"

  depends_on = ["aws_organizations_organization.test"]
}
`, strconv.Quote(content), rName, policyType)
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package netlog

import (
	"sync"
	"time"
)

type nWriter interface {
	WriteN(p []byte, n int) (written int, err error)
}

type messageBuffer struct {
	writer nWriter
	comp   CompressionType

	mu       sync.Mutex
	buff     []Message
	buffered int
	messages int
	stopChan chan struct{}
}

func newMessageBuffer(w nWriter, settings TopicSettings) *messageBuffer {

	m := &messageBuffer{
		writer:   w,
		buff:     make([]Message, settings.BatchNumMessages),
		comp:     settings.CompressionType,
		messages: settings.BatchNumMessages,
		stopChan: make(chan struct{}),
	}

	go m.launchFlusher(settings.BatchInterval.Duration())

	return m
}

// Write implements the io.Writer interface for the messageBuffer
func (m *messageBuffer) Write(p []byte) (n int, err error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	m.buff[m.buffered] = Message(p)
	m.buffered++
	if m.buffered == m.messages {
		err = m.flush()
	}

	return len(p), err
}

// Flush flushes the data from the buffer into the underlying writer
func (m *messageBuffer) Flush() (err error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.flush()
}

func (m *messageBuffer) flush() (err error) {
	if m.buffered == 0 {
		return nil
	}

	defer func() {
		m.buffered = 0
	}()

	data := MessageSet(m.buff[:m.buffered], m.comp)
	_, err = m.writer.WriteN(data.Bytes(), m.buffered)
	return err
}

// Close releases all resources
func (m *messageBuffer) Close() (err error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.stopChan <- struct{}{}
	m.writer = nil
	return nil
}

func (m *messageBuffer) launchFlusher(d time.Duration) {
	if d == 0 {
		return
	}

	ticker := time.NewTicker(d)
	for {
		select {
		case <-ticker.C:
			m.Flush()
			continue
		case <-m.stopChan:
			close(m.stopChan)
			return
		}
	}
}
<commit_msg>netlog: fix single message batch<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package netlog

import (
	"sync"
	"time"
)

type nWriter interface {
	WriteN(p []byte, n int) (written int, err error)
}

type messageBuffer struct {
	writer nWriter
	comp   CompressionType

	mu       sync.Mutex
	buff     []Message
	buffered int
	messages int
	stopChan chan struct{}
}

func newMessageBuffer(w nWriter, settings TopicSettings) *messageBuffer {

	m := &messageBuffer{
		writer:   w,
		buff:     make([]Message, settings.BatchNumMessages),
		comp:     settings.CompressionType,
		messages: settings.BatchNumMessages,
		stopChan: make(chan struct{}),
	}

	go m.launchFlusher(settings.BatchInterval.Duration())

	return m
}

// Write implements the io.Writer interface for the messageBuffer
func (m *messageBuffer) Write(p []byte) (n int, err error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	m.buff[m.buffered] = Message(p)
	m.buffered++
	if m.buffered == m.messages {
		err = m.flush()
	}

	return len(p), err
}

// Flush flushes the data from the buffer into the underlying writer
func (m *messageBuffer) Flush() (err error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.flush()
}

func (m *messageBuffer) flush() (err error) {
	if m.buffered == 0 {
		return nil
	}

	defer func() {
		m.buffered = 0
	}()

	var data Message
	if m.buffered == 1 {
		data = m.buff[0]
	} else {
		data = MessageSet(m.buff[:m.buffered], m.comp)
	}

	_, err = m.writer.WriteN(data.Bytes(), m.buffered)
	return err
}

// Close releases all resources
func (m *messageBuffer) Close() (err error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.stopChan <- struct{}{}
	m.writer = nil
	return nil
}

func (m *messageBuffer) launchFlusher(d time.Duration) {
	if d == 0 {
		return
	}

	ticker := time.NewTicker(d)
	for {
		select {
		case <-ticker.C:
			m.Flush()
			continue
		case <-m.stopChan:
			close(m.stopChan)
			return
		}
	}
}
<|endoftext|>