<commit_before>package tail

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"
)

type Tail struct {
	Filename   string
	BufferSize int64
	Lines      chan string
	cmd        *exec.Cmd
	wait       chan bool
}

func (t *Tail) String() string {
	return fmt.Sprintf("&Tail{Filename:%s, BufferSize:%d}", t.Filename, t.BufferSize)
}

func TailFile(filepath string, buffersize int64) (*Tail, error) {
	// check whether the file exists
	_, err := os.Stat(filepath)
	if err != nil {
		return nil, err
	}

	cmd := exec.Command("tail", "-c", "+1", "-f", filepath)
	reader, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	t := &Tail{
		Filename:   filepath,
		BufferSize: buffersize,
		Lines:      make(chan string, buffersize),
		cmd:        cmd,
		wait:       make(chan bool, 1),
	}

	go func() {
		scanner := bufio.NewScanner(reader)
		for scanner.Scan() {
			t.Lines <- scanner.Text()
		}

		t.wait <- true
	}()

	return t, nil
}

func (t *Tail) Stop() {
	t.cmd.Process.Signal(syscall.SIGINT)
	timeout := time.After(time.Second)
	select {
	case <-t.wait:
	case <-timeout:
		t.cmd.Process.Kill()
	}

	close(t.wait)
}
<commit_msg>close the channel when done tailing<commit_after>package tail

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"
)

type Tail struct {
	Filename   string
	BufferSize int64
	Lines      chan string
	cmd        *exec.Cmd
	wait       chan bool
}

func (t *Tail) String() string {
	return fmt.Sprintf("&Tail{Filename:%s, BufferSize:%d}", t.Filename, t.BufferSize)
}

func TailFile(filepath string, buffersize int64) (*Tail, error) {
	// check whether the file exists
	_, err := os.Stat(filepath)
	if err != nil {
		return nil, err
	}

	cmd := exec.Command("tail", "-c", "+1", "-f", filepath)
	reader, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	t := &Tail{
		Filename:   filepath,
		BufferSize: buffersize,
		Lines:      make(chan string, buffersize),
		cmd:        cmd,
		wait:       make(chan bool, 1),
	}

	go func() {
		scanner := bufio.NewScanner(reader)
		for scanner.Scan() {
			t.Lines <- scanner.Text()
		}

		close(t.Lines)
		t.wait <- true
	}()

	return t, nil
}

func (t *Tail) Stop() {
	t.cmd.Process.Signal(syscall.SIGINT)
	timeout := time.After(2 * time.Second)
	select {
	case <-t.wait:
	case <-timeout:
		t.cmd.Process.Kill()
		<-t.wait
	}

	close(t.wait)
}
<|endoftext|>


<commit_before><commit_msg>tail: fix tid<commit_after><|endoftext|>


<commit_before>package containerd

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"runtime"
	"strings"
	"syscall"

	"github.com/containerd/containerd/api/services/containers/v1"
	eventsapi "github.com/containerd/containerd/api/services/events/v1"
	"github.com/containerd/containerd/api/services/tasks/v1"
	tasktypes "github.com/containerd/containerd/api/types/task"
	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/events"
	"github.com/containerd/containerd/rootfs"
	"github.com/opencontainers/image-spec/specs-go/v1"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

const UnknownExitStatus = 255

type TaskStatus string

const (
	Running TaskStatus = "running"
	Created TaskStatus = "created"
	Stopped TaskStatus = "stopped"
	Paused  TaskStatus = "paused"
	Pausing TaskStatus = "pausing"
)

type IOCloserOpts func(*tasks.CloseIORequest)

func WithStdinCloser(r *tasks.CloseIORequest) {
	r.Stdin = true
}

type CheckpointOpts func(*tasks.CheckpointTaskRequest) error

type Task interface {
	Pid() uint32
	Delete(context.Context) (uint32, error)
	Kill(context.Context, syscall.Signal) error
	Pause(context.Context) error
	Resume(context.Context) error
	Start(context.Context) error
	Status(context.Context) (TaskStatus, error)
	Wait(context.Context) (uint32, error)
	Exec(context.Context, *specs.Process, IOCreation) (Process, error)
	Processes(context.Context) ([]uint32, error)
	CloseIO(context.Context, ...IOCloserOpts) error
	Resize(ctx context.Context, w, h uint32) error
	IO() *IO
	Checkpoint(context.Context, ...CheckpointOpts) (v1.Descriptor, error)
}

type Process interface {
	Pid() uint32
	Start(context.Context) error
	Delete(context.Context) (uint32, error)
	Kill(context.Context, syscall.Signal) error
	Wait(context.Context) (uint32, error)
	CloseIO(context.Context, ...IOCloserOpts) error
	Resize(ctx context.Context, w, h uint32) error
	IO() *IO
}

var _ = (Task)(&task{})

type task struct {
	client *Client

	io          *IO
	containerID string
	pid         uint32

	deferred *tasks.CreateTaskRequest
	pidSync  chan struct{}
}

// Pid returns the pid or process id for the task
func (t *task) Pid() uint32 {
	return t.pid
}

func (t *task) Start(ctx context.Context) error {
	if t.deferred != nil {
		response, err := t.client.TaskService().Create(ctx, t.deferred)
		t.deferred = nil
		if err != nil {
			return err
		}
		t.pid = response.Pid
		close(t.pidSync)
		return nil
	}
	_, err := t.client.TaskService().Start(ctx, &tasks.StartTaskRequest{
		ContainerID: t.containerID,
	})
	return err
}

func (t *task) Kill(ctx context.Context, s syscall.Signal) error {
	_, err := t.client.TaskService().Kill(ctx, &tasks.KillRequest{
		Signal:      uint32(s),
		ContainerID: t.containerID,
		PidOrAll: &tasks.KillRequest_All{
			All: true,
		},
	})
	return err
}

func (t *task) Pause(ctx context.Context) error {
	_, err := t.client.TaskService().Pause(ctx, &tasks.PauseTaskRequest{
		ContainerID: t.containerID,
	})
	return err
}

func (t *task) Resume(ctx context.Context) error {
	_, err := t.client.TaskService().Resume(ctx, &tasks.ResumeTaskRequest{
		ContainerID: t.containerID,
	})
	return err
}

func (t *task) Status(ctx context.Context) (TaskStatus, error) {
	r, err := t.client.TaskService().Get(ctx, &tasks.GetTaskRequest{
		ContainerID: t.containerID,
	})
	if err != nil {
		return "", err
	}
	return TaskStatus(strings.ToLower(r.Task.Status.String())), nil
}

// Wait is a blocking call that will wait for the task to exit and return the exit status
func (t *task) Wait(ctx context.Context) (uint32, error) {
	// TODO (ehazlett): add filtering for specific event
	eventstream, err := t.client.EventService().Stream(ctx, &eventsapi.StreamEventsRequest{})
	if err != nil {
		return UnknownExitStatus, err
	}
	<-t.pidSync
evloop:
	for {
		evt, err := eventstream.Recv()
		if err != nil {
			return UnknownExitStatus, err
		}

		switch {
		case events.Is(evt.Event, &eventsapi.RuntimeEvent{}):
			var e eventsapi.RuntimeEvent
			if err := events.UnmarshalEvent(evt.Event, &e); err != nil {
				return UnknownExitStatus, err
			}

			if e.Type != tasktypes.Event_EXIT {
				continue evloop
			}

			if e.ID == t.containerID && e.Pid == t.pid {
				return e.ExitStatus, nil
			}
		}
	}
}

// Delete deletes the task and its runtime state
// it returns the exit status of the task and any errors that were encountered
// during cleanup
func (t *task) Delete(ctx context.Context) (uint32, error) {
	var cerr error
	if t.io != nil {
		cerr = t.io.Close()
	}
	r, err := t.client.TaskService().Delete(ctx, &tasks.DeleteTaskRequest{
		ContainerID: t.containerID,
	})
	if err != nil {
		return UnknownExitStatus, err
	}
	return r.ExitStatus, cerr
}

func (t *task) Exec(ctx context.Context, spec *specs.Process, ioCreate IOCreation) (Process, error) {
	i, err := ioCreate()
	if err != nil {
		return nil, err
	}
	return &process{
		task:    t,
		io:      i,
		spec:    spec,
		pidSync: make(chan struct{}),
	}, nil
}

func (t *task) Processes(ctx context.Context) ([]uint32, error) {
	response, err := t.client.TaskService().ListProcesses(ctx, &tasks.ListProcessesRequest{
		ContainerID: t.containerID,
	})
	if err != nil {
		return nil, err
	}
	var out []uint32
	for _, p := range response.Processes {
		out = append(out, p.Pid)
	}
	return out, nil
}

func (t *task) CloseIO(ctx context.Context, opts ...IOCloserOpts) error {
	r := &tasks.CloseIORequest{
		ContainerID: t.containerID,
		Pid:         t.pid,
	}
	for _, o := range opts {
		o(r)
	}
	_, err := t.client.TaskService().CloseIO(ctx, r)
	return err
}

func (t *task) IO() *IO {
	return t.io
}

func (t *task) Resize(ctx context.Context, w, h uint32) error {
	_, err := t.client.TaskService().ResizePty(ctx, &tasks.ResizePtyRequest{
		ContainerID: t.containerID,
		Width:       w,
		Height:      h,
		Pid:         t.pid,
	})
	return err
}

func WithExit(r *tasks.CheckpointTaskRequest) error {
	r.Options["exit"] = "true"
	return nil
}

func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointOpts) (d v1.Descriptor, err error) {
	request := &tasks.CheckpointTaskRequest{
		ContainerID: t.containerID,
		Options:     make(map[string]string),
	}
	for _, o := range opts {
		if err := o(request); err != nil {
			return d, err
		}
	}
	// make sure we pause it and resume after all other filesystem operations are completed
	if err := t.Pause(ctx); err != nil {
		return d, err
	}
	defer t.Resume(ctx)
	cr, err := t.client.ContainerService().Get(ctx, &containers.GetContainerRequest{
		ID: t.containerID,
	})
	if err != nil {
		return d, err
	}
	var index v1.Index
	if err := t.checkpointTask(ctx, &index, request); err != nil {
		return d, err
	}
	if err := t.checkpointImage(ctx, &index, cr.Container.Image); err != nil {
		return d, err
	}
	if err := t.checkpointRWSnapshot(ctx, &index, cr.Container.RootFS); err != nil {
		return d, err
	}
	index.Annotations = make(map[string]string)
	index.Annotations["image.name"] = cr.Container.Image
	return t.writeIndex(ctx, &index)
}

func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tasks.CheckpointTaskRequest) error {
	response, err := t.client.TaskService().Checkpoint(ctx, request)
	if err != nil {
		return err
	}
	// add the checkpoint descriptors to the index
	for _, d := range response.Descriptors {
		index.Manifests = append(index.Manifests, v1.Descriptor{
			MediaType: d.MediaType,
			Size:      d.Size_,
			Digest:    d.Digest,
			Platform: &v1.Platform{
				OS:           runtime.GOOS,
				Architecture: runtime.GOARCH,
			},
		})
	}
	return nil
}

func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, id string) error {
	rw, err := rootfs.Diff(ctx, id, fmt.Sprintf("checkpoint-rw-%s", id), t.client.SnapshotService(), t.client.DiffService())
	if err != nil {
		return err
	}
	rw.Platform = &v1.Platform{
		OS:           runtime.GOOS,
		Architecture: runtime.GOARCH,
	}
	index.Manifests = append(index.Manifests, rw)
	return nil
}

func (t *task) checkpointImage(ctx context.Context, index *v1.Index, image string) error {
	if image == "" {
		return fmt.Errorf("cannot checkpoint image with empty name")
	}
	ir, err := t.client.ImageService().Get(ctx, image)
	if err != nil {
		return err
	}
	index.Manifests = append(index.Manifests, ir.Target)
	return nil
}

func (t *task) writeIndex(ctx context.Context, index *v1.Index) (v1.Descriptor, error) {
	buf := bytes.NewBuffer(nil)
	if err := json.NewEncoder(buf).Encode(index); err != nil {
		return v1.Descriptor{}, err
	}
	return writeContent(ctx, t.client.ContentStore(), v1.MediaTypeImageIndex, t.containerID, buf)
}

func writeContent(ctx context.Context, store content.Store, mediaType, ref string, r io.Reader) (d v1.Descriptor, err error) {
	writer, err := store.Writer(ctx, ref, 0, "")
	if err != nil {
		return d, err
	}
	defer writer.Close()
	size, err := io.Copy(writer, r)
	if err != nil {
		return d, err
	}
	if err := writer.Commit(0, ""); err != nil {
		return d, err
	}
	return v1.Descriptor{
		MediaType: mediaType,
		Digest:    writer.Digest(),
		Size:      size,
	}, nil
}
<commit_msg>Simplify task.Wait() a bit<commit_after>package containerd

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"runtime"
	"strings"
	"syscall"

	"github.com/containerd/containerd/api/services/containers/v1"
	eventsapi "github.com/containerd/containerd/api/services/events/v1"
	"github.com/containerd/containerd/api/services/tasks/v1"
	tasktypes "github.com/containerd/containerd/api/types/task"
	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/events"
	"github.com/containerd/containerd/rootfs"
	"github.com/opencontainers/image-spec/specs-go/v1"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

const UnknownExitStatus = 255

type TaskStatus string

const (
	Running TaskStatus = "running"
	Created TaskStatus = "created"
	Stopped TaskStatus = "stopped"
	Paused  TaskStatus = "paused"
	Pausing TaskStatus = "pausing"
)

type IOCloserOpts func(*tasks.CloseIORequest)

func WithStdinCloser(r *tasks.CloseIORequest) {
	r.Stdin = true
}

type CheckpointOpts func(*tasks.CheckpointTaskRequest) error

type Task interface {
	Pid() uint32
	Delete(context.Context) (uint32, error)
	Kill(context.Context, syscall.Signal) error
	Pause(context.Context) error
	Resume(context.Context) error
	Start(context.Context) error
	Status(context.Context) (TaskStatus, error)
	Wait(context.Context) (uint32, error)
	Exec(context.Context, *specs.Process, IOCreation) (Process, error)
	Processes(context.Context) ([]uint32, error)
	CloseIO(context.Context, ...IOCloserOpts) error
	Resize(ctx context.Context, w, h uint32) error
	IO() *IO
	Checkpoint(context.Context, ...CheckpointOpts) (v1.Descriptor, error)
}

type Process interface {
	Pid() uint32
	Start(context.Context) error
	Delete(context.Context) (uint32, error)
	Kill(context.Context, syscall.Signal) error
	Wait(context.Context) (uint32, error)
	CloseIO(context.Context, ...IOCloserOpts) error
	Resize(ctx context.Context, w, h uint32) error
	IO() *IO
}

var _ = (Task)(&task{})

type task struct {
	client *Client

	io          *IO
	containerID string
	pid         uint32

	deferred *tasks.CreateTaskRequest
	pidSync  chan struct{}
}

// Pid returns the pid or process id for the task
func (t *task) Pid() uint32 {
	return t.pid
}

func (t *task) Start(ctx context.Context) error {
	if t.deferred != nil {
		response, err := t.client.TaskService().Create(ctx, t.deferred)
		t.deferred = nil
		if err != nil {
			return err
		}
		t.pid = response.Pid
		close(t.pidSync)
		return nil
	}
	_, err := t.client.TaskService().Start(ctx, &tasks.StartTaskRequest{
		ContainerID: t.containerID,
	})
	return err
}

func (t *task) Kill(ctx context.Context, s syscall.Signal) error {
	_, err := t.client.TaskService().Kill(ctx, &tasks.KillRequest{
		Signal:      uint32(s),
		ContainerID: t.containerID,
		PidOrAll: &tasks.KillRequest_All{
			All: true,
		},
	})
	return err
}

func (t *task) Pause(ctx context.Context) error {
	_, err := t.client.TaskService().Pause(ctx, &tasks.PauseTaskRequest{
		ContainerID: t.containerID,
	})
	return err
}

func (t *task) Resume(ctx context.Context) error {
	_, err := t.client.TaskService().Resume(ctx, &tasks.ResumeTaskRequest{
		ContainerID: t.containerID,
	})
	return err
}

func (t *task) Status(ctx context.Context) (TaskStatus, error) {
	r, err := t.client.TaskService().Get(ctx, &tasks.GetTaskRequest{
		ContainerID: t.containerID,
	})
	if err != nil {
		return "", err
	}
	return TaskStatus(strings.ToLower(r.Task.Status.String())), nil
}

// Wait is a blocking call that will wait for the task to exit and return the exit status
func (t *task) Wait(ctx context.Context) (uint32, error) {
	// TODO (ehazlett): add filtering for specific event
	eventstream, err := t.client.EventService().Stream(ctx, &eventsapi.StreamEventsRequest{})
	if err != nil {
		return UnknownExitStatus, err
	}
	<-t.pidSync

	var e eventsapi.RuntimeEvent

	for {
		evt, err := eventstream.Recv()
		if err != nil {
			return UnknownExitStatus, err
		}

		if !events.Is(evt.Event, &eventsapi.RuntimeEvent{}) {
			continue
		}

		if err := events.UnmarshalEvent(evt.Event, &e); err != nil {
			return UnknownExitStatus, err
		}

		if e.Type != tasktypes.Event_EXIT {
			continue
		}

		if e.ID == t.containerID && e.Pid == t.pid {
			return e.ExitStatus, nil
		}
	}
}

// Delete deletes the task and its runtime state
// it returns the exit status of the task and any errors that were encountered
// during cleanup
func (t *task) Delete(ctx context.Context) (uint32, error) {
	var cerr error
	if t.io != nil {
		cerr = t.io.Close()
	}
	r, err := t.client.TaskService().Delete(ctx, &tasks.DeleteTaskRequest{
		ContainerID: t.containerID,
	})
	if err != nil {
		return UnknownExitStatus, err
	}
	return r.ExitStatus, cerr
}

func (t *task) Exec(ctx context.Context, spec *specs.Process, ioCreate IOCreation) (Process, error) {
	i, err := ioCreate()
	if err != nil {
		return nil, err
	}
	return &process{
		task:    t,
		io:      i,
		spec:    spec,
		pidSync: make(chan struct{}),
	}, nil
}

func (t *task) Processes(ctx context.Context) ([]uint32, error) {
	response, err := t.client.TaskService().ListProcesses(ctx, &tasks.ListProcessesRequest{
		ContainerID: t.containerID,
	})
	if err != nil {
		return nil, err
	}
	var out []uint32
	for _, p := range response.Processes {
		out = append(out, p.Pid)
	}
	return out, nil
}

func (t *task) CloseIO(ctx context.Context, opts ...IOCloserOpts) error {
	r := &tasks.CloseIORequest{
		ContainerID: t.containerID,
		Pid:         t.pid,
	}
	for _, o := range opts {
		o(r)
	}
	_, err := t.client.TaskService().CloseIO(ctx, r)
	return err
}

func (t *task) IO() *IO {
	return t.io
}

func (t *task) Resize(ctx context.Context, w, h uint32) error {
	_, err := t.client.TaskService().ResizePty(ctx, &tasks.ResizePtyRequest{
		ContainerID: t.containerID,
		Width:       w,
		Height:      h,
		Pid:         t.pid,
	})
	return err
}

func WithExit(r *tasks.CheckpointTaskRequest) error {
	r.Options["exit"] = "true"
	return nil
}

func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointOpts) (d v1.Descriptor, err error) {
	request := &tasks.CheckpointTaskRequest{
		ContainerID: t.containerID,
		Options:     make(map[string]string),
	}
	for _, o := range opts {
		if err := o(request); err != nil {
			return d, err
		}
	}
	// make sure we pause it and resume after all other filesystem operations are completed
	if err := t.Pause(ctx); err != nil {
		return d, err
	}
	defer t.Resume(ctx)
	cr, err := t.client.ContainerService().Get(ctx, &containers.GetContainerRequest{
		ID: t.containerID,
	})
	if err != nil {
		return d, err
	}
	var index v1.Index
	if err := t.checkpointTask(ctx, &index, request); err != nil {
		return d, err
	}
	if err := t.checkpointImage(ctx, &index, cr.Container.Image); err != nil {
		return d, err
	}
	if err := t.checkpointRWSnapshot(ctx, &index, cr.Container.RootFS); err != nil {
		return d, err
	}
	index.Annotations = make(map[string]string)
	index.Annotations["image.name"] = cr.Container.Image
	return t.writeIndex(ctx, &index)
}

func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tasks.CheckpointTaskRequest) error {
	response, err := t.client.TaskService().Checkpoint(ctx, request)
	if err != nil {
		return err
	}
	// add the checkpoint descriptors to the index
	for _, d := range response.Descriptors {
		index.Manifests = append(index.Manifests, v1.Descriptor{
			MediaType: d.MediaType,
			Size:      d.Size_,
			Digest:    d.Digest,
			Platform: &v1.Platform{
				OS:           runtime.GOOS,
				Architecture: runtime.GOARCH,
			},
		})
	}
	return nil
}

func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, id string) error {
	rw, err := rootfs.Diff(ctx, id, fmt.Sprintf("checkpoint-rw-%s", id), t.client.SnapshotService(), t.client.DiffService())
	if err != nil {
		return err
	}
	rw.Platform = &v1.Platform{
		OS:           runtime.GOOS,
		Architecture: runtime.GOARCH,
	}
	index.Manifests = append(index.Manifests, rw)
	return nil
}

func (t *task) checkpointImage(ctx context.Context, index *v1.Index, image string) error {
	if image == "" {
		return fmt.Errorf("cannot checkpoint image with empty name")
	}
	ir, err := t.client.ImageService().Get(ctx, image)
	if err != nil {
		return err
	}
	index.Manifests = append(index.Manifests, ir.Target)
	return nil
}

func (t *task) writeIndex(ctx context.Context, index *v1.Index) (v1.Descriptor, error) {
	buf := bytes.NewBuffer(nil)
	if err := json.NewEncoder(buf).Encode(index); err != nil {
		return v1.Descriptor{}, err
	}
	return writeContent(ctx, t.client.ContentStore(), v1.MediaTypeImageIndex, t.containerID, buf)
}

func writeContent(ctx context.Context, store content.Store, mediaType, ref string, r io.Reader) (d v1.Descriptor, err error) {
	writer, err := store.Writer(ctx, ref, 0, "")
	if err != nil {
		return d, err
	}
	defer writer.Close()
	size, err := io.Copy(writer, r)
	if err != nil {
		return d, err
	}
	if err := writer.Commit(0, ""); err != nil {
		return d, err
	}
	return v1.Descriptor{
		MediaType: mediaType,
		Digest:    writer.Digest(),
		Size:      size,
	}, nil
}
<|endoftext|>


<commit_before>// Package ui provides a higher-level user-interface API using SDL2.
package ui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"runtime"
	"time"

	"github.com/eaburns/sdl2"
)

func init() {
	runtime.LockOSThread()
}

var (
	doChan  = make(chan func(), 1)
	windows = make(map[sdl2.WindowID]*Window, 1)
)

// Hijack must be called by the main go routine to hijack it for the user interface;
// it never returns. The function f is called in a new go routine as the new "main" function,
// and rate is the rate at which the user interface should poll for events.
func Hijack(f func(), rate time.Duration) {
	if err := sdl2.Init(sdl2.Everything); err != nil {
		panic(err)
	}

	go f()

	tick := time.NewTicker(rate)
	for {
		select {
		case f := <-doChan:
			f()
		case <-tick.C:
			pollEvents()
		}
	}
}

func do(f func()) {
	done := make(chan struct{})
	doChan <- func() {
		f()
		done <- struct{}{}
	}
	<-done
}

func pollEvents() {
	for {
		ev := sdl2.PollEvent()
		if ev == nil {
			break
		}
		if e, ok := ev.(interface {
			WindowID() sdl2.WindowID
		}); ok {
			win := windows[e.WindowID()]
			win.events <- ev
		}
	}
}

// A Window is a single window on the user's graphical interface.
type Window struct {
	win    *sdl2.Window
	rend   *sdl2.Renderer
	events chan interface{}
	imgs   map[string]img
}

type img struct {
	tex           *sdl2.Texture
	width, height int
}

// NewWindow returns a new window.
func NewWindow(title string, w, h int) *Window {
	win := &Window{
		events: make(chan interface{}, 1),
		imgs:   make(map[string]img),
	}
	do(func() {
		var err error
		x, y := sdl2.WindowPosUndefined, sdl2.WindowPosUndefined
		win.win, err = sdl2.CreateWindow(title, x, y, w, h, sdl2.Shown|sdl2.OpenGL)
		if err != nil {
			panic(err)
		}

		win.rend, err = sdl2.CreateRenderer(win.win, -1, sdl2.Accelerated)
		if err != nil {
			panic(err)
		}
		if err := win.rend.SetDrawBlendMode(sdl2.Blend); err != nil {
			panic(err)
		}

		windows[win.win.ID()] = win
	})
	return win
}

// Destroy destroys the window.
func (win *Window) Destroy() {
	do(func() {
		win.rend.Destroy()
		win.win.Destroy()
	})
}

// FlushCache flushes any cached textures on this window.
func (win *Window) FlushCache() {
	do(func() {
		for _, img := range win.imgs {
			img.tex.Destroy()
		}
		win.imgs = make(map[string]img)
	})
}

// Events returns the event channel for the window.
func (win *Window) Events() <-chan interface{} {
	return win.events
}

// Draw calls a function running on the main go routine, and passes it a canvas
// which can draw to the window. The function can use the Canvas's operations
// as long as  it does not use them in a different go routine than the one in which
// the function was called by Draw.
func (win *Window) Draw(f func(win Canvas)) {
	do(func() { f(Canvas{win}) })
}

// A Canvas can draw to a window.
// The drawing operations can only be safely used within the main go routine.
type Canvas struct {
	win *Window
}

// Clear clears the canvas with the drawing color.
func (canv Canvas) Clear() {
	must(canv.win.rend.Clear())
}

// DrawLine draws a line on the canvas.
func (canv Canvas) DrawLine(x1, y1, x2, y2 int) {
	must(canv.win.rend.DrawLine(x1, y1, x2, y2))
}

// DrawLines draws a series of connected lines on the canvas.
func (canv Canvas) DrawLines(points []image.Point) {
	must(canv.win.rend.DrawLines(points))
}

// DrawPoint draws a point on the canvas.
func (canv Canvas) DrawPoint(x, y int) {
	must(canv.win.rend.DrawPoint(x, y))
}

// DrawPoint draws multiple points on the canvas.
func (canv Canvas) DrawPoints(points []image.Point) {
	must(canv.win.rend.DrawPoints(points))
}

// DratRect draws a rectangle on the canvas.
func (canv Canvas) DrawRect(rect *image.Rectangle) {
	must(canv.win.rend.DrawRect(rect))
}

// DrawRects draws some number of rectangles on the canvas.
func (canv Canvas) DrawRects(rects []image.Rectangle) {
	must(canv.win.rend.DrawRects(rects))
}

// FillRect fills a rectangle on the canvas with the drawing color.
func (canv Canvas) FillRect(rect *image.Rectangle) {
	must(canv.win.rend.FillRect(rect))
}

// FillRects fills some number of rectangles on the canvas with the drawing color.
func (canv Canvas) FillRects(rects []image.Rectangle) {
	must(canv.win.rend.FillRects(rects))
}

// Present updates the canvas with drawing performed.
func (canv Canvas) Present() {
	canv.win.rend.Present()
}

// SetDrawColor sets the color used for drawing operations (Rect, Line and Clear).
func (canv Canvas) SetDrawColor(col color.Color) {
	must(canv.win.rend.SetDrawColor(col))
}

// DrawPng draws the image loaded from a PNG file to the canvas.
// The image is drawn with the upper-left corner located at x, y.
func (canv Canvas) DrawPng(path string, x, y int) {
	i, ok := canv.win.imgs[path]
	if !ok {
		png := loadPng(path)
		tex, err := sdl2.CreateTextureFromImage(canv.win.rend, png)
		if err != nil {
			panic(err)
		}
		if err := tex.SetBlendMode(sdl2.Blend); err != nil {
			panic(err)
		}
		i = img{
			tex:    tex,
			width:  png.Bounds().Dx(),
			height: png.Bounds().Dy(),
		}
		canv.win.imgs[path] = i
	}
	dst := image.Rect(x, y, x+i.width, y+i.height)
	must(canv.win.rend.Copy(i.tex, nil, &dst))
}

func loadPng(path string) *image.NRGBA {
	r, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	img, err := png.Decode(r)
	if err != nil {
		panic(err)
	}
	return img.(*image.NRGBA)
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Handle events coming in while a window is being created.<commit_after>// Package ui provides a higher-level user-interface API using SDL2.
package ui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"runtime"
	"time"

	"github.com/eaburns/sdl2"
)

func init() {
	runtime.LockOSThread()
}

var (
	doChan  = make(chan func(), 1)
	windows = make(map[sdl2.WindowID]*Window, 1)
	missedEvents []windowIDer
)

// Hijack must be called by the main go routine to hijack it for the user interface;
// it never returns. The function f is called in a new go routine as the new "main" function,
// and rate is the rate at which the user interface should poll for events.
func Hijack(f func(), rate time.Duration) {
	if err := sdl2.Init(sdl2.Everything); err != nil {
		panic(err)
	}

	go f()

	tick := time.NewTicker(rate)
	for {
		select {
		case f := <-doChan:
			f()
		case <-tick.C:
			pollEvents()
		}
	}
}

func do(f func()) {
	done := make(chan struct{})
	doChan <- func() {
		f()
		done <- struct{}{}
	}
	<-done
}

type windowIDer interface {
	WindowID() sdl2.WindowID
}

func pollEvents() {
	for {
		missed := missedEvents
		missedEvents = nil
		for _, m := range missed {
			sendEvent(m)
		}

		ev := sdl2.PollEvent()
		if ev == nil {
			break
		}
		if e, ok := ev.(windowIDer); ok {
			sendEvent(e)
		}
	}
}

func sendEvent(e windowIDer) {
	if win, ok := windows[e.WindowID()]; ok {
		win.events <- e
	} else {
		// Must be that the window is still being created.  Let's try again later.
		missedEvents = append(missedEvents, e)
	}
}

// A Window is a single window on the user's graphical interface.
type Window struct {
	win    *sdl2.Window
	rend   *sdl2.Renderer
	events chan interface{}
	imgs   map[string]img
}

type img struct {
	tex           *sdl2.Texture
	width, height int
}

// NewWindow returns a new window.
func NewWindow(title string, w, h int) *Window {
	win := &Window{
		events: make(chan interface{}, 1),
		imgs:   make(map[string]img),
	}
	do(func() {
		var err error
		x, y := sdl2.WindowPosUndefined, sdl2.WindowPosUndefined
		win.win, err = sdl2.CreateWindow(title, x, y, w, h, sdl2.Shown|sdl2.OpenGL)
		if err != nil {
			panic(err)
		}

		win.rend, err = sdl2.CreateRenderer(win.win, -1, sdl2.Accelerated)
		if err != nil {
			panic(err)
		}
		if err := win.rend.SetDrawBlendMode(sdl2.Blend); err != nil {
			panic(err)
		}

		windows[win.win.ID()] = win
	})
	return win
}

// Destroy destroys the window.
func (win *Window) Destroy() {
	do(func() {
		win.rend.Destroy()
		win.win.Destroy()
	})
}

// FlushCache flushes any cached textures on this window.
func (win *Window) FlushCache() {
	do(func() {
		for _, img := range win.imgs {
			img.tex.Destroy()
		}
		win.imgs = make(map[string]img)
	})
}

// Events returns the event channel for the window.
func (win *Window) Events() <-chan interface{} {
	return win.events
}

// Draw calls a function running on the main go routine, and passes it a canvas
// which can draw to the window. The function can use the Canvas's operations
// as long as  it does not use them in a different go routine than the one in which
// the function was called by Draw.
func (win *Window) Draw(f func(win Canvas)) {
	do(func() { f(Canvas{win}) })
}

// A Canvas can draw to a window.
// The drawing operations can only be safely used within the main go routine.
type Canvas struct {
	win *Window
}

// Clear clears the canvas with the drawing color.
func (canv Canvas) Clear() {
	must(canv.win.rend.Clear())
}

// DrawLine draws a line on the canvas.
func (canv Canvas) DrawLine(x1, y1, x2, y2 int) {
	must(canv.win.rend.DrawLine(x1, y1, x2, y2))
}

// DrawLines draws a series of connected lines on the canvas.
func (canv Canvas) DrawLines(points []image.Point) {
	must(canv.win.rend.DrawLines(points))
}

// DrawPoint draws a point on the canvas.
func (canv Canvas) DrawPoint(x, y int) {
	must(canv.win.rend.DrawPoint(x, y))
}

// DrawPoint draws multiple points on the canvas.
func (canv Canvas) DrawPoints(points []image.Point) {
	must(canv.win.rend.DrawPoints(points))
}

// DratRect draws a rectangle on the canvas.
func (canv Canvas) DrawRect(rect *image.Rectangle) {
	must(canv.win.rend.DrawRect(rect))
}

// DrawRects draws some number of rectangles on the canvas.
func (canv Canvas) DrawRects(rects []image.Rectangle) {
	must(canv.win.rend.DrawRects(rects))
}

// FillRect fills a rectangle on the canvas with the drawing color.
func (canv Canvas) FillRect(rect *image.Rectangle) {
	must(canv.win.rend.FillRect(rect))
}

// FillRects fills some number of rectangles on the canvas with the drawing color.
func (canv Canvas) FillRects(rects []image.Rectangle) {
	must(canv.win.rend.FillRects(rects))
}

// Present updates the canvas with drawing performed.
func (canv Canvas) Present() {
	canv.win.rend.Present()
}

// SetDrawColor sets the color used for drawing operations (Rect, Line and Clear).
func (canv Canvas) SetDrawColor(col color.Color) {
	must(canv.win.rend.SetDrawColor(col))
}

// DrawPng draws the image loaded from a PNG file to the canvas.
// The image is drawn with the upper-left corner located at x, y.
func (canv Canvas) DrawPng(path string, x, y int) {
	i, ok := canv.win.imgs[path]
	if !ok {
		png := loadPng(path)
		tex, err := sdl2.CreateTextureFromImage(canv.win.rend, png)
		if err != nil {
			panic(err)
		}
		if err := tex.SetBlendMode(sdl2.Blend); err != nil {
			panic(err)
		}
		i = img{
			tex:    tex,
			width:  png.Bounds().Dx(),
			height: png.Bounds().Dy(),
		}
		canv.win.imgs[path] = i
	}
	dst := image.Rect(x, y, x+i.width, y+i.height)
	must(canv.win.rend.Copy(i.tex, nil, &dst))
}

func loadPng(path string) *image.NRGBA {
	r, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	img, err := png.Decode(r)
	if err != nil {
		panic(err)
	}
	return img.(*image.NRGBA)
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package conf

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"sync"

	log "github.com/Sirupsen/logrus"

	"github.com/Cepave/open-falcon-backend/modules/query/g"
	"github.com/Cepave/open-falcon-backend/modules/query/utils"
)

type Gconfig struct {
	Funcations []FunConfig
}

type FunConfig struct {
	FuncationName string   `json:"funcation_name"`
	FilePath      string   `json:"file_path"`
	Params        []string `json:"params"`
	Description   string   `json:"description"`
	Codes         string   `json:"-"`
}

var (
	gconfig     []*FunConfig
	configLock  = new(sync.RWMutex)
	confpath    *string
	FunctionMap map[string]*FunConfig
)

func Config() map[string]*FunConfig {
	configLock.RLock()
	defer configLock.RUnlock()
	return FunctionMap
}

func functionMapGen() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"../config/js", "config/js", "conf/js", "js"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("load js files got error, currentPaht: %s , please check your code tree and make is correct!", currentPath)
	}

	FunctionMap = map[string]*FunConfig{}
	for _, v := range gconfig {
		contain := jsFileReader(fmt.Sprintf("%s/%s", f, v.FilePath))
		v.Codes = contain
		FunctionMap[v.FuncationName] = v
	}
}

func ReadConf() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"conf/lambdaSetup.json", "config/lambdaSetup.json", "../config/lambdaSetup.json"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("lambdaSetup.json not found, currentPaht: %s", currentPath)
	}

	confpath = &f
	dat, err := ioutil.ReadFile(f)
	if err != nil {
		log.Println(err)
	}
	var myconf []*FunConfig
	json.Unmarshal(dat, &myconf)
	if len(myconf) == 0 {
		log.Println("conf file is empty or format is wrong, please check it!")
	}
	gconfig = myconf
	functionMapGen()
}

func Reload() {
	configLock.RLock()
	ReadConf()
	defer configLock.RUnlock()
}

func GetFunc(key string) *FunConfig {
	return FunctionMap[key]
}

func GetAvaibleFun() []string {
	return utils.GetMapKeys(reflect.ValueOf(FunctionMap).MapKeys())
}
<commit_msg>add logging information of read conf successed for query module<commit_after>package conf

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"sync"

	log "github.com/Sirupsen/logrus"

	"github.com/Cepave/open-falcon-backend/modules/query/g"
	"github.com/Cepave/open-falcon-backend/modules/query/utils"
)

type Gconfig struct {
	Funcations []FunConfig
}

type FunConfig struct {
	FuncationName string   `json:"funcation_name"`
	FilePath      string   `json:"file_path"`
	Params        []string `json:"params"`
	Description   string   `json:"description"`
	Codes         string   `json:"-"`
}

var (
	gconfig     []*FunConfig
	configLock  = new(sync.RWMutex)
	confpath    *string
	FunctionMap map[string]*FunConfig
)

func Config() map[string]*FunConfig {
	configLock.RLock()
	defer configLock.RUnlock()
	return FunctionMap
}

func functionMapGen() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"../config/js", "config/js", "conf/js", "js"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("load js files got error, currentPaht: %s , please check your code tree and make is correct!", currentPath)
	} else {
		log.Info("load javascript scrips successed in " + f)
	}

	FunctionMap = map[string]*FunConfig{}
	for _, v := range gconfig {
		contain := jsFileReader(fmt.Sprintf("%s/%s", f, v.FilePath))
		v.Codes = contain
		FunctionMap[v.FuncationName] = v
	}
}

func ReadConf() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"conf/lambdaSetup.json", "config/lambdaSetup.json", "../config/lambdaSetup.json"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("lambdaSetup.json not found, currentPaht: %s", currentPath)
	} else {
		log.Info("read lambdaSetup.json successed wuth " + f)
	}

	confpath = &f
	dat, err := ioutil.ReadFile(f)
	if err != nil {
		log.Println(err)
	}
	var myconf []*FunConfig
	json.Unmarshal(dat, &myconf)
	if len(myconf) == 0 {
		log.Println("conf file is empty or format is wrong, please check it!")
	}
	gconfig = myconf
	functionMapGen()
}

func Reload() {
	configLock.RLock()
	ReadConf()
	defer configLock.RUnlock()
}

func GetFunc(key string) *FunConfig {
	return FunctionMap[key]
}

func GetAvaibleFun() []string {
	return utils.GetMapKeys(reflect.ValueOf(FunctionMap).MapKeys())
}
<|endoftext|>


<commit_before>package dmgo

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io/ioutil"
)

const currentSnapshotVersion = 1

var supportedSnapshotVersions = []int{
	1,
}

const infoString = "dmgo snapshot"

type snapshot struct {
	Version int
	Info    string
	State   cpuState
	MBC     marshalledMBC
}

func (cs *cpuState) loadSnapshot(snapBytes []byte) (*cpuState, error) {
	reader, err := gzip.NewReader(bytes.NewReader(snapBytes))
	if err != nil {
		return nil, err
	}
	unpackedBytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	var snap snapshot
	err = json.Unmarshal(unpackedBytes, &snap)
	if err != nil {
		return nil, err
	}
	if snap.Version != currentSnapshotVersion {
		return nil, fmt.Errorf("old snapshot version! todo: write version converter")
	}
	snap.State.Mem.cart = cs.Mem.cart
	snap.State.Mem.mbc, err = unmarshalMBC(snap.MBC)
	if err != nil {
		return nil, err
	}

	// NOTE: what about external RAM? Doesn't this overwrite .sav files with whatever's in the snapshot?

	return &snap.State, nil
}

func (cs *cpuState) makeSnapshot() []byte {
	snap := snapshot{
		Version: currentSnapshotVersion,
		Info:    infoString,
		State:   *cs,
		MBC:     cs.Mem.mbc.Marshal(),
	}
	rawJSON, err := json.Marshal(&snap)
	if err != nil {
		panic(err)
	}
	buf := &bytes.Buffer{}
	writer := gzip.NewWriter(buf)
	writer.Write(rawJSON)
	writer.Close()
	return buf.Bytes()
}
<commit_msg>Use aborted change to prepare for snap versioning<commit_after>package dmgo

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
)

const currentSnapshotVersion = 1

const infoString = "dmgo snapshot"

type snapshot struct {
	Version int
	Info    string
	State   json.RawMessage
	MBC     marshalledMBC
}

func (cs *cpuState) loadSnapshot(snapBytes []byte) (*cpuState, error) {
	var err error
	var reader io.Reader
	var unpackedBytes []byte
	var snap snapshot
	if reader, err = gzip.NewReader(bytes.NewReader(snapBytes)); err != nil {
		return nil, err
	} else if unpackedBytes, err = ioutil.ReadAll(reader); err != nil {
		return nil, err
	} else if err = json.Unmarshal(unpackedBytes, &snap); err != nil {
		return nil, err
	} else if snap.Version < currentSnapshotVersion {
		return cs.convertOldSnapshot(&snap)
	} else if snap.Version > currentSnapshotVersion {
		return nil, fmt.Errorf("this version of dmgo is too old to open this snapshot")
	}

	// NOTE: what about external RAM? Doesn't this overwrite .sav files with whatever's in the snapshot?

	return cs.convertLatestSnapshot(&snap)
}

func (cs *cpuState) convertLatestSnapshot(snap *snapshot) (*cpuState, error) {
	var err error
	var newState cpuState
	if err = json.Unmarshal(snap.State, &newState); err != nil {
		return nil, err
	} else if newState.Mem.mbc, err = unmarshalMBC(snap.MBC); err != nil {
		return nil, err
	}
	newState.Mem.cart = cs.Mem.cart
	return &newState, nil
}

var snapshotConverters = map[int]func([]byte) []byte{
// example converter
// 0: func(stateBytes []byte) {
// 	stateBytes = stateBytes[:len(stateBytes)-1]
// 	stateBytes = append(stateBytes, []byte(",\"ExampleNewField\":0}")...)
// 	return stateBytes
// }
}

func (cs *cpuState) convertOldSnapshot(snap *snapshot) (*cpuState, error) {

	var err error
	var newState cpuState

	// unfortunately, can't use json, as go is crazy enough to make it so
	// converting something in and out of json as a map[string]interface{}
	// will kill the ability to import it back in as a struct. so we have
	// to change it by hand to keep the go conventions that go will break
	// otherwise :/
	stateBytes := []byte(snap.State)

	converterFn, ok := snapshotConverters[snap.Version]
	if !ok {
		return nil, fmt.Errorf("unknown snapshot version: %v", snap.Version)
	}
	stateBytes = converterFn(stateBytes)

	if err = json.Unmarshal(stateBytes, &newState); err != nil {
		return nil, fmt.Errorf("post-convert unpack err: %v", err)
	} else if newState.Mem.mbc, err = unmarshalMBC(snap.MBC); err != nil {
		return nil, fmt.Errorf("unpack mbc err: %v", err)
	}
	newState.Mem.cart = cs.Mem.cart
	return &newState, nil
}

func (cs *cpuState) makeSnapshot() []byte {
	var err error
	var csJSON []byte
	var snapJSON []byte
	if csJSON, err = json.Marshal(cs); err != nil {
		panic(err)
	}
	snap := snapshot{
		Version: currentSnapshotVersion,
		Info:    infoString,
		State:   json.RawMessage(csJSON),
		MBC:     cs.Mem.mbc.Marshal(),
	}
	if snapJSON, err = json.Marshal(&snap); err != nil {
		panic(err)
	}
	buf := &bytes.Buffer{}
	writer := gzip.NewWriter(buf)
	writer.Write(snapJSON)
	writer.Close()
	return buf.Bytes()
}
<|endoftext|>


<commit_before>package asock

// Copyright (c) 2014,2015 Shawn Boyette <shawn@firepear.net>. All
// rights reserved.  Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Socket code for asock

import (
	"fmt"
	"net"
	"time"

	"firepear.net/goutils/qsplit"
)

// sockAccept monitors the listener socket and spawns connections for
// clients.
func (a *Asock) sockAccept() {
	defer a.w.Done()
	for n := 1; true; n++ {
		c, err := a.l.Accept()
		if err != nil {
			select {
			case <-a.q:
				// a.Quit() was invoked; close up shop
				a.genMsg(0, 0, 199, 1, "closing listener socket", nil)
				return
			default:
				// we've had a networking error
				a.Msgr <- &Msg{0, 0, 599, "read from listener socket failed", err}
				return
			}
		}
		// we have a new client
		a.w.Add(1)
		go a.connHandler(c, n)
	}
}

// connHandler dispatches commands from, and sends reponses to, a client. It
// is launched, per-connection, from sockAccept().
func (a *Asock) connHandler(c net.Conn, n int) {
	defer a.w.Done()
	defer c.Close()
	b1 := make([]byte, 64) // buffer 1:  network reads go here, 64B at a time
	var b2 []byte          // buffer 2:  then are accumulated here
	var bs []string        // b2, turned into strings by word
	var reqnum int         // request counter for this connection
	var cmdhelp string     // list of commands for the auto-help msg
	for cmd := range a.d {
		cmdhelp = cmdhelp + "    " + cmd + "\n"
	}
	a.genMsg(n, reqnum, 100, 1, "client connected", nil)
	for {
		// set conn timeout deadline if needed
		if a.t != 0 {
			err := a.setConnTimeout(c)
			if err != nil {
				a.genMsg(n, reqnum, 501, 2, "deadline set failed; disconnecting client", err)
				c.Write([]byte("Sorry, an error occurred. Terminating connection."))
				return
			}
		}
		// get request from the client
		for {
			b, err := c.Read(b1)
			if err != nil {
				if err.Error() == "EOF" {
					a.genMsg(n, reqnum, 198, 1, "client disconnected", err)
				} else {
					a.genMsg(n, reqnum, 197, 1, "ending session", err)
				}
				return
			}
			if b > 0 {
				// then copy those bytes into the b2 slice
				b2 = append(b2, b1[:b]...)
				// if we read 64 bytes, loop back to get anything that
				// might be left on the wire
				if b == 64 {
					continue
				}
				bs = qsplit.ToStrings(b2)
				// reslice b2 so that it will be "empty" on the next read
				b2 = b2[:0]
				// break inner loop; drop to dispatch
				break
			}
		}
		reqnum++
		// bs[0] is the command. dispatch if we recognize it, and send
		// response. if not, send error and list of known commands.
		if _, ok := a.d[bs[0]]; ok {
			a.genMsg(n, reqnum, 101, 0, fmt.Sprintf("dispatching %v", bs), nil)
			reply, err := a.d[bs[0]](bs[1:])
			if err != nil {
				c.Write([]byte("Sorry, an error occurred and your request could not be completed."))
				a.genMsg(n, reqnum, 500, 2, "request failed", err)
			} else {
				c.Write(reply)
				a.genMsg(n, reqnum, 200, 0, "reply sent", nil)
			}
		} else {
			c.Write([]byte(fmt.Sprintf("Unknown command '%v'\nAvailable commands:\n%v",
				bs[0], cmdhelp)))
			a.genMsg(n, reqnum, 400, 0, fmt.Sprintf("bad command '%v'", bs[0]), nil)
		}
		// we're done if we're a one-shot connection
		if a.t < 0 {
			a.genMsg(n, reqnum, 197, 1, "ending session", nil)
			return
		}
	}
}

func (a *Asock) setConnTimeout(c net.Conn) error {
	var t time.Duration
	if a.t > 0 {
		t = time.Duration(a.t)
	} else {
		t = time.Duration(a.t - (a.t * 2))
	}
	err := c.SetReadDeadline(time.Now().Add(t * time.Second))
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>ToStringBytes, one-shot improvements<commit_after>package asock

// Copyright (c) 2014,2015 Shawn Boyette <shawn@firepear.net>. All
// rights reserved.  Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Socket code for asock

import (
	"fmt"
	"net"
	"time"

	"firepear.net/goutils/qsplit"
)

// sockAccept monitors the listener socket and spawns connections for
// clients.
func (a *Asock) sockAccept() {
	defer a.w.Done()
	for n := 1; true; n++ {
		c, err := a.l.Accept()
		if err != nil {
			select {
			case <-a.q:
				// a.Quit() was invoked; close up shop
				a.genMsg(0, 0, 199, 1, "closing listener socket", nil)
				return
			default:
				// we've had a networking error
				a.Msgr <- &Msg{0, 0, 599, "read from listener socket failed", err}
				return
			}
		}
		// we have a new client
		a.w.Add(1)
		go a.connHandler(c, n)
	}
}

// connHandler dispatches commands from, and sends reponses to, a client. It
// is launched, per-connection, from sockAccept().
func (a *Asock) connHandler(c net.Conn, n int) {
	defer a.w.Done()
	defer c.Close()
	b1 := make([]byte, 64) // buffer 1:  network reads go here, 64B at a time
	var b2 []byte          // buffer 2:  then are accumulated here
	var bs []string        // b2, turned into strings by word
	var reqnum int         // request counter for this connection
	var cmdhelp string     // list of commands for the auto-help msg
	for cmd := range a.d {
		cmdhelp = cmdhelp + "    " + cmd + "\n"
	}
	a.genMsg(n, reqnum, 100, 1, "client connected", nil)
	for {
		// check if we're a one-shot connection, and if we're done
		if a.t < 0 && reqnum > 0 {
			a.genMsg(n, reqnum, 197, 1, "ending session", nil)
			return
		}
		// set conn timeout deadline if needed
		if a.t != 0 {
			err := a.setConnTimeout(c)
			if err != nil {
				a.genMsg(n, reqnum, 501, 2, "deadline set failed; disconnecting client", err)
				c.Write([]byte("Sorry, an error occurred. Terminating connection."))
				return
			}
		}
		// get request from the client
		for {
			b, err := c.Read(b1)
			if err != nil {
				if err.Error() == "EOF" {
					a.genMsg(n, reqnum, 198, 1, "client disconnected", err)
				} else {
					a.genMsg(n, reqnum, 197, 1, "ending session", err)
				}
				return
			}
			if b > 0 {
				// then copy those bytes into the b2 slice
				b2 = append(b2, b1[:b]...)
				// if we read 64 bytes, loop back to get anything that
				// might be left on the wire
				if b == 64 {
					continue
				}
				cmd, bs = qsplit.ToStringBytes(b2)
				// reslice b2 so that it will be "empty" on the next read
				b2 = b2[:0]
				// break inner loop; drop to dispatch
				break
			}
		}
		reqnum++
		// bs[0] is the command. dispatch if we recognize it, and send
		// response. if not, send error and list of known commands.
		if _, ok := a.d[cmd]; ok {
			a.genMsg(n, reqnum, 101, 0, fmt.Sprintf("dispatching %v %v", cmd, bs), nil)
			reply, err := a.d[cmd](bs)
			if err != nil {
				c.Write([]byte("Sorry, an error occurred and your request could not be completed."))
				a.genMsg(n, reqnum, 500, 2, "request failed", err)
				continue
			}
			c.Write(reply)
			a.genMsg(n, reqnum, 200, 0, "reply sent", nil)
		} else {
			c.Write([]byte(fmt.Sprintf("Unknown command '%v'\nAvailable commands:\n%v",
				bs[0], cmdhelp)))
			a.genMsg(n, reqnum, 400, 0, fmt.Sprintf("bad command '%v'", bs[0]), nil)
		}
	}
}

func (a *Asock) setConnTimeout(c net.Conn) error {
	var t time.Duration
	if a.t > 0 {
		t = time.Duration(a.t)
	} else {
		t = time.Duration(a.t - (a.t * 2))
	}
	err := c.SetReadDeadline(time.Now().Add(t * time.Second))
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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 strfmt

import (
	"database/sql/driver"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"

	"go.mongodb.org/mongo-driver/bson/bsontype"
	bsonprim "go.mongodb.org/mongo-driver/bson/primitive"
)

func init() {
	var id ObjectId
	// register this format in the default registry
	Default.Add("bsonobjectid", &id, IsBSONObjectID)
}

// IsBSONObjectID returns true when the string is a valid BSON.ObjectId
func IsBSONObjectID(str string) bool {
	_, err := bsonprim.ObjectIDFromHex(str)
	return err == nil
}

// ObjectId represents a BSON object ID (alias to go.mongodb.org/mongo-driver/bson/primitive.ObjectID)
//
// swagger:strfmt bsonobjectid
type ObjectId bsonprim.ObjectID

// NewObjectId creates a ObjectId from a Hex String
func NewObjectId(hex string) ObjectId {
	oid, err := bsonprim.ObjectIDFromHex(hex)
	if err != nil {
		panic(err)
	}
	return ObjectId(oid)
}

// MarshalText turns this instance into text
func (id ObjectId) MarshalText() ([]byte, error) {
	oid := bsonprim.ObjectID(id)
	if oid == bsonprim.NilObjectID {
		return nil, nil
	}
	return []byte(oid.Hex()), nil
}

// UnmarshalText hydrates this instance from text
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
	if len(data) == 0 {
		*id = ObjectId(bsonprim.NilObjectID)
		return nil
	}
	oidstr := string(data)
	oid, err := bsonprim.ObjectIDFromHex(oidstr)
	if err != nil {
		return err
	}
	*id = ObjectId(oid)
	return nil
}

// Scan read a value from a database driver
func (id *ObjectId) Scan(raw interface{}) error {
	var data []byte
	switch v := raw.(type) {
	case []byte:
		data = v
	case string:
		data = []byte(v)
	default:
		return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v", v)
	}

	return id.UnmarshalText(data)
}

// Value converts a value to a database driver value
func (id ObjectId) Value() (driver.Value, error) {
	return driver.Value(bsonprim.ObjectID(id).Hex()), nil
}

func (id ObjectId) String() string {
	return bsonprim.ObjectID(id).String()
}

// MarshalJSON returns the ObjectId as JSON
func (id ObjectId) MarshalJSON() ([]byte, error) {
	return bsonprim.ObjectID(id).MarshalJSON()
}

// UnmarshalJSON sets the ObjectId from JSON
func (id *ObjectId) UnmarshalJSON(data []byte) error {
	var obj bsonprim.ObjectID
	if err := obj.UnmarshalJSON(data); err != nil {
		return err
	}
	*id = ObjectId(obj)
	return nil
}

// MarshalBSON renders the object id as a BSON document
func (id ObjectId) MarshalBSON() ([]byte, error) {
	return bson.Marshal(bson.M{"data": bsonprim.ObjectID(id)})
}

// UnmarshalBSON reads the objectId from a BSON document
func (id *ObjectId) UnmarshalBSON(data []byte) error {
	var obj struct {
		Data bsonprim.ObjectID
	}
	if err := bson.Unmarshal(data, &obj); err != nil {
		return err
	}
	*id = ObjectId(obj.Data)
	return nil
}

// MarshalBSONValue is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil.
func (id ObjectId) MarshalBSONValue() (bsontype.Type, []byte, error) {
	oid := bsonprim.ObjectID(id)
	return bsontype.ObjectID, oid[:], nil
}

// UnmarshalBSONValue is an interface implemented by types that can unmarshal a
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
func (id *ObjectId) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
	var oid bsonprim.ObjectID
	copy(oid[:], data)
	*id = ObjectId(oid)
	return nil
}

// DeepCopyInto copies the receiver and writes its value into out.
func (id *ObjectId) DeepCopyInto(out *ObjectId) {
	*out = *id
}

// DeepCopy copies the receiver into a new ObjectId.
func (id *ObjectId) DeepCopy() *ObjectId {
	if id == nil {
		return nil
	}
	out := new(ObjectId)
	id.DeepCopyInto(out)
	return out
}
<commit_msg>issue-83: ObjectId.String() breaks swagger validation and CLI<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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 strfmt

import (
	"database/sql/driver"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"

	"go.mongodb.org/mongo-driver/bson/bsontype"
	bsonprim "go.mongodb.org/mongo-driver/bson/primitive"
)

func init() {
	var id ObjectId
	// register this format in the default registry
	Default.Add("bsonobjectid", &id, IsBSONObjectID)
}

// IsBSONObjectID returns true when the string is a valid BSON.ObjectId
func IsBSONObjectID(str string) bool {
	_, err := bsonprim.ObjectIDFromHex(str)
	return err == nil
}

// ObjectId represents a BSON object ID (alias to go.mongodb.org/mongo-driver/bson/primitive.ObjectID)
//
// swagger:strfmt bsonobjectid
type ObjectId bsonprim.ObjectID

// NewObjectId creates a ObjectId from a Hex String
func NewObjectId(hex string) ObjectId {
	oid, err := bsonprim.ObjectIDFromHex(hex)
	if err != nil {
		panic(err)
	}
	return ObjectId(oid)
}

// MarshalText turns this instance into text
func (id ObjectId) MarshalText() ([]byte, error) {
	oid := bsonprim.ObjectID(id)
	if oid == bsonprim.NilObjectID {
		return nil, nil
	}
	return []byte(oid.Hex()), nil
}

// UnmarshalText hydrates this instance from text
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
	if len(data) == 0 {
		*id = ObjectId(bsonprim.NilObjectID)
		return nil
	}
	oidstr := string(data)
	oid, err := bsonprim.ObjectIDFromHex(oidstr)
	if err != nil {
		return err
	}
	*id = ObjectId(oid)
	return nil
}

// Scan read a value from a database driver
func (id *ObjectId) Scan(raw interface{}) error {
	var data []byte
	switch v := raw.(type) {
	case []byte:
		data = v
	case string:
		data = []byte(v)
	default:
		return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v", v)
	}

	return id.UnmarshalText(data)
}

// Value converts a value to a database driver value
func (id ObjectId) Value() (driver.Value, error) {
	return driver.Value(bsonprim.ObjectID(id).Hex()), nil
}

func (id ObjectId) String() string {
	return bsonprim.ObjectID(id).Hex()
}

// MarshalJSON returns the ObjectId as JSON
func (id ObjectId) MarshalJSON() ([]byte, error) {
	return bsonprim.ObjectID(id).MarshalJSON()
}

// UnmarshalJSON sets the ObjectId from JSON
func (id *ObjectId) UnmarshalJSON(data []byte) error {
	var obj bsonprim.ObjectID
	if err := obj.UnmarshalJSON(data); err != nil {
		return err
	}
	*id = ObjectId(obj)
	return nil
}

// MarshalBSON renders the object id as a BSON document
func (id ObjectId) MarshalBSON() ([]byte, error) {
	return bson.Marshal(bson.M{"data": bsonprim.ObjectID(id)})
}

// UnmarshalBSON reads the objectId from a BSON document
func (id *ObjectId) UnmarshalBSON(data []byte) error {
	var obj struct {
		Data bsonprim.ObjectID
	}
	if err := bson.Unmarshal(data, &obj); err != nil {
		return err
	}
	*id = ObjectId(obj.Data)
	return nil
}

// MarshalBSONValue is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil.
func (id ObjectId) MarshalBSONValue() (bsontype.Type, []byte, error) {
	oid := bsonprim.ObjectID(id)
	return bsontype.ObjectID, oid[:], nil
}

// UnmarshalBSONValue is an interface implemented by types that can unmarshal a
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
func (id *ObjectId) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
	var oid bsonprim.ObjectID
	copy(oid[:], data)
	*id = ObjectId(oid)
	return nil
}

// DeepCopyInto copies the receiver and writes its value into out.
func (id *ObjectId) DeepCopyInto(out *ObjectId) {
	*out = *id
}

// DeepCopy copies the receiver into a new ObjectId.
func (id *ObjectId) DeepCopy() *ObjectId {
	if id == nil {
		return nil
	}
	out := new(ObjectId)
	id.DeepCopyInto(out)
	return out
}
<|endoftext|>


<commit_before>package cidcommands

/*
  Copyright David Thorpe 2015 All Rights Reserved
  Please see file LICENSE for information on distribution, etc
*/

import (
	"errors"
	"strings"

	"github.com/djthorpe/ytapi/youtubepartner/v1"
	"github.com/djthorpe/ytapi/ytapi"
	"github.com/djthorpe/ytapi/ytservice"
)

////////////////////////////////////////////////////////////////////////////////
// Register commands

func RegisterClaimCommands() []*ytapi.Command {
	return []*ytapi.Command{
		&ytapi.Command{
			Name:           "Claim",
			Description:    "Create a claim between a video and asset with a defined policy",
			ServiceAccount: true,
			Required:       []*ytapi.Flag{&ytapi.FlagVideo, &ytapi.FlagAsset, &ytapi.FlagPolicy},
			Optional:       []*ytapi.Flag{&ytapi.FlagClaimType, &ytapi.FlagClaimBlockOutsideOwnership},
			Setup:          RegisterClaimFormat,
			Execute:        InsertClaim,
		},
		&ytapi.Command{
			Name:           "GetClaim",
			Description:    "Get Existing claim",
			ServiceAccount: true,
			Required:       []*ytapi.Flag{&ytapi.FlagClaim},
			Setup:          RegisterClaimFormat,
			Execute:        GetClaim,
		},
		&ytapi.Command{
			Name:           "ListClaims",
			Description:    "List all claims",
			ServiceAccount: true,
			Optional:       []*ytapi.Flag{&ytapi.FlagMaxResults},
			Setup:          RegisterClaimFormat,
			Execute:        ListClaims,
		},
		&ytapi.Command{
			Name:           "ClaimHistory",
			Description:    "List history for a claim",
			ServiceAccount: true,
			Required:       []*ytapi.Flag{&ytapi.FlagClaim},
			Setup:          RegisterClaimHistoryFormat,
			Execute:        GetClaimHistory,
		},
		&ytapi.Command{
			Name:           "UpdateClaim",
			Description:    "Update an existing claim or video",
			ServiceAccount: true,
			Optional:       []*ytapi.Flag{&ytapi.FlagVideo, &ytapi.FlagClaim, &ytapi.FlagClaimStatus, &ytapi.FlagPolicy, &ytapi.FlagClaimBlockOutsideOwnership},
			Setup:          RegisterClaimFormat,
			Execute:        PatchClaim,
		},
	}
}

////////////////////////////////////////////////////////////////////////////////
// Register format

func RegisterClaimFormat(values *ytapi.Values, table *ytapi.Table) error {

	table.RegisterPart("id", []*ytapi.Flag{
		&ytapi.Flag{Name: "claim", Path: "Id", Type: ytapi.FLAG_STRING},
	})

	table.RegisterPart("snippet", []*ytapi.Flag{
		&ytapi.Flag{Name: "asset", Path: "AssetId", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "video", Path: "VideoId", Type: ytapi.FLAG_VIDEO},
		&ytapi.Flag{Name: "timeCreated", Path: "TimeCreated", Type: ytapi.FLAG_TIME},
	})

	table.RegisterPart("claimDetails", []*ytapi.Flag{
		&ytapi.Flag{Name: "status", Path: "Status", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "origin", Path: "Origin/Source", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "type", Path: "ContentType", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "isPartnerUploaded", Path: "IsPartnerUploaded", Type: ytapi.FLAG_BOOL},
		&ytapi.Flag{Name: "blockOutsideOwnership", Path: "BlockOutsideOwnership", Type: ytapi.FLAG_BOOL},
	})

	table.RegisterPart("policyDetails", []*ytapi.Flag{
		&ytapi.Flag{Name: "policy", Path: "Policy/Id", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "policyName", Path: "Policy/Name", Type: ytapi.FLAG_STRING},
	})

	// set default columns
	table.SetColumns([]string{"claim", "asset", "video", "status", "origin", "type", "timeCreated", "policyName"})

	// success
	return nil
}

func RegisterClaimHistoryFormat(values *ytapi.Values, table *ytapi.Table) error {

	table.RegisterPart("snippet", []*ytapi.Flag{
		&ytapi.Flag{Name: "type", Path: "Type", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "time", Path: "Time", Type: ytapi.FLAG_TIME},
		&ytapi.Flag{Name: "source", Path: "Source/Type", Type: ytapi.FLAG_STRING},
	})

	// set default columns
	table.SetColumns([]string{"type", "time"})

	// success
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Return Policy

func policyByValue(value string) (*youtubepartner.Policy, error) {
	return &youtubepartner.Policy{
		Id: value,
	}, nil
}

func policyByIdentifier(name string) (*youtubepartner.Policy, error) {
	return &youtubepartner.Policy{
		Id: name,
	}, nil
}

func policyByWorldwideRule(name string) (*youtubepartner.Policy, error) {
	switch strings.TrimSpace(strings.ToLower(name)) {
	case "block":
		// TODO
		return &youtubepartner.Policy{}, nil
	case "track":
		// TODO
		return &youtubepartner.Policy{}, nil
	case "monetize":
		// TODO
		return &youtubepartner.Policy{}, nil
	default:
		return nil, errors.New("Invalid policy value")
	}
}

////////////////////////////////////////////////////////////////////////////////
// Return Claim

func claimSearchByVideo(service *ytservice.Service, values *ytapi.Values) (string, error) {
	// create call and set parameters
	call := service.PAPI.ClaimSearch.List()
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))
	call = call.VideoId(values.GetString(&ytapi.FlagVideo))
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return "", err
	}
	if len(response.Items) != 1 {
		return "", errors.New("Invalid claim")
	}
	return response.Items[0].Id, nil
}

////////////////////////////////////////////////////////////////////////////////
// List Claims

func ListClaims(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// create call and set parameters
	call := service.PAPI.Claims.List()
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	return ytapi.DoClaimsList(call, table, values.GetInt(&ytapi.FlagMaxResults))
}

////////////////////////////////////////////////////////////////////////////////
// Get Claim

func GetClaim(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// create call and set parameters
	call := service.PAPI.Claims.Get(values.GetString(&ytapi.FlagClaim))
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}
	if err = table.Append([]*youtubepartner.Claim{response}); err != nil {
		return err
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Claim History

func GetClaimHistory(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// create call and set parameters
	call := service.PAPI.ClaimHistory.Get(values.GetString(&ytapi.FlagClaim))
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}
	if err = table.Append(response.Event); err != nil {
		return err
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Create Claim

func InsertClaim(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// create call and set parameters
	call := service.PAPI.Claims.Insert(&youtubepartner.Claim{
		AssetId:     values.GetString(&ytapi.FlagAsset),
		VideoId:     values.GetString(&ytapi.FlagVideo),
		ContentType: values.GetString(&ytapi.FlagClaimType),
		Policy: &youtubepartner.Policy{
			Id: values.GetString(&ytapi.FlagPolicy),
		},
	})
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}

	// Handle block outside ownership
	// TODO: always force sending the flag
	if values.IsSet(&ytapi.FlagClaimBlockOutsideOwnership) {
		call := service.PAPI.Claims.Patch(response.Id, &youtubepartner.Claim{
			BlockOutsideOwnership: values.GetBool(&ytapi.FlagClaimBlockOutsideOwnership),
		})
		call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))
		// Execute
		response, err = call.Do(service.CallOptions()...)
		if err != nil {
			return err
		}
	}

	if err = table.Append([]*youtubepartner.Claim{response}); err != nil {
		return err
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Patch Claim

func PatchClaim(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	var err error

	// claim or video parameter
	var claim string
	if values.IsSet(&ytapi.FlagClaim) {
		claim = values.GetString(&ytapi.FlagClaim)
	} else if values.IsSet(&ytapi.FlagVideo) {
		if claim, err = claimSearchByVideo(service, values); err != nil {
			return err
		}
	} else {
		return errors.New("Expect -claim or -video flag")
	}

	// policy parameter
	var policy *youtubepartner.Policy
	if values.IsSet(&ytapi.FlagPolicy) {
		policy, err = policyByValue(values.GetString(&ytapi.FlagPolicy))
	}

	call := service.PAPI.Claims.Patch(claim, &youtubepartner.Claim{
		BlockOutsideOwnership: values.GetBool(&ytapi.FlagClaimBlockOutsideOwnership),
		Status:                values.GetString(&ytapi.FlagClaimStatus),
		Policy:                policy,
		ForceSendFields: values.SetFields(map[string]*ytapi.Flag{
			"BlockOutsideOwnership": &ytapi.FlagClaimBlockOutsideOwnership,
			"Status":                &ytapi.FlagClaimStatus,
			"Policy":                &ytapi.FlagPolicy,
		}),
	})
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}

	// Append claim to table
	if err = table.Append([]*youtubepartner.Claim{response}); err != nil {
		return err
	}
	return nil
}
<commit_msg>Updated claim policy creation for track, block, monetize and takedown<commit_after>package cidcommands

/*
  Copyright David Thorpe 2015 All Rights Reserved
  Please see file LICENSE for information on distribution, etc
*/

import (
	"errors"
	"strings"

	"github.com/djthorpe/ytapi/youtubepartner/v1"
	"github.com/djthorpe/ytapi/ytapi"
	"github.com/djthorpe/ytapi/ytservice"
)

////////////////////////////////////////////////////////////////////////////////
// Register commands

func RegisterClaimCommands() []*ytapi.Command {
	return []*ytapi.Command{
		&ytapi.Command{
			Name:           "Claim",
			Description:    "Create a claim between a video and asset with a defined policy",
			ServiceAccount: true,
			Required:       []*ytapi.Flag{&ytapi.FlagVideo, &ytapi.FlagAsset, &ytapi.FlagPolicy},
			Optional:       []*ytapi.Flag{&ytapi.FlagClaimType, &ytapi.FlagClaimBlockOutsideOwnership},
			Setup:          RegisterClaimFormat,
			Execute:        InsertClaim,
		},
		&ytapi.Command{
			Name:           "GetClaim",
			Description:    "Get Existing claim",
			ServiceAccount: true,
			Optional:       []*ytapi.Flag{&ytapi.FlagClaim, &ytapi.FlagVideo},
			Setup:          RegisterClaimFormat,
			Execute:        GetClaim,
		},
		&ytapi.Command{
			Name:           "ListClaims",
			Description:    "List all claims",
			ServiceAccount: true,
			Optional:       []*ytapi.Flag{&ytapi.FlagMaxResults},
			Setup:          RegisterClaimFormat,
			Execute:        ListClaims,
		},
		&ytapi.Command{
			Name:           "ClaimHistory",
			Description:    "List history for a claim",
			ServiceAccount: true,
			Optional:       []*ytapi.Flag{&ytapi.FlagClaim, &ytapi.FlagVideo},
			Setup:          RegisterClaimHistoryFormat,
			Execute:        GetClaimHistory,
		},
		&ytapi.Command{
			Name:           "UpdateClaim",
			Description:    "Update an existing claim or video",
			ServiceAccount: true,
			Optional:       []*ytapi.Flag{&ytapi.FlagVideo, &ytapi.FlagClaim, &ytapi.FlagClaimStatus, &ytapi.FlagPolicy, &ytapi.FlagClaimBlockOutsideOwnership},
			Setup:          RegisterClaimFormat,
			Execute:        PatchClaim,
		},
	}
}

////////////////////////////////////////////////////////////////////////////////
// Register format

func RegisterClaimFormat(values *ytapi.Values, table *ytapi.Table) error {

	table.RegisterPart("id", []*ytapi.Flag{
		&ytapi.Flag{Name: "claim", Path: "Id", Type: ytapi.FLAG_STRING},
	})

	table.RegisterPart("snippet", []*ytapi.Flag{
		&ytapi.Flag{Name: "asset", Path: "AssetId", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "video", Path: "VideoId", Type: ytapi.FLAG_VIDEO},
		&ytapi.Flag{Name: "timeCreated", Path: "TimeCreated", Type: ytapi.FLAG_TIME},
	})

	table.RegisterPart("claimDetails", []*ytapi.Flag{
		&ytapi.Flag{Name: "status", Path: "Status", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "origin", Path: "Origin/Source", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "type", Path: "ContentType", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "isPartnerUploaded", Path: "IsPartnerUploaded", Type: ytapi.FLAG_BOOL},
		&ytapi.Flag{Name: "blockOutsideOwnership", Path: "BlockOutsideOwnership", Type: ytapi.FLAG_BOOL},
	})

	table.RegisterPart("policyDetails", []*ytapi.Flag{
		&ytapi.Flag{Name: "policy", Path: "Policy/Id", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "policyName", Path: "Policy/Name", Type: ytapi.FLAG_STRING},
	})

	// set default columns
	table.SetColumns([]string{"claim", "asset", "video", "status", "origin", "type", "timeCreated", "policyName"})

	// success
	return nil
}

func RegisterClaimHistoryFormat(values *ytapi.Values, table *ytapi.Table) error {

	table.RegisterPart("snippet", []*ytapi.Flag{
		&ytapi.Flag{Name: "type", Path: "Type", Type: ytapi.FLAG_STRING},
		&ytapi.Flag{Name: "time", Path: "Time", Type: ytapi.FLAG_TIME},
		&ytapi.Flag{Name: "source", Path: "Source/Type", Type: ytapi.FLAG_STRING},
	})

	// set default columns
	table.SetColumns([]string{"type", "time"})

	// success
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Return Policy

func policyByValue(value string) (*youtubepartner.Policy, error) {
	value2 := strings.TrimSpace(strings.ToLower(value))
	switch value2 {
	case "block", "track", "monetize", "takedown":
		return policyByWorldwideRule(value2)
	default:
		return policyByIdentifier(value)
	}
}

func policyByIdentifier(name string) (*youtubepartner.Policy, error) {
	return &youtubepartner.Policy{
		Id: name,
	}, nil
}

func policyByWorldwideRule(name string) (*youtubepartner.Policy, error) {
	switch name {
	case "block":
		return &youtubepartner.Policy{
			Rules: []*youtubepartner.PolicyRule{
				&youtubepartner.PolicyRule{
					Action: "block",
				},
			},
		}, nil
	case "track":
		return &youtubepartner.Policy{
			Rules: []*youtubepartner.PolicyRule{
				&youtubepartner.PolicyRule{
					Action: "track",
				},
			},
		}, nil
	case "monetize":
		return &youtubepartner.Policy{
			Rules: []*youtubepartner.PolicyRule{
				&youtubepartner.PolicyRule{
					Action: "monetize",
				},
			},
		}, nil
	case "takedown":
		return &youtubepartner.Policy{
			Rules: []*youtubepartner.PolicyRule{
				&youtubepartner.PolicyRule{
					Action: "takedown",
				},
			},
		}, nil
	default:
		return nil, errors.New("Invalid policy value")
	}
}

////////////////////////////////////////////////////////////////////////////////
// Return Claim

func claimSearchByVideo(service *ytservice.Service, values *ytapi.Values) (string, error) {
	// create call and set parameters
	call := service.PAPI.ClaimSearch.List()
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))
	call = call.VideoId(values.GetString(&ytapi.FlagVideo))
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return "", err
	}
	if len(response.Items) != 1 {
		return "", errors.New("Invalid claim")
	}
	return response.Items[0].Id, nil
}

////////////////////////////////////////////////////////////////////////////////
// List Claims

func ListClaims(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// create call and set parameters
	call := service.PAPI.Claims.List()
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	return ytapi.DoClaimsList(call, table, values.GetInt(&ytapi.FlagMaxResults))
}

////////////////////////////////////////////////////////////////////////////////
// Get Claim

func GetClaim(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// claim or video parameter
	var err error
	var claim string
	if values.IsSet(&ytapi.FlagClaim) {
		claim = values.GetString(&ytapi.FlagClaim)
	} else if values.IsSet(&ytapi.FlagVideo) {
		if claim, err = claimSearchByVideo(service, values); err != nil {
			return err
		}
	} else {
		return errors.New("Expect -claim or -video flag")
	}

	// create call and set parameters
	call := service.PAPI.Claims.Get(claim)
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}
	if err = table.Append([]*youtubepartner.Claim{response}); err != nil {
		return err
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Claim History

func GetClaimHistory(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// claim or video parameter
	var err error
	var claim string
	if values.IsSet(&ytapi.FlagClaim) {
		claim = values.GetString(&ytapi.FlagClaim)
	} else if values.IsSet(&ytapi.FlagVideo) {
		if claim, err = claimSearchByVideo(service, values); err != nil {
			return err
		}
	} else {
		return errors.New("Expect -claim or -video flag")
	}

	// create call and set parameters
	call := service.PAPI.ClaimHistory.Get(claim)
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}
	if err = table.Append(response.Event); err != nil {
		return err
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Create Claim

func InsertClaim(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	// create call and set parameters
	call := service.PAPI.Claims.Insert(&youtubepartner.Claim{
		AssetId:     values.GetString(&ytapi.FlagAsset),
		VideoId:     values.GetString(&ytapi.FlagVideo),
		ContentType: values.GetString(&ytapi.FlagClaimType),
		Policy: &youtubepartner.Policy{
			Id: values.GetString(&ytapi.FlagPolicy),
		},
	})
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}

	// Handle block outside ownership
	// TODO: always force sending the flag
	if values.IsSet(&ytapi.FlagClaimBlockOutsideOwnership) {
		call := service.PAPI.Claims.Patch(response.Id, &youtubepartner.Claim{
			BlockOutsideOwnership: values.GetBool(&ytapi.FlagClaimBlockOutsideOwnership),
		})
		call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))
		// Execute
		response, err = call.Do(service.CallOptions()...)
		if err != nil {
			return err
		}
	}

	if err = table.Append([]*youtubepartner.Claim{response}); err != nil {
		return err
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////////
// Patch Claim

func PatchClaim(service *ytservice.Service, values *ytapi.Values, table *ytapi.Table) error {
	var err error

	// claim or video parameter
	var claim string
	if values.IsSet(&ytapi.FlagClaim) {
		claim = values.GetString(&ytapi.FlagClaim)
	} else if values.IsSet(&ytapi.FlagVideo) {
		if claim, err = claimSearchByVideo(service, values); err != nil {
			return err
		}
	} else {
		return errors.New("Expect -claim or -video flag")
	}

	// policy parameter
	var policy *youtubepartner.Policy
	if values.IsSet(&ytapi.FlagPolicy) {
		policy, err = policyByValue(values.GetString(&ytapi.FlagPolicy))
	}

	call := service.PAPI.Claims.Patch(claim, &youtubepartner.Claim{
		BlockOutsideOwnership: values.GetBool(&ytapi.FlagClaimBlockOutsideOwnership),
		Status:                values.GetString(&ytapi.FlagClaimStatus),
		Policy:                policy,
		ForceSendFields: values.SetFields(map[string]*ytapi.Flag{
			"BlockOutsideOwnership": &ytapi.FlagClaimBlockOutsideOwnership,
			"Status":                &ytapi.FlagClaimStatus,
			"Policy":                &ytapi.FlagPolicy,
		}),
	})
	call = call.OnBehalfOfContentOwner(values.GetString(&ytapi.FlagContentOwner))

	// Execute
	response, err := call.Do(service.CallOptions()...)
	if err != nil {
		return err
	}

	// Append claim to table
	if err = table.Append([]*youtubepartner.Claim{response}); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"text/template"
)

// Step ...
// Step configuration container
type Step struct {
	Context  map[string]string
	Name     string
	Register string
	Type     string
	UUID     string
}

// Compile ...
// Compile, in place, `Step.Context` entry templates with
// state data from a WorkflowRunner
func (s *Step) Compile(v map[string]interface{}) (*Step, error) {
	var err error

	for varKey, varValue := range s.Context {
		var buf bytes.Buffer

		tmpl := template.Must(template.New("stepContext").Parse(varValue))

		err = tmpl.Execute(&buf, v)
		if err != nil {
			return s, err
		}

		s.Context[varKey] = buf.String()
	}

	return s, nil
}

// JSON ...
// JSON representation of a `Step`
func (s *Step) JSON() (j []byte, err error) {
	return json.Marshal(s)
}
<commit_msg>Update `*Step`s after run with metadata<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"text/template"
)

// Step ...
// Step configuration container
type Step struct {
	Context      map[string]string
	Duration     string
	End          string
	ErrorMessage string
	Failed       bool
	Name         string
	Register     string
	Start        string
	Type         string
	UUID         string
}

// Compile ...
// Compile, in place, `Step.Context` entry templates with
// state data from a WorkflowRunner
func (s *Step) Compile(v map[string]interface{}) (*Step, error) {
	var err error

	for varKey, varValue := range s.Context {
		var buf bytes.Buffer

		tmpl := template.Must(template.New("stepContext").Parse(varValue))

		err = tmpl.Execute(&buf, v)
		if err != nil {
			return s, err
		}

		s.Context[varKey] = buf.String()
	}

	return
}

// SetStatus receives data from job nodes and updates compiled
// Step data within a Workflow Runner for added metadata visibility
func (s *Step) SetStatus(m map[string]interface{}) {
	s.Duration = m["Duration"].(string)
	s.Start = m["Start"].(string)
	s.End = m["End"].(string)
	s.Failed = m["Failed"].(bool)

	if s.Failed {
		s.ErrorMessage = m["ErrorMessage"].(string)
	}
}

// JSON ...
// JSON representation of a `Step`
func (s *Step) JSON() (j []byte, err error) {
	return json.Marshal(s)
}
<|endoftext|>


<commit_before>package affiliate

import (
	"encoding/json"
	"math/big"
	"context"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/notegio/openrelay/channels"
	"github.com/notegio/openrelay/types"
	"github.com/notegio/openrelay/affiliates"
	"github.com/notegio/openrelay/monitor/blocks"
	"gopkg.in/redis.v3"
	"log"
)

type affiliateBlockConsumer struct {
	affiliateSignupAddress   *big.Int
	affiliateService  affiliates.AffiliateService
	logFilter         ethereum.LogFilterer
}

func (consumer *affiliateBlockConsumer) Consume(delivery channels.Delivery) {
	block := &blocks.MiniBlock{}
	err := json.Unmarshal([]byte(delivery.Payload()), block)
	if err != nil {
		log.Printf("Error parsing payload: %v\n", err.Error())
	}
	affiliateTopic := &big.Int{}
	affiliateTopic.SetString("7d749bde5f784fee88b0252e238a232cb0554e7c2c4f34ee5e785529217ac145", 16)
	if block.Bloom.Test(consumer.affiliateSignupAddress) && block.Bloom.Test(affiliateTopic) {
		query := ethereum.FilterQuery{
			FromBlock: block.Number,
			ToBlock: block.Number,
			Addresses: []common.Address{common.BigToAddress(consumer.affiliateSignupAddress)},
			Topics: [][]common.Hash{
				[]common.Hash{common.BigToHash(affiliateTopic)},
				nil,
				nil,
			},
		}
		logs, err := consumer.logFilter.FilterLogs(context.Background(), query)
		if err != nil {
			delivery.Return()
			log.Fatalf("Failed to filter logs on block %v - aborting: %v", block.Number, err.Error())
		}
		for _, affiliateLog := range logs {
			affiliate := affiliates.NewAffiliate(nil, 100)
			affiliateAddress := &types.Address{}
			copy(affiliateAddress[:], affiliateLog.Data[12:32])
			if err := consumer.affiliateService.Set(affiliateAddress, affiliate); err != nil {
				delivery.Return()
				log.Fatalf("Error registering affiliate: %#x", affiliateAddress[:])
			}
			log.Printf("Added affiliate: %#x", affiliateAddress[:])
		}
	}
	delivery.Ack()
}

func NewAffiliateBlockConsumer(affiliateSignupAddress *big.Int, lf ethereum.LogFilterer, affiliateService affiliates.AffiliateService) (channels.Consumer) {
	return &affiliateBlockConsumer{affiliateSignupAddress, affiliateService, lf}
}

func NewRPCAffiliateBlockConsumer(rpcURL string, affiliateSignupAddress string, redisClient *redis.Client) (channels.Consumer, error) {

	client, err := ethclient.Dial(rpcURL)
	if err != nil {
		return nil, err
	}
	return NewAffiliateBlockConsumer(common.HexToAddress(affiliateSignupAddress).Big(), client, affiliates.NewRedisAffiliateService(redisClient)), nil
}
<commit_msg>Update affiliate topic based on changes to event parameters<commit_after>package affiliate

import (
	"encoding/json"
	"math/big"
	"context"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/notegio/openrelay/channels"
	"github.com/notegio/openrelay/types"
	"github.com/notegio/openrelay/affiliates"
	"github.com/notegio/openrelay/monitor/blocks"
	"gopkg.in/redis.v3"
	"log"
)

type affiliateBlockConsumer struct {
	affiliateSignupAddress   *big.Int
	affiliateService  affiliates.AffiliateService
	logFilter         ethereum.LogFilterer
}

func (consumer *affiliateBlockConsumer) Consume(delivery channels.Delivery) {
	block := &blocks.MiniBlock{}
	err := json.Unmarshal([]byte(delivery.Payload()), block)
	if err != nil {
		log.Printf("Error parsing payload: %v\n", err.Error())
	}
	affiliateTopic := &big.Int{}
	affiliateTopic.SetString("60dad0d232381238c031553102e3a2d779bda5a9507ec806820542b3da2801eb", 16)
	if block.Bloom.Test(consumer.affiliateSignupAddress) && block.Bloom.Test(affiliateTopic) {
		query := ethereum.FilterQuery{
			FromBlock: block.Number,
			ToBlock: block.Number,
			Addresses: []common.Address{common.BigToAddress(consumer.affiliateSignupAddress)},
			Topics: [][]common.Hash{
				[]common.Hash{common.BigToHash(affiliateTopic)},
				nil,
				nil,
			},
		}
		logs, err := consumer.logFilter.FilterLogs(context.Background(), query)
		if err != nil {
			delivery.Return()
			log.Fatalf("Failed to filter logs on block %v - aborting: %v", block.Number, err.Error())
		}
		for _, affiliateLog := range logs {
			affiliate := affiliates.NewAffiliate(nil, 100)
			affiliateAddress := &types.Address{}
			copy(affiliateAddress[:], affiliateLog.Data[12:32])
			if err := consumer.affiliateService.Set(affiliateAddress, affiliate); err != nil {
				delivery.Return()
				log.Fatalf("Error registering affiliate: %#x", affiliateAddress[:])
			}
			log.Printf("Added affiliate: %#x", affiliateAddress[:])
		}
	}
	delivery.Ack()
}

func NewAffiliateBlockConsumer(affiliateSignupAddress *big.Int, lf ethereum.LogFilterer, affiliateService affiliates.AffiliateService) (channels.Consumer) {
	return &affiliateBlockConsumer{affiliateSignupAddress, affiliateService, lf}
}

func NewRPCAffiliateBlockConsumer(rpcURL string, affiliateSignupAddress string, redisClient *redis.Client) (channels.Consumer, error) {

	client, err := ethclient.Dial(rpcURL)
	if err != nil {
		return nil, err
	}
	return NewAffiliateBlockConsumer(common.HexToAddress(affiliateSignupAddress).Big(), client, affiliates.NewRedisAffiliateService(redisClient)), nil
}
<|endoftext|>


<commit_before>package detailed

import (
	"sort"

	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/report"
)

// Parent is the information needed to build a link to the parent of a Node.
type Parent struct {
	ID         string `json:"id"`
	Label      string `json:"label"`
	TopologyID string `json:"topologyId"`
}

func node(t report.Topology) func(string) (report.Node, bool) {
	return func(id string) (report.Node, bool) {
		n, ok := t.Nodes[id]
		return n, ok
	}
}

func fake(id string) (report.Node, bool) {
	return report.MakeNode(id), true
}

// Parents renders the parents of this report.Node, which have been aggregated
// from the probe reports.
func Parents(r report.Report, n report.Node) (result []Parent) {
	topologies := map[string]struct {
		node   func(id string) (report.Node, bool)
		render func(report.Node) Parent
	}{
		report.Container:      {node(r.Container), containerParent},
		report.Pod:            {node(r.Pod), podParent},
		report.ReplicaSet:     {node(r.ReplicaSet), replicaSetParent},
		report.Deployment:     {node(r.Deployment), deploymentParent},
		report.Service:        {node(r.Service), serviceParent},
		report.ContainerImage: {fake, containerImageParent},
		report.Host:           {node(r.Host), hostParent},
	}
	topologyIDs := []string{}
	for topologyID := range topologies {
		topologyIDs = append(topologyIDs, topologyID)
	}
	sort.Strings(topologyIDs)
	for _, topologyID := range topologyIDs {
		t := topologies[topologyID]
		parents, _ := n.Parents.Lookup(topologyID)
		for _, id := range parents {
			if topologyID == n.Topology && id == n.ID {
				continue
			}

			parent, ok := t.node(id)
			if !ok {
				continue
			}

			result = append(result, t.render(parent))
		}
	}
	return result
}

func containerParent(n report.Node) Parent {
	label := getRenderableContainerName(n)
	return Parent{
		ID:         n.ID,
		Label:      label,
		TopologyID: "containers",
	}
}

var (
	podParent        = kubernetesParent("pods")
	replicaSetParent = kubernetesParent("replica-sets")
	deploymentParent = kubernetesParent("deployments")
	serviceParent    = kubernetesParent("services")
)

func kubernetesParent(topology string) func(report.Node) Parent {
	return func(n report.Node) Parent {
		name, _ := n.Latest.Lookup(kubernetes.Name)
		return Parent{
			ID:         n.ID,
			Label:      name,
			TopologyID: topology,
		}
	}
}

func containerImageParent(n report.Node) Parent {
	name, _ := report.ParseContainerImageNodeID(n.ID)
	return Parent{
		ID:         n.ID,
		Label:      name,
		TopologyID: "containers-by-image",
	}
}

func hostParent(n report.Node) Parent {
	hostName, _ := n.Latest.Lookup(host.HostName)
	return Parent{
		ID:         n.ID,
		Label:      hostName,
		TopologyID: "hosts",
	}
}
<commit_msg>render.detailed: Add ECS topologies to detailed parents conversion<commit_after>package detailed

import (
	"sort"

	"github.com/weaveworks/scope/probe/awsecs"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/report"
)

// Parent is the information needed to build a link to the parent of a Node.
type Parent struct {
	ID         string `json:"id"`
	Label      string `json:"label"`
	TopologyID string `json:"topologyId"`
}

func node(t report.Topology) func(string) (report.Node, bool) {
	return func(id string) (report.Node, bool) {
		n, ok := t.Nodes[id]
		return n, ok
	}
}

func fake(id string) (report.Node, bool) {
	return report.MakeNode(id), true
}

// Parents renders the parents of this report.Node, which have been aggregated
// from the probe reports.
func Parents(r report.Report, n report.Node) (result []Parent) {
	topologies := map[string]struct {
		node   func(id string) (report.Node, bool)
		render func(report.Node) Parent
	}{
		report.Container:      {node(r.Container), containerParent},
		report.Pod:            {node(r.Pod), podParent},
		report.ReplicaSet:     {node(r.ReplicaSet), replicaSetParent},
		report.Deployment:     {node(r.Deployment), deploymentParent},
		report.Service:        {node(r.Service), serviceParent},
		report.ECSTask:        {node(r.ECSTask), ecsTaskParent},
		report.ECSService:     {node(r.ECSService), ecsServiceParent},
		report.ContainerImage: {fake, containerImageParent},
		report.Host:           {node(r.Host), hostParent},
	}
	topologyIDs := []string{}
	for topologyID := range topologies {
		topologyIDs = append(topologyIDs, topologyID)
	}
	sort.Strings(topologyIDs)
	for _, topologyID := range topologyIDs {
		t := topologies[topologyID]
		parents, _ := n.Parents.Lookup(topologyID)
		for _, id := range parents {
			if topologyID == n.Topology && id == n.ID {
				continue
			}

			parent, ok := t.node(id)
			if !ok {
				continue
			}

			result = append(result, t.render(parent))
		}
	}
	return result
}

func containerParent(n report.Node) Parent {
	label := getRenderableContainerName(n)
	return Parent{
		ID:         n.ID,
		Label:      label,
		TopologyID: "containers",
	}
}

var (
	podParent        = kubernetesParent("pods")
	replicaSetParent = kubernetesParent("replica-sets")
	deploymentParent = kubernetesParent("deployments")
	serviceParent    = kubernetesParent("services")
)

func kubernetesParent(topology string) func(report.Node) Parent {
	return func(n report.Node) Parent {
		name, _ := n.Latest.Lookup(kubernetes.Name)
		return Parent{
			ID:         n.ID,
			Label:      name,
			TopologyID: topology,
		}
	}
}

func ecsTaskParent(n report.Node) Parent {
	family, _ := n.Latest.Lookup(awsecs.TaskFamily)
	return Parent{
		ID:         n.ID,
		Label:      family,
		TopologyID: "ecs-tasks",
	}
}

func ecsServiceParent(n report.Node) Parent {
	name, _ := report.ParseECSServiceNodeID(n.ID)
	return Parent{
		ID:         n.ID,
		Label:      name,
		TopologyID: "ecs-services",
	}
}

func containerImageParent(n report.Node) Parent {
	name, _ := report.ParseContainerImageNodeID(n.ID)
	return Parent{
		ID:         n.ID,
		Label:      name,
		TopologyID: "containers-by-image",
	}
}

func hostParent(n report.Node) Parent {
	hostName, _ := n.Latest.Lookup(host.HostName)
	return Parent{
		ID:         n.ID,
		Label:      hostName,
		TopologyID: "hosts",
	}
}
<|endoftext|>