<commit_before>package mpb

import (
	"container/heap"
	"io"
	"os"
	"sync"
	"time"

	"github.com/vbauerster/mpb/cwriter"
)

const (
	// default RefreshRate
	prr = 120 * time.Millisecond
	// default width
	pwidth = 80
	// default format
	pformat = "[=>-]"
)

// Progress represents the container that renders Progress bars
type Progress struct {
	operateState chan func(*pState)
	done         chan struct{}
}

type (
	// progress state, which may contain several bars
	pState struct {
		bHeap       *priorityQueue
		heapUpdated bool
		zeroWait    bool
		idCounter   int
		width       int
		format      string
		rr          time.Duration
		cw          *cwriter.Writer
		ticker      *time.Ticker

		// following are provided by user
		uwg              *sync.WaitGroup
		cancel           <-chan struct{}
		shutdownNotifier chan struct{}
		interceptors     []func(io.Writer)
	}
	widthSyncer struct {
		// Public for easy testing
		Accumulator []chan int
		Distributor []chan int
	}
	barRendering struct {
		bar   *Bar
		ready <-chan *renderedReader
	}
)

// New creates new Progress instance, which orchestrates bars rendering process.
// Accepts mpb.ProgressOption funcs for customization.
func New(options ...ProgressOption) *Progress {
	pq := make(priorityQueue, 0)
	heap.Init(&pq)
	s := &pState{
		bHeap:  &pq,
		width:  pwidth,
		format: pformat,
		cw:     cwriter.New(os.Stdout),
		rr:     prr,
		ticker: time.NewTicker(prr),
	}

	for _, opt := range options {
		opt(s)
	}

	p := &Progress{
		operateState: make(chan func(*pState)),
		done:         make(chan struct{}),
	}
	go p.serve(s)
	return p
}

// AddBar creates a new progress bar and adds to the container.
func (p *Progress) AddBar(total int64, options ...BarOption) *Bar {
	result := make(chan *Bar, 1)
	select {
	case p.operateState <- func(s *pState) {
		options = append(options, barWidth(s.width), barFormat(s.format))
		b := newBar(s.idCounter, total, s.cancel, options...)
		heap.Push(s.bHeap, b)
		s.heapUpdated = true
		s.idCounter++
		result <- b
	}:
		return <-result
	case <-p.done:
		// fail early
		return nil
	}
}

// RemoveBar removes the bar at next render cycle
func (p *Progress) RemoveBar(b *Bar) bool {
	return b.askToComplete(true)
}

// UpdateBarPriority provides a way to change bar's order position.
// Zero is highest priority, i.e. bar will be on top.
func (p *Progress) UpdateBarPriority(b *Bar, priority int) {
	select {
	case p.operateState <- func(s *pState) { s.bHeap.update(b, priority) }:
	case <-p.done:
	}
}

// BarCount returns bars count
func (p *Progress) BarCount() int {
	result := make(chan int, 1)
	select {
	case p.operateState <- func(s *pState) { result <- s.bHeap.Len() }:
		return <-result
	case <-p.done:
		return 0
	}
}

// Wait first waits for all bars to complete, then waits for user provided WaitGroup, if any.
// It's optional to call, in other words if you don't call Progress.Wait(),
// it's not guaranteed that all bars will be flushed completely to the underlying io.Writer.
func (p *Progress) Wait() {
	if p.BarCount() == 0 {
		select {
		case p.operateState <- func(s *pState) { s.zeroWait = true }:
		case <-p.done:
		}
		return
	}
	<-p.done
}

func newWidthSyncer(timeout <-chan struct{}, numBars, numColumn int) *widthSyncer {
	ws := &widthSyncer{
		Accumulator: make([]chan int, numColumn),
		Distributor: make([]chan int, numColumn),
	}
	for i := 0; i < numColumn; i++ {
		ws.Accumulator[i] = make(chan int, numBars)
		ws.Distributor[i] = make(chan int, numBars)
	}
	for i := 0; i < numColumn; i++ {
		go func(accumulator <-chan int, distributor chan<- int) {
			defer close(distributor)
			widths := make([]int, 0, numBars)
		loop:
			for {
				select {
				case w := <-accumulator:
					widths = append(widths, w)
					if len(widths) == numBars {
						break loop
					}
				case <-timeout:
					if len(widths) == 0 {
						return
					}
					break loop
				}
			}
			maxWidth := calcMax(widths)
			for i := 0; i < len(widths); i++ {
				distributor <- maxWidth
			}
		}(ws.Accumulator[i], ws.Distributor[i])
	}
	return ws
}

func (s *pState) writeAndFlush(tw, numP, numA int) (err error) {
	timeout := make(chan struct{})
	pSyncer := newWidthSyncer(timeout, s.bHeap.Len(), numP)
	aSyncer := newWidthSyncer(timeout, s.bHeap.Len(), numA)
	time.AfterFunc(s.rr-s.rr/12, func() {
		close(timeout)
	})

	for _, br := range s.renderByPriority(tw, pSyncer, aSyncer) {
		r := <-br.ready
		_, err = s.cw.ReadFrom(r)
		if !br.bar.completed && r.toComplete {
			close(br.bar.shutdown)
			br.bar.completed = true
		}
		if r.toRemove {
			s.heapUpdated = heap.Remove(s.bHeap, br.bar.index) != nil
		}
	}

	for _, interceptor := range s.interceptors {
		interceptor(s.cw)
	}

	if e := s.cw.Flush(); err == nil {
		err = e
	}
	return
}

func (s *pState) renderByPriority(tw int, pSyncer, aSyncer *widthSyncer) []*barRendering {
	slice := make([]*barRendering, 0, s.bHeap.Len())
	for s.bHeap.Len() > 0 {
		b := heap.Pop(s.bHeap).(*Bar)
		defer heap.Push(s.bHeap, b)
		slice = append(slice, &barRendering{
			bar:   b,
			ready: b.render(tw, pSyncer, aSyncer),
		})
	}
	return slice
}

func (s *pState) waitAll() {
	for s.bHeap.Len() > 0 {
		b := heap.Pop(s.bHeap).(*Bar)
		<-b.done
	}
	if s.uwg != nil {
		s.uwg.Wait()
	}
}

func calcMax(slice []int) int {
	if len(slice) == 0 {
		return 0
	}

	max := slice[0]
	for i := 1; i < len(slice); i++ {
		if slice[i] > max {
			max = slice[i]
		}
	}
	return max
}
<commit_msg>Fix #18<commit_after>package mpb

import (
	"container/heap"
	"io"
	"os"
	"sync"
	"time"

	"github.com/vbauerster/mpb/cwriter"
)

const (
	// default RefreshRate
	prr = 120 * time.Millisecond
	// default width
	pwidth = 80
	// default format
	pformat = "[=>-]"
)

// Progress represents the container that renders Progress bars
type Progress struct {
	operateState chan func(*pState)
	done         chan struct{}
}

type (
	// progress state, which may contain several bars
	pState struct {
		bHeap       *priorityQueue
		heapUpdated bool
		zeroWait    bool
		idCounter   int
		width       int
		format      string
		rr          time.Duration
		cw          *cwriter.Writer
		ticker      *time.Ticker

		// following are provided by user
		uwg              *sync.WaitGroup
		cancel           <-chan struct{}
		shutdownNotifier chan struct{}
		interceptors     []func(io.Writer)
	}
	widthSyncer struct {
		// Public for easy testing
		Accumulator []chan int
		Distributor []chan int
	}
	barRendering struct {
		bar   *Bar
		ready <-chan *renderedReader
	}
)

// New creates new Progress instance, which orchestrates bars rendering process.
// Accepts mpb.ProgressOption funcs for customization.
func New(options ...ProgressOption) *Progress {
	pq := make(priorityQueue, 0)
	heap.Init(&pq)
	s := &pState{
		bHeap:  &pq,
		width:  pwidth,
		format: pformat,
		cw:     cwriter.New(os.Stdout),
		rr:     prr,
		ticker: time.NewTicker(prr),
	}

	for _, opt := range options {
		opt(s)
	}

	p := &Progress{
		operateState: make(chan func(*pState)),
		done:         make(chan struct{}),
	}
	go p.serve(s)
	return p
}

// AddBar creates a new progress bar and adds to the container.
func (p *Progress) AddBar(total int64, options ...BarOption) *Bar {
	result := make(chan *Bar, 1)
	select {
	case p.operateState <- func(s *pState) {
		options = append(options, barWidth(s.width), barFormat(s.format))
		b := newBar(s.idCounter, total, s.cancel, options...)
		heap.Push(s.bHeap, b)
		s.heapUpdated = true
		s.idCounter++
		result <- b
	}:
		return <-result
	case <-p.done:
		// fail early
		return nil
	}
}

// RemoveBar removes the bar at next render cycle
func (p *Progress) RemoveBar(b *Bar) bool {
	result := b.askToComplete(true)
	<-b.done
	return result
}

// UpdateBarPriority provides a way to change bar's order position.
// Zero is highest priority, i.e. bar will be on top.
func (p *Progress) UpdateBarPriority(b *Bar, priority int) {
	select {
	case p.operateState <- func(s *pState) { s.bHeap.update(b, priority) }:
	case <-p.done:
	}
}

// BarCount returns bars count
func (p *Progress) BarCount() int {
	result := make(chan int, 1)
	select {
	case p.operateState <- func(s *pState) { result <- s.bHeap.Len() }:
		return <-result
	case <-p.done:
		return 0
	}
}

// Wait first waits for all bars to complete, then waits for user provided WaitGroup, if any.
// It's optional to call, in other words if you don't call Progress.Wait(),
// it's not guaranteed that all bars will be flushed completely to the underlying io.Writer.
func (p *Progress) Wait() {
	if p.BarCount() == 0 {
		select {
		case p.operateState <- func(s *pState) { s.zeroWait = true }:
		case <-p.done:
		}
		return
	}
	<-p.done
}

func newWidthSyncer(timeout <-chan struct{}, numBars, numColumn int) *widthSyncer {
	ws := &widthSyncer{
		Accumulator: make([]chan int, numColumn),
		Distributor: make([]chan int, numColumn),
	}
	for i := 0; i < numColumn; i++ {
		ws.Accumulator[i] = make(chan int, numBars)
		ws.Distributor[i] = make(chan int, numBars)
	}
	for i := 0; i < numColumn; i++ {
		go func(accumulator <-chan int, distributor chan<- int) {
			defer close(distributor)
			widths := make([]int, 0, numBars)
		loop:
			for {
				select {
				case w := <-accumulator:
					widths = append(widths, w)
					if len(widths) == numBars {
						break loop
					}
				case <-timeout:
					if len(widths) == 0 {
						return
					}
					break loop
				}
			}
			maxWidth := calcMax(widths)
			for i := 0; i < len(widths); i++ {
				distributor <- maxWidth
			}
		}(ws.Accumulator[i], ws.Distributor[i])
	}
	return ws
}

func (s *pState) writeAndFlush(tw, numP, numA int) (err error) {
	timeout := make(chan struct{})
	pSyncer := newWidthSyncer(timeout, s.bHeap.Len(), numP)
	aSyncer := newWidthSyncer(timeout, s.bHeap.Len(), numA)
	time.AfterFunc(s.rr-s.rr/12, func() {
		close(timeout)
	})

	for _, br := range s.renderByPriority(tw, pSyncer, aSyncer) {
		r := <-br.ready
		if !r.toRemove {
			_, err = s.cw.ReadFrom(r)
		} else {
			s.heapUpdated = heap.Remove(s.bHeap, br.bar.index) != nil
		}
		if !br.bar.completed && r.toComplete {
			br.bar.completed = true
			defer close(br.bar.shutdown)
		}
	}

	for _, interceptor := range s.interceptors {
		interceptor(s.cw)
	}

	if e := s.cw.Flush(); err == nil {
		err = e
	}
	return
}

func (s *pState) renderByPriority(tw int, pSyncer, aSyncer *widthSyncer) []*barRendering {
	slice := make([]*barRendering, 0, s.bHeap.Len())
	for s.bHeap.Len() > 0 {
		b := heap.Pop(s.bHeap).(*Bar)
		defer heap.Push(s.bHeap, b)
		slice = append(slice, &barRendering{
			bar:   b,
			ready: b.render(tw, pSyncer, aSyncer),
		})
	}
	return slice
}

func (s *pState) waitAll() {
	for s.bHeap.Len() > 0 {
		b := heap.Pop(s.bHeap).(*Bar)
		<-b.done
	}
	if s.uwg != nil {
		s.uwg.Wait()
	}
}

func calcMax(slice []int) int {
	if len(slice) == 0 {
		return 0
	}

	max := slice[0]
	for i := 1; i < len(slice); i++ {
		if slice[i] > max {
			max = slice[i]
		}
	}
	return max
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"syscall"
	"time"
)

/* No way to teach net or syscall about vsock sockaddr, so go right to C */

/*
#include <sys/socket.h>
#include "include/uapi/linux/vm_sockets.h"
int bind_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return bind(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int connect_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return connect(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int accept_vm(int fd, struct sockaddr_vm *sa_vm, socklen_t *sa_vm_len) {
    return accept4(fd, (struct sockaddr *)sa_vm, sa_vm_len, 0);
}
*/
import "C"

const (
	AF_VSOCK            = 40
	VSOCK_CID_ANY       = 4294967295 /* 2^32-1 */
)

var (
	port   uint
	sock   string
	detach bool
)

func init() {
	flag.UintVar(&port, "port", 2376, "vsock port to forward")
	flag.StringVar(&sock, "sock", "/var/run/docker.sock", "path of the local Unix domain socket to forward to")
	flag.BoolVar(&detach, "detach", false, "detach from terminal")
}

func main() {
	log.SetFlags(log.LstdFlags)
	flag.Parse()

	if detach {
		logFile, err := os.Create("/var/log/vsudd.log")
		if err != nil {
			log.Fatalln("Failed to open log file", err)
		}
		log.SetOutput(logFile)
		null, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
		if err != nil {
			log.Fatalln("Failed to open /dev/null", err)
		}
		fd := null.Fd()
		syscall.Dup2(int(fd), int(os.Stdin.Fd()))
		syscall.Dup2(int(fd), int(os.Stdout.Fd()))
		syscall.Dup2(int(fd), int(os.Stderr.Fd()))
	}

	accept_fd, err := syscall.Socket(AF_VSOCK, syscall.SOCK_STREAM, 0)
	if err != nil {
		log.Fatal(err)
	}

	sa := C.struct_sockaddr_vm{}
	sa.svm_family = AF_VSOCK
	sa.svm_port = C.uint(port)
	sa.svm_cid = 3

	if ret := C.bind_sockaddr_vm(C.int(accept_fd), &sa); ret != 0 {
		log.Fatal(fmt.Sprintf("failed bind vsock connection to %08x.%08x, returned %d", sa.svm_cid, sa.svm_port, ret))
	}

	err = syscall.Listen(accept_fd, syscall.SOMAXCONN)
	if err != nil {
		log.Fatalln("Failed to listen to VSOCK", err)
	}

	log.Printf("Listening on fd %d", accept_fd)

	connid := 0

	for {
		var accept_sa C.struct_sockaddr_vm
		var accept_sa_len C.socklen_t

		connid++
		accept_sa_len = C.sizeof_struct_sockaddr_vm
		fd, err := C.accept_vm(C.int(accept_fd), &accept_sa, &accept_sa_len)
		if err != nil {
			log.Fatalln("Error accepting connection", err)
		}
		go handleOne(connid, int(fd), uint(accept_sa.svm_cid), uint(accept_sa.svm_port))
	}
}

func handleOne(connid int, fd int, cid, port uint) {
	vsock := os.NewFile(uintptr(fd), fmt.Sprintf("vsock:%d", fd))
	log.Printf("%d Accepted connection on fd %d from %08x.%08x", connid, fd, cid, port)

	defer syscall.Close(fd)

	var docker *net.UnixConn
	var err error

	// Cope with the server socket appearing up to 10s later
	for i := 0; i < 200; i++ {
		docker, err = net.DialUnix("unix", nil, &net.UnixAddr{sock, "unix"})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	defer docker.Close()

	if err != nil {
		// If the forwarding program has broken then close and continue
		log.Println(connid, "Failed to connect to Unix domain socket after 10s", sock, err)
		return
	}

	w := make(chan int64)
	go func() {
		n, err := io.Copy(vsock, docker)
		if err != nil {
			log.Println(connid, "error copying from docker to vsock:", err)
		}
		log.Println(connid, "copying from docker to vsock: ", n, "bytes done")

		err = docker.CloseRead()
		if err != nil {
			log.Println(connid, "error CloseRead on docker socket:", err)
		}
		err = syscall.Shutdown(fd, syscall.SHUT_WR)
		if err != nil {
			log.Println(connid, "error SHUT_WR on vsock:", err)
		}
		w <- n
	}()

	n, err := io.Copy(docker, vsock)
	if err != nil {
		log.Println(connid, "error copying from vsock to docker:", err)
	}
	log.Println(connid, "copying from vsock to docker: ", n, "bytes done")
	totalRead := n

	err = docker.CloseWrite()
	if err != nil {
		log.Println(connid, "error CloseWrite on docker socket:", err)
	}
	err = syscall.Shutdown(fd, syscall.SHUT_RD)
	if err != nil {
		log.Println(connid, "error SHUT_RD on vsock:", err)
	}

	totalWritten := <-w
	log.Println(connid, "Done. read:", totalRead, "written:", totalWritten)
}
<commit_msg>vsudd: Bind to VSOCK_CID_ANY rather than "3"<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"syscall"
	"time"
)

/* No way to teach net or syscall about vsock sockaddr, so go right to C */

/*
#include <sys/socket.h>
#include "include/uapi/linux/vm_sockets.h"
int bind_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return bind(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int connect_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return connect(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int accept_vm(int fd, struct sockaddr_vm *sa_vm, socklen_t *sa_vm_len) {
    return accept4(fd, (struct sockaddr *)sa_vm, sa_vm_len, 0);
}
*/
import "C"

const (
	AF_VSOCK            = 40
	VSOCK_CID_ANY       = 4294967295 /* 2^32-1 */
)

var (
	port   uint
	sock   string
	detach bool
)

func init() {
	flag.UintVar(&port, "port", 2376, "vsock port to forward")
	flag.StringVar(&sock, "sock", "/var/run/docker.sock", "path of the local Unix domain socket to forward to")
	flag.BoolVar(&detach, "detach", false, "detach from terminal")
}

func main() {
	log.SetFlags(log.LstdFlags)
	flag.Parse()

	if detach {
		logFile, err := os.Create("/var/log/vsudd.log")
		if err != nil {
			log.Fatalln("Failed to open log file", err)
		}
		log.SetOutput(logFile)
		null, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
		if err != nil {
			log.Fatalln("Failed to open /dev/null", err)
		}
		fd := null.Fd()
		syscall.Dup2(int(fd), int(os.Stdin.Fd()))
		syscall.Dup2(int(fd), int(os.Stdout.Fd()))
		syscall.Dup2(int(fd), int(os.Stderr.Fd()))
	}

	accept_fd, err := syscall.Socket(AF_VSOCK, syscall.SOCK_STREAM, 0)
	if err != nil {
		log.Fatal(err)
	}

	sa := C.struct_sockaddr_vm{}
	sa.svm_family = AF_VSOCK
	sa.svm_port = C.uint(port)
	sa.svm_cid = VSOCK_CID_ANY

	if ret := C.bind_sockaddr_vm(C.int(accept_fd), &sa); ret != 0 {
		log.Fatal(fmt.Sprintf("failed bind vsock connection to %08x.%08x, returned %d", sa.svm_cid, sa.svm_port, ret))
	}

	err = syscall.Listen(accept_fd, syscall.SOMAXCONN)
	if err != nil {
		log.Fatalln("Failed to listen to VSOCK", err)
	}

	log.Printf("Listening on fd %d", accept_fd)

	connid := 0

	for {
		var accept_sa C.struct_sockaddr_vm
		var accept_sa_len C.socklen_t

		connid++
		accept_sa_len = C.sizeof_struct_sockaddr_vm
		fd, err := C.accept_vm(C.int(accept_fd), &accept_sa, &accept_sa_len)
		if err != nil {
			log.Fatalln("Error accepting connection", err)
		}
		go handleOne(connid, int(fd), uint(accept_sa.svm_cid), uint(accept_sa.svm_port))
	}
}

func handleOne(connid int, fd int, cid, port uint) {
	vsock := os.NewFile(uintptr(fd), fmt.Sprintf("vsock:%d", fd))
	log.Printf("%d Accepted connection on fd %d from %08x.%08x", connid, fd, cid, port)

	defer syscall.Close(fd)

	var docker *net.UnixConn
	var err error

	// Cope with the server socket appearing up to 10s later
	for i := 0; i < 200; i++ {
		docker, err = net.DialUnix("unix", nil, &net.UnixAddr{sock, "unix"})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	defer docker.Close()

	if err != nil {
		// If the forwarding program has broken then close and continue
		log.Println(connid, "Failed to connect to Unix domain socket after 10s", sock, err)
		return
	}

	w := make(chan int64)
	go func() {
		n, err := io.Copy(vsock, docker)
		if err != nil {
			log.Println(connid, "error copying from docker to vsock:", err)
		}
		log.Println(connid, "copying from docker to vsock: ", n, "bytes done")

		err = docker.CloseRead()
		if err != nil {
			log.Println(connid, "error CloseRead on docker socket:", err)
		}
		err = syscall.Shutdown(fd, syscall.SHUT_WR)
		if err != nil {
			log.Println(connid, "error SHUT_WR on vsock:", err)
		}
		w <- n
	}()

	n, err := io.Copy(docker, vsock)
	if err != nil {
		log.Println(connid, "error copying from vsock to docker:", err)
	}
	log.Println(connid, "copying from vsock to docker: ", n, "bytes done")
	totalRead := n

	err = docker.CloseWrite()
	if err != nil {
		log.Println(connid, "error CloseWrite on docker socket:", err)
	}
	err = syscall.Shutdown(fd, syscall.SHUT_RD)
	if err != nil {
		log.Println(connid, "error SHUT_RD on vsock:", err)
	}

	totalWritten := <-w
	log.Println(connid, "Done. read:", totalRead, "written:", totalWritten)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"syscall"
	"time"
)

/* No way to teach net or syscall about vsock sockaddr, so go right to C */

/*
#include <sys/socket.h>
#include "include/uapi/linux/vm_sockets.h"
int bind_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return bind(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int connect_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return connect(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int accept_vm(int fd) {
    return accept(fd, 0, 0);
}
*/
import "C"

const (
	AF_VSOCK            = 40
	VSOCK_CID_ANY       = 4294967295 /* 2^32-1 */
)

var (
	port   uint
	sock   string
	detach bool
)

func init() {
	flag.UintVar(&port, "port", 2376, "vsock port to forward")
	flag.StringVar(&sock, "sock", "/var/run/docker.sock", "path of the local Unix domain socket to forward to")
	flag.BoolVar(&detach, "detach", false, "detach from terminal")
}

func main() {
	log.SetFlags(log.LstdFlags)
	flag.Parse()

	if detach {
		logFile, err := os.Create("/var/log/vsudd.log")
		if err != nil {
			log.Fatalln("Failed to open log file", err)
		}
		log.SetOutput(logFile)
		null, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
		if err != nil {
			log.Fatalln("Failed to open /dev/null", err)
		}
		fd := null.Fd()
		syscall.Dup2(int(fd), int(os.Stdin.Fd()))
		syscall.Dup2(int(fd), int(os.Stdout.Fd()))
		syscall.Dup2(int(fd), int(os.Stderr.Fd()))
	}

	accept_fd, err := syscall.Socket(AF_VSOCK, syscall.SOCK_STREAM, 0)
	if err != nil {
		log.Fatal(err)
	}

	sa := C.struct_sockaddr_vm{}
	sa.svm_family = AF_VSOCK
	sa.svm_port = C.uint(port)
	sa.svm_cid = 3

	if ret := C.bind_sockaddr_vm(C.int(accept_fd), &sa); ret != 0 {
		log.Fatal(fmt.Sprintf("failed bind vsock connection to %08x.%08x, returned %d", sa.svm_cid, sa.svm_port, ret))
	}

	err = syscall.Listen(accept_fd, syscall.SOMAXCONN)
	if err != nil {
		log.Fatalln("Failed to listen to VSOCK", err)
	}

	log.Printf("Listening on fd %d", accept_fd)

	connid := 0

	for {
		connid++
		fd, err := C.accept_vm(C.int(accept_fd))
		if err != nil {
			log.Fatalln("Error accepting connection", err)
		}
		go handleOne(connid, int(fd))
	}
}

func handleOne(connid int, fd int) {
	vsock := os.NewFile(uintptr(fd), fmt.Sprintf("vsock:%d", fd))
	log.Println(connid, "Accepted connection on fd", fd)

	defer syscall.Close(fd)

	var docker *net.UnixConn
	var err error

	// Cope with the server socket appearing up to 10s later
	for i := 0; i < 200; i++ {
		docker, err = net.DialUnix("unix", nil, &net.UnixAddr{sock, "unix"})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	defer docker.Close()

	if err != nil {
		// If the forwarding program has broken then close and continue
		log.Println(connid, "Failed to connect to Unix domain socket after 10s", sock, err)
		return
	}

	w := make(chan int64)
	go func() {
		n, err := io.Copy(vsock, docker)
		if err != nil {
			log.Println(connid, "error copying from docker to vsock:", err)
		}
		log.Println(connid, "copying from docker to vsock: ", n, "bytes done")

		err = docker.CloseRead()
		if err != nil {
			log.Println(connid, "error CloseRead on docker socket:", err)
		}
		err = syscall.Shutdown(fd, syscall.SHUT_WR)
		if err != nil {
			log.Println(connid, "error SHUT_WR on vsock:", err)
		}
		w <- n
	}()

	n, err := io.Copy(docker, vsock)
	if err != nil {
		log.Println(connid, "error copying from vsock to docker:", err)
	}
	log.Println(connid, "copying from vsock to docker: ", n, "bytes done")
	totalRead := n

	err = docker.CloseWrite()
	if err != nil {
		log.Println(connid, "error CloseWrite on docker socket:", err)
	}
	err = syscall.Shutdown(fd, syscall.SHUT_RD)
	if err != nil {
		log.Println(connid, "error SHUT_RD on vsock:", err)
	}

	totalWritten := <-w
	log.Println(connid, "Done. read:", totalRead, "written:", totalWritten)
}
<commit_msg>vsudd: Log the peer's port number<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"syscall"
	"time"
)

/* No way to teach net or syscall about vsock sockaddr, so go right to C */

/*
#include <sys/socket.h>
#include "include/uapi/linux/vm_sockets.h"
int bind_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return bind(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int connect_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) {
    return connect(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm));
}
int accept_vm(int fd, struct sockaddr_vm *sa_vm, socklen_t *sa_vm_len) {
    return accept4(fd, (struct sockaddr *)sa_vm, sa_vm_len, 0);
}
*/
import "C"

const (
	AF_VSOCK            = 40
	VSOCK_CID_ANY       = 4294967295 /* 2^32-1 */
)

var (
	port   uint
	sock   string
	detach bool
)

func init() {
	flag.UintVar(&port, "port", 2376, "vsock port to forward")
	flag.StringVar(&sock, "sock", "/var/run/docker.sock", "path of the local Unix domain socket to forward to")
	flag.BoolVar(&detach, "detach", false, "detach from terminal")
}

func main() {
	log.SetFlags(log.LstdFlags)
	flag.Parse()

	if detach {
		logFile, err := os.Create("/var/log/vsudd.log")
		if err != nil {
			log.Fatalln("Failed to open log file", err)
		}
		log.SetOutput(logFile)
		null, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
		if err != nil {
			log.Fatalln("Failed to open /dev/null", err)
		}
		fd := null.Fd()
		syscall.Dup2(int(fd), int(os.Stdin.Fd()))
		syscall.Dup2(int(fd), int(os.Stdout.Fd()))
		syscall.Dup2(int(fd), int(os.Stderr.Fd()))
	}

	accept_fd, err := syscall.Socket(AF_VSOCK, syscall.SOCK_STREAM, 0)
	if err != nil {
		log.Fatal(err)
	}

	sa := C.struct_sockaddr_vm{}
	sa.svm_family = AF_VSOCK
	sa.svm_port = C.uint(port)
	sa.svm_cid = 3

	if ret := C.bind_sockaddr_vm(C.int(accept_fd), &sa); ret != 0 {
		log.Fatal(fmt.Sprintf("failed bind vsock connection to %08x.%08x, returned %d", sa.svm_cid, sa.svm_port, ret))
	}

	err = syscall.Listen(accept_fd, syscall.SOMAXCONN)
	if err != nil {
		log.Fatalln("Failed to listen to VSOCK", err)
	}

	log.Printf("Listening on fd %d", accept_fd)

	connid := 0

	for {
		var accept_sa C.struct_sockaddr_vm
		var accept_sa_len C.socklen_t

		connid++
		accept_sa_len = C.sizeof_struct_sockaddr_vm
		fd, err := C.accept_vm(C.int(accept_fd), &accept_sa, &accept_sa_len)
		if err != nil {
			log.Fatalln("Error accepting connection", err)
		}
		go handleOne(connid, int(fd), uint(accept_sa.svm_cid), uint(accept_sa.svm_port))
	}
}

func handleOne(connid int, fd int, cid, port uint) {
	vsock := os.NewFile(uintptr(fd), fmt.Sprintf("vsock:%d", fd))
	log.Printf("%d Accepted connection on fd %d from %08x.%08x", connid, fd, cid, port)

	defer syscall.Close(fd)

	var docker *net.UnixConn
	var err error

	// Cope with the server socket appearing up to 10s later
	for i := 0; i < 200; i++ {
		docker, err = net.DialUnix("unix", nil, &net.UnixAddr{sock, "unix"})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	defer docker.Close()

	if err != nil {
		// If the forwarding program has broken then close and continue
		log.Println(connid, "Failed to connect to Unix domain socket after 10s", sock, err)
		return
	}

	w := make(chan int64)
	go func() {
		n, err := io.Copy(vsock, docker)
		if err != nil {
			log.Println(connid, "error copying from docker to vsock:", err)
		}
		log.Println(connid, "copying from docker to vsock: ", n, "bytes done")

		err = docker.CloseRead()
		if err != nil {
			log.Println(connid, "error CloseRead on docker socket:", err)
		}
		err = syscall.Shutdown(fd, syscall.SHUT_WR)
		if err != nil {
			log.Println(connid, "error SHUT_WR on vsock:", err)
		}
		w <- n
	}()

	n, err := io.Copy(docker, vsock)
	if err != nil {
		log.Println(connid, "error copying from vsock to docker:", err)
	}
	log.Println(connid, "copying from vsock to docker: ", n, "bytes done")
	totalRead := n

	err = docker.CloseWrite()
	if err != nil {
		log.Println(connid, "error CloseWrite on docker socket:", err)
	}
	err = syscall.Shutdown(fd, syscall.SHUT_RD)
	if err != nil {
		log.Println(connid, "error SHUT_RD on vsock:", err)
	}

	totalWritten := <-w
	log.Println(connid, "Done. read:", totalRead, "written:", totalWritten)
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "strings"
    "strconv"
    "github.com/PuerkitoBio/goquery"
)

// Build course properties
func (this *Course) GetProperties() *Course {
    log.Print("--------------------- FIRED")
    course := GetDocument(this.url)
    key_facts := course.Find("#keyFacts-Content p")

    this.department = strings.TrimPrefix(key_facts.First().Text(), "Department: ")
    this.students, _ = strconv.Atoi(strings.Split(key_facts.Eq(1).Text(), ": ")[1])
    this.class, _ = strconv.Atoi(strings.Split(key_facts.Eq(2).Text(), ": ")[1])

    if strings.Split(key_facts.Eq(3).Text(), " ")[1] == "Half" {
        this.value = 0.5
    } else {
        this.value = 1
    }

    teachers := strings.Replace(course.Find("#teacherResponsible-Content p").First().Text(), " and", ",", -1)
    this.teachers = strings.Split(teachers, ", ")

    this.availability = FormatProperty(course.Find("#availability-Content p"))
    this.content = FormatProperty(course.Find("#courseContent-Content p"))
    this.teaching = FormatProperty(course.Find("#teaching-Content p"))
    this.formative = FormatProperty(course.Find("#formativeCoursework-Content p"))
    this.readings = FormatProperty(course.Find("#indicativeReading-Content p"))
    this.assessments = FormatProperty(course.Find("#assessment-Content p"))

    return this
}

func FormatProperty(sel *goquery.Selection) string {
    noHTML := strings.Join(sel.Map(func(i int, s *goquery.Selection) string {
        return s.Text()
    }), "\n")
    return strings.TrimSpace(noHTML)
}

// Getters
func (this *Course) Code() string {
    return this.code
}

func (this *Course) Title() string {
    return this.title
}

func (this *Course) URL() string {
    return this.url
}

func (this *Course) Department() string {
    if this.department == "" {
        this.GetProperties()
    }
    return this.department
}

func (this *Course) Students() int {
    if this.students == 0 {
        this.GetProperties()
    }
    return this.students
}

func (this *Course) Class() int {
    if this.class == 0 {
        this.GetProperties()
    }
    return this.class
}

func (this *Course) Value() float32 {
    if this.value == 0 {
        this.GetProperties()
    }
    return this.value
}

func (this *Course) Teachers() []string {
    if len(this.teachers) == 0 {
        this.GetProperties()
    }
    return this.teachers
}

func (this *Course) Availability() string {
    if this.availability == "" {
        this.GetProperties()
    }
    return this.availability
}

func (this *Course) Content() string {
    if this.content == "" {
        this.GetProperties()
    }
    return this.content
}

func (this *Course) Teaching() string {
    if this.teaching == "" {
        this.GetProperties()
    }
    return this.teaching
}

func (this *Course) Formative() string {
    if this.formative == "" {
        this.GetProperties()
    }
    return this.formative
}

func (this *Course) Readings() string {
    if this.readings == "" {
        this.GetProperties()
    }
    return this.readings
}

func (this *Course) Assessments() string {
    if this.assessments == "" {
        this.GetProperties()
    }
    return this.assessments
}

func (this *Course) Program() int {
    return this.program
}<commit_msg>Removed getters (redundant) and updated struct fields<commit_after>package main

import (
    "strings"
    "strconv"
    "github.com/PuerkitoBio/goquery"
)

// Build course properties
func (this *Course) GetProperties() *Course {
    course := GetDocument(this.URL)
    key_facts := course.Find("#keyFacts-Content p")

    this.Department = strings.TrimPrefix(key_facts.First().Text(), "Department: ")
    this.Students, _ = strconv.Atoi(strings.Split(key_facts.Eq(1).Text(), ": ")[1])
    this.Class, _ = strconv.Atoi(strings.Split(key_facts.Eq(2).Text(), ": ")[1])

    if strings.Split(key_facts.Eq(3).Text(), " ")[1] == "Half" {
        this.Value = 0.5
    } else {
        this.Value = 1
    }

    teachers := strings.Replace(course.Find("#teacherResponsible-Content p").First().Text(), " and", ",", -1)
    this.Teachers = strings.Split(teachers, ", ")

    this.Availability = FormatProperty(course.Find("#availability-Content p"))
    this.Content = FormatProperty(course.Find("#courseContent-Content p"))
    this.Teaching = FormatProperty(course.Find("#teaching-Content p"))
    this.Formative = FormatProperty(course.Find("#formativeCoursework-Content p"))
    this.Readings = FormatProperty(course.Find("#indicativeReading-Content p"))
    this.Assessments = FormatProperty(course.Find("#assessment-Content p"))

    return this
}

func FormatProperty(sel *goquery.Selection) string {
    noHTML := strings.Join(sel.Map(func(i int, s *goquery.Selection) string {
        return s.Text()
    }), "\n")
    return strings.TrimSpace(noHTML)
}<|endoftext|>


<commit_before>package repository

import (
	"context"
	"fmt"

	"github.com/fabric8-services/fabric8-wit/errors"

	"github.com/jinzhu/gorm"
	errs "github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

type Exister interface {
	// Exists returns nil if the object with the given ID exists; otherwise an
	// error is returned in case the given ID doesn't exists or any other
	// unknown issue occured
	CheckExists(ctx context.Context, id uuid.UUID) error
}

// Exists returns true if an item exists in the database table with a given ID
func Exists(ctx context.Context, db *gorm.DB, tableName string, id string) (bool, error) {
	var exists bool
	query := fmt.Sprintf(`
		SELECT EXISTS (
			SELECT 1 FROM %[1]s
			WHERE
				id=$1
				AND deleted_at IS NULL
		)`, tableName)

	err := db.CommonDB().QueryRow(query, id).Scan(&exists)
	if err == nil && !exists {
		return exists, errors.NewNotFoundError(tableName, id)
	}
	if err != nil {
		return false, errors.NewInternalError(ctx, errs.Wrapf(err, "unable to verify if %s exists", tableName))
	}
	return exists, nil
}

// CheckExists does the same as Exists but only returns the error value; thereby
// being a handy convenience function.
func CheckExists(ctx context.Context, db *gorm.DB, tableName string, id uuid.UUID) error {
	_, err := Exists(ctx, db, tableName, id.String())
	return err
}
<commit_msg>Fix comment on repository.Exister.CheckExists (#1983)<commit_after>package repository

import (
	"context"
	"fmt"

	"github.com/fabric8-services/fabric8-wit/errors"

	"github.com/jinzhu/gorm"
	errs "github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

type Exister interface {
	// CheckExists returns nil if the object with the given ID exists; otherwise an
	// error is returned in case the given ID doesn't exists or any other
	// unknown issue occured
	CheckExists(ctx context.Context, id uuid.UUID) error
}

// Exists returns true if an item exists in the database table with a given ID
func Exists(ctx context.Context, db *gorm.DB, tableName string, id string) (bool, error) {
	var exists bool
	query := fmt.Sprintf(`
		SELECT EXISTS (
			SELECT 1 FROM %[1]s
			WHERE
				id=$1
				AND deleted_at IS NULL
		)`, tableName)

	err := db.CommonDB().QueryRow(query, id).Scan(&exists)
	if err == nil && !exists {
		return exists, errors.NewNotFoundError(tableName, id)
	}
	if err != nil {
		return false, errors.NewInternalError(ctx, errs.Wrapf(err, "unable to verify if %s exists", tableName))
	}
	return exists, nil
}

// CheckExists does the same as Exists but only returns the error value; thereby
// being a handy convenience function.
func CheckExists(ctx context.Context, db *gorm.DB, tableName string, id uuid.UUID) error {
	_, err := Exists(ctx, db, tableName, id.String())
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2020 Gravitational, Inc.

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

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

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

package types

import (
	"fmt"
	"time"

	"github.com/gravitational/trace"
)

// UserTokenSecrets contains user token secrets.
type UserTokenSecrets interface {
	// Resource provides common resource properties
	Resource
	// GetCreated returns Created
	GetCreated() time.Time
	// SetCreated sets Created
	SetCreated(time.Time)
	// GetQRCode returns QRCode
	GetQRCode() []byte
	// SetQRCode sets QRCode
	SetQRCode([]byte)
	// GetOTPKey returns OTP key
	GetOTPKey() string
	// SetOTPKey sets OTP Key
	SetOTPKey(string)
}

// NewUserTokenSecrets creates an instance of UserTokenSecrets.
func NewUserTokenSecrets(tokenID string) (UserTokenSecrets, error) {
	secrets := UserTokenSecretsV3{
		Metadata: Metadata{
			Name: tokenID,
		},
	}
	if err := secrets.CheckAndSetDefaults(); err != nil {
		return nil, trace.Wrap(err)
	}
	return &secrets, nil
}

// GetName returns Name
func (u *UserTokenSecretsV3) GetName() string {
	return u.Metadata.Name
}

// GetCreated returns Created
func (u *UserTokenSecretsV3) GetCreated() time.Time {
	return u.Spec.Created
}

// SetCreated sets Created
func (u *UserTokenSecretsV3) SetCreated(t time.Time) {
	u.Spec.Created = t
}

// GetOTPKey returns OTP Key
func (u *UserTokenSecretsV3) GetOTPKey() string {
	return u.Spec.OTPKey
}

// SetOTPKey sets OTP Key
func (u *UserTokenSecretsV3) SetOTPKey(key string) {
	u.Spec.OTPKey = key
}

// GetQRCode returns QRCode
func (u *UserTokenSecretsV3) GetQRCode() []byte {
	return []byte(u.Spec.QRCode)
}

// SetQRCode sets QRCode
func (u *UserTokenSecretsV3) SetQRCode(code []byte) {
	u.Spec.QRCode = string(code)
}

// Expiry returns object expiry setting
func (u *UserTokenSecretsV3) Expiry() time.Time {
	return u.Metadata.Expiry()
}

// SetExpiry sets object expiry
func (u *UserTokenSecretsV3) SetExpiry(t time.Time) {
	u.Metadata.SetExpiry(t)
}

// GetMetadata returns object metadata
func (u *UserTokenSecretsV3) GetMetadata() Metadata {
	return u.Metadata
}

// GetVersion returns resource version
func (u *UserTokenSecretsV3) GetVersion() string {
	return u.Version
}

// GetKind returns resource kind
func (u *UserTokenSecretsV3) GetKind() string {
	return u.Kind
}

// SetName sets the name of the resource
func (u *UserTokenSecretsV3) SetName(name string) {
	u.Metadata.Name = name
}

// GetResourceID returns resource ID
func (u *UserTokenSecretsV3) GetResourceID() int64 {
	return u.Metadata.ID
}

// SetResourceID sets resource ID
func (u *UserTokenSecretsV3) SetResourceID(id int64) {
	u.Metadata.ID = id
}

// GetSubKind returns resource sub kind
func (u *UserTokenSecretsV3) GetSubKind() string {
	return u.SubKind
}

// SetSubKind sets resource subkind
func (u *UserTokenSecretsV3) SetSubKind(s string) {
	u.SubKind = s
}

// setStaticFields sets static resource header and metadata fields.
func (u *UserTokenSecretsV3) setStaticFields() {
	u.Kind = KindUserTokenSecrets
	u.Version = V3
}

// CheckAndSetDefaults checks and set default values for any missing fields.
func (u UserTokenSecretsV3) CheckAndSetDefaults() error {
	u.setStaticFields()
	if err := u.Metadata.CheckAndSetDefaults(); err != nil {
		return trace.Wrap(err)
	}
	return nil
}

// String represents a human readable version of the token secrets
func (u *UserTokenSecretsV3) String() string {
	return fmt.Sprintf("UserTokenSecretsV3(tokenID=%v, opt_key=%v, qr_code=%v)", u.GetName(), u.Spec.OTPKey, u.Spec.QRCode)
}
<commit_msg>Fix CheckAndSetDefaults for UserTokenSecretsV3 (#9290)<commit_after>/*
Copyright 2020 Gravitational, Inc.

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

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

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

package types

import (
	"fmt"
	"time"

	"github.com/gravitational/trace"
)

// UserTokenSecrets contains user token secrets.
type UserTokenSecrets interface {
	// Resource provides common resource properties
	Resource
	// GetCreated returns Created
	GetCreated() time.Time
	// SetCreated sets Created
	SetCreated(time.Time)
	// GetQRCode returns QRCode
	GetQRCode() []byte
	// SetQRCode sets QRCode
	SetQRCode([]byte)
	// GetOTPKey returns OTP key
	GetOTPKey() string
	// SetOTPKey sets OTP Key
	SetOTPKey(string)
}

// NewUserTokenSecrets creates an instance of UserTokenSecrets.
func NewUserTokenSecrets(tokenID string) (UserTokenSecrets, error) {
	secrets := UserTokenSecretsV3{
		Metadata: Metadata{
			Name: tokenID,
		},
	}
	if err := secrets.CheckAndSetDefaults(); err != nil {
		return nil, trace.Wrap(err)
	}
	return &secrets, nil
}

// GetName returns Name
func (u *UserTokenSecretsV3) GetName() string {
	return u.Metadata.Name
}

// GetCreated returns Created
func (u *UserTokenSecretsV3) GetCreated() time.Time {
	return u.Spec.Created
}

// SetCreated sets Created
func (u *UserTokenSecretsV3) SetCreated(t time.Time) {
	u.Spec.Created = t
}

// GetOTPKey returns OTP Key
func (u *UserTokenSecretsV3) GetOTPKey() string {
	return u.Spec.OTPKey
}

// SetOTPKey sets OTP Key
func (u *UserTokenSecretsV3) SetOTPKey(key string) {
	u.Spec.OTPKey = key
}

// GetQRCode returns QRCode
func (u *UserTokenSecretsV3) GetQRCode() []byte {
	return []byte(u.Spec.QRCode)
}

// SetQRCode sets QRCode
func (u *UserTokenSecretsV3) SetQRCode(code []byte) {
	u.Spec.QRCode = string(code)
}

// Expiry returns object expiry setting
func (u *UserTokenSecretsV3) Expiry() time.Time {
	return u.Metadata.Expiry()
}

// SetExpiry sets object expiry
func (u *UserTokenSecretsV3) SetExpiry(t time.Time) {
	u.Metadata.SetExpiry(t)
}

// GetMetadata returns object metadata
func (u *UserTokenSecretsV3) GetMetadata() Metadata {
	return u.Metadata
}

// GetVersion returns resource version
func (u *UserTokenSecretsV3) GetVersion() string {
	return u.Version
}

// GetKind returns resource kind
func (u *UserTokenSecretsV3) GetKind() string {
	return u.Kind
}

// SetName sets the name of the resource
func (u *UserTokenSecretsV3) SetName(name string) {
	u.Metadata.Name = name
}

// GetResourceID returns resource ID
func (u *UserTokenSecretsV3) GetResourceID() int64 {
	return u.Metadata.ID
}

// SetResourceID sets resource ID
func (u *UserTokenSecretsV3) SetResourceID(id int64) {
	u.Metadata.ID = id
}

// GetSubKind returns resource sub kind
func (u *UserTokenSecretsV3) GetSubKind() string {
	return u.SubKind
}

// SetSubKind sets resource subkind
func (u *UserTokenSecretsV3) SetSubKind(s string) {
	u.SubKind = s
}

// setStaticFields sets static resource header and metadata fields.
func (u *UserTokenSecretsV3) setStaticFields() {
	u.Kind = KindUserTokenSecrets
	u.Version = V3
}

// CheckAndSetDefaults checks and set default values for any missing fields.
func (u *UserTokenSecretsV3) CheckAndSetDefaults() error {
	u.setStaticFields()
	if err := u.Metadata.CheckAndSetDefaults(); err != nil {
		return trace.Wrap(err)
	}
	return nil
}

// String represents a human readable version of the token secrets
func (u *UserTokenSecretsV3) String() string {
	return fmt.Sprintf("UserTokenSecretsV3(tokenID=%v, opt_key=%v, qr_code=%v)", u.GetName(), u.Spec.OTPKey, u.Spec.QRCode)
}
<|endoftext|>


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

// +build ignore

package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/coreos/rkt/api/v1alpha"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func getLogsWithoutFollow(c v1alpha.PublicAPIClient, p *v1alpha.Pod) {
	logsResp, err := c.GetLogs(context.Background(), &v1alpha.GetLogsRequest{
		PodId:     p.Id,
		Follow:    false,
		AppName:   p.Apps[0].Name,
		SinceTime: time.Now().Add(-time.Second * 5).Unix(),
		Lines:     10,
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	logsRecvResp, err := logsResp.Recv()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, l := range logsRecvResp.Lines {
		fmt.Println(l)
	}
}

func getLogsWithFollow(c v1alpha.PublicAPIClient, p *v1alpha.Pod) {
	logsResp, err := c.GetLogs(context.Background(), &v1alpha.GetLogsRequest{
		PodId:   p.Id,
		Follow:  true,
		AppName: p.Apps[0].Name,
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for {
		logsRecvResp, err := logsResp.Recv()
		if err == io.EOF {
			return
		}

		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		for _, l := range logsRecvResp.Lines {
			fmt.Println(l)
		}
	}
}

func main() {
	followFlag := flag.Bool("follow", false, "enable 'follow' option on GetLogs")
	flag.Parse()

	conn, err := grpc.Dial("localhost:15441", grpc.WithInsecure())
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	c := v1alpha.NewPublicAPIClient(conn)
	defer conn.Close()

	// List pods.
	podResp, err := c.ListPods(context.Background(), &v1alpha.ListPodsRequest{
		// Specify the request: Fetch and print only running pods and their details.
		Detail: true,
		Filters: []*v1alpha.PodFilter{
			{
				States: []v1alpha.PodState{v1alpha.PodState_POD_STATE_RUNNING},
			},
		},
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, p := range podResp.Pods {
		if *followFlag {
			fmt.Printf("Pod %q is running. Following logs:\n", p.Id)
			getLogsWithFollow(c, p)
		} else {
			fmt.Printf("Pod %q is running.\n", p.Id)
			getLogsWithoutFollow(c, p)
		}
	}

	// List images.
	imgResp, err := c.ListImages(context.Background(), &v1alpha.ListImagesRequest{
		// In this request, we fetch the details of images whose names are prefixed with "coreos.com".
		Detail: true,
		Filters: []*v1alpha.ImageFilter{
			{
				Prefixes: []string{"coreos.com"},
			},
		},
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, im := range imgResp.Images {
		fmt.Printf("Found image %q\n", im.Name)
	}
}
<commit_msg>api/client_example: fix panic if pod has no apps<commit_after>// Copyright 2015 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build ignore

package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/coreos/rkt/api/v1alpha"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func getLogsWithoutFollow(c v1alpha.PublicAPIClient, p *v1alpha.Pod) {
	if len(p.Apps) == 0 {
		fmt.Printf("Pod %q has no apps\n", p.Id)
		return
	}

	logsResp, err := c.GetLogs(context.Background(), &v1alpha.GetLogsRequest{
		PodId:     p.Id,
		Follow:    false,
		AppName:   p.Apps[0].Name,
		SinceTime: time.Now().Add(-time.Second * 5).Unix(),
		Lines:     10,
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	logsRecvResp, err := logsResp.Recv()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, l := range logsRecvResp.Lines {
		fmt.Println(l)
	}
}

func getLogsWithFollow(c v1alpha.PublicAPIClient, p *v1alpha.Pod) {
	if len(p.Apps) == 0 {
		fmt.Printf("Pod %q has no apps\n", p.Id)
		return
	}

	logsResp, err := c.GetLogs(context.Background(), &v1alpha.GetLogsRequest{
		PodId:   p.Id,
		Follow:  true,
		AppName: p.Apps[0].Name,
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for {
		logsRecvResp, err := logsResp.Recv()
		if err == io.EOF {
			return
		}

		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		for _, l := range logsRecvResp.Lines {
			fmt.Println(l)
		}
	}
}

func main() {
	followFlag := flag.Bool("follow", false, "enable 'follow' option on GetLogs")
	flag.Parse()

	conn, err := grpc.Dial("localhost:15441", grpc.WithInsecure())
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	c := v1alpha.NewPublicAPIClient(conn)
	defer conn.Close()

	// List pods.
	podResp, err := c.ListPods(context.Background(), &v1alpha.ListPodsRequest{
		// Specify the request: Fetch and print only running pods and their details.
		Detail: true,
		Filters: []*v1alpha.PodFilter{
			{
				States: []v1alpha.PodState{v1alpha.PodState_POD_STATE_RUNNING},
			},
		},
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, p := range podResp.Pods {
		if *followFlag {
			fmt.Printf("Pod %q is running. Following logs:\n", p.Id)
			getLogsWithFollow(c, p)
		} else {
			fmt.Printf("Pod %q is running.\n", p.Id)
			getLogsWithoutFollow(c, p)
		}
	}

	// List images.
	imgResp, err := c.ListImages(context.Background(), &v1alpha.ListImagesRequest{
		// In this request, we fetch the details of images whose names are prefixed with "coreos.com".
		Detail: true,
		Filters: []*v1alpha.ImageFilter{
			{
				Prefixes: []string{"coreos.com"},
			},
		},
	})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, im := range imgResp.Images {
		fmt.Printf("Found image %q\n", im.Name)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//go:build go1.18
// +build go1.18

package zap

import (
	"fmt"

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

// Objects constructs a field with the given key, holding a list of the
// provided objects that can be marshaled by Zap.
//
// Note that these objects must implement zapcore.ObjectMarshaler directly.
// That is, if you're trying to marshal a []Request, the MarshalLogObject
// method must be declared on the Request type, not its pointer (*Request).
// If it's on the pointer, use ObjectValues.
//
// Given an object that implements MarshalLogObject on the value receiver, you
// can log a slice of those objects with Objects like so:
//
//	type Author struct{ ... }
//	func (a Author) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
//	var authors []Author = ...
//	logger.Info("loading article", zap.Objects("authors", authors))
//
// Similarly, given a type that implements MarshalLogObject on its pointer
// receiver, you can log a slice of pointers to that object with Objects like
// so:
//
//	type Request struct{ ... }
//	func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
//	var requests []*Request = ...
//	logger.Info("sending requests", zap.Objects("requests", requests))
//
// If instead, you have a slice of values of such an object, use the
// ObjectValues constructor.
//
//	var requests []Request = ...
//	logger.Info("sending requests", zap.ObjectValues("requests", requests))
func Objects[T zapcore.ObjectMarshaler](key string, values []T) Field {
	return Array(key, objects[T](values))
}

type objects[T zapcore.ObjectMarshaler] []T

func (os objects[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
	for _, o := range os {
		if err := arr.AppendObject(o); err != nil {
			return err
		}
	}
	return nil
}

// objectMarshalerPtr is a constraint that specifies that the given type
// implements zapcore.ObjectMarshaler on a pointer receiver.
type objectMarshalerPtr[T any] interface {
	*T
	zapcore.ObjectMarshaler
}

// ObjectValues constructs a field with the given key, holding a list of the
// provided objects, where pointers to these objects can be marshaled by Zap.
//
// Note that pointers to these objects must implement zapcore.ObjectMarshaler.
// That is, if you're trying to marshal a []Request, the MarshalLogObject
// method must be declared on the *Request type, not the value (Request).
// If it's on the value, use Objects.
//
// Given an object that implements MarshalLogObject on the pointer receiver,
// you can log a slice of those objects with ObjectValues like so:
//
//	type Request struct{ ... }
//	func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
//	var requests []Request = ...
//	logger.Info("sending requests", zap.ObjectValues("requests", requests))
//
// If instead, you have a slice of pointers of such an object, use the Objects
// field constructor.
//
//	var requests []*Request = ...
//	logger.Info("sending requests", zap.Objects("requests", requests))
func ObjectValues[T any, P objectMarshalerPtr[T]](key string, values []T) Field {
	return Array(key, objectValues[T, P](values))
}

type objectValues[T any, P objectMarshalerPtr[T]] []T

func (os objectValues[T, P]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
	for i := range os {
		// It is necessary for us to explicitly reference the "P" type.
		// We cannot simply pass "&os[i]" to AppendObject because its type
		// is "*T", which the type system does not consider as
		// implementing ObjectMarshaler.
		// Only the type "P" satisfies ObjectMarshaler, which we have
		// to convert "*T" to explicitly.
		var p P = &os[i]
		if err := arr.AppendObject(p); err != nil {
			return err
		}
	}
	return nil
}

// Stringers constructs a field with the given key, holding a list of the
// output provided by the value's String method
//
// Given an object that implements String on the value receiver, you
// can log a slice of those objects with Objects like so:
//
//	type Request struct{ ... }
//	func (a Request) String() string
//
//	var requests []Request = ...
//	logger.Info("sending requests", zap.Stringers("requests", requests))
//
// Note that these objects must implement fmt.Stringer directly.
// That is, if you're trying to marshal a []Request, the String method
// must be declared on the Request type, not its pointer (*Request).
func Stringers[T fmt.Stringer](key string, values []T) Field {
	return Array(key, stringers[T](values))
}

type stringers[T fmt.Stringer] []T

func (os stringers[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
	for _, o := range os {
		arr.AppendString(o.String())
	}
	return nil
}
<commit_msg>Export objectMarshalerPtr (#1171)<commit_after>// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//go:build go1.18
// +build go1.18

package zap

import (
	"fmt"

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

// Objects constructs a field with the given key, holding a list of the
// provided objects that can be marshaled by Zap.
//
// Note that these objects must implement zapcore.ObjectMarshaler directly.
// That is, if you're trying to marshal a []Request, the MarshalLogObject
// method must be declared on the Request type, not its pointer (*Request).
// If it's on the pointer, use ObjectValues.
//
// Given an object that implements MarshalLogObject on the value receiver, you
// can log a slice of those objects with Objects like so:
//
//	type Author struct{ ... }
//	func (a Author) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
//	var authors []Author = ...
//	logger.Info("loading article", zap.Objects("authors", authors))
//
// Similarly, given a type that implements MarshalLogObject on its pointer
// receiver, you can log a slice of pointers to that object with Objects like
// so:
//
//	type Request struct{ ... }
//	func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
//	var requests []*Request = ...
//	logger.Info("sending requests", zap.Objects("requests", requests))
//
// If instead, you have a slice of values of such an object, use the
// ObjectValues constructor.
//
//	var requests []Request = ...
//	logger.Info("sending requests", zap.ObjectValues("requests", requests))
func Objects[T zapcore.ObjectMarshaler](key string, values []T) Field {
	return Array(key, objects[T](values))
}

type objects[T zapcore.ObjectMarshaler] []T

func (os objects[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
	for _, o := range os {
		if err := arr.AppendObject(o); err != nil {
			return err
		}
	}
	return nil
}

// ObjectMarshalerPtr is a constraint that specifies that the given type
// implements zapcore.ObjectMarshaler on a pointer receiver.
type ObjectMarshalerPtr[T any] interface {
	*T
	zapcore.ObjectMarshaler
}

// ObjectValues constructs a field with the given key, holding a list of the
// provided objects, where pointers to these objects can be marshaled by Zap.
//
// Note that pointers to these objects must implement zapcore.ObjectMarshaler.
// That is, if you're trying to marshal a []Request, the MarshalLogObject
// method must be declared on the *Request type, not the value (Request).
// If it's on the value, use Objects.
//
// Given an object that implements MarshalLogObject on the pointer receiver,
// you can log a slice of those objects with ObjectValues like so:
//
//	type Request struct{ ... }
//	func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
//	var requests []Request = ...
//	logger.Info("sending requests", zap.ObjectValues("requests", requests))
//
// If instead, you have a slice of pointers of such an object, use the Objects
// field constructor.
//
//	var requests []*Request = ...
//	logger.Info("sending requests", zap.Objects("requests", requests))
func ObjectValues[T any, P ObjectMarshalerPtr[T]](key string, values []T) Field {
	return Array(key, objectValues[T, P](values))
}

type objectValues[T any, P ObjectMarshalerPtr[T]] []T

func (os objectValues[T, P]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
	for i := range os {
		// It is necessary for us to explicitly reference the "P" type.
		// We cannot simply pass "&os[i]" to AppendObject because its type
		// is "*T", which the type system does not consider as
		// implementing ObjectMarshaler.
		// Only the type "P" satisfies ObjectMarshaler, which we have
		// to convert "*T" to explicitly.
		var p P = &os[i]
		if err := arr.AppendObject(p); err != nil {
			return err
		}
	}
	return nil
}

// Stringers constructs a field with the given key, holding a list of the
// output provided by the value's String method
//
// Given an object that implements String on the value receiver, you
// can log a slice of those objects with Objects like so:
//
//	type Request struct{ ... }
//	func (a Request) String() string
//
//	var requests []Request = ...
//	logger.Info("sending requests", zap.Stringers("requests", requests))
//
// Note that these objects must implement fmt.Stringer directly.
// That is, if you're trying to marshal a []Request, the String method
// must be declared on the Request type, not its pointer (*Request).
func Stringers[T fmt.Stringer](key string, values []T) Field {
	return Array(key, stringers[T](values))
}

type stringers[T fmt.Stringer] []T

func (os stringers[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
	for _, o := range os {
		arr.AppendString(o.String())
	}
	return nil
}
<|endoftext|>


<commit_before>package asana

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/manishrjain/asanawarrior/x"
	"github.com/pkg/errors"
)

var token = flag.String("token", "", "Token provided by Asana.")
var domain = flag.String("domain", "", "Workspace name, generally your domain name in Asana.")
var cache *acache = new(acache)

const (
	prefix = "https://app.asana.com/api/1.0"
	stamp  = "2006-01-02T15:04:05.999Z"
)

func runRequest(method, url string) ([]byte, error) {
RUNLOOP:
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		log.Fatal(err)
	}

	req.Header.Add("Authorization", "Bearer "+*token)
	client := &http.Client{
		Timeout: 10 * time.Minute,
	}

	resp, err := client.Do(req)
	if err != nil {
		log.Printf("runRequest method: [%v] url: [%v] err: [%v]", method, url, err)
		time.Sleep(5 * time.Second)
		goto RUNLOOP
	}

	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

func runGetter(i interface{}, suffix string, fields ...string) error {
	url := fmt.Sprintf("%s/%s?opt_fields=%s", prefix, suffix, strings.Join(fields, ","))
	body, err := runRequest("GET", url)
	if err != nil {
		return errors.Wrapf(err, "runGetter: %q", body)
	}
	if err := json.Unmarshal(body, i); err != nil {
		return errors.Wrapf(err, "Unmarshal: %q", body)
	}
	return nil
}

type Basic struct {
	Id    uint64 `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}
type BasicData struct {
	Data []Basic `json:"data"`
}
type BasicDataOne struct {
	Data Basic `json:"data"`
}

func getVarious(suffix string, opts ...string) ([]Basic, error) {
	var bd BasicData
	if err := runGetter(&bd, suffix, opts...); err != nil {
		return nil, err
	}
	return bd.Data, nil
}

type psec struct {
	Project Basic `json:"project"`
	Section Basic `json:"section"`
}

type task struct {
	Basic
	Assignee    Basic   `json:"assignee"`
	Tags        []Basic `json:"tags"`
	CompletedAt string  `json:"completed_at"`
	ModifiedAt  string  `json:"modified_at"`
	CreatedAt   string  `json:"created_at"`
	Memberships []psec  `json:"memberships"`
}

type tasks struct {
	Data []task `json:"data"`
}

type oneTask struct {
	Data task `json:"data"`
}

func convert(tsk task, proj, section string) (x.WarriorTask, error) {
	e := x.WarriorTask{}

	mts, err := time.Parse(stamp, tsk.ModifiedAt)
	if err != nil {
		return e, errors.Wrap(err, "asana modified at")
	}
	cts, err := time.Parse(stamp, tsk.CreatedAt)
	if err != nil {
		return e, errors.Wrap(err, "asana created at")
	}
	var dts time.Time
	if len(tsk.CompletedAt) > 0 {
		dts, err = time.Parse(stamp, tsk.CompletedAt)
		if err != nil {
			return e, errors.Wrap(err, "asana completed at")
		}
	}

	wt := x.WarriorTask{
		Name:      tsk.Name,
		Project:   proj,
		Xid:       tsk.Id,
		Assignee:  cache.User(tsk.Assignee.Id),
		Modified:  mts,
		Created:   cts,
		Completed: dts,
		Section:   section,
	}
	for _, tag := range tsk.Tags {
		wt.Tags = append(wt.Tags, cache.Tag(tag.Id))
	}
	return wt, nil
}

func getTasks(proj Basic, out chan x.WarriorTask, errc chan error) {
	var sectionName string
	var t tasks
	if err := runGetter(&t, fmt.Sprintf("projects/%d/tasks", proj.Id),
		"assignee,name,tags,completed_at,modified_at,created_at"); err != nil {
		errc <- errors.Wrapf(err, "getTasks for project: %v", proj.Name)
		return
	}

	for _, tsk := range t.Data {
		if len(tsk.Name) == 0 {
			// Don't sync such tasks.
			continue
		}
		if strings.HasSuffix(tsk.Name, ":") {
			sec := Basic{
				Id:   tsk.Id,
				Name: tsk.Name,
			}
			sectionName = cache.AddSection(proj.Id, sec)
			continue
		}

		wt, err := convert(tsk, proj.Name, sectionName)
		if err != nil {
			errc <- errors.Wrapf(err, "convert: getTasks for project: %v", proj.Name)
			return
		}
		out <- wt
	}
	errc <- nil
}

func GetTasks() ([]x.WarriorTask, error) {
	if err := cache.update(); err != nil {
		return nil, errors.Wrap(err, "cache.update")
	}

	out := make(chan x.WarriorTask, 100)
	projects := cache.Projects()
	errc := make(chan error, len(projects))
	for _, proj := range projects {
		go getTasks(proj, out, errc)
	}

	// Asana can send back the same task multiple times, if it's part of multiple projects.
	// So, let's dedup them.
	seen := make(map[uint64]bool)
	wtasks := make([]x.WarriorTask, 0, 100)
	done := make(chan struct{})
	go func() {
		for wt := range out {
			if _, has := seen[wt.Xid]; has {
				// ignore
				continue
			}
			wtasks = append(wtasks, wt)
			seen[wt.Xid] = true
		}
		done <- struct{}{}
	}()

	var rerr error
	for _ = range projects {
		if err := <-errc; err != nil {
			rerr = err
		}
	}
	close(out)
	<-done // Wait for all tasks to be picked up by goroutine.
	return wtasks, rerr
}

// runPost would run a PUT or POST to Asana. No locks should be acquired.
func runPost(method, suffix string, values url.Values) ([]byte, error) {
POSTLOOP:
	url := fmt.Sprintf("%s/%s", prefix, suffix)
	fmt.Println(url, values.Encode())
	req, err := http.NewRequest(method, url, bytes.NewBufferString(values.Encode()))
	if err != nil {
		log.Fatal(errors.Wrap(err, "runPost http.NewRequest"))
	}

	req.Header.Add("Authorization", "Bearer "+*token)
	req.Header.Add("content-type", "application/x-www-form-urlencoded")
	client := &http.Client{
		Timeout: 10 * time.Minute,
	}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("runPost url: [%v] err: [%v]", url, err)
		time.Sleep(5 * time.Second)
		goto POSTLOOP
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

func toTagIds(tnames []string) []string {
	var tags []string
	for _, t := range tnames {
		tid := cache.TagId(t)
		if tid == 0 {
			tid = cache.CreateTag(t)
			fmt.Printf("New Tag created. ID: %d", tid)
		}
		if tid > 0 {
			tags = append(tags, strconv.FormatUint(tid, 10))
		}
	}
	return tags
}

func removeProject(tid, pid uint64) error {
	v := url.Values{}
	v.Add("project", strconv.FormatUint(pid, 10))
	_, err := runPost("POST", fmt.Sprintf("tasks/%d/removeProject", tid), v)
	return err
}

func updateSection(tid, pid uint64, section string) error {
	v := url.Values{}
	v.Add("project", strconv.FormatUint(pid, 10))

	sid := cache.SectionId(pid, section)
	if sid > 0 {
		v.Add("section", strconv.FormatUint(sid, 10))
	}

	_, err := runPost("POST", fmt.Sprintf("tasks/%d/addProject", tid), v)
	return err
}

func AddNew(wt x.WarriorTask) (x.WarriorTask, error) {
	e := x.WarriorTask{}

	// Ensure that project actually exists before proceeding.
	pid := cache.ProjectId(wt.Project)
	if pid == 0 {
		return e, fmt.Errorf("Project not found: %v", wt.Project)
	}

	v := url.Values{}
	v.Add("workspace", strconv.FormatUint(cache.Workspace(), 10))
	v.Add("name", wt.Name)
	aid := cache.UserId(wt.Assignee)
	if aid > 0 {
		v.Add("assignee", strconv.FormatUint(aid, 10))
	}
	if !wt.Completed.IsZero() {
		v.Add("completed", "true")
	}

	tags := toTagIds(wt.Tags)
	v.Add("tags", strings.Join(tags, ","))
	resp, err := runPost("POST", "tasks", v)
	if err != nil {
		return e, errors.Wrap(err, "AddNew runPost")
	}
	fmt.Println(string(resp))

	var ot oneTask
	if err := json.Unmarshal(resp, &ot); err != nil {
		return e, errors.Wrap(err, "AddNew unmarshal")
	}
	if ot.Data.Id == 0 {
		return e, fmt.Errorf("Unable to find ID assigned by Asana: %+v", ot.Data)
	}

	// Now set the project and section.
	if err := updateSection(ot.Data.Id, pid, wt.Section); err != nil {
		return e, errors.Wrap(err, "AddNew updateSection")
	}

	// Now retrieve the task back again so we can sync it up with TW.
	return GetOneTask(ot.Data.Id)
}

func diff(t1 []string, t2 []string) []string {
	m := make(map[string]bool)
	for _, s := range t2 {
		m[s] = true
	}

	var result []string
	for _, t := range t1 {
		if has := m[t]; !has {
			result = append(result, t)
		}
	}
	return result
}

func updateOneTag(tagid, taskid, instruction string, errc chan error) {
	v := url.Values{}
	v.Add("tag", tagid)
	suffix := fmt.Sprintf("tasks/%s/%s", taskid, instruction)
	_, err := runPost("POST", suffix, v)
	if err != nil {
		errc <- errors.Wrap(err, "updateTags")
		return
	}
	errc <- nil
}

func updateTags(tw x.WarriorTask, asana x.WarriorTask) error {
	taskid := strconv.FormatUint(tw.Xid, 10)
	add := diff(tw.Tags, asana.Tags)
	rem := diff(asana.Tags, tw.Tags)

	addids := toTagIds(add)
	remids := toTagIds(rem)
	sz := len(addids) + len(remids)

	errc := make(chan error, sz)
	for _, id := range addids {
		go updateOneTag(id, taskid, "addTag", errc)
	}
	for _, id := range remids {
		go updateOneTag(id, taskid, "removeTag", errc)
	}

	var rerr error
	for i := 0; i < sz; i++ {
		if err := <-errc; err != nil {
			rerr = err
		}
	}

	return rerr
}

func UpdateTask(tw x.WarriorTask, asana x.WarriorTask) error {
	v := url.Values{}
	if tw.Name != asana.Name {
		v.Add("name", tw.Name)
	}
	if tw.Assignee != asana.Assignee {
		a := cache.UserId(tw.Assignee)
		if a > 0 {
			v.Add("assignee", strconv.FormatUint(a, 10))
		}
	}
	if !tw.Completed.IsZero() && asana.Completed.IsZero() {
		v.Add("completed", "true")
	}

	if len(v) > 0 {
		resp, err := runPost("PUT", "tasks/"+strconv.FormatUint(tw.Xid, 10), v)
		if err != nil {
			return errors.Wrap(err, "UpdateAsanaTask")
		}
		fmt.Println(string(resp))
	}

	if err := updateTags(tw, asana); err != nil {
		return errors.Wrap(err, "asana.UpdateTask updateTags")
	}

	// Update project or section if changed.
	pid := cache.ProjectId(tw.Project)
	if pid > 0 && (tw.Project != asana.Project || tw.Section != asana.Section) {
		fmt.Printf("Updating project and section: %v %v\n", tw.Project, tw.Section)
		if err := updateSection(tw.Xid, pid, tw.Section); err != nil {
			return errors.Wrap(err, "asana.UpdateTask updateSection")
		}
		if tw.Project == asana.Project {
			return nil
		}
		// Project was changed. So, remove the last one.
		fmt.Printf("Removing from project: %v\n", asana.Project)
		if previd := cache.ProjectId(asana.Project); previd > 0 {
			if err := removeProject(tw.Xid, previd); err != nil {
				return err
			}
		}
	}
	return nil
}

func GetOneTask(taskid uint64) (x.WarriorTask, error) {
	e := x.WarriorTask{}
	var ot oneTask
	if err := runGetter(&ot, "tasks/"+strconv.FormatUint(taskid, 10)); err != nil {
		return e, errors.Wrap(err, "AddNew runGetter")
	}

	if len(ot.Data.Memberships) == 0 {
		return e, fmt.Errorf("Member of no project")
	}
	member := ot.Data.Memberships[0]

	sname := cache.SectionName(member.Project.Id, member.Section.Id)
	return convert(ot.Data, member.Project.Name, sname)
}

func Delete(taskid uint64) error {
	url := fmt.Sprintf("%s/tasks/%d", prefix, taskid)
	_, err := runRequest("DELETE", url)
	return err
}
<commit_msg>Check status code for Asana API and print err while fetching task (#24)<commit_after>package asana

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/manishrjain/asanawarrior/x"
	"github.com/pkg/errors"
)

var token = flag.String("token", "", "Token provided by Asana.")
var domain = flag.String("domain", "", "Workspace name, generally your domain name in Asana.")
var cache *acache = new(acache)

const (
	prefix = "https://app.asana.com/api/1.0"
	stamp  = "2006-01-02T15:04:05.999Z"
)

func runRequest(method, url string) ([]byte, error) {
RUNLOOP:
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		log.Fatal(err)
	}

	req.Header.Add("Authorization", "Bearer "+*token)
	client := &http.Client{
		Timeout: 10 * time.Minute,
	}

	resp, err := client.Do(req)
	statusCode := resp.StatusCode
	if err != nil || statusCode != http.StatusOK {
		log.Printf("runRequest method: [%v] url: [%v] status: [%v] err: [%v]", method, url, http.StatusText(statusCode), err)
		time.Sleep(5 * time.Second)
		goto RUNLOOP
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

func runGetter(i interface{}, suffix string, fields ...string) error {
	url := fmt.Sprintf("%s/%s?opt_fields=%s", prefix, suffix, strings.Join(fields, ","))
	body, err := runRequest("GET", url)
	if err != nil {
		return errors.Wrapf(err, "runGetter: %q", body)
	}
	if err := json.Unmarshal(body, i); err != nil {
		return errors.Wrapf(err, "Unmarshal: %q", body)
	}
	return nil
}

type Basic struct {
	Id    uint64 `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}
type BasicData struct {
	Data []Basic `json:"data"`
}
type BasicDataOne struct {
	Data Basic `json:"data"`
}

func getVarious(suffix string, opts ...string) ([]Basic, error) {
	var bd BasicData
	if err := runGetter(&bd, suffix, opts...); err != nil {
		return nil, err
	}
	return bd.Data, nil
}

type psec struct {
	Project Basic `json:"project"`
	Section Basic `json:"section"`
}

type task struct {
	Basic
	Assignee    Basic   `json:"assignee"`
	Tags        []Basic `json:"tags"`
	CompletedAt string  `json:"completed_at"`
	ModifiedAt  string  `json:"modified_at"`
	CreatedAt   string  `json:"created_at"`
	Memberships []psec  `json:"memberships"`
}

type tasks struct {
	Data []task `json:"data"`
}

type oneTask struct {
	Data task `json:"data"`
}

func convert(tsk task, proj, section string) (x.WarriorTask, error) {
	e := x.WarriorTask{}

	mts, err := time.Parse(stamp, tsk.ModifiedAt)
	if err != nil {
		return e, errors.Wrap(err, "asana modified at")
	}
	cts, err := time.Parse(stamp, tsk.CreatedAt)
	if err != nil {
		return e, errors.Wrap(err, "asana created at")
	}
	var dts time.Time
	if len(tsk.CompletedAt) > 0 {
		dts, err = time.Parse(stamp, tsk.CompletedAt)
		if err != nil {
			return e, errors.Wrap(err, "asana completed at")
		}
	}

	wt := x.WarriorTask{
		Name:      tsk.Name,
		Project:   proj,
		Xid:       tsk.Id,
		Assignee:  cache.User(tsk.Assignee.Id),
		Modified:  mts,
		Created:   cts,
		Completed: dts,
		Section:   section,
	}
	for _, tag := range tsk.Tags {
		wt.Tags = append(wt.Tags, cache.Tag(tag.Id))
	}
	return wt, nil
}

func getTasks(proj Basic, out chan x.WarriorTask, errc chan error) {
	var sectionName string
	var t tasks
	if err := runGetter(&t, fmt.Sprintf("projects/%d/tasks", proj.Id),
		"assignee,name,tags,completed_at,modified_at,created_at"); err != nil {
		errc <- errors.Wrapf(err, "getTasks for project: %v", proj.Name)
		return
	}

	for _, tsk := range t.Data {
		if len(tsk.Name) == 0 {
			// Don't sync such tasks.
			continue
		}
		if strings.HasSuffix(tsk.Name, ":") {
			sec := Basic{
				Id:   tsk.Id,
				Name: tsk.Name,
			}
			sectionName = cache.AddSection(proj.Id, sec)
			continue
		}

		wt, err := convert(tsk, proj.Name, sectionName)
		if err != nil {
			errc <- errors.Wrapf(err, "convert: getTasks for project: %v", proj.Name)
			return
		}
		out <- wt
	}
	errc <- nil
}

func GetTasks() ([]x.WarriorTask, error) {
	if err := cache.update(); err != nil {
		return nil, errors.Wrap(err, "cache.update")
	}

	out := make(chan x.WarriorTask, 100)
	projects := cache.Projects()
	errc := make(chan error, len(projects))
	for _, proj := range projects {
		go getTasks(proj, out, errc)
	}

	// Asana can send back the same task multiple times, if it's part of multiple projects.
	// So, let's dedup them.
	seen := make(map[uint64]bool)
	wtasks := make([]x.WarriorTask, 0, 100)
	done := make(chan struct{})
	go func() {
		for wt := range out {
			if _, has := seen[wt.Xid]; has {
				// ignore
				continue
			}
			wtasks = append(wtasks, wt)
			seen[wt.Xid] = true
		}
		done <- struct{}{}
	}()

	var rerr error
	for _ = range projects {
		if err := <-errc; err != nil {
			rerr = err
		}
	}
	close(out)
	<-done // Wait for all tasks to be picked up by goroutine.
	return wtasks, rerr
}

// runPost would run a PUT or POST to Asana. No locks should be acquired.
func runPost(method, suffix string, values url.Values) ([]byte, error) {
POSTLOOP:
	url := fmt.Sprintf("%s/%s", prefix, suffix)
	fmt.Println(url, values.Encode())
	req, err := http.NewRequest(method, url, bytes.NewBufferString(values.Encode()))
	if err != nil {
		log.Fatal(errors.Wrap(err, "runPost http.NewRequest"))
	}

	req.Header.Add("Authorization", "Bearer "+*token)
	req.Header.Add("content-type", "application/x-www-form-urlencoded")
	client := &http.Client{
		Timeout: 10 * time.Minute,
	}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("runPost url: [%v] err: [%v]", url, err)
		time.Sleep(5 * time.Second)
		goto POSTLOOP
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

func toTagIds(tnames []string) []string {
	var tags []string
	for _, t := range tnames {
		tid := cache.TagId(t)
		if tid == 0 {
			tid = cache.CreateTag(t)
			fmt.Printf("New Tag created. ID: %d", tid)
		}
		if tid > 0 {
			tags = append(tags, strconv.FormatUint(tid, 10))
		}
	}
	return tags
}

func removeProject(tid, pid uint64) error {
	v := url.Values{}
	v.Add("project", strconv.FormatUint(pid, 10))
	_, err := runPost("POST", fmt.Sprintf("tasks/%d/removeProject", tid), v)
	return err
}

func updateSection(tid, pid uint64, section string) error {
	v := url.Values{}
	v.Add("project", strconv.FormatUint(pid, 10))

	sid := cache.SectionId(pid, section)
	if sid > 0 {
		v.Add("section", strconv.FormatUint(sid, 10))
	}

	_, err := runPost("POST", fmt.Sprintf("tasks/%d/addProject", tid), v)
	return err
}

func AddNew(wt x.WarriorTask) (x.WarriorTask, error) {
	e := x.WarriorTask{}

	// Ensure that project actually exists before proceeding.
	pid := cache.ProjectId(wt.Project)
	if pid == 0 {
		return e, fmt.Errorf("Project not found: %v", wt.Project)
	}

	v := url.Values{}
	v.Add("workspace", strconv.FormatUint(cache.Workspace(), 10))
	v.Add("name", wt.Name)
	aid := cache.UserId(wt.Assignee)
	if aid > 0 {
		v.Add("assignee", strconv.FormatUint(aid, 10))
	}
	if !wt.Completed.IsZero() {
		v.Add("completed", "true")
	}

	tags := toTagIds(wt.Tags)
	v.Add("tags", strings.Join(tags, ","))
	resp, err := runPost("POST", "tasks", v)
	if err != nil {
		return e, errors.Wrap(err, "AddNew runPost")
	}
	fmt.Println(string(resp))

	var ot oneTask
	if err := json.Unmarshal(resp, &ot); err != nil {
		return e, errors.Wrap(err, "AddNew unmarshal")
	}
	if ot.Data.Id == 0 {
		return e, fmt.Errorf("Unable to find ID assigned by Asana: %+v", ot.Data)
	}

	// Now set the project and section.
	if err := updateSection(ot.Data.Id, pid, wt.Section); err != nil {
		return e, errors.Wrap(err, "AddNew updateSection")
	}

	// Now retrieve the task back again so we can sync it up with TW.
	return GetOneTask(ot.Data.Id)
}

func diff(t1 []string, t2 []string) []string {
	m := make(map[string]bool)
	for _, s := range t2 {
		m[s] = true
	}

	var result []string
	for _, t := range t1 {
		if has := m[t]; !has {
			result = append(result, t)
		}
	}
	return result
}

func updateOneTag(tagid, taskid, instruction string, errc chan error) {
	v := url.Values{}
	v.Add("tag", tagid)
	suffix := fmt.Sprintf("tasks/%s/%s", taskid, instruction)
	_, err := runPost("POST", suffix, v)
	if err != nil {
		errc <- errors.Wrap(err, "updateTags")
		return
	}
	errc <- nil
}

func updateTags(tw x.WarriorTask, asana x.WarriorTask) error {
	taskid := strconv.FormatUint(tw.Xid, 10)
	add := diff(tw.Tags, asana.Tags)
	rem := diff(asana.Tags, tw.Tags)

	addids := toTagIds(add)
	remids := toTagIds(rem)
	sz := len(addids) + len(remids)

	errc := make(chan error, sz)
	for _, id := range addids {
		go updateOneTag(id, taskid, "addTag", errc)
	}
	for _, id := range remids {
		go updateOneTag(id, taskid, "removeTag", errc)
	}

	var rerr error
	for i := 0; i < sz; i++ {
		if err := <-errc; err != nil {
			rerr = err
		}
	}

	return rerr
}

func UpdateTask(tw x.WarriorTask, asana x.WarriorTask) error {
	v := url.Values{}
	if tw.Name != asana.Name {
		v.Add("name", tw.Name)
	}
	if tw.Assignee != asana.Assignee {
		a := cache.UserId(tw.Assignee)
		if a > 0 {
			v.Add("assignee", strconv.FormatUint(a, 10))
		}
	}
	if !tw.Completed.IsZero() && asana.Completed.IsZero() {
		v.Add("completed", "true")
	}

	if len(v) > 0 {
		resp, err := runPost("PUT", "tasks/"+strconv.FormatUint(tw.Xid, 10), v)
		if err != nil {
			return errors.Wrap(err, "UpdateAsanaTask")
		}
		fmt.Println(string(resp))
	}

	if err := updateTags(tw, asana); err != nil {
		return errors.Wrap(err, "asana.UpdateTask updateTags")
	}

	// Update project or section if changed.
	pid := cache.ProjectId(tw.Project)
	if pid > 0 && (tw.Project != asana.Project || tw.Section != asana.Section) {
		fmt.Printf("Updating project and section: %v %v\n", tw.Project, tw.Section)
		if err := updateSection(tw.Xid, pid, tw.Section); err != nil {
			return errors.Wrap(err, "asana.UpdateTask updateSection")
		}
		if tw.Project == asana.Project {
			return nil
		}
		// Project was changed. So, remove the last one.
		fmt.Printf("Removing from project: %v\n", asana.Project)
		if previd := cache.ProjectId(asana.Project); previd > 0 {
			if err := removeProject(tw.Xid, previd); err != nil {
				return err
			}
		}
	}
	return nil
}

func GetOneTask(taskid uint64) (x.WarriorTask, error) {
	e := x.WarriorTask{}
	var ot oneTask
	if err := runGetter(&ot, "tasks/"+strconv.FormatUint(taskid, 10)); err != nil {
		return e, errors.Wrap(err, "AddNew runGetter")
	}

	if len(ot.Data.Memberships) == 0 {
		return e, fmt.Errorf("Member of no project")
	}
	member := ot.Data.Memberships[0]

	sname := cache.SectionName(member.Project.Id, member.Section.Id)
	return convert(ot.Data, member.Project.Name, sname)
}

func Delete(taskid uint64) error {
	url := fmt.Sprintf("%s/tasks/%d", prefix, taskid)
	_, err := runRequest("DELETE", url)
	return err
}
<|endoftext|>