<commit_before>package http2

import (
	"encoding/hex"
	"fmt"
	hpack "github.com/ami-GS/GoHPACK"
)

type Http2Header struct {
	Wire       []byte
	Length     uint32
	Type, Flag byte
	StreamID   uint32
}

func (self *Http2Header) Pack() {
	self.Wire = make([]byte, 9)
	for i := 0; i < 3; i++ {
		self.Wire[i] = byte(self.Length >> byte((2-i)*8))
	}
	self.Wire[3], self.Wire[4] = self.Type, self.Flag
	for i := 0; i < 4; i++ {
		self.Wire[i+5] = byte(self.StreamID >> byte((3-i)*8))
	}
}

func (self *Http2Header) Parse(data []byte) {
	self.Length = uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
	self.Type = data[3]
	self.Flag = data[4]
	self.StreamID = uint32(data[5])<<24 | uint32(data[6])<<16 | uint32(data[7])<<8 | uint32(data[8])
}

type Data struct {
	Wire   []byte
	Data   string
	PadLen byte
}

func NewData(data string, streamID uint32, flag, padLen byte) []byte {
	frame := Data{Data: data, PadLen: padLen}
	frame.Pack(flag)
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_DATA, Flag: flag, StreamID: streamID}
	header.Pack()
	return append(header.Wire, frame.Wire...)
}

func (self *Data) Pack(flag byte) {
	idx := 0
	if flag == FLAG_PADDED {
		self.Wire = make([]byte, len(self.Data)+int(self.PadLen+1))
		self.Wire[idx] = self.PadLen
		idx++
	} else {
		self.Wire = make([]byte, uint32(len(self.Data)))
	}
	for i, d := range self.Data {
		self.Wire[idx+i] = byte(d)
	}
}

func (self *Data) Parse(data []byte, flag byte, length uint32) {
	if flag == FLAG_PADDED {
		self.PadLen = data[0]
		self.Data = string(data[1 : length-uint32(self.PadLen)])
	} else {
		self.Data = string(data)
	}
}

type Settings struct {
	Wire      []byte
	SettingID uint16
	Value     uint32
}

func NewSettings(settingID uint16, value uint32, flag byte) []byte {
	frame := Settings{SettingID: settingID, Value: value}
	frame.Pack()
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_SETTINGS, Flag: flag, StreamID: 0}
	header.Pack()
	return append(header.Wire, frame.Wire...)
}

func (self *Settings) Pack() {
	self.Wire = make([]byte, 6)
	for i := 0; i < 2; i++ {
		self.Wire[i] = byte(self.SettingID >> byte((1-i)*8))
	}
	for i := 0; i < 4; i++ {
		self.Wire[2+i] = byte(self.Value >> byte((3-i)*8))
	}
}

func (self *Settings) Parse(data []byte, flag byte) {
	self.SettingID = uint16(data[0])<<8 | uint16(data[1])
	self.Value = uint32(data[2])<<24 | uint32(data[3])<<16 | uint32(data[4])<<8 | uint32(data[5])
	_ = flag //temporally
}

type Headers struct {
	Wire             []byte
	Headers          []hpack.Header
	PadLen, Weight   byte
	E                bool
	StreamDependency uint32
}

func NewHeaders(headers []hpack.Header, table *hpack.Table, streamID uint32, flag, padLen, weight byte, e bool, streamDependency uint32) []byte {
	frame := Headers{Headers: headers, PadLen: padLen, Weight: weight, E: e, StreamDependency: streamDependency}
	frame.Pack(flag, table)
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_HEADERS, Flag: flag, StreamID: streamID}
	header.Pack()
	return append(header.Wire, frame.Wire...)
}

func (self *Headers) Pack(flag byte, table *hpack.Table) {
	idx := 0
	encHeaders, err := hex.DecodeString(hpack.Encode(self.Headers, false, false, false, table, -1))
	if err != nil {
		panic(err)
	}
	if flag == FLAG_PADDED {
		self.Wire = make([]byte, int(self.PadLen+1)+len(encHeaders))
		self.Wire[idx] = self.PadLen
		idx++
	} else if flag == FLAG_PRIORITY {
		self.Wire = make([]byte, 5+len(encHeaders))
		for i := 0; i < 4; i++ {
			self.Wire[i] = byte(self.StreamDependency >> byte((3-i)*8))
		}
		if self.E {
			self.Wire[0] |= 0x80
		}
		self.Wire[4] = self.Weight
		idx = 5
	} else if flag == FLAG_END_HEADERS || flag == FLAG_END_STREAM {
		self.Wire = make([]byte, len(encHeaders))
	} else {
		panic("undefined flag")
	}
	for i, h := range encHeaders {
		self.Wire[idx+i] = h
	}
}

func (self *Headers) Parse(data []byte, flag byte, table *hpack.Table) {
	idx := 0
	if flag == FLAG_PADDED {
		self.PadLen = data[idx]
		idx++
	} else if flag == FLAG_PRIORITY {
		if data[0]&0x80 > 0 {
			self.E = true
		}
		self.StreamDependency = uint32(data[0]&0xef)<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
		self.Weight = data[4]
		idx += 5
	} else if flag == FLAG_END_HEADERS || flag == FLAG_END_STREAM {
		fmt.Println("change stream state")
	} else {
		panic("undefined flag")
	}
	self.Headers = hpack.Decode(hex.EncodeToString(data[idx:len(data)-int(self.PadLen)]), table)
}

type GoAway struct {
	Wire         []byte
	LastStreamID uint32
	ErrorCode    uint32
	Debug        string
}

func NewGoAway(lastStreamID, errorCode uint32, debug string) []byte {
	frame := GoAway{LastStreamID: lastStreamID, ErrorCode: errorCode, Debug: debug}
	frame.Pack()
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_GOAWAY, Flag: FLAG_NO, StreamID: 0}
	header.Pack()
	return append(header.Wire, frame.Wire...)

}

func (self *GoAway) Pack() {
	self.Wire = make([]byte, 8+len(self.Debug))
	for i := 0; i < 4; i++ {
		self.Wire[i] = byte(self.LastStreamID >> byte((3-i)*8))
		self.Wire[i+4] = byte(self.ErrorCode >> byte((3-i)*8))
	}
	for i, d := range self.Debug {
		self.Wire[i+8] = byte(d)
	}
}

func (self *GoAway) Parse(data []byte) {
	self.LastStreamID = uint32(data[0]&0xef)<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
	self.ErrorCode = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
	if len(data) >= 9 {
		self.Debug = string(data[8:])
	}
}

func main() {
	table := hpack.InitTable()
	headers := []hpack.Header{hpack.Header{":method", "GET"}, hpack.Header{":scheme", "http"},
		hpack.Header{":authority", "127.0.0.1"}, hpack.Header{":path", "/"}}

	http2Header := Http2Header{Length: 12, Type: TYPE_DATA, Flag: FLAG_PADDED, StreamID: 1}
	http2Header.Pack()
	fmt.Printf("http2Header %v\n", http2Header)
	data := Data{Data: "Hello!", PadLen: 5}
	data.Pack(http2Header.Flag)
	data2 := Data{}
	data2.Parse(data.Wire, http2Header.Flag, http2Header.Length)
	fmt.Printf("data %v\n", data)
	fmt.Printf("data2 %v\n", data2)
	settings := Settings{SettingID: 0xff00, Value: 0xff00ff00}
	settings2 := Settings{}
	settings.Pack()
	settings2.Parse(settings.Wire, http2Header.Flag)
	fmt.Printf("settings %v\n", settings)
	fmt.Printf("settings2 %v\n", settings2)
	h := Headers{Headers: headers, PadLen: 5, Weight: 0, E: false}
	h2 := Headers{}
	h.Pack(http2Header.Flag, &table)
	h2.Parse(h.Wire, http2Header.Flag, &table)
	fmt.Printf("headers %v\n", h)
	fmt.Printf("headers2 %v\n", h2)
	goaway := GoAway{LastStreamID: 0xef00ff00, ErrorCode: 0xff00ff00, Debug: "DEBUG MESSAGE!!"}
	goaway2 := GoAway{}
	goaway.Pack()
	goaway2.Parse(goaway.Wire)
	fmt.Printf("goaway %v\n", goaway)
	fmt.Printf("goaway2 %v\n", goaway2)
}
<commit_msg>adjust for new version of HPACK<commit_after>package http2

import (
	"fmt"
	hpack "github.com/ami-GS/GoHPACK"
)

type Http2Header struct {
	Wire       []byte
	Length     uint32
	Type, Flag byte
	StreamID   uint32
}

func (self *Http2Header) Pack() {
	self.Wire = make([]byte, 9)
	for i := 0; i < 3; i++ {
		self.Wire[i] = byte(self.Length >> byte((2-i)*8))
	}
	self.Wire[3], self.Wire[4] = self.Type, self.Flag
	for i := 0; i < 4; i++ {
		self.Wire[i+5] = byte(self.StreamID >> byte((3-i)*8))
	}
}

func (self *Http2Header) Parse(data []byte) {
	self.Length = uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
	self.Type = data[3]
	self.Flag = data[4]
	self.StreamID = uint32(data[5])<<24 | uint32(data[6])<<16 | uint32(data[7])<<8 | uint32(data[8])
}

type Data struct {
	Wire   []byte
	Data   string
	PadLen byte
}

func NewData(data string, streamID uint32, flag, padLen byte) []byte {
	frame := Data{Data: data, PadLen: padLen}
	frame.Pack(flag)
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_DATA, Flag: flag, StreamID: streamID}
	header.Pack()
	return append(header.Wire, frame.Wire...)
}

func (self *Data) Pack(flag byte) {
	idx := 0
	if flag == FLAG_PADDED {
		self.Wire = make([]byte, len(self.Data)+int(self.PadLen+1))
		self.Wire[idx] = self.PadLen
		idx++
	} else {
		self.Wire = make([]byte, uint32(len(self.Data)))
	}
	for i, d := range self.Data {
		self.Wire[idx+i] = byte(d)
	}
}

func (self *Data) Parse(data []byte, flag byte, length uint32) {
	if flag == FLAG_PADDED {
		self.PadLen = data[0]
		self.Data = string(data[1 : length-uint32(self.PadLen)])
	} else {
		self.Data = string(data)
	}
}

type Settings struct {
	Wire      []byte
	SettingID uint16
	Value     uint32
}

func NewSettings(settingID uint16, value uint32, flag byte) []byte {
	frame := Settings{SettingID: settingID, Value: value}
	frame.Pack()
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_SETTINGS, Flag: flag, StreamID: 0}
	header.Pack()
	return append(header.Wire, frame.Wire...)
}

func (self *Settings) Pack() {
	self.Wire = make([]byte, 6)
	for i := 0; i < 2; i++ {
		self.Wire[i] = byte(self.SettingID >> byte((1-i)*8))
	}
	for i := 0; i < 4; i++ {
		self.Wire[2+i] = byte(self.Value >> byte((3-i)*8))
	}
}

func (self *Settings) Parse(data []byte, flag byte) {
	self.SettingID = uint16(data[0])<<8 | uint16(data[1])
	self.Value = uint32(data[2])<<24 | uint32(data[3])<<16 | uint32(data[4])<<8 | uint32(data[5])
	_ = flag //temporally
}

type Headers struct {
	Wire             []byte
	Headers          []hpack.Header
	PadLen, Weight   byte
	E                bool
	StreamDependency uint32
}

func NewHeaders(headers []hpack.Header, table *hpack.Table, streamID uint32, flag, padLen, weight byte, e bool, streamDependency uint32) []byte {
	frame := Headers{Headers: headers, PadLen: padLen, Weight: weight, E: e, StreamDependency: streamDependency}
	frame.Pack(flag, table)
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_HEADERS, Flag: flag, StreamID: streamID}
	header.Pack()
	return append(header.Wire, frame.Wire...)
}

func (self *Headers) Pack(flag byte, table *hpack.Table) {
	idx := 0
	encHeaders := hpack.Encode(self.Headers, false, false, false, table, -1)
	if flag == FLAG_PADDED {
		self.Wire = make([]byte, int(self.PadLen+1)+len(encHeaders))
		self.Wire[idx] = self.PadLen
		idx++
	} else if flag == FLAG_PRIORITY {
		self.Wire = make([]byte, 5+len(encHeaders))
		for i := 0; i < 4; i++ {
			self.Wire[i] = byte(self.StreamDependency >> byte((3-i)*8))
		}
		if self.E {
			self.Wire[0] |= 0x80
		}
		self.Wire[4] = self.Weight
		idx = 5
	} else if flag == FLAG_END_HEADERS || flag == FLAG_END_STREAM {
		self.Wire = make([]byte, len(encHeaders))
	} else {
		panic("undefined flag")
	}
	for i, h := range encHeaders {
		self.Wire[idx+i] = h
	}
}

func (self *Headers) Parse(data []byte, flag byte, table *hpack.Table) {
	idx := 0
	if flag == FLAG_PADDED {
		self.PadLen = data[idx]
		idx++
	} else if flag == FLAG_PRIORITY {
		if data[0]&0x80 > 0 {
			self.E = true
		}
		self.StreamDependency = uint32(data[0]&0xef)<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
		self.Weight = data[4]
		idx += 5
	} else if flag == FLAG_END_HEADERS || flag == FLAG_END_STREAM {
		fmt.Println("change stream state")
	} else {
		panic("undefined flag")
	}
	self.Headers = hpack.Decode(data[idx:len(data)-int(self.PadLen)], table)
}

type GoAway struct {
	Wire         []byte
	LastStreamID uint32
	ErrorCode    uint32
	Debug        string
}

func NewGoAway(lastStreamID, errorCode uint32, debug string) []byte {
	frame := GoAway{LastStreamID: lastStreamID, ErrorCode: errorCode, Debug: debug}
	frame.Pack()
	header := Http2Header{Length: uint32(len(frame.Wire)), Type: TYPE_GOAWAY, Flag: FLAG_NO, StreamID: 0}
	header.Pack()
	return append(header.Wire, frame.Wire...)

}

func (self *GoAway) Pack() {
	self.Wire = make([]byte, 8+len(self.Debug))
	for i := 0; i < 4; i++ {
		self.Wire[i] = byte(self.LastStreamID >> byte((3-i)*8))
		self.Wire[i+4] = byte(self.ErrorCode >> byte((3-i)*8))
	}
	for i, d := range self.Debug {
		self.Wire[i+8] = byte(d)
	}
}

func (self *GoAway) Parse(data []byte) {
	self.LastStreamID = uint32(data[0]&0xef)<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
	self.ErrorCode = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
	if len(data) >= 9 {
		self.Debug = string(data[8:])
	}
}

func main() {
	table := hpack.InitTable()
	headers := []hpack.Header{hpack.Header{":method", "GET"}, hpack.Header{":scheme", "http"},
		hpack.Header{":authority", "127.0.0.1"}, hpack.Header{":path", "/"}}

	http2Header := Http2Header{Length: 12, Type: TYPE_DATA, Flag: FLAG_PADDED, StreamID: 1}
	http2Header.Pack()
	fmt.Printf("http2Header %v\n", http2Header)
	data := Data{Data: "Hello!", PadLen: 5}
	data.Pack(http2Header.Flag)
	data2 := Data{}
	data2.Parse(data.Wire, http2Header.Flag, http2Header.Length)
	fmt.Printf("data %v\n", data)
	fmt.Printf("data2 %v\n", data2)
	settings := Settings{SettingID: 0xff00, Value: 0xff00ff00}
	settings2 := Settings{}
	settings.Pack()
	settings2.Parse(settings.Wire, http2Header.Flag)
	fmt.Printf("settings %v\n", settings)
	fmt.Printf("settings2 %v\n", settings2)
	h := Headers{Headers: headers, PadLen: 5, Weight: 0, E: false}
	h2 := Headers{}
	h.Pack(http2Header.Flag, &table)
	h2.Parse(h.Wire, http2Header.Flag, &table)
	fmt.Printf("headers %v\n", h)
	fmt.Printf("headers2 %v\n", h2)
	goaway := GoAway{LastStreamID: 0xef00ff00, ErrorCode: 0xff00ff00, Debug: "DEBUG MESSAGE!!"}
	goaway2 := GoAway{}
	goaway.Pack()
	goaway2.Parse(goaway.Wire)
	fmt.Printf("goaway %v\n", goaway)
	fmt.Printf("goaway2 %v\n", goaway2)
}
<|endoftext|>


<commit_before>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements the frame data type.

package golisp

import (
	"gopkg.in/fatih/set.v0"
	"strings"
)

type FrameMap map[string]*Data

func (self *FrameMap) hasSlotLocally(key string) bool {
	_, ok := (*self)[key]
	return ok
}

func (self *FrameMap) localSlots() []string {
	slots := make([]string, 0, len(*self))
	for k, _ := range *self {
		slots = append(slots, k)
	}
	return slots
}

func isParentKey(key string) bool {
	return strings.HasSuffix(key, "*:")
}

func (self *FrameMap) hasParentSlots() bool {
	for k, _ := range *self {
		if isParentKey(k) {
			return true
		}
	}

	return false
}

func (self *FrameMap) parentSlots() []string {
	slots := make([]string, 0, len(*self))
	for k, _ := range *self {
		if isParentKey(k) {
			slots = append(slots, k)
		}
	}
	return slots
}

func (self *FrameMap) Parents() []*FrameMap {
	parents := make([]*FrameMap, 0, 0)
	for k, v := range *self {
		if isParentKey(k) {
			parents = append(parents, FrameValue(v))
		}
	}
	return parents
}

func toSet(items []string) *set.Set {
	s := set.New()
	for _, i := range items {
		s.Add(i)
	}
	return s
}

func (self *FrameMap) inheritedValueSlots() []string {
	parentFrames := self.Parents()
	inheritedSlots := make([][]string, len(parentFrames))
	for _, p := range parentFrames {
		inheritedSlots = append(inheritedSlots, p.inheritedValueSlots())
	}

	slots := set.New()
	for _, s := range self.localSlots() {
		if !isParentKey(s) {
			slots.Add(s)
		}
	}

	for _, is := range inheritedSlots {
		slots.Merge(toSet(is))
	}

	return set.StringSlice(slots)
}

func (self *FrameMap) HasSlot(key string) bool {
	if self.hasSlotLocally(key) {
		return true
	}

	if !self.hasParentSlots() {
		return false
	}

	for _, p := range self.Parents() {
		if p.HasSlot(key) {
			return true
		}
	}

	return false
}

func (self *FrameMap) Get(key string) *Data {
	v, ok := (*self)[key]
	if ok {
		return v
	}

	for _, p := range self.Parents() {
		v := p.Get(key)
		if v != nil {
			return v
		}
	}

	return nil
}

func (self *FrameMap) Remove(key string) bool {
	if !self.hasSlotLocally(key) {
		return false
	}
	delete(*self, key)
	return true
}

func (self *FrameMap) Set(key string, value *Data) *Data {
	if !self.HasSlot(key) || self.hasSlotLocally(key) {
		(*self)[key] = value
		return value
	}

	for _, p := range self.Parents() {
		v := p.Set(key, value)
		if v != nil {
			return v
		}
	}
	return nil
}

func (self *FrameMap) Clone() *FrameMap {
	f := make(FrameMap)
	for k, v := range *self {
		f[k] = v
	}
	return &f
}
<commit_msg>Remove unused code, add protection against circular parent graphs and diamond inheritance.<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements the frame data type.

package golisp

import (
	"gopkg.in/fatih/set.v0"
	"strings"
)

type FrameMap map[string]*Data

func (self *FrameMap) hasSlotLocally(key string) bool {
	_, ok := (*self)[key]
	return ok
}

func (self *FrameMap) localSlots() []string {
	slots := make([]string, 0, len(*self))
	for k, _ := range *self {
		slots = append(slots, k)
	}
	return slots
}

func isParentKey(key string) bool {
	return strings.HasSuffix(key, "*:")
}

func (self *FrameMap) hasParentSlots() bool {
	for k, _ := range *self {
		if isParentKey(k) {
			return true
		}
	}

	return false
}

func (self *FrameMap) parentSlots() []string {
	slots := make([]string, 0, len(*self))
	for k, _ := range *self {
		if isParentKey(k) {
			slots = append(slots, k)
		}
	}
	return slots
}

func (self *FrameMap) Parents() []*FrameMap {
	parents := make([]*FrameMap, 0, 0)
	for k, v := range *self {
		if isParentKey(k) {
			parents = append(parents, FrameValue(v))
		}
	}
	return parents
}

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

func (self *FrameMap) hasSlotHelper(key string, v *set.Set) bool {
	if v.Has(self) {
		return false
	}

	v.Add(self)

	if self.hasSlotLocally(key) {
		return true
	}

	if !self.hasParentSlots() {
		return false
	}

	for _, p := range self.Parents() {
		if p.hasSlotHelper(key, v) {
			return true
		}
	}

	return false
}

func (self *FrameMap) HasSlot(key string) bool {
	visited := set.New()
	return self.hasSlotHelper(key, visited)
}

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

func (self *FrameMap) getHelper(key string, v *set.Set) *Data {
	if v.Has(self) {
		return nil
	}

	v.Add(self)

	val, ok := (*self)[key]
	if ok {
		return val
	}

	for _, p := range self.Parents() {
		val := p.getHelper(key, v)
		if val != nil {
			return val
		}
	}

	return nil
}

func (self *FrameMap) Get(key string) *Data {
	visited := set.New()
	return self.getHelper(key, visited)
}

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

func (self *FrameMap) Remove(key string) bool {
	if !self.hasSlotLocally(key) {
		return false
	}
	delete(*self, key)
	return true
}

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

func (self *FrameMap) setHelper(key string, value *Data, v *set.Set) *Data {
	if v.Has(self) {
		return nil
	}

	v.Add(self)

	if !self.HasSlot(key) || self.hasSlotLocally(key) {
		(*self)[key] = value
		return value
	}

	for _, p := range self.Parents() {
		v := p.Set(key, value)
		if v != nil {
			return v
		}
	}
	return nil
}

func (self *FrameMap) Set(key string, value *Data) *Data {
	visited := set.New()
	return self.setHelper(key, value, visited)
}

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

func (self *FrameMap) Clone() *FrameMap {
	f := make(FrameMap)
	for k, v := range *self {
		f[k] = v
	}
	return &f
}
<|endoftext|>


<commit_before>/*
See https://github.com/glycerine/tmframe for the specification of the TMFRAME
format which we implement here.
*/
package frame

import (
	"encoding/binary"
	"fmt"
	"math"
	"time"
)

// PTI is the Payload Type Indicator. It is the low 3-bits
// of the Primary word in a TMFRAME message.
type PTI byte

const (
	PtiZero       PTI = 0
	PtiOne        PTI = 1
	PtiOneFloat64 PTI = 2
	PtiTwo64      PTI = 3
	PtiNull       PTI = 4
	PtiNA         PTI = 5
	PtiNaN        PTI = 6
	PtiUDE        PTI = 7
)

// The Evtnum is the message type when pti = PtiUDE and
// UDE descriptors are in use for describing TMFRAME
// message longer than just the one Primary word.
type Evtnum int32

const (
	EvErr Evtnum = -1

	// 0-7 deliberately match the PTI to make the
	// API easier to use. Callers to NewFrame need
	// only specify an Evtnum, and the framing code
	// sets PTI and EVTNUM correctly.
	EvZero       Evtnum = 0
	EvOne        Evtnum = 1
	EvOneFloat64 Evtnum = 2
	EvTwo64      Evtnum = 3
	EvNull       Evtnum = 4
	EvNA         Evtnum = 5
	EvNaN        Evtnum = 6
	EvUDE        Evtnum = 7

	EvHeader    Evtnum = 8
	EvMsgpack   Evtnum = 9
	EvBinc      Evtnum = 10
	EvCapnp     Evtnum = 11
	EvZygo      Evtnum = 12
	EvUtf8      Evtnum = 13
	EvJson      Evtnum = 14
	EvMsgpKafka Evtnum = 15
)

// Frame holds a fully parsed TMFRAME message.
type Frame struct {
	Prim int64 // the primary word
	//GetTm()  int64 // returns low 3 bits all zeros, nanoseconds since unix epoch.
	//GetPTI() PTI   // returns low 3 bits of the primary word

	V0 float64 // primary float64 value, for EvOneFloat64 and EvTwo64
	V1 int64   // uint64 secondary payload, for EvTwo64

	Ude int64 // the User-Defined-Encoding word

	// break down the Ude:
	//GetEvtnum() Evtnum
	//GetUlen()  int64

	Data []byte // the variable length payload after the UDE
}

func (f *Frame) GetTm() int64 {
	return f.Prim &^ 7
}

func (f *Frame) GetPTI() PTI {
	return PTI(f.Prim & 7)
}

func (f *Frame) GetUDE() int64 {
	return f.Ude
}

func (f *Frame) GetUlen() int64 {
	if f.GetPTI() != PtiUDE || len(f.Data) == 0 {
		return 0
	}
	return int64(len(f.Data)) + 1 // +1 for the zero termination that only goes on the wire
}

func (f *Frame) GetEvtnum() Evtnum {
	pti := f.GetPTI()
	evnum := Evtnum(pti)
	if pti != PtiUDE {
		return evnum
	}
	evnum = Evtnum(f.Ude >> 43)
	return evnum
}

func (f *Frame) GetV0() float64 {
	pti := f.GetPTI()
	switch pti {
	case PtiZero:
		return 0
	case PtiOne:
		return 1
	case PtiOneFloat64:
		return f.V0
	case PtiTwo64:
		return f.V0
	}
	return MyNaN
}

func (f *Frame) GetV1() int64 {
	if f.GetPTI() == PtiTwo64 {
		return f.V1
	}
	return 0
}

var MyNaN float64

func init() {
	MyNaN = math.NaN()
}

// Marshal serialized the Frame into bytes. We'll
// reuse the space pointed to by buf if there is
// sufficient space in it. We return the bytes
// that we wrote, plus any error.
func (f *Frame) Marshal(buf []byte) ([]byte, error) {
	n := 8
	pti := f.GetPTI()
	switch pti {
	case PtiZero:
		n = 8
	case PtiOne:
		n = 8
	case PtiOneFloat64:
		n = 16
	case PtiTwo64:
		n = 24
	case PtiNull:
		n = 8
	case PtiNA:
		n = 8
	case PtiNaN:
		n = 8
	case PtiUDE:
		n = 16
		if len(f.Data) > 0 {
			n += len(f.Data) + 1 // +1 for the zero termination that only goes on the wire
		}
	default:
		panic(fmt.Sprintf("unrecog pti: %v", pti))
	}
	var m []byte
	if len(buf) >= n {
		m = buf[:n]
	} else {
		m = make([]byte, n)
	}
	binary.LittleEndian.PutUint64(m[:8], uint64(f.Prim))
	if n == 8 {
		return m, nil
	}
	switch pti {
	case PtiOneFloat64:
		binary.LittleEndian.PutUint64(m[8:16], math.Float64bits(f.V0))
	case PtiTwo64:
		binary.LittleEndian.PutUint64(m[8:16], math.Float64bits(f.V0))
		binary.LittleEndian.PutUint64(m[16:24], uint64(f.V1))
	case PtiUDE:
		binary.LittleEndian.PutUint64(m[8:16], uint64(f.Ude))
		if n == 16 {
			return m, nil
		}
		copy(m[16:], f.Data)
		m[n-1] = 0
	}

	return m, nil
}

var TooShortErr = fmt.Errorf("data supplied is too short to represent a TMFRAME frame")

// Unmarshal overwrites f with the restored value of the TMFRAME found
// in the by []byte data.
func (f *Frame) Unmarshal(by []byte) (rest []byte, err error) {
	// zero it all
	*f = Frame{}

	n := int64(len(by))
	if n < 8 {
		return by, TooShortErr
	}
	prim := binary.LittleEndian.Uint64(by[:8])
	pti := PTI(prim % 8)

	f.Prim = int64(prim)

	switch pti {
	case PtiZero:
		f.V0 = 0.0
		return by[8:], nil
	case PtiOne:
		f.V0 = 1.0
		return by[8:], nil
	case PtiOneFloat64:
		if n < 16 {
			return by, TooShortErr
		}
		f.V0 = math.Float64frombits(binary.LittleEndian.Uint64(by[8:16]))
		return by[16:], nil
	case PtiTwo64:
		if n < 24 {
			return by, TooShortErr
		}
		f.V0 = math.Float64frombits(binary.LittleEndian.Uint64(by[8:16]))
		f.V1 = int64(binary.LittleEndian.Uint64(by[16:24]))
		return by[24:], nil
	case PtiNull:
		return by[8:], nil
	case PtiNA:
		return by[8:], nil
	case PtiNaN:
		// don't actually do this, as it make reflect.DeepEquals not work (of course): f.V0 = MyNaN
		return by[8:], nil
	case PtiUDE:
		ude := binary.LittleEndian.Uint64(by[8:16])
		f.Ude = int64(ude)
		ucount := ude & KeepLow43Bits
		ulen := int64(ucount)
		if n < 16+ulen {
			return by, TooShortErr
		}
		if ulen > 0 {
			f.Data = by[16 : 16+ucount-1] // -1 because the zero terminating byte only goes on the wire
		}
		return by[16+ucount:], nil
	default:
		panic(fmt.Sprintf("unrecog pti: %v", pti))
	}
	panic("should never get here")
}

const KeepLow43Bits uint64 = 0x000007FFFFFFFFFF

var NoDataAllowedErr = fmt.Errorf("data must be empty for this evtnum")
var EvtnumOutOfRangeErr = fmt.Errorf("evtnum out of range. min allowed is -1048576, max is 1048575")

// Validate our acceptable range of evtnum.
// The min allowed is -1048576, max allowed is 1048575
func ValidEvtnum(evtnum Evtnum) bool {
	if evtnum > 1048575 || evtnum < -1048576 {
		return false
	}
	return true
}

// NewFrame creates a new TMFRAME message, ready to have Marshal called on
// for serialization into bytes. It will not make an internal copy of data.
// When copied on to the wire with Marshal(), a zero byte will be added
// to the data to make interop with C bindings easier; hence the UCOUNT will
// always include in its count this terminating zero byte if len(data) > 0.
//
func NewFrame(tm time.Time, evtnum Evtnum, v0 float64, v1 int64, data []byte) (*Frame, error) {

	if !ValidEvtnum(evtnum) {
		return nil, EvtnumOutOfRangeErr
	}

	// sanity check that data is empty when it should be
	if len(data) > 0 {
		if evtnum >= 0 && evtnum < 7 {
			return nil, NoDataAllowedErr
		}
	}

	utm := tm.UnixNano()
	mod := utm - (utm % 8)

	en := uint64(evtnum % (1 << 21))
	Q("en = %v", en)
	Q("pre shift en = %b", en)
	en = en << 43
	Q("post shift en = %b", en)
	Q("len(data) = %v", len(data))
	Q("len(data) = %b", len(data))
	var ude uint64
	if len(data) > 0 {
		// the +1 is so we zero-terminate strings -- for C bindings
		ude = uint64(len(data)+1) | en
	} else {
		ude = en
	}
	Q("ude = %b", ude)

	var useData []byte
	var myUDE uint64
	//var myUlen int64

	var pti PTI
	switch evtnum {
	case EvZero:
		pti = PtiZero
	case EvOne:
		pti = PtiOne
	case EvOneFloat64:
		pti = PtiOneFloat64
	case EvTwo64:
		pti = PtiTwo64
	case EvNull:
		pti = PtiNull
	case EvNA:
		pti = PtiNA
	case EvNaN:
		pti = PtiNaN
	default:
		// includes case EvUDE and EvErr
		pti = PtiUDE
		useData = data
		myUDE = ude
	}

	f := &Frame{
		Prim: mod | int64(pti),
		Ude:  int64(myUDE),
		Data: useData,
	}

	// set f.V0 and v.V1
	switch evtnum {
	case EvZero:
		f.V0 = 0.0
	case EvOne:
		f.V0 = 1.0
	case EvOneFloat64:
		f.V0 = v0
	case EvTwo64:
		f.V0 = v0
		f.V1 = v1
	}

	Q("f = %#v", f)
	return f, nil
}
<commit_msg>atg. docs++<commit_after>/*
See https://github.com/glycerine/tmframe for the specification of the TMFRAME
format which we implement here.
*/
package frame

import (
	"encoding/binary"
	"fmt"
	"math"
	"time"
)

// PTI is the Payload Type Indicator. It is the low 3-bits
// of the Primary word in a TMFRAME message.
type PTI byte

const (
	PtiZero       PTI = 0
	PtiOne        PTI = 1
	PtiOneFloat64 PTI = 2
	PtiTwo64      PTI = 3
	PtiNull       PTI = 4
	PtiNA         PTI = 5
	PtiNaN        PTI = 6
	PtiUDE        PTI = 7
)

// The Evtnum is the message type when pti = PtiUDE and
// UDE descriptors are in use for describing TMFRAME
// message longer than just the one Primary word.
type Evtnum int32

const (
	EvErr Evtnum = -1

	// 0-7 deliberately match the PTI to make the
	// API easier to use. Callers to NewFrame need
	// only specify an Evtnum, and the framing code
	// sets PTI and EVTNUM correctly.
	EvZero       Evtnum = 0
	EvOne        Evtnum = 1
	EvOneFloat64 Evtnum = 2
	EvTwo64      Evtnum = 3
	EvNull       Evtnum = 4
	EvNA         Evtnum = 5
	EvNaN        Evtnum = 6
	EvUDE        Evtnum = 7

	EvHeader    Evtnum = 8
	EvMsgpack   Evtnum = 9
	EvBinc      Evtnum = 10
	EvCapnp     Evtnum = 11
	EvZygo      Evtnum = 12
	EvUtf8      Evtnum = 13
	EvJson      Evtnum = 14
	EvMsgpKafka Evtnum = 15
)

// Frame holds a fully parsed TMFRAME message.
type Frame struct {
	Prim int64 // the primary word
	//GetTm()  int64 // returns low 3 bits all zeros, nanoseconds since unix epoch.
	//GetPTI() PTI   // returns low 3 bits of the primary word

	V0 float64 // primary float64 value, for EvOneFloat64 and EvTwo64
	V1 int64   // uint64 secondary payload, for EvTwo64

	Ude int64 // the User-Defined-Encoding word

	// break down the Ude:
	//GetEvtnum() Evtnum
	//GetUlen()  int64

	Data []byte // the variable length payload after the UDE
}

func (f *Frame) GetTm() int64 {
	return f.Prim &^ 7
}

func (f *Frame) GetPTI() PTI {
	return PTI(f.Prim & 7)
}

func (f *Frame) GetUDE() int64 {
	return f.Ude
}

func (f *Frame) GetUlen() int64 {
	if f.GetPTI() != PtiUDE || len(f.Data) == 0 {
		return 0
	}
	return int64(len(f.Data)) + 1 // +1 for the zero termination that only goes on the wire
}

func (f *Frame) GetEvtnum() Evtnum {
	pti := f.GetPTI()
	evnum := Evtnum(pti)
	if pti != PtiUDE {
		return evnum
	}
	evnum = Evtnum(f.Ude >> 43)
	return evnum
}

func (f *Frame) GetV0() float64 {
	pti := f.GetPTI()
	switch pti {
	case PtiZero:
		return 0
	case PtiOne:
		return 1
	case PtiOneFloat64:
		return f.V0
	case PtiTwo64:
		return f.V0
	}
	return MyNaN
}

func (f *Frame) GetV1() int64 {
	if f.GetPTI() == PtiTwo64 {
		return f.V1
	}
	return 0
}

var MyNaN float64

func init() {
	MyNaN = math.NaN()
}

// Marshal serialized the Frame into bytes. We'll
// reuse the space pointed to by buf if there is
// sufficient space in it. We return the bytes
// that we wrote, plus any error.
func (f *Frame) Marshal(buf []byte) ([]byte, error) {
	n := 8
	pti := f.GetPTI()
	switch pti {
	case PtiZero:
		n = 8
	case PtiOne:
		n = 8
	case PtiOneFloat64:
		n = 16
	case PtiTwo64:
		n = 24
	case PtiNull:
		n = 8
	case PtiNA:
		n = 8
	case PtiNaN:
		n = 8
	case PtiUDE:
		n = 16
		if len(f.Data) > 0 {
			n += len(f.Data) + 1 // +1 for the zero termination that only goes on the wire
		}
	default:
		panic(fmt.Sprintf("unrecog pti: %v", pti))
	}
	var m []byte
	if len(buf) >= n {
		m = buf[:n]
	} else {
		m = make([]byte, n)
	}
	binary.LittleEndian.PutUint64(m[:8], uint64(f.Prim))
	if n == 8 {
		return m, nil
	}
	switch pti {
	case PtiOneFloat64:
		binary.LittleEndian.PutUint64(m[8:16], math.Float64bits(f.V0))
	case PtiTwo64:
		binary.LittleEndian.PutUint64(m[8:16], math.Float64bits(f.V0))
		binary.LittleEndian.PutUint64(m[16:24], uint64(f.V1))
	case PtiUDE:
		binary.LittleEndian.PutUint64(m[8:16], uint64(f.Ude))
		if n == 16 {
			return m, nil
		}
		copy(m[16:], f.Data)
		m[n-1] = 0
	}

	return m, nil
}

var TooShortErr = fmt.Errorf("data supplied is too short to represent a TMFRAME frame")

// Unmarshal overwrites f with the restored value of the TMFRAME found
// in the by []byte data.
func (f *Frame) Unmarshal(by []byte) (rest []byte, err error) {
	// zero it all
	*f = Frame{}

	n := int64(len(by))
	if n < 8 {
		return by, TooShortErr
	}
	prim := binary.LittleEndian.Uint64(by[:8])
	pti := PTI(prim % 8)

	f.Prim = int64(prim)

	switch pti {
	case PtiZero:
		f.V0 = 0.0
		return by[8:], nil
	case PtiOne:
		f.V0 = 1.0
		return by[8:], nil
	case PtiOneFloat64:
		if n < 16 {
			return by, TooShortErr
		}
		f.V0 = math.Float64frombits(binary.LittleEndian.Uint64(by[8:16]))
		return by[16:], nil
	case PtiTwo64:
		if n < 24 {
			return by, TooShortErr
		}
		f.V0 = math.Float64frombits(binary.LittleEndian.Uint64(by[8:16]))
		f.V1 = int64(binary.LittleEndian.Uint64(by[16:24]))
		return by[24:], nil
	case PtiNull:
		return by[8:], nil
	case PtiNA:
		return by[8:], nil
	case PtiNaN:
		// don't actually do this, as it make reflect.DeepEquals not work (of course): f.V0 = MyNaN
		return by[8:], nil
	case PtiUDE:
		ude := binary.LittleEndian.Uint64(by[8:16])
		f.Ude = int64(ude)
		ucount := ude & KeepLow43Bits
		ulen := int64(ucount)
		if n < 16+ulen {
			return by, TooShortErr
		}
		if ulen > 0 {
			f.Data = by[16 : 16+ucount-1] // -1 because the zero terminating byte only goes on the wire
		}
		return by[16+ucount:], nil
	default:
		panic(fmt.Sprintf("unrecog pti: %v", pti))
	}
	panic("should never get here")
}

// KeepLow43Bits allows one to mask off a UDE and discover
// the UCOUNT in the lower 43 bits quickly.
// For example: ucount := ude & KeepLow43Bits
//
const KeepLow43Bits uint64 = 0x000007FFFFFFFFFF

// NoDataAllowedErr is returned from NewFrame() when the
// data argument is supplied but not conveyed in that
// evtnum specified.
var NoDataAllowedErr = fmt.Errorf("data must be empty for this evtnum")

// EvtnumOutOfRangeErr is retuned from NewFrame() when
// the evtnum is out of the allowed range.
var EvtnumOutOfRangeErr = fmt.Errorf("evtnum out of range. min allowed is -1048576, max is 1048575")

// Validate our acceptable range of evtnum.
// The min allowed is -1048576, max allowed is 1048575
func ValidEvtnum(evtnum Evtnum) bool {
	if evtnum > 1048575 || evtnum < -1048576 {
		return false
	}
	return true
}

// NewFrame creates a new TMFRAME message, ready to have Marshal called on
// for serialization into bytes. It will not make an internal copy of data.
// When copied on to the wire with Marshal(), a zero byte will be added
// to the data to make interop with C bindings easier; hence the UCOUNT will
// always include in its count this terminating zero byte if len(data) > 0.
//
func NewFrame(tm time.Time, evtnum Evtnum, v0 float64, v1 int64, data []byte) (*Frame, error) {

	if !ValidEvtnum(evtnum) {
		return nil, EvtnumOutOfRangeErr
	}

	// sanity check that data is empty when it should be
	if len(data) > 0 {
		if evtnum >= 0 && evtnum < 7 {
			return nil, NoDataAllowedErr
		}
	}

	utm := tm.UnixNano()
	mod := utm - (utm % 8)

	en := uint64(evtnum % (1 << 21))
	Q("en = %v", en)
	Q("pre shift en = %b", en)
	en = en << 43
	Q("post shift en = %b", en)
	Q("len(data) = %v", len(data))
	Q("len(data) = %b", len(data))
	var ude uint64
	if len(data) > 0 {
		// the +1 is so we zero-terminate strings -- for C bindings
		ude = uint64(len(data)+1) | en
	} else {
		ude = en
	}
	Q("ude = %b", ude)

	var useData []byte
	var myUDE uint64
	//var myUlen int64

	var pti PTI
	switch evtnum {
	case EvZero:
		pti = PtiZero
	case EvOne:
		pti = PtiOne
	case EvOneFloat64:
		pti = PtiOneFloat64
	case EvTwo64:
		pti = PtiTwo64
	case EvNull:
		pti = PtiNull
	case EvNA:
		pti = PtiNA
	case EvNaN:
		pti = PtiNaN
	default:
		// includes case EvUDE and EvErr
		pti = PtiUDE
		useData = data
		myUDE = ude
	}

	f := &Frame{
		Prim: mod | int64(pti),
		Ude:  int64(myUDE),
		Data: useData,
	}

	// set f.V0 and v.V1
	switch evtnum {
	case EvZero:
		f.V0 = 0.0
	case EvOne:
		f.V0 = 1.0
	case EvOneFloat64:
		f.V0 = v0
	case EvTwo64:
		f.V0 = v0
		f.V1 = v1
	}

	Q("f = %#v", f)
	return f, nil
}
<|endoftext|>


<commit_before>package redsync

import (
	"crypto/rand"
	"encoding/base64"
	"time"

	"github.com/gomodule/redigo/redis"
)

// A DelayFunc is used to decide the amount of time to wait between retries.
type DelayFunc func(tries int) time.Duration

// A Mutex is a distributed mutual exclusion lock.
type Mutex struct {
	name   string
	expiry time.Duration

	tries     int
	delayFunc DelayFunc

	factor float64

	quorum int

	genValueFunc func() (string, error)
	value        string
	until        time.Time

	pools []Pool
}

// Lock locks m. In case it returns an error on failure, you may retry to acquire the lock by calling this method again.
func (m *Mutex) Lock() error {
	value, err := m.genValueFunc()
	if err != nil {
		return err
	}

	for i := 0; i < m.tries; i++ {
		if i != 0 {
			time.Sleep(m.delayFunc(i))
		}

		start := time.Now()

		n := m.actOnPoolsAsync(func(pool Pool) bool {
			return m.acquire(pool, value)
		})

		until := time.Now().Add(m.expiry - time.Now().Sub(start) - time.Duration(int64(float64(m.expiry)*m.factor)) + 2*time.Millisecond)
		if n >= m.quorum && time.Now().Before(until) {
			m.value = value
			m.until = until
			return nil
		}
		m.actOnPoolsAsync(func(pool Pool) bool {
			return m.release(pool, value)
		})
	}

	return ErrFailed
}

// Unlock unlocks m and returns the status of unlock.
func (m *Mutex) Unlock() bool {
	n := m.actOnPoolsAsync(func(pool Pool) bool {
		return m.release(pool, m.value)
	})
	return n >= m.quorum
}

// Extend resets the mutex's expiry and returns the status of expiry extension.
func (m *Mutex) Extend() bool {
	n := m.actOnPoolsAsync(func(pool Pool) bool {
		return m.touch(pool, m.value, int(m.expiry/time.Millisecond))
	})
	return n >= m.quorum
}

func genValue() (string, error) {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(b), nil
}

func (m *Mutex) acquire(pool Pool, value string) bool {
	conn := pool.Get()
	defer conn.Close()
	reply, err := redis.String(conn.Do("SET", m.name, value, "NX", "PX", int(m.expiry/time.Millisecond)))
	return err == nil && reply == "OK"
}

var deleteScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("DEL", KEYS[1])
	else
		return 0
	end
`)

func (m *Mutex) release(pool Pool, value string) bool {
	conn := pool.Get()
	defer conn.Close()
	status, err := redis.Int64(deleteScript.Do(conn, m.name, value))

	return err == nil && status != 0
}

var touchScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("pexpire", KEYS[1], ARGV[2])
	else
		return 0
	end
`)

func (m *Mutex) touch(pool Pool, value string, expiry int) bool {
	conn := pool.Get()
	defer conn.Close()
	status, err := redis.Int64(touchScript.Do(conn, m.name, value, expiry))

	return err == nil && status != 0
}

func (m *Mutex) actOnPoolsAsync(actFn func(Pool) bool) int {
	ch := make(chan bool)
	for _, pool := range m.pools {
		go func(pool Pool) {
			ch <- actFn(pool)
		}(pool)
	}
	n := 0
	for range m.pools {
		if <-ch {
			n++
		}
	}
	return n
}
<commit_msg>Remove unnecessary delay<commit_after>package redsync

import (
	"crypto/rand"
	"encoding/base64"
	"time"

	"github.com/gomodule/redigo/redis"
)

// A DelayFunc is used to decide the amount of time to wait between retries.
type DelayFunc func(tries int) time.Duration

// A Mutex is a distributed mutual exclusion lock.
type Mutex struct {
	name   string
	expiry time.Duration

	tries     int
	delayFunc DelayFunc

	factor float64

	quorum int

	genValueFunc func() (string, error)
	value        string
	until        time.Time

	pools []Pool
}

// Lock locks m. In case it returns an error on failure, you may retry to acquire the lock by calling this method again.
func (m *Mutex) Lock() error {
	value, err := m.genValueFunc()
	if err != nil {
		return err
	}

	for i := 0; i < m.tries; i++ {
		if i != 0 {
			time.Sleep(m.delayFunc(i))
		}

		start := time.Now()

		n := m.actOnPoolsAsync(func(pool Pool) bool {
			return m.acquire(pool, value)
		})

		until := time.Now().Add(m.expiry - time.Now().Sub(start) - time.Duration(int64(float64(m.expiry)*m.factor)))
		if n >= m.quorum && time.Now().Before(until) {
			m.value = value
			m.until = until
			return nil
		}
		m.actOnPoolsAsync(func(pool Pool) bool {
			return m.release(pool, value)
		})
	}

	return ErrFailed
}

// Unlock unlocks m and returns the status of unlock.
func (m *Mutex) Unlock() bool {
	n := m.actOnPoolsAsync(func(pool Pool) bool {
		return m.release(pool, m.value)
	})
	return n >= m.quorum
}

// Extend resets the mutex's expiry and returns the status of expiry extension.
func (m *Mutex) Extend() bool {
	n := m.actOnPoolsAsync(func(pool Pool) bool {
		return m.touch(pool, m.value, int(m.expiry/time.Millisecond))
	})
	return n >= m.quorum
}

func genValue() (string, error) {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(b), nil
}

func (m *Mutex) acquire(pool Pool, value string) bool {
	conn := pool.Get()
	defer conn.Close()
	reply, err := redis.String(conn.Do("SET", m.name, value, "NX", "PX", int(m.expiry/time.Millisecond)))
	return err == nil && reply == "OK"
}

var deleteScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("DEL", KEYS[1])
	else
		return 0
	end
`)

func (m *Mutex) release(pool Pool, value string) bool {
	conn := pool.Get()
	defer conn.Close()
	status, err := redis.Int64(deleteScript.Do(conn, m.name, value))

	return err == nil && status != 0
}

var touchScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("pexpire", KEYS[1], ARGV[2])
	else
		return 0
	end
`)

func (m *Mutex) touch(pool Pool, value string, expiry int) bool {
	conn := pool.Get()
	defer conn.Close()
	status, err := redis.Int64(touchScript.Do(conn, m.name, value, expiry))

	return err == nil && status != 0
}

func (m *Mutex) actOnPoolsAsync(actFn func(Pool) bool) int {
	ch := make(chan bool)
	for _, pool := range m.pools {
		go func(pool Pool) {
			ch <- actFn(pool)
		}(pool)
	}
	n := 0
	for range m.pools {
		if <-ch {
			n++
		}
	}
	return n
}
<|endoftext|>


<commit_before>package MQTTg

type MessageType uint8

const (
	Reserved_1 MessageType = iota
	Connect
	Connack
	Publish
	Puback
	Pubrec
	Pubrel
	Pubcomp
	Subscribe
	Suback
	Unsubscribe
	Unsuback
	Pingreq
	Pingresp
	Disconnect
	Reserved_2
)

type FixedHeader struct {
	Type         MessageType
	Dup          bool
	QoS          uint8
	Retain       bool
	RemainLength uint8
}

func NewFixedHeader(mType MessageType, dup bool, qos uint8, retain bool, length uint8) *FixedHeader {
	return &FixedHeader{
		Type:         mType,
		Dup:          dup,
		QoS:          qos,
		Retain:       retain,
		RemainLength: length,
	}
}

type Message interface {
	Parse(data []byte)
	GetWire() ([]byte, error)
	String() string
}

type ConnectFlag uint8

const (
	CleanSession ConnectFlag = 0x02
	WillFlag     ConnectFlag = 0x04
	WillQoS_0    ConnectFlag = 0x00
	WillQoS_1    ConnectFlag = 0x08
	WillQoS_2    ConnectFlag = 0x10
	WillQoS_3    ConnectFlag = 0x18
	WillRetain   ConnectFlag = 0x20
	Password     ConnectFlag = 0x40
	UserName     ConnectFlag = 0x80
)

type ConnectMessage struct {
	*FixedHeader
	ProtoName    string
	ProtoLevel   uint8
	ConnectFlags ConnectFlag
	KeepAlive    uint16
}

func NewConnectMessage(connectFlags ConnectFlags, keepAlive uint16) *Connect {

	return &Connect{
		FixedHeader: NewFixedHeader(
			Connect,
			false, 0, false,
			0, // TODO:check
		),
		ProtoName:    "MQTT",
		ProtoLevel:   4,
		ConnectFlags: connectFlags,
		KeepAlive:    keepAlive,
	}
}
<commit_msg>write interface about Variable Header<commit_after>package MQTTg

type MessageType uint8

const (
	Reserved_1 MessageType = iota
	Connect
	Connack
	Publish
	Puback
	Pubrec
	Pubrel
	Pubcomp
	Subscribe
	Suback
	Unsubscribe
	Unsuback
	Pingreq
	Pingresp
	Disconnect
	Reserved_2
)

type FixedHeader struct {
	Type         MessageType
	Dup          bool
	QoS          uint8
	Retain       bool
	RemainLength uint8
}

func NewFixedHeader(mType MessageType, dup bool, qos uint8, retain bool, length uint8) *FixedHeader {
	return &FixedHeader{
		Type:         mType,
		Dup:          dup,
		QoS:          qos,
		Retain:       retain,
		RemainLength: length,
	}
}

type VariableHeader interface {
	VHeaderParse(data []byte)
	VHeaderWire() ([]byte, error)
	VHeaderString() string
}

type Message interface {
	Parse(data []byte)
	GetWire() ([]byte, error)
	String() string
}

type ConnectFlag uint8

const (
	CleanSession ConnectFlag = 0x02
	WillFlag     ConnectFlag = 0x04
	WillQoS_0    ConnectFlag = 0x00
	WillQoS_1    ConnectFlag = 0x08
	WillQoS_2    ConnectFlag = 0x10
	WillQoS_3    ConnectFlag = 0x18
	WillRetain   ConnectFlag = 0x20
	Password     ConnectFlag = 0x40
	UserName     ConnectFlag = 0x80
)

type ConnectMessage struct {
	*FixedHeader
	ProtoName    string
	ProtoLevel   uint8
	ConnectFlags ConnectFlag
	KeepAlive    uint16
}

func NewConnectMessage(connectFlags ConnectFlags, keepAlive uint16) *Connect {

	return &Connect{
		FixedHeader: NewFixedHeader(
			Connect,
			false, 0, false,
			0, // TODO:check
		),
		ProtoName:    "MQTT",
		ProtoLevel:   4,
		ConnectFlags: connectFlags,
		KeepAlive:    keepAlive,
	}
}
<|endoftext|>


<commit_before>package MQTTg

type MessageType uint8

const (
	Reserved_1 MessageType = iota
	Connect
	Connack
	Publish
	Puback
	Pubrec
	Pubrel
	Pubcomp
	Subscribe
	Suback
	Unsubscribe
	Unsuback
	Pingreq
	Pingresp
	Disconnect
	Reserved_2
)

type FixedHeader struct {
	Type         MessageType
	Dup          bool
	QoS          uint8
	Retain       bool
	RemainLength uint8
}

func NewFixedHeader(mType MessageType, dup bool, qos uint8, retain bool, length uint8) *FixedHeader {
	return &FixedHeader{
		Type:         mType,
		Dup:          dup,
		QoS:          qos,
		Retain:       retain,
		RemainLength: length,
	}
}

type VariableHeader interface {
	VHeaderParse(data []byte)
	VHeaderWire() ([]byte, error)
	VHeaderString() string
}

type Message interface {
	Parse(data []byte)
	GetWire() ([]byte, error)
	String() string
}

type ConnectFlag uint8

const (
	CleanSession ConnectFlag = 0x02
	WillFlag     ConnectFlag = 0x04
	WillQoS_0    ConnectFlag = 0x00
	WillQoS_1    ConnectFlag = 0x08
	WillQoS_2    ConnectFlag = 0x10
	WillQoS_3    ConnectFlag = 0x18
	WillRetain   ConnectFlag = 0x20
	Password     ConnectFlag = 0x40
	UserName     ConnectFlag = 0x80
)

type ConnectMessage struct {
	*FixedHeader
	ProtoName    string
	ProtoLevel   uint8
	ConnectFlags ConnectFlag
	KeepAlive    uint16
}

func NewConnectMessage(connectFlags ConnectFlags, keepAlive uint16) *ConnectMessage {

	return &ConnectMessage{
		FixedHeader: NewFixedHeader(
			Connect,
			false, 0, false,
			0, // TODO:check
		),
		ProtoName:    "MQTT",
		ProtoLevel:   4,
		ConnectFlags: connectFlags,
		KeepAlive:    keepAlive,
	}
}

type ConnectReturnCode uint8

const (
	Accepted ConnectReturnCode = iota
	UnacceptableProtocolVersion
	IdentifierRejected
	ServerUnavailable
	BadUserNameOrPassword
	NotAuthorized
)
<commit_msg>add Connack Message<commit_after>package MQTTg

type MessageType uint8

const (
	Reserved_1 MessageType = iota
	Connect
	Connack
	Publish
	Puback
	Pubrec
	Pubrel
	Pubcomp
	Subscribe
	Suback
	Unsubscribe
	Unsuback
	Pingreq
	Pingresp
	Disconnect
	Reserved_2
)

type FixedHeader struct {
	Type         MessageType
	Dup          bool
	QoS          uint8
	Retain       bool
	RemainLength uint8
}

func NewFixedHeader(mType MessageType, dup bool, qos uint8, retain bool, length uint8) *FixedHeader {
	return &FixedHeader{
		Type:         mType,
		Dup:          dup,
		QoS:          qos,
		Retain:       retain,
		RemainLength: length,
	}
}

type VariableHeader interface {
	VHeaderParse(data []byte)
	VHeaderWire() ([]byte, error)
	VHeaderString() string
}

type Message interface {
	Parse(data []byte)
	GetWire() ([]byte, error)
	String() string
}

type ConnectFlag uint8

const (
	CleanSession ConnectFlag = 0x02
	WillFlag     ConnectFlag = 0x04
	WillQoS_0    ConnectFlag = 0x00
	WillQoS_1    ConnectFlag = 0x08
	WillQoS_2    ConnectFlag = 0x10
	WillQoS_3    ConnectFlag = 0x18
	WillRetain   ConnectFlag = 0x20
	Password     ConnectFlag = 0x40
	UserName     ConnectFlag = 0x80
)

type ConnectMessage struct {
	*FixedHeader
	ProtoName    string
	ProtoLevel   uint8
	ConnectFlags ConnectFlag
	KeepAlive    uint16
}

func NewConnectMessage(connectFlags ConnectFlags, keepAlive uint16) *ConnectMessage {

	return &ConnectMessage{
		FixedHeader: NewFixedHeader(
			Connect,
			false, 0, false,
			0, // TODO:check
		),
		ProtoName:    "MQTT",
		ProtoLevel:   4,
		ConnectFlags: connectFlags,
		KeepAlive:    keepAlive,
	}
}

type ConnectReturnCode uint8

const (
	Accepted ConnectReturnCode = iota
	UnacceptableProtocolVersion
	IdentifierRejected
	ServerUnavailable
	BadUserNameOrPassword
	NotAuthorized
)

type ConnackMessage struct {
	*FixedHeader
	SessionPresentFlag bool
	ReturnCode         ConnectReturnCode
}

func NewConnackMessage(flag bool, code ConnectReturnCode) *ConnackMessage {
	return &ConnackMessage{
		FixedHeader: NewFixedHeader(
			Connack,
			false, 0, false,
			0, // TODO:check
		),
		SessionPresentFlag: flag,
		ReturnCode:         code,
	}
}
<|endoftext|>


<commit_before>package application

import (
	"cf/terminal"
	"code.google.com/p/gogoprotobuf/proto"
	"fmt"
	"github.com/cloudfoundry/loggregatorlib/logmessage"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestLogMessageOutput(t *testing.T) {
	cloud_controller := logmessage.LogMessage_CLOUD_CONTROLLER
	router := logmessage.LogMessage_ROUTER
	uaa := logmessage.LogMessage_UAA
	dea := logmessage.LogMessage_DEA
	wardenContainer := logmessage.LogMessage_WARDEN_CONTAINER

	stdout := logmessage.LogMessage_OUT
	stderr := logmessage.LogMessage_ERR

	zone, _ := time.Now().Zone()
	date := fmt.Sprintf("2013 Sep 20 09:33:30 %s", zone)
	logTime, err := time.Parse("2006 Jan 2 15:04:05 MST", date)

	assert.NoError(t, err)
	expectedTZ := logTime.Format("-0700")

	timestamp := logTime.UnixNano()

	sourceId := "0"

	protoMessage := &logmessage.LogMessage{
		Message:     []byte("Hello World!\n\r\n\r"),
		AppId:       proto.String("my-app-guid"),
		MessageType: &stdout,
		SourceId:    &sourceId,
		Timestamp:   &timestamp,
	}

	msg := createMessage(t, protoMessage, &cloud_controller, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [API]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))

	msg = createMessage(t, protoMessage, &cloud_controller, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [API]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "1"
	msg = createMessage(t, protoMessage, &router, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [RTR]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &router, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [RTR]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "2"
	msg = createMessage(t, protoMessage, &uaa, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [UAA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &uaa, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [UAA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "3"
	msg = createMessage(t, protoMessage, &dea, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [DEA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &dea, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [DEA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "4"
	msg = createMessage(t, protoMessage, &wardenContainer, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [App/4]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &wardenContainer, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [App/4]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))
}

func createMessage(t *testing.T, protoMsg *logmessage.LogMessage, sourceType *logmessage.LogMessage_SourceType, msgType *logmessage.LogMessage_MessageType) (msg *logmessage.Message) {
	protoMsg.SourceType = sourceType
	protoMsg.MessageType = msgType

	data, err := proto.Marshal(protoMsg)
	assert.NoError(t, err)

	msg, err = logmessage.ParseMessage(data)
	assert.NoError(t, err)

	return
}
<commit_msg>fixing daylight savings bug in log tests<commit_after>package application

import (
	"cf/terminal"
	"code.google.com/p/gogoprotobuf/proto"
	"fmt"
	"github.com/cloudfoundry/loggregatorlib/logmessage"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestLogMessageOutput(t *testing.T) {
	cloud_controller := logmessage.LogMessage_CLOUD_CONTROLLER
	router := logmessage.LogMessage_ROUTER
	uaa := logmessage.LogMessage_UAA
	dea := logmessage.LogMessage_DEA
	wardenContainer := logmessage.LogMessage_WARDEN_CONTAINER

	stdout := logmessage.LogMessage_OUT
	stderr := logmessage.LogMessage_ERR

	date := "2013 Sep 20 09:33:30 PDT"
	logTime, err := time.Parse("2006 Jan 2 15:04:05 MST", date)
	assert.NoError(t, err)
	timestamp := logTime.UnixNano()

	expectedTZ := logTime.Format("-0700")

	sourceId := "0"

	protoMessage := &logmessage.LogMessage{
		Message:     []byte("Hello World!\n\r\n\r"),
		AppId:       proto.String("my-app-guid"),
		MessageType: &stdout,
		SourceId:    &sourceId,
		Timestamp:   &timestamp,
	}

	msg := createMessage(t, protoMessage, &cloud_controller, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [API]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))

	msg = createMessage(t, protoMessage, &cloud_controller, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [API]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "1"
	msg = createMessage(t, protoMessage, &router, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [RTR]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &router, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [RTR]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "2"
	msg = createMessage(t, protoMessage, &uaa, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [UAA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &uaa, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [UAA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "3"
	msg = createMessage(t, protoMessage, &dea, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [DEA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &dea, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [DEA]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))

	sourceId = "4"
	msg = createMessage(t, protoMessage, &wardenContainer, &stdout)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [App/4]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStdoutColor("OUT Hello World!"))
	msg = createMessage(t, protoMessage, &wardenContainer, &stderr)
	assert.Contains(t, logMessageOutput(msg), fmt.Sprintf("2013-09-20T09:33:30.00%s [App/4]", expectedTZ))
	assert.Contains(t, logMessageOutput(msg), terminal.LogStderrColor("ERR Hello World!"))
}

func createMessage(t *testing.T, protoMsg *logmessage.LogMessage, sourceType *logmessage.LogMessage_SourceType, msgType *logmessage.LogMessage_MessageType) (msg *logmessage.Message) {
	protoMsg.SourceType = sourceType
	protoMsg.MessageType = msgType

	data, err := proto.Marshal(protoMsg)
	assert.NoError(t, err)

	msg, err = logmessage.ParseMessage(data)
	assert.NoError(t, err)

	return
}
<|endoftext|>


<commit_before>package docker_test

import (
	"fmt"
	"io/ioutil"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-product-bundle/products/docker/enaml-gen/docker"
	. "github.com/enaml-ops/omg-product-bundle/products/docker/plugin"
	"github.com/enaml-ops/pluginlib/util"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/xchapter7x/lo"
	"github.com/xchapter7x/lo/lofakes"
)

var _ = Describe("given docker Plugin", func() {
	var plgn *Plugin

	BeforeEach(func() {
		plgn = new(Plugin)
	})

	Context("when called with a `--insecure-registry` stringslice flag value/s given", func() {
		var deployment *enaml.DeploymentManifest
		var controlRegistry1 = "blah"
		var controlRegistry2 = "bleh"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", "private",
				"--vm-type", "medium",
				"--disk-type", "medium",
				"--ip", "1.2.3.4",
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
				"--insecure-registry", controlRegistry1,
				"--insecure-registry", controlRegistry2,
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
			Ω(len(deployment.InstanceGroups)).Should(BeNumerically(">", 0), "we expect there to be some instance groups defined")
		})

		It("then it should properly pass the flag value to the plugin", func() {
			Ω(plgn.InsecureRegistries).Should(ConsistOf(controlRegistry1, controlRegistry2), "there should be insecure registries in the job properties")
		})
	})

	Context("when called with a `--docker-release-ver` `--docker-release-url` `--docker-release-sha` flag", func() {

		It("then it should have those registered as valid flags", func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			Ω(func() {
				plgn.GetProduct([]string{
					"appname",
					"--network", "private",
					"--vm-type", "medium",
					"--disk-type", "medium",
					"--ip", "1.2.3.4",
					"--az", "z1",
					"--stemcell-ver", "12.3.44",
					"--container-definition", "./fixtures/sample-docker.yml",
					"--docker-release-ver", "skjdf",
					"--docker-release-url", "asdfasdf",
					"--docker-release-sha", "asdfasdf",
				}, cloudConfigBytes)
			}).ShouldNot(Panic(), "these flags should not cause a panic, b/c they should exist")
		})
		It("then it should set the give values as the release values", func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			controlver := "asdfasdf"
			controlurl := "fasdfasdf"
			controlsha := "akjhasdkghasdg"
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", "private",
				"--vm-type", "medium",
				"--disk-type", "medium",
				"--ip", "1.2.3.4",
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
				"--docker-release-ver", controlver,
				"--docker-release-url", controlurl,
				"--docker-release-sha", controlsha,
			}, cloudConfigBytes)
			deployment := enaml.NewDeploymentManifest(dmBytes)
			Ω(deployment.Releases[0].Version).Should(Equal(controlver))
			Ω(deployment.Releases[0].URL).Should(Equal(controlurl))
			Ω(deployment.Releases[0].SHA1).Should(Equal(controlsha))
		})
	})

	Context("when called with a `--registry-mirror` stringslice flag value/s given", func() {
		var deployment *enaml.DeploymentManifest
		var controlMirror1 = "blah"
		var controlMirror2 = "bleh"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", "private",
				"--vm-type", "medium",
				"--disk-type", "medium",
				"--ip", "1.2.3.4",
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
				"--registry-mirror", controlMirror1,
				"--registry-mirror", controlMirror2,
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
			Ω(len(deployment.InstanceGroups)).Should(BeNumerically(">", 0), "we expect there to be some instance groups defined")
		})

		It("then it should properly pass the flag value to the plugin", func() {
			Ω(plgn.RegistryMirrors).Should(ConsistOf(controlMirror1, controlMirror2), "there should be registry mirrors in the job properties")
		})
	})

	Context("when the plugin has a InsecureRegistries value set", func() {
		var plgn *Plugin
		var ig *enaml.InstanceGroup
		var controlRegistry1 = "blah"
		var controlRegistry2 = "bleh"
		BeforeEach(func() {
			plgn = new(Plugin)
			plgn.InsecureRegistries = []string{controlRegistry1, controlRegistry2}
			ig = plgn.NewDockerInstanceGroup()
		})
		It("then it should set the insecure-registries array in the bosh deployment manifest the plugin generates", func() {
			var dockerJobProperties *docker.DockerJob = ig.GetJobByName("docker").Properties.(*docker.DockerJob)
			Ω(dockerJobProperties.Docker.InsecureRegistries).Should(ConsistOf(controlRegistry1, controlRegistry2), "there should be insecure registries in the job properties")
		})
	})

	Context("when the plugin has a RegistryMirrors value set", func() {
		var plgn *Plugin
		var ig *enaml.InstanceGroup
		var controlMirror1 = "blah"
		var controlMirror2 = "bleh"
		BeforeEach(func() {
			plgn = new(Plugin)
			plgn.RegistryMirrors = []string{controlMirror1, controlMirror2}
			ig = plgn.NewDockerInstanceGroup()
		})
		It("then it should set the insecure-registries array in the bosh deployment manifest the plugin generates", func() {
			var dockerJobProperties *docker.DockerJob = ig.GetJobByName("docker").Properties.(*docker.DockerJob)
			Ω(dockerJobProperties.Docker.RegistryMirrors).Should(ConsistOf(controlMirror1, controlMirror2), "there should be insecure registries in the job properties")
		})
	})

	Context("when calling GetProduct while targeting an un-compatible cloud config'd bosh", func() {
		var logHolder = lo.G
		var logfake = new(lofakes.FakeLogger)
		var cloudConfigBytes []byte
		var controlNetName = "hello"
		var controlDisk = "medium"
		var controlVM = "large"
		var controlIP = "1.2.3.4"

		BeforeEach(func() {
			logfake = new(lofakes.FakeLogger)
			logHolder = lo.G
			lo.G = logfake
			cloudConfigBytes, _ = ioutil.ReadFile("./fixtures/sample-aws.yml")
		})

		AfterEach(func() {
			lo.G = logHolder
		})

		It("then we should fail fast and give the user guidance on what is wrong", func() {
			plgn.GetProduct([]string{
				"appname",
				"--disk-type", controlDisk,
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--ip", controlIP,
				"--az", "z1-nothere",
				"--stemcell-url", "something",
				"--stemcell-ver", "12.3.44",
				"--stemcell-sha", "ilkjag09dhsg90ahsd09gsadg9",
				"--container-definition", "./fixtures/sample-docker.yml",
			}, cloudConfigBytes)
			Ω(logfake.FatalCallCount()).Should(Equal(1))
		})
	})

	Context("when calling plugin without all required flags", func() {

		var logHolder = lo.G
		var logfake = new(lofakes.FakeLogger)

		BeforeEach(func() {
			logfake = new(lofakes.FakeLogger)
			logHolder = lo.G
			lo.G = logfake
		})

		AfterEach(func() {
			lo.G = logHolder
		})

		It("then it should fail fast and give the user guidance on what is wrong", func() {
			plgn.GetProduct([]string{"appname"}, []byte(``))
			Ω(logfake.FatalCallCount()).Should(BeNumerically(">=", 1))
		})
	})

	Context("when calling GetProduct without a valid docker def file", func() {
		var controlNetName = "private"
		var controlDisk = "medium"
		var controlVM = "medium"
		var controlIP = "1.2.3.4"
		var realLog = lo.G
		var logfake = new(lofakes.FakeLogger)

		BeforeEach(func() {

			realLog = lo.G
			logfake = new(lofakes.FakeLogger)
			lo.G = logfake
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			plgn.GetProduct([]string{
				"appname",
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--disk-type", controlDisk,
				"--ip", controlIP,
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "this-file-does-not-exist",
			}, cloudConfigBytes)
		})

		AfterEach(func() {
			lo.G = realLog
		})

		It("then we should have a properly initialized deployment set", func() {
			Ω(logfake.FatalfCallCount()).Should(Equal(1))
		})
	})

	Context("when calling GetProduct w/ valid flags and matching cloud config", func() {
		var deployment *enaml.DeploymentManifest
		var controlNetName = "private"
		var controlDisk = "medium"
		var controlVM = "medium"
		var controlIP = "1.2.3.4"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--disk-type", controlDisk,
				"--ip", controlIP,
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
		})
		It("then we should have a properly initialized deployment set", func() {
			Ω(deployment.Update).ShouldNot(BeNil())
			Ω(len(deployment.Releases)).Should(Equal(1))
			Ω(len(deployment.Stemcells)).Should(Equal(1))
			Ω(len(deployment.InstanceGroups)).Should(Equal(1))
		})
	})

	Context("when calling GetProduct w/ a stemcell name flag ", func() {
		var deployment *enaml.DeploymentManifest
		var controlNetName = "private"
		var controlDisk = "medium"
		var controlVM = "medium"
		var controlIP = "1.2.3.4"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--disk-type", controlDisk,
				"--ip", controlIP,
				"--az", "z1",
				"--stemcell-name", "blahname",
				"--stemcell-url", "something",
				"--stemcell-ver", "12.3.44",
				"--stemcell-sha", "ilkjag09dhsg90ahsd09gsadg9",
				"--container-definition", "./fixtures/sample-docker.yml",
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
		})
		It("then we should have a properly configured stemcell definition in our deployment (os & alias from flag value)", func() {
			Ω(len(deployment.Stemcells)).Should(Equal(1))
			Ω(deployment.Stemcells[0].OS).Should(Equal("blahname"))
			Ω(deployment.Stemcells[0].Alias).Should(Equal("blahname"))
		})
	})

	Context("when calling the plugin", func() {
		var flags []cli.Flag

		BeforeEach(func() {
			flags = pluginutil.ToCliFlagArray(plgn.GetFlags())
		})
		It("then there should be valid flags available", func() {
			for _, flagname := range []string{
				"ip",
				"az",
				"network",
				"vm-type",
				"disk-type",
				"stemcell-url",
				"stemcell-ver",
				"stemcell-sha",
				"stemcell-name",
				"container-definition",
			} {
				Ω(checkFlags(flags, flagname)).ShouldNot(HaveOccurred())
			}
		})
	})
})

func checkFlags(flags []cli.Flag, flagName string) error {
	var err = fmt.Errorf("could not find an flag %s in plugin", flagName)
	for _, f := range flags {
		if f.GetName() == flagName {
			err = nil
		}
	}
	return err
}
<commit_msg>[#130291241] fixing urfave dependency being busted in docker plugin<commit_after>package docker_test

import (
	"fmt"
	"io/ioutil"

	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-product-bundle/products/docker/enaml-gen/docker"
	. "github.com/enaml-ops/omg-product-bundle/products/docker/plugin"
	"github.com/enaml-ops/pluginlib/util"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/xchapter7x/lo"
	"github.com/xchapter7x/lo/lofakes"
	"gopkg.in/urfave/cli.v2"
)

var _ = Describe("given docker Plugin", func() {
	var plgn *Plugin

	BeforeEach(func() {
		plgn = new(Plugin)
	})

	Context("when called with a `--insecure-registry` stringslice flag value/s given", func() {
		var deployment *enaml.DeploymentManifest
		var controlRegistry1 = "blah"
		var controlRegistry2 = "bleh"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", "private",
				"--vm-type", "medium",
				"--disk-type", "medium",
				"--ip", "1.2.3.4",
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
				"--insecure-registry", controlRegistry1,
				"--insecure-registry", controlRegistry2,
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
			Ω(len(deployment.InstanceGroups)).Should(BeNumerically(">", 0), "we expect there to be some instance groups defined")
		})

		It("then it should properly pass the flag value to the plugin", func() {
			Ω(plgn.InsecureRegistries).Should(ConsistOf(controlRegistry1, controlRegistry2), "there should be insecure registries in the job properties")
		})
	})

	Context("when called with a `--docker-release-ver` `--docker-release-url` `--docker-release-sha` flag", func() {

		It("then it should have those registered as valid flags", func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			Ω(func() {
				plgn.GetProduct([]string{
					"appname",
					"--network", "private",
					"--vm-type", "medium",
					"--disk-type", "medium",
					"--ip", "1.2.3.4",
					"--az", "z1",
					"--stemcell-ver", "12.3.44",
					"--container-definition", "./fixtures/sample-docker.yml",
					"--docker-release-ver", "skjdf",
					"--docker-release-url", "asdfasdf",
					"--docker-release-sha", "asdfasdf",
				}, cloudConfigBytes)
			}).ShouldNot(Panic(), "these flags should not cause a panic, b/c they should exist")
		})
		It("then it should set the give values as the release values", func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			controlver := "asdfasdf"
			controlurl := "fasdfasdf"
			controlsha := "akjhasdkghasdg"
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", "private",
				"--vm-type", "medium",
				"--disk-type", "medium",
				"--ip", "1.2.3.4",
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
				"--docker-release-ver", controlver,
				"--docker-release-url", controlurl,
				"--docker-release-sha", controlsha,
			}, cloudConfigBytes)
			deployment := enaml.NewDeploymentManifest(dmBytes)
			Ω(deployment.Releases[0].Version).Should(Equal(controlver))
			Ω(deployment.Releases[0].URL).Should(Equal(controlurl))
			Ω(deployment.Releases[0].SHA1).Should(Equal(controlsha))
		})
	})

	Context("when called with a `--registry-mirror` stringslice flag value/s given", func() {
		var deployment *enaml.DeploymentManifest
		var controlMirror1 = "blah"
		var controlMirror2 = "bleh"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", "private",
				"--vm-type", "medium",
				"--disk-type", "medium",
				"--ip", "1.2.3.4",
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
				"--registry-mirror", controlMirror1,
				"--registry-mirror", controlMirror2,
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
			Ω(len(deployment.InstanceGroups)).Should(BeNumerically(">", 0), "we expect there to be some instance groups defined")
		})

		It("then it should properly pass the flag value to the plugin", func() {
			Ω(plgn.RegistryMirrors).Should(ConsistOf(controlMirror1, controlMirror2), "there should be registry mirrors in the job properties")
		})
	})

	Context("when the plugin has a InsecureRegistries value set", func() {
		var plgn *Plugin
		var ig *enaml.InstanceGroup
		var controlRegistry1 = "blah"
		var controlRegistry2 = "bleh"
		BeforeEach(func() {
			plgn = new(Plugin)
			plgn.InsecureRegistries = []string{controlRegistry1, controlRegistry2}
			ig = plgn.NewDockerInstanceGroup()
		})
		It("then it should set the insecure-registries array in the bosh deployment manifest the plugin generates", func() {
			var dockerJobProperties *docker.DockerJob = ig.GetJobByName("docker").Properties.(*docker.DockerJob)
			Ω(dockerJobProperties.Docker.InsecureRegistries).Should(ConsistOf(controlRegistry1, controlRegistry2), "there should be insecure registries in the job properties")
		})
	})

	Context("when the plugin has a RegistryMirrors value set", func() {
		var plgn *Plugin
		var ig *enaml.InstanceGroup
		var controlMirror1 = "blah"
		var controlMirror2 = "bleh"
		BeforeEach(func() {
			plgn = new(Plugin)
			plgn.RegistryMirrors = []string{controlMirror1, controlMirror2}
			ig = plgn.NewDockerInstanceGroup()
		})
		It("then it should set the insecure-registries array in the bosh deployment manifest the plugin generates", func() {
			var dockerJobProperties *docker.DockerJob = ig.GetJobByName("docker").Properties.(*docker.DockerJob)
			Ω(dockerJobProperties.Docker.RegistryMirrors).Should(ConsistOf(controlMirror1, controlMirror2), "there should be insecure registries in the job properties")
		})
	})

	Context("when calling GetProduct while targeting an un-compatible cloud config'd bosh", func() {
		var logHolder = lo.G
		var logfake = new(lofakes.FakeLogger)
		var cloudConfigBytes []byte
		var controlNetName = "hello"
		var controlDisk = "medium"
		var controlVM = "large"
		var controlIP = "1.2.3.4"

		BeforeEach(func() {
			logfake = new(lofakes.FakeLogger)
			logHolder = lo.G
			lo.G = logfake
			cloudConfigBytes, _ = ioutil.ReadFile("./fixtures/sample-aws.yml")
		})

		AfterEach(func() {
			lo.G = logHolder
		})

		It("then we should fail fast and give the user guidance on what is wrong", func() {
			plgn.GetProduct([]string{
				"appname",
				"--disk-type", controlDisk,
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--ip", controlIP,
				"--az", "z1-nothere",
				"--stemcell-url", "something",
				"--stemcell-ver", "12.3.44",
				"--stemcell-sha", "ilkjag09dhsg90ahsd09gsadg9",
				"--container-definition", "./fixtures/sample-docker.yml",
			}, cloudConfigBytes)
			Ω(logfake.FatalCallCount()).Should(Equal(1))
		})
	})

	Context("when calling plugin without all required flags", func() {

		var logHolder = lo.G
		var logfake = new(lofakes.FakeLogger)

		BeforeEach(func() {
			logfake = new(lofakes.FakeLogger)
			logHolder = lo.G
			lo.G = logfake
		})

		AfterEach(func() {
			lo.G = logHolder
		})

		It("then it should fail fast and give the user guidance on what is wrong", func() {
			plgn.GetProduct([]string{"appname"}, []byte(``))
			Ω(logfake.FatalCallCount()).Should(BeNumerically(">=", 1))
		})
	})

	Context("when calling GetProduct without a valid docker def file", func() {
		var controlNetName = "private"
		var controlDisk = "medium"
		var controlVM = "medium"
		var controlIP = "1.2.3.4"
		var realLog = lo.G
		var logfake = new(lofakes.FakeLogger)

		BeforeEach(func() {

			realLog = lo.G
			logfake = new(lofakes.FakeLogger)
			lo.G = logfake
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			plgn.GetProduct([]string{
				"appname",
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--disk-type", controlDisk,
				"--ip", controlIP,
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "this-file-does-not-exist",
			}, cloudConfigBytes)
		})

		AfterEach(func() {
			lo.G = realLog
		})

		It("then we should have a properly initialized deployment set", func() {
			Ω(logfake.FatalfCallCount()).Should(Equal(1))
		})
	})

	Context("when calling GetProduct w/ valid flags and matching cloud config", func() {
		var deployment *enaml.DeploymentManifest
		var controlNetName = "private"
		var controlDisk = "medium"
		var controlVM = "medium"
		var controlIP = "1.2.3.4"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--disk-type", controlDisk,
				"--ip", controlIP,
				"--az", "z1",
				"--stemcell-ver", "12.3.44",
				"--container-definition", "./fixtures/sample-docker.yml",
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
		})
		It("then we should have a properly initialized deployment set", func() {
			Ω(deployment.Update).ShouldNot(BeNil())
			Ω(len(deployment.Releases)).Should(Equal(1))
			Ω(len(deployment.Stemcells)).Should(Equal(1))
			Ω(len(deployment.InstanceGroups)).Should(Equal(1))
		})
	})

	Context("when calling GetProduct w/ a stemcell name flag ", func() {
		var deployment *enaml.DeploymentManifest
		var controlNetName = "private"
		var controlDisk = "medium"
		var controlVM = "medium"
		var controlIP = "1.2.3.4"

		BeforeEach(func() {
			cloudConfigBytes, _ := ioutil.ReadFile("./fixtures/sample-aws.yml")
			dmBytes := plgn.GetProduct([]string{
				"appname",
				"--network", controlNetName,
				"--vm-type", controlVM,
				"--disk-type", controlDisk,
				"--ip", controlIP,
				"--az", "z1",
				"--stemcell-name", "blahname",
				"--stemcell-url", "something",
				"--stemcell-ver", "12.3.44",
				"--stemcell-sha", "ilkjag09dhsg90ahsd09gsadg9",
				"--container-definition", "./fixtures/sample-docker.yml",
			}, cloudConfigBytes)
			deployment = enaml.NewDeploymentManifest(dmBytes)
		})
		It("then we should have a properly configured stemcell definition in our deployment (os & alias from flag value)", func() {
			Ω(len(deployment.Stemcells)).Should(Equal(1))
			Ω(deployment.Stemcells[0].OS).Should(Equal("blahname"))
			Ω(deployment.Stemcells[0].Alias).Should(Equal("blahname"))
		})
	})

	Context("when calling the plugin", func() {
		var flags []cli.Flag

		BeforeEach(func() {
			flags = pluginutil.ToCliFlagArray(plgn.GetFlags())
		})
		It("then there should be valid flags available", func() {
			for _, flagname := range []string{
				"ip",
				"az",
				"network",
				"vm-type",
				"disk-type",
				"stemcell-url",
				"stemcell-ver",
				"stemcell-sha",
				"stemcell-name",
				"container-definition",
			} {
				Ω(checkFlags(flags, flagname)).ShouldNot(HaveOccurred())
			}
		})
	})
})

func checkFlags(flags []cli.Flag, flagName string) error {
	var err = fmt.Errorf("could not find an flag %s in plugin", flagName)
	for _, f := range flags {
		if len(f.Names()) > 0 && f.Names()[0] == flagName {
			err = nil
		}
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
)

func GetPage(c string) []byte {
	url := fmt.Sprintf("http://www.nciku.com/search/all/%v", c)
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Add("User-agent", "Mozilla/5.0")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func SearchForID(c string) string {
	search := fmt.Sprintf("(\\d+)\">%v", c)
	r, err := regexp.Compile(search)
	if err != nil {
		log.Fatal(err)
	}
	page := GetPage(c)
	match := r.Find(page)
	// taking off the last 5 chars, ie ">好 is 5 chars long
	match = match[:(len(match) - 5)]
	return string(match)
}

func StrokeURL(c string) string {
	URL := fmt.Sprintf("http://images.nciku.com/stroke_order/%v.swf", SearchForID(c))
	return URL
}

func main() {
	// GetPage("好")
	fmt.Println(StrokeURL("好"))
}
<commit_msg>add informative comment about chinese char len<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
)

func GetPage(c string) []byte {
	url := fmt.Sprintf("http://www.nciku.com/search/all/%v", c)
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Add("User-agent", "Mozilla/5.0")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func SearchForID(c string) string {
	search := fmt.Sprintf("(\\d+)\">%v", c)
	r, err := regexp.Compile(search)
	if err != nil {
		log.Fatal(err)
	}
	page := GetPage(c)
	match := r.Find(page)
	// taking off the last 5 chars, ie ">好 is 5 chars long
	// Chinese characters take up 3 bytes
	match = match[:(len(match) - 5)]
	return string(match)
}

func StrokeURL(c string) string {
	URL := fmt.Sprintf("http://images.nciku.com/stroke_order/%v.swf", SearchForID(c))
	return URL
}

func main() {
	// GetPage("好")
	fmt.Println(StrokeURL("好"))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

func WithServerHeader(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithServerHeader()")
		r.Header.Add("aa", "bb")
		w.Header().Set("Server", "HelloServer v0.0.1")
		h(w, r)
	}
}

func WithAuthCookie(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithAuthCookie()")
		cookie := &http.Cookie{Name: "Auth", Value: "Pass", Path: "/"}
		http.SetCookie(w, cookie)
		h(w, r)
	}
}

func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithBasicAuth()")
		cookie, err := r.Cookie("Auth")
		if err != nil || cookie.Value != "Pass" {
			w.WriteHeader(http.StatusForbidden)
			return
		}
		h(w, r)
	}
}

func WithDebugLog(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithDebugLog")
		r.ParseForm()
		log.Println(r.Form)
		log.Println("path", r.URL.Path)
		log.Println("scheme", r.URL.Scheme)
		log.Println(r.Form["url_long"])
		for k, v := range r.Form {
			log.Println("key:", k)
			log.Println("val:", strings.Join(v, ""))
		}
		h(w, r)
	}
}

func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Recieved Request %s from %s\n", r.URL.Path, r.RemoteAddr)
	fmt.Fprintf(w, "Hello, World! %s -> %s", r.URL.Path, r.Header.Get("aa"))
}

func main() {
	http.HandleFunc("/v1/hello", WithServerHeader(hello))
	http.HandleFunc("/v2/hello", WithServerHeader(WithAuthCookie(hello)))
	http.HandleFunc("/v3/hello", WithServerHeader(WithBasicAuth(hello)))
	http.HandleFunc("/v4/hello", WithServerHeader(WithBasicAuth(WithDebugLog(hello))))
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>add pipiline decoration<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

func WithServerHeader(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithServerHeader()")
		r.Header.Add("aa", "bb")
		w.Header().Set("Server", "HelloServer v0.0.1")
		h(w, r)
	}
}

func WithAuthCookie(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithAuthCookie()")
		cookie := &http.Cookie{Name: "Auth", Value: "Pass", Path: "/"}
		http.SetCookie(w, cookie)
		h(w, r)
	}
}

func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithBasicAuth()")
		cookie, err := r.Cookie("Auth")
		if err != nil || cookie.Value != "Pass" {
			w.WriteHeader(http.StatusForbidden)
			return
		}
		h(w, r)
	}
}

func WithDebugLog(h http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("--->WithDebugLog")
		r.ParseForm()
		log.Println(r.Form)
		log.Println("path", r.URL.Path)
		log.Println("scheme", r.URL.Scheme)
		log.Println(r.Form["url_long"])
		for k, v := range r.Form {
			log.Println("key:", k)
			log.Println("val:", strings.Join(v, ""))
		}
		h(w, r)
	}
}

// Pipeline
type HttpHandlerDecorator func(http.HandlerFunc) http.HandlerFunc

func With(h http.HandlerFunc, decors ...HttpHandlerDecorator) http.HandlerFunc {
	n := len(decors)
	for i := range decors {
		d := decors[n-1-i] // iterate in reverse
		h = d(h)
	}
	return h
}

func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Recieved Request %s from %s\n", r.URL.Path, r.RemoteAddr)
	fmt.Fprintf(w, "Hello, World! %s -> %s", r.URL.Path, r.Header.Get("aa"))
}

func main() {
	http.HandleFunc("/v1/hello", WithServerHeader(hello))
	http.HandleFunc("/v2/hello", WithServerHeader(WithAuthCookie(hello)))
	http.HandleFunc("/v3/hello", WithServerHeader(WithBasicAuth(hello)))
	http.HandleFunc("/v4/hello", WithServerHeader(WithBasicAuth(WithDebugLog(hello))))
	http.HandleFunc("/v5/hello", With(hello, WithServerHeader, WithAuthCookie, WithDebugLog))
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


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

package fs

import (
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/timeutil"
	"golang.org/x/net/context"
)

// Create a fuse file system whose root directory is the root of the supplied
// bucket. The supplied clock will be used for cache invalidation, modification
// times, etc.
func NewFuseFS(
	clock timeutil.Clock,
	bucket gcs.Bucket) (fs fuse.FileSystem, err error) {
	fs = &fileSystem{
		clock:  clock,
		bucket: bucket,
	}

	return
}

type fileSystem struct {
	fuseutil.NotImplementedFileSystem

	/////////////////////////
	// Dependencies
	/////////////////////////

	clock  timeutil.Clock
	bucket gcs.Bucket

	/////////////////////////
	// Mutable state
	/////////////////////////

	// When acquiring this lock, the caller must hold no inode locks.
	mu syncutil.InvariantMutex

	// The collection of live inodes, indexed by ID. IDs of free inodes that may
	// be re-used have nil entries. No ID less than fuse.RootInodeID is ever used.
	//
	// INVARIANT: All elements are of type *inode.FileInode or *inode.DirInode
	// INVARIANT: len(inodes) > fuse.RootInodeID
	// INVARIANT: For all i < fuse.RootInodeID, inodes[i] == nil
	// INVARIANT: inodes[fuse.RootInodeID] != nil
	// INVARIANT: inodes[fuse.RootInodeID] is of type *inode.DirInode
	//
	// GUARDED_BY(mu)
	inodes []interface{}

	// A list of inode IDs within inodes available for reuse, not including the
	// reserved IDs less than fuse.RootInodeID.
	//
	// INVARIANT: This is all and only indices i of 'inodes' such that i >
	// fuse.RootInodeID and inodes[i] == nil
	//
	// GUARDED_BY(mu)
	freeInodeIDs []fuse.InodeID
}

////////////////////////////////////////////////////////////////////////
// fuse.FileSystem methods
////////////////////////////////////////////////////////////////////////

func (fs *fileSystem) Init(
	ctx context.Context,
	req *fuse.InitRequest) (resp *fuse.InitResponse, err error) {
	// Nothing interesting to do.
	resp = &fuse.InitResponse{}
	return
}
<commit_msg>Set up invariant checking.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fs

import (
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/timeutil"
	"golang.org/x/net/context"
)

// Create a fuse file system whose root directory is the root of the supplied
// bucket. The supplied clock will be used for cache invalidation, modification
// times, etc.
func NewFuseFS(
	clock timeutil.Clock,
	bucket gcs.Bucket) (ffs fuse.FileSystem, err error) {
	fs := &fileSystem{
		clock:  clock,
		bucket: bucket,
	}

	fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants)

	ffs = fs
	return
}

type fileSystem struct {
	fuseutil.NotImplementedFileSystem

	/////////////////////////
	// Dependencies
	/////////////////////////

	clock  timeutil.Clock
	bucket gcs.Bucket

	/////////////////////////
	// Mutable state
	/////////////////////////

	// When acquiring this lock, the caller must hold no inode locks.
	mu syncutil.InvariantMutex

	// The collection of live inodes, indexed by ID. IDs of free inodes that may
	// be re-used have nil entries. No ID less than fuse.RootInodeID is ever used.
	//
	// INVARIANT: All elements are of type *inode.FileInode or *inode.DirInode
	// INVARIANT: len(inodes) > fuse.RootInodeID
	// INVARIANT: For all i < fuse.RootInodeID, inodes[i] == nil
	// INVARIANT: inodes[fuse.RootInodeID] != nil
	// INVARIANT: inodes[fuse.RootInodeID] is of type *inode.DirInode
	//
	// GUARDED_BY(mu)
	inodes []interface{}

	// A list of inode IDs within inodes available for reuse, not including the
	// reserved IDs less than fuse.RootInodeID.
	//
	// INVARIANT: This is all and only indices i of 'inodes' such that i >
	// fuse.RootInodeID and inodes[i] == nil
	//
	// GUARDED_BY(mu)
	freeInodeIDs []fuse.InodeID
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (fs *fileSystem) checkInvariants()

////////////////////////////////////////////////////////////////////////
// fuse.FileSystem methods
////////////////////////////////////////////////////////////////////////

func (fs *fileSystem) Init(
	ctx context.Context,
	req *fuse.InitRequest) (resp *fuse.InitResponse, err error) {
	// Nothing interesting to do.
	resp = &fuse.InitResponse{}
	return
}
<|endoftext|>