<commit_before>package signals

import (
	"io"
)

// PCM is the state and behaviour common to all PCM, it doesn't include encoding information, so cannot return a property and so its not a Signal.
// Specific PCM<<encoding>> types embed this, and then are Signal's.
// these specific precision types, the Signals, return continuous property values that step from one PCM value to the next, Segmented could be used to get interpolated property values.
type PCM struct {
	samplePeriod x
	Data         []byte
}

// make a PCM type, from raw bytes.
func NewPCM(sampleRate uint32, Data []byte) PCM {
	return PCM{X(1 / float32(sampleRate)), Data}
}

func (s PCM) Period() x {
	return s.samplePeriod
}

// from a PCM return two new PCM's (with the same underlying data) from either side of a sample.
func (s PCM) Split(sample uint32, sampleBytes uint8) (head PCM, tail PCM) {
	copy := func(s PCM) PCM { return s }
	bytePosition := sample * uint32(sampleBytes)
	if bytePosition > uint32(len(s.Data)) {
		bytePosition = uint32(len(s.Data))
	}
	head, tail = s, copy(s)
	tail.Data = tail.Data[bytePosition:]
	head.Data = head.Data[:bytePosition]
	return
}

// 8 bit PCM Signal.
// unlike the other precisions of PCM, that use signed data, 8bit uses un-signed. (the default OpenAL and wave file representation for 8bit precision.)
type PCM8bit struct {
	PCM
}

func NewPCM8bit(sampleRate uint32, Data []byte) PCM8bit {
	return PCM8bit{NewPCM(sampleRate, Data)}
}

func (s PCM8bit) property(p x) y {
	index := int(p / s.samplePeriod)
	if index < 0 || index >= len(s.Data){
		return 0
	}
	return decodePCM8bit(s.Data[index])
}

func encodePCM8bit(v y) byte {
	return byte(v>>(yBits-8)) + 128
}

func decodePCM8bit(b byte) y {
	return y(b-128) << (yBits-8)
}

func (s PCM8bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-1)
}

func (s PCM8bit) Encode(w io.Writer) {
	Encode(w, 1, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM8bit) Split(p x) (PCM8bit, PCM8bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 1)
	return PCM8bit{head}, PCM8bit{tail}
}

// 16 bit PCM Signal
type PCM16bit struct {
	PCM
}

func NewPCM16bit(sampleRate uint32, Data []byte) PCM16bit {
	return PCM16bit{NewPCM(sampleRate, Data)}
}

func (s PCM16bit) property(p x) y {
	index := int(p/s.samplePeriod) * 2
	if index < 0 || index >= len(s.Data)-1 {
		return 0
	}
	return decodePCM16bit(s.Data[index], s.Data[index+1])
}

func encodePCM16bit(v y) (byte, byte) {
	return byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}

func decodePCM16bit(b1, b2 byte) y {
	return y(b1) << (yBits-16)|y(b2) << (yBits-8)
}

func (s PCM16bit) Encode(w io.Writer) {
	Encode(w, 2, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM16bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-2) / 2
}

func (s PCM16bit) Split(p x) (PCM16bit, PCM16bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 2)
	return PCM16bit{head}, PCM16bit{tail}
}

// 24 bit PCM Signal
type PCM24bit struct {
	PCM
}

func NewPCM24bit(sampleRate uint32, Data []byte) PCM24bit {
	return PCM24bit{NewPCM(sampleRate, Data)}
}

func (s PCM24bit) property(p x) y {
	index := int(p/s.samplePeriod) * 3
	if index < 0 || index >= len(s.Data)-2 {
		return 0
	}
	return decodePCM24bit(s.Data[index], s.Data[index+1], s.Data[index+2])
}
func encodePCM24bit(v y) (byte, byte, byte) {
	return byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM24bit(b1, b2, b3 byte) y {
	return y(b1) << (yBits-24)|y(b2) << (yBits-16)|y(b3) << (yBits-8)
}

func (s PCM24bit) Encode(w io.Writer) {
	Encode(w, 3, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM24bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-3) / 3
}

func (s PCM24bit) Split(p x) (PCM24bit, PCM24bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 3)
	return PCM24bit{head}, PCM24bit{tail}
}

// 32 bit PCM Signal
type PCM32bit struct {
	PCM
}

func NewPCM32bit(sampleRate uint32, Data []byte) PCM32bit {
	return PCM32bit{NewPCM(sampleRate, Data)}
}

func (s PCM32bit) property(p x) y {
	index := int(p/s.samplePeriod) * 4
	if index < 0 || index >= len(s.Data)-3 {
		return 0
	}
	return decodePCM32bit(s.Data[index], s.Data[index+1], s.Data[index+2], s.Data[index+3])
}
func encodePCM32bit(v y) (byte, byte, byte, byte) {
	return byte(v >> (yBits - 32)), byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM32bit(b1, b2, b3, b4 byte) y {
	return y(b1) << (yBits-32)|y(b2) << (yBits-24)|y(b3) << (yBits-16)|y(b4) << (yBits-8)
}

func (s PCM32bit) Encode(w io.Writer) {
	Encode(w, 4, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM32bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-4) / 4
}

func (s PCM32bit) Split(p x) (PCM32bit, PCM32bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 4)
	return PCM32bit{head}, PCM32bit{tail}
}

// 48 bit PCM Signal
type PCM48bit struct {
	PCM
}

func NewPCM48bit(sampleRate uint32, Data []byte) PCM48bit {
	return PCM48bit{NewPCM(sampleRate, Data)}
}

func (s PCM48bit) property(p x) y {
	index := int(p/s.samplePeriod) * 6
	if index < 0 || index >= len(s.Data)-5 {
		return 0
	}
	return decodePCM48bit(s.Data[index], s.Data[index+1], s.Data[index+2], s.Data[index+3], s.Data[index+4], s.Data[index+5])
}
func encodePCM48bit(v y) (byte, byte, byte, byte, byte, byte) {
	return byte(v >> (yBits - 48)), byte(v >> (yBits - 40)), byte(v >> (yBits - 32)), byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM48bit(b1, b2, b3, b4, b5, b6 byte) y {
	return y(b1) << (yBits-48)|y(b2) << (yBits-40)|y(b3) << (yBits-32)|y(b4) << (yBits-24)|y(b5) << (yBits-16)|y(b6) << (yBits-8)
}

func (s PCM48bit) Encode(w io.Writer) {
	Encode(w, 6, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM48bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-6) / 6
}

func (s PCM48bit) Split(p x) (PCM48bit, PCM48bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 6)
	return PCM48bit{head}, PCM48bit{tail}
}

// 64 bit PCM Signal
type PCM64bit struct {
	PCM
}

func NewPCM64bit(sampleRate uint32, Data []byte) PCM64bit {
	return PCM64bit{NewPCM(sampleRate, Data)}
}

func (s PCM64bit) property(p x) y {
	index := int(p/s.samplePeriod) * 8
	if index < 0 || index >= len(s.Data)-7 {
		return 0
	}
	return decodePCM64bit(s.Data[index], s.Data[index+1], s.Data[index+2], s.Data[index+3], s.Data[index+4], s.Data[index+5], s.Data[index+6], s.Data[index+7])
}
func encodePCM64bit(v y) (byte, byte, byte, byte, byte, byte, byte, byte) {
	return byte(v >> (yBits - 64)), byte(v >> (yBits - 56)),byte(v >> (yBits - 48)), byte(v >> (yBits - 40)), byte(v >> (yBits - 32)), byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM64bit(b1, b2, b3, b4, b5, b6 , b7, b8 byte) y {
	return y(b1) << (yBits-64)|y(b1) << (yBits-56)|y(b1) << (yBits-48)|y(b2) << (yBits-40)|y(b3) << (yBits-32)|y(b4) << (yBits-24)|y(b5) << (yBits-16)|y(b6) << (yBits-8)
}

func (s PCM64bit) Encode(w io.Writer) {
	Encode(w, 8, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM64bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-8) / 8
}

func (s PCM64bit) Split(p x) (PCM64bit, PCM64bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 8)
	return PCM64bit{head}, PCM64bit{tail}
}

// make a PeriodicLimitedSignal by sampling from another Signal, using provided parameters.
func NewPCMSignal(s Signal, length x, sampleRate uint32, sampleBytes uint8) PeriodicLimitedSignal {
	out, in := io.Pipe()
	go func() {
		Encode(in, sampleBytes, sampleRate, length, s)
		in.Close()
	}()
	channels, _ := Decode(out)
	out.Close()
	return channels[0]
}

<commit_msg>comment<commit_after>package signals

import (
	"io"
)

// PCM is the state and behaviour common to all PCM, it doesn't include encoding information, so cannot return a property and so its not a Signal.
// Specific PCM<<encoding>> types embed this, and then are Signal's.
// these specific precision types, the Signals, return continuous property values that step from one PCM value to the next, Segmented could be used to get interpolated property values.
type PCM struct {
	samplePeriod x
	Data         []byte
}

// make a PCM type, from raw bytes.
func NewPCM(sampleRate uint32, Data []byte) PCM {
	return PCM{X(1 / float32(sampleRate)), Data}
}

func (s PCM) Period() x {
	return s.samplePeriod
}

// from a PCM return two new PCM's (with the same underlying data) from either side of a sample.
func (s PCM) Split(sample uint32, sampleBytes uint8) (head PCM, tail PCM) {
	copy := func(s PCM) PCM { return s }
	bytePosition := sample * uint32(sampleBytes)
	if bytePosition > uint32(len(s.Data)) {
		bytePosition = uint32(len(s.Data))
	}
	head, tail = s, copy(s)
	tail.Data = tail.Data[bytePosition:]
	head.Data = head.Data[:bytePosition]
	return
}

// 8 bit PCM Signal.
// unlike the other precisions of PCM, that use signed data, 8bit uses un-signed. (the default OpenAL and wave file representation for 8bit precision.)
type PCM8bit struct {
	PCM
}

func NewPCM8bit(sampleRate uint32, Data []byte) PCM8bit {
	return PCM8bit{NewPCM(sampleRate, Data)}
}

func (s PCM8bit) property(p x) y {
	index := int(p / s.samplePeriod)
	if index < 0 || index >= len(s.Data){
		return 0
	}
	return decodePCM8bit(s.Data[index])
}

func encodePCM8bit(v y) byte {
	return byte(v>>(yBits-8)) + 128
}

func decodePCM8bit(b byte) y {
	return y(b-128) << (yBits-8)
}

func (s PCM8bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-1)
}

func (s PCM8bit) Encode(w io.Writer) {
	Encode(w, 1, uint32(unitX/s.Period()), s.MaxX(), s)
}

func (s PCM8bit) Split(p x) (PCM8bit, PCM8bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 1)
	return PCM8bit{head}, PCM8bit{tail}
}

// 16 bit PCM Signal
type PCM16bit struct {
	PCM
}

func NewPCM16bit(sampleRate uint32, Data []byte) PCM16bit {
	return PCM16bit{NewPCM(sampleRate, Data)}
}

func (s PCM16bit) property(p x) y {
	index := int(p/s.samplePeriod) * 2
	if index < 0 || index >= len(s.Data)-1 {
		return 0
	}
	return decodePCM16bit(s.Data[index], s.Data[index+1])
}

func encodePCM16bit(v y) (byte, byte) {
	return byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}

func decodePCM16bit(b1, b2 byte) y {
	return y(b1) << (yBits-16)|y(b2) << (yBits-8)
}

func (s PCM16bit) Encode(w io.Writer) {
	Encode(w, 2, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM16bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-2) / 2
}

func (s PCM16bit) Split(p x) (PCM16bit, PCM16bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 2)
	return PCM16bit{head}, PCM16bit{tail}
}

// 24 bit PCM Signal
type PCM24bit struct {
	PCM
}

func NewPCM24bit(sampleRate uint32, Data []byte) PCM24bit {
	return PCM24bit{NewPCM(sampleRate, Data)}
}

func (s PCM24bit) property(p x) y {
	index := int(p/s.samplePeriod) * 3
	if index < 0 || index >= len(s.Data)-2 {
		return 0
	}
	return decodePCM24bit(s.Data[index], s.Data[index+1], s.Data[index+2])
}
func encodePCM24bit(v y) (byte, byte, byte) {
	return byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM24bit(b1, b2, b3 byte) y {
	return y(b1) << (yBits-24)|y(b2) << (yBits-16)|y(b3) << (yBits-8)
}

func (s PCM24bit) Encode(w io.Writer) {
	Encode(w, 3, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM24bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-3) / 3
}

func (s PCM24bit) Split(p x) (PCM24bit, PCM24bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 3)
	return PCM24bit{head}, PCM24bit{tail}
}

// 32 bit PCM Signal
type PCM32bit struct {
	PCM
}

func NewPCM32bit(sampleRate uint32, Data []byte) PCM32bit {
	return PCM32bit{NewPCM(sampleRate, Data)}
}

func (s PCM32bit) property(p x) y {
	index := int(p/s.samplePeriod) * 4
	if index < 0 || index >= len(s.Data)-3 {
		return 0
	}
	return decodePCM32bit(s.Data[index], s.Data[index+1], s.Data[index+2], s.Data[index+3])
}
func encodePCM32bit(v y) (byte, byte, byte, byte) {
	return byte(v >> (yBits - 32)), byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM32bit(b1, b2, b3, b4 byte) y {
	return y(b1) << (yBits-32)|y(b2) << (yBits-24)|y(b3) << (yBits-16)|y(b4) << (yBits-8)
}

func (s PCM32bit) Encode(w io.Writer) {
	Encode(w, 4, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM32bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-4) / 4
}

func (s PCM32bit) Split(p x) (PCM32bit, PCM32bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 4)
	return PCM32bit{head}, PCM32bit{tail}
}

// 48 bit PCM Signal
type PCM48bit struct {
	PCM
}

func NewPCM48bit(sampleRate uint32, Data []byte) PCM48bit {
	return PCM48bit{NewPCM(sampleRate, Data)}
}

func (s PCM48bit) property(p x) y {
	index := int(p/s.samplePeriod) * 6
	if index < 0 || index >= len(s.Data)-5 {
		return 0
	}
	return decodePCM48bit(s.Data[index], s.Data[index+1], s.Data[index+2], s.Data[index+3], s.Data[index+4], s.Data[index+5])
}
func encodePCM48bit(v y) (byte, byte, byte, byte, byte, byte) {
	return byte(v >> (yBits - 48)), byte(v >> (yBits - 40)), byte(v >> (yBits - 32)), byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM48bit(b1, b2, b3, b4, b5, b6 byte) y {
	return y(b1) << (yBits-48)|y(b2) << (yBits-40)|y(b3) << (yBits-32)|y(b4) << (yBits-24)|y(b5) << (yBits-16)|y(b6) << (yBits-8)
}

func (s PCM48bit) Encode(w io.Writer) {
	Encode(w, 6, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM48bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-6) / 6
}

func (s PCM48bit) Split(p x) (PCM48bit, PCM48bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 6)
	return PCM48bit{head}, PCM48bit{tail}
}

// 64 bit PCM Signal
type PCM64bit struct {
	PCM
}

func NewPCM64bit(sampleRate uint32, Data []byte) PCM64bit {
	return PCM64bit{NewPCM(sampleRate, Data)}
}

func (s PCM64bit) property(p x) y {
	index := int(p/s.samplePeriod) * 8
	if index < 0 || index >= len(s.Data)-7 {
		return 0
	}
	return decodePCM64bit(s.Data[index], s.Data[index+1], s.Data[index+2], s.Data[index+3], s.Data[index+4], s.Data[index+5], s.Data[index+6], s.Data[index+7])
}
func encodePCM64bit(v y) (byte, byte, byte, byte, byte, byte, byte, byte) {
	return byte(v >> (yBits - 64)), byte(v >> (yBits - 56)),byte(v >> (yBits - 48)), byte(v >> (yBits - 40)), byte(v >> (yBits - 32)), byte(v >> (yBits - 24)), byte(v >> (yBits - 16)), byte(v >> (yBits - 8))
}
func decodePCM64bit(b1, b2, b3, b4, b5, b6 , b7, b8 byte) y {
	return y(b1) << (yBits-64)|y(b1) << (yBits-56)|y(b1) << (yBits-48)|y(b2) << (yBits-40)|y(b3) << (yBits-32)|y(b4) << (yBits-24)|y(b5) << (yBits-16)|y(b6) << (yBits-8)
}

func (s PCM64bit) Encode(w io.Writer) {
	Encode(w, 8, uint32(unitX/s.Period()), s.MaxX(), s)
}
func (s PCM64bit) MaxX() x {
	return s.PCM.samplePeriod * x(len(s.PCM.Data)-8) / 8
}

func (s PCM64bit) Split(p x) (PCM64bit, PCM64bit) {
	head, tail := s.PCM.Split(uint32(p/s.PCM.samplePeriod)+1, 8)
	return PCM64bit{head}, PCM64bit{tail}
}

// make a PeriodicLimitedSignal by sampling from another Signal, using provided parameters.
func NewPCMSignal(s Signal, length x, sampleRate uint32, sampleBytes uint8) PeriodicLimitedSignal {
	out, in := io.Pipe()
	go func() {
		Encode(in, sampleBytes, sampleRate, length, s)
		in.Close()
	}()
	channels, _ := Decode(out)
	out.Close()
	return channels[0]
}

<|endoftext|>


<commit_before>package haproxyconfigparser

import (
	"fmt"
	"strings"
)

func CreateUseBackendClauses(judge string, source []string) (*UseBackendClauses, error) {
	// https://www.haproxy.com/doc/aloha/7.0/haproxy/conditions.html
	dest := &UseBackendClauses{}

	if judge == "if" {
		dest.ReverseJudge = false
	} else if judge == "unless" {
		dest.ReverseJudge = true
	} else {
		return dest, fmt.Errorf("expected if|unless, but '%s'", judge)
	}

	// TODO suport [!], such as !if_xxx
	buf := make([]string, 0)

	for _, n := range source {
		if n == "or" || n == "OR" || n == "||" {
			if len(buf) > 0 {
				dest.Any = append(dest.Any, buf)
			}
		} else if n == "and" || n == "AND" {
			continue
		} else {
			buf = append(buf, n)
		}
	}
	if len(buf) > 0 {
		dest.Any = append(dest.Any, buf)
	}

	return dest, nil
}

func backendReferenceByAcl(frontend Frontend, backends []Backend) error {
	for _, ub := range frontend.UseBackends {
		b, err := findBackendByName(ub.Name, backends)
		if err != nil {
			return err
		}
		ub.Backend = b

		for _, a := range ub.Condition.Any {
			// TODO support or/and conditions
			for _, s := range a {
				//TODO Handle ! correctly instead of ignoring it
				if strings.HasPrefix(s, "!") {
					s=strings.TrimLeft(s,"!")
				}
				acl, err := findAclByName(s, &frontend)
				if err != nil {
					return err
				}
				ub.Acls = append(ub.Acls, acl)
			}
		}
	}
	return nil
}

func findAclByName(name string, frontend *Frontend) (*Acl, error) {
	for _, acl := range frontend.Acls {
		if acl.Name == name {
			return acl, nil
		}
	}
	return &Acl{}, fmt.Errorf("ACL '%s' not found", name)
}

func findBackendByName(name string, backends []Backend) (*Backend, error) {
	for _, b := range backends {
		if b.Name == name {
			return &b, nil
		}
	}
	return nil, fmt.Errorf("Backend '%s' not found", name)
}
<commit_msg>Applied go fmt<commit_after>package haproxyconfigparser

import (
	"fmt"
	"strings"
)

func CreateUseBackendClauses(judge string, source []string) (*UseBackendClauses, error) {
	// https://www.haproxy.com/doc/aloha/7.0/haproxy/conditions.html
	dest := &UseBackendClauses{}

	if judge == "if" {
		dest.ReverseJudge = false
	} else if judge == "unless" {
		dest.ReverseJudge = true
	} else {
		return dest, fmt.Errorf("expected if|unless, but '%s'", judge)
	}

	// TODO suport [!], such as !if_xxx
	buf := make([]string, 0)

	for _, n := range source {
		if n == "or" || n == "OR" || n == "||" {
			if len(buf) > 0 {
				dest.Any = append(dest.Any, buf)
			}
		} else if n == "and" || n == "AND" {
			continue
		} else {
			buf = append(buf, n)
		}
	}
	if len(buf) > 0 {
		dest.Any = append(dest.Any, buf)
	}

	return dest, nil
}

func backendReferenceByAcl(frontend Frontend, backends []Backend) error {
	for _, ub := range frontend.UseBackends {
		b, err := findBackendByName(ub.Name, backends)
		if err != nil {
			return err
		}
		ub.Backend = b

		for _, a := range ub.Condition.Any {
			// TODO support or/and conditions
			for _, s := range a {
				//TODO Handle ! correctly instead of ignoring it
				if strings.HasPrefix(s, "!") {
					s = strings.TrimLeft(s, "!")
				}
				acl, err := findAclByName(s, &frontend)
				if err != nil {
					return err
				}
				ub.Acls = append(ub.Acls, acl)
			}
		}
	}
	return nil
}

func findAclByName(name string, frontend *Frontend) (*Acl, error) {
	for _, acl := range frontend.Acls {
		if acl.Name == name {
			return acl, nil
		}
	}
	return &Acl{}, fmt.Errorf("ACL '%s' not found", name)
}

func findBackendByName(name string, backends []Backend) (*Backend, error) {
	for _, b := range backends {
		if b.Name == name {
			return &b, nil
		}
	}
	return nil, fmt.Errorf("Backend '%s' not found", name)
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "math/big"
import "runtime"

// Returns whether (X + a)^n = X^n + a mod (n, X^r - 1).
func isAKSWitness(n, r, a *big.Int) bool {
	reduceAKS := func(p *IntPoly) {
		p.PowMod(p, r).Mod(p, n)
	}

	zero := big.NewInt(0)
	one := big.NewInt(1)
	lhs := NewIntPoly([][2]*big.Int{{a, zero}, {one, one}})
	lhs.GenPow(lhs, n, reduceAKS)

	rhs := NewIntPoly([][2]*big.Int{{a, zero}, {one, n}})
	reduceAKS(rhs)

	isWitness := !lhs.Eq(rhs)
	return isWitness
}

// Returns the first AKS witness of n with the parameters r and M, or
// nil if there isn't one.
func getFirstAKSWitness(n, r, M *big.Int) *big.Int {
	for a := big.NewInt(1); a.Cmp(M) < 0; a.Add(a, big.NewInt(1)) {
		fmt.Printf("Testing %v (M = %v)...\n", a, M)
		if isWitness := isAKSWitness(n, r, a); isWitness {
			return a
		}
	}
	return nil
}

// Holds the result of an AKS witness test.
type witnessResult struct {
	a         *big.Int
	isWitness bool
}

// Tests all numbers received on numberCh if they are witnesses of n
// with parameter r. Sends the results to resultCh.
func testAKSWitnesses(
	n, r *big.Int,
	numberCh chan *big.Int,
	resultCh chan witnessResult) {
	for a := range numberCh {
		fmt.Printf("Testing %v...\n", a)
		isWitness := isAKSWitness(n, r, a)
		fmt.Printf("Finished testing %v (isWitness=%t)\n",
			a, isWitness)
		resultCh <- witnessResult{a, isWitness}
	}
}

// Returns an AKS witness of n with the parameters r and M, or nil if
// there isn't one. Tests up to maxOutstanding numbers at once.
func getAKSWitness(n, r, M *big.Int, maxOutstanding int) *big.Int {
	numberCh := make(chan *big.Int, maxOutstanding)
	defer close(numberCh)
	resultCh := make(chan witnessResult, maxOutstanding)
	for i := 0; i < maxOutstanding; i++ {
		go testAKSWitnesses(n, r, numberCh, resultCh)
	}

	// Send off all numbers for testing, draining any results that
	// come in while we're doing so.
	tested := big.NewInt(1)
	for i := big.NewInt(1); i.Cmp(M) < 0; {
		select {
		case result := <-resultCh:
			tested.Add(tested, big.NewInt(1))
			fmt.Printf("%v isWitness=%t\n",
				result.a, result.isWitness)
			if result.isWitness {
				return result.a
			}
		default:
			var a big.Int
			a.Set(i)
			numberCh <- &a
			i.Add(i, big.NewInt(1))
		}
	}

	// Drain any remaining results.
	for tested.Cmp(M) < 0 {
		result := <-resultCh
		tested.Add(tested, big.NewInt(1))
		fmt.Printf("%v isWitness=%t\n", result.a, result.isWitness)
		if result.isWitness {
			return result.a
		}
	}

	return nil
}

func main() {
	numCPU := runtime.NumCPU()
	runtime.GOMAXPROCS(numCPU)

	n := big.NewInt(46633)
	r := big.NewInt(262)
	M := big.NewInt(257)
	fmt.Printf("n = %v, r = %v, M = %v\n", n, r, M)
	a := getAKSWitness(n, r, M, numCPU)
	if a != nil {
		fmt.Printf("n is composite with AKS witness %v\n", a)
	} else {
		fmt.Printf("n is prime\n")
	}
}
<commit_msg>Make aks utility take command-line input<commit_after>package main

import "fmt"
import "math/big"
import "os"
import "runtime"

// Returns whether (X + a)^n = X^n + a mod (n, X^r - 1).
func isAKSWitness(n, r, a *big.Int) bool {
	reduceAKS := func(p *IntPoly) {
		p.PowMod(p, r).Mod(p, n)
	}

	zero := big.NewInt(0)
	one := big.NewInt(1)
	lhs := NewIntPoly([][2]*big.Int{{a, zero}, {one, one}})
	lhs.GenPow(lhs, n, reduceAKS)

	rhs := NewIntPoly([][2]*big.Int{{a, zero}, {one, n}})
	reduceAKS(rhs)

	isWitness := !lhs.Eq(rhs)
	return isWitness
}

// Returns the first AKS witness of n with the parameters r and M, or
// nil if there isn't one.
func getFirstAKSWitness(n, r, M *big.Int) *big.Int {
	for a := big.NewInt(1); a.Cmp(M) < 0; a.Add(a, big.NewInt(1)) {
		fmt.Printf("Testing %v (M = %v)...\n", a, M)
		if isWitness := isAKSWitness(n, r, a); isWitness {
			return a
		}
	}
	return nil
}

// Holds the result of an AKS witness test.
type witnessResult struct {
	a         *big.Int
	isWitness bool
}

// Tests all numbers received on numberCh if they are witnesses of n
// with parameter r. Sends the results to resultCh.
func testAKSWitnesses(
	n, r *big.Int,
	numberCh chan *big.Int,
	resultCh chan witnessResult) {
	for a := range numberCh {
		fmt.Printf("Testing %v...\n", a)
		isWitness := isAKSWitness(n, r, a)
		fmt.Printf("Finished testing %v (isWitness=%t)\n",
			a, isWitness)
		resultCh <- witnessResult{a, isWitness}
	}
}

// Returns an AKS witness of n with the parameters r and M, or nil if
// there isn't one. Tests up to maxOutstanding numbers at once.
func getAKSWitness(n, r, M *big.Int, maxOutstanding int) *big.Int {
	numberCh := make(chan *big.Int, maxOutstanding)
	defer close(numberCh)
	resultCh := make(chan witnessResult, maxOutstanding)
	for i := 0; i < maxOutstanding; i++ {
		go testAKSWitnesses(n, r, numberCh, resultCh)
	}

	// Send off all numbers for testing, draining any results that
	// come in while we're doing so.
	tested := big.NewInt(1)
	for i := big.NewInt(1); i.Cmp(M) < 0; {
		select {
		case result := <-resultCh:
			tested.Add(tested, big.NewInt(1))
			fmt.Printf("%v isWitness=%t\n",
				result.a, result.isWitness)
			if result.isWitness {
				return result.a
			}
		default:
			var a big.Int
			a.Set(i)
			numberCh <- &a
			i.Add(i, big.NewInt(1))
		}
	}

	// Drain any remaining results.
	for tested.Cmp(M) < 0 {
		result := <-resultCh
		tested.Add(tested, big.NewInt(1))
		fmt.Printf("%v isWitness=%t\n", result.a, result.isWitness)
		if result.isWitness {
			return result.a
		}
	}

	return nil
}

func main() {
	numCPU := runtime.NumCPU()
	runtime.GOMAXPROCS(numCPU)

	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "%s [number]\n", os.Args[0])
		os.Exit(-1)
	}

	var n big.Int
	_, parsed := n.SetString(os.Args[1], 10)
	if !parsed {
		fmt.Fprintf(os.Stderr, "could not parse %s\n", os.Args[1])
		os.Exit(-1)
	}
	if n.Cmp(big.NewInt(2)) < 0 {
		fmt.Fprintf(os.Stderr, "n must be >= 2\n")
		os.Exit(-1)
	}

	// TODO(akalin): Calculate AKS parameters properly.
	r := n
	M := n
	fmt.Printf("n = %v, r = %v, M = %v\n", &n, &r, &M)
	a := getAKSWitness(&n, &r, &M, numCPU)
	if a != nil {
		fmt.Printf("n is composite with AKS witness %v\n", a)
	} else {
		fmt.Printf("n is prime\n")
	}
}
<|endoftext|>


<commit_before>package dnsimple

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Client provides a client to the DNSimple API
type Client struct {
	// Access Token
	Token string

	// User Email
	Email string

	// URL to the DO API to use
	URL string

	// HttpClient is the client to use. Default will be
	// used if not provided.
	Http *http.Client
}

// DNSimpleError is the error format that they return
// to us if there is a problem
type DNSimpleError struct {
	Errors map[string][]string `json:"errors"`
}

func (d *DNSimpleError) Join() string {
	var errs []string

	for k, v := range d.Errors {
		errs = append(errs, fmt.Sprintf("%s errors: %s", k, strings.Join(v, ", ")))
	}

	return strings.Join(errs, ", ")
}

// NewClient returns a new dnsimple client,
// requires an authorization token. You can generate
// an OAuth token by visiting the Apps & API section
// of the DNSimple control panel for your account.
func NewClient(email string, token string) (*Client, error) {
	client := Client{
		Token: token,
		Email: email,
		URL:   "https://api.dnsimple.com/v1",
		Http:  http.DefaultClient,
	}
	return &client, nil
}

// Creates a new request with the params
func (c *Client) NewRequest(body map[string]interface{}, method string, endpoint string) (*http.Request, error) {
	u, err := url.Parse(c.URL + endpoint)

	if err != nil {
		return nil, fmt.Errorf("Error parsing base URL: %s", err)
	}

	rBody, err := encodeBody(body)
	if err != nil {
		return nil, fmt.Errorf("Error encoding request body: %s", err)
	}

	// Build the request
	req, err := http.NewRequest(method, u.String(), rBody)
	if err != nil {
		return nil, fmt.Errorf("Error creating request: %s", err)
	}

	// Add the authorization header
	req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", c.Email, c.Token))
	req.Header.Add("Accept", "application/json")

	// If it's a not a get, add a content-type
	if method != "GET" {
		req.Header.Add("Content-Type", "application/json")
	}

	return req, nil

}

// parseErr is used to take an error json resp
// and return a single string for use in error messages
func parseErr(resp *http.Response) error {
	dnsError := DNSimpleError{}

	err := decodeBody(resp, &dnsError)

	// if there was an error decoding the body, just return that
	if err != nil {
		return fmt.Errorf("Error parsing error body for non-200 request: %s", err)
	}

	return fmt.Errorf("API Error: %s", dnsError.Join())
}

// decodeBody is used to JSON decode a body
func decodeBody(resp *http.Response, out interface{}) error {
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return err
	}

	if err = json.Unmarshal(body, &out); err != nil {
		return err
	}

	return nil
}

func encodeBody(obj interface{}) (io.Reader, error) {
	buf := bytes.NewBuffer(nil)
	enc := json.NewEncoder(buf)
	if err := enc.Encode(obj); err != nil {
		return nil, err
	}
	return buf, nil
}

// checkResp wraps http.Client.Do() and verifies that the
// request was successful. A non-200 request returns an error
// formatted to included any validation problems or otherwise
func checkResp(resp *http.Response, err error) (*http.Response, error) {
	// If the err is already there, there was an error higher
	// up the chain, so just return that
	if err != nil {
		return resp, err
	}

	switch i := resp.StatusCode; {
	case i == 200:
		return resp, nil
	case i == 202:
		return resp, nil
	case i == 204:
		return resp, nil
	case i == 422:
		return nil, parseErr(resp)
	case i == 400:
		return nil, parseErr(resp)
	default:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	}
}
<commit_msg>handle different error responses<commit_after>package dnsimple

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Client provides a client to the DNSimple API
type Client struct {
	// Access Token
	Token string

	// User Email
	Email string

	// URL to the DO API to use
	URL string

	// HttpClient is the client to use. Default will be
	// used if not provided.
	Http *http.Client
}

// DNSimpleError is the error format that they return
// to us if there is a problem
type DNSimpleError struct {
	Errors map[string][]string `json:"errors"`
}

func (d *DNSimpleError) Join() string {
	var errs []string

	for k, v := range d.Errors {
		errs = append(errs, fmt.Sprintf("%s errors: %s", k, strings.Join(v, ", ")))
	}

	return strings.Join(errs, ", ")
}

// NewClient returns a new dnsimple client,
// requires an authorization token. You can generate
// an OAuth token by visiting the Apps & API section
// of the DNSimple control panel for your account.
func NewClient(email string, token string) (*Client, error) {
	client := Client{
		Token: token,
		Email: email,
		URL:   "https://api.dnsimple.com/v1",
		Http:  http.DefaultClient,
	}
	return &client, nil
}

// Creates a new request with the params
func (c *Client) NewRequest(body map[string]interface{}, method string, endpoint string) (*http.Request, error) {
	u, err := url.Parse(c.URL + endpoint)

	if err != nil {
		return nil, fmt.Errorf("Error parsing base URL: %s", err)
	}

	rBody, err := encodeBody(body)
	if err != nil {
		return nil, fmt.Errorf("Error encoding request body: %s", err)
	}

	// Build the request
	req, err := http.NewRequest(method, u.String(), rBody)
	if err != nil {
		return nil, fmt.Errorf("Error creating request: %s", err)
	}

	// Add the authorization header
	req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", c.Email, c.Token))
	req.Header.Add("Accept", "application/json")

	// If it's a not a get, add a content-type
	if method != "GET" {
		req.Header.Add("Content-Type", "application/json")
	}

	return req, nil

}

// parseErr is used to take an error json resp
// and return a single string for use in error messages
func parseErr(resp *http.Response) error {
	dnsError := DNSimpleError{}

	err := decodeBody(resp, &dnsError)

	// if there was an error decoding the body, just return that
	if err != nil {
		return fmt.Errorf("Error parsing error body for non-200 request: %s", err)
	}

	return fmt.Errorf("API Error: %s", dnsError.Join())
}

// decodeBody is used to JSON decode a body
func decodeBody(resp *http.Response, out interface{}) error {
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return err
	}

	if err = json.Unmarshal(body, &out); err != nil {
		return err
	}

	return nil
}

func encodeBody(obj interface{}) (io.Reader, error) {
	buf := bytes.NewBuffer(nil)
	enc := json.NewEncoder(buf)
	if err := enc.Encode(obj); err != nil {
		return nil, err
	}
	return buf, nil
}

// checkResp wraps http.Client.Do() and verifies that the
// request was successful. A non-200 request returns an error
// formatted to included any validation problems or otherwise
func checkResp(resp *http.Response, err error) (*http.Response, error) {
	// If the err is already there, there was an error higher
	// up the chain, so just return that
	if err != nil {
		return resp, err
	}

	switch i := resp.StatusCode; {
	case i == 200:
		return resp, nil
	case i == 201:
		return resp, nil
	case i == 202:
		return resp, nil
	case i == 204:
		return resp, nil
	case i == 422:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	case i == 400:
		return nil, parseErr(resp)
	default:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/crypto/nacl/secretbox"
)

type EnvVar struct {
	Name    string `json:"name"`
	Exposed string `json:"exposed"`
	Value   string `json:"value"`
	Path    string `json:"-"`
}

type EnvBox struct {
	System
	Prompter
	// Config
}

func NewEnvBox() (*EnvBox, error) {
	return &EnvBox{
		System:   &DefaultSystem{},
		Prompter: &DefaultPrompter{},
	}, nil
}

func (box *EnvBox) AddVariable(name, exposed, file string) error {

	var err error

	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	// check for duplicate name
	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load vars")
	}

	if _, ok := vars[name]; ok {
		return fmt.Errorf("var %s already exists", name)
	}

	if len(exposed) == 0 {
		exposed = name
	}

	var value string
	if len(file) > 0 {
		data, err := ioutil.ReadFile(file)
		if err != nil {
			return errors.Wrap(err, "error reading file")
		}
		value = strings.TrimSpace(string(data))
	} else {
		value, err = box.PromptFor("value: ")
		if err != nil {
			return errors.Wrap(err, "error reading value")
		}
	}

	message, err := json.Marshal(EnvVar{Name: name, Exposed: exposed, Value: value})
	if err != nil {
		return err
	}

	var keyBytes [32]byte
	copy(keyBytes[:], []byte(key)[:32])

	var nonce [24]byte
	if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
		panic(err)
	}

	out := make([]byte, 24)
	copy(out, nonce[:])

	out = secretbox.Seal(out, message, &nonce, &keyBytes)

	// fmt.Println(out)

	var fname [24]byte
	if _, err := io.ReadFull(rand.Reader, fname[:]); err != nil {
		return errors.Wrap(err, "unable to read random")
	}

	dataPath, err := box.DataPath()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filepath.Join(dataPath, fmt.Sprintf("%s.envenc", hex.EncodeToString(fname[:]))), out, 0600)
}

func (box *EnvBox) keyPath() (string, error) {
	dataPath, err := box.DataPath()
	if err != nil {
		return "", err
	}

	return filepath.Join(dataPath, "secret.key"), nil
}

func (box *EnvBox) ReadKey() (string, error) {
	keyPath, err := box.keyPath()
	if err != nil {
		return "", errors.Wrap(err, "unable to get key path")
	}

	if !box.FileExists(keyPath) {
		key, err := box.PromptForKey()
		if err != nil {
			return "", errors.Wrap(err, "unable prompt for key")
		}

		err = box.StoreKey(key)
		if err != nil {
			return "", errors.Wrap(err, "unable to set key")
		}
	}

	data, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return "", errors.Wrap(err, "unable to read keypath")
	}

	key := strings.TrimSpace(string(data))

	return key, nil
}

func (box *EnvBox) PromptForKey() (string, error) {

	key, err := box.PromptMasked("enter key: ")
	if err != nil {
		return "", errors.Wrap(err, "unable to prompt for key")
	}

	// TODO: check that key is valid

	return key, nil
}

func (box *EnvBox) StoreKey(key string) error {
	keyPath, err := box.keyPath()
	if err != nil {
		return errors.Wrap(err, "unable to get key path")
	}

	return ioutil.WriteFile(keyPath, []byte(key), 0600)
}

func (box *EnvBox) LoadEnvVars(key string) (map[string]EnvVar, error) {
	vars := make(map[string]EnvVar)

	dataPath, err := box.DataPath()
	if err != nil {
		return vars, errors.Wrap(err, "unable to get data path")
	}
	files, err := ioutil.ReadDir(dataPath)
	if err != nil {
		return vars, errors.Wrap(err, "unable to read directory")
	}

	var keyBytes [32]byte
	copy(keyBytes[:], []byte(key)[:32])

	for _, info := range files {
		if !info.IsDir() && strings.HasSuffix(info.Name(), ".envenc") {
			fileName := filepath.Join(dataPath, info.Name())
			// fmt.Println("Loading file", fileName)

			data, err := ioutil.ReadFile(fileName)
			if err != nil {
				return vars, errors.Wrap(err, "unable to read file")
			}

			nonce := new([24]byte)
			copy(nonce[:], data[:24])

			if message, ok := secretbox.Open(nil, data[24:], nonce, &keyBytes); ok {
				// fmt.Println(string(message))

				var envVar EnvVar
				err := json.Unmarshal(message, &envVar)
				if err != nil {
					// ignore
				}
				envVar.Path = fileName

				vars[envVar.Name] = envVar
			} else {
				// ignore
			}

		}
	}

	return vars, nil
}

func (box *EnvBox) ListVariables() error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load vars")
	}

	for name, envVar := range vars {
		// TODO: figure out a better way to list these
		fmt.Print(name)
		if envVar.Exposed != envVar.Name {
			fmt.Printf("(%s)", envVar.Exposed)
		}
		fmt.Printf("=%s", envVar.Value)
		fmt.Println()
	}

	return nil
}

func (box *EnvBox) GenerateNewKey(set bool) error {
	var pass [32]byte
	if _, err := io.ReadFull(rand.Reader, pass[:]); err != nil {
		return errors.Wrap(err, "unable to read random")
	}

	key := hex.EncodeToString(pass[:])
	fmt.Println(key)

	if set {
		// TODO: warn when overriding existing key
		return box.StoreKey(key)
	}
	return nil
}

func (box *EnvBox) PromptAndStoreKey() error {
	key, err := box.PromptForKey()
	if err != nil {
		return errors.Wrap(err, "unable to prompt for key")
	}

	return box.StoreKey(key)
}

func (box *EnvBox) ShowKey() error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	fmt.Println(key)

	return nil
}

func (box *EnvBox) RemoveVariable(name string) error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load env vars")
	}

	if envVar, ok := vars[name]; ok {
		err = os.Remove(envVar.Path)
		if err != nil {
			return errors.Wrap(err, "unable to remove file")
		}
	} else {
		return fmt.Errorf("variable %s not found", name)
	}
	return nil
}

func (box *EnvBox) RunCommandWithEnv(varNames, command []string) error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	hostEnv := os.Environ()
	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load env vars")
	}
	for _, varName := range varNames {
		if envVar, ok := vars[varName]; ok {
			hostEnv = append(hostEnv, fmt.Sprintf("%s=%s", envVar.Exposed, envVar.Value))
		} else {
			fmt.Fprintf(os.Stdout, "unable to find %s\n", varName)
		}
	}

	return box.ExecCommandWithEnv(command[0], command[1:], hostEnv)
}
<commit_msg>compose an io.Writer in<commit_after>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/crypto/nacl/secretbox"
)

type EnvVar struct {
	Name    string `json:"name"`
	Exposed string `json:"exposed"`
	Value   string `json:"value"`
	Path    string `json:"-"`
}

type EnvBox struct {
	System
	Prompter
	io.Writer
	// Config
}

func NewEnvBox() (*EnvBox, error) {
	return &EnvBox{
		System:   &DefaultSystem{},
		Prompter: &DefaultPrompter{},
		Writer:   os.Stdout,
	}, nil
}

func (box *EnvBox) AddVariable(name, exposed, file string) error {

	var err error

	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	// check for duplicate name
	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load vars")
	}

	if _, ok := vars[name]; ok {
		return fmt.Errorf("var %s already exists", name)
	}

	if len(exposed) == 0 {
		exposed = name
	}

	var value string
	if len(file) > 0 {
		data, err := ioutil.ReadFile(file)
		if err != nil {
			return errors.Wrap(err, "error reading file")
		}
		value = strings.TrimSpace(string(data))
	} else {
		value, err = box.PromptFor("value: ")
		if err != nil {
			return errors.Wrap(err, "error reading value")
		}
	}

	message, err := json.Marshal(EnvVar{Name: name, Exposed: exposed, Value: value})
	if err != nil {
		return err
	}

	var keyBytes [32]byte
	copy(keyBytes[:], []byte(key)[:32])

	var nonce [24]byte
	if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
		panic(err)
	}

	out := make([]byte, 24)
	copy(out, nonce[:])

	out = secretbox.Seal(out, message, &nonce, &keyBytes)

	var fname [24]byte
	if _, err := io.ReadFull(rand.Reader, fname[:]); err != nil {
		return errors.Wrap(err, "unable to read random")
	}

	dataPath, err := box.DataPath()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filepath.Join(dataPath, fmt.Sprintf("%s.envenc", hex.EncodeToString(fname[:]))), out, 0600)
}

func (box *EnvBox) keyPath() (string, error) {
	dataPath, err := box.DataPath()
	if err != nil {
		return "", err
	}

	return filepath.Join(dataPath, "secret.key"), nil
}

func (box *EnvBox) ReadKey() (string, error) {
	keyPath, err := box.keyPath()
	if err != nil {
		return "", errors.Wrap(err, "unable to get key path")
	}

	if !box.FileExists(keyPath) {
		key, err := box.PromptForKey()
		if err != nil {
			return "", errors.Wrap(err, "unable prompt for key")
		}

		err = box.StoreKey(key)
		if err != nil {
			return "", errors.Wrap(err, "unable to set key")
		}
	}

	data, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return "", errors.Wrap(err, "unable to read keypath")
	}

	key := strings.TrimSpace(string(data))

	return key, nil
}

func (box *EnvBox) PromptForKey() (string, error) {

	key, err := box.PromptMasked("enter key: ")
	if err != nil {
		return "", errors.Wrap(err, "unable to prompt for key")
	}

	// TODO: check that key is valid

	return key, nil
}

func (box *EnvBox) StoreKey(key string) error {
	keyPath, err := box.keyPath()
	if err != nil {
		return errors.Wrap(err, "unable to get key path")
	}

	return ioutil.WriteFile(keyPath, []byte(key), 0600)
}

func (box *EnvBox) LoadEnvVars(key string) (map[string]EnvVar, error) {
	vars := make(map[string]EnvVar)

	dataPath, err := box.DataPath()
	if err != nil {
		return vars, errors.Wrap(err, "unable to get data path")
	}
	files, err := ioutil.ReadDir(dataPath)
	if err != nil {
		return vars, errors.Wrap(err, "unable to read directory")
	}

	var keyBytes [32]byte
	copy(keyBytes[:], []byte(key)[:32])

	for _, info := range files {
		if !info.IsDir() && strings.HasSuffix(info.Name(), ".envenc") {
			fileName := filepath.Join(dataPath, info.Name())

			data, err := ioutil.ReadFile(fileName)
			if err != nil {
				return vars, errors.Wrap(err, "unable to read file")
			}

			nonce := new([24]byte)
			copy(nonce[:], data[:24])

			if message, ok := secretbox.Open(nil, data[24:], nonce, &keyBytes); ok {

				var envVar EnvVar
				err := json.Unmarshal(message, &envVar)
				if err != nil {
					// ignore
				}
				envVar.Path = fileName

				vars[envVar.Name] = envVar
			} else {
				// ignore
			}

		}
	}

	return vars, nil
}

func (box *EnvBox) ListVariables() error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load vars")
	}

	for name, envVar := range vars {
		// TODO: figure out a better way to list these
		fmt.Fprintf(box.Writer, name)
		if envVar.Exposed != envVar.Name {
			fmt.Fprintf(box.Writer, "(%s)", envVar.Exposed)
		}
		fmt.Fprintf(box.Writer, "=%s", envVar.Value)
		fmt.Fprintf(box.Writer, "\n")
	}

	return nil
}

func (box *EnvBox) GenerateNewKey(set bool) error {
	var pass [32]byte
	if _, err := io.ReadFull(rand.Reader, pass[:]); err != nil {
		return errors.Wrap(err, "unable to read random")
	}

	key := hex.EncodeToString(pass[:])
	fmt.Fprintf(box.Writer, "%s\n", key)

	if set {
		// TODO: warn when overriding existing key
		return box.StoreKey(key)
	}
	return nil
}

func (box *EnvBox) PromptAndStoreKey() error {
	key, err := box.PromptForKey()
	if err != nil {
		return errors.Wrap(err, "unable to prompt for key")
	}

	return box.StoreKey(key)
}

func (box *EnvBox) ShowKey() error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	fmt.Fprintf(box.Writer, "%s\n", key)

	return nil
}

func (box *EnvBox) RemoveVariable(name string) error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load env vars")
	}

	if envVar, ok := vars[name]; ok {
		err = os.Remove(envVar.Path)
		if err != nil {
			return errors.Wrap(err, "unable to remove file")
		}
	} else {
		return fmt.Errorf("variable %s not found", name)
	}
	return nil
}

func (box *EnvBox) RunCommandWithEnv(varNames, command []string) error {
	key, err := box.ReadKey()
	if err != nil {
		return errors.Wrap(err, "unable to read key")
	}

	hostEnv := os.Environ()
	vars, err := box.LoadEnvVars(key)
	if err != nil {
		return errors.Wrap(err, "unable to load env vars")
	}
	for _, varName := range varNames {
		if envVar, ok := vars[varName]; ok {
			hostEnv = append(hostEnv, fmt.Sprintf("%s=%s", envVar.Exposed, envVar.Value))
		} else {
			fmt.Fprintf(os.Stdout, "unable to find %s\n", varName)
		}
	}

	return box.ExecCommandWithEnv(command[0], command[1:], hostEnv)
}
<|endoftext|>


<commit_before>package dnsimple

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Client provides a client to the DNSimple API
type Client struct {
	// Access Token
	Token string

	// User Email
	Email string

	// Domain Token
	DomainToken string

	// URL to the DO API to use
	URL string

	// HttpClient is the client to use. Default will be
	// used if not provided.
	Http *http.Client
}

// DNSimpleError is the error format that they return
// to us if there is a problem
type DNSimpleError struct {
	Errors map[string][]string `json:"errors"`
}

func (d *DNSimpleError) Join() string {
	var errs []string

	for k, v := range d.Errors {
		errs = append(errs, fmt.Sprintf("%s errors: %s", k, strings.Join(v, ", ")))
	}

	return strings.Join(errs, ", ")
}

// NewClient returns a new dnsimple client,
// requires an authorization token. You can generate
// an OAuth token by visiting the Apps & API section
// of the DNSimple control panel for your account.
func NewClient(email string, token string) (*Client, error) {
	client := Client{
		Token: token,
		Email: email,
		URL:   "https://api.dnsimple.com/v1",
		Http:  http.DefaultClient,
	}
	return &client, nil
}

func NewClientWithDomainToken(domainToken string) (*Client, error) {
	client := Client{
		DomainToken: domainToken,
		URL:         "https://api.dnsimple.com/v1",
		Http:        http.DefaultClient,
	}
	return &client, nil
}

// Creates a new request with the params
func (c *Client) NewRequest(body map[string]interface{}, method string, endpoint string) (*http.Request, error) {
	u, err := url.Parse(c.URL + endpoint)

	if err != nil {
		return nil, fmt.Errorf("Error parsing base URL: %s", err)
	}

	rBody, err := encodeBody(body)
	if err != nil {
		return nil, fmt.Errorf("Error encoding request body: %s", err)
	}

	// Build the request
	req, err := http.NewRequest(method, u.String(), rBody)
	if err != nil {
		return nil, fmt.Errorf("Error creating request: %s", err)
	}

	// Add the authorization header
	if c.DomainToken != "" {
		req.Header.Add("X-DNSimple-Domain-Token", c.DomainToken)
	} else {
		req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", c.Email, c.Token))
	}
	req.Header.Add("Accept", "application/json")

	// If it's a not a get, add a content-type
	if method != "GET" {
		req.Header.Add("Content-Type", "application/json")
	}

	return req, nil

}

// parseErr is used to take an error json resp
// and return a single string for use in error messages
func parseErr(resp *http.Response) error {
	dnsError := DNSimpleError{}

	err := decodeBody(resp, &dnsError)

	// if there was an error decoding the body, just return that
	if err != nil {
		return fmt.Errorf("Error parsing error body for non-200 request: %s", err)
	}

	return fmt.Errorf("API Error: %s", dnsError.Join())
}

// decodeBody is used to JSON decode a body
func decodeBody(resp *http.Response, out interface{}) error {
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return err
	}

	if err = json.Unmarshal(body, &out); err != nil {
		return err
	}

	return nil
}

func encodeBody(obj interface{}) (io.Reader, error) {
	buf := bytes.NewBuffer(nil)
	enc := json.NewEncoder(buf)
	if err := enc.Encode(obj); err != nil {
		return nil, err
	}
	return buf, nil
}

// checkResp wraps http.Client.Do() and verifies that the
// request was successful. A non-200 request returns an error
// formatted to included any validation problems or otherwise
func checkResp(resp *http.Response, err error) (*http.Response, error) {
	// If the err is already there, there was an error higher
	// up the chain, so just return that
	if err != nil {
		return resp, err
	}

	switch i := resp.StatusCode; {
	case i == 200:
		return resp, nil
	case i == 201:
		return resp, nil
	case i == 202:
		return resp, nil
	case i == 204:
		return resp, nil
	case i == 422:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	case i == 400:
		return nil, parseErr(resp)
	default:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	}
}
<commit_msg>Do not use http.DefaultClient<commit_after>package dnsimple

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Client provides a client to the DNSimple API
type Client struct {
	// Access Token
	Token string

	// User Email
	Email string

	// Domain Token
	DomainToken string

	// URL to the DO API to use
	URL string

	// HttpClient is the client to use. A client with
	// default values will be used if not provided.
	Http *http.Client
}

// DNSimpleError is the error format that they return
// to us if there is a problem
type DNSimpleError struct {
	Errors map[string][]string `json:"errors"`
}

func (d *DNSimpleError) Join() string {
	var errs []string

	for k, v := range d.Errors {
		errs = append(errs, fmt.Sprintf("%s errors: %s", k, strings.Join(v, ", ")))
	}

	return strings.Join(errs, ", ")
}

// NewClient returns a new dnsimple client,
// requires an authorization token. You can generate
// an OAuth token by visiting the Apps & API section
// of the DNSimple control panel for your account.
func NewClient(email string, token string) (*Client, error) {
	client := Client{
		Token: token,
		Email: email,
		URL:   "https://api.dnsimple.com/v1",
		Http:  &http.Client{},
	}
	return &client, nil
}

func NewClientWithDomainToken(domainToken string) (*Client, error) {
	client := Client{
		DomainToken: domainToken,
		URL:         "https://api.dnsimple.com/v1",
		Http:        &http.Client{},
	}
	return &client, nil
}

// Creates a new request with the params
func (c *Client) NewRequest(body map[string]interface{}, method string, endpoint string) (*http.Request, error) {
	u, err := url.Parse(c.URL + endpoint)

	if err != nil {
		return nil, fmt.Errorf("Error parsing base URL: %s", err)
	}

	rBody, err := encodeBody(body)
	if err != nil {
		return nil, fmt.Errorf("Error encoding request body: %s", err)
	}

	// Build the request
	req, err := http.NewRequest(method, u.String(), rBody)
	if err != nil {
		return nil, fmt.Errorf("Error creating request: %s", err)
	}

	// Add the authorization header
	if c.DomainToken != "" {
		req.Header.Add("X-DNSimple-Domain-Token", c.DomainToken)
	} else {
		req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", c.Email, c.Token))
	}
	req.Header.Add("Accept", "application/json")

	// If it's a not a get, add a content-type
	if method != "GET" {
		req.Header.Add("Content-Type", "application/json")
	}

	return req, nil

}

// parseErr is used to take an error json resp
// and return a single string for use in error messages
func parseErr(resp *http.Response) error {
	dnsError := DNSimpleError{}

	err := decodeBody(resp, &dnsError)

	// if there was an error decoding the body, just return that
	if err != nil {
		return fmt.Errorf("Error parsing error body for non-200 request: %s", err)
	}

	return fmt.Errorf("API Error: %s", dnsError.Join())
}

// decodeBody is used to JSON decode a body
func decodeBody(resp *http.Response, out interface{}) error {
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return err
	}

	if err = json.Unmarshal(body, &out); err != nil {
		return err
	}

	return nil
}

func encodeBody(obj interface{}) (io.Reader, error) {
	buf := bytes.NewBuffer(nil)
	enc := json.NewEncoder(buf)
	if err := enc.Encode(obj); err != nil {
		return nil, err
	}
	return buf, nil
}

// checkResp wraps http.Client.Do() and verifies that the
// request was successful. A non-200 request returns an error
// formatted to included any validation problems or otherwise
func checkResp(resp *http.Response, err error) (*http.Response, error) {
	// If the err is already there, there was an error higher
	// up the chain, so just return that
	if err != nil {
		return resp, err
	}

	switch i := resp.StatusCode; {
	case i == 200:
		return resp, nil
	case i == 201:
		return resp, nil
	case i == 202:
		return resp, nil
	case i == 204:
		return resp, nil
	case i == 422:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	case i == 400:
		return nil, parseErr(resp)
	default:
		return nil, fmt.Errorf("API Error: %s", resp.Status)
	}
}
<|endoftext|>


<commit_before>package hsapi

import (
	"net/http"
)

//HsAPI is the main struct for our API
type HsAPI struct {
	token  string       `json:"token"`
	Debug  bool         `json:"debug"`
	client *http.Client `json:"-"`
}

//NewHsAPI creates a new API with a token
func NewHsAPI(token string) *HsAPI {
	return NewHsAPIWithClient(token, &http.Client{})
}

//NewHsAPIWithClient returns a new client with a custom client
func NewHsAPIWithClient(token string, client *http.Client) *HsAPI {
	return &HsAPI{
		token:  token,
		client: client,
	}
}
<commit_msg>Adding Govet<commit_after>package hsapi

import (
	"net/http"
)

//HsAPI is the main struct for our API
type HsAPI struct {
	Token  string       `json:"token"`
	Debug  bool         `json:"debug"`
	Client *http.Client `json:"-"`
}

//NewHsAPI creates a new API with a token
func NewHsAPI(token string) *HsAPI {
	return NewHsAPIWithClient(token, &http.Client{})
}

//NewHsAPIWithClient returns a new client with a custom client
func NewHsAPIWithClient(token string, client *http.Client) *HsAPI {
	return &HsAPI{
		Token:  token,
		Client: client,
	}
}
<|endoftext|>


<commit_before>package apiGatewayConfDeploy

import (
	"bytes"
	"encoding/json"
	"github.com/gorilla/mux"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync/atomic"
	"time"
)

// todo: the full set of states should probably be RECEIVED, READY, FAIL, SUCCESS
const (
	RESPONSE_STATUS_SUCCESS = "SUCCESS"
	RESPONSE_STATUS_FAIL    = "FAIL"
)

const (
	TRACKER_ERR_BUNDLE_DOWNLOAD_TIMEOUT = iota + 1
)

const (
	API_ERR_BAD_BLOCK = iota + 1
	API_ERR_INTERNAL
)

const (
	sqlTimeFormat    = "2006-01-02 15:04:05.999 -0700 MST"
	iso8601          = "2006-01-02T15:04:05.999Z07:00"
	sqliteTimeFormat = "2006-01-02 15:04:05.999-07:00"
)

type deploymentsResult struct {
	deployments []DataDeployment
	err         error
	eTag        string
}

var (
	deploymentsChanged = make(chan interface{}, 5)
	addSubscriber      = make(chan chan deploymentsResult)
	removeSubscriber   = make(chan chan deploymentsResult)
	eTag               int64
)

type errorResponse struct {
	ErrorCode int    `json:"errorCode"`
	Reason    string `json:"reason"`
}

type ApiDeploymentDetails struct {
	Self           string `json:"self"`
	Name           string `json:"name"`
	Org            string `json:"org"`
	Env            string `json:"env"`
	Scope          string `json:"scope"`
	Type           string `json:"type"`
	BlobURL        string `json:"bloburl"`
	Revision       string `json:"revision"`
	BlobId         string `json:"blobId"`
	ResourceBlobId string `json:"resourceBlobId"`
	Created        string `json:"created"`
	Updated        string `json:"updated"`
}

type ApiDeploymentResponse struct {
	Kind                  string                 `json:"kind"`
	Self                  string                 `json:"self"`
	ApiDeploymentResponse []ApiDeploymentDetails `json:"contents"`
}

const deploymentsEndpoint = "/configurations"
const BlobEndpoint = "/blob/{blobId}"

func InitAPI() {
	services.API().HandleFunc(deploymentsEndpoint, apiGetCurrentDeployments).Methods("GET")
	services.API().HandleFunc(BlobEndpoint, apiReturnBlobData).Methods("GET")
}

func writeError(w http.ResponseWriter, status int, code int, reason string) {
	w.WriteHeader(status)
	e := errorResponse{
		ErrorCode: code,
		Reason:    reason,
	}
	bytes, err := json.Marshal(e)
	if err != nil {
		log.Errorf("unable to marshal errorResponse: %v", err)
	} else {
		w.Write(bytes)
	}
	log.Debugf("sending %d error to client: %s", status, reason)
}

func writeInternalError(w http.ResponseWriter, err string) {
	writeError(w, http.StatusInternalServerError, API_ERR_INTERNAL, err)
}

func debounce(in chan interface{}, out chan []interface{}, window time.Duration) {
	send := func(toSend []interface{}) {
		if toSend != nil {
			log.Debugf("debouncer sending: %v", toSend)
			out <- toSend
		}
	}
	var toSend []interface{}
	for {
		select {
		case incoming, ok := <-in:
			if ok {
				log.Debugf("debouncing %v", incoming)
				toSend = append(toSend, incoming)
			} else {
				send(toSend)
				log.Debugf("closing debouncer")
				close(out)
				return
			}
		case <-time.After(window):
			send(toSend)
			toSend = nil
		}
	}
}

func distributeEvents() {
	subscribers := make(map[chan deploymentsResult]struct{})
	deliverDeployments := make(chan []interface{}, 1)

	go debounce(deploymentsChanged, deliverDeployments, debounceDuration)

	for {
		select {
		case _, ok := <-deliverDeployments:
			if !ok {
				return // todo: using this?
			}
			subs := subscribers
			subscribers = make(map[chan deploymentsResult]struct{})
			go func() {
				eTag := incrementETag()
				deployments, err := getUnreadyDeployments()
				log.Debugf("delivering deployments to %d subscribers", len(subs))
				for subscriber := range subs {
					log.Debugf("delivering to: %v", subscriber)
					subscriber <- deploymentsResult{deployments, err, eTag}
				}
			}()
		case subscriber := <-addSubscriber:
			log.Debugf("Add subscriber: %v", subscriber)
			subscribers[subscriber] = struct{}{}
		case subscriber := <-removeSubscriber:
			log.Debugf("Remove subscriber: %v", subscriber)
			delete(subscribers, subscriber)
		}
	}
}

func apiReturnBlobData(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	blobId := vars["blobId"]
	fs, err := getLocalFSLocation(blobId)
	if err != nil {
		writeInternalError(w, "BlobId "+blobId+" has no mapping blob file")
		return
	}
	byte, err := ioutil.ReadFile(fs)
	if err != nil {
		writeInternalError(w, err.Error())
		return
	}
	_, err = io.Copy(w, bytes.NewReader(byte))
	if err != nil {
		writeInternalError(w, err.Error())
	}

}

func apiGetCurrentDeployments(w http.ResponseWriter, r *http.Request) {

	// If returning without a bundle (immediately or after timeout), status = 404
	// If returning If-None-Match value is equal to current deployment, status = 304
	// If returning a new value, status = 200

	// If timeout > 0 AND there is no deployment (or new deployment) available (per If-None-Match), then
	// block for up to the specified number of seconds until a new deployment becomes available.
	b := r.URL.Query().Get("block")
	var timeout int
	if b != "" {
		var err error
		timeout, err = strconv.Atoi(b)
		if err != nil {
			writeError(w, http.StatusBadRequest, API_ERR_BAD_BLOCK, "bad block value, must be number of seconds")
			return
		}
	}
	log.Debugf("api timeout: %d", timeout)

	// If If-None-Match header matches the ETag of current bundle list AND if the request does NOT have a 'block'
	// query param > 0, the server returns a 304 Not Modified response indicating that the client already has the
	// most recent bundle list.
	ifNoneMatch := r.Header.Get("If-None-Match")
	log.Debugf("if-none-match: %s", ifNoneMatch)

	// send unmodified if matches prior eTag and no timeout
	eTag := getETag()
	if eTag == ifNoneMatch && timeout == 0 {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	// send results if different eTag
	if eTag != ifNoneMatch {
		sendReadyDeployments(w)
		return
	}

	// otherwise, subscribe to any new deployment changes
	var newDeploymentsChannel chan deploymentsResult
	if timeout > 0 && ifNoneMatch != "" {
		newDeploymentsChannel = make(chan deploymentsResult, 1)
		addSubscriber <- newDeploymentsChannel
	}

	log.Debug("Blocking request... Waiting for new Deployments.")

	select {
	case result := <-newDeploymentsChannel:
		if result.err != nil {
			writeInternalError(w, "Database error")
		} else {
			sendDeployments(w, result.deployments, result.eTag)
		}

	case <-time.After(time.Duration(timeout) * time.Second):
		removeSubscriber <- newDeploymentsChannel
		log.Debug("Blocking deployment request timed out.")
		if ifNoneMatch != "" {
			w.WriteHeader(http.StatusNotModified)
		} else {
			sendReadyDeployments(w)
		}
	}
}

func sendReadyDeployments(w http.ResponseWriter) {
	eTag := getETag()
	deployments, err := getReadyDeployments()
	if err != nil {
		writeInternalError(w, "Database error")
		return
	}
	sendDeployments(w, deployments, eTag)
}

func get_http_host() string {
	// apid-core has to set this according to the protocol apid is to be run: http/https
	proto := config.GetString("protocol_type")
	if proto == "" {
		proto = "http"
	}
	proto = proto + "://" + config.GetString("api_listen")
	return proto
}

func sendDeployments(w http.ResponseWriter, dataDeps []DataDeployment, eTag string) {

	apiDeps := ApiDeploymentResponse{}
	apiDepDetails := []ApiDeploymentDetails{}

	apiDeps.Kind = "Collections"
	apiDeps.Self = get_http_host() + "/configurations"

	for _, d := range dataDeps {
		apiDepDetails = append(apiDepDetails, ApiDeploymentDetails{
			Org:            d.OrgID,
			Env:            d.EnvID,
			Revision:       d.Revision,
			BlobId:         d.GWBlobID,
			ResourceBlobId: d.BlobResourceID,
			Created:        d.Created,
			Updated:        d.Updated,
			Type:           d.Type,
			BlobURL:        d.BlobURL,
		})
	}
	apiDeps.ApiDeploymentResponse = apiDepDetails

	b, err := json.Marshal(apiDeps)
	if err != nil {
		log.Errorf("unable to marshal deployments: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Debugf("sending deployments %s: %s", eTag, b)
	w.Header().Set("ETag", eTag)
	w.Write(b)
}

// call whenever the list of deployments changes
func incrementETag() string {
	e := atomic.AddInt64(&eTag, 1)
	return strconv.FormatInt(e, 10)
}

func getETag() string {
	e := atomic.LoadInt64(&eTag)
	return strconv.FormatInt(e, 10)
}
<commit_msg>remove scope.<commit_after>package apiGatewayConfDeploy

import (
	"bytes"
	"encoding/json"
	"github.com/gorilla/mux"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync/atomic"
	"time"
)

// todo: the full set of states should probably be RECEIVED, READY, FAIL, SUCCESS
const (
	RESPONSE_STATUS_SUCCESS = "SUCCESS"
	RESPONSE_STATUS_FAIL    = "FAIL"
)

const (
	TRACKER_ERR_BUNDLE_DOWNLOAD_TIMEOUT = iota + 1
)

const (
	API_ERR_BAD_BLOCK = iota + 1
	API_ERR_INTERNAL
)

const (
	sqlTimeFormat    = "2006-01-02 15:04:05.999 -0700 MST"
	iso8601          = "2006-01-02T15:04:05.999Z07:00"
	sqliteTimeFormat = "2006-01-02 15:04:05.999-07:00"
)

type deploymentsResult struct {
	deployments []DataDeployment
	err         error
	eTag        string
}

var (
	deploymentsChanged = make(chan interface{}, 5)
	addSubscriber      = make(chan chan deploymentsResult)
	removeSubscriber   = make(chan chan deploymentsResult)
	eTag               int64
)

type errorResponse struct {
	ErrorCode int    `json:"errorCode"`
	Reason    string `json:"reason"`
}

type ApiDeploymentDetails struct {
	Self           string `json:"self"`
	Name           string `json:"name"`
	Org            string `json:"org"`
	Env            string `json:"env"`
	Type           string `json:"type"`
	BlobURL        string `json:"bloburl"`
	Revision       string `json:"revision"`
	BlobId         string `json:"blobId"`
	ResourceBlobId string `json:"resourceBlobId"`
	Created        string `json:"created"`
	Updated        string `json:"updated"`
}

type ApiDeploymentResponse struct {
	Kind                  string                 `json:"kind"`
	Self                  string                 `json:"self"`
	ApiDeploymentResponse []ApiDeploymentDetails `json:"contents"`
}

const deploymentsEndpoint = "/configurations"
const BlobEndpoint = "/blob/{blobId}"

func InitAPI() {
	services.API().HandleFunc(deploymentsEndpoint, apiGetCurrentDeployments).Methods("GET")
	services.API().HandleFunc(BlobEndpoint, apiReturnBlobData).Methods("GET")
}

func writeError(w http.ResponseWriter, status int, code int, reason string) {
	w.WriteHeader(status)
	e := errorResponse{
		ErrorCode: code,
		Reason:    reason,
	}
	bytes, err := json.Marshal(e)
	if err != nil {
		log.Errorf("unable to marshal errorResponse: %v", err)
	} else {
		w.Write(bytes)
	}
	log.Debugf("sending %d error to client: %s", status, reason)
}

func writeInternalError(w http.ResponseWriter, err string) {
	writeError(w, http.StatusInternalServerError, API_ERR_INTERNAL, err)
}

func debounce(in chan interface{}, out chan []interface{}, window time.Duration) {
	send := func(toSend []interface{}) {
		if toSend != nil {
			log.Debugf("debouncer sending: %v", toSend)
			out <- toSend
		}
	}
	var toSend []interface{}
	for {
		select {
		case incoming, ok := <-in:
			if ok {
				log.Debugf("debouncing %v", incoming)
				toSend = append(toSend, incoming)
			} else {
				send(toSend)
				log.Debugf("closing debouncer")
				close(out)
				return
			}
		case <-time.After(window):
			send(toSend)
			toSend = nil
		}
	}
}

func distributeEvents() {
	subscribers := make(map[chan deploymentsResult]struct{})
	deliverDeployments := make(chan []interface{}, 1)

	go debounce(deploymentsChanged, deliverDeployments, debounceDuration)

	for {
		select {
		case _, ok := <-deliverDeployments:
			if !ok {
				return // todo: using this?
			}
			subs := subscribers
			subscribers = make(map[chan deploymentsResult]struct{})
			go func() {
				eTag := incrementETag()
				deployments, err := getUnreadyDeployments()
				log.Debugf("delivering deployments to %d subscribers", len(subs))
				for subscriber := range subs {
					log.Debugf("delivering to: %v", subscriber)
					subscriber <- deploymentsResult{deployments, err, eTag}
				}
			}()
		case subscriber := <-addSubscriber:
			log.Debugf("Add subscriber: %v", subscriber)
			subscribers[subscriber] = struct{}{}
		case subscriber := <-removeSubscriber:
			log.Debugf("Remove subscriber: %v", subscriber)
			delete(subscribers, subscriber)
		}
	}
}

func apiReturnBlobData(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	blobId := vars["blobId"]
	fs, err := getLocalFSLocation(blobId)
	if err != nil {
		writeInternalError(w, "BlobId "+blobId+" has no mapping blob file")
		return
	}
	byte, err := ioutil.ReadFile(fs)
	if err != nil {
		writeInternalError(w, err.Error())
		return
	}
	_, err = io.Copy(w, bytes.NewReader(byte))
	if err != nil {
		writeInternalError(w, err.Error())
	}

}

func apiGetCurrentDeployments(w http.ResponseWriter, r *http.Request) {

	// If returning without a bundle (immediately or after timeout), status = 404
	// If returning If-None-Match value is equal to current deployment, status = 304
	// If returning a new value, status = 200

	// If timeout > 0 AND there is no deployment (or new deployment) available (per If-None-Match), then
	// block for up to the specified number of seconds until a new deployment becomes available.
	b := r.URL.Query().Get("block")
	var timeout int
	if b != "" {
		var err error
		timeout, err = strconv.Atoi(b)
		if err != nil {
			writeError(w, http.StatusBadRequest, API_ERR_BAD_BLOCK, "bad block value, must be number of seconds")
			return
		}
	}
	log.Debugf("api timeout: %d", timeout)

	// If If-None-Match header matches the ETag of current bundle list AND if the request does NOT have a 'block'
	// query param > 0, the server returns a 304 Not Modified response indicating that the client already has the
	// most recent bundle list.
	ifNoneMatch := r.Header.Get("If-None-Match")
	log.Debugf("if-none-match: %s", ifNoneMatch)

	// send unmodified if matches prior eTag and no timeout
	eTag := getETag()
	if eTag == ifNoneMatch && timeout == 0 {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	// send results if different eTag
	if eTag != ifNoneMatch {
		sendReadyDeployments(w)
		return
	}

	// otherwise, subscribe to any new deployment changes
	var newDeploymentsChannel chan deploymentsResult
	if timeout > 0 && ifNoneMatch != "" {
		newDeploymentsChannel = make(chan deploymentsResult, 1)
		addSubscriber <- newDeploymentsChannel
	}

	log.Debug("Blocking request... Waiting for new Deployments.")

	select {
	case result := <-newDeploymentsChannel:
		if result.err != nil {
			writeInternalError(w, "Database error")
		} else {
			sendDeployments(w, result.deployments, result.eTag)
		}

	case <-time.After(time.Duration(timeout) * time.Second):
		removeSubscriber <- newDeploymentsChannel
		log.Debug("Blocking deployment request timed out.")
		if ifNoneMatch != "" {
			w.WriteHeader(http.StatusNotModified)
		} else {
			sendReadyDeployments(w)
		}
	}
}

func sendReadyDeployments(w http.ResponseWriter) {
	eTag := getETag()
	deployments, err := getReadyDeployments()
	if err != nil {
		writeInternalError(w, "Database error")
		return
	}
	sendDeployments(w, deployments, eTag)
}

func get_http_host() string {
	// apid-core has to set this according to the protocol apid is to be run: http/https
	proto := config.GetString("protocol_type")
	if proto == "" {
		proto = "http"
	}
	proto = proto + "://" + config.GetString("api_listen")
	return proto
}

func sendDeployments(w http.ResponseWriter, dataDeps []DataDeployment, eTag string) {

	apiDeps := ApiDeploymentResponse{}
	apiDepDetails := []ApiDeploymentDetails{}

	apiDeps.Kind = "Collections"
	apiDeps.Self = get_http_host() + "/configurations"

	for _, d := range dataDeps {
		apiDepDetails = append(apiDepDetails, ApiDeploymentDetails{
			Org:            d.OrgID,
			Env:            d.EnvID,
			Revision:       d.Revision,
			BlobId:         d.GWBlobID,
			ResourceBlobId: d.BlobResourceID,
			Created:        d.Created,
			Updated:        d.Updated,
			Type:           d.Type,
			BlobURL:        d.BlobURL,
		})
	}
	apiDeps.ApiDeploymentResponse = apiDepDetails

	b, err := json.Marshal(apiDeps)
	if err != nil {
		log.Errorf("unable to marshal deployments: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Debugf("sending deployments %s: %s", eTag, b)
	w.Header().Set("ETag", eTag)
	w.Write(b)
}

// call whenever the list of deployments changes
func incrementETag() string {
	e := atomic.AddInt64(&eTag, 1)
	return strconv.FormatInt(e, 10)
}

func getETag() string {
	e := atomic.LoadInt64(&eTag)
	return strconv.FormatInt(e, 10)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"gopkg.in/gin-contrib/cors.v1"
)

func isRunningInDockerContainer() bool {
	// slightly modified from blog: https://paulbradley.org/indocker/
	// docker creates a .dockerenv file at the root
	// of the directory tree inside the container.
	// if this file exists then the viewer is running
	// from inside a container so return true

	if _, err := os.Stat("/.dockerenv"); err == nil {
		return true
	}

	return false
}

// StartAPIServer starts the API server
func StartAPIServer(config *Config,
	reloadChan chan bool,
	blockCache *MemoryBlockCache,
	questionCache *MemoryQuestionCache) (*http.Server, error) {
	if !config.APIDebug {
		gin.SetMode(gin.ReleaseMode)
	}

	router := gin.Default()

	// Automatically replace the default listening address in the docker with `0.0.0.0`
	if isRunningInDockerContainer() {
		const localhost = "127.0.0.1:"
		if strings.HasPrefix(config.API, localhost) {
			config.API = strings.Replace(config.API, localhost, "0.0.0.0:", 1)
		}
	}

	server := &http.Server{
		Addr:    config.API,
		Handler: router,
	}

	router.Use(cors.Default())

	router.GET("/blockcache", func(c *gin.Context) {
		special := make([]string, 0, len(blockCache.Special))
		for k := range blockCache.Special {
			special = append(special, k)
		}
		c.IndentedJSON(http.StatusOK, gin.H{"length": blockCache.Length(), "items": blockCache.Backend, "special": special})
	})

	router.GET("/blockcache/exists/:key", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"exists": blockCache.Exists(c.Param("key"))})
	})

	router.GET("/blockcache/get/:key", func(c *gin.Context) {
		if ok, _ := blockCache.Get(c.Param("key")); !ok {
			c.IndentedJSON(http.StatusOK, gin.H{"error": c.Param("key") + " not found"})
		} else {
			c.IndentedJSON(http.StatusOK, gin.H{"success": ok})
		}
	})

	router.GET("/blockcache/length", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"length": blockCache.Length()})
	})

	router.GET("/blockcache/remove/:key", func(c *gin.Context) {
		// Removes from BlockCache only. If the domain has already been queried and placed into MemoryCache, will need to wait until item is expired.
		blockCache.Remove(c.Param("key"))
		c.IndentedJSON(http.StatusOK, gin.H{"success": true})
	})

	router.GET("/blockcache/personal", func(c *gin.Context) {
		filePath := filepath.FromSlash("sources/personal.list")
		f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_RDONLY, 0600)
		if err != nil {
			logger.Critical(err)
		}

		defer func() {
			if err := f.Close(); err != nil {
				logger.Criticalf("Error closing file: %s\n", err)
			}
		}()

		var personalBlockList []string

		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			line := scanner.Text()
			personalBlockList = append(personalBlockList, line)
		}
		c.IndentedJSON(http.StatusOK, gin.H{"personalBlockList": personalBlockList})
	})

	router.GET("/blockcache/set/:key", func(c *gin.Context) {
		filePath := filepath.FromSlash("sources/personal.list")
		f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0600)
		if err != nil {
			logger.Critical(err)
		}

		defer func() {
			if err := f.Close(); err != nil {
				logger.Criticalf("Error closing file: %s\n", err)
			}
		}()

		_, err = blockCache.Get(c.Param("key"))
		if err == (KeyNotFound{c.Param("key")}) {
			// MemoryBlockCache Set() always returns nil, so ignoring response.
			_ = blockCache.Set(c.Param("key"), true)
			c.IndentedJSON(http.StatusOK, gin.H{"success": true})

			// Add domain to user block list
			if _, err := f.WriteString(c.Param("key") + "\n"); err != nil {
				logger.Critical(err)
			}
		} else {
			//_ = blockCache.Set(c.Param("key"), false)
			blockCache.Remove(c.Param("key"))
			c.IndentedJSON(http.StatusOK, gin.H{"success": true})

			personalBlockList := ""
			// Remove domain from user block list
			scanner := bufio.NewScanner(f)
			for scanner.Scan() {
				line := scanner.Text()
				if strings.Replace(line, "\n", "", 1) != c.Param("key") {
					personalBlockList = personalBlockList + "\n" + line
				}
			}
			if scanner.Err() != nil {
				logger.Critical("error while reading personal block list")
				return
			}
			err := f.Truncate(0)
			if err != nil {
				logger.Error(err)
			}
			_, err = f.Write([]byte(personalBlockList))
			if err != nil {
				logger.Error(err)
			}
		}
	})

	router.GET("/questioncache", func(c *gin.Context) {
		highWater, err := strconv.ParseInt(c.DefaultQuery("highWater", "-1"), 10, 64)
		if err != nil {
			highWater = -1
		}
		c.IndentedJSON(http.StatusOK, gin.H{
			"length": questionCache.Length(),
			"items":  questionCache.GetOlder(highWater),
		})
	})

	router.GET("/questioncache/length", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"length": questionCache.Length()})
	})

	router.GET("/questioncache/clear", func(c *gin.Context) {
		questionCache.Clear()
		c.IndentedJSON(http.StatusOK, gin.H{"success": true})
	})

	router.GET("/questioncache/client/:client", func(c *gin.Context) {
		var filteredCache []QuestionCacheEntry

		questionCache.mu.RLock()
		for _, entry := range questionCache.Backend {
			if entry.Remote == c.Param("client") {
				filteredCache = append(filteredCache, entry)
			}
		}
		questionCache.mu.RUnlock()

		c.IndentedJSON(http.StatusOK, filteredCache)
	})

	router.GET("/questioncache/client", func(c *gin.Context) {
		clientList := make(map[string]bool)
		questionCache.mu.RLock()
		for _, entry := range questionCache.Backend {
			if _, ok := clientList[entry.Remote]; !ok {
				clientList[entry.Remote] = true
			}
		}
		questionCache.mu.RUnlock()
		var clients []string
		for client := range clientList {
			clients = append(clients, client)
		}
		c.IndentedJSON(http.StatusOK, clients)
	})

	router.OPTIONS("/application/active", func(c *gin.Context) {
		c.AbortWithStatus(http.StatusOK)
	})

	router.GET("/application/active", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"active": grimdActive})
	})

	// Handle the setting of active state.
	// Possible values for state:
	// On
	// Off
	// Snooze: off for `timeout` seconds; timeout defaults to 300
	router.PUT("/application/active", func(c *gin.Context) {
		active := c.Query("state")
		version := c.Query("v")
		if version != "1" {
			c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "Illegal value for 'version'"})
		} else {
			switch active {
			case "On":
				grimdActivation.set(true)
				c.IndentedJSON(http.StatusOK, gin.H{"active": grimdActive})
			case "Off":
				grimdActivation.set(false)
				c.IndentedJSON(http.StatusOK, gin.H{"active": grimdActive})
			case "Snooze":
				timeoutString := c.DefaultQuery("timeout", "300")
				timeout, err := strconv.ParseUint(timeoutString, 0, 0)
				if err != nil {
					c.JSON(http.StatusBadRequest, gin.H{"error": "Illegal value for 'timeout'"})
				} else {
					grimdActivation.toggleOff(uint(timeout))
					c.IndentedJSON(http.StatusOK, gin.H{
						"active":  grimdActive,
						"timeout": timeout,
					})
				}
			default:
				c.JSON(http.StatusBadRequest, gin.H{"error": "Illegal value for 'state'"})
			}
		}
	})

	router.POST("/blocklist/update", func(c *gin.Context) {
		c.AbortWithStatus(http.StatusOK)
		// Send reload trigger to chan in background goroutine so does not hang
		go func(reloadChan chan bool) {
			reloadChan <- true
		}(reloadChan)
	})

	listener, err := net.Listen("tcp", config.API)
	if err != nil {
		return nil, err
	}
	go func() {
		if err := server.Serve(listener); err != http.ErrServerClosed {
			logger.Fatal(err)
		}
	}()

	logger.Criticalf("API server listening on %s", config.API)
	return server, err
}
<commit_msg>chore: embed reaper<commit_after>package main

import (
	"bufio"
	"embed"
	"io/fs"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"gopkg.in/gin-contrib/cors.v1"
)

//go:embed dashboard/reaper
var dashboardAssets embed.FS

func isRunningInDockerContainer() bool {
	// slightly modified from blog: https://paulbradley.org/indocker/
	// docker creates a .dockerenv file at the root
	// of the directory tree inside the container.
	// if this file exists then the viewer is running
	// from inside a container so return true

	if _, err := os.Stat("/.dockerenv"); err == nil {
		return true
	}

	return false
}

// StartAPIServer starts the API server
func StartAPIServer(config *Config,
	reloadChan chan bool,
	blockCache *MemoryBlockCache,
	questionCache *MemoryQuestionCache) (*http.Server, error) {
	if !config.APIDebug {
		gin.SetMode(gin.ReleaseMode)
	}

	router := gin.Default()

	// Automatically replace the default listening address in the docker with `0.0.0.0`
	if isRunningInDockerContainer() {
		const localhost = "127.0.0.1:"
		if strings.HasPrefix(config.API, localhost) {
			config.API = strings.Replace(config.API, localhost, "0.0.0.0:", 1)
		}
	}

	server := &http.Server{
		Addr:    config.API,
		Handler: router,
	}

	router.Use(cors.Default())

	router.GET("/", func(c *gin.Context) {
		c.Redirect(http.StatusTemporaryRedirect, "/dashboard")
		c.Abort()
	})

	dashboardAssets, _ := fs.Sub(dashboardAssets, "dashboard/reaper")
	router.StaticFS("/dashboard", http.FS(dashboardAssets))

	router.GET("/blockcache", func(c *gin.Context) {
		special := make([]string, 0, len(blockCache.Special))
		for k := range blockCache.Special {
			special = append(special, k)
		}
		c.IndentedJSON(http.StatusOK, gin.H{"length": blockCache.Length(), "items": blockCache.Backend, "special": special})
	})

	router.GET("/blockcache/exists/:key", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"exists": blockCache.Exists(c.Param("key"))})
	})

	router.GET("/blockcache/get/:key", func(c *gin.Context) {
		if ok, _ := blockCache.Get(c.Param("key")); !ok {
			c.IndentedJSON(http.StatusOK, gin.H{"error": c.Param("key") + " not found"})
		} else {
			c.IndentedJSON(http.StatusOK, gin.H{"success": ok})
		}
	})

	router.GET("/blockcache/length", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"length": blockCache.Length()})
	})

	router.GET("/blockcache/remove/:key", func(c *gin.Context) {
		// Removes from BlockCache only. If the domain has already been queried and placed into MemoryCache, will need to wait until item is expired.
		blockCache.Remove(c.Param("key"))
		c.IndentedJSON(http.StatusOK, gin.H{"success": true})
	})

	router.GET("/blockcache/personal", func(c *gin.Context) {
		filePath := filepath.FromSlash("sources/personal.list")
		f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_RDONLY, 0600)
		if err != nil {
			logger.Critical(err)
		}

		defer func() {
			if err := f.Close(); err != nil {
				logger.Criticalf("Error closing file: %s\n", err)
			}
		}()

		var personalBlockList []string

		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			line := scanner.Text()
			personalBlockList = append(personalBlockList, line)
		}
		c.IndentedJSON(http.StatusOK, gin.H{"personalBlockList": personalBlockList})
	})

	router.GET("/blockcache/set/:key", func(c *gin.Context) {
		filePath := filepath.FromSlash("sources/personal.list")
		f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0600)
		if err != nil {
			logger.Critical(err)
		}

		defer func() {
			if err := f.Close(); err != nil {
				logger.Criticalf("Error closing file: %s\n", err)
			}
		}()

		_, err = blockCache.Get(c.Param("key"))
		if err == (KeyNotFound{c.Param("key")}) {
			// MemoryBlockCache Set() always returns nil, so ignoring response.
			_ = blockCache.Set(c.Param("key"), true)
			c.IndentedJSON(http.StatusOK, gin.H{"success": true})

			// Add domain to user block list
			if _, err := f.WriteString(c.Param("key") + "\n"); err != nil {
				logger.Critical(err)
			}
		} else {
			//_ = blockCache.Set(c.Param("key"), false)
			blockCache.Remove(c.Param("key"))
			c.IndentedJSON(http.StatusOK, gin.H{"success": true})

			personalBlockList := ""
			// Remove domain from user block list
			scanner := bufio.NewScanner(f)
			for scanner.Scan() {
				line := scanner.Text()
				if strings.Replace(line, "\n", "", 1) != c.Param("key") {
					personalBlockList = personalBlockList + "\n" + line
				}
			}
			if scanner.Err() != nil {
				logger.Critical("error while reading personal block list")
				return
			}
			err := f.Truncate(0)
			if err != nil {
				logger.Error(err)
			}
			_, err = f.Write([]byte(personalBlockList))
			if err != nil {
				logger.Error(err)
			}
		}
	})

	router.GET("/questioncache", func(c *gin.Context) {
		highWater, err := strconv.ParseInt(c.DefaultQuery("highWater", "-1"), 10, 64)
		if err != nil {
			highWater = -1
		}
		c.IndentedJSON(http.StatusOK, gin.H{
			"length": questionCache.Length(),
			"items":  questionCache.GetOlder(highWater),
		})
	})

	router.GET("/questioncache/length", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"length": questionCache.Length()})
	})

	router.GET("/questioncache/clear", func(c *gin.Context) {
		questionCache.Clear()
		c.IndentedJSON(http.StatusOK, gin.H{"success": true})
	})

	router.GET("/questioncache/client/:client", func(c *gin.Context) {
		var filteredCache []QuestionCacheEntry

		questionCache.mu.RLock()
		for _, entry := range questionCache.Backend {
			if entry.Remote == c.Param("client") {
				filteredCache = append(filteredCache, entry)
			}
		}
		questionCache.mu.RUnlock()

		c.IndentedJSON(http.StatusOK, filteredCache)
	})

	router.GET("/questioncache/client", func(c *gin.Context) {
		clientList := make(map[string]bool)
		questionCache.mu.RLock()
		for _, entry := range questionCache.Backend {
			if _, ok := clientList[entry.Remote]; !ok {
				clientList[entry.Remote] = true
			}
		}
		questionCache.mu.RUnlock()
		var clients []string
		for client := range clientList {
			clients = append(clients, client)
		}
		c.IndentedJSON(http.StatusOK, clients)
	})

	router.OPTIONS("/application/active", func(c *gin.Context) {
		c.AbortWithStatus(http.StatusOK)
	})

	router.GET("/application/active", func(c *gin.Context) {
		c.IndentedJSON(http.StatusOK, gin.H{"active": grimdActive})
	})

	// Handle the setting of active state.
	// Possible values for state:
	// On
	// Off
	// Snooze: off for `timeout` seconds; timeout defaults to 300
	router.PUT("/application/active", func(c *gin.Context) {
		active := c.Query("state")
		version := c.Query("v")
		if version != "1" {
			c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "Illegal value for 'version'"})
		} else {
			switch active {
			case "On":
				grimdActivation.set(true)
				c.IndentedJSON(http.StatusOK, gin.H{"active": grimdActive})
			case "Off":
				grimdActivation.set(false)
				c.IndentedJSON(http.StatusOK, gin.H{"active": grimdActive})
			case "Snooze":
				timeoutString := c.DefaultQuery("timeout", "300")
				timeout, err := strconv.ParseUint(timeoutString, 0, 0)
				if err != nil {
					c.JSON(http.StatusBadRequest, gin.H{"error": "Illegal value for 'timeout'"})
				} else {
					grimdActivation.toggleOff(uint(timeout))
					c.IndentedJSON(http.StatusOK, gin.H{
						"active":  grimdActive,
						"timeout": timeout,
					})
				}
			default:
				c.JSON(http.StatusBadRequest, gin.H{"error": "Illegal value for 'state'"})
			}
		}
	})

	router.POST("/blocklist/update", func(c *gin.Context) {
		c.AbortWithStatus(http.StatusOK)
		// Send reload trigger to chan in background goroutine so does not hang
		go func(reloadChan chan bool) {
			reloadChan <- true
		}(reloadChan)
	})

	listener, err := net.Listen("tcp", config.API)
	if err != nil {
		return nil, err
	}
	go func() {
		if err := server.Serve(listener); err != http.ErrServerClosed {
			logger.Fatal(err)
		}
	}()

	logger.Criticalf("API server listening on %s", config.API)
	return server, err
}
<|endoftext|>


<commit_before>/*
gopcap is pure-Go implementation of a parser for .pcap files. Written from the
ground up for plugging directly into other components, the API is focused on
simplicity and clarity. To this end, it exposes the barest minimum of
functionality in as clear an API as possible.
*/
package gopcap

import (
	"errors"
	"io"
	"time"
)

// Errors
var NotAPcapFile error = errors.New("Not a pcap file.")
var InsufficientLength error = errors.New("Insufficient length.")
var UnexpectedEOF error = errors.New("Unexpected EOF.")

// Link encodes a given Link-Layer header type. See http://www.tcpdump.org/linktypes.html for a more-full
// explanation of each header type.
type Link uint32

const (
	NULL                       Link = 0
	ETHERNET                   Link = 1
	AX25                       Link = 3
	IEEE802_5                  Link = 6
	ARCNET_BSD                 Link = 7
	SLIP                       Link = 8
	PPP                        Link = 9
	FDDI                       Link = 10
	PPP_HDLC                   Link = 50
	PPP_ETHER                  Link = 51
	ATM_RFC1483                Link = 100
	RAW                        Link = 101
	C_HDLC                     Link = 104
	IEEE802_11                 Link = 105
	FRELAY                     Link = 107
	LOOP                       Link = 108
	LINUX_SLL                  Link = 113
	LTALK                      Link = 114
	PFLOG                      Link = 117
	IEEE802_11_PRISM           Link = 119
	IP_OVER_FC                 Link = 122
	SUNATM                     Link = 123
	IEEE802_11_RADIOTAP        Link = 127
	ARCNET_LINUX               Link = 129
	APPLE_IP_OVER_IEEE1394     Link = 138
	MTP2_WITH_PHDR             Link = 139
	MTP2                       Link = 140
	MTP3                       Link = 141
	SCCP                       Link = 142
	DOCSIS                     Link = 143
	LINUX_IRDA                 Link = 144
	IEEE802_11_AVS             Link = 163
	BACNET_MS_TP               Link = 165
	PPP_PPPD                   Link = 166
	GPRS_LLC                   Link = 169
	LINUX_LAPD                 Link = 177
	BLUETOOTH_HCI_H4           Link = 187
	USB_LINUX                  Link = 189
	PPI                        Link = 192
	IEEE802_15_4               Link = 195
	SITA                       Link = 196
	ERF                        Link = 197
	BLUETOOTH_HCI_H4_WITH_PHDR Link = 201
	AX25_KISS                  Link = 202
	LAPD                       Link = 203
	PPP_WITH_DIR               Link = 204
	C_HDLC_WITH_DIR            Link = 205
	FRELAY_WITH_DIR            Link = 206
	IPMB_LINUX                 Link = 209
	IEEE802_15_4_NONASK_PHY    Link = 215
	USB_LINUX_MMAPPED          Link = 220
	FC_2                       Link = 224
	FC_2_WITH_FRAME_DELIMS     Link = 225
	IPNET                      Link = 226
	CAN_SOCKETCAN              Link = 227
	IPV4                       Link = 228
	IPV6                       Link = 229
	IEEE802_15_4_NOFCS         Link = 230
	DBUS                       Link = 231
	DVB_CI                     Link = 235
	MUX27010                   Link = 236
	STANAG_5066_D_PDU          Link = 237
	NFLOG                      Link = 239
	NETANALYZER                Link = 240
	NETANALYZER_TRANSPARENT    Link = 241
	IPOIB                      Link = 242
	MPEG_2_TS                  Link = 243
	NG40                       Link = 244
	NFC_LLCP                   Link = 245
	INFINIBAND                 Link = 247
	SCTP                       Link = 248
	USBPCAP                    Link = 249
	RTAC_SERIAL                Link = 250
	BLUETOOTH_LE_LL            Link = 251
)

// PcapFile represents the parsed form of a single .pcap file. The structure
// contains some details about the file itself, but is mostly a container for
// the parsed Packets.
type PcapFile struct {
	MajorVersion uint16
	MinorVersion uint16
	TZCorrection int32 // In seconds east of UTC
	SigFigs      uint32
	MaxLen       uint32
	LinkType     Link
	Packets      []Packet
}

// Packet is a representation of a single network packet. The structure
// contains the timestamp on the packet, some information about packet size,
// and the recorded bytes from the packet.
type Packet struct {
	Timestamp   time.Duration
	IncludedLen uint32
	ActualLen   uint32
	Data        LinkLayer
}

// LinkLayer is a non-specific representation of a single link-layer level datagram, e.g. an Ethernet
// frame. It provides an abstract interface for pulling the lower layers out without specific knowledge
// of the structure of the link-layer in question.
type LinkLayer interface {
	LinkData() []byte
	FromBytes(data []byte) error
}

// InternetLayer is a non-specific representation of a single internet-layer level datagram, e.g. an
// IPv4 datagram. It provides an abstract interface for pulling the higher layers out without specific
// knowledge of the structure of the internet-layer in question.
type InternetLayer interface {
	InternetData() []byte
	FromBytes(data []byte) error
}

// Parse is the external API of gopcap. It takes anything that implements the
// io.Reader interface, but will mostly expect a file produced by anything that
// produces .pcap files. It will attempt to parse the entire file. If an error
// is encountered, as much of the parsed content as is possible will be returned,
// along with an error value.
func Parse(src io.Reader) (PcapFile, error) {
	file := new(PcapFile)

	// Check whether this is a libpcap file at all, and if so what byte ordering it has.
	_, flipped, err := checkMagicNum(src)
	if err != nil {
		return *file, err
	}

	// Then populate the file header.
	err = populateFileHeader(file, src, flipped)
	if err != nil {
		return *file, err
	}

	// Whatever remains now are packets. Parse the rest of the file.
	file.Packets = make([]Packet, 0)

	for err == nil {
		pkt := new(Packet)
		err = parsePacket(pkt, src, flipped, file.LinkType)
		file.Packets = append(file.Packets, *pkt)
	}

	// EOF is a safe error, so switch that to nil.
	if err == io.EOF {
		err = nil
	}

	return *file, err
}
<commit_msg>Higher.<commit_after>/*
gopcap is pure-Go implementation of a parser for .pcap files. Written from the
ground up for plugging directly into other components, the API is focused on
simplicity and clarity. To this end, it exposes the barest minimum of
functionality in as clear an API as possible.
*/
package gopcap

import (
	"errors"
	"io"
	"time"
)

// Errors
var NotAPcapFile error = errors.New("Not a pcap file.")
var InsufficientLength error = errors.New("Insufficient length.")
var UnexpectedEOF error = errors.New("Unexpected EOF.")

// Link encodes a given Link-Layer header type. See http://www.tcpdump.org/linktypes.html for a more-full
// explanation of each header type.
type Link uint32

const (
	NULL                       Link = 0
	ETHERNET                   Link = 1
	AX25                       Link = 3
	IEEE802_5                  Link = 6
	ARCNET_BSD                 Link = 7
	SLIP                       Link = 8
	PPP                        Link = 9
	FDDI                       Link = 10
	PPP_HDLC                   Link = 50
	PPP_ETHER                  Link = 51
	ATM_RFC1483                Link = 100
	RAW                        Link = 101
	C_HDLC                     Link = 104
	IEEE802_11                 Link = 105
	FRELAY                     Link = 107
	LOOP                       Link = 108
	LINUX_SLL                  Link = 113
	LTALK                      Link = 114
	PFLOG                      Link = 117
	IEEE802_11_PRISM           Link = 119
	IP_OVER_FC                 Link = 122
	SUNATM                     Link = 123
	IEEE802_11_RADIOTAP        Link = 127
	ARCNET_LINUX               Link = 129
	APPLE_IP_OVER_IEEE1394     Link = 138
	MTP2_WITH_PHDR             Link = 139
	MTP2                       Link = 140
	MTP3                       Link = 141
	SCCP                       Link = 142
	DOCSIS                     Link = 143
	LINUX_IRDA                 Link = 144
	IEEE802_11_AVS             Link = 163
	BACNET_MS_TP               Link = 165
	PPP_PPPD                   Link = 166
	GPRS_LLC                   Link = 169
	LINUX_LAPD                 Link = 177
	BLUETOOTH_HCI_H4           Link = 187
	USB_LINUX                  Link = 189
	PPI                        Link = 192
	IEEE802_15_4               Link = 195
	SITA                       Link = 196
	ERF                        Link = 197
	BLUETOOTH_HCI_H4_WITH_PHDR Link = 201
	AX25_KISS                  Link = 202
	LAPD                       Link = 203
	PPP_WITH_DIR               Link = 204
	C_HDLC_WITH_DIR            Link = 205
	FRELAY_WITH_DIR            Link = 206
	IPMB_LINUX                 Link = 209
	IEEE802_15_4_NONASK_PHY    Link = 215
	USB_LINUX_MMAPPED          Link = 220
	FC_2                       Link = 224
	FC_2_WITH_FRAME_DELIMS     Link = 225
	IPNET                      Link = 226
	CAN_SOCKETCAN              Link = 227
	IPV4                       Link = 228
	IPV6                       Link = 229
	IEEE802_15_4_NOFCS         Link = 230
	DBUS                       Link = 231
	DVB_CI                     Link = 235
	MUX27010                   Link = 236
	STANAG_5066_D_PDU          Link = 237
	NFLOG                      Link = 239
	NETANALYZER                Link = 240
	NETANALYZER_TRANSPARENT    Link = 241
	IPOIB                      Link = 242
	MPEG_2_TS                  Link = 243
	NG40                       Link = 244
	NFC_LLCP                   Link = 245
	INFINIBAND                 Link = 247
	SCTP                       Link = 248
	USBPCAP                    Link = 249
	RTAC_SERIAL                Link = 250
	BLUETOOTH_LE_LL            Link = 251
)

// PcapFile represents the parsed form of a single .pcap file. The structure
// contains some details about the file itself, but is mostly a container for
// the parsed Packets.
type PcapFile struct {
	MajorVersion uint16
	MinorVersion uint16
	TZCorrection int32 // In seconds east of UTC
	SigFigs      uint32
	MaxLen       uint32
	LinkType     Link
	Packets      []Packet
}

// Packet is a representation of a single network packet. The structure
// contains the timestamp on the packet, some information about packet size,
// and the recorded bytes from the packet.
type Packet struct {
	Timestamp   time.Duration
	IncludedLen uint32
	ActualLen   uint32
	Data        LinkLayer
}

// LinkLayer is a non-specific representation of a single link-layer level datagram, e.g. an Ethernet
// frame. It provides an abstract interface for pulling the higher layers out without specific knowledge
// of the structure of the link-layer in question.
type LinkLayer interface {
	LinkData() []byte
	FromBytes(data []byte) error
}

// InternetLayer is a non-specific representation of a single internet-layer level datagram, e.g. an
// IPv4 datagram. It provides an abstract interface for pulling the higher layers out without specific
// knowledge of the structure of the internet-layer in question.
type InternetLayer interface {
	InternetData() []byte
	FromBytes(data []byte) error
}

// Parse is the external API of gopcap. It takes anything that implements the
// io.Reader interface, but will mostly expect a file produced by anything that
// produces .pcap files. It will attempt to parse the entire file. If an error
// is encountered, as much of the parsed content as is possible will be returned,
// along with an error value.
func Parse(src io.Reader) (PcapFile, error) {
	file := new(PcapFile)

	// Check whether this is a libpcap file at all, and if so what byte ordering it has.
	_, flipped, err := checkMagicNum(src)
	if err != nil {
		return *file, err
	}

	// Then populate the file header.
	err = populateFileHeader(file, src, flipped)
	if err != nil {
		return *file, err
	}

	// Whatever remains now are packets. Parse the rest of the file.
	file.Packets = make([]Packet, 0)

	for err == nil {
		pkt := new(Packet)
		err = parsePacket(pkt, src, flipped, file.LinkType)
		file.Packets = append(file.Packets, *pkt)
	}

	// EOF is a safe error, so switch that to nil.
	if err == io.EOF {
		err = nil
	}

	return *file, err
}
<|endoftext|>