<commit_before>package sdl

/*
#include "sdl_wrapper.h"
static Sint64 RWsize(SDL_RWops *ctx)
{
	return ctx->size(ctx);
}

static Sint64 RWseek(SDL_RWops *ctx, Sint64 offset, int whence)
{
	return ctx->seek(ctx, offset, whence);
}

static size_t RWread(SDL_RWops *ctx, void *ptr, size_t size, size_t maxnum)
{
	return ctx->read(ctx, ptr, size, maxnum);
}

static size_t RWwrite(SDL_RWops *ctx, void *ptr, size_t size, size_t num)
{
	return ctx->write(ctx, ptr, size, num);
}

static int RWclose(SDL_RWops *ctx)
{
	return ctx->close(ctx);
}
*/
import "C"
import "unsafe"

/* RWops Types */
const (
	RWOPS_UNKNOWN   = 0
	RWOPS_WINFILE   = 1
	RWOPS_STDFILE   = 2
	RWOPS_JNIFILE   = 3
	RWOPS_MEMORY    = 4
	RWOPS_MEMORY_RO = 5
)

const (
	RW_SEEK_SET = C.RW_SEEK_SET
	RW_SEEK_CUR = C.RW_SEEK_CUR
	RW_SEEK_END = C.RW_SEEK_END
)

// RWops (https://wiki.libsdl.org/SDL_RWops)
type RWops C.SDL_RWops

func (rw *RWops) cptr() *C.SDL_RWops {
	return (*C.SDL_RWops)(rw)
}

// RWFromFile (https://wiki.libsdl.org/SDL_RWFromFile)
func RWFromFile(file, mode string) *RWops {
	_file := C.CString(file)
	_mode := C.CString(mode)
	defer C.free(unsafe.Pointer(_file))
	defer C.free(unsafe.Pointer(_mode))
	return (*RWops)(unsafe.Pointer(C.SDL_RWFromFile(_file, _mode)))
}

// RWFromMem (https://wiki.libsdl.org/SDL_RWFromMem)
func RWFromMem(mem unsafe.Pointer, size int) *RWops {
	if mem == nil {
		return nil
	}
	return (*RWops)(unsafe.Pointer(C.SDL_RWFromMem(mem, C.int(size))))
}

// AllocRW (https://wiki.libsdl.org/SDL_AllocRW)
func AllocRW() *RWops {
	return (*RWops)(unsafe.Pointer(C.SDL_AllocRW()))
}

// FreeRW (https://wiki.libsdl.org/SDL_FreeRW)
func (area *RWops) FreeRW() {
	if area == nil {
		return
	}
	C.SDL_FreeRW(area.cptr())
}

// RWsize (https://wiki.libsdl.org/SDL_RWsize)
func (ctx *RWops) RWsize() int64 {
	return int64(C.RWsize(ctx.cptr()))
}

// RWseek (https://wiki.libsdl.org/SDL_RWseek)
func (ctx *RWops) RWseek(offset int64, whence int) int64 {
	if ctx == nil {
		return -1
	}
	return int64(C.RWseek(ctx.cptr(), C.Sint64(offset), C.int(whence)))
}

// RWread (https://wiki.libsdl.org/SDL_RWread)
func (ctx *RWops) RWread(ptr unsafe.Pointer, size, maxnum uint) uint {
	if ctx == nil {
		return 0
	}
	return uint(C.RWread(ctx.cptr(), ptr, C.size_t(size), C.size_t(maxnum)))
}

// RWtell (https://wiki.libsdl.org/SDL_RWtell)
func (ctx *RWops) RWtell() int64 {
	if ctx == nil {
		return 0
	}
	return int64(C.RWseek(ctx.cptr(), 0, RW_SEEK_CUR))
}

// RWwrite (https://wiki.libsdl.org/SDL_RWwrite)
func (ctx *RWops) RWwrite(ptr unsafe.Pointer, size, num uint) uint {
	if ctx == nil {
		return 0
	}
	if ptr == nil {
		return 0
	}
	return uint(C.RWwrite(ctx.cptr(), ptr, C.size_t(size), C.size_t(size)))
}

// RWclose (https://wiki.libsdl.org/SDL_RWclose)
func (ctx *RWops) RWclose() int {
	if ctx == nil {
		return 0
	}
	return int(C.RWclose(ctx.cptr()))
}

func (src *RWops) ReadU8() uint8 {
	if src == nil {
		return 0
	}
	return uint8(C.SDL_ReadU8(src.cptr()))
}

// ReadLE16 (https://wiki.libsdl.org/SDL_ReadLE16)
func (src *RWops) ReadLE16() uint16 {
	if src == nil {
		return 0
	}
	return uint16(C.SDL_ReadLE16(src.cptr()))
}

// ReadBE16 (https://wiki.libsdl.org/SDL_ReadBE16)
func (src *RWops) ReadBE16() uint16 {
	if src == nil {
		return 0
	}
	return uint16(C.SDL_ReadBE16(src.cptr()))
}

// ReadLE32 (https://wiki.libsdl.org/SDL_ReadLE32)
func (src *RWops) ReadLE32() uint32 {
	if src == nil {
		return 0
	}
	return uint32(C.SDL_ReadLE32(src.cptr()))
}

// ReadBE32 (https://wiki.libsdl.org/SDL_ReadBE32)
func (src *RWops) ReadBE32() uint32 {
	if src == nil {
		return 0
	}
	return uint32(C.SDL_ReadBE32(src.cptr()))
}

// ReadLE64 (https://wiki.libsdl.org/SDL_ReadLE64)
func (src *RWops) ReadLE64() uint64 {
	if src == nil {
		return 0
	}
	return uint64(C.SDL_ReadLE64(src.cptr()))
}

// ReadBE64 (https://wiki.libsdl.org/SDL_ReadBE64)
func (src *RWops) ReadBE64() uint64 {
	if src == nil {
		return 0
	}
	return uint64(C.SDL_ReadBE64(src.cptr()))
}

func (dst *RWops) WriteU8(value uint8) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteU8(dst.cptr(), C.Uint8(value)))
}

// WriteLE16 (https://wiki.libsdl.org/SDL_WriteLE16)
func (dst *RWops) WriteLE16(value uint16) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteLE16(dst.cptr(), C.Uint16(value)))
}

// WriteBE16 (https://wiki.libsdl.org/SDL_WriteBE16)
func (dst *RWops) WriteBE16(value uint16) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteBE16(dst.cptr(), C.Uint16(value)))
}

// WriteLE32 (https://wiki.libsdl.org/SDL_WriteLE32)
func (dst *RWops) WriteLE32(value uint32) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteLE32(dst.cptr(), C.Uint32(value)))
}

// WriteBE32 (https://wiki.libsdl.org/SDL_WriteBE32)
func (dst *RWops) WriteBE32(value uint32) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteBE32(dst.cptr(), C.Uint32(value)))
}

// WriteLE64 (https://wiki.libsdl.org/SDL_WriteLE64)
func (dst *RWops) WriteLE64(value uint64) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteLE64(dst.cptr(), C.Uint64(value)))
}

// WriteBE64 (https://wiki.libsdl.org/SDL_WriteBE64)
func (dst *RWops) WriteBE64(value uint64) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteBE64(dst.cptr(), C.Uint64(value)))
}
<commit_msg>Make RWclose() return error instead of int<commit_after>package sdl

/*
#include "sdl_wrapper.h"
static Sint64 RWsize(SDL_RWops *ctx)
{
	return ctx->size(ctx);
}

static Sint64 RWseek(SDL_RWops *ctx, Sint64 offset, int whence)
{
	return ctx->seek(ctx, offset, whence);
}

static size_t RWread(SDL_RWops *ctx, void *ptr, size_t size, size_t maxnum)
{
	return ctx->read(ctx, ptr, size, maxnum);
}

static size_t RWwrite(SDL_RWops *ctx, void *ptr, size_t size, size_t num)
{
	return ctx->write(ctx, ptr, size, num);
}

static int RWclose(SDL_RWops *ctx)
{
	return ctx->close(ctx);
}
*/
import "C"
import "unsafe"

/* RWops Types */
const (
	RWOPS_UNKNOWN   = 0
	RWOPS_WINFILE   = 1
	RWOPS_STDFILE   = 2
	RWOPS_JNIFILE   = 3
	RWOPS_MEMORY    = 4
	RWOPS_MEMORY_RO = 5
)

const (
	RW_SEEK_SET = C.RW_SEEK_SET
	RW_SEEK_CUR = C.RW_SEEK_CUR
	RW_SEEK_END = C.RW_SEEK_END
)

// RWops (https://wiki.libsdl.org/SDL_RWops)
type RWops C.SDL_RWops

func (rw *RWops) cptr() *C.SDL_RWops {
	return (*C.SDL_RWops)(rw)
}

// RWFromFile (https://wiki.libsdl.org/SDL_RWFromFile)
func RWFromFile(file, mode string) *RWops {
	_file := C.CString(file)
	_mode := C.CString(mode)
	defer C.free(unsafe.Pointer(_file))
	defer C.free(unsafe.Pointer(_mode))
	return (*RWops)(unsafe.Pointer(C.SDL_RWFromFile(_file, _mode)))
}

// RWFromMem (https://wiki.libsdl.org/SDL_RWFromMem)
func RWFromMem(mem unsafe.Pointer, size int) *RWops {
	if mem == nil {
		return nil
	}
	return (*RWops)(unsafe.Pointer(C.SDL_RWFromMem(mem, C.int(size))))
}

// AllocRW (https://wiki.libsdl.org/SDL_AllocRW)
func AllocRW() *RWops {
	return (*RWops)(unsafe.Pointer(C.SDL_AllocRW()))
}

// FreeRW (https://wiki.libsdl.org/SDL_FreeRW)
func (area *RWops) FreeRW() {
	if area == nil {
		return
	}
	C.SDL_FreeRW(area.cptr())
}

// RWsize (https://wiki.libsdl.org/SDL_RWsize)
func (ctx *RWops) RWsize() int64 {
	return int64(C.RWsize(ctx.cptr()))
}

// RWseek (https://wiki.libsdl.org/SDL_RWseek)
func (ctx *RWops) RWseek(offset int64, whence int) int64 {
	if ctx == nil {
		return -1
	}
	return int64(C.RWseek(ctx.cptr(), C.Sint64(offset), C.int(whence)))
}

// RWread (https://wiki.libsdl.org/SDL_RWread)
func (ctx *RWops) RWread(ptr unsafe.Pointer, size, maxnum uint) uint {
	if ctx == nil {
		return 0
	}
	return uint(C.RWread(ctx.cptr(), ptr, C.size_t(size), C.size_t(maxnum)))
}

// RWtell (https://wiki.libsdl.org/SDL_RWtell)
func (ctx *RWops) RWtell() int64 {
	if ctx == nil {
		return 0
	}
	return int64(C.RWseek(ctx.cptr(), 0, RW_SEEK_CUR))
}

// RWwrite (https://wiki.libsdl.org/SDL_RWwrite)
func (ctx *RWops) RWwrite(ptr unsafe.Pointer, size, num uint) uint {
	if ctx == nil {
		return 0
	}
	if ptr == nil {
		return 0
	}
	return uint(C.RWwrite(ctx.cptr(), ptr, C.size_t(size), C.size_t(size)))
}

// RWclose (https://wiki.libsdl.org/SDL_RWclose)
func (ctx *RWops) RWclose() error {
	if ctx != nil && C.RWclose(ctx.cptr()) != 0 {
		return GetError()
	}
	return nil
}

func (src *RWops) ReadU8() uint8 {
	if src == nil {
		return 0
	}
	return uint8(C.SDL_ReadU8(src.cptr()))
}

// ReadLE16 (https://wiki.libsdl.org/SDL_ReadLE16)
func (src *RWops) ReadLE16() uint16 {
	if src == nil {
		return 0
	}
	return uint16(C.SDL_ReadLE16(src.cptr()))
}

// ReadBE16 (https://wiki.libsdl.org/SDL_ReadBE16)
func (src *RWops) ReadBE16() uint16 {
	if src == nil {
		return 0
	}
	return uint16(C.SDL_ReadBE16(src.cptr()))
}

// ReadLE32 (https://wiki.libsdl.org/SDL_ReadLE32)
func (src *RWops) ReadLE32() uint32 {
	if src == nil {
		return 0
	}
	return uint32(C.SDL_ReadLE32(src.cptr()))
}

// ReadBE32 (https://wiki.libsdl.org/SDL_ReadBE32)
func (src *RWops) ReadBE32() uint32 {
	if src == nil {
		return 0
	}
	return uint32(C.SDL_ReadBE32(src.cptr()))
}

// ReadLE64 (https://wiki.libsdl.org/SDL_ReadLE64)
func (src *RWops) ReadLE64() uint64 {
	if src == nil {
		return 0
	}
	return uint64(C.SDL_ReadLE64(src.cptr()))
}

// ReadBE64 (https://wiki.libsdl.org/SDL_ReadBE64)
func (src *RWops) ReadBE64() uint64 {
	if src == nil {
		return 0
	}
	return uint64(C.SDL_ReadBE64(src.cptr()))
}

func (dst *RWops) WriteU8(value uint8) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteU8(dst.cptr(), C.Uint8(value)))
}

// WriteLE16 (https://wiki.libsdl.org/SDL_WriteLE16)
func (dst *RWops) WriteLE16(value uint16) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteLE16(dst.cptr(), C.Uint16(value)))
}

// WriteBE16 (https://wiki.libsdl.org/SDL_WriteBE16)
func (dst *RWops) WriteBE16(value uint16) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteBE16(dst.cptr(), C.Uint16(value)))
}

// WriteLE32 (https://wiki.libsdl.org/SDL_WriteLE32)
func (dst *RWops) WriteLE32(value uint32) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteLE32(dst.cptr(), C.Uint32(value)))
}

// WriteBE32 (https://wiki.libsdl.org/SDL_WriteBE32)
func (dst *RWops) WriteBE32(value uint32) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteBE32(dst.cptr(), C.Uint32(value)))
}

// WriteLE64 (https://wiki.libsdl.org/SDL_WriteLE64)
func (dst *RWops) WriteLE64(value uint64) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteLE64(dst.cptr(), C.Uint64(value)))
}

// WriteBE64 (https://wiki.libsdl.org/SDL_WriteBE64)
func (dst *RWops) WriteBE64(value uint64) uint {
	if dst == nil {
		return 0
	}
	return uint(C.SDL_WriteBE64(dst.cptr(), C.Uint64(value)))
}
<|endoftext|>


<commit_before>package egoscale

import (
	"encoding/json"
	"fmt"
	"net/url"
)

// CreateEgressRule is an alias of AuthorizeSecurityGroupEgress
func (exo *Client) CreateEgressRule(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.AuthorizeSecurityGroupEgress(rule, async)
}

// AutorizeSecurityGroupEgress authorizes a particular egress rule for this security group
func (exo *Client) AuthorizeSecurityGroupEgress(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.doSecurityGroupRule("authorize", "Egress", rule, async)
}

// CreateIngressRule is an alias of AuthorizeSecurityGroupIngress
func (exo *Client) CreateIngressRule(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.AuthorizeSecurityGroupIngress(rule, async)
}

// AutorizeSecurityGroupIngress authorizes a particular ingress rule for this security group
func (exo *Client) AuthorizeSecurityGroupIngress(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.doSecurityGroupRule("authorize", "Ingress", rule, async)
}

func (exo *Client) doSecurityGroupRule(action string, kind string, rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	params := url.Values{}
	params.Set("securitygroupid", rule.SecurityGroupId)

	if rule.Cidr != "" {
		params.Set("cidrlist", rule.Cidr)
	} else if len(rule.UserSecurityGroupList) > 0 {
		for i, usg := range rule.UserSecurityGroupList {
			key := fmt.Sprintf("usersecuritygrouplist[%d]", i)
			params.Set(key+".account", usg.Account)
			params.Set(key+".group", usg.Group)
		}
	} else {
		return nil, fmt.Errorf("No CIDR or Security Group List provided")
	}

	params.Set("protocol", rule.Protocol)

	if rule.Protocol == "ICMP" {
		params.Set("icmpcode", fmt.Sprintf("%d", rule.IcmpCode))
		params.Set("icmptype", fmt.Sprintf("%d", rule.IcmpType))
	} else if rule.Protocol == "TCP" || rule.Protocol == "UDP" {
		params.Set("startport", fmt.Sprintf("%d", rule.StartPort))
		params.Set("endport", fmt.Sprintf("%d", rule.EndPort))
	} else {
		return nil, fmt.Errorf("Invalid rule Protocol: %s", rule.Protocol)
	}

	resp, err := exo.AsyncRequest(action+"SecurityGroup"+kind, params, async)
	if err != nil {
		return nil, err
	}

	var r SecurityGroupRuleResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	return r.SecurityGroupRule, nil
}

func (exo *Client) CreateSecurityGroupWithRules(name string, ingress []SecurityGroupRule, egress []SecurityGroupRule, async AsyncInfo) (*CreateSecurityGroupResponse, error) {

	params := url.Values{}
	params.Set("name", name)

	resp, err := exo.Request("createSecurityGroup", params)

	var r CreateSecurityGroupResponseWrapper
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	if err != nil {
		return nil, err
	}

	sgid := r.Wrapped.Id

	for _, erule := range egress {
		erule.SecurityGroupId = sgid
		_, err = exo.CreateEgressRule(erule, async)
		if err != nil {
			return nil, err
		}
	}

	for _, inrule := range ingress {
		inrule.SecurityGroupId = sgid
		_, err = exo.CreateIngressRule(inrule, async)
		if err != nil {
			return nil, err
		}
	}

	return &r.Wrapped, nil
}

func (exo *Client) DeleteSecurityGroup(name string) error {
	params := url.Values{}
	params.Set("name", name)

	resp, err := exo.Request("deleteSecurityGroup", params)
	if err != nil {
		return err
	}

	fmt.Printf("## response: %+v\n", resp)
	return nil
}
<commit_msg>typo<commit_after>package egoscale

import (
	"encoding/json"
	"fmt"
	"net/url"
)

// CreateEgressRule is an alias of AuthorizeSecurityGroupEgress
func (exo *Client) CreateEgressRule(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.AuthorizeSecurityGroupEgress(rule, async)
}

// AuthorizeSecurityGroupEgress authorizes a particular egress rule for this security group
func (exo *Client) AuthorizeSecurityGroupEgress(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.doSecurityGroupRule("authorize", "Egress", rule, async)
}

// CreateIngressRule is an alias of AuthorizeSecurityGroupIngress
func (exo *Client) CreateIngressRule(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.AuthorizeSecurityGroupIngress(rule, async)
}

// AuthorizeSecurityGroupIngress authorizes a particular ingress rule for this security group
func (exo *Client) AuthorizeSecurityGroupIngress(rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	return exo.doSecurityGroupRule("authorize", "Ingress", rule, async)
}

func (exo *Client) doSecurityGroupRule(action string, kind string, rule SecurityGroupRule, async AsyncInfo) (*SecurityGroupRule, error) {
	params := url.Values{}
	params.Set("securitygroupid", rule.SecurityGroupId)

	if rule.Cidr != "" {
		params.Set("cidrlist", rule.Cidr)
	} else if len(rule.UserSecurityGroupList) > 0 {
		for i, usg := range rule.UserSecurityGroupList {
			key := fmt.Sprintf("usersecuritygrouplist[%d]", i)
			params.Set(key+".account", usg.Account)
			params.Set(key+".group", usg.Group)
		}
	} else {
		return nil, fmt.Errorf("No CIDR or Security Group List provided")
	}

	params.Set("protocol", rule.Protocol)

	if rule.Protocol == "ICMP" {
		params.Set("icmpcode", fmt.Sprintf("%d", rule.IcmpCode))
		params.Set("icmptype", fmt.Sprintf("%d", rule.IcmpType))
	} else if rule.Protocol == "TCP" || rule.Protocol == "UDP" {
		params.Set("startport", fmt.Sprintf("%d", rule.StartPort))
		params.Set("endport", fmt.Sprintf("%d", rule.EndPort))
	} else {
		return nil, fmt.Errorf("Invalid rule Protocol: %s", rule.Protocol)
	}

	resp, err := exo.AsyncRequest(action+"SecurityGroup"+kind, params, async)
	if err != nil {
		return nil, err
	}

	var r SecurityGroupRuleResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	return r.SecurityGroupRule, nil
}

func (exo *Client) CreateSecurityGroupWithRules(name string, ingress []SecurityGroupRule, egress []SecurityGroupRule, async AsyncInfo) (*CreateSecurityGroupResponse, error) {

	params := url.Values{}
	params.Set("name", name)

	resp, err := exo.Request("createSecurityGroup", params)

	var r CreateSecurityGroupResponseWrapper
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	if err != nil {
		return nil, err
	}

	sgid := r.Wrapped.Id

	for _, erule := range egress {
		erule.SecurityGroupId = sgid
		_, err = exo.CreateEgressRule(erule, async)
		if err != nil {
			return nil, err
		}
	}

	for _, inrule := range ingress {
		inrule.SecurityGroupId = sgid
		_, err = exo.CreateIngressRule(inrule, async)
		if err != nil {
			return nil, err
		}
	}

	return &r.Wrapped, nil
}

func (exo *Client) DeleteSecurityGroup(name string) error {
	params := url.Values{}
	params.Set("name", name)

	resp, err := exo.Request("deleteSecurityGroup", params)
	if err != nil {
		return err
	}

	fmt.Printf("## response: %+v\n", resp)
	return nil
}
<|endoftext|>


<commit_before>package senso

import (
	"context"
	"errors"
	"io"
	"net"
	"time"

	"github.com/sirupsen/logrus"
)

// connectTCP creates a persistent tcp connection to address
func connectTCP(ctx context.Context, baseLogger *logrus.Entry, address string, data chan []byte) {
	var dialer net.Dialer

	var log = baseLogger.WithField("address", address)

	// loop to retry connection
	for {
		// attempt to open a new connection
		dialer.Deadline = time.Now().Add(1 * time.Second)
		log.Info("dialing")
		conn, connErr := dialer.DialContext(ctx, "tcp", address)

		if connErr != nil {
			log.WithError(connErr).Info("dial failed")
		} else {

			log.Info("connected")

			// Close connection if we break or return
			defer conn.Close()

			// create channel for reading data and go read
			readChannel := make(chan []byte)
			go tcpReader(log, conn, readChannel)

			// create channel for writing data
			writeChannel := make(chan []byte)
			// We need an additional channel for handling write errors, unlike the readChannel we don't want to close the channel as somebody might try to write to it
			writeErrors := make(chan error)
			defer close(writeChannel)
			go tcpWriter(conn, writeChannel, writeErrors)

			// Inner loop for handling data
		DataLoop:
			for {
				select {

				case <-ctx.Done():
					return

				case receivedData, more := <-readChannel:
					if more {
						// Attempt to send data, if can not send immediately discard
						select {
						case data <- receivedData:
						default:
						}
					} else {
						close(writeChannel)
						break DataLoop
					}

				case dataToWrite := <-data:
					writeChannel <- dataToWrite

				case writeError := <-writeErrors:
					if err, ok := writeError.(net.Error); ok && err.Timeout() {
						log.Debug("timeout")
					} else {
						log.WithError(writeError).Error("write error")
						close(writeChannel)
						break DataLoop
					}
				}
			}

		}
		// Check if connection has been cancelled
		select {
		case <-ctx.Done():
			return
		default:
			// Sleep 5s before reattempting to reconnect
			time.Sleep(5 * time.Second)
		}

	}
}

// Helper to read from TCP connection
func tcpReader(log *logrus.Entry, conn net.Conn, channel chan<- []byte) {

	defer close(channel)

	buffer := make([]byte, 1024)

	// Loop and read from connection.
	for {
		// conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
		readN, readErr := conn.Read(buffer)

		if readErr != nil {
			if readErr == io.EOF {
				// connection is closed
				log.Info("connection closed")
				return
			} else if err, ok := readErr.(net.Error); ok && err.Timeout() {
				// Read timeout, just continue Nothing
			} else {
				log.WithError(readErr).Error("read error")
				return
			}
		} else {
			channel <- buffer[:readN]
		}
	}
}

// Helper to write to TCP connection. Note that this requires an additional channel to report errors
func tcpWriter(conn net.Conn, channel <-chan []byte, errorChannel chan<- error) {
	for {

		dataToWrite, more := <-channel

		if more {

			if conn != nil {
				conn.SetWriteDeadline(time.Now().Add(50 * time.Millisecond))
				_, err := conn.Write(dataToWrite)

				if err != nil {
					errorChannel <- err
				}

			} else {
				errorChannel <- errors.New("not connected, can not write to TCP connection")
			}

		} else {
			return
		}

	}
}
<commit_msg>Move timeouts to constants<commit_after>package senso

import (
	"context"
	"errors"
	"io"
	"net"
	"time"

	"github.com/sirupsen/logrus"
)

// TODO: implement a backoff strategy
const dialTimeout = 1 * time.Second
const retryTimeout = 5 * time.Second

// connectTCP creates a persistent tcp connection to address
func connectTCP(ctx context.Context, baseLogger *logrus.Entry, address string, data chan []byte) {
	var dialer net.Dialer

	var log = baseLogger.WithField("address", address)

	// loop to retry connection
	for {
		// attempt to open a new connection
		dialer.Deadline = time.Now().Add(dialTimeout)
		log.Info("dialing")
		conn, connErr := dialer.DialContext(ctx, "tcp", address)

		if connErr != nil {
			log.WithError(connErr).Info("dial failed")
		} else {

			log.Info("connected")

			// Close connection if we break or return
			defer conn.Close()

			// create channel for reading data and go read
			readChannel := make(chan []byte)
			go tcpReader(log, conn, readChannel)

			// create channel for writing data
			writeChannel := make(chan []byte)
			// We need an additional channel for handling write errors, unlike the readChannel we don't want to close the channel as somebody might try to write to it
			writeErrors := make(chan error)
			defer close(writeChannel)
			go tcpWriter(conn, writeChannel, writeErrors)

			// Inner loop for handling data
		DataLoop:
			for {
				select {

				case <-ctx.Done():
					return

				case receivedData, more := <-readChannel:
					if more {
						// Attempt to send data, if can not send immediately discard
						select {
						case data <- receivedData:
						default:
						}
					} else {
						close(writeChannel)
						break DataLoop
					}

				case dataToWrite := <-data:
					writeChannel <- dataToWrite

				case writeError := <-writeErrors:
					if err, ok := writeError.(net.Error); ok && err.Timeout() {
						log.Debug("timeout")
					} else {
						log.WithError(writeError).Error("write error")
						close(writeChannel)
						break DataLoop
					}
				}
			}

		}
		// Check if connection has been cancelled
		select {
		case <-ctx.Done():
			return
		default:
			// Sleep 5s before reattempting to reconnect
			time.Sleep(retryTimeout)
		}

	}
}

// Helper to read from TCP connection
func tcpReader(log *logrus.Entry, conn net.Conn, channel chan<- []byte) {

	defer close(channel)

	buffer := make([]byte, 1024)

	// Loop and read from connection.
	for {
		// conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
		readN, readErr := conn.Read(buffer)

		if readErr != nil {
			if readErr == io.EOF {
				// connection is closed
				log.Info("connection closed")
				return
			} else if err, ok := readErr.(net.Error); ok && err.Timeout() {
				// Read timeout, just continue Nothing
			} else {
				log.WithError(readErr).Error("read error")
				return
			}
		} else {
			channel <- buffer[:readN]
		}
	}
}

// Helper to write to TCP connection. Note that this requires an additional channel to report errors
func tcpWriter(conn net.Conn, channel <-chan []byte, errorChannel chan<- error) {
	for {

		dataToWrite, more := <-channel

		if more {

			if conn != nil {
				conn.SetWriteDeadline(time.Now().Add(50 * time.Millisecond))
				_, err := conn.Write(dataToWrite)

				if err != nil {
					errorChannel <- err
				}

			} else {
				errorChannel <- errors.New("not connected, can not write to TCP connection")
			}

		} else {
			return
		}

	}
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

package main

import (
	"fmt"
	"os/exec"
	"path"

	"github.com/pkg/errors"
	"k8s.io/minikube/pkg/minikube/download"
)

func uploadTarball(tarballFilename, k8sVer string) error {
	// Upload tarball to GCS
	hostPath := path.Join("out/", tarballFilename)
	gcsDest := fmt.Sprintf("gs://%s/%s/%s", download.PreloadBucket, download.PreloadVersion, k8sVer)
	cmd := exec.Command("gsutil", "cp", hostPath, gcsDest)
	fmt.Printf("Running: %v\n", cmd.Args)
	if output, err := cmd.CombinedOutput(); err != nil {
		return errors.Wrapf(err, "uploading %s to GCS bucket: %v\n%s", hostPath, err, string(output))
	}
	return nil
}
<commit_msg>add trailing slash to bucket destination to indicate folder<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

package main

import (
	"fmt"
	"os/exec"
	"path"

	"github.com/pkg/errors"
	"k8s.io/minikube/pkg/minikube/download"
)

func uploadTarball(tarballFilename, k8sVer string) error {
	// Upload tarball to GCS
	hostPath := path.Join("out/", tarballFilename)
	gcsDest := fmt.Sprintf("gs://%s/%s/%s/", download.PreloadBucket, download.PreloadVersion, k8sVer)
	cmd := exec.Command("gsutil", "cp", hostPath, gcsDest)
	fmt.Printf("Running: %v\n", cmd.Args)
	if output, err := cmd.CombinedOutput(); err != nil {
		return errors.Wrapf(err, "uploading %s to GCS bucket: %v\n%s", hostPath, err, string(output))
	}
	return nil
}
<|endoftext|>


<commit_before>// Package apexlogs implements a handler for Apex Logs.
package apexlogs

import (
	"sync"

	"github.com/apex/log"
	"github.com/apex/logs/go/logs"
)

// TODO: periodic buffering

var levelMap = map[log.Level]string{
	log.DebugLevel: "debug",
	log.InfoLevel:  "info",
	log.WarnLevel:  "warning",
	log.ErrorLevel: "error",
	log.FatalLevel: "emergency",
}

// Handler implementation.
type Handler struct {
	// URL is the endpoint for your Apex Logs deployment API.
	URL string

	// ProjectID is the id of the project that you are collecting logs for.
	ProjectID string

	// buffer
	mu     sync.Mutex
	buffer []logs.Event

	// client
	once sync.Once
	c    logs.Client
}

// HandleLog implements log.Handler.
func (h *Handler) HandleLog(e *log.Entry) error {
	// initialize client
	h.once.Do(func() {
		h.c = logs.Client{
			URL: h.URL,
		}
	})

	// create event
	event := logs.Event{
		Level:     levelMap[e.Level],
		Message:   e.Message,
		Fields:    map[string]interface{}(e.Fields),
		Timestamp: e.Timestamp,
	}

	// buffer event
	h.mu.Lock()
	h.buffer = append(h.buffer, event)
	h.mu.Unlock()

	return nil
}

// Events returns the buffered events, and clears the buffer.
func (h *Handler) Events() (events []logs.Event) {
	h.mu.Lock()
	events = h.buffer
	h.buffer = nil
	h.mu.Unlock()
	return
}

// Flush all buffered logs.
func (h *Handler) Flush() error {
	return h.c.AddEvents(logs.AddEventsInput{
		ProjectID: h.ProjectID,
		Events:    h.Events(),
	})
}
<commit_msg>add events len check before flushing to apexlogs handler<commit_after>// Package apexlogs implements a handler for Apex Logs.
package apexlogs

import (
	"sync"

	"github.com/apex/log"
	"github.com/apex/logs/go/logs"
)

// TODO: periodic buffering

var levelMap = map[log.Level]string{
	log.DebugLevel: "debug",
	log.InfoLevel:  "info",
	log.WarnLevel:  "warning",
	log.ErrorLevel: "error",
	log.FatalLevel: "emergency",
}

// Handler implementation.
type Handler struct {
	// URL is the endpoint for your Apex Logs deployment API.
	URL string

	// ProjectID is the id of the project that you are collecting logs for.
	ProjectID string

	// buffer
	mu     sync.Mutex
	buffer []logs.Event

	// client
	once sync.Once
	c    logs.Client
}

// HandleLog implements log.Handler.
func (h *Handler) HandleLog(e *log.Entry) error {
	// initialize client
	h.once.Do(func() {
		h.c = logs.Client{
			URL: h.URL,
		}
	})

	// create event
	event := logs.Event{
		Level:     levelMap[e.Level],
		Message:   e.Message,
		Fields:    map[string]interface{}(e.Fields),
		Timestamp: e.Timestamp,
	}

	// buffer event
	h.mu.Lock()
	h.buffer = append(h.buffer, event)
	h.mu.Unlock()

	return nil
}

// Events returns the buffered events, and clears the buffer.
func (h *Handler) Events() (events []logs.Event) {
	h.mu.Lock()
	events = h.buffer
	h.buffer = nil
	h.mu.Unlock()
	return
}

// Flush all buffered logs.
func (h *Handler) Flush() error {
	events := h.Events()

	if len(events) == 0 {
		return nil
	}

	return h.c.AddEvents(logs.AddEventsInput{
		ProjectID: h.ProjectID,
		Events:    events,
	})
}
<|endoftext|>


<commit_before>package instance

import (
	"crypto/tls"
	"fmt"
	"net/http"

	"github.com/pivotal-pez/cfmgo"
	"github.com/pivotal-pez/haas-broker/handlers"
)

//Put - handler function for put calls
func Put(collection cfmgo.Collection, dispenserCreds handlers.DispenserCreds) func(http.ResponseWriter, *http.Request) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	instanceCreator := &InstanceCreator{ClientDoer: client}
	instanceCreator.Collection = collection
	instanceCreator.Dispenser = dispenserCreds
	return instanceCreator.PutHandler
}

//Patch - handler function for patch calls
func Patch(collection cfmgo.Collection) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page!")
	}
}

//Delete - handler function for delete calls
func Delete(collection cfmgo.Collection) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page!")
	}
}

//Get - handler function for get calls
func Get(collection cfmgo.Collection, dispenserCreds handlers.DispenserCreds) func(http.ResponseWriter, *http.Request) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	instanceCreator := &InstanceCreator{ClientDoer: client}
	instanceCreator.Collection = collection
	instanceCreator.Dispenser = dispenserCreds
	return instanceCreator.GetHandler
}
<commit_msg>[#110117492] delete success value<commit_after>package instance

import (
	"crypto/tls"
	"fmt"
	"net/http"

	"github.com/pivotal-pez/cfmgo"
	"github.com/pivotal-pez/haas-broker/handlers"
)

//Put - handler function for put calls
func Put(collection cfmgo.Collection, dispenserCreds handlers.DispenserCreds) func(http.ResponseWriter, *http.Request) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	instanceCreator := &InstanceCreator{ClientDoer: client}
	instanceCreator.Collection = collection
	instanceCreator.Dispenser = dispenserCreds
	return instanceCreator.PutHandler
}

//Patch - handler function for patch calls
func Patch(collection cfmgo.Collection) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page!")
	}
}

//Delete - handler function for delete calls
func Delete(collection cfmgo.Collection) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "{}")
	}
}

//Get - handler function for get calls
func Get(collection cfmgo.Collection, dispenserCreds handlers.DispenserCreds) func(http.ResponseWriter, *http.Request) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	instanceCreator := &InstanceCreator{ClientDoer: client}
	instanceCreator.Collection = collection
	instanceCreator.Dispenser = dispenserCreds
	return instanceCreator.GetHandler
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"time"
)

var (
	delay    = flag.Duration("d", 0, "delay between updates")
	duration = flag.Duration("D", 0, "duration to output continually")

	pid   = flag.Int("p", 0, "process to inspect")
	pname = flag.String("n", "", "name of process to inspec")

	socketregex = regexp.MustCompile(`\.gmx\.[0-9]+\.0`)
)

type conn struct {
	net.Conn
	*json.Decoder
	*json.Encoder
}

func listGmxProcesses(f func(file string, args interface{})) {
	dir, err := os.Open(os.TempDir())
	if err != nil {
		log.Fatalf("unable to open %s: %v", os.TempDir(), err)
	}
	pids, err := dir.Readdirnames(0)
	if err != nil {
		log.Fatalf("unable to read pids: %v", err)
	}
	for _, pid := range pids {
		if socketregex.MatchString(pid) {
			c, err := dial(filepath.Join(os.TempDir(), pid))
			if err != nil {
				continue
			}
			defer c.Close()
			c.Encode([]string{"os.args"})
			var result = make(map[string]interface{})
			if err := c.Decode(&result); err != nil {
				log.Printf("unable to decode response from %s: %v", pid, err)
				continue
			}
			if args, ok := result["os.args"]; ok {
				f(pid, args)
			}
		}
	}
}

func findGmxProcess(pname string) int {
	var found int
	listGmxProcesses(func(file string, args interface{}) {
		if argslist, ok := args.([]interface{}); ok && len(argslist) >= 1 {
			name, ok := argslist[0].(string)
			if ok {
				if name == pname {
					str_pid := file[5 : len(file)-2] // ".gmx.####.0"
					numeric_pid, err := strconv.Atoi(str_pid)
					if err == nil {
						if found == 0 {
							fmt.Printf("Using %s\t%v\n", name, args)
							found = numeric_pid
						} else if found > 0 {
							fmt.Printf("Ambiguous situation. Both %d and %d could be %s. Use -p option\n", found, numeric_pid, pname)
							found = -1
						}
					}
				}
			}
		}
	})
	if found > 0 {
		return found
	}
	return 0
}

// fetchKeys returns all the registered keys from the process.
func fetchKeys(c *conn) []string {
	// retrieve list of registered keys
	if err := c.Encode([]string{"keys"}); err != nil {
		log.Fatalf("unable to send keys request to process: %v", err)
	}
	var result = make(map[string][]string)
	if err := c.Decode(&result); err != nil {
		log.Fatalf("unable to decode keys response: %v", err)
	}
	keys, ok := result["keys"]
	if !ok {
		log.Fatalf("gmx server did not return a keys list")
	}
	sort.Strings(keys)
	return keys
}

func main() {
	flag.Parse()
	if *pid == 0 && *pname != "" {
		*pid = findGmxProcess(*pname)
	}
	if *pid == 0 {
		listGmxProcesses(func(name string, args interface{}) { fmt.Printf("%s\t%v\n", name, args) })
		return
	}
	c, err := dial(filepath.Join(os.TempDir(), fmt.Sprintf(".gmx.%d.0", *pid)))
	if err != nil {
		log.Fatalf("unable to connect to process %d: %v", *pid, err)
	}
	defer c.Close()

	// match flag.Args() as regexps
	registeredKeys := fetchKeys(c)
	var keys []string
	if len(flag.Args()) == 0 {
		// no patterns? then you get everything
		keys = registeredKeys
	} else {
		for _, a := range flag.Args() {
			r, err := regexp.Compile(a)
			if err != nil {
				log.Fatal("unable to compile regex %v: %v", a, err)
			}
			for _, k := range registeredKeys {
				if r.MatchString(k) {
					keys = append(keys, k)
				}
			}
		}
	}

	deadline := time.Now().Add(*duration)
	for {
		if err := c.Encode(keys); err != nil {
			log.Fatalf("unable to send request to process: %v", err)
		}
		var result = make(map[string]interface{})
		if err := c.Decode(&result); err != nil {
			log.Fatalf("unable to decode response: %v", err)
		}
		for _, k := range keys {
			if v, ok := result[k]; ok {
				fmt.Printf("%s: %v\n", k, v)
			}
		}
		if time.Now().After(deadline) {
			return
		}
		time.Sleep(*delay)
		fmt.Println("----") // separator line
	}
}
<commit_msg>Add custom usage text to `gmxc -h` to help explain how to use this<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"time"
)

var (
	delay    = flag.Duration("d", 0, "delay between updates")
	duration = flag.Duration("D", 0, "duration to output continually")

	pid   = flag.Int("p", 0, "process to inspect")
	pname = flag.String("n", "", "name of process to inspec")

	socketregex = regexp.MustCompile(`\.gmx\.[0-9]+\.0`)
)

type conn struct {
	net.Conn
	*json.Decoder
	*json.Encoder
}

func listGmxProcesses(f func(file string, args interface{})) {
	dir, err := os.Open(os.TempDir())
	if err != nil {
		log.Fatalf("unable to open %s: %v", os.TempDir(), err)
	}
	pids, err := dir.Readdirnames(0)
	if err != nil {
		log.Fatalf("unable to read pids: %v", err)
	}
	for _, pid := range pids {
		if socketregex.MatchString(pid) {
			c, err := dial(filepath.Join(os.TempDir(), pid))
			if err != nil {
				continue
			}
			defer c.Close()
			c.Encode([]string{"os.args"})
			var result = make(map[string]interface{})
			if err := c.Decode(&result); err != nil {
				log.Printf("unable to decode response from %s: %v", pid, err)
				continue
			}
			if args, ok := result["os.args"]; ok {
				f(pid, args)
			}
		}
	}
}

func findGmxProcess(pname string) int {
	var found int
	listGmxProcesses(func(file string, args interface{}) {
		if argslist, ok := args.([]interface{}); ok && len(argslist) >= 1 {
			name, ok := argslist[0].(string)
			if ok {
				if name == pname {
					str_pid := file[5 : len(file)-2] // ".gmx.####.0"
					numeric_pid, err := strconv.Atoi(str_pid)
					if err == nil {
						if found == 0 {
							fmt.Printf("Using %s\t%v\n", name, args)
							found = numeric_pid
						} else if found > 0 {
							fmt.Printf("Ambiguous situation. Both %d and %d could be %s. Use -p option\n", found, numeric_pid, pname)
							found = -1
						}
					}
				}
			}
		}
	})
	if found > 0 {
		return found
	}
	return 0
}

// fetchKeys returns all the registered keys from the process.
func fetchKeys(c *conn) []string {
	// retrieve list of registered keys
	if err := c.Encode([]string{"keys"}); err != nil {
		log.Fatalf("unable to send keys request to process: %v", err)
	}
	var result = make(map[string][]string)
	if err := c.Decode(&result); err != nil {
		log.Fatalf("unable to decode keys response: %v", err)
	}
	keys, ok := result["keys"]
	if !ok {
		log.Fatalf("gmx server did not return a keys list")
	}
	sort.Strings(keys)
	return keys
}

func main() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:")
		fmt.Fprintf(os.Stderr, "  %s [OPTIONS] [REGEX PATTERN]*\n", os.Args[0])
		fmt.Fprintln(os.Stderr, "")
		fmt.Fprintln(os.Stderr, "Options:")
		flag.PrintDefaults()
	}
	flag.Parse()
	if *pid == 0 && *pname != "" {
		*pid = findGmxProcess(*pname)
	}
	if *pid == 0 {
		listGmxProcesses(func(name string, args interface{}) { fmt.Printf("%s\t%v\n", name, args) })
		return
	}
	c, err := dial(filepath.Join(os.TempDir(), fmt.Sprintf(".gmx.%d.0", *pid)))
	if err != nil {
		log.Fatalf("unable to connect to process %d: %v", *pid, err)
	}
	defer c.Close()

	// match flag.Args() as regexps
	registeredKeys := fetchKeys(c)
	var keys []string
	if len(flag.Args()) == 0 {
		// no patterns? then you get everything
		keys = registeredKeys
	} else {
		for _, a := range flag.Args() {
			r, err := regexp.Compile(a)
			if err != nil {
				log.Fatal("unable to compile regex %v: %v", a, err)
			}
			for _, k := range registeredKeys {
				if r.MatchString(k) {
					keys = append(keys, k)
				}
			}
		}
	}

	deadline := time.Now().Add(*duration)
	for {
		if err := c.Encode(keys); err != nil {
			log.Fatalf("unable to send request to process: %v", err)
		}
		var result = make(map[string]interface{})
		if err := c.Decode(&result); err != nil {
			log.Fatalf("unable to decode response: %v", err)
		}
		for _, k := range keys {
			if v, ok := result[k]; ok {
				fmt.Printf("%s: %v\n", k, v)
			}
		}
		if time.Now().After(deadline) {
			return
		}
		time.Sleep(*delay)
		fmt.Println("----") // separator line
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var (
	globalConf  = "/etc/dput.cf"
	peruserConf = filepath.Join(os.Getenv("HOME"), ".dput.cf")
)

func (t *task) dput() error {
	if err := runDput(t.WorkingDir, t.PPA, t.Output); err != nil {
		return err
	}
	return nil
}

func runDput(workingDir string, PPA string, output io.Writer) error {
	if err := checkPPA(PPA); err != nil {
		return err
	}

	var args = []string{"-d"}

	args = append(args, PPA)

	// FIXME: Generate .changes name instead of iterate working
	// dir
	changesFile := findChangesFile(workingDir)
	if changesFile == "" {
		return errors.New("Can not find .changes file")
	}
	// target := filepath.Join(workingDir, changesFile)
	// args = append(args, target)
	args = append(args, changesFile)

	cmd := exec.Command("dput", args...)
	cmd.Dir = workingDir
	cmd.Stdout = output
	cmd.Stderr = output

	return cmd.Run()
}

func checkPPA(PPA string) error {
	if strings.HasPrefix(PPA, "ppa:") {
		return nil
	}

	p3a := getPrivatePPA()
	for _, p := range p3a {
		if PPA == p {
			return nil
		}
	}

	return errors.New("unknown PPA")
}

func getPrivatePPA() (res []string) {
	res = make([]string, 10)

	// First, read global dput conf
	gf, err := os.Open(globalConf)
	if err != nil {
		goto peruser
	}
	defer gf.Close()

	res = append(res, getPrivatePPAFromConf(gf)...)

peruser:
	pf, err := os.Open(peruserConf)
	if err != nil {
		return res
	}
	defer pf.Close()

	res = append(res, getPrivatePPAFromConf(pf)...)

	return res
}

func getPrivatePPAFromConf(f *os.File) (res []string) {
	res = make([]string, 5)
	reader := bufio.NewReader(f)

	re := regexp.MustCompilePOSIX("^\\[(.+)\\]$")

	for {
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			break
		}
		if match := re.FindStringSubmatch(line); len(match) == 2 {
			res = append(res, match[1])
		}

		if err == io.EOF {
			break
		}
	}
	return res
}

func findChangesFile(workingDir string) string {
	fis, err := ioutil.ReadDir(workingDir)
	if err != nil {
		return ""
	}

	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}
		if strings.HasSuffix(fi.Name(), ".changes") {
			return fi.Name()
		}
	}

	return ""
}
<commit_msg>add -f arg to dput<commit_after>package main

import (
	"bufio"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var (
	globalConf  = "/etc/dput.cf"
	peruserConf = filepath.Join(os.Getenv("HOME"), ".dput.cf")
)

func (t *task) dput() error {
	if err := runDput(t.WorkingDir, t.PPA, t.Output); err != nil {
		return err
	}
	return nil
}

func runDput(workingDir string, PPA string, output io.Writer) error {
	if err := checkPPA(PPA); err != nil {
		return err
	}

	var args = []string{"-d"}

	args = append(args, "-f")

	args = append(args, PPA)

	// FIXME: Generate .changes name instead of iterate working
	// dir
	changesFile := findChangesFile(workingDir)
	if changesFile == "" {
		return errors.New("Can not find .changes file")
	}
	// target := filepath.Join(workingDir, changesFile)
	// args = append(args, target)
	args = append(args, changesFile)

	cmd := exec.Command("dput", args...)
	cmd.Dir = workingDir
	cmd.Stdout = output
	cmd.Stderr = output

	return cmd.Run()
}

func checkPPA(PPA string) error {
	if strings.HasPrefix(PPA, "ppa:") {
		return nil
	}

	p3a := getPrivatePPA()
	for _, p := range p3a {
		if PPA == p {
			return nil
		}
	}

	return errors.New("unknown PPA")
}

func getPrivatePPA() (res []string) {
	res = make([]string, 10)

	// First, read global dput conf
	gf, err := os.Open(globalConf)
	if err != nil {
		goto peruser
	}
	defer gf.Close()

	res = append(res, getPrivatePPAFromConf(gf)...)

peruser:
	pf, err := os.Open(peruserConf)
	if err != nil {
		return res
	}
	defer pf.Close()

	res = append(res, getPrivatePPAFromConf(pf)...)

	return res
}

func getPrivatePPAFromConf(f *os.File) (res []string) {
	res = make([]string, 5)
	reader := bufio.NewReader(f)

	re := regexp.MustCompilePOSIX("^\\[(.+)\\]$")

	for {
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			break
		}
		if match := re.FindStringSubmatch(line); len(match) == 2 {
			res = append(res, match[1])
		}

		if err == io.EOF {
			break
		}
	}
	return res
}

func findChangesFile(workingDir string) string {
	fis, err := ioutil.ReadDir(workingDir)
	if err != nil {
		return ""
	}

	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}
		if strings.HasSuffix(fi.Name(), ".changes") {
			return fi.Name()
		}
	}

	return ""
}
<|endoftext|>


<commit_before>package goini

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"regexp"
)

func Dump(i interface{}) (string, error) {
	s := new(bytes.Buffer)
	err := write(s, i)
	if err != nil {
		return "", err
	}
	return s.String(), nil
}

func write(w io.Writer, i interface{}) error {
	v := reflect.ValueOf(i)
	return writeValue(w, v, 0)
}

func writeValue(w io.Writer, v reflect.Value, deep int) error {
	if deep > 2 {
		return fmt.Errorf("not support nested map or struct more than 2 level")
	}
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		if err := encodeMap(w, v, deep+1); err != nil {
			return err
		}
	case reflect.Struct:
		if err := encodeStruct(w, v, deep+1); err != nil {
			return err
		}
	default:
		return fmt.Errorf("dump only support map and struct")
	}
	return nil
}

func isBaseKind(k reflect.Kind, includeBool bool) bool {
	switch k {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Float32,
		reflect.Float64,
		reflect.String:
		return true
	case reflect.Bool:
		return includeBool
	}
	return false
}

func parseTag(tag string) (string, []string) {
	splitter := regexp.MustCompile(`\s*,\s*`)
	commentSplitter := regexp.MustCompile(`\s*;\s*`)
	parts := splitter.Split(tag, 2)
	if len(parts) == 1 {
		return parts[0], nil
	}
	comments := commentSplitter.Split(parts[1], -1)
	return parts[0], comments
}

func writeSection(w io.Writer, name string) {
	fmt.Fprintf(w, "[%s]", name)
	fmt.Fprintln(w, "")
}

func writeComment(w io.Writer, comments []string) {
	if comments != nil {
		for _, c := range comments {
			fmt.Fprintln(w, ";", c)
		}
	}
}

func writeItem(w io.Writer, name string, comments []string, v reflect.Value, dumpSimpleType bool, deep int, addLine bool) (dumped bool, err error) {
	k := v.Type().Kind()
	if isBaseKind(k, true) {
		if dumpSimpleType {
			writeComment(w, comments)
			_, err = fmt.Fprintln(w, name, "=", v.Interface())
			dumped = true
		}
	} else if k == reflect.Slice {
		if dumpSimpleType {
			writeComment(w, comments)
			err = encodeSlice(w, name, v.Type().Elem().Kind(), v)
			dumped = true
		}
	} else if !dumpSimpleType {
		if addLine {
			fmt.Fprintln(w, "")
		}
		writeComment(w, comments)
		writeSection(w, name)
		err = writeValue(w, v, deep+1)
		dumped = true
	}
	return
}

func encodeMap(w io.Writer, v reflect.Value, deep int) (err error) {
	addLine, dumped := false, false
	for _, dumpType := range [2]bool{true, false} {
		for _, i := range v.MapKeys() {
			vv := v.MapIndex(i)
			if vv.Type().Kind() == reflect.Interface {
				vv = vv.Elem()
			}
			dumped, err = writeItem(w, i.String(), nil, vv, dumpType, deep, addLine)
			if err != nil {
				return
			}
			addLine = addLine || dumped
		}
	}
	return
}

func encodeSlice(w io.Writer, name string, k reflect.Kind, v reflect.Value) error {
	if !isBaseKind(k, false) {
		return fmt.Errorf("not support %s", v.Type())
	}
	fmt.Fprintf(w, "%s = ", name)
	for i := 0; i < v.Len(); i++ {
		if i > 0 {
			fmt.Fprint(w, ", ", v.Index(i).Interface())
		} else {
			fmt.Fprint(w, v.Index(i).Interface())
		}
	}
	fmt.Fprintln(w, "")
	return nil
}

func encodeStruct(w io.Writer, v reflect.Value, deep int) error {
	t := v.Type()
	addLine, dumped := false, false
	var err error
	for _, dumpType := range [2]bool{true, false} {
		for i := 0; i < t.NumField(); i++ {
			s := t.Field(i)
			name, comments := parseTag(s.Tag.Get("ini"))
			if name == "" {
				name = s.Name
			}
			if name == "-" || s.PkgPath != "" {
				continue
			}
			dumped, err = writeItem(w, name, comments, v.Field(i), dumpType, deep, addLine)
			if err != nil {
				return err
			}
			addLine = addLine || dumped
		}
	}
	return nil
}
<commit_msg>check for exported fields in embedded structs, according to https://tip.golang.org/doc/go1.6#reflect<commit_after>package goini

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"regexp"
)

func Dump(i interface{}) (string, error) {
	s := new(bytes.Buffer)
	err := write(s, i)
	if err != nil {
		return "", err
	}
	return s.String(), nil
}

func write(w io.Writer, i interface{}) error {
	v := reflect.ValueOf(i)
	return writeValue(w, v, 0)
}

func writeValue(w io.Writer, v reflect.Value, deep int) error {
	if deep > 2 {
		return fmt.Errorf("not support nested map or struct more than 2 level")
	}
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		if err := encodeMap(w, v, deep+1); err != nil {
			return err
		}
	case reflect.Struct:
		if err := encodeStruct(w, v, deep+1); err != nil {
			return err
		}
	default:
		return fmt.Errorf("dump only support map and struct")
	}
	return nil
}

func isBaseKind(k reflect.Kind, includeBool bool) bool {
	switch k {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Float32,
		reflect.Float64,
		reflect.String:
		return true
	case reflect.Bool:
		return includeBool
	}
	return false
}

func parseTag(tag string) (string, []string) {
	splitter := regexp.MustCompile(`\s*,\s*`)
	commentSplitter := regexp.MustCompile(`\s*;\s*`)
	parts := splitter.Split(tag, 2)
	if len(parts) == 1 {
		return parts[0], nil
	}
	comments := commentSplitter.Split(parts[1], -1)
	return parts[0], comments
}

func writeSection(w io.Writer, name string) {
	fmt.Fprintf(w, "[%s]", name)
	fmt.Fprintln(w, "")
}

func writeComment(w io.Writer, comments []string) {
	if comments != nil {
		for _, c := range comments {
			fmt.Fprintln(w, ";", c)
		}
	}
}

func writeItem(w io.Writer, name string, comments []string, v reflect.Value, dumpSimpleType bool, deep int, addLine bool) (dumped bool, err error) {
	k := v.Type().Kind()
	if isBaseKind(k, true) {
		if dumpSimpleType {
			writeComment(w, comments)
			_, err = fmt.Fprintln(w, name, "=", v.Interface())
			dumped = true
		}
	} else if k == reflect.Slice {
		if dumpSimpleType {
			writeComment(w, comments)
			err = encodeSlice(w, name, v.Type().Elem().Kind(), v)
			dumped = true
		}
	} else if !dumpSimpleType {
		if addLine {
			fmt.Fprintln(w, "")
		}
		writeComment(w, comments)
		writeSection(w, name)
		err = writeValue(w, v, deep+1)
		dumped = true
	}
	return
}

func encodeMap(w io.Writer, v reflect.Value, deep int) (err error) {
	addLine, dumped := false, false
	for _, dumpType := range [2]bool{true, false} {
		for _, i := range v.MapKeys() {
			vv := v.MapIndex(i)
			if vv.Type().Kind() == reflect.Interface {
				vv = vv.Elem()
			}
			dumped, err = writeItem(w, i.String(), nil, vv, dumpType, deep, addLine)
			if err != nil {
				return
			}
			addLine = addLine || dumped
		}
	}
	return
}

func encodeSlice(w io.Writer, name string, k reflect.Kind, v reflect.Value) error {
	if !isBaseKind(k, false) {
		return fmt.Errorf("not support %s", v.Type())
	}
	fmt.Fprintf(w, "%s = ", name)
	for i := 0; i < v.Len(); i++ {
		if i > 0 {
			fmt.Fprint(w, ", ", v.Index(i).Interface())
		} else {
			fmt.Fprint(w, v.Index(i).Interface())
		}
	}
	fmt.Fprintln(w, "")
	return nil
}

func encodeStruct(w io.Writer, v reflect.Value, deep int) error {
	t := v.Type()
	addLine, dumped := false, false
	var err error
	for _, dumpType := range [2]bool{true, false} {
		for i := 0; i < t.NumField(); i++ {
			s := t.Field(i)
			name, comments := parseTag(s.Tag.Get("ini"))
			if name == "" {
				name = s.Name
			}
			if name == "-" || (s.PkgPath != "" && !s.Anonymous) {
				continue
			}
			dumped, err = writeItem(w, name, comments, v.Field(i), dumpType, deep, addLine)
			if err != nil {
				return err
			}
			addLine = addLine || dumped
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/ClusterHQ/dvol/cmd"
	"os"
	//    "github.com/ClusterHQ/dvol/dockercontainers"
	//    "github.com/ClusterHQ/dvol/plugin"
)

func main() {
	if err := cmd.RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}
<commit_msg>lowercase import for godep - godep will treat ClusterHQ and clusterhq as two seperate paths and include the lowercased one in dependancies<commit_after>package main

import (
	"fmt"
	"github.com/clusterhq/dvol/cmd"
	"os"
	//    "github.com/ClusterHQ/dvol/dockercontainers"
	//    "github.com/ClusterHQ/dvol/plugin"
)

func main() {
	if err := cmd.RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}
<|endoftext|>


<commit_before>// +build 386 arm armbe arm64 mips mipsle mips64p32 mips64p32le ppc ppc64 ppc64le sparc

/*
 * Copyright 2020 Dgraph Labs, Inc. and Contributors
 *
 * 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 simd

// Search uses the Clever search to find the correct key.
func Search(xs []uint64, k uint64) int16 {
	if len(xs) < 8 {
		return Naive(xs, k)
	}
	var twos, pk [4]uint64
	pk[0] = k
	pk[1] = k
	pk[2] = k
	pk[3] = k
	for i := 0; i < len(xs); i += 8 {
		twos[0] = xs[i]
		twos[1] = xs[i+2]
		twos[2] = xs[i+4]
		twos[3] = xs[i+6]
		if twos[0] >= pk[0] {
			return int16(i / 2)
		}
		if twos[1] >= pk[1] {
			return int16((i + 2) / 2)
		}
		if twos[2] >= pk[2] {
			return int16((i + 4) / 2)
		}
		if twos[3] >= pk[3] {
			return int16((i + 6) / 2)
		}

	}
	return int16(len(xs) / 2)
}
<commit_msg>fix (build): build search.go for all architectures (#257)<commit_after>// +build !amd64

/*
 * Copyright 2020 Dgraph Labs, Inc. and Contributors
 *
 * 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 simd

// Search uses the Clever search to find the correct key.
func Search(xs []uint64, k uint64) int16 {
	if len(xs) < 8 {
		return Naive(xs, k)
	}
	var twos, pk [4]uint64
	pk[0] = k
	pk[1] = k
	pk[2] = k
	pk[3] = k
	for i := 0; i < len(xs); i += 8 {
		twos[0] = xs[i]
		twos[1] = xs[i+2]
		twos[2] = xs[i+4]
		twos[3] = xs[i+6]
		if twos[0] >= pk[0] {
			return int16(i / 2)
		}
		if twos[1] >= pk[1] {
			return int16((i + 2) / 2)
		}
		if twos[2] >= pk[2] {
			return int16((i + 4) / 2)
		}
		if twos[3] >= pk[3] {
			return int16((i + 6) / 2)
		}

	}
	return int16(len(xs) / 2)
}
<|endoftext|>


<commit_before>package squad

import (
	"fmt"
	"github.com/sqdron/squad/activation"
	"github.com/sqdron/squad/connect"
	"log"
	"os"
	"os/signal"
	"sync"
)

func (s *squad) Activate(cb ...func(activation.ServiceInfo)) {
	s.Connect = connect.NatsTransport(s.options.Hub)

	act := activation.RequestActivation{ID: s.options.Name, Actions: s.Api.getMetadata()}
	restartApi := func(info activation.ServiceInfo) bool {
		log.Println("Activation complited!")
		s.Api.start(&info)
		if len(cb) > 0 {
			cb[0](info)
		}
		return true
	}
	s.Connect.Request("activate", act, restartApi)
	s.start()
}

func (s *squad) RunDetached() {
	fmt.Println("Running detached...")
	s.Api.start(&activation.ServiceInfo{Group: "", Endpoint: s.options.Hub})
	s.start()
}

func (s *squad) start() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	wg := sync.WaitGroup{}
	defer wg.Wait()
	wg.Add(1)
	go func() {
		for {
			select {
			case <-c:
				fmt.Println("Interrupting...")
				wg.Done()
				os.Exit(1)
			}
		}
	}()
	wg.Wait()
}
<commit_msg>Sqdron deployment configuration<commit_after>package squad

import (
	"fmt"
	"github.com/sqdron/squad/activation"
	"github.com/sqdron/squad/connect"
	"log"
	"os"
	"os/signal"
	"sync"
)

func (s *squad) Activate(cb ...func(activation.ServiceInfo)) {
	fmt.Println(s.options.Hub)
	s.Connect = connect.NatsTransport(s.options.Hub)

	act := activation.RequestActivation{ID: s.options.Name, Actions: s.Api.getMetadata()}
	restartApi := func(info activation.ServiceInfo) bool {
		log.Println("Activation complited!")
		s.Api.start(&info)
		if len(cb) > 0 {
			cb[0](info)
		}
		return true
	}
	s.Connect.Request("activate", act, restartApi)
	s.start()
}

func (s *squad) RunDetached() {
	fmt.Println("Running detached...")
	s.Api.start(&activation.ServiceInfo{Group: "", Endpoint: s.options.Hub})
	s.start()
}

func (s *squad) start() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	wg := sync.WaitGroup{}
	defer wg.Wait()
	wg.Add(1)
	go func() {
		for {
			select {
			case <-c:
				fmt.Println("Interrupting...")
				wg.Done()
				os.Exit(1)
			}
		}
	}()
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

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

	"github.com/hawx/serve"
	"hawx.me/code/route"
)

var (
	port   = flag.String("port", "8080", "")
	socket = flag.String("socket", "", "")
)

type Any interface{}
type Json map[string]Any

func createResponseBody(r *http.Request) string {
	err := r.ParseForm()
	if err != nil {
		log.Println("form:", err)
	}

	form := Json{}
	for k, v := range r.Form {
		form[k] = v
	}

	headers := Json{}
	for k, v := range r.Header {
		headers[k] = strings.Join(v, ", ")
	}

	body, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		log.Println("body:", err)
	}

	j := Json{
		"method":  r.Method,
		"url":     r.Host + r.URL.String(),
		"version": r.Proto,
		"headers": headers,
		"body":    string(body),
		"form":    form,
	}

	b, err := json.MarshalIndent(j, "", "  ")
	if err != nil {
		log.Println("json:", err)
		return ""
	}

	return string(b) + "\n"
}

func main() {
	flag.Parse()

	route.HandleFunc("/delay/:ms/*path", func(w http.ResponseWriter, r *http.Request) {
		ms, err := strconv.ParseInt(route.Vars(r)["ms"], 10, 64)
		if err != nil {
			log.Println(err)
			return
		}

		time.Sleep(time.Duration(ms) * time.Millisecond)
		fmt.Fprintf(w, createResponseBody(r))
	})

	route.HandleFunc("/code/:code/*path", func(w http.ResponseWriter, r *http.Request) {
		code, err := strconv.ParseInt(route.Vars(r)["code"], 10, 0)
		if err != nil {
			log.Println(err)
			return
		}

		w.WriteHeader(int(code))
		fmt.Fprint(w, createResponseBody(r))
	})

	route.HandleFunc("/*path", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, createResponseBody(r))
	})

	serve.Serve(*port, *socket, route.Default)
}
<commit_msg>Move to hawx.me/code/echo<commit_after>package main

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

	"hawx.me/code/route"
	"hawx.me/code/serve"
)

var (
	port   = flag.String("port", "8080", "")
	socket = flag.String("socket", "", "")
)

type Any interface{}
type Json map[string]Any

func createResponseBody(r *http.Request) string {
	err := r.ParseForm()
	if err != nil {
		log.Println("form:", err)
	}

	form := Json{}
	for k, v := range r.Form {
		form[k] = v
	}

	headers := Json{}
	for k, v := range r.Header {
		headers[k] = strings.Join(v, ", ")
	}

	body, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		log.Println("body:", err)
	}

	j := Json{
		"method":  r.Method,
		"url":     r.Host + r.URL.String(),
		"version": r.Proto,
		"headers": headers,
		"body":    string(body),
		"form":    form,
	}

	b, err := json.MarshalIndent(j, "", "  ")
	if err != nil {
		log.Println("json:", err)
		return ""
	}

	return string(b) + "\n"
}

func main() {
	flag.Parse()

	route.HandleFunc("/delay/:ms/*path", func(w http.ResponseWriter, r *http.Request) {
		ms, err := strconv.ParseInt(route.Vars(r)["ms"], 10, 64)
		if err != nil {
			log.Println(err)
			return
		}

		time.Sleep(time.Duration(ms) * time.Millisecond)
		fmt.Fprintf(w, createResponseBody(r))
	})

	route.HandleFunc("/code/:code/*path", func(w http.ResponseWriter, r *http.Request) {
		code, err := strconv.ParseInt(route.Vars(r)["code"], 10, 0)
		if err != nil {
			log.Println(err)
			return
		}

		w.WriteHeader(int(code))
		fmt.Fprint(w, createResponseBody(r))
	})

	route.HandleFunc("/*path", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, createResponseBody(r))
	})

	serve.Serve(*port, *socket, route.Default)
}
<|endoftext|>


<commit_before>// +build linux darwin freebsd netbsd openbsd

package password

import (
	"fmt"
	"os"

	"golang.org/x/crypto/ssh/terminal"
)

func read(f *os.File) (string, error) {
	fd := int(f.Fd())
	if !terminal.IsTerminal(fd) {
		return "", fmt.Errorf("file descriptor %d is not a terminal", fd)
	}

	oldState, err := terminal.MakeRaw(fd)
	if err != nil {
		return "", err
	}
	defer terminal.Restore(fd, oldState)

	return readline(f)
}
<commit_msg>Allow to build on DragonFlyBSD (#5950)<commit_after>// +build linux darwin freebsd netbsd openbsd dragonfly

package password

import (
	"fmt"
	"os"

	"golang.org/x/crypto/ssh/terminal"
)

func read(f *os.File) (string, error) {
	fd := int(f.Fd())
	if !terminal.IsTerminal(fd) {
		return "", fmt.Errorf("file descriptor %d is not a terminal", fd)
	}

	oldState, err := terminal.MakeRaw(fd)
	if err != nil {
		return "", err
	}
	defer terminal.Restore(fd, oldState)

	return readline(f)
}
<|endoftext|>


<commit_before>package router

import (
	"strconv"
	"strings"

	"github.com/nanobox-io/golang-portal-client"

	"github.com/nanobox-io/nanobox-boxfile"
	"github.com/nanobox-io/nanobox/models"
)

// Update the ports that portal knows about.
func BuildServices(appModel *models.App) []portal.Service {
	services := []portal.Service{}
	boxfile := loadBoxfile(appModel)
	//
	for _, node := range boxfile.Nodes("code") {
		component, err := models.FindComponentBySlug(appModel.ID, node)
		if err != nil {
			continue // unable to get the component
		}

		//
		for _, service := range buildComponentServices(boxfile.Node(node), component) {

			if duplicateService(services, service) {
				continue // if there is a duplicate port we will just contine
			}

			// add the new service to the list of services
			services = append(services, service)
		}
	}

	// send to portal
	return services
}

// buildService builds all the tcp and udp port forwarding services
// it does not take into account any routing or information
func buildComponentServices(boxfile boxfile.Boxfile, component *models.Component) []portal.Service {

	portServices := []portal.Service{}

	//
	for protocol, protocolMap := range ports(boxfile) {
		for from, to := range protocolMap {
			fromInt, _ := strconv.Atoi(from)
			toInt, _ := strconv.Atoi(to)
			portService := portal.Service{
				Interface: "eth0",
				Port:      fromInt,
				Type:      protocol,
				Scheduler: "rr",
				Servers: []portal.Server{
					{
						Host:      component.IPAddr(),
						Port:      toInt,
						Forwarder: "m",
						Weight:    1,
					},
				},
			}

			portServices = append(portServices, portService)
		}
	}

	return portServices
}

// duplicateService ...
func duplicateService(services []portal.Service, service portal.Service) bool {
	for _, existingService := range services {
		if existingService.Port == service.Port {
			return true
		}
	}
	return false
}

// ports ...
func ports(box boxfile.Boxfile) map[string]map[string]string {
	// we allow tcp and udp ports
	rtn := map[string]map[string]string{
		"tcp": {},
		"udp": {},
	}

	// get the boxfiles ports section
	ports, ok := box.Value("ports").([]interface{})
	if !ok {
		return rtn
	}

	// loop through the given ports and create hash data
	// for each one.
	for _, port := range ports {
		p, ok := port.(string)
		if ok {
			portParts := strings.Split(p, ":")
			switch len(portParts) {
			case 1:
				rtn["tcp"][portParts[0]] = portParts[0]
			case 2:
				rtn["tcp"][portParts[0]] = portParts[1]
			case 3:
				// the first part needs to be tcp or udp
				// if it is neither we just assume tcp
				switch portParts[0] {
				case "udp":
					rtn[portParts[0]][portParts[1]] = portParts[2]
				case "tcp":
					rtn["tcp"][portParts[1]] = portParts[2]
				default:
					display.BadPortType(portParts[0])
					rtn["tcp"][portParts[1]] = portParts[2]
				}

			}
		}
		// if only a number is provided we assume tcp:num:num
		portInt, ok := port.(int)
		if ok {
			rtn["tcp"][strconv.Itoa(portInt)] = strconv.Itoa(portInt)
		}

	}

	return rtn
}
<commit_msg>add imports<commit_after>package router

import (
	"strconv"
	"strings"

	"github.com/nanobox-io/golang-portal-client"

	"github.com/nanobox-io/nanobox-boxfile"
	"github.com/nanobox-io/nanobox/util/display"
	"github.com/nanobox-io/nanobox/models"
)

// Update the ports that portal knows about.
func BuildServices(appModel *models.App) []portal.Service {
	services := []portal.Service{}
	boxfile := loadBoxfile(appModel)
	//
	for _, node := range boxfile.Nodes("code") {
		component, err := models.FindComponentBySlug(appModel.ID, node)
		if err != nil {
			continue // unable to get the component
		}

		//
		for _, service := range buildComponentServices(boxfile.Node(node), component) {

			if duplicateService(services, service) {
				continue // if there is a duplicate port we will just contine
			}

			// add the new service to the list of services
			services = append(services, service)
		}
	}

	// send to portal
	return services
}

// buildService builds all the tcp and udp port forwarding services
// it does not take into account any routing or information
func buildComponentServices(boxfile boxfile.Boxfile, component *models.Component) []portal.Service {

	portServices := []portal.Service{}

	//
	for protocol, protocolMap := range ports(boxfile) {
		for from, to := range protocolMap {
			fromInt, _ := strconv.Atoi(from)
			toInt, _ := strconv.Atoi(to)
			portService := portal.Service{
				Interface: "eth0",
				Port:      fromInt,
				Type:      protocol,
				Scheduler: "rr",
				Servers: []portal.Server{
					{
						Host:      component.IPAddr(),
						Port:      toInt,
						Forwarder: "m",
						Weight:    1,
					},
				},
			}

			portServices = append(portServices, portService)
		}
	}

	return portServices
}

// duplicateService ...
func duplicateService(services []portal.Service, service portal.Service) bool {
	for _, existingService := range services {
		if existingService.Port == service.Port {
			return true
		}
	}
	return false
}

// ports ...
func ports(box boxfile.Boxfile) map[string]map[string]string {
	// we allow tcp and udp ports
	rtn := map[string]map[string]string{
		"tcp": {},
		"udp": {},
	}

	// get the boxfiles ports section
	ports, ok := box.Value("ports").([]interface{})
	if !ok {
		return rtn
	}

	// loop through the given ports and create hash data
	// for each one.
	for _, port := range ports {
		p, ok := port.(string)
		if ok {
			portParts := strings.Split(p, ":")
			switch len(portParts) {
			case 1:
				rtn["tcp"][portParts[0]] = portParts[0]
			case 2:
				rtn["tcp"][portParts[0]] = portParts[1]
			case 3:
				// the first part needs to be tcp or udp
				// if it is neither we just assume tcp
				switch portParts[0] {
				case "udp":
					rtn[portParts[0]][portParts[1]] = portParts[2]
				case "tcp":
					rtn["tcp"][portParts[1]] = portParts[2]
				default:
					display.BadPortType(portParts[0])
					rtn["tcp"][portParts[1]] = portParts[2]
				}

			}
		}
		// if only a number is provided we assume tcp:num:num
		portInt, ok := port.(int)
		if ok {
			rtn["tcp"][strconv.Itoa(portInt)] = strconv.Itoa(portInt)
		}

	}

	return rtn
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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 gnmi contains a reference on-device gNMI implementation.
package gnmi

import (
	"context"
	"fmt"
	"strconv"
	"sync"
	"time"

	log "github.com/golang/glog"
	"github.com/openconfig/gnmi/cache"
	"github.com/openconfig/gnmi/subscribe"
	"github.com/openconfig/lemming/gnmi/oc"
	"github.com/openconfig/lemming/gnmi/reconciler"
	"github.com/openconfig/ygot/ygot"
	"github.com/openconfig/ygot/ytypes"
	"golang.org/x/exp/slices"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	gpb "github.com/openconfig/gnmi/proto/gnmi"
)

const (
	OpenConfigOrigin = "openconfig"
)

// Server is a reference gNMI implementation.
type Server struct {
	// The subscribe Server implements only Subscribe for gNMI.
	*subscribe.Server
	c *Collector

	// TODO(wenbli): Implement gnmi.Get and remove this.
	GetResponses []interface{}

	configMu     sync.Mutex
	configSchema *ytypes.Schema

	stateMu     sync.Mutex
	stateSchema *ytypes.Schema

	validators  []func(*oc.Root) error
	reconcilers []reconciler.Reconciler
}

// New creates and registers a reference gNMI server on the given gRPC server.
//
// - targetName is the gNMI target name of the datastore.
func New(srv *grpc.Server, targetName string, recs ...reconciler.Reconciler) (*Server, error) {
	gnmiServer, err := newServer(context.Background(), targetName, true, recs...)
	if err != nil {
		return nil, fmt.Errorf("failed to create gNMI server: %v", err)
	}
	gpb.RegisterGNMIServer(srv, gnmiServer)
	return gnmiServer, nil
}

// newServer returns a new reference gNMI server implementation that can be
// registered on an existing gRPC server.
//
// - configSchema is the specification of the schema if gnmi.Set on config paths is used.
// - stateSchema is the specification of the schema if gnmi.Set on state paths is used.
// - targetName is the name of the target.
func newServer(ctx context.Context, targetName string, enableSet bool, recs ...reconciler.Reconciler) (*Server, error) {
	c := NewCollector(targetName)
	subscribeSrv, err := c.Start(ctx, false)
	if err != nil {
		return nil, err
	}

	gnmiServer := &Server{
		Server:      subscribeSrv, // use the 'subscribe' implementation.
		c:           c,
		reconcilers: recs,
	}

	if !enableSet {
		return gnmiServer, nil
	}

	configSchema, err := oc.Schema()
	if err != nil {
		return nil, fmt.Errorf("cannot create ygot schema object: %v", err)
	}
	// Initialize the cache with the input schema root.
	if configSchema != nil {
		if err := setupSchema(configSchema); err != nil {
			return nil, err
		}
		if err := ygot.PruneConfigFalse(configSchema.RootSchema(), configSchema.Root); err != nil {
			return nil, fmt.Errorf("gnmi: %v", err)
		}
		updateCache(c.cache, configSchema.Root, nil, targetName, OpenConfigOrigin, true, time.Now().UnixNano())
	}

	stateSchema, err := oc.Schema()
	if err != nil {
		return nil, fmt.Errorf("cannot create ygot schema object: %v", err)
	}
	if stateSchema != nil {
		if err := setupSchema(stateSchema); err != nil {
			return nil, err
		}
		updateCache(c.cache, stateSchema.Root, nil, targetName, OpenConfigOrigin, true, time.Now().UnixNano())
	}

	for _, rec := range recs {
		if len(rec.ValidationPaths()) > 0 {
			gnmiServer.validators = append(gnmiServer.validators, rec.Validate)
		}
	}

	gnmiServer.configSchema = configSchema
	gnmiServer.stateSchema = stateSchema

	return gnmiServer, nil
}

type populateDefaultser interface {
	PopulateDefaults()
}

// setupSchema takes in a ygot schema object which it assumes to be
// uninitialized. It initializes and validates it, returning any errors
// encountered.
func setupSchema(schema *ytypes.Schema) error {
	if !schema.IsValid() {
		return fmt.Errorf("cannot obtain valid schema for GoStructs: %v", schema)
	}

	// Initialize the root with default values.
	schema.Root.(populateDefaultser).PopulateDefaults()
	if err := schema.Validate(); err != nil {
		return fmt.Errorf("default root of input schema fails validation: %v", err)
	}

	return nil
}

// updateCache updates the cache with the difference between the root ->
// dirtyRoot such that if the root represents the cache, then the dirtyRoot
// will represent the cache afterwards.
//
// If root is nil, then it is assumed the cache is empty, and the entirety of
// the dirtyRoot is put into the cache.
func updateCache(cache *cache.Cache, dirtyRoot, root ygot.GoStruct, target, origin string, preferShadowPath bool, timestamp int64) error {
	var nos []*gpb.Notification
	if root == nil {
		var err error
		if nos, err = ygot.TogNMINotifications(dirtyRoot, timestamp, ygot.GNMINotificationsConfig{
			UsePathElem: true,
		}); err != nil {
			return fmt.Errorf("gnmi: %v", err)
		}
	} else {
		n, err := ygot.Diff(root, dirtyRoot, &ygot.DiffPathOpt{PreferShadowPath: preferShadowPath})
		if err != nil {
			return fmt.Errorf("gnmi: error while creating update notification for Set: %v", err)
		}
		n.Timestamp = timestamp
		nos = append(nos, n)
	}

	return updateCacheNotifs(cache, nos, target, origin)
}

// updateCacheNotifs updates the target cache with the given notifications.
func updateCacheNotifs(cache *cache.Cache, nos []*gpb.Notification, target, origin string) error {
	cacheTarget := cache.GetTarget(target)
	for _, n := range nos {
		n.Prefix = &gpb.Path{Origin: origin, Target: target}
		if n.Prefix.Origin == "" {
			n.Prefix.Origin = OpenConfigOrigin
		}

		var pathsForDelete []string
		for _, path := range n.Delete {
			p, err := ygot.PathToString(path)
			if err != nil {
				return fmt.Errorf("cannot convert deleted path to string: %v", err)
			}
			pathsForDelete = append(pathsForDelete, p)
		}
		log.V(1).Infof("datastore: updating the following values: %+v", n.Update)
		log.V(1).Infof("datastore: deleting the following paths: %+v", pathsForDelete)
		if err := cacheTarget.GnmiUpdate(n); err != nil {
			return err
		}
	}
	return nil
}

// set updates the datastore and intended configuration with the SetRequest,
// allowing read-only values to be updated.
//
// update indicates whether to update the cache with the values from the set
// request.
// set returns a gRPC error with the correct code and shouldn't be wrapped again.
func set(schema *ytypes.Schema, cache *cache.Cache, target string, req *gpb.SetRequest, preferShadowPath bool, validators []func(*oc.Root) error, timestamp int64) error {
	prevRoot, err := ygot.DeepCopy(schema.Root)
	if err != nil {
		return status.Errorf(codes.Internal, "failed to ygot.DeepCopy the cached root object: %v", err)
	}

	success := false

	// Rollback function
	defer func() {
		if !success {
			log.V(1).Infof("Rolling back set request: %v", req)
			schema.Root = prevRoot
		}
	}()

	var unmarshalOpts []ytypes.UnmarshalOpt
	if preferShadowPath {
		unmarshalOpts = append(unmarshalOpts, &ytypes.PreferShadowPath{})
	}
	if err := ytypes.UnmarshalSetRequest(schema, req, unmarshalOpts...); err != nil {
		return status.Errorf(codes.InvalidArgument, "failed to unmarshal set request %v", err)
	}

	if err := schema.Validate(); err != nil {
		return status.Errorf(codes.InvalidArgument, "invalid SetRequest: %v", err)
	}
	for _, validator := range validators {
		if err := validator(schema.Root.(*oc.Root)); err != nil {
			return status.Errorf(codes.InvalidArgument, "validation error: %v", err)
		}
	}

	success = true

	if err := updateCache(cache, schema.Root, prevRoot, target, req.Prefix.Origin, preferShadowPath, timestamp); err != nil {
		return status.Error(codes.Internal, err.Error())
	}
	return nil
}

// Set is a prototype for a gNMI Set operation.
func (s *Server) Set(ctx context.Context, req *gpb.SetRequest) (*gpb.SetResponse, error) {
	timestamp := time.Now().UnixNano()
	// Use ConfigMode by default so that external users don't need to set metadata.
	gnmiMode := ConfigMode
	md, ok := metadata.FromIncomingContext(ctx)
	if ok {
		switch {
		case slices.Contains(md.Get(GNMIModeMetadataKey), string(ConfigMode)):
			gnmiMode = ConfigMode
		case slices.Contains(md.Get(GNMIModeMetadataKey), string(StateMode)):
			gnmiMode = StateMode

			timestampMD := md.Get(TimestampMetadataKey)
			if len(timestampMD) > 0 {
				var err error
				if timestamp, err = strconv.ParseInt(timestampMD[0], 10, 64); err != nil {
					return nil, status.Errorf(codes.InvalidArgument, "timestamp metadata specified in SetRequest cannot be parsed: %v", err)
				}
			}
		}
	}

	switch gnmiMode {
	case ConfigMode:
		s.configMu.Lock()
		defer s.configMu.Unlock()

		log.V(1).Infof("config datastore service received SetRequest: %v", req)
		if s.configSchema == nil {
			return s.UnimplementedGNMIServer.Set(ctx, req)
		}

		// TODO(wenbli): Reject paths that try to modify read-only values.
		// TODO(wenbli): Question: what to do if there are operational-state values in a container that is specified to be replaced or deleted?
		err := set(s.configSchema, s.c.cache, s.c.name, req, true, s.validators, timestamp)

		// TODO(wenbli): Currently the SetResponse is not filled.
		return &gpb.SetResponse{
			Timestamp: time.Now().UnixNano(),
		}, err
	case StateMode:
		s.stateMu.Lock()
		defer s.stateMu.Unlock()

		log.V(1).Infof("operational state datastore service received SetRequest: %v", req)
		if s.stateSchema == nil {
			return s.UnimplementedGNMIServer.Set(ctx, req)
		}
		// TODO(wenbli): Reject values that modify config values. We only allow modifying state in this mode.
		if err := set(s.stateSchema, s.c.cache, s.c.name, req, false, nil, timestamp); err != nil {
			return &gpb.SetResponse{}, err
		}

		// This mode is intended to be used internally, and the SetResponse doesn't matter.
		return &gpb.SetResponse{}, nil
	default:
		return nil, status.Errorf(codes.Internal, "incoming gNMI SetRequest must specify a valid gnmi.Mode via context metadata: %v", md)
	}
}

func (s *Server) Capabilities(ctx context.Context, req *gpb.CapabilityRequest) (*gpb.CapabilityResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Reference Implementation Unimplemented")
}

func (s *Server) Get(ctx context.Context, req *gpb.GetRequest) (*gpb.GetResponse, error) {
	if len(s.GetResponses) == 0 {
		return nil, status.Errorf(codes.Unimplemented, "Reference Implementation Unimplemented")
	}
	resp := s.GetResponses[0]
	s.GetResponses = s.GetResponses[1:]
	switch v := resp.(type) {
	case error:
		return nil, v
	case *gpb.GetResponse:
		return v, nil
	default:
		return nil, status.Errorf(codes.DataLoss, "Unknown message type: %T", resp)
	}
}

// LocalClient returns a gNMI client for the server.
func (s *Server) LocalClient() gpb.GNMIClient {
	return newLocalClient(s)
}

// StartReconcilers starts all the reconcilers.
func (s *Server) StartReconcilers(ctx context.Context) error {
	c := s.LocalClient()
	for _, rec := range s.reconcilers {
		if err := rec.Start(ctx, c, s.c.name); err != nil {
			return err
		}
	}
	return nil
}

// StopReconcilers stops all the reconcilers.
func (s *Server) StopReconcilers(ctx context.Context) error {
	for _, rec := range s.reconcilers {
		if err := rec.Stop(ctx); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>add comments<commit_after>// Copyright 2022 Google LLC
//
// 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 gnmi contains a reference on-device gNMI implementation.
package gnmi

import (
	"context"
	"fmt"
	"strconv"
	"sync"
	"time"

	log "github.com/golang/glog"
	"github.com/openconfig/gnmi/cache"
	"github.com/openconfig/gnmi/subscribe"
	"github.com/openconfig/lemming/gnmi/oc"
	"github.com/openconfig/lemming/gnmi/reconciler"
	"github.com/openconfig/ygot/ygot"
	"github.com/openconfig/ygot/ytypes"
	"golang.org/x/exp/slices"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	gpb "github.com/openconfig/gnmi/proto/gnmi"
)

const (
	OpenConfigOrigin = "openconfig"
)

// Server is a reference gNMI implementation.
type Server struct {
	// The subscribe Server implements only Subscribe for gNMI.
	*subscribe.Server
	c *Collector

	// TODO(wenbli): Implement gnmi.Get and remove this.
	GetResponses []interface{}

	configMu     sync.Mutex
	configSchema *ytypes.Schema

	stateMu     sync.Mutex
	stateSchema *ytypes.Schema

	validators  []func(*oc.Root) error
	reconcilers []reconciler.Reconciler
}

// New creates and registers a reference gNMI server on the given gRPC server.
//
// - targetName is the gNMI target name of the datastore.
func New(srv *grpc.Server, targetName string, recs ...reconciler.Reconciler) (*Server, error) {
	gnmiServer, err := newServer(context.Background(), targetName, true, recs...)
	if err != nil {
		return nil, fmt.Errorf("failed to create gNMI server: %v", err)
	}
	gpb.RegisterGNMIServer(srv, gnmiServer)
	return gnmiServer, nil
}

// newServer returns a new reference gNMI server implementation that can be
// registered on an existing gRPC server.
//
// - configSchema is the specification of the schema if gnmi.Set on config paths is used.
// - stateSchema is the specification of the schema if gnmi.Set on state paths is used.
// - targetName is the name of the target.
func newServer(ctx context.Context, targetName string, enableSet bool, recs ...reconciler.Reconciler) (*Server, error) {
	c := NewCollector(targetName)
	subscribeSrv, err := c.Start(ctx, false)
	if err != nil {
		return nil, err
	}

	gnmiServer := &Server{
		Server:      subscribeSrv, // use the 'subscribe' implementation.
		c:           c,
		reconcilers: recs,
	}

	if !enableSet {
		return gnmiServer, nil
	}

	configSchema, err := oc.Schema()
	if err != nil {
		return nil, fmt.Errorf("cannot create ygot schema object: %v", err)
	}
	// Initialize the cache with the input schema root.
	if configSchema != nil {
		if err := setupSchema(configSchema); err != nil {
			return nil, err
		}
		if err := ygot.PruneConfigFalse(configSchema.RootSchema(), configSchema.Root); err != nil {
			return nil, fmt.Errorf("gnmi: %v", err)
		}
		updateCache(c.cache, configSchema.Root, nil, targetName, OpenConfigOrigin, true, time.Now().UnixNano())
	}

	stateSchema, err := oc.Schema()
	if err != nil {
		return nil, fmt.Errorf("cannot create ygot schema object: %v", err)
	}
	if stateSchema != nil {
		if err := setupSchema(stateSchema); err != nil {
			return nil, err
		}
		updateCache(c.cache, stateSchema.Root, nil, targetName, OpenConfigOrigin, true, time.Now().UnixNano())
	}

	for _, rec := range recs {
		if len(rec.ValidationPaths()) > 0 {
			gnmiServer.validators = append(gnmiServer.validators, rec.Validate)
		}
	}

	gnmiServer.configSchema = configSchema
	gnmiServer.stateSchema = stateSchema

	return gnmiServer, nil
}

type populateDefaultser interface {
	PopulateDefaults()
}

// setupSchema takes in a ygot schema object which it assumes to be
// uninitialized. It initializes and validates it, returning any errors
// encountered.
func setupSchema(schema *ytypes.Schema) error {
	if !schema.IsValid() {
		return fmt.Errorf("cannot obtain valid schema for GoStructs: %v", schema)
	}

	// Initialize the root with default values.
	schema.Root.(populateDefaultser).PopulateDefaults()
	if err := schema.Validate(); err != nil {
		return fmt.Errorf("default root of input schema fails validation: %v", err)
	}

	return nil
}

// updateCache updates the cache with the difference between the root ->
// dirtyRoot such that if the root represents the cache, then the dirtyRoot
// will represent the cache afterwards.
//
// If root is nil, then it is assumed the cache is empty, and the entirety of
// the dirtyRoot is put into the cache.
func updateCache(cache *cache.Cache, dirtyRoot, root ygot.GoStruct, target, origin string, preferShadowPath bool, timestamp int64) error {
	var nos []*gpb.Notification
	if root == nil {
		var err error
		if nos, err = ygot.TogNMINotifications(dirtyRoot, timestamp, ygot.GNMINotificationsConfig{
			UsePathElem: true,
		}); err != nil {
			return fmt.Errorf("gnmi: %v", err)
		}
	} else {
		n, err := ygot.Diff(root, dirtyRoot, &ygot.DiffPathOpt{PreferShadowPath: preferShadowPath})
		if err != nil {
			return fmt.Errorf("gnmi: error while creating update notification for Set: %v", err)
		}
		n.Timestamp = timestamp
		nos = append(nos, n)
	}

	return updateCacheNotifs(cache, nos, target, origin)
}

// updateCacheNotifs updates the target cache with the given notifications.
func updateCacheNotifs(cache *cache.Cache, nos []*gpb.Notification, target, origin string) error {
	cacheTarget := cache.GetTarget(target)
	for _, n := range nos {
		n.Prefix = &gpb.Path{Origin: origin, Target: target}
		if n.Prefix.Origin == "" {
			n.Prefix.Origin = OpenConfigOrigin
		}

		var pathsForDelete []string
		for _, path := range n.Delete {
			p, err := ygot.PathToString(path)
			if err != nil {
				return fmt.Errorf("cannot convert deleted path to string: %v", err)
			}
			pathsForDelete = append(pathsForDelete, p)
		}
		log.V(1).Infof("datastore: updating the following values: %+v", n.Update)
		log.V(1).Infof("datastore: deleting the following paths: %+v", pathsForDelete)
		if err := cacheTarget.GnmiUpdate(n); err != nil {
			return err
		}
	}
	return nil
}

// set updates the datastore and intended configuration with the SetRequest,
// allowing read-only values to be updated.
//
// set returns a gRPC error with the correct code and shouldn't be wrapped again.
//
// - timestamp specifies the timestamp of the values that are to be updated in
// the gNMI cache.
func set(schema *ytypes.Schema, cache *cache.Cache, target string, req *gpb.SetRequest, preferShadowPath bool, validators []func(*oc.Root) error, timestamp int64) error {
	prevRoot, err := ygot.DeepCopy(schema.Root)
	if err != nil {
		return status.Errorf(codes.Internal, "failed to ygot.DeepCopy the cached root object: %v", err)
	}

	success := false

	// Rollback function
	defer func() {
		if !success {
			log.V(1).Infof("Rolling back set request: %v", req)
			schema.Root = prevRoot
		}
	}()

	var unmarshalOpts []ytypes.UnmarshalOpt
	if preferShadowPath {
		unmarshalOpts = append(unmarshalOpts, &ytypes.PreferShadowPath{})
	}
	if err := ytypes.UnmarshalSetRequest(schema, req, unmarshalOpts...); err != nil {
		return status.Errorf(codes.InvalidArgument, "failed to unmarshal set request %v", err)
	}

	if err := schema.Validate(); err != nil {
		return status.Errorf(codes.InvalidArgument, "invalid SetRequest: %v", err)
	}
	for _, validator := range validators {
		if err := validator(schema.Root.(*oc.Root)); err != nil {
			return status.Errorf(codes.InvalidArgument, "validation error: %v", err)
		}
	}

	success = true

	if err := updateCache(cache, schema.Root, prevRoot, target, req.Prefix.Origin, preferShadowPath, timestamp); err != nil {
		return status.Error(codes.Internal, err.Error())
	}
	return nil
}

// Set implements lemming's gNMI Set operation.
//
// If the given SetRequest is schema compliant AND passes higher-level
// validators, then the gNMI datastore is updated. Otherwise, the gNMI
// datastore is untouched and an error is returned.
//
// Context metadata modifies the behaviour of this API.
// - GNMIModeMetadataKey specifies whether config or state leaves are expected
// in the SetRequest. This is an exclusive expectation: either the update
// consists solely of config values (a user request), or state values (an
// internal goroutine update).
// - TimestampMetadataKey specifies the timestamp for state leaf updates. This
// is to support cases where the data comes from an externally-timestamped
// source.
func (s *Server) Set(ctx context.Context, req *gpb.SetRequest) (*gpb.SetResponse, error) {
	timestamp := time.Now().UnixNano()
	// Use ConfigMode by default so that external users don't need to set metadata.
	gnmiMode := ConfigMode
	md, ok := metadata.FromIncomingContext(ctx)
	if ok {
		switch {
		case slices.Contains(md.Get(GNMIModeMetadataKey), string(ConfigMode)):
			gnmiMode = ConfigMode
		case slices.Contains(md.Get(GNMIModeMetadataKey), string(StateMode)):
			gnmiMode = StateMode

			timestampMD := md.Get(TimestampMetadataKey)
			if len(timestampMD) > 0 {
				var err error
				if timestamp, err = strconv.ParseInt(timestampMD[0], 10, 64); err != nil {
					return nil, status.Errorf(codes.InvalidArgument, "timestamp metadata specified in SetRequest cannot be parsed: %v", err)
				}
			}
		}
	}

	switch gnmiMode {
	case ConfigMode:
		s.configMu.Lock()
		defer s.configMu.Unlock()

		log.V(1).Infof("config datastore service received SetRequest: %v", req)
		if s.configSchema == nil {
			return s.UnimplementedGNMIServer.Set(ctx, req)
		}

		// TODO(wenbli): Reject paths that try to modify read-only values.
		// TODO(wenbli): Question: what to do if there are operational-state values in a container that is specified to be replaced or deleted?
		err := set(s.configSchema, s.c.cache, s.c.name, req, true, s.validators, timestamp)

		// TODO(wenbli): Currently the SetResponse is not filled.
		return &gpb.SetResponse{
			Timestamp: time.Now().UnixNano(),
		}, err
	case StateMode:
		s.stateMu.Lock()
		defer s.stateMu.Unlock()

		log.V(1).Infof("operational state datastore service received SetRequest: %v", req)
		if s.stateSchema == nil {
			return s.UnimplementedGNMIServer.Set(ctx, req)
		}
		// TODO(wenbli): Reject values that modify config values. We only allow modifying state in this mode.
		if err := set(s.stateSchema, s.c.cache, s.c.name, req, false, nil, timestamp); err != nil {
			return &gpb.SetResponse{}, err
		}

		// This mode is intended to be used internally, and the SetResponse doesn't matter.
		return &gpb.SetResponse{}, nil
	default:
		return nil, status.Errorf(codes.Internal, "incoming gNMI SetRequest must specify a valid gnmi.Mode via context metadata: %v", md)
	}
}

func (s *Server) Capabilities(ctx context.Context, req *gpb.CapabilityRequest) (*gpb.CapabilityResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Reference Implementation Unimplemented")
}

func (s *Server) Get(ctx context.Context, req *gpb.GetRequest) (*gpb.GetResponse, error) {
	if len(s.GetResponses) == 0 {
		return nil, status.Errorf(codes.Unimplemented, "Reference Implementation Unimplemented")
	}
	resp := s.GetResponses[0]
	s.GetResponses = s.GetResponses[1:]
	switch v := resp.(type) {
	case error:
		return nil, v
	case *gpb.GetResponse:
		return v, nil
	default:
		return nil, status.Errorf(codes.DataLoss, "Unknown message type: %T", resp)
	}
}

// LocalClient returns a gNMI client for the server.
func (s *Server) LocalClient() gpb.GNMIClient {
	return newLocalClient(s)
}

// StartReconcilers starts all the reconcilers.
func (s *Server) StartReconcilers(ctx context.Context) error {
	c := s.LocalClient()
	for _, rec := range s.reconcilers {
		if err := rec.Start(ctx, c, s.c.name); err != nil {
			return err
		}
	}
	return nil
}

// StopReconcilers stops all the reconcilers.
func (s *Server) StopReconcilers(ctx context.Context) error {
	for _, rec := range s.reconcilers {
		if err := rec.Stop(ctx); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>