<commit_before>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"bufio"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/bogem/id3v2/bwpool"
	"github.com/bogem/id3v2/util"
)

// Tag stores all frames of opened file.
type Tag struct {
	frames    map[string]Framer
	sequences map[string]sequencer

	file         *os.File
	originalSize int64
	version      byte
}

// AddFrame adds f to tag with appropriate id. If id is "" or f is nil,
// AddFrame will not add f to tag.
//
// If you want to add attached picture, comment or unsynchronised lyrics/text
// transcription frames, better use AddAttachedPicture, AddCommentFrame
// or AddUnsynchronisedLyricsFrame methods respectively.
func (t *Tag) AddFrame(id string, f Framer) {
	if id == "" || f == nil {
		return
	}

	if _, exists := sequenceConstructors[id]; exists { // check if frame should be added in sequence
		if t.sequences[id] == nil {
			constructor := sequenceConstructors[id]
			t.sequences[id] = constructor()
		}
		t.sequences[id].AddFrame(f)
	} else {
		t.frames[id] = f
	}
}

func (t *Tag) AddAttachedPicture(pf PictureFrame) {
	id := t.CommonID("Attached picture")
	t.AddFrame(id, pf)
}

func (t *Tag) AddCommentFrame(cf CommentFrame) {
	id := t.CommonID("Comments")
	t.AddFrame(id, cf)
}

func (t *Tag) AddUnsynchronisedLyricsFrame(uslf UnsynchronisedLyricsFrame) {
	id := t.CommonID("Unsynchronised lyrics/text transcription")
	t.AddFrame(id, uslf)
}

// CommonID returns ID3v2.3 or ID3v2.4 (in appropriate to version of Tag) frame ID
// from given description.
// For example, CommonID("Language") will return "TLAN".
// All descriptions you can find in file common_ids.go or in id3 documentation (for fourth version: http://id3.org/id3v2.4.0-frames; for third version: http://id3.org/id3v2.3.0#Declared_ID3v2_frames).
func (t Tag) CommonID(description string) string {
	if t.version == 3 {
		return V23CommonIDs[description]
	} else {
		return V24CommonIDs[description]
	}

	return ""
}

// AllFrames returns map, that contains all frames in tag, that could be parsed.
// The key of this map is an ID of frame and value is an array of frames.
func (t *Tag) AllFrames() map[string][]Framer {
	frames := make(map[string][]Framer)

	for id, f := range t.frames {
		frames[id] = []Framer{f}
	}
	for id, sequence := range t.sequences {
		frames[id] = sequence.Frames()
	}

	return frames
}

// DeleteAllFrames deletes all frames in tag.
func (t *Tag) DeleteAllFrames() {
	t.frames = make(map[string]Framer)
	t.sequences = make(map[string]sequencer)
}

// DeleteFrames deletes frames in tag with given id.
func (t *Tag) DeleteFrames(id string) {
	delete(t.frames, id)
	delete(t.sequences, id)
}

// GetLastFrame returns last frame from slice, that is returned from GetFrames function.
// GetLastFrame is suitable for frames, that can be only one in whole tag.
// For example, for text frames.
//
// Example of usage:
//	bpmFramer := tag.GetLastFrame(tag.CommonID("BPM"))
//	if bpmFramer != nil {
//		bpm, ok := bpmFramer.(id3v2.TextFrame)
//		if !ok {
//			log.Fatal("Couldn't assert bpm frame")
//		}
//		fmt.Println(bpm.Text)
//	}
func (t *Tag) GetLastFrame(id string) Framer {
	// Avoid an allocation of slice in GetFrames,
	// if there is anyway one frame.
	if f, exists := t.frames[id]; exists {
		return f
	}

	fs := t.GetFrames(id)
	if len(fs) == 0 || fs == nil {
		return nil
	}
	return fs[len(fs)-1]
}

// GetFrames returns frames with corresponding id.
// It returns nil if there is no frames with given id.
//
// Example of usage:
//	pictures := tag.GetFrames(tag.CommonID("Attached picture"))
//	if pictures != nil {
//		for _, f := range pictures {
//			pic, ok := f.(id3v2.PictureFrame)
//			if !ok {
//				log.Fatal("Couldn't assert picture frame")
//			}
//
//			// Do some operations with picture frame:
//			fmt.Println(pic.Description) // For example, print description of picture frame
//		}
//	}
func (t *Tag) GetFrames(id string) []Framer {
	if f, exists := t.frames[id]; exists {
		return []Framer{f}
	} else if s, exists := t.sequences[id]; exists {
		return s.Frames()
	}
	return nil
}

// GetTextFrame returns text frame with corresponding id.
func (t Tag) GetTextFrame(id string) TextFrame {
	f := t.GetLastFrame(id)
	if f == nil {
		return TextFrame{}
	}
	tf := f.(TextFrame)
	return tf
}

// Count returns the number of frames in tag.
func (t Tag) Count() int {
	n := len(t.frames)
	for _, s := range t.sequences {
		n += s.Count()
	}
	return n
}

// HasAnyFrames checks if there is at least one frame in tag.
// It's much faster than tag.Count() > 0.
func (t Tag) HasAnyFrames() bool {
	return len(t.frames) > 0 || len(t.sequences) > 0
}

func (t Tag) Title() string {
	f := t.GetTextFrame(t.CommonID("Title/Songname/Content description"))
	return f.Text
}

func (t *Tag) SetTitle(title string) {
	t.AddFrame(t.CommonID("Title/Songname/Content description"), TextFrame{Encoding: ENUTF8, Text: title})
}

func (t Tag) Artist() string {
	f := t.GetTextFrame(t.CommonID("Lead artist/Lead performer/Soloist/Performing group"))
	return f.Text
}

func (t *Tag) SetArtist(artist string) {
	t.AddFrame(t.CommonID("Lead artist/Lead performer/Soloist/Performing group"), TextFrame{Encoding: ENUTF8, Text: artist})
}

func (t Tag) Album() string {
	f := t.GetTextFrame(t.CommonID("Album/Movie/Show title"))
	return f.Text
}

func (t *Tag) SetAlbum(album string) {
	t.AddFrame(t.CommonID("Album/Movie/Show title"), TextFrame{Encoding: ENUTF8, Text: album})
}

func (t Tag) Year() string {
	f := t.GetTextFrame(t.CommonID("Year"))
	return f.Text
}

func (t *Tag) SetYear(year string) {
	t.AddFrame(t.CommonID("Year"), TextFrame{Encoding: ENUTF8, Text: year})
}

func (t Tag) Genre() string {
	f := t.GetTextFrame(t.CommonID("Content type"))
	return f.Text
}

func (t *Tag) SetGenre(genre string) {
	t.AddFrame(t.CommonID("Content type"), TextFrame{Encoding: ENUTF8, Text: genre})
}

// iterateOverAllFrames iterates over every single frame in tag and call
// f for them. It consumps no memory at all, unlike the tag.AllFrames().
// It returns error only if f returns error.
func (t Tag) iterateOverAllFrames(f func(id string, frame Framer) error) error {
	for id, frame := range t.frames {
		if err := f(id, frame); err != nil {
			return err
		}
	}
	for id, sequence := range t.sequences {
		for _, frame := range sequence.Frames() {
			if err := f(id, frame); err != nil {
				return err
			}
		}
	}
	return nil
}

// Size returns the size of all ID3 tag in bytes.
func (t Tag) Size() int {
	if !t.HasAnyFrames() {
		return 0
	}

	var n int
	n += tagHeaderSize // Add the size of tag header
	t.iterateOverAllFrames(func(id string, f Framer) error {
		n += frameHeaderSize + f.Size()
		return nil
	})

	return n
}

// Version returns current ID3v2 version of tag.
func (t Tag) Version() byte {
	return t.version
}

// SetVersion sets given ID3v2 version to tag.
// If version is less than 3 or more than 4, then this method will do nothing.
// If tag has some frames, which are deprecated or changed in given version,
// then to your notice you can delete, change or just stay them.
func (t *Tag) SetVersion(version byte) {
	if version < 3 || version > 4 {
		return
	}
	t.version = version
}

// Save writes tag to the file. If there are no frames in tag, Save will write
// only music part without any ID3v2 information.
func (t *Tag) Save() error {
	// Create a temp file for mp3 file, which will contain new tag
	newFile, err := ioutil.TempFile(filepath.Dir(t.file.Name()), "id3v2-")
	if err != nil {
		return err
	}

	// Make sure we clean up the temp file if it's still around
	defer os.Remove(newFile.Name())

	// If there is at least one frame, write whole tag in new file
	if t.HasAnyFrames() {
		if err = t.Write(newFile); err != nil {
			return err
		}
	}

	// Seek to a music part of original file
	originalFile := t.file
	if _, err = originalFile.Seek(t.originalSize, os.SEEK_SET); err != nil {
		return err
	}

	// Write to new file the music part
	if _, err = io.Copy(newFile, originalFile); err != nil {
		return err
	}

	// Get original file mode
	originalFileStat, err := originalFile.Stat()
	if err != nil {
		return err
	}

	// Set original file mode to new file
	if err = os.Chmod(newFile.Name(), originalFileStat.Mode()); err != nil {
		return err
	}

	// Close files to allow replacing
	newFile.Close()
	originalFile.Close()

	// Replace original file with new file
	if err = os.Rename(newFile.Name(), originalFile.Name()); err != nil {
		return err
	}

	// Set t.file to new file with original name
	t.file, err = os.Open(originalFile.Name())
	if err != nil {
		return err
	}

	// Set t.originalSize to new frames size
	framesSize := t.Size() - tagHeaderSize
	t.originalSize = int64(framesSize)

	return nil
}

// Write writes whole tag in w.
func (t Tag) Write(w io.Writer) error {
	// Form size of frames
	framesSize := t.Size() - tagHeaderSize
	byteFramesSize, err := util.FormSize(framesSize)
	if err != nil {
		return err
	}

	// Write tag header
	if _, err = w.Write(formTagHeader(byteFramesSize, t.version)); err != nil {
		return err
	}

	// Write frames
	if err = t.writeAllFrames(w); err != nil {
		return err
	}

	return nil
}

func (t Tag) writeAllFrames(w io.Writer) error {
	bw := bwpool.Get(w)
	defer bwpool.Put(bw)

	err := t.iterateOverAllFrames(func(id string, f Framer) error {
		return writeFrame(bw, id, f)
	})
	if err != nil {
		return err
	}

	return bw.Flush()
}

func writeFrame(bw *bufio.Writer, id string, frame Framer) error {
	if err := writeFrameHeader(bw, id, frame.Size()); err != nil {
		return err
	}
	if _, err := frame.WriteTo(bw); err != nil {
		return err
	}

	return nil
}

func writeFrameHeader(bw *bufio.Writer, id string, frameSize int) error {
	size, err := util.FormSize(frameSize)
	if err != nil {
		return err
	}

	bw.WriteString(id)
	bw.Write(size)
	bw.Write([]byte{0, 0})
	return nil
}

// Close closes the tag's file, rendering it unusable for I/O.
// It returns an error, if any.
func (t *Tag) Close() error {
	return t.file.Close()
}
<commit_msg>Delete unreachable code in tag.CommonID()<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"bufio"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/bogem/id3v2/bwpool"
	"github.com/bogem/id3v2/util"
)

// Tag stores all frames of opened file.
type Tag struct {
	frames    map[string]Framer
	sequences map[string]sequencer

	file         *os.File
	originalSize int64
	version      byte
}

// AddFrame adds f to tag with appropriate id. If id is "" or f is nil,
// AddFrame will not add f to tag.
//
// If you want to add attached picture, comment or unsynchronised lyrics/text
// transcription frames, better use AddAttachedPicture, AddCommentFrame
// or AddUnsynchronisedLyricsFrame methods respectively.
func (t *Tag) AddFrame(id string, f Framer) {
	if id == "" || f == nil {
		return
	}

	if _, exists := sequenceConstructors[id]; exists { // check if frame should be added in sequence
		if t.sequences[id] == nil {
			constructor := sequenceConstructors[id]
			t.sequences[id] = constructor()
		}
		t.sequences[id].AddFrame(f)
	} else {
		t.frames[id] = f
	}
}

func (t *Tag) AddAttachedPicture(pf PictureFrame) {
	id := t.CommonID("Attached picture")
	t.AddFrame(id, pf)
}

func (t *Tag) AddCommentFrame(cf CommentFrame) {
	id := t.CommonID("Comments")
	t.AddFrame(id, cf)
}

func (t *Tag) AddUnsynchronisedLyricsFrame(uslf UnsynchronisedLyricsFrame) {
	id := t.CommonID("Unsynchronised lyrics/text transcription")
	t.AddFrame(id, uslf)
}

// CommonID returns ID3v2.3 or ID3v2.4 (in appropriate to version of Tag) frame ID
// from given description.
// For example, CommonID("Language") will return "TLAN".
// All descriptions you can find in file common_ids.go or in id3 documentation (for fourth version: http://id3.org/id3v2.4.0-frames; for third version: http://id3.org/id3v2.3.0#Declared_ID3v2_frames).
func (t Tag) CommonID(description string) string {
	if t.version == 3 {
		return V23CommonIDs[description]
	}
	return V24CommonIDs[description]
}

// AllFrames returns map, that contains all frames in tag, that could be parsed.
// The key of this map is an ID of frame and value is an array of frames.
func (t *Tag) AllFrames() map[string][]Framer {
	frames := make(map[string][]Framer)

	for id, f := range t.frames {
		frames[id] = []Framer{f}
	}
	for id, sequence := range t.sequences {
		frames[id] = sequence.Frames()
	}

	return frames
}

// DeleteAllFrames deletes all frames in tag.
func (t *Tag) DeleteAllFrames() {
	t.frames = make(map[string]Framer)
	t.sequences = make(map[string]sequencer)
}

// DeleteFrames deletes frames in tag with given id.
func (t *Tag) DeleteFrames(id string) {
	delete(t.frames, id)
	delete(t.sequences, id)
}

// GetLastFrame returns last frame from slice, that is returned from GetFrames function.
// GetLastFrame is suitable for frames, that can be only one in whole tag.
// For example, for text frames.
//
// Example of usage:
//	bpmFramer := tag.GetLastFrame(tag.CommonID("BPM"))
//	if bpmFramer != nil {
//		bpm, ok := bpmFramer.(id3v2.TextFrame)
//		if !ok {
//			log.Fatal("Couldn't assert bpm frame")
//		}
//		fmt.Println(bpm.Text)
//	}
func (t *Tag) GetLastFrame(id string) Framer {
	// Avoid an allocation of slice in GetFrames,
	// if there is anyway one frame.
	if f, exists := t.frames[id]; exists {
		return f
	}

	fs := t.GetFrames(id)
	if len(fs) == 0 || fs == nil {
		return nil
	}
	return fs[len(fs)-1]
}

// GetFrames returns frames with corresponding id.
// It returns nil if there is no frames with given id.
//
// Example of usage:
//	pictures := tag.GetFrames(tag.CommonID("Attached picture"))
//	if pictures != nil {
//		for _, f := range pictures {
//			pic, ok := f.(id3v2.PictureFrame)
//			if !ok {
//				log.Fatal("Couldn't assert picture frame")
//			}
//
//			// Do some operations with picture frame:
//			fmt.Println(pic.Description) // For example, print description of picture frame
//		}
//	}
func (t *Tag) GetFrames(id string) []Framer {
	if f, exists := t.frames[id]; exists {
		return []Framer{f}
	} else if s, exists := t.sequences[id]; exists {
		return s.Frames()
	}
	return nil
}

// GetTextFrame returns text frame with corresponding id.
func (t Tag) GetTextFrame(id string) TextFrame {
	f := t.GetLastFrame(id)
	if f == nil {
		return TextFrame{}
	}
	tf := f.(TextFrame)
	return tf
}

// Count returns the number of frames in tag.
func (t Tag) Count() int {
	n := len(t.frames)
	for _, s := range t.sequences {
		n += s.Count()
	}
	return n
}

// HasAnyFrames checks if there is at least one frame in tag.
// It's much faster than tag.Count() > 0.
func (t Tag) HasAnyFrames() bool {
	return len(t.frames) > 0 || len(t.sequences) > 0
}

func (t Tag) Title() string {
	f := t.GetTextFrame(t.CommonID("Title/Songname/Content description"))
	return f.Text
}

func (t *Tag) SetTitle(title string) {
	t.AddFrame(t.CommonID("Title/Songname/Content description"), TextFrame{Encoding: ENUTF8, Text: title})
}

func (t Tag) Artist() string {
	f := t.GetTextFrame(t.CommonID("Lead artist/Lead performer/Soloist/Performing group"))
	return f.Text
}

func (t *Tag) SetArtist(artist string) {
	t.AddFrame(t.CommonID("Lead artist/Lead performer/Soloist/Performing group"), TextFrame{Encoding: ENUTF8, Text: artist})
}

func (t Tag) Album() string {
	f := t.GetTextFrame(t.CommonID("Album/Movie/Show title"))
	return f.Text
}

func (t *Tag) SetAlbum(album string) {
	t.AddFrame(t.CommonID("Album/Movie/Show title"), TextFrame{Encoding: ENUTF8, Text: album})
}

func (t Tag) Year() string {
	f := t.GetTextFrame(t.CommonID("Year"))
	return f.Text
}

func (t *Tag) SetYear(year string) {
	t.AddFrame(t.CommonID("Year"), TextFrame{Encoding: ENUTF8, Text: year})
}

func (t Tag) Genre() string {
	f := t.GetTextFrame(t.CommonID("Content type"))
	return f.Text
}

func (t *Tag) SetGenre(genre string) {
	t.AddFrame(t.CommonID("Content type"), TextFrame{Encoding: ENUTF8, Text: genre})
}

// iterateOverAllFrames iterates over every single frame in tag and call
// f for them. It consumps no memory at all, unlike the tag.AllFrames().
// It returns error only if f returns error.
func (t Tag) iterateOverAllFrames(f func(id string, frame Framer) error) error {
	for id, frame := range t.frames {
		if err := f(id, frame); err != nil {
			return err
		}
	}
	for id, sequence := range t.sequences {
		for _, frame := range sequence.Frames() {
			if err := f(id, frame); err != nil {
				return err
			}
		}
	}
	return nil
}

// Size returns the size of all ID3 tag in bytes.
func (t Tag) Size() int {
	if !t.HasAnyFrames() {
		return 0
	}

	var n int
	n += tagHeaderSize // Add the size of tag header
	t.iterateOverAllFrames(func(id string, f Framer) error {
		n += frameHeaderSize + f.Size()
		return nil
	})

	return n
}

// Version returns current ID3v2 version of tag.
func (t Tag) Version() byte {
	return t.version
}

// SetVersion sets given ID3v2 version to tag.
// If version is less than 3 or more than 4, then this method will do nothing.
// If tag has some frames, which are deprecated or changed in given version,
// then to your notice you can delete, change or just stay them.
func (t *Tag) SetVersion(version byte) {
	if version < 3 || version > 4 {
		return
	}
	t.version = version
}

// Save writes tag to the file. If there are no frames in tag, Save will write
// only music part without any ID3v2 information.
func (t *Tag) Save() error {
	// Create a temp file for mp3 file, which will contain new tag
	newFile, err := ioutil.TempFile(filepath.Dir(t.file.Name()), "id3v2-")
	if err != nil {
		return err
	}

	// Make sure we clean up the temp file if it's still around
	defer os.Remove(newFile.Name())

	// If there is at least one frame, write whole tag in new file
	if t.HasAnyFrames() {
		if err = t.Write(newFile); err != nil {
			return err
		}
	}

	// Seek to a music part of original file
	originalFile := t.file
	if _, err = originalFile.Seek(t.originalSize, os.SEEK_SET); err != nil {
		return err
	}

	// Write to new file the music part
	if _, err = io.Copy(newFile, originalFile); err != nil {
		return err
	}

	// Get original file mode
	originalFileStat, err := originalFile.Stat()
	if err != nil {
		return err
	}

	// Set original file mode to new file
	if err = os.Chmod(newFile.Name(), originalFileStat.Mode()); err != nil {
		return err
	}

	// Close files to allow replacing
	newFile.Close()
	originalFile.Close()

	// Replace original file with new file
	if err = os.Rename(newFile.Name(), originalFile.Name()); err != nil {
		return err
	}

	// Set t.file to new file with original name
	t.file, err = os.Open(originalFile.Name())
	if err != nil {
		return err
	}

	// Set t.originalSize to new frames size
	framesSize := t.Size() - tagHeaderSize
	t.originalSize = int64(framesSize)

	return nil
}

// Write writes whole tag in w.
func (t Tag) Write(w io.Writer) error {
	// Form size of frames
	framesSize := t.Size() - tagHeaderSize
	byteFramesSize, err := util.FormSize(framesSize)
	if err != nil {
		return err
	}

	// Write tag header
	if _, err = w.Write(formTagHeader(byteFramesSize, t.version)); err != nil {
		return err
	}

	// Write frames
	if err = t.writeAllFrames(w); err != nil {
		return err
	}

	return nil
}

func (t Tag) writeAllFrames(w io.Writer) error {
	bw := bwpool.Get(w)
	defer bwpool.Put(bw)

	err := t.iterateOverAllFrames(func(id string, f Framer) error {
		return writeFrame(bw, id, f)
	})
	if err != nil {
		return err
	}

	return bw.Flush()
}

func writeFrame(bw *bufio.Writer, id string, frame Framer) error {
	if err := writeFrameHeader(bw, id, frame.Size()); err != nil {
		return err
	}
	if _, err := frame.WriteTo(bw); err != nil {
		return err
	}

	return nil
}

func writeFrameHeader(bw *bufio.Writer, id string, frameSize int) error {
	size, err := util.FormSize(frameSize)
	if err != nil {
		return err
	}

	bw.WriteString(id)
	bw.Write(size)
	bw.Write([]byte{0, 0})
	return nil
}

// Close closes the tag's file, rendering it unusable for I/O.
// It returns an error, if any.
func (t *Tag) Close() error {
	return t.file.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"go-bots/ev3"
	"go-bots/greyhound/config"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func handleSignals() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		sig := <-sigs
		quit("Terminated by signal", sig)
	}()
}

var devs *ev3.Devices
var initializationTime time.Time
var motorL1, motorL2, motorR1, motorR2 *ev3.Attribute
var cLL, cL, cR, cRR *ev3.Attribute
var buttons *ev3.Buttons

var conf config.Config

func closeSensors() {
	cLL.Close()
	cL.Close()
	cR.Close()
	cRR.Close()
}

func setSensorsMode() {
	ev3.SetMode(devs.In1, ev3.ColorModeReflect)
	ev3.SetMode(devs.In2, ev3.ColorModeReflect)
	ev3.SetMode(devs.In3, ev3.ColorModeReflect)
	ev3.SetMode(devs.In4, ev3.ColorModeReflect)

	cLL = ev3.OpenByteR(devs.In4, ev3.BinData)
	cL = ev3.OpenByteR(devs.In3, ev3.BinData)
	cR = ev3.OpenByteR(devs.In2, ev3.BinData)
	cRR = ev3.OpenByteR(devs.In1, ev3.BinData)
}

func initialize() {
	initializationTime = time.Now()

	buttons = ev3.OpenButtons()

	devs = ev3.Scan(&ev3.OutPortModes{
		OutA: ev3.OutPortModeDcMotor,
		OutB: ev3.OutPortModeDcMotor,
		OutC: ev3.OutPortModeDcMotor,
		OutD: ev3.OutPortModeDcMotor,
	})

	// Check motors
	ev3.CheckDriver(devs.OutA, ev3.DriverRcxMotor, ev3.OutA)
	ev3.CheckDriver(devs.OutB, ev3.DriverRcxMotor, ev3.OutB)
	ev3.CheckDriver(devs.OutC, ev3.DriverRcxMotor, ev3.OutC)
	ev3.CheckDriver(devs.OutD, ev3.DriverRcxMotor, ev3.OutD)

	// Check sensors
	ev3.CheckDriver(devs.In1, ev3.DriverColor, ev3.In1)
	ev3.CheckDriver(devs.In2, ev3.DriverColor, ev3.In2)
	ev3.CheckDriver(devs.In3, ev3.DriverColor, ev3.In3)
	ev3.CheckDriver(devs.In4, ev3.DriverColor, ev3.In4)

	// Set sensors mode
	setSensorsMode()

	// Stop motors
	ev3.RunCommand(devs.OutA, ev3.CmdStop)
	ev3.RunCommand(devs.OutB, ev3.CmdStop)
	ev3.RunCommand(devs.OutC, ev3.CmdStop)
	ev3.RunCommand(devs.OutD, ev3.CmdStop)

	// Open motors
	motorL1 = ev3.OpenTextW(devs.OutC, ev3.DutyCycleSp)
	motorL2 = ev3.OpenTextW(devs.OutD, ev3.DutyCycleSp)
	motorR1 = ev3.OpenTextW(devs.OutA, ev3.DutyCycleSp)
	motorR2 = ev3.OpenTextW(devs.OutB, ev3.DutyCycleSp)

	// Reset motor speed
	motorL1.Value = 0
	motorL2.Value = 0
	motorR1.Value = 0
	motorR2.Value = 0

	motorL1.Sync()
	motorL2.Sync()
	motorR1.Sync()
	motorR2.Sync()

	// Put motors in direct mode
	ev3.RunCommand(devs.OutA, ev3.CmdRunDirect)
	ev3.RunCommand(devs.OutB, ev3.CmdRunDirect)
	ev3.RunCommand(devs.OutC, ev3.CmdRunDirect)
	ev3.RunCommand(devs.OutD, ev3.CmdRunDirect)
}

func close() {
	// Close buttons
	buttons.Close()

	// Stop motors
	ev3.RunCommand(devs.OutA, ev3.CmdStop)
	ev3.RunCommand(devs.OutB, ev3.CmdStop)
	ev3.RunCommand(devs.OutC, ev3.CmdStop)
	ev3.RunCommand(devs.OutD, ev3.CmdStop)

	// Close motors
	motorL1.Close()
	motorL2.Close()
	motorR1.Close()
	motorR2.Close()

	// Close sensor values
	closeSensors()
}

var lastMoveTicks int
var lastSpeedLeft int
var lastSpeedRight int

const accelPerTicks int = 5

func move(left int, right int, now int) {
	ticks := now - lastMoveTicks
	lastMoveTicks = now

	nextSpeedLeft := lastSpeedLeft
	nextSpeedRight := lastSpeedRight
	delta := ticks * accelPerTicks
	// delta := ticks * ticks * accelPerTicks

	if left > nextSpeedLeft {
		nextSpeedLeft += delta
		if nextSpeedLeft > left {
			nextSpeedLeft = left
		}
	} else if left < nextSpeedLeft {
		nextSpeedLeft -= delta
		if nextSpeedLeft < left {
			nextSpeedLeft = left
		}
	}
	if right > nextSpeedRight {
		nextSpeedRight += delta
		if nextSpeedRight > right {
			nextSpeedRight = right
		}
	} else if right < nextSpeedRight {
		nextSpeedRight -= delta
		if nextSpeedRight < right {
			nextSpeedRight = right
		}
	}
	lastSpeedLeft = nextSpeedLeft
	lastSpeedRight = nextSpeedRight

	motorL1.Value = nextSpeedLeft / 10000
	motorL2.Value = nextSpeedLeft / 10000
	motorR1.Value = -nextSpeedRight / 10000
	motorR2.Value = -nextSpeedRight / 10000

	motorL1.Sync()
	motorL2.Sync()
	motorR1.Sync()
	motorR2.Sync()
}

func read() {
	cLL.Sync()
	cL.Sync()
	cR.Sync()
	cRR.Sync()
}

func durationToTicks(d time.Duration) int {
	return int(d / 1000)
}
func timespanAsTicks(start time.Time, end time.Time) int {
	return durationToTicks(end.Sub(start))
}
func currentTicks() int {
	return timespanAsTicks(initializationTime, time.Now())
}
func ticksToMillis(ticks int) int {
	return ticks / 1000
}

func print(data ...interface{}) {
	fmt.Fprintln(os.Stderr, data...)
}

func quit(data ...interface{}) {
	close()
	log.Fatalln(data...)
}

func waitOneSecond() {
	print("wait one second")
	start := currentTicks()
	for {
		now := currentTicks()
		elapsed := now - start
		move(0, 0, now)
		if elapsed >= 1000000 {
			break
		}
	}
}

func moveOneSecond() {
	print("move one second")
	start := currentTicks()
	for {
		now := currentTicks()
		elapsed := now - start
		move(conf.MaxSpeed, conf.MaxSpeed, now)
		if elapsed >= 1000000 {
			break
		}
	}
}

func main() {
	handleSignals()
	initialize()
	defer close()

	conf = config.Default()

	for {
	}

	// waitOneSecond()
	// moveOneSecond()
}
<commit_msg>Testing buttons.<commit_after>package main

import (
	"fmt"
	"go-bots/ev3"
	"go-bots/greyhound/config"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func handleSignals() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		sig := <-sigs
		quit("Terminated by signal", sig)
	}()
}

var devs *ev3.Devices
var initializationTime time.Time
var motorL1, motorL2, motorR1, motorR2 *ev3.Attribute
var cLL, cL, cR, cRR *ev3.Attribute
var buttons *ev3.Buttons

var conf config.Config

func closeSensors() {
	cLL.Close()
	cL.Close()
	cR.Close()
	cRR.Close()
}

func setSensorsMode() {
	ev3.SetMode(devs.In1, ev3.ColorModeReflect)
	ev3.SetMode(devs.In2, ev3.ColorModeReflect)
	ev3.SetMode(devs.In3, ev3.ColorModeReflect)
	ev3.SetMode(devs.In4, ev3.ColorModeReflect)

	cLL = ev3.OpenByteR(devs.In4, ev3.BinData)
	cL = ev3.OpenByteR(devs.In3, ev3.BinData)
	cR = ev3.OpenByteR(devs.In2, ev3.BinData)
	cRR = ev3.OpenByteR(devs.In1, ev3.BinData)
}

func initialize() {
	initializationTime = time.Now()

	buttons = ev3.OpenButtons()

	devs = ev3.Scan(&ev3.OutPortModes{
		OutA: ev3.OutPortModeDcMotor,
		OutB: ev3.OutPortModeDcMotor,
		OutC: ev3.OutPortModeDcMotor,
		OutD: ev3.OutPortModeDcMotor,
	})

	// Check motors
	ev3.CheckDriver(devs.OutA, ev3.DriverRcxMotor, ev3.OutA)
	ev3.CheckDriver(devs.OutB, ev3.DriverRcxMotor, ev3.OutB)
	ev3.CheckDriver(devs.OutC, ev3.DriverRcxMotor, ev3.OutC)
	ev3.CheckDriver(devs.OutD, ev3.DriverRcxMotor, ev3.OutD)

	// Check sensors
	ev3.CheckDriver(devs.In1, ev3.DriverColor, ev3.In1)
	ev3.CheckDriver(devs.In2, ev3.DriverColor, ev3.In2)
	ev3.CheckDriver(devs.In3, ev3.DriverColor, ev3.In3)
	ev3.CheckDriver(devs.In4, ev3.DriverColor, ev3.In4)

	// Set sensors mode
	setSensorsMode()

	// Stop motors
	ev3.RunCommand(devs.OutA, ev3.CmdStop)
	ev3.RunCommand(devs.OutB, ev3.CmdStop)
	ev3.RunCommand(devs.OutC, ev3.CmdStop)
	ev3.RunCommand(devs.OutD, ev3.CmdStop)

	// Open motors
	motorL1 = ev3.OpenTextW(devs.OutC, ev3.DutyCycleSp)
	motorL2 = ev3.OpenTextW(devs.OutD, ev3.DutyCycleSp)
	motorR1 = ev3.OpenTextW(devs.OutA, ev3.DutyCycleSp)
	motorR2 = ev3.OpenTextW(devs.OutB, ev3.DutyCycleSp)

	// Reset motor speed
	motorL1.Value = 0
	motorL2.Value = 0
	motorR1.Value = 0
	motorR2.Value = 0

	motorL1.Sync()
	motorL2.Sync()
	motorR1.Sync()
	motorR2.Sync()

	// Put motors in direct mode
	ev3.RunCommand(devs.OutA, ev3.CmdRunDirect)
	ev3.RunCommand(devs.OutB, ev3.CmdRunDirect)
	ev3.RunCommand(devs.OutC, ev3.CmdRunDirect)
	ev3.RunCommand(devs.OutD, ev3.CmdRunDirect)
}

func close() {
	// Close buttons
	buttons.Close()

	// Stop motors
	ev3.RunCommand(devs.OutA, ev3.CmdStop)
	ev3.RunCommand(devs.OutB, ev3.CmdStop)
	ev3.RunCommand(devs.OutC, ev3.CmdStop)
	ev3.RunCommand(devs.OutD, ev3.CmdStop)

	// Close motors
	motorL1.Close()
	motorL2.Close()
	motorR1.Close()
	motorR2.Close()

	// Close sensor values
	closeSensors()
}

var lastMoveTicks int
var lastSpeedLeft int
var lastSpeedRight int

const accelPerTicks int = 5

func move(left int, right int, now int) {
	ticks := now - lastMoveTicks
	lastMoveTicks = now

	nextSpeedLeft := lastSpeedLeft
	nextSpeedRight := lastSpeedRight
	delta := ticks * accelPerTicks
	// delta := ticks * ticks * accelPerTicks

	if left > nextSpeedLeft {
		nextSpeedLeft += delta
		if nextSpeedLeft > left {
			nextSpeedLeft = left
		}
	} else if left < nextSpeedLeft {
		nextSpeedLeft -= delta
		if nextSpeedLeft < left {
			nextSpeedLeft = left
		}
	}
	if right > nextSpeedRight {
		nextSpeedRight += delta
		if nextSpeedRight > right {
			nextSpeedRight = right
		}
	} else if right < nextSpeedRight {
		nextSpeedRight -= delta
		if nextSpeedRight < right {
			nextSpeedRight = right
		}
	}
	lastSpeedLeft = nextSpeedLeft
	lastSpeedRight = nextSpeedRight

	motorL1.Value = nextSpeedLeft / 10000
	motorL2.Value = nextSpeedLeft / 10000
	motorR1.Value = -nextSpeedRight / 10000
	motorR2.Value = -nextSpeedRight / 10000

	motorL1.Sync()
	motorL2.Sync()
	motorR1.Sync()
	motorR2.Sync()
}

func read() {
	cLL.Sync()
	cL.Sync()
	cR.Sync()
	cRR.Sync()
}

func durationToTicks(d time.Duration) int {
	return int(d / 1000)
}
func timespanAsTicks(start time.Time, end time.Time) int {
	return durationToTicks(end.Sub(start))
}
func currentTicks() int {
	return timespanAsTicks(initializationTime, time.Now())
}
func ticksToMillis(ticks int) int {
	return ticks / 1000
}

func print(data ...interface{}) {
	fmt.Fprintln(os.Stderr, data...)
}

func quit(data ...interface{}) {
	close()
	log.Fatalln(data...)
}

func waitOneSecond() {
	print("wait one second")
	start := currentTicks()
	for {
		now := currentTicks()
		elapsed := now - start
		move(0, 0, now)
		if elapsed >= 1000000 {
			break
		}
	}
}

func moveOneSecond() {
	print("move one second")
	start := currentTicks()
	for {
		now := currentTicks()
		elapsed := now - start
		move(conf.MaxSpeed, conf.MaxSpeed, now)
		if elapsed >= 1000000 {
			break
		}
	}
}

func main() {
	handleSignals()
	initialize()
	defer close()

	conf = config.Default()

	lastPrint := 0
	for {
		now := currentTicks()
		if now-lastPrint > 1000000 {
			lastPrint = now
			print("Tock...")
		}
	}

	// waitOneSecond()
	// moveOneSecond()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"pcfdev/cert"
	"pcfdev/fs"
	"pcfdev/provisioner"
	"strconv"
	"syscall"
	"time"
)

var (
	provisionScriptPath = "/var/pcfdev/run"
	timeoutInSeconds    = "1800"
)

func main() {
	provisionTimeout, err := strconv.Atoi(timeoutInSeconds)
	if err != nil {
		fmt.Printf("Error: %s.", err)
		os.Exit(1)
	}

	p := &provisioner.Provisioner{
		Cert: &cert.Cert{},
		CmdRunner: &provisioner.ConcreteCmdRunner{
			Stdout:  os.Stdout,
			Stderr:  os.Stderr,
			Timeout: time.Duration(provisionTimeout) * time.Second,
		},
		FS: &fs.FS{},
	}

	if err := p.Provision(provisionScriptPath, os.Args[1:]...); err != nil {
		switch err.(type) {
		case *exec.ExitError:
			if exitErr, ok := err.(*exec.ExitError); ok {
				if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
					os.Exit(status.ExitStatus())
				} else {
					os.Exit(1)
				}
			}
		case *provisioner.TimeoutError:
			fmt.Printf("Timed out after %s seconds.\n", timeoutInSeconds)
			os.Exit(1)
		default:
			os.Exit(1)
		}
	}
}
<commit_msg>Bump provisioning timeout from 30min to 1hr<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"pcfdev/cert"
	"pcfdev/fs"
	"pcfdev/provisioner"
	"strconv"
	"syscall"
	"time"
)

var (
	provisionScriptPath = "/var/pcfdev/run"
	timeoutInSeconds    = "3600"
)

func main() {
	provisionTimeout, err := strconv.Atoi(timeoutInSeconds)
	if err != nil {
		fmt.Printf("Error: %s.", err)
		os.Exit(1)
	}

	p := &provisioner.Provisioner{
		Cert: &cert.Cert{},
		CmdRunner: &provisioner.ConcreteCmdRunner{
			Stdout:  os.Stdout,
			Stderr:  os.Stderr,
			Timeout: time.Duration(provisionTimeout) * time.Second,
		},
		FS: &fs.FS{},
	}

	if err := p.Provision(provisionScriptPath, os.Args[1:]...); err != nil {
		switch err.(type) {
		case *exec.ExitError:
			if exitErr, ok := err.(*exec.ExitError); ok {
				if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
					os.Exit(status.ExitStatus())
				} else {
					os.Exit(1)
				}
			}
		case *provisioner.TimeoutError:
			fmt.Printf("Timed out after %s seconds.\n", timeoutInSeconds)
			os.Exit(1)
		default:
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package gospell

import (
	"testing"
)

func TestCaseStye(t *testing.T) {
	cases := []struct {
		word string
		want WordCase
	}{
		{"lower", AllLower},
		{"UPPER", AllUpper},
		{"Title", Title},
		{"CamelCase", Mixed},
		{"camelCase", Mixed},
	}

	for pos, tt := range cases {
		got := CaseStyle(tt.word)
		if tt.want != got {
			t.Errorf("Case %d %q: want %v got %v", pos, tt.word, tt.want, got)
		}
	}
}
<commit_msg>Typo in function name<commit_after>package gospell

import (
	"testing"
)

func TestCaseStyle(t *testing.T) {
	cases := []struct {
		word string
		want WordCase
	}{
		{"lower", AllLower},
		{"UPPER", AllUpper},
		{"Title", Title},
		{"CamelCase", Mixed},
		{"camelCase", Mixed},
	}

	for pos, tt := range cases {
		got := CaseStyle(tt.word)
		if tt.want != got {
			t.Errorf("Case %d %q: want %v got %v", pos, tt.word, tt.want, got)
		}
	}
}
<|endoftext|>


<commit_before>package chaos

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"sync"
	"time"
)

var renderClient *http.Client

func init() {
	renderClient = &http.Client{
		Timeout: time.Second * 2, // definitely works as timeout in waiting for response, not sure re dial timeout
	}
}

func renderQuery(base, target, from string) response {
	var r response
	url := fmt.Sprintf("%s/render?target=%s&format=json&from=%s", base, target, from)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}
	req.Header.Add("X-Org-Id", "1") // only really needed for MT, not for graphite. oh well...
	//fmt.Println("requesting", url)
	resp, err := renderClient.Do(req)
	if err != nil {
		r.httpErr = err
		return r
	}
	r.code = resp.StatusCode
	traceHeader := resp.Header["Trace-Id"]
	if len(traceHeader) > 0 {
		r.traceID = traceHeader[0]
	}
	r.decodeErr = json.NewDecoder(resp.Body).Decode(&r.r)
	resp.Body.Close()
	return r
}

func retryGraphite(query, from string, times int, validate Validator) (bool, response) {
	return retry(query, from, times, validate, "http://localhost")
}
func retryMT(query, from string, times int, validate Validator) (bool, response) {
	return retry(query, from, times, validate, "http://localhost:6060")
}
func retry(query, from string, times int, validate Validator, base string) (bool, response) {
	var resp response
	for i := 0; i < times; i++ {
		if i > 0 {
			time.Sleep(time.Second)
		}
		resp = renderQuery(base, query, from)
		if validate(resp) {
			return true, resp
		}
	}
	return false, resp
}

type checkResults struct {
	sync.Mutex
	valid []int // each position corresponds to a validator
	// categories of invalid responses
	empty      int
	timeout    int
	other      int
	firstOther *response
}

func newCheckResults(validators []Validator) *checkResults {
	return &checkResults{
		valid: make([]int, len(validators)),
	}
}

func checkWorker(base, query, from string, wg *sync.WaitGroup, cr *checkResults, validators []Validator) {
	r := renderQuery(base, query, from)
	defer wg.Done()
	for i, v := range validators {
		if v(r) {
			cr.Lock()
			cr.valid[i] += 1
			cr.Unlock()
			return
		}
	}
	// if not valid, try to categorize in the common buckets, or fall back to 'other'
	if r.httpErr == nil && r.decodeErr == nil && len(r.r) == 0 {
		cr.Lock()
		cr.empty += 1
		cr.Unlock()
		return
	}
	if r.httpErr != nil {
		if err2, ok := r.httpErr.(*url.Error); ok {
			if err3, ok := err2.Err.(net.Error); ok {
				if err3.Timeout() {
					cr.Lock()
					cr.timeout += 1
					cr.Unlock()
					return
				}
			}
		}
	}
	cr.Lock()
	if cr.other == 0 {
		cr.firstOther = &r
	}
	cr.other += 1
	cr.Unlock()
}

// checkMT queries all provided MT endpoints and provides a summary of all the outcomes;
// meaning the counts of each response matching each validator function, and the number
// of timeouts, and finally all others (non-timeouting invalid responses)
// we recommend for 60s duration to use 6000 requests, e.g. 100 per second
func checkMT(endpoints []int, query, from string, dur time.Duration, reqs int, validators ...Validator) checkResults {
	pre := time.Now()
	ret := newCheckResults(validators)
	period := dur / time.Duration(reqs)
	tick := time.NewTicker(period)
	issued := 0
	wg := &sync.WaitGroup{}
	for range tick.C {
		wg.Add(1)
		base := fmt.Sprintf("http://localhost:%d", endpoints[issued%len(endpoints)])
		go checkWorker(base, query, from, wg, ret, validators)
		issued += 1
		if issued == reqs {
			break
		}
	}
	// note: could take 2 seconds longer than foreseen due to the client timeout, but anything longer may be a problem,
	wg.Wait()
	if time.Since(pre) > (110*dur/100)+2*time.Second {
		panic(fmt.Sprintf("checkMT ran too long for some reason. expected %s. took actually %s. system overloaded?", dur, time.Since(pre)))
	}
	return *ret
}
<commit_msg>fix: be correct about timeouts<commit_after>package chaos

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"sync"
	"time"
)

var renderClient *http.Client

func init() {
	renderClient = &http.Client{
		// definitely works as timeout in waiting for response, not sure re dial timeout
		// note : MT's internal cross-cluster timeouts are 5s, so we have to wait at least as long to classify properly
		Timeout: time.Second * 6,
	}
}

func renderQuery(base, target, from string) response {
	var r response
	url := fmt.Sprintf("%s/render?target=%s&format=json&from=%s", base, target, from)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}
	req.Header.Add("X-Org-Id", "1") // only really needed for MT, not for graphite. oh well...
	//fmt.Println("requesting", url)
	resp, err := renderClient.Do(req)
	if err != nil {
		r.httpErr = err
		return r
	}
	r.code = resp.StatusCode
	traceHeader := resp.Header["Trace-Id"]
	if len(traceHeader) > 0 {
		r.traceID = traceHeader[0]
	}
	r.decodeErr = json.NewDecoder(resp.Body).Decode(&r.r)
	resp.Body.Close()
	return r
}

func retryGraphite(query, from string, times int, validate Validator) (bool, response) {
	return retry(query, from, times, validate, "http://localhost")
}
func retryMT(query, from string, times int, validate Validator) (bool, response) {
	return retry(query, from, times, validate, "http://localhost:6060")
}
func retry(query, from string, times int, validate Validator, base string) (bool, response) {
	var resp response
	for i := 0; i < times; i++ {
		if i > 0 {
			time.Sleep(time.Second)
		}
		resp = renderQuery(base, query, from)
		if validate(resp) {
			return true, resp
		}
	}
	return false, resp
}

type checkResults struct {
	sync.Mutex
	valid []int // each position corresponds to a validator
	// categories of invalid responses
	empty      int
	timeout    int
	other      int
	firstOther *response
}

func newCheckResults(validators []Validator) *checkResults {
	return &checkResults{
		valid: make([]int, len(validators)),
	}
}

func checkWorker(base, query, from string, wg *sync.WaitGroup, cr *checkResults, validators []Validator) {
	r := renderQuery(base, query, from)
	defer wg.Done()
	for i, v := range validators {
		if v(r) {
			cr.Lock()
			cr.valid[i] += 1
			cr.Unlock()
			return
		}
	}
	// if not valid, try to categorize in the common buckets, or fall back to 'other'
	if r.httpErr == nil && r.decodeErr == nil && len(r.r) == 0 {
		cr.Lock()
		cr.empty += 1
		cr.Unlock()
		return
	}
	if r.httpErr != nil {
		if err2, ok := r.httpErr.(*url.Error); ok {
			if err3, ok := err2.Err.(net.Error); ok {
				if err3.Timeout() {
					cr.Lock()
					cr.timeout += 1
					cr.Unlock()
					return
				}
			}
		}
	}
	cr.Lock()
	if cr.other == 0 {
		cr.firstOther = &r
	}
	cr.other += 1
	cr.Unlock()
}

// checkMT queries all provided MT endpoints and provides a summary of all the outcomes;
// meaning the counts of each response matching each validator function, and the number
// of timeouts, and finally all others (non-timeouting invalid responses)
// we recommend for 60s duration to use 6000 requests, e.g. 100 per second
func checkMT(endpoints []int, query, from string, dur time.Duration, reqs int, validators ...Validator) checkResults {
	pre := time.Now()
	ret := newCheckResults(validators)
	period := dur / time.Duration(reqs)
	tick := time.NewTicker(period)
	issued := 0
	wg := &sync.WaitGroup{}
	for range tick.C {
		wg.Add(1)
		base := fmt.Sprintf("http://localhost:%d", endpoints[issued%len(endpoints)])
		go checkWorker(base, query, from, wg, ret, validators)
		issued += 1
		if issued == reqs {
			break
		}
	}
	// note: could take 2 seconds longer than foreseen due to the client timeout, but anything longer may be a problem,
	wg.Wait()
	if time.Since(pre) > (110*dur/100)+2*time.Second {
		panic(fmt.Sprintf("checkMT ran too long for some reason. expected %s. took actually %s. system overloaded?", dur, time.Since(pre)))
	}
	return *ret
}
<|endoftext|>


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

package quota

import (
	"reflect"
	"sync"
	"testing"
	"time"
)

func TestBucket(t *testing.T) {
	now := func() time.Time { return time.Unix(1521221450, 0) }
	m := &manager{now: now}

	cases := map[string]struct {
		priorRequest *Request
		priorResult  *Result
		request      *Request
		want         *Result
	}{
		"First request": {
			&Request{
				Allow: 3,
			},
			nil,
			&Request{
				Allow:  3,
				Weight: 2,
			},
			&Result{
				Allowed:    3,
				Used:       2,
				Exceeded:   0,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
		"Valid request": {
			&Request{
				Allow:  4,
				Weight: 1,
			},
			&Result{
				Used:       2,
				ExpiryTime: now().Unix(),
			},
			&Request{
				Allow:  4,
				Weight: 1,
			},
			&Result{
				Allowed:    4,
				Used:       4,
				Exceeded:   0,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
		"Newly exceeded": {
			&Request{
				Allow:  7,
				Weight: 3,
			},
			&Result{
				Used:       3,
				ExpiryTime: now().Unix(),
			},
			&Request{
				Allow:  7,
				Weight: 2,
			},
			&Result{
				Allowed:    7,
				Used:       7,
				Exceeded:   1,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
		"Previously exceeded": {
			&Request{
				Allow: 3,
			},
			&Result{
				Used:       3,
				Exceeded:   1,
				ExpiryTime: now().Unix(),
			},
			&Request{
				Allow:  3,
				Weight: 1,
			},
			&Result{
				Allowed:    3,
				Used:       3,
				Exceeded:   2,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
	}

	for id, c := range cases {
		t.Logf("** Executing test case '%s' **", id)

		b := &bucket{
			manager:     m,
			request:     c.priorRequest,
			result:      c.priorResult,
			created:     now(),
			lock:        sync.RWMutex{},
			deleteAfter: defaultDeleteAfter,
		}

		res, err := b.apply(c.request)
		if err != nil {
			t.Errorf("should not get error: %v", err)
		}

		if !reflect.DeepEqual(res, c.want) {
			t.Errorf("got: %#v, want: %#v", res, c.want)
		}
	}
}

func TestNeedToDelete(t *testing.T) {
	now := func() time.Time { return time.Unix(1521221450, 0) }
	m := &manager{now: now}

	cases := map[string]struct {
		request *Request
		checked time.Time
		want    bool
	}{
		"empty": {
			request: &Request{},
			want:    true,
		},
		"recently checked": {
			request: &Request{},
			checked: now(),
			want:    false,
		},
		"not recently checked": {
			request: &Request{},
			checked: now().Add(-time.Hour),
			want:    true,
		},
		"has pending requests": {
			request: &Request{Weight: 1},
			checked: now().Add(-time.Hour),
			want:    false,
		},
	}

	for id, c := range cases {
		t.Logf("** Executing test case '%s' **", id)
		b := bucket{
			manager:     m,
			deleteAfter: time.Minute,
			request:     c.request,
			checked:     c.checked,
		}
		if c.want != b.needToDelete() {
			t.Errorf("want: %v got: %v", c.want, b.needToDelete())
		}
	}
}

func TestNeedToSync(t *testing.T) {
	now := func() time.Time { return time.Unix(1521221450, 0) }
	m := &manager{now: now}

	cases := map[string]struct {
		request *Request
		synced  time.Time
		want    bool
	}{
		"empty": {
			request: &Request{},
			want:    true,
		},
		"recently synced": {
			request: &Request{},
			synced:  now(),
			want:    false,
		},
		"not recently synced": {
			request: &Request{},
			synced:  now().Add(-time.Hour),
			want:    true,
		},
		"has pending requests": {
			request: &Request{Weight: 1},
			synced:  now(),
			want:    true,
		},
	}

	for id, c := range cases {
		t.Logf("** Executing test case '%s' **", id)
		b := bucket{
			manager:      m,
			refreshAfter: time.Minute,
			request:      c.request,
			synced:       c.synced,
		}
		if c.want != b.needToSync() {
			t.Errorf("want: %v got: %v", c.want, b.needToDelete())
		}
	}
}

func TestCalcLocalExpiry(t *testing.T) {

	now, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 23:59:59 PST")
	nowStartMinute, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 23:59:00 PST")
	nowStartHour, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 23:00:00 PST")
	nowStartDay, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 00:00:00 PST")
	nowStartMonth, err := time.Parse(time.RFC1123, "Mon, 01 Mar 2006 00:00:00 PST")
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		interval    int64
		quotaLength string
		want        time.Time
	}{
		{1, quotaSecond, now},
		{2, quotaSecond, now.Add(time.Second)},
		{1, quotaMinute, nowStartMinute.Add(time.Minute).Add(-time.Second)},
		{2, quotaMinute, nowStartMinute.Add(2 * time.Minute).Add(-time.Second)},
		{1, quotaHour, nowStartHour.Add(time.Hour).Add(-time.Second)},
		{2, quotaHour, nowStartHour.Add(2 * time.Hour).Add(-time.Second)},
		{1, quotaDay, nowStartDay.AddDate(0, 0, 1).Add(-time.Second)},
		{2, quotaDay, nowStartDay.AddDate(0, 0, 2).Add(-time.Second)},
		{1, quotaMonth, nowStartMonth.AddDate(0, 1, 0).Add(-time.Second)},
		{2, quotaMonth, nowStartMonth.AddDate(0, 2, 0).Add(-time.Second)},
	}

	for _, tst := range tests {
		got := calcLocalExpiry(now, tst.interval, tst.quotaLength)
		if got != tst.want {
			t.Errorf("%d %s got: %v, want: %v", tst.interval, tst.quotaLength, got, tst.want)
		}
	}
}
<commit_msg>check seconds<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package quota

import (
	"reflect"
	"sync"
	"testing"
	"time"
)

func TestBucket(t *testing.T) {
	now := func() time.Time { return time.Unix(1521221450, 0) }
	m := &manager{now: now}

	cases := map[string]struct {
		priorRequest *Request
		priorResult  *Result
		request      *Request
		want         *Result
	}{
		"First request": {
			&Request{
				Allow: 3,
			},
			nil,
			&Request{
				Allow:  3,
				Weight: 2,
			},
			&Result{
				Allowed:    3,
				Used:       2,
				Exceeded:   0,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
		"Valid request": {
			&Request{
				Allow:  4,
				Weight: 1,
			},
			&Result{
				Used:       2,
				ExpiryTime: now().Unix(),
			},
			&Request{
				Allow:  4,
				Weight: 1,
			},
			&Result{
				Allowed:    4,
				Used:       4,
				Exceeded:   0,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
		"Newly exceeded": {
			&Request{
				Allow:  7,
				Weight: 3,
			},
			&Result{
				Used:       3,
				ExpiryTime: now().Unix(),
			},
			&Request{
				Allow:  7,
				Weight: 2,
			},
			&Result{
				Allowed:    7,
				Used:       7,
				Exceeded:   1,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
		"Previously exceeded": {
			&Request{
				Allow: 3,
			},
			&Result{
				Used:       3,
				Exceeded:   1,
				ExpiryTime: now().Unix(),
			},
			&Request{
				Allow:  3,
				Weight: 1,
			},
			&Result{
				Allowed:    3,
				Used:       3,
				Exceeded:   2,
				ExpiryTime: now().Unix(),
				Timestamp:  now().Unix(),
			},
		},
	}

	for id, c := range cases {
		t.Logf("** Executing test case '%s' **", id)

		b := &bucket{
			manager:     m,
			request:     c.priorRequest,
			result:      c.priorResult,
			created:     now(),
			lock:        sync.RWMutex{},
			deleteAfter: defaultDeleteAfter,
		}

		res, err := b.apply(c.request)
		if err != nil {
			t.Errorf("should not get error: %v", err)
		}

		if !reflect.DeepEqual(res, c.want) {
			t.Errorf("got: %#v, want: %#v", res, c.want)
		}
	}
}

func TestNeedToDelete(t *testing.T) {
	now := func() time.Time { return time.Unix(1521221450, 0) }
	m := &manager{now: now}

	cases := map[string]struct {
		request *Request
		checked time.Time
		want    bool
	}{
		"empty": {
			request: &Request{},
			want:    true,
		},
		"recently checked": {
			request: &Request{},
			checked: now(),
			want:    false,
		},
		"not recently checked": {
			request: &Request{},
			checked: now().Add(-time.Hour),
			want:    true,
		},
		"has pending requests": {
			request: &Request{Weight: 1},
			checked: now().Add(-time.Hour),
			want:    false,
		},
	}

	for id, c := range cases {
		t.Logf("** Executing test case '%s' **", id)
		b := bucket{
			manager:     m,
			deleteAfter: time.Minute,
			request:     c.request,
			checked:     c.checked,
		}
		if c.want != b.needToDelete() {
			t.Errorf("want: %v got: %v", c.want, b.needToDelete())
		}
	}
}

func TestNeedToSync(t *testing.T) {
	now := func() time.Time { return time.Unix(1521221450, 0) }
	m := &manager{now: now}

	cases := map[string]struct {
		request *Request
		synced  time.Time
		want    bool
	}{
		"empty": {
			request: &Request{},
			want:    true,
		},
		"recently synced": {
			request: &Request{},
			synced:  now(),
			want:    false,
		},
		"not recently synced": {
			request: &Request{},
			synced:  now().Add(-time.Hour),
			want:    true,
		},
		"has pending requests": {
			request: &Request{Weight: 1},
			synced:  now(),
			want:    true,
		},
	}

	for id, c := range cases {
		t.Logf("** Executing test case '%s' **", id)
		b := bucket{
			manager:      m,
			refreshAfter: time.Minute,
			request:      c.request,
			synced:       c.synced,
		}
		if c.want != b.needToSync() {
			t.Errorf("want: %v got: %v", c.want, b.needToDelete())
		}
	}
}

func TestCalcLocalExpiry(t *testing.T) {

	now, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 23:59:59 PST")
	nowStartMinute, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 23:59:00 PST")
	nowStartHour, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 23:00:00 PST")
	nowStartDay, _ := time.Parse(time.RFC1123, "Mon, 31 Mar 2006 00:00:00 PST")
	nowStartMonth, err := time.Parse(time.RFC1123, "Mon, 01 Mar 2006 00:00:00 PST")
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		interval    int64
		quotaLength string
		want        time.Time
	}{
		{1, quotaSecond, now},
		{2, quotaSecond, now.Add(time.Second)},
		{1, quotaMinute, nowStartMinute.Add(time.Minute).Add(-time.Second)},
		{2, quotaMinute, nowStartMinute.Add(2 * time.Minute).Add(-time.Second)},
		{1, quotaHour, nowStartHour.Add(time.Hour).Add(-time.Second)},
		{2, quotaHour, nowStartHour.Add(2 * time.Hour).Add(-time.Second)},
		{1, quotaDay, nowStartDay.AddDate(0, 0, 1).Add(-time.Second)},
		{2, quotaDay, nowStartDay.AddDate(0, 0, 2).Add(-time.Second)},
		{1, quotaMonth, nowStartMonth.AddDate(0, 1, 0).Add(-time.Second)},
		{2, quotaMonth, nowStartMonth.AddDate(0, 2, 0).Add(-time.Second)},
	}

	for _, tst := range tests {
		got := calcLocalExpiry(now, tst.interval, tst.quotaLength)
		if got.Unix() != tst.want.Unix() {
			t.Errorf("%d %s got: %v (%d), want: %v (%d)", tst.interval, tst.quotaLength, got, got.Unix(), tst.want, tst.want.Unix())
		}
	}
}
<|endoftext|>


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

package jwt_test

import (
	"testing"

	"github.com/google/tink/go/jwt"
	"github.com/google/tink/go/keyset"

	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

type templateTestCase struct {
	tag     string
	temlate *tinkpb.KeyTemplate
}

func TestJWTComputeVerifyMAC(t *testing.T) {
	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
	if err != nil {
		t.Errorf("NewRawJWT() err = %v, want nil", err)
	}
	for _, tc := range []templateTestCase{
		{tag: "JWT_HS256", temlate: jwt.HS256Template()},
		{tag: "JWT_HS384", temlate: jwt.HS384Template()},
		{tag: "JWT_HS512", temlate: jwt.HS512Template()},
		{tag: "JWT_HS256_RAW", temlate: jwt.RawHS256Template()},
		{tag: "JWT_HS384_RAW", temlate: jwt.RawHS384Template()},
		{tag: "JWT_HS512_RAW", temlate: jwt.RawHS512Template()},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			handle, err := keyset.NewHandle(tc.temlate)
			if err != nil {
				t.Errorf("keyset.NewHandle() err = %v, want nil", err)
			}
			m, err := jwt.NewMAC(handle)
			if err != nil {
				t.Errorf("New() err = %v, want nil", err)
			}
			compact, err := m.ComputeMACAndEncode(rawJWT)
			if err != nil {
				t.Errorf("m.ComputeMACAndEncode() err = %v, want nil", err)
			}
			verifier, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true})
			if err != nil {
				t.Errorf("NewValidator() err = %v, want nil", err)
			}
			if _, err := m.VerifyMACAndDecode(compact, verifier); err != nil {
				t.Errorf("m.VerifyMACAndDecode() err = %v, want nil", err)
			}
		})
	}
}

func TestJWTSignVerifyECDSA(t *testing.T) {
	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
	if err != nil {
		t.Errorf("jwt.NewRawJWT() err = %v, want nil", err)
	}
	for _, tc := range []templateTestCase{
		{tag: "JWT_ES256", temlate: jwt.ES256Template()},
		{tag: "JWT_ES384", temlate: jwt.ES384Template()},
		{tag: "JWT_ES512", temlate: jwt.ES512Template()},
		{tag: "JWT_ES256_RAW", temlate: jwt.RawES256Template()},
		{tag: "JWT_ES384_RAW", temlate: jwt.RawES384Template()},
		{tag: "JWT_ES512_RAW", temlate: jwt.RawES512Template()},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			kh, err := keyset.NewHandle(tc.temlate)
			if err != nil {
				t.Errorf("keyset.NewHandle() err = %v, want nil", err)
			}
			signer, err := jwt.NewSigner(kh)
			if err != nil {
				t.Errorf("jwt.NewSigner() err = %v, want nil", err)
			}
			compact, err := signer.SignAndEncode(rawJWT)
			if err != nil {
				t.Errorf("signer.SignAndEncode() err = %v, want nil", err)
			}
			pubkh, err := kh.Public()
			if err != nil {
				t.Fatalf("key handle Public() err = %v, want nil", err)
			}
			verifier, err := jwt.NewVerifier(pubkh)
			if err != nil {
				t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
			}
			validator, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true})
			if err != nil {
				t.Fatalf("jwt.NewJWTValidator() err = %v, want nil", err)
			}
			if _, err := verifier.VerifyAndDecode(compact, validator); err != nil {
				t.Errorf("verifier.VerifyAndDecode() err = %v, want nil", err)
			}
		})
	}
}
<commit_msg>Fix spelling in JWT key templates test.<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package jwt_test

import (
	"testing"

	"github.com/google/tink/go/jwt"
	"github.com/google/tink/go/keyset"

	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

type templateTestCase struct {
	tag      string
	template *tinkpb.KeyTemplate
}

func TestJWTComputeVerifyMAC(t *testing.T) {
	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
	if err != nil {
		t.Errorf("NewRawJWT() err = %v, want nil", err)
	}
	for _, tc := range []templateTestCase{
		{tag: "JWT_HS256", template: jwt.HS256Template()},
		{tag: "JWT_HS384", template: jwt.HS384Template()},
		{tag: "JWT_HS512", template: jwt.HS512Template()},
		{tag: "JWT_HS256_RAW", template: jwt.RawHS256Template()},
		{tag: "JWT_HS384_RAW", template: jwt.RawHS384Template()},
		{tag: "JWT_HS512_RAW", template: jwt.RawHS512Template()},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			handle, err := keyset.NewHandle(tc.template)
			if err != nil {
				t.Errorf("keyset.NewHandle() err = %v, want nil", err)
			}
			m, err := jwt.NewMAC(handle)
			if err != nil {
				t.Errorf("New() err = %v, want nil", err)
			}
			compact, err := m.ComputeMACAndEncode(rawJWT)
			if err != nil {
				t.Errorf("m.ComputeMACAndEncode() err = %v, want nil", err)
			}
			verifier, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true})
			if err != nil {
				t.Errorf("NewValidator() err = %v, want nil", err)
			}
			if _, err := m.VerifyMACAndDecode(compact, verifier); err != nil {
				t.Errorf("m.VerifyMACAndDecode() err = %v, want nil", err)
			}
		})
	}
}

func TestJWTSignVerifyECDSA(t *testing.T) {
	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
	if err != nil {
		t.Errorf("jwt.NewRawJWT() err = %v, want nil", err)
	}
	for _, tc := range []templateTestCase{
		{tag: "JWT_ES256", template: jwt.ES256Template()},
		{tag: "JWT_ES384", template: jwt.ES384Template()},
		{tag: "JWT_ES512", template: jwt.ES512Template()},
		{tag: "JWT_ES256_RAW", template: jwt.RawES256Template()},
		{tag: "JWT_ES384_RAW", template: jwt.RawES384Template()},
		{tag: "JWT_ES512_RAW", template: jwt.RawES512Template()},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			kh, err := keyset.NewHandle(tc.template)
			if err != nil {
				t.Errorf("keyset.NewHandle() err = %v, want nil", err)
			}
			signer, err := jwt.NewSigner(kh)
			if err != nil {
				t.Errorf("jwt.NewSigner() err = %v, want nil", err)
			}
			compact, err := signer.SignAndEncode(rawJWT)
			if err != nil {
				t.Errorf("signer.SignAndEncode() err = %v, want nil", err)
			}
			pubkh, err := kh.Public()
			if err != nil {
				t.Fatalf("key handle Public() err = %v, want nil", err)
			}
			verifier, err := jwt.NewVerifier(pubkh)
			if err != nil {
				t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
			}
			validator, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true})
			if err != nil {
				t.Fatalf("jwt.NewJWTValidator() err = %v, want nil", err)
			}
			if _, err := verifier.VerifyAndDecode(compact, validator); err != nil {
				t.Errorf("verifier.VerifyAndDecode() err = %v, want nil", err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package kite

import (
	"encoding/json"
	"github.com/streadway/amqp"
	"koding/db/mongodb/modelhelper"
	"koding/tools/amqputil"
	"koding/tools/dnode"
	"koding/tools/lifecycle"
	"koding/tools/log"
	"koding/virt"
	"os"
	"strconv"
	"strings"
	"time"
)

type Kite struct {
	Name              string
	Handlers          map[string]Handler
	ServiceUniqueName string
	LoadBalancer      func(correlationName string, username string, deadService string) string
}

type Handler struct {
	Concurrent bool
	Callback   func(args *dnode.Partial, channel *Channel) (interface{}, error)
}

type Channel struct {
	Username        string
	RoutingKey      string
	CorrelationName string
	Alive           bool
	KiteData        interface{}
	onDisconnect    []func()
}

// Control is used by controlChannel to shutdown shutdown VM's associated with
// their hostnameAlias.
type Control struct {
	HostnameAlias string
}

func New(name string, onePerHost bool) *Kite {
	hostname, _ := os.Hostname()
	serviceUniqueName := "kite-" + name + "-" + strconv.Itoa(os.Getpid()) + "|" + strings.Replace(hostname, ".", "_", -1)
	if onePerHost {
		serviceUniqueName = "kite-" + name + "|" + strings.Replace(hostname, ".", "_", -1)
	}

	return &Kite{
		Name:              name,
		Handlers:          make(map[string]Handler),
		ServiceUniqueName: serviceUniqueName,
	}
}

func (k *Kite) Handle(method string, concurrent bool, callback func(args *dnode.Partial, channel *Channel) (interface{}, error)) {
	k.Handlers[method] = Handler{concurrent, callback}
}

func (k *Kite) Run() {
	consumeConn := amqputil.CreateConnection("kite-" + k.Name)
	defer consumeConn.Close()

	publishConn := amqputil.CreateConnection("kite-" + k.Name)
	defer publishConn.Close()

	publishChannel := amqputil.CreateChannel(publishConn)
	defer publishChannel.Close()

	consumeChannel := amqputil.CreateChannel(consumeConn)

	amqputil.JoinPresenceExchange(consumeChannel, "services-presence", "kite", "kite-"+k.Name, k.ServiceUniqueName, k.LoadBalancer != nil)

	stream := amqputil.DeclareBindConsumeQueue(consumeChannel, "fanout", k.ServiceUniqueName, "", true)
	go k.startRouting(stream, publishChannel)

	// listen to an external control channel
	controlChannel := amqputil.CreateChannel(consumeConn)
	defer controlChannel.Close()

	controlStream := amqputil.DeclareBindConsumeQueue(controlChannel, "fanout", "control", "", true)
	controlRouting(controlStream) // blocking
}

func controlRouting(stream <-chan amqp.Delivery) {
	for msg := range stream {
		switch msg.RoutingKey {
		// those are temporary here
		// and should not be here
		case "control.suspendVM":
			var control Control
			err := json.Unmarshal(msg.Body, &control)
			if err != nil || control.HostnameAlias == "" {
				log.Err("Invalid control message.", string(msg.Body))
				continue
			}

			v, err := modelhelper.GetVM(control.HostnameAlias)
			if err != nil {
				log.Err("vm not found '%s'", control.HostnameAlias)
				continue
			}

			vm := virt.VM(*v)
			if err := vm.Stop(); err != nil {
				log.Err("could not stop vm '%s'", control.HostnameAlias)
				continue
			}
		}
	}
}

func (k *Kite) startRouting(stream <-chan amqp.Delivery, publishChannel *amqp.Channel) {
	changeClientsGauge := lifecycle.CreateClientsGauge()
	log.RunGaugesLoop()

	timeoutChannel := make(chan string)

	routeMap := make(map[string](chan<- []byte))
	defer func() {
		for _, route := range routeMap {
			close(route)
		}
	}()

	for {
		select {
		case message, ok := <-stream:
			if !ok {
				return
			}

			switch message.RoutingKey {
			case "auth.join":
				log.Debug("auth.join", message)

				var channel Channel
				err := json.Unmarshal(message.Body, &channel)
				if err != nil || channel.Username == "" || channel.RoutingKey == "" {
					log.Err("Invalid auth.join message.", message.Body)
					continue
				}

				if _, found := routeMap[channel.RoutingKey]; found {
					// log.Warn("Duplicate auth.join for same routing key.")
					continue
				}
				route := make(chan []byte, 1024)
				routeMap[channel.RoutingKey] = route

				go func() {
					defer log.RecoverAndLog()
					defer channel.Close()

					changeClientsGauge(1)
					log.Debug("Client connected: " + channel.Username)
					defer func() {
						changeClientsGauge(-1)
						log.Debug("Client disconnected: " + channel.Username)
					}()

					d := dnode.New()
					defer d.Close()
					d.OnRootMethod = func(method string, args *dnode.Partial) {
						defer log.RecoverAndLog()

						if method == "ping" {
							d.Send("pong")
							return
						}
						if method == "pong" {
							return
						}

						var partials []*dnode.Partial
						err := args.Unmarshal(&partials)
						if err != nil {
							panic(err)
						}

						var options struct {
							WithArgs *dnode.Partial
						}
						err = partials[0].Unmarshal(&options)
						if err != nil {
							panic(err)
						}
						var resultCallback dnode.Callback
						err = partials[1].Unmarshal(&resultCallback)
						if err != nil {
							panic(err)
						}

						handler, found := k.Handlers[method]
						if !found {
							resultCallback(CreateErrorObject(&UnknownMethodError{Method: method}), nil)
							return
						}

						execHandler := func() {
							defer func() {
								if err := recover(); err != nil {
									log.LogError(err, 1, channel.Username, channel.CorrelationName)
									time.Sleep(time.Second) // penalty for avoiding that the client rapidly sends the request again on error
									resultCallback(CreateErrorObject(&InternalKiteError{}), nil)
								}
							}()

							result, err := handler.Callback(options.WithArgs, &channel)
							if b, ok := result.([]byte); ok {
								result = string(b)
							}

							if err != nil {
								if _, ok := err.(*WrongChannelError); ok {
									if err := publishChannel.Publish("broker", channel.RoutingKey+".cycleChannel", false, false, amqp.Publishing{Body: []byte("null")}); err != nil {
										log.LogError(err, 0)
									}
									return
								}

								resultCallback(CreateErrorObject(err), result)
								return
							}

							resultCallback(nil, result)
						}

						if handler.Concurrent {
							go execHandler()
							return
						}

						execHandler()
					}

					// Publish dnode messages to the broker.
					go func() {
						defer log.RecoverAndLog()
						for data := range d.SendChan {
							log.Debug("Write", channel.RoutingKey, data)
							if err := publishChannel.Publish("broker", channel.RoutingKey, false, false, amqp.Publishing{Body: data}); err != nil {
								log.LogError(err, 0)
							}
						}
					}()

					d.Send("ready", k.ServiceUniqueName)

					// Process dnode messages coming from route.
					pingAlreadySent := false
					for {
						select {
						case message, ok := <-route:
							if !ok {
								return
							}
							func() {
								defer func() {
									if err := recover(); err != nil {
										log.LogError(err, 1, channel.Username, channel.CorrelationName, message)
									}
								}()
								log.Debug("Read", channel.RoutingKey, message)
								d.ProcessMessage(message)
							}()
							pingAlreadySent = false
						case <-time.After(5 * time.Minute):
							if pingAlreadySent {
								timeoutChannel <- channel.RoutingKey
								break
							}
							d.Send("ping")
							pingAlreadySent = true
						}
					}
				}()

			case "auth.leave":
				// ignored, session end is handled by ping/pong timeout

			case "auth.who":
				var client struct {
					Username           string `json:"username"`
					RoutingKey         string `json:"routingKey"`
					CorrelationName    string `json:"correlationName"`
					DeadService        string `json:"deadService"`
					ReplyExchange      string `json:"replyExchange"`
					ServiceGenericName string `json:"serviceGenericName"`
					ServiceUniqueName  string `json:"serviceUniqueName"` // used only for response
				}
				err := json.Unmarshal(message.Body, &client)
				if err != nil || client.Username == "" || client.RoutingKey == "" || client.CorrelationName == "" {
					log.Err("Invalid auth.who message.", message.Body)
					continue
				}
				if k.LoadBalancer == nil {
					log.Err("Got auth.who without having a load balancer.", message.Body)
					continue
				}

				client.ServiceUniqueName = k.LoadBalancer(client.CorrelationName, client.Username, client.DeadService)
				response, err := json.Marshal(client)
				if err != nil {
					log.LogError(err, 0)
					continue
				}
				if client.ReplyExchange == "" { // backwards-compatibility
					client.ReplyExchange = "auth"
				}
				if err := publishChannel.Publish(client.ReplyExchange, "kite.who", false, false, amqp.Publishing{Body: response}); err != nil {
					log.LogError(err, 0)
				}

			default:
				route, found := routeMap[message.RoutingKey]
				if found {
					select {
					case route <- message.Body:
						// successful
					default:
						close(route)
						delete(routeMap, message.RoutingKey)
						log.Warn("Dropped client because of message buffer overflow.")
					}
				}
			}

		case routingKey := <-timeoutChannel:
			route, found := routeMap[routingKey]
			if found {
				close(route)
				delete(routeMap, routingKey)
			}
		}
	}

}

func (channel *Channel) OnDisconnect(f func()) {
	channel.onDisconnect = append(channel.onDisconnect, f)
}

func (channel *Channel) Close() {
	channel.Alive = false
	for _, f := range channel.onDisconnect {
		f()
	}
	channel.onDisconnect = nil
}
<commit_msg>kite: remove unused function closure<commit_after>package kite

import (
	"encoding/json"
	"koding/db/mongodb/modelhelper"
	"koding/tools/amqputil"
	"koding/tools/dnode"
	"koding/tools/lifecycle"
	"koding/tools/log"
	"koding/virt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

type Kite struct {
	Name              string
	Handlers          map[string]Handler
	ServiceUniqueName string
	LoadBalancer      func(correlationName string, username string, deadService string) string
}

type Handler struct {
	Concurrent bool
	Callback   func(args *dnode.Partial, channel *Channel) (interface{}, error)
}

type Channel struct {
	Username        string
	RoutingKey      string
	CorrelationName string
	Alive           bool
	KiteData        interface{}
	onDisconnect    []func()
}

// Control is used by controlChannel to shutdown shutdown VM's associated with
// their hostnameAlias.
type Control struct {
	HostnameAlias string
}

func New(name string, onePerHost bool) *Kite {
	hostname, _ := os.Hostname()
	serviceUniqueName := "kite-" + name + "-" + strconv.Itoa(os.Getpid()) + "|" + strings.Replace(hostname, ".", "_", -1)
	if onePerHost {
		serviceUniqueName = "kite-" + name + "|" + strings.Replace(hostname, ".", "_", -1)
	}

	return &Kite{
		Name:              name,
		Handlers:          make(map[string]Handler),
		ServiceUniqueName: serviceUniqueName,
	}
}

func (k *Kite) Handle(method string, concurrent bool, callback func(args *dnode.Partial, channel *Channel) (interface{}, error)) {
	k.Handlers[method] = Handler{concurrent, callback}
}

func (k *Kite) Run() {
	consumeConn := amqputil.CreateConnection("kite-" + k.Name)
	defer consumeConn.Close()

	publishConn := amqputil.CreateConnection("kite-" + k.Name)
	defer publishConn.Close()

	publishChannel := amqputil.CreateChannel(publishConn)
	defer publishChannel.Close()

	consumeChannel := amqputil.CreateChannel(consumeConn)

	amqputil.JoinPresenceExchange(consumeChannel, "services-presence", "kite", "kite-"+k.Name, k.ServiceUniqueName, k.LoadBalancer != nil)

	stream := amqputil.DeclareBindConsumeQueue(consumeChannel, "fanout", k.ServiceUniqueName, "", true)
	go k.startRouting(stream, publishChannel)

	// listen to an external control channel
	controlChannel := amqputil.CreateChannel(consumeConn)
	defer controlChannel.Close()

	controlStream := amqputil.DeclareBindConsumeQueue(controlChannel, "fanout", "control", "", true)
	controlRouting(controlStream) // blocking
}

func controlRouting(stream <-chan amqp.Delivery) {
	for msg := range stream {
		switch msg.RoutingKey {
		// those are temporary here
		// and should not be here
		case "control.suspendVM":
			var control Control
			err := json.Unmarshal(msg.Body, &control)
			if err != nil || control.HostnameAlias == "" {
				log.Err("Invalid control message.", string(msg.Body))
				continue
			}

			v, err := modelhelper.GetVM(control.HostnameAlias)
			if err != nil {
				log.Err("vm not found '%s'", control.HostnameAlias)
				continue
			}

			vm := virt.VM(*v)
			if err := vm.Stop(); err != nil {
				log.Err("could not stop vm '%s'", control.HostnameAlias)
				continue
			}
		}
	}
}

func (k *Kite) startRouting(stream <-chan amqp.Delivery, publishChannel *amqp.Channel) {
	changeClientsGauge := lifecycle.CreateClientsGauge()
	log.RunGaugesLoop()

	timeoutChannel := make(chan string)

	routeMap := make(map[string](chan<- []byte))
	defer func() {
		for _, route := range routeMap {
			close(route)
		}
	}()

	for {
		select {
		case message, ok := <-stream:
			if !ok {
				return
			}

			switch message.RoutingKey {
			case "auth.join":
				log.Debug("auth.join", message)

				var channel Channel
				err := json.Unmarshal(message.Body, &channel)
				if err != nil || channel.Username == "" || channel.RoutingKey == "" {
					log.Err("Invalid auth.join message.", message.Body)
					continue
				}

				if _, found := routeMap[channel.RoutingKey]; found {
					// log.Warn("Duplicate auth.join for same routing key.")
					continue
				}
				route := make(chan []byte, 1024)
				routeMap[channel.RoutingKey] = route

				go func() {
					defer log.RecoverAndLog()
					defer channel.Close()

					changeClientsGauge(1)
					log.Debug("Client connected: " + channel.Username)
					defer func() {
						changeClientsGauge(-1)
						log.Debug("Client disconnected: " + channel.Username)
					}()

					d := dnode.New()
					defer d.Close()
					d.OnRootMethod = func(method string, args *dnode.Partial) {
						defer log.RecoverAndLog()

						if method == "ping" {
							d.Send("pong")
							return
						}
						if method == "pong" {
							return
						}

						var partials []*dnode.Partial
						err := args.Unmarshal(&partials)
						if err != nil {
							panic(err)
						}

						var options struct {
							WithArgs *dnode.Partial
						}
						err = partials[0].Unmarshal(&options)
						if err != nil {
							panic(err)
						}
						var resultCallback dnode.Callback
						err = partials[1].Unmarshal(&resultCallback)
						if err != nil {
							panic(err)
						}

						handler, found := k.Handlers[method]
						if !found {
							resultCallback(CreateErrorObject(&UnknownMethodError{Method: method}), nil)
							return
						}

						execHandler := func() {
							defer func() {
								if err := recover(); err != nil {
									log.LogError(err, 1, channel.Username, channel.CorrelationName)
									time.Sleep(time.Second) // penalty for avoiding that the client rapidly sends the request again on error
									resultCallback(CreateErrorObject(&InternalKiteError{}), nil)
								}
							}()

							result, err := handler.Callback(options.WithArgs, &channel)
							if b, ok := result.([]byte); ok {
								result = string(b)
							}

							if err != nil {
								if _, ok := err.(*WrongChannelError); ok {
									if err := publishChannel.Publish("broker", channel.RoutingKey+".cycleChannel", false, false, amqp.Publishing{Body: []byte("null")}); err != nil {
										log.LogError(err, 0)
									}
									return
								}

								resultCallback(CreateErrorObject(err), result)
								return
							}

							resultCallback(nil, result)
						}

						if handler.Concurrent {
							go execHandler()
							return
						}

						execHandler()
					}

					// Publish dnode messages to the broker.
					go func() {
						defer log.RecoverAndLog()
						for data := range d.SendChan {
							log.Debug("Write", channel.RoutingKey, data)
							if err := publishChannel.Publish("broker", channel.RoutingKey, false, false, amqp.Publishing{Body: data}); err != nil {
								log.LogError(err, 0)
							}
						}
					}()

					d.Send("ready", k.ServiceUniqueName)

					// Process dnode messages coming from route.
					pingAlreadySent := false
					for {
						select {
						case message, ok := <-route:
							if !ok {
								return
							}

							defer func() {
								if err := recover(); err != nil {
									log.LogError(err, 1, channel.Username, channel.CorrelationName, message)
								}
							}()

							log.Debug("Read", channel.RoutingKey, message)
							d.ProcessMessage(message)
							pingAlreadySent = false
						case <-time.After(5 * time.Minute):
							if pingAlreadySent {
								timeoutChannel <- channel.RoutingKey
								break
							}
							d.Send("ping")
							pingAlreadySent = true
						}
					}
				}()

			case "auth.leave":
				// ignored, session end is handled by ping/pong timeout

			case "auth.who":
				var client struct {
					Username           string `json:"username"`
					RoutingKey         string `json:"routingKey"`
					CorrelationName    string `json:"correlationName"`
					DeadService        string `json:"deadService"`
					ReplyExchange      string `json:"replyExchange"`
					ServiceGenericName string `json:"serviceGenericName"`
					ServiceUniqueName  string `json:"serviceUniqueName"` // used only for response
				}
				err := json.Unmarshal(message.Body, &client)
				if err != nil || client.Username == "" || client.RoutingKey == "" || client.CorrelationName == "" {
					log.Err("Invalid auth.who message.", message.Body)
					continue
				}
				if k.LoadBalancer == nil {
					log.Err("Got auth.who without having a load balancer.", message.Body)
					continue
				}

				client.ServiceUniqueName = k.LoadBalancer(client.CorrelationName, client.Username, client.DeadService)
				response, err := json.Marshal(client)
				if err != nil {
					log.LogError(err, 0)
					continue
				}
				if client.ReplyExchange == "" { // backwards-compatibility
					client.ReplyExchange = "auth"
				}
				if err := publishChannel.Publish(client.ReplyExchange, "kite.who", false, false, amqp.Publishing{Body: response}); err != nil {
					log.LogError(err, 0)
				}

			default:
				route, found := routeMap[message.RoutingKey]
				if found {
					select {
					case route <- message.Body:
						// successful
					default:
						close(route)
						delete(routeMap, message.RoutingKey)
						log.Warn("Dropped client because of message buffer overflow.")
					}
				}
			}

		case routingKey := <-timeoutChannel:
			route, found := routeMap[routingKey]
			if found {
				close(route)
				delete(routeMap, routingKey)
			}
		}
	}

}

func (channel *Channel) OnDisconnect(f func()) {
	channel.onDisconnect = append(channel.onDisconnect, f)
}

func (channel *Channel) Close() {
	channel.Alive = false
	for _, f := range channel.onDisconnect {
		f()
	}
	channel.onDisconnect = nil
}
<|endoftext|>