<commit_before>package tcx

import (
	"github.com/philhofer/vec"
)

type TrackSpline struct {
	lat  *vec.CubicSplineInterpolation
	long *vec.CubicSplineInterpolation
	spd  *vec.CubicSplineInterpolation
	alt  *vec.CubicSplineInterpolation
}

func (t *TrackSpline) Lat(dist float64) float64 {
	return t.lat.F(dist)
}

func (t *TrackSpline) Long(dist float64) float64 {
	return t.long.F(dist)
}

func (t *TrackSpline) Speed(dist float64) float64 {
	return t.spd.F(dist)
}

func (t *TrackSpline) Alt(dist float64) float64 {
	return t.alt.F(dist)
}

func Spline(trk Track) *TrackSpline {
	Npts := len(trk.Pt)
	lats := make([]float64, Npts)
	longs := make([]float64, Npts)
	spds := make([]float64, Npts)
	alts := make([]float64, Npts)
	dists := make([]float64, Npts)
	for i := 0; i < Npts; i++ {
		lats[i] = trk.Pt[i].Lat
		longs[i] = trk.Pt[i].Long
		spds[i] = trk.Pt[i].Speed
		alts[i] = trk.Pt[i].Alt
		dists[i] = trk.Pt[i].Dist
	}
	latsplin := vec.CubicSpline(vec.MakeBiVariateData(dists, lats))
	longssplin := vec.CubicSpline(vec.MakeBiVariateData(dists, longs))
	spdssplin := vec.CubicSpline(vec.MakeBiVariateData(dists, spds))
	altssplin := vec.CubicSpline(vec.MakeBiVariateData(dists, alts))
	return &TrackSpline{lat: latsplin, long: longssplin, spd: spdssplin, alt: altssplin}
}
<commit_msg>Added more ops.<commit_after>package tcx

import (
	"github.com/philhofer/vec"
	"math"
	"time"
)

type TrackSpline struct {
	lat  *vec.CubicSplineInterpolation
	long *vec.CubicSplineInterpolation
	spd  *vec.CubicSplineInterpolation
	alt  *vec.CubicSplineInterpolation
}

func (t *TrackSpline) Lat(dist float64) float64 {
	return t.lat.F(dist)
}

func (t *TrackSpline) Long(dist float64) float64 {
	return t.long.F(dist)
}

func (t *TrackSpline) Speed(dist float64) float64 {
	return t.spd.F(dist)
}

func (t *TrackSpline) Alt(dist float64) float64 {
	return t.alt.F(dist)
}

type LapZeroDistError struct{}

func (l *LapZeroDistError) Error() string {
	return "Lap Distance Cannot Be Zero."
}

func (lap Lap) MatchTime(sec float64) error {
	isec := int(math.Floor(sec))
	ldist := lap.Dist
	if ldist == 0 {
		return new(LapZeroDistError)
	}
	maxs := lap.MaxSpeed
	startTime := lap.Trk.Pt[0].Time
	startDist := lap.Trk.Pt[0].Dist
	vfactor := lap.TotalTime / sec
	trkspl := Spline(lap.Trk)
	newtrk := make([]Trackpoint, isec)
	onesec, err := time.ParseDuration("1.0s")
	if err != nil {
		panic(err)
	}

	for i := 0; i < isec; i++ {
		thisSpeed := trkspl.Speed(startDist) * vfactor
		if thisSpeed > maxs {
			lap.MaxSpeed = thisSpeed
		}
		newtrk[i] = Trackpoint{
			Time:  startTime,
			Lat:   trkspl.Lat(startDist),
			Long:  trkspl.Long(startDist),
			Speed: thisSpeed,
			Alt:   trkspl.Alt(startDist),
		}
		startDist += thisSpeed
		startTime.Add(onesec)
	}
	lap.TotalTime = float64(isec)
	lap.Trk = Track{Pt: newtrk}
	return nil
}

func Spline(trk Track) *TrackSpline {
	Npts := len(trk.Pt)
	lats := make([]float64, Npts)
	longs := make([]float64, Npts)
	spds := make([]float64, Npts)
	alts := make([]float64, Npts)
	dists := make([]float64, Npts)
	for i := 0; i < Npts; i++ {
		lats[i] = trk.Pt[i].Lat
		longs[i] = trk.Pt[i].Long
		spds[i] = trk.Pt[i].Speed
		alts[i] = trk.Pt[i].Alt
		dists[i] = trk.Pt[i].Dist
	}
	latsplin := vec.CubicSpline(vec.MakeBiVariateData(dists, lats))
	longssplin := vec.CubicSpline(vec.MakeBiVariateData(dists, longs))
	spdssplin := vec.CubicSpline(vec.MakeBiVariateData(dists, spds))
	altssplin := vec.CubicSpline(vec.MakeBiVariateData(dists, alts))
	return &TrackSpline{lat: latsplin, long: longssplin, spd: spdssplin, alt: altssplin}
}
<|endoftext|>


<commit_before>// Package structinfo contains tools to inspect structs.

package structinfo

import (
	"reflect"
	"sync"
)

type jsonFieldMap struct {
	lock   sync.Mutex
	fields map[string]string
}

var type2jfm = map[reflect.Type]jsonFieldMap{}
var type2jfmMutex = sync.Mutex{}

// JSONFieldsFromStruct returns the names of JSON fields associated
// with the given struct. Returns nil if v is not a struct
func JSONFieldsFromStruct(v reflect.Value) []string {
	if v.Kind() != reflect.Struct {
		return nil
	}

	m := getType2jfm(v.Type())
	m.lock.Lock()
	defer m.lock.Unlock()

	l := make([]string, 0, len(m.fields))
	for k := range m.fields {
		l = append(l, k)
	}
	return l
}

// StructFieldFromJSONName returns the struct field name on the
// given struct value. Empty value means the field is either not
// public, or does not exist.
//
// This can be used to map JSON field names to actual struct fields.
func StructFieldFromJSONName(v reflect.Value, name string) string {
	if v.Kind() != reflect.Struct {
		return ""
	}

	m := getType2jfm(v.Type())
	m.lock.Lock()
	defer m.lock.Unlock()

	s, ok := m.fields[name]
	if !ok {
		return ""
	}
	return s
}

func getType2jfm(t reflect.Type) jsonFieldMap {
	type2jfmMutex.Lock()
	defer type2jfmMutex.Unlock()

	return getType2jfm_nolock(t)
}

func getType2jfm_nolock(t reflect.Type) jsonFieldMap {
	fm, ok := type2jfm[t]
	if ok {
		return fm
	}

	fm = constructJfm(t)
	type2jfm[t] = fm
	return fm
}

func constructJfm(t reflect.Type) jsonFieldMap {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	fm := jsonFieldMap{
		fields: make(map[string]string),
	}
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		if sf.Anonymous { // embedded! got to recurse
			fm2 := getType2jfm_nolock(sf.Type)
			for k, v := range fm2.fields {
				fm.fields[k] = v
			}
			continue
		}

		if sf.PkgPath != "" { // unexported
			continue
		}

		tag := sf.Tag.Get("json")
		if tag == "" || tag == "-" || tag[0] == ',' {
			fm.fields[sf.Name] = sf.Name
			continue
		}

		flen := 0
		for j := 0; j < len(tag); j++ {
			if tag[j] == ',' {
				break
			}
			flen = j
		}
		fm.fields[tag[:flen+1]] = sf.Name
	}

	return fm
}<commit_msg>ignore fields if json tag is "-"<commit_after>// Package structinfo contains tools to inspect structs.

package structinfo

import (
	"reflect"
	"sync"
)

type jsonFieldMap struct {
	lock   sync.Mutex
	fields map[string]string
}

var type2jfm = map[reflect.Type]jsonFieldMap{}
var type2jfmMutex = sync.Mutex{}

// JSONFieldsFromStruct returns the names of JSON fields associated
// with the given struct. Returns nil if v is not a struct
func JSONFieldsFromStruct(v reflect.Value) []string {
	if v.Kind() != reflect.Struct {
		return nil
	}

	m := getType2jfm(v.Type())
	m.lock.Lock()
	defer m.lock.Unlock()

	l := make([]string, 0, len(m.fields))
	for k := range m.fields {
		l = append(l, k)
	}
	return l
}

// StructFieldFromJSONName returns the struct field name on the
// given struct value. Empty value means the field is either not
// public, or does not exist.
//
// This can be used to map JSON field names to actual struct fields.
func StructFieldFromJSONName(v reflect.Value, name string) string {
	if v.Kind() != reflect.Struct {
		return ""
	}

	m := getType2jfm(v.Type())
	m.lock.Lock()
	defer m.lock.Unlock()

	s, ok := m.fields[name]
	if !ok {
		return ""
	}
	return s
}

func getType2jfm(t reflect.Type) jsonFieldMap {
	type2jfmMutex.Lock()
	defer type2jfmMutex.Unlock()

	return getType2jfm_nolock(t)
}

func getType2jfm_nolock(t reflect.Type) jsonFieldMap {
	fm, ok := type2jfm[t]
	if ok {
		return fm
	}

	fm = constructJfm(t)
	type2jfm[t] = fm
	return fm
}

func constructJfm(t reflect.Type) jsonFieldMap {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	fm := jsonFieldMap{
		fields: make(map[string]string),
	}
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		if sf.Anonymous { // embedded! got to recurse
			fm2 := getType2jfm_nolock(sf.Type)
			for k, v := range fm2.fields {
				fm.fields[k] = v
			}
			continue
		}

		if sf.PkgPath != "" { // unexported
			continue
		}

		tag := sf.Tag.Get("json")
		if tag == "-" {
			continue
		}

		if tag == "" || tag[0] == ',' {
			fm.fields[sf.Name] = sf.Name
			continue
		}

		flen := 0
		for j := 0; j < len(tag); j++ {
			if tag[j] == ',' {
				break
			}
			flen = j
		}
		fm.fields[tag[:flen+1]] = sf.Name
	}

	return fm
}<|endoftext|>


<commit_before>package maputil

import (
	"reflect"
	"sort"
	"strings"

	"github.com/grokify/gotilla/sort/sortutil"
)

func StringKeys(mp interface{}) []string {
	keysVal := reflect.ValueOf(mp).MapKeys()
	keysArr := []string{}
	for _, key := range keysVal {
		keysArr = append(keysArr, key.String())
	}
	return keysArr
}

func StringKeysSorted(mp interface{}) []string {
	keysArr := StringKeys(mp)
	sort.Strings(keysArr)
	return keysArr
}

func StringKeysToLowerSorted(mp interface{}) []string {
	keysArr := StringKeys(mp)
	for i := range keysArr {
		keysArr[i] = strings.ToLower(keysArr[i])
	}
	sort.Strings(keysArr)
	return keysArr
}

func MapSSMerge(first map[string]string, second map[string]string) map[string]string {
	newMap := map[string]string{}
	for k1, v1 := range first {
		newMap[k1] = v1
	}
	for k2, v2 := range second {
		newMap[k2] = v2
	}
	return newMap
}

func MapSSValOrEmpty(data map[string]string, key string) string {
	if val, ok := data[key]; ok {
		return val
	}
	return ""
}

func MapSSEqual(a, b map[string]string) bool {
	if len(a) != len(b) {
		return false
	}

	for k, v := range a {
		if w, ok := b[k]; !ok || v != w {
			return false
		}
	}

	return true
}

type MapInt64Int64 map[int64]int64

func (m MapInt64Int64) KeysSorted() []int64 {
	keys := []int64{}
	for k := range m {
		keys = append(keys, k)
	}
	sort.Sort(sortutil.Int64Slice(keys))
	return keys
}

func (m MapInt64Int64) ValuesSortedByKeys() []int64 {
	vals := []int64{}
	keys := m.KeysSorted()
	for _, k := range keys {
		vals = append(vals, k)
	}
	return vals
}
<commit_msg>add maputil.MapSSToKeyValues()<commit_after>package maputil

import (
	"reflect"
	"sort"
	"strings"

	"github.com/grokify/gotilla/sort/sortutil"
)

func StringKeys(mp interface{}) []string {
	keysVal := reflect.ValueOf(mp).MapKeys()
	keysArr := []string{}
	for _, key := range keysVal {
		keysArr = append(keysArr, key.String())
	}
	return keysArr
}

func StringKeysSorted(mp interface{}) []string {
	keysArr := StringKeys(mp)
	sort.Strings(keysArr)
	return keysArr
}

func StringKeysToLowerSorted(mp interface{}) []string {
	keysArr := StringKeys(mp)
	for i := range keysArr {
		keysArr[i] = strings.ToLower(keysArr[i])
	}
	sort.Strings(keysArr)
	return keysArr
}

func MapSSMerge(first map[string]string, second map[string]string) map[string]string {
	newMap := map[string]string{}
	for k1, v1 := range first {
		newMap[k1] = v1
	}
	for k2, v2 := range second {
		newMap[k2] = v2
	}
	return newMap
}

func MapSSValOrEmpty(data map[string]string, key string) string {
	if val, ok := data[key]; ok {
		return val
	}
	return ""
}

func MapSSEqual(a, b map[string]string) bool {
	if len(a) != len(b) {
		return false
	}

	for k, v := range a {
		if w, ok := b[k]; !ok || v != w {
			return false
		}
	}

	return true
}

func MapSSToKeyValues(kvs map[string]string, sep string) string {
	pairs := []string{}
	for k, v := range kvs {
		k = strings.Trim(k, sep)
		v = strings.Trim(v, sep)
		if len(k) > 0 {
			pairs = append(pairs, k+"="+v)
		}
	}
	return strings.Join(pairs, sep)
}

type MapInt64Int64 map[int64]int64

func (m MapInt64Int64) KeysSorted() []int64 {
	keys := []int64{}
	for k := range m {
		keys = append(keys, k)
	}
	sort.Sort(sortutil.Int64Slice(keys))
	return keys
}

func (m MapInt64Int64) ValuesSortedByKeys() []int64 {
	vals := []int64{}
	keys := m.KeysSorted()
	for _, k := range keys {
		vals = append(vals, k)
	}
	return vals
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"sync"

	. "github.com/reujab/bronze/types"
	"github.com/urfave/cli"
)

var cmdPrint = cli.Command{
	Name:  "print",
	Usage: "Prints the prompt with the specified syntax",
	// TODO: improve description
	Description: "Example: bronze print dir:blue:black",
	Action: func(ctx *cli.Context) error {
		if len(ctx.Args()) == 0 {
			cli.ShowCommandHelpAndExit(ctx, "print", 1)
		}

		cmdPrintAction(ctx.Args())
		return nil
	},
}

func cmdPrintAction(args []string) {
	var segments []*Segment
	waitgroup := new(sync.WaitGroup)
	waitgroup.Add(len(args))

	for _, arg := range args {
		// validate argument
		fields := strings.Split(arg, ":")
		if len(fields) < 3 {
			dief("invalid argument: %q, at least three fields expected", arg)
		}

		segment := &Segment{
			Background: fields[1],
			Foreground: fields[2],
		}
		segments = append(segments, segment)

		go func() {
			handleModule(fields[0], segment, fields[3:])
			waitgroup.Done()
		}()
	}

	// wait for all the async segments
	waitgroup.Wait()

	// print the prompt
	first := true
	lastSegment := &Segment{
		Background: "black",
		Foreground: "white",
	}
	for _, segment := range segments {
		if segment.Value == "" {
			continue
		}

		// if this isn't the first segment, before printing the next segment, separate them
		if !first {
			if segment.Background == lastSegment.Background {
				printSegment(segment.Background, lastSegment.Foreground, thinSeparator)
			} else {
				// use the last background as the current foreground
				printSegment(segment.Background, lastSegment.Background, separator)
			}
		}
		first = false

		printSegment(segment.Background, segment.Foreground, " "+segment.Value+" ")
		lastSegment = segment
	}
	// print final separator
	printSegment("none", lastSegment.Background, separator)
	resetColors()
}

func printSegment(background, foreground, value string) {
	fmt.Print(escapeBackground(background) + escapeForeground(foreground) + value)
}
<commit_msg>updated subcommand print's usage<commit_after>package main

import (
	"fmt"
	"strings"
	"sync"

	. "github.com/reujab/bronze/types"
	"github.com/urfave/cli"
)

var cmdPrint = cli.Command{
	Name:        "print",
	Usage:       "Prints the prompt with the specified modules",
	Description: "Example: bronze print dir:blue:black",
	Action: func(ctx *cli.Context) error {
		if len(ctx.Args()) == 0 {
			cli.ShowCommandHelpAndExit(ctx, "print", 1)
		}

		cmdPrintAction(ctx.Args())
		return nil
	},
}

func cmdPrintAction(args []string) {
	var segments []*Segment
	waitgroup := new(sync.WaitGroup)
	waitgroup.Add(len(args))

	for _, arg := range args {
		// validate argument
		fields := strings.Split(arg, ":")
		if len(fields) < 3 {
			dief("invalid argument: %q, at least three fields expected", arg)
		}

		segment := &Segment{
			Background: fields[1],
			Foreground: fields[2],
		}
		segments = append(segments, segment)

		go func() {
			handleModule(fields[0], segment, fields[3:])
			waitgroup.Done()
		}()
	}

	// wait for all the async segments
	waitgroup.Wait()

	// print the prompt
	first := true
	lastSegment := &Segment{
		Background: "black",
		Foreground: "white",
	}
	for _, segment := range segments {
		if segment.Value == "" {
			continue
		}

		// if this isn't the first segment, before printing the next segment, separate them
		if !first {
			if segment.Background == lastSegment.Background {
				printSegment(segment.Background, lastSegment.Foreground, thinSeparator)
			} else {
				// use the last background as the current foreground
				printSegment(segment.Background, lastSegment.Background, separator)
			}
		}
		first = false

		printSegment(segment.Background, segment.Foreground, " "+segment.Value+" ")
		lastSegment = segment
	}
	// print final separator
	printSegment("none", lastSegment.Background, separator)
	resetColors()
}

func printSegment(background, foreground, value string) {
	fmt.Print(escapeBackground(background) + escapeForeground(foreground) + value)
}
<|endoftext|>


<commit_before>package flash_test

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"sync"
	"testing"

	"github.com/blue-jay/core/flash"
	"github.com/blue-jay/core/view"
)

// Session is an interface for typical sessions
type Session struct {
	flashes []interface{}
	mutex   sync.RWMutex
}

// Save mocks saving the session
func (s *Session) Save(r *http.Request, w http.ResponseWriter) error {
	return nil
}

// Flashes retrieves the flashes
func (s *Session) Flashes(vars ...string) []interface{} {
	s.mutex.RLock()
	f := s.flashes
	// Clear the flashes
	s.flashes = s.flashes[:0]
	s.mutex.RUnlock()
	return f
}

// AddFlash adds a flash to the list
func (s *Session) AddFlash(f interface{}) {
	s.mutex.Lock()
	s.flashes = append(s.flashes, f)
	s.mutex.Unlock()
}

// TestFlashSession ensures flashes can be added to the session.
func TestFlashSession(t *testing.T) {
	text := "Success test."

	// Get the fake session
	sess := Session{}

	// Add flashes to the session
	sess.AddFlash(flash.Info{text, flash.Success})

	// Get the flashes
	flashes := sess.Flashes()

	if len(flashes) != 1 {
		t.Fatal("Expected 1 flash message.")
	}

	// Convert the flash
	f, ok := flashes[0].(flash.Info)

	if f.Class != flash.Success {
		t.Fatal("Flash class is: %v, should be: %v.", f.Class, flash.Success)
	}

	if f.Message != text {
		t.Fatalf("Flash message is: %v, should be: %v", f.Message, text)
	}

	if !ok {
		t.Fatal("Flashes missing from session.")
	}
}

// TestSendFlashes are available for AJAX.
func TestSendFlashes(t *testing.T) {
	viewInfo := &view.Info{
		BaseURI:   "/",
		Extension: "tmpl",
		Folder:    "testdata/view",
		Caching:   false,
	}

	templates := view.Template{
		Root:     "test",
		Children: []string{},
	}

	// Set up the view
	viewInfo.SetTemplates(templates.Root, templates.Children)

	// Simulate a request
	w := httptest.NewRecorder()
	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	text := "Success test."

	// Get the fake session
	sess := &Session{}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Add flashes to the session
		sess.AddFlash(flash.Info{text, flash.Success})
		sess.AddFlash(text)

		// Send the flashes
		flash.SendFlashes(w, r, sess)
	})

	handler.ServeHTTP(w, r)

	actual := w.Body.String()
	expected := fmt.Sprintf(`[{"Message":"%v","Class":"%v"},{"Message":"%v","Class":"%v"}]`, text, flash.Success, text, flash.Standard)

	if actual != expected {
		t.Fatalf("\nactual: %v\nexpected: %v", actual, expected)
	}
}
<commit_msg>Update flash_test.go<commit_after>package flash_test

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"sync"
	"testing"

	"github.com/blue-jay/core/flash"
	"github.com/blue-jay/core/view"
)

// Session is an interface for typical sessions
type Session struct {
	flashes []interface{}
	mutex   sync.RWMutex
}

// Save mocks saving the session
func (s *Session) Save(r *http.Request, w http.ResponseWriter) error {
	return nil
}

// Flashes retrieves the flashes
func (s *Session) Flashes(vars ...string) []interface{} {
	s.mutex.RLock()
	f := s.flashes
	// Clear the flashes
	s.flashes = s.flashes[:0]
	s.mutex.RUnlock()
	return f
}

// AddFlash adds a flash to the list
func (s *Session) AddFlash(f interface{}) {
	s.mutex.Lock()
	s.flashes = append(s.flashes, f)
	s.mutex.Unlock()
}

// TestFlashSession ensures flashes can be added to the session.
func TestFlashSession(t *testing.T) {
	text := "Success test."

	// Get the fake session
	sess := Session{}

	// Add flashes to the session
	sess.AddFlash(flash.Info{text, flash.Success})

	// Get the flashes
	flashes := sess.Flashes()

	if len(flashes) != 1 {
		t.Fatal("Expected 1 flash message.")
	}

	// Convert the flash
	f, ok := flashes[0].(flash.Info)

	if f.Class != flash.Success {
		t.Fatalf("Flash class is: %v, should be: %v.", f.Class, flash.Success)
	}

	if f.Message != text {
		t.Fatalf("Flash message is: %v, should be: %v", f.Message, text)
	}

	if !ok {
		t.Fatal("Flashes missing from session.")
	}
}

// TestSendFlashes are available for AJAX.
func TestSendFlashes(t *testing.T) {
	viewInfo := &view.Info{
		BaseURI:   "/",
		Extension: "tmpl",
		Folder:    "testdata/view",
		Caching:   false,
	}

	templates := view.Template{
		Root:     "test",
		Children: []string{},
	}

	// Set up the view
	viewInfo.SetTemplates(templates.Root, templates.Children)

	// Simulate a request
	w := httptest.NewRecorder()
	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	text := "Success test."

	// Get the fake session
	sess := &Session{}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Add flashes to the session
		sess.AddFlash(flash.Info{text, flash.Success})
		sess.AddFlash(text)

		// Send the flashes
		flash.SendFlashes(w, r, sess)
	})

	handler.ServeHTTP(w, r)

	actual := w.Body.String()
	expected := fmt.Sprintf(`[{"Message":"%v","Class":"%v"},{"Message":"%v","Class":"%v"}]`, text, flash.Success, text, flash.Standard)

	if actual != expected {
		t.Fatalf("\nactual: %v\nexpected: %v", actual, expected)
	}
}
<|endoftext|>


<commit_before><commit_msg>fix json string->[]byte conversion error<commit_after><|endoftext|>


<commit_before>/*
 *    Copyright (C) 2015 Stefan Luecke
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors: Stefan Luecke <glaxx@glaxx.net>
 */

package backend

import (
	//	"database/sql"
	log "github.com/Sirupsen/logrus"
	"github.com/emicklei/go-restful"
	"html/template"
	"net/http"
	"strconv"
	"strings"
)

type Item struct {
	ID          uint64
	Name        string
	Description string
	Contains    []uint64
	Owner       uint64
	Maintainer  uint64
	Usage       uint64
	Discard     uint64
}

func NewItemService() *restful.WebService {
	service := new(restful.WebService)
	service.
		Path("/item").
		Consumes(restful.MIME_JSON, restful.MIME_XML).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	service.Route(service.GET("/{id}").To(GetItemById))
	service.Route(service.GET("").To(ListItem))
	service.Route(service.PUT("").To(UpdateItem))
	service.Route(service.PUT("/{id}").To(UpdateItem))
	service.Route(service.POST("").To(CreateItem))
	service.Route(service.DELETE("/{id}").To(DeleteItem))
	return service
}

func GetItemById(request *restful.Request, response *restful.Response) {
	sid := request.PathParameter("id")
	log.WithFields(log.Fields{"Requested ID": sid}).Debug("Got Request")
	id, err := strconv.ParseUint(sid, 10, 64)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		log.WithFields(log.Fields{"Error Msg": err}).
			Info(ERROR_INVALID_ID)
		return
	}
	itm, err := getItemById(id)
	if err != nil || itm.ID == 0 {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		log.WithFields(log.Fields{"Error Msg": err}).
			Info(ERROR_INVALID_ID)
		return
	}
	response.WriteEntity(itm)
}

func getItemById(id uint64) (Item, error) {
	stmt, err := db.Prepare("SELECT * FROM item WHERE id=?;")
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).
			Fatal(ERROR_STMT_PREPARE)
	}
	defer stmt.Close()
	row := stmt.QueryRow(id)
	itm := new(Item)
	unpacked_string := ""
	err = row.Scan(&itm.ID, &itm.Name, &itm.Description, &unpacked_string, &itm.Owner, &itm.Maintainer, &itm.Usage, &itm.Discard)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).
			Warn("Scan Error")
	}
	itm.Contains = unpack_contains(unpacked_string)
	return *itm, nil
}

func unpack_contains(input string) []uint64 {
	ids := strings.Split(input, ";")

	if len(ids) <= 1 {
		return make([]uint64, 0)
	}
	res := make([]uint64, len(ids))
	for i := 0; i != len(ids); i++ {
		log.WithFields(log.Fields{"String": ids[i], "length": len(ids), "i": i}).Debug("Trying to parse string")
		temp, err := strconv.ParseUint(ids[i], 10, 64)
		if err != nil {
			log.WithFields(log.Fields{"Error Msg": err}).
				Warn("Failed to unpack 'Contains' string")
		}
		res[i] = temp
	}
	return res
}

func pack_contains(input []uint64) string {
	if len(input) == 0 {
		return ""
	}
	if len(input) == 1 {
		return strconv.FormatUint(input[0], 10)
	}
	str := ""
	for i := 0; i != len(input); i++ {
		str = str + strconv.FormatUint(input[i], 10) + ";"
	}
	return str
}

func CreateItem(request *restful.Request, response *restful.Response) {
	itm := new(Item)
	err := request.ReadEntity(itm)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_INPUT)
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INVALID_INPUT)
		return
	}

	id, err := createItem(itm)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity("/item/" + strconv.FormatUint(id, 10))
}

func createItem(itm *Item) (uint64, error) {
	stmt, err := db.Prepare(`
		INSERT INTO item ('name', 'description', 'contains', 'owner', 'maintainer', 'usage', 'discard') VALUES (?, ?, ?, ?, ?, ?, ?);`)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Fatal(ERROR_STMT_PREPARE)
		return 0, err
	}
	defer stmt.Close()
	res, err := stmt.Exec(template.HTMLEscapeString(itm.Name), template.HTMLEscapeString(itm.Description), pack_contains(itm.Contains), itm.Owner, itm.Maintainer, itm.Usage, itm.Discard)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INSERT)
		return 0, err
	}

	id, err := res.LastInsertId()
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_QUERY)
		return 0, err
	}

	return uint64(id), nil
}

func ListItem(request *restful.Request, response *restful.Response) {
	itm, err := listItem()
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity(itm)
}

func listItem() ([]Item, error) {
	stmt, err := db.Prepare(`
		SELECT * FROM item;`)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Fatal(ERROR_STMT_PREPARE)
		return nil, err
	}
	defer stmt.Close()
	rows, err := stmt.Query()
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return nil, err
	}
	result := make([]Item, 0)
	for rows.Next() {
		temp := new(Item) // Item{0, "", make([]uint64, 0), 0, 0, 0, 0)
		str := ""
		rows.Scan(&temp.ID, &temp.Name, &temp.Description, &str, &temp.Owner, &temp.Maintainer, &temp.Usage, &temp.Discard)
		temp.Contains = unpack_contains(str)
		result = append(result, *temp)
	}

	return result, nil
}

func UpdateItem(request *restful.Request, response *restful.Response) {
	itm := new(Item)
	err := request.ReadEntity(itm)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	stmt, err := db.Prepare(`
		SELECT * FROM item ORDER BY id DESC LIMIT 0, 1;`)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	defer stmt.Close()
	row := stmt.QueryRow()
	var id uint64
	temp := new(Item)
	temp2 := ""
	err = row.Scan(&id, &temp.Name, &temp.Description, &temp2, &temp.Owner, &temp.Maintainer, &temp.Usage, &temp.Discard)

	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}

	log.WithFields(log.Fields{"Id": id}).Debug("Highest ID")

	if itm.ID <= id {
		err := updateItem(itm)
		if err != nil {
			response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
			return
		} else {
			response.WriteEntity(true)
		}
	} else {
		CreateItem(request, response)
	}
}

func updateItem(itm *Item) error {
	stmt, err := db.Prepare(`
		UPDATE item SET name=?, description=?, contains=?, owner=?, maintainer=?, usage=?, discard=? WHERE id=?;`)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return err
	}
	defer stmt.Close()
	_, err = stmt.Exec(template.HTMLEscapeString(itm.Name), template.HTMLEscapeString(itm.Description), pack_contains(itm.Contains), itm.Owner, itm.Maintainer, itm.Usage, itm.Discard, itm.ID)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return err
	}
	return nil
}

func DeleteItem(request *restful.Request, response *restful.Response) {
	sid := request.PathParameter("id")
	id, err := strconv.ParseUint(sid, 10, 64)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INVALID_ID)
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		return
	}

	err = deleteItem(id)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INTERNAL)
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		return
	}
	response.WriteEntity(true)
}

func deleteItem(id uint64) error {
	stmt, err := db.Prepare(`
		DELETE FROM item WHERE id=?;
		`)
	if err != nil {
		return err
	}
	defer stmt.Close()
	_, err = stmt.Exec(id)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>item.go: sqlite -> mongodb<commit_after>/*
 *    Copyright (C) 2015 Stefan Luecke
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors: Stefan Luecke <glaxx@glaxx.net>
 */
package backend

import (
	//	"database/sql"
	log "github.com/Sirupsen/logrus"
	"github.com/emicklei/go-restful"
	//"html/template"
	"gopkg.in/mgo.v2/bson"
	"net/http"
	"strconv"
	//"strings"
)

type Item struct {
	ID          bson.ObjectId `bson:"_id,omitempty" json:"-"`
	EID         uint64
	Name        string
	Description string
	Contains    []bson.ObjectId
	Owner       uint64
	Maintainer  uint64
	Usage       uint64
	Discard     uint64
}

func NewItemService() *restful.WebService {
	service := new(restful.WebService)
	service.
		Path("/item").
		Consumes(restful.MIME_JSON, restful.MIME_XML).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	service.Route(service.GET("/{id}").To(GetItemById))
	service.Route(service.GET("").To(ListItem))
	service.Route(service.PUT("").To(UpdateItem))
	service.Route(service.POST("").To(CreateItem))
	service.Route(service.DELETE("/{id}").To(DeleteItem))
	return service
}

func GetItemById(request *restful.Request, response *restful.Response) {
	sid := request.PathParameter("id")
	log.WithFields(log.Fields{"Requested ID": sid, "Path": request.SelectedRoutePath()}).Debug("Got Request")
	id, err := strconv.ParseUint(sid, 10, 64)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		log.WithFields(log.Fields{"Error Msg": err}).
			Info(ERROR_INVALID_ID)
		return
	}
	itm, err := getItemById(id)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		log.WithFields(log.Fields{"Error Msg": err}).
			Info(ERROR_INVALID_ID)
		return
	}
	response.WriteEntity(itm)
}

func getItemById(id uint64) (Item, error) {
	res := Item{}
	err := iCol.Find(bson.M{"eid": id}).One(&res)
	return res, err
}

func CreateItem(request *restful.Request, response *restful.Response) {
	itm := new(Item)
	err := request.ReadEntity(itm)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_INPUT)
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INVALID_INPUT)
		return
	}

	id, err := createItem(itm)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity("/item/" + strconv.FormatUint(id, 10))
}

func createItem(itm *Item) (uint64, error) {
	itm.EID = idgen.GenerateID()
	log.WithFields(log.Fields{"ID": itm.EID}).Debug("Generated ID")
	err := iCol.Insert(itm)
	return itm.EID, err
}

func ListItem(request *restful.Request, response *restful.Response) {
	itm, err := listItem()
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity(itm)
}

func listItem() ([]Item, error) {
	itm := make([]Item, 0)
	err := iCol.Find(nil).All(&itm)
	return itm, err
}

func UpdateItem(request *restful.Request, response *restful.Response) {
	itm := new(Item)
	err := request.ReadEntity(itm)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	ex := checkItemExistance(itm)
	if ex {
		err = updateItem(itm)
		if err != nil {
			response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
			log.WithFields(log.Fields{"Err": err}).Warn("Error while updating Item")
			return
		}
		response.WriteEntity(true)
		return
	} else {
		response.WriteErrorString(http.StatusNotFound, "Item not found")
		return
	}
}

func updateItem(itm *Item) error {
	return iCol.Update(bson.M{"eid": itm.EID}, itm)
}

func checkItemExistance(itm *Item) bool {
	temp := Item{}
	err := iCol.Find(bson.M{"eid": itm.EID}).One(&temp)
	if err != nil {
		if err.Error() == "not found" {
			return false
		} else {
			log.WithFields(log.Fields{"Err": err}).
				Debug("TODO: check more error codes here")
			return true
		}
	}
	return true
}

func DeleteItem(request *restful.Request, response *restful.Response) {
	sid := request.PathParameter("id")
	id, err := strconv.ParseUint(sid, 10, 64)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INVALID_ID)
		response.WriteErrorString(http.StatusNotFound, ERROR_INVALID_ID)
		return
	}

	err = deleteItem(id)
	if err != nil {
		if err.Error() == "not found" {
			log.WithFields(log.Fields{"ID": id}).Info(ERROR_INVALID_ID)
			response.WriteErrorString(http.StatusNotFound, ERROR_INVALID_ID)
			return
		}
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INTERNAL)
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		return
	}
	response.WriteEntity(true)
}

func deleteItem(id uint64) error {
	return iCol.Remove(bson.M{"eid": id})
}
<|endoftext|>


<commit_before>package proto

// The Proto type. (Get it?)
//
// The `Proto` type is a stand-in approximation for dynamic typing. Due to
// Go's powerful casting and type inference idioms, we can approximate the
// flexibility of dynamic typing even though Go is a statically typed language.
// Doing so sacrifices some of the benefits of static typing AND some of the
// benefits of dynamic typing, but this sacrifice is fundamentally required by
// Go until such time as a true 'Generic' type is implemented.
//
// In order to use a Proto-typed variable (from here on out, simply a 'Proto'),
// you will generally have to cast it to a type that you will know to use based
// on the semantics of your program.
//
// This package (specifically, the other files in this package) provide
// operations on Proto variables as well as some that make Proto variables out
// of 'traditionally typed' variables. Many of the operations will require the
// use of higher-order functions which you will need to provide, and those
// functions commonly will need you to manually "unbox" (cast-from-Proto) the
// variable to perform useful operations.
//
// Examples of the use of this package can be found in the "*_test.go" files,
// which contain testing code. A good example of a higher-order function which
// will commonly need manual-unboxing is the `Filter` function, found in
// "filter.go". `Filter` takes as its first argument a filter-function which
// will almost certainly require you to un-box the Proto channel values that it
// receives to perform the filtering action.
//
// Finally, a word on the entire point of this package: while it is named after
// the Proto type that pervades it and guides its syntax, the true nature of
// the `proto` package lies in cascading channels, rather than in dynamic
// typing. In fact this package might be more appropriately named after
// channels. Maybe `canal` would have been a better name. I wanted to bring
// the syntax and familiar patterns of functional programming idioms to the
// power and scalability of Go's goroutines and channels, and found that the
// syntax made this task very simple.
//
// You may find, as I did, that the majority of the code in this package is very
// 'obvious'. At first I was concerned by this - much of the code is very
// trivial - but now I feel pleased by the re-usability and natural
// 'correctness' of `proto`. Look at this package not as some monumental
// time-saving framework, but rather as a light scaffold for a useful and
// idiomatic style of programming within the existing constructs of Go.
//
// Ultimately, though, you're going to be typing the word Proto an awful lot,
// and thus the type became the eponym.
type Proto interface{}
<commit_msg>godoc comment movement<commit_after>// The `Proto` type is a stand-in approximation for dynamic typing. Due to
// Go's powerful casting and type inference idioms, we can approximate the
// flexibility of dynamic typing even though Go is a statically typed language.
// Doing so sacrifices some of the benefits of static typing AND some of the
// benefits of dynamic typing, but this sacrifice is fundamentally required by
// Go until such time as a true 'Generic' type is implemented.
//
// In order to use a Proto-typed variable (from here on out, simply a 'Proto'),
// you will generally have to cast it to a type that you will know to use based
// on the semantics of your program.
//
// This package (specifically, the other files in this package) provide
// operations on Proto variables as well as some that make Proto variables out
// of 'traditionally typed' variables. Many of the operations will require the
// use of higher-order functions which you will need to provide, and those
// functions commonly will need you to manually "unbox" (cast-from-Proto) the
// variable to perform useful operations.
//
// Examples of the use of this package can be found in the "*_test.go" files,
// which contain testing code. A good example of a higher-order function which
// will commonly need manual-unboxing is the `Filter` function, found in
// "filter.go". `Filter` takes as its first argument a filter-function which
// will almost certainly require you to un-box the Proto channel values that it
// receives to perform the filtering action.
//
// Finally, a word on the entire point of this package: while it is named after
// the Proto type that pervades it and guides its syntax, the true nature of
// the `proto` package lies in cascading channels, rather than in dynamic
// typing. In fact this package might be more appropriately named after
// channels. Maybe `canal` would have been a better name. I wanted to bring
// the syntax and familiar patterns of functional programming idioms to the
// power and scalability of Go's goroutines and channels, and found that the
// syntax made this task very simple.
//
// You may find, as I did, that the majority of the code in this package is very
// 'obvious'. At first I was concerned by this - much of the code is very
// trivial - but now I feel pleased by the re-usability and natural
// 'correctness' of `proto`. Look at this package not as some monumental
// time-saving framework, but rather as a light scaffold for a useful and
// idiomatic style of programming within the existing constructs of Go.
//
// Ultimately, though, you're going to be typing the word Proto an awful lot,
// and thus the type became the eponym.
package proto

// The Proto type. (Get it?)
type Proto interface{}
<|endoftext|>


<commit_before>package proxy

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"

	"github.com/go-openapi/errors"
	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
	"github.com/go-openapi/swag"
	"github.com/go-openapi/validate"
	"github.com/gorilla/mux"
)

type Proxy struct {
	// Opts
	target  string
	verbose bool

	router       *mux.Router
	routes       map[*mux.Route]*spec.Operation
	reverseProxy http.Handler

	reporter Reporter
	doc      interface{} // This is useful for validate (TODO: find a better way)
}

type ProxyOpt func(*Proxy)

func WithTarget(target string) ProxyOpt { return func(proxy *Proxy) { proxy.target = target } }
func WithVerbose(v bool) ProxyOpt       { return func(proxy *Proxy) { proxy.verbose = v } }

func New(s *spec.Swagger, reporter Reporter, opts ...ProxyOpt) (*Proxy, error) {
	// validate.NewSchemaValidator requires the spec as an interface{}
	// That's why we Unmarshal(Marshal()) the document
	data, err := json.Marshal(s)
	if err != nil {
		return nil, err
	}

	var doc interface{}
	if err := json.Unmarshal(data, &doc); err != nil {
		return nil, err
	}

	proxy := &Proxy{
		target:   "http://localhost:8080",
		router:   mux.NewRouter(),
		routes:   make(map[*mux.Route]*spec.Operation),
		reporter: reporter,
		doc:      doc,
	}

	for _, opt := range opts {
		opt(proxy)
	}

	rpURL, err := url.Parse(proxy.target)
	if err != nil {
		return nil, err
	}
	proxy.reverseProxy = httputil.NewSingleHostReverseProxy(rpURL)

	proxy.router.NotFoundHandler = http.HandlerFunc(proxy.notFound)
	proxy.registerPaths(s.BasePath, s.Paths)

	return proxy, nil
}

func (proxy *Proxy) Router() http.Handler {
	return proxy.router
}

func (proxy *Proxy) registerPaths(base string, paths *spec.Paths) {
	for path, item := range paths.Paths {
		// Register every spec operation under a newHandler
		for method, op := range getOperations(&item) {
			newPath := base + path
			if proxy.verbose {
				log.Printf("Register %s %s", method, newPath)
			}
			route := proxy.router.Handle(
				newPath, proxy.newHandler(),
			).Methods(method)
			proxy.routes[route] = op
		}
	}
}

func (proxy *Proxy) notFound(w http.ResponseWriter, req *http.Request) {
	proxy.reporter.Warning(req, "Route not defined on the Spec")
	proxy.reverseProxy.ServeHTTP(w, req)
}

func (proxy *Proxy) newHandler() http.Handler {
	return proxy.Handler(proxy.reverseProxy)
}
func (proxy *Proxy) Handler(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, req *http.Request) {
		var match mux.RouteMatch
		proxy.router.Match(req, &match)
		op := proxy.routes[match.Route]

		if match.Handler == nil || op == nil {
			proxy.reporter.Warning(req, "Route not defined on the Spec")
			// Route hasn't been registered on the muxer
			return
		}

		wr := &WriterRecorder{ResponseWriter: w}
		next.ServeHTTP(wr, req)

		specResp, ok := op.Responses.StatusCodeResponses[wr.Status()]
		if !ok {
			err := fmt.Errorf("Server Status %d not defined by the spec", wr.Status())
			proxy.reporter.Error(req, err)
			return
		}

		if err := proxy.Validate(wr.Status(), wr.Header(), wr.Body(), &specResp); err != nil {
			proxy.reporter.Error(req, err)
		} else {
			proxy.reporter.Success(req)
		}
	}
	return http.HandlerFunc(fn)
}

func (proxy *Proxy) Validate(status int, header http.Header, body []byte, resp *spec.Response) error {
	var data interface{}
	if err := json.Unmarshal(body, &data); err != nil {
		return err
	}

	var errs []error
	for key, val := range resp.Headers {
		if err := validateHeaderValue(key, header.Get(key), &val); err != nil {
			errs = append(errs, err)
		}
	}

	// No schema to validate against
	if resp.Schema != nil {
		validator := validate.NewSchemaValidator(resp.Schema, proxy.doc, "", strfmt.NewFormats())
		result := validator.Validate(data)
		if result.HasErrors() {
			errs = append(errs, result.Errors...)
		}
	}

	if len(errs) == 0 {
		return nil
	}
	return errors.CompositeValidationError(errs...)
}

func validateHeaderValue(key, value string, spec *spec.Header) error {
	if value == "" {
		return fmt.Errorf("%s in headers is missing", key)
	}

	// TODO: Implement the rest of the format validators
	switch spec.Format {
	case "int32":
		_, err := swag.ConvertInt32(value)
		return err
	case "date-time":
		_, err := strfmt.ParseDateTime(value)
		return err
	}
	return nil
}

func getOperations(props *spec.PathItem) map[string]*spec.Operation {
	ops := make(map[string]*spec.Operation)

	if props.Delete != nil {
		ops["DELETE"] = props.Delete
	} else if props.Get != nil {
		ops["GET"] = props.Get
	} else if props.Head != nil {
		ops["HEAD"] = props.Head
	} else if props.Options != nil {
		ops["OPTIONS"] = props.Options
	} else if props.Patch != nil {
		ops["PATCH"] = props.Patch
	} else if props.Post != nil {
		ops["POST"] = props.Post
	} else if props.Put != nil {
		ops["PUT"] = props.Put
	}

	return ops
}
<commit_msg>Call next even if not found<commit_after>package proxy

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"

	"github.com/go-openapi/errors"
	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
	"github.com/go-openapi/swag"
	"github.com/go-openapi/validate"
	"github.com/gorilla/mux"
)

type Proxy struct {
	// Opts
	target  string
	verbose bool

	router       *mux.Router
	routes       map[*mux.Route]*spec.Operation
	reverseProxy http.Handler

	reporter Reporter
	doc      interface{} // This is useful for validate (TODO: find a better way)
}

type ProxyOpt func(*Proxy)

func WithTarget(target string) ProxyOpt { return func(proxy *Proxy) { proxy.target = target } }
func WithVerbose(v bool) ProxyOpt       { return func(proxy *Proxy) { proxy.verbose = v } }

func New(s *spec.Swagger, reporter Reporter, opts ...ProxyOpt) (*Proxy, error) {
	// validate.NewSchemaValidator requires the spec as an interface{}
	// That's why we Unmarshal(Marshal()) the document
	data, err := json.Marshal(s)
	if err != nil {
		return nil, err
	}

	var doc interface{}
	if err := json.Unmarshal(data, &doc); err != nil {
		return nil, err
	}

	proxy := &Proxy{
		target:   "http://localhost:8080",
		router:   mux.NewRouter(),
		routes:   make(map[*mux.Route]*spec.Operation),
		reporter: reporter,
		doc:      doc,
	}

	for _, opt := range opts {
		opt(proxy)
	}

	rpURL, err := url.Parse(proxy.target)
	if err != nil {
		return nil, err
	}
	proxy.reverseProxy = httputil.NewSingleHostReverseProxy(rpURL)

	proxy.router.NotFoundHandler = http.HandlerFunc(proxy.notFound)
	proxy.registerPaths(s.BasePath, s.Paths)

	return proxy, nil
}

func (proxy *Proxy) Router() http.Handler {
	return proxy.router
}

func (proxy *Proxy) registerPaths(base string, paths *spec.Paths) {
	for path, item := range paths.Paths {
		// Register every spec operation under a newHandler
		for method, op := range getOperations(&item) {
			newPath := base + path
			if proxy.verbose {
				log.Printf("Register %s %s", method, newPath)
			}
			route := proxy.router.Handle(
				newPath, proxy.newHandler(),
			).Methods(method)
			proxy.routes[route] = op
		}
	}
}

func (proxy *Proxy) notFound(w http.ResponseWriter, req *http.Request) {
	proxy.reporter.Warning(req, "Route not defined on the Spec")
	proxy.reverseProxy.ServeHTTP(w, req)
}

func (proxy *Proxy) newHandler() http.Handler {
	return proxy.Handler(proxy.reverseProxy)
}
func (proxy *Proxy) Handler(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, req *http.Request) {
		wr := &WriterRecorder{ResponseWriter: w}
		next.ServeHTTP(wr, req)

		var match mux.RouteMatch
		proxy.router.Match(req, &match)
		op := proxy.routes[match.Route]

		if match.Handler == nil || op == nil {
			proxy.reporter.Warning(req, "Route not defined on the Spec")
			// Route hasn't been registered on the muxer
			return
		}

		specResp, ok := op.Responses.StatusCodeResponses[wr.Status()]
		if !ok {
			err := fmt.Errorf("Server Status %d not defined by the spec", wr.Status())
			proxy.reporter.Error(req, err)
			return
		}

		if err := proxy.Validate(wr.Status(), wr.Header(), wr.Body(), &specResp); err != nil {
			proxy.reporter.Error(req, err)
		} else {
			proxy.reporter.Success(req)
		}
	}
	return http.HandlerFunc(fn)
}

func (proxy *Proxy) Validate(status int, header http.Header, body []byte, resp *spec.Response) error {
	var data interface{}
	if err := json.Unmarshal(body, &data); err != nil {
		return err
	}

	var errs []error
	for key, val := range resp.Headers {
		if err := validateHeaderValue(key, header.Get(key), &val); err != nil {
			errs = append(errs, err)
		}
	}

	// No schema to validate against
	if resp.Schema != nil {
		validator := validate.NewSchemaValidator(resp.Schema, proxy.doc, "", strfmt.NewFormats())
		result := validator.Validate(data)
		if result.HasErrors() {
			errs = append(errs, result.Errors...)
		}
	}

	if len(errs) == 0 {
		return nil
	}
	return errors.CompositeValidationError(errs...)
}

func validateHeaderValue(key, value string, spec *spec.Header) error {
	if value == "" {
		return fmt.Errorf("%s in headers is missing", key)
	}

	// TODO: Implement the rest of the format validators
	switch spec.Format {
	case "int32":
		_, err := swag.ConvertInt32(value)
		return err
	case "date-time":
		_, err := strfmt.ParseDateTime(value)
		return err
	}
	return nil
}

func getOperations(props *spec.PathItem) map[string]*spec.Operation {
	ops := make(map[string]*spec.Operation)

	if props.Delete != nil {
		ops["DELETE"] = props.Delete
	} else if props.Get != nil {
		ops["GET"] = props.Get
	} else if props.Head != nil {
		ops["HEAD"] = props.Head
	} else if props.Options != nil {
		ops["OPTIONS"] = props.Options
	} else if props.Patch != nil {
		ops["PATCH"] = props.Patch
	} else if props.Post != nil {
		ops["POST"] = props.Post
	} else if props.Put != nil {
		ops["PUT"] = props.Put
	}

	return ops
}
<|endoftext|>


<commit_before>// This package contains the reverse proxy that implements http.HandlerFunc
package vulcan

import (
	log "github.com/mailgun/gotools-log"
	"github.com/mailgun/vulcan/errors"
	"github.com/mailgun/vulcan/netutils"
	"github.com/mailgun/vulcan/request"
	"github.com/mailgun/vulcan/route"
	"io"
	"io/ioutil"
	"net/http"
	"sync/atomic"
)

type Proxy struct {
	// Router selects a location for each request
	router route.Router
	// Options like ErrorFormatter
	options Options
	// Counter that is used to provide unique identifiers for requests
	lastRequestId int64
}

type Options struct {
	// Takes a status code and formats it into proxy response
	ErrorFormatter errors.Formatter
}

// Accepts requests, round trips it to the endpoint, and writes back the response.
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Record the request body so we can replay it on errors.
	body, err := netutils.NewBodyBuffer(r.Body)
	if err != nil || body == nil {
		log.Errorf("Request read error %s", err)
		// "i/o timeout" message is generated by net pkg in response
		// to, for example, http.Server.ReadTimeout being exeeded.
		if err.Error() == "i/o timeout" {
			p.replyError(errors.FromStatus(http.StatusRequestTimeout), w, r)
		} else {
			p.replyError(errors.FromStatus(http.StatusBadRequest), w, r)
		}
		return
	}
	defer body.Close()
	r.Body = body

	req := &request.BaseRequest{
		HttpRequest: r,
		Id:          atomic.AddInt64(&p.lastRequestId, 1),
		Body:        body,
	}

	err = p.proxyRequest(w, req)
	if err != nil {
		log.Errorf("%s failed: %s", req, err)
		p.replyError(err, w, r)
	}
}

// Creates a proxy with a given router
func NewProxy(router route.Router) (*Proxy, error) {
	return NewProxyWithOptions(router, Options{})
}

// Creates reverse proxy that acts like http request handler
func NewProxyWithOptions(router route.Router, o Options) (*Proxy, error) {
	o, err := validateOptions(o)
	if err != nil {
		return nil, err
	}

	p := &Proxy{
		options: o,
		router:  router,
	}
	return p, nil
}

func (p *Proxy) GetRouter() route.Router {
	return p.router
}

// Round trips the request to the selected location and writes back the response
func (p *Proxy) proxyRequest(w http.ResponseWriter, req *request.BaseRequest) error {
	location, err := p.router.Route(req)
	if err != nil {
		return err
	}
	// Router could not find a matching location, we can do nothing more
	if location == nil {
		log.Errorf("%s failed to route", req)
		return errors.FromStatus(http.StatusBadGateway)
	}
	response, err := location.RoundTrip(req)
	if response != nil {
		netutils.CopyHeaders(w.Header(), response.Header)
		w.WriteHeader(response.StatusCode)
		io.Copy(w, response.Body)
		defer response.Body.Close()
		return nil
	} else {
		return err
	}
}

// Helper function to reply with http errors
func (p *Proxy) replyError(err error, w http.ResponseWriter, req *http.Request) {
	// Discard the request body, so that clients can actually receive the response
	// otherwise they can only see lost connection
	// TODO: actually check this
	proxyError, ok := err.(errors.ProxyError)
	if !ok {
		proxyError = errors.FromStatus(http.StatusBadGateway)
	}

	io.Copy(ioutil.Discard, req.Body)
	statusCode, body, contentType := p.options.ErrorFormatter.Format(proxyError)
	w.Header().Set("Content-Type", contentType)
	w.WriteHeader(statusCode)
	w.Write(body)
}

func validateOptions(o Options) (Options, error) {
	if o.ErrorFormatter == nil {
		o.ErrorFormatter = &errors.JsonFormatter{}
	}
	return o, nil
}
<commit_msg>Improve timeout error logic<commit_after>// This package contains the reverse proxy that implements http.HandlerFunc
package vulcan

import (
	log "github.com/mailgun/gotools-log"
	"github.com/mailgun/vulcan/errors"
	"github.com/mailgun/vulcan/netutils"
	"github.com/mailgun/vulcan/request"
	"github.com/mailgun/vulcan/route"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"sync/atomic"
)

type Proxy struct {
	// Router selects a location for each request
	router route.Router
	// Options like ErrorFormatter
	options Options
	// Counter that is used to provide unique identifiers for requests
	lastRequestId int64
}

type Options struct {
	// Takes a status code and formats it into proxy response
	ErrorFormatter errors.Formatter
}

// Accepts requests, round trips it to the endpoint, and writes back the response.
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Record the request body so we can replay it on errors.
	body, err := netutils.NewBodyBuffer(r.Body)
	if err != nil || body == nil {
		log.Errorf("Request read error %s", err)
		if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
			p.replyError(errors.FromStatus(http.StatusRequestTimeout), w, r)
		} else {
			p.replyError(errors.FromStatus(http.StatusBadRequest), w, r)
		}
		return
	}
	defer body.Close()
	r.Body = body

	req := &request.BaseRequest{
		HttpRequest: r,
		Id:          atomic.AddInt64(&p.lastRequestId, 1),
		Body:        body,
	}

	err = p.proxyRequest(w, req)
	if err != nil {
		log.Errorf("%s failed: %s", req, err)
		p.replyError(err, w, r)
	}
}

// Creates a proxy with a given router
func NewProxy(router route.Router) (*Proxy, error) {
	return NewProxyWithOptions(router, Options{})
}

// Creates reverse proxy that acts like http request handler
func NewProxyWithOptions(router route.Router, o Options) (*Proxy, error) {
	o, err := validateOptions(o)
	if err != nil {
		return nil, err
	}

	p := &Proxy{
		options: o,
		router:  router,
	}
	return p, nil
}

func (p *Proxy) GetRouter() route.Router {
	return p.router
}

// Round trips the request to the selected location and writes back the response
func (p *Proxy) proxyRequest(w http.ResponseWriter, req *request.BaseRequest) error {
	location, err := p.router.Route(req)
	if err != nil {
		return err
	}
	// Router could not find a matching location, we can do nothing more
	if location == nil {
		log.Errorf("%s failed to route", req)
		return errors.FromStatus(http.StatusBadGateway)
	}
	response, err := location.RoundTrip(req)
	if response != nil {
		netutils.CopyHeaders(w.Header(), response.Header)
		w.WriteHeader(response.StatusCode)
		io.Copy(w, response.Body)
		defer response.Body.Close()
		return nil
	} else {
		return err
	}
}

// Helper function to reply with http errors
func (p *Proxy) replyError(err error, w http.ResponseWriter, req *http.Request) {
	// Discard the request body, so that clients can actually receive the response
	// otherwise they can only see lost connection
	// TODO: actually check this
	proxyError, ok := err.(errors.ProxyError)
	if !ok {
		proxyError = errors.FromStatus(http.StatusBadGateway)
	}

	io.Copy(ioutil.Discard, req.Body)
	statusCode, body, contentType := p.options.ErrorFormatter.Format(proxyError)
	w.Header().Set("Content-Type", contentType)
	w.WriteHeader(statusCode)
	w.Write(body)
}

func validateOptions(o Options) (Options, error) {
	if o.ErrorFormatter == nil {
		o.ErrorFormatter = &errors.JsonFormatter{}
	}
	return o, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"net"
)

func NewSinglePortProxy(host string, port int) (*SinglePortProxy, error) {
	portstr := fmt.Sprintf(":%d", port)

	//todo handle udp
	ln, err := net.Listen("tcp", portstr)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	log.Printf("New Proxy on Port %s for host %s", portstr, host)

	spp := SinglePortProxy{
		host:     host,
		port:     port,
		listener: ln,
	}

	go spp.listenForConnections()

	return &spp, nil
}

type SinglePortProxy struct {
	host     string
	port     int
	listener net.Listener
	stopped  bool
}

func (proxy *SinglePortProxy) listenForConnections() {
	for {
		defer func() {
			if r := recover(); r != nil {
				//it's ok, Accept probably stopped because port is closed
			}
		}()

		conn, err := proxy.listener.Accept()
		if err != nil {
			if proxy.stopped {
				break
			} else {
				panic(err)
			}
		}

		pc := proxyConnection{
			upstream:       conn,
			downstreamHost: proxy.host,
			downstreamPort: proxy.port,
		}

		go pc.establish()
	}
}

func (proxy SinglePortProxy) stopListen() {
	log.Printf("Stop listening to port %v\n", proxy.port)
	proxy.stopped = true
	proxy.listener.Close()
}

type proxyConnection struct {
	upstream       net.Conn
	downstream     net.Conn
	downstreamHost string
	downstreamPort int
}

func (pc *proxyConnection) establish() {

	defer pc.upstream.Close()

	var err error
	pc.downstream, err = net.Dial("tcp", fmt.Sprintf("%s:%d", pc.downstreamHost, pc.downstreamPort))
	if err != nil {
		panic(err)
	}
	defer pc.downstream.Close()

	//in parallel copy responses back
	done := make(chan bool)
	go copyContent(pc.downstream, pc.upstream, done)
	go copyContent(pc.upstream, pc.downstream, done)

	//wait for one channel to finish
	<-done
}

func copyContent(in net.Conn, out net.Conn, done chan bool) {
	io.Copy(out, in)
	done <- true
}
<commit_msg>Gentle Handling of connection refused.<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"net"
)

func NewSinglePortProxy(host string, port int) (*SinglePortProxy, error) {
	portstr := fmt.Sprintf(":%d", port)

	//todo handle udp
	ln, err := net.Listen("tcp", portstr)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	log.Printf("New Proxy on Port %s for host %s", portstr, host)

	spp := SinglePortProxy{
		host:     host,
		port:     port,
		listener: ln,
	}

	go spp.listenForConnections()

	return &spp, nil
}

type SinglePortProxy struct {
	host     string
	port     int
	listener net.Listener
	stopped  bool
}

func (proxy *SinglePortProxy) listenForConnections() {
	for {
		defer func() {
			if r := recover(); r != nil {
				//it's ok, Accept probably stopped because port is closed
			}
		}()

		conn, err := proxy.listener.Accept()
		if err != nil {
			if proxy.stopped {
				break
			} else {
				panic(err)
			}
		}

		pc := proxyConnection{
			upstream:       conn,
			downstreamHost: proxy.host,
			downstreamPort: proxy.port,
		}

		go pc.establish()
	}
}

func (proxy SinglePortProxy) stopListen() {
	log.Printf("Stop listening to port %v\n", proxy.port)
	proxy.stopped = true
	proxy.listener.Close()
}

type proxyConnection struct {
	upstream       net.Conn
	downstream     net.Conn
	downstreamHost string
	downstreamPort int
}

func (pc *proxyConnection) establish() {

	defer pc.upstream.Close()

	var err error
	pc.downstream, err = net.Dial("tcp", fmt.Sprintf("%s:%d", pc.downstreamHost, pc.downstreamPort))
	if err != nil {
		//TODO if it is connection refused pass this on to the client
		log.Println(err)
		return
	}
	defer pc.downstream.Close()

	//in parallel copy responses back
	done := make(chan bool)
	go copyContent(pc.downstream, pc.upstream, done)
	go copyContent(pc.upstream, pc.downstream, done)

	//wait for one channel to finish
	<-done
}

func copyContent(in net.Conn, out net.Conn, done chan bool) {
	io.Copy(out, in)
	done <- true
}
<|endoftext|>


<commit_before><commit_msg>add memory info<commit_after><|endoftext|>


<commit_before>/*
 *    Copyright (C) 2015 Stefan Luecke
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors: Stefan Luecke <glaxx@glaxx.net>
 */

package backend

import (
	log "github.com/Sirupsen/logrus"
	"github.com/emicklei/go-restful"
	//"html/template"
	"net/http"
	//"strconv"
	//"strings"
	"gopkg.in/mgo.v2/bson"
)

type User struct {
	ID    bson.ObjectId `bson:"_id,omitempty" json:"-"`
	Name  string
	EMail string
}

func NewUserService() *restful.WebService {
	service := new(restful.WebService)
	service.
		Path("/user").
		Consumes(restful.MIME_JSON, restful.MIME_XML).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	service.Route(service.GET("/{name}").To(GetUserByName))
	service.Route(service.GET("").To(ListUser))
	service.Route(service.PUT("").To(UpdateUser))
	service.Route(service.POST("").To(CreateUser))
	service.Route(service.DELETE("/{name}").To(DeleteUser))
	return service
}

func GetUserByName(request *restful.Request, response *restful.Response) {
	name := request.PathParameter("name")
	user, err := getUserByName(name)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		log.WithFields(log.Fields{"Error Msg": err}).
			Info(ERROR_INVALID_ID)
		return
	}
	response.WriteEntity(user)
}

func getUserByName(name string) (User, error) {
	res := User{}
	err := uCol.Find(bson.M{"name": name}).One(&res)
	return res, err
}

func ListUser(request *restful.Request, response *restful.Response) {
	usr, err := listUser()
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity(usr)
}

func listUser() ([]User, error) {
	usr := make([]User, 0)
	err := uCol.Find(nil).All(&usr)
	return usr, err
}

func UpdateUser(request *restful.Request, response *restful.Response) {
	usr := new(User)
	err := request.ReadEntity(usr)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_INPUT)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INVALID_INPUT)
		return
	}
	ex := checkUserExistance(usr)
	if ex {
		err = updateUser(usr)
		if err != nil {
			response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
			log.WithFields(log.Fields{"Err": err}).Warn("Error while updating User")
			return
		}
		response.WriteEntity(true)
		return
	} else {
		response.WriteErrorString(http.StatusNotFound, "User not found. Please register first")
		return
	}
}

func updateUser(usr *User) error {
	return uCol.Update(bson.M{"name": usr.Name}, usr)
}

func CreateUser(request *restful.Request, response *restful.Response) {
	usr := new(User)
	err := request.ReadEntity(usr)
	log.WithFields(log.Fields{"Username": usr.Name}).Info("Attempted user registration")
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_INPUT)
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INVALID_INPUT)
		return
	}

	ex := checkUserExistance(usr)

	if ex {
		response.WriteErrorString(http.StatusUnauthorized, "This username is not available")
		return
	}

	err = createUser(usr)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity("/user/" + usr.Name)
}

func checkUserExistance(usr *User) bool {
	temp := User{}
	err := uCol.Find(bson.M{"name": usr.Name}).One(&temp)
	if err != nil {
		if err.Error() == "not found" {
			return false
		} else {
			log.WithFields(log.Fields{"Err": err}).
				Debug("TODO: check more error codes here")
			return true // if something strange in the neighbourhood …
			// what you gonna do? - do not register a new user!
		}
	} else {
		return true
	}
	return true
}

func createUser(usr *User) error {
	return uCol.Insert(usr)
}

func DeleteUser(request *restful.Request, response *restful.Response) {
	name := request.PathParameter("name")
	log.WithFields(log.Fields{"Name": name}).Info("Got user DELETE request")
	err := deleteUser(name)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INTERNAL)
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		return
	}
	response.WriteEntity(true)
}

func deleteUser(name string) error {
	return uCol.Remove(bson.M{"name": name})
}
<commit_msg>Remove unneeded code<commit_after>/*
 *    Copyright (C) 2015 Stefan Luecke
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors: Stefan Luecke <glaxx@glaxx.net>
 */

package backend

import (
	log "github.com/Sirupsen/logrus"
	"github.com/emicklei/go-restful"
	//"html/template"
	"net/http"
	//"strconv"
	//"strings"
	"gopkg.in/mgo.v2/bson"
)

type User struct {
	ID    bson.ObjectId `bson:"_id,omitempty" json:"-"`
	Name  string
	EMail string
}

func NewUserService() *restful.WebService {
	service := new(restful.WebService)
	service.
		Path("/user").
		Consumes(restful.MIME_JSON, restful.MIME_XML).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	service.Route(service.GET("/{name}").To(GetUserByName))
	service.Route(service.GET("").To(ListUser))
	service.Route(service.PUT("").To(UpdateUser))
	service.Route(service.POST("").To(CreateUser))
	service.Route(service.DELETE("/{name}").To(DeleteUser))
	return service
}

func GetUserByName(request *restful.Request, response *restful.Response) {
	name := request.PathParameter("name")
	user, err := getUserByName(name)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_ID)
		log.WithFields(log.Fields{"Error Msg": err}).
			Info(ERROR_INVALID_ID)
		return
	}
	response.WriteEntity(user)
}

func getUserByName(name string) (User, error) {
	res := User{}
	err := uCol.Find(bson.M{"name": name}).One(&res)
	return res, err
}

func ListUser(request *restful.Request, response *restful.Response) {
	usr, err := listUser()
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity(usr)
}

func listUser() ([]User, error) {
	usr := make([]User, 0)
	err := uCol.Find(nil).All(&usr)
	return usr, err
}

func UpdateUser(request *restful.Request, response *restful.Response) {
	usr := new(User)
	err := request.ReadEntity(usr)
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_INPUT)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INVALID_INPUT)
		return
	}
	ex := checkUserExistance(usr)
	if ex {
		err = updateUser(usr)
		if err != nil {
			response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
			log.WithFields(log.Fields{"Err": err}).Warn("Error while updating User")
			return
		}
		response.WriteEntity(true)
		return
	} else {
		response.WriteErrorString(http.StatusNotFound, "User not found. Please register first")
		return
	}
}

func updateUser(usr *User) error {
	return uCol.Update(bson.M{"name": usr.Name}, usr)
}

func CreateUser(request *restful.Request, response *restful.Response) {
	usr := new(User)
	err := request.ReadEntity(usr)
	log.WithFields(log.Fields{"Username": usr.Name}).Info("Attempted user registration")
	if err != nil {
		response.WriteErrorString(http.StatusBadRequest, ERROR_INVALID_INPUT)
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INVALID_INPUT)
		return
	}

	ex := checkUserExistance(usr)

	if ex {
		response.WriteErrorString(http.StatusUnauthorized, "This username is not available")
		return
	}

	err = createUser(usr)
	if err != nil {
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		log.WithFields(log.Fields{"Error Msg": err}).Warn(ERROR_INTERNAL)
		return
	}
	response.WriteEntity("/user/" + usr.Name)
}

func checkUserExistance(usr *User) bool {
	temp := User{}
	err := uCol.Find(bson.M{"name": usr.Name}).One(&temp)
	if err != nil {
		if err.Error() == "not found" {
			return false
		} else {
			log.WithFields(log.Fields{"Err": err}).
				Debug("TODO: check more error codes here")
			return true // if something strange in the neighbourhood …
			// what you gonna do? - do not register a new user!
		}
	}
	return true
}

func createUser(usr *User) error {
	return uCol.Insert(usr)
}

func DeleteUser(request *restful.Request, response *restful.Response) {
	name := request.PathParameter("name")
	log.WithFields(log.Fields{"Name": name}).Info("Got user DELETE request")
	err := deleteUser(name)
	if err != nil {
		log.WithFields(log.Fields{"Error Msg": err}).Info(ERROR_INTERNAL)
		response.WriteErrorString(http.StatusInternalServerError, ERROR_INTERNAL)
		return
	}
	response.WriteEntity(true)
}

func deleteUser(name string) error {
	return uCol.Remove(bson.M{"name": name})
}
<|endoftext|>


<commit_before>// Copyright 2020 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://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.

// Neither windows nor windows_test
// +build !windows,!windows_test

package cmdtest

import (
	"fmt"

	"github.com/google/renameio"
)

func createTempFile(filename string) (tempFile, error) {
	fmt.Println("RENAMEIO")
	return renameio.TempFile("", filename)
}
<commit_msg>remove debug output<commit_after>// Copyright 2020 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://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.

// Neither windows nor windows_test
// +build !windows,!windows_test

package cmdtest

import (
	"github.com/google/renameio"
)

func createTempFile(filename string) (tempFile, error) {
	return renameio.TempFile("", filename)
}
<|endoftext|>


<commit_before><commit_msg>validate port-forwards by attempting to bind to port<commit_after><|endoftext|>


<commit_before>package main

import (
	"github.com/technoweenie/grohl"
	"os"
	"path/filepath"
	"sync"
	"time"
)

const (
	supervisorReaderChunkSize = 64
)

type Supervisor struct {
	files       []FileConfiguration
	clients     []Client
	snapshotter Snapshotter

	// Optional settings
	SpoolSize int

	// How frequently to glob for new files that may have appeared
	GlobRefresh time.Duration
	globTimer   *time.Timer

	readerPool  *FileReaderPool
	readyChunks chan *readyChunk
	// A separate channel for retries to avoid deadlocking when multiple clients
	// need to retry.
	retryChunks chan *readyChunk

	stopRequest chan interface{}
	routineWg   sync.WaitGroup
}

type readyChunk struct {
	Chunk         []*FileData
	LockedReaders []*FileReader
}

func NewSupervisor(files []FileConfiguration, clients []Client, snapshotter Snapshotter) *Supervisor {
	spoolSize := 1024

	return &Supervisor{
		files:       files,
		clients:     clients,
		snapshotter: snapshotter,

		// Can be adjusted by clients later before calling Start
		SpoolSize:   spoolSize,
		GlobRefresh: 10 * time.Second,
	}
}

// Start pulls things together and plays match-maker.
func (s *Supervisor) Start() {
	s.stopRequest = make(chan interface{})

	s.readerPool = NewFileReaderPool()
	s.readyChunks = make(chan *readyChunk, len(s.clients))
	s.retryChunks = make(chan *readyChunk, len(s.clients))

	s.routineWg.Add(1)
	go func() {
		s.populateReaderPool()
		s.routineWg.Done()
	}()

	s.routineWg.Add(1)
	go func() {
		s.populateReadyChunks()
		s.routineWg.Done()
	}()

	for _, client := range s.clients {
		s.routineWg.Add(1)
		go func(client Client) {
			s.sendReadyChunksToClient(client)
			s.routineWg.Done()
		}(client)
	}
}

// Stop stops the supervisor cleanly, making sure all progress has been snapshotted
// before exiting.
func (s *Supervisor) Stop() {
	close(s.stopRequest)
	s.routineWg.Wait()
}

// Reads chunks from available file readers, putting together ready 'chunks'
// that can be sent to clients.
func (s *Supervisor) populateReadyChunks() {
	backoff := &ExponentialBackoff{Minimum: 50 * time.Millisecond, Maximum: 5000 * time.Millisecond}
	for {
		available, locked := s.readerPool.Counts()
		GlobalStatistics.UpdateFileReaderPoolStatistics(available, locked)

		currentChunk := &readyChunk{
			Chunk:         make([]*FileData, 0),
			LockedReaders: make([]*FileReader, 0),
		}

		for len(currentChunk.Chunk) < s.SpoolSize {
			if reader := s.readerPool.LockNext(); reader != nil {
				select {
				case <-s.stopRequest:
					return
				case chunk, ok := <-reader.C:
					if ok {
						currentChunk.Chunk = append(currentChunk.Chunk, chunk...)
						currentChunk.LockedReaders = append(currentChunk.LockedReaders, reader)

						if len(chunk) > 0 {
							if hwm := chunk[len(chunk)-1].HighWaterMark; hwm != nil {
								GlobalStatistics.SetFilePosition(hwm.FilePath, hwm.Position)
							}
						}
					} else {
						// The reader hit EOF or another error. Remove it and it'll get
						// picked up by populateReaderPool again if it still needs to be
						// read.
						s.readerPool.Remove(reader)
						GlobalStatistics.DeleteFileStatistics(reader.FilePath())
					}
				default:
					// The reader didn't have anything queued up for us. Unlock the
					// reader and move on.
					s.readerPool.Unlock(reader)
				}
			} else {
				// If there are no more readers, send the chunk ASAP so we can get
				// the next chunk in line
				grohl.Log(grohl.Data{"msg": "no readers available", "resolution": "sending current chunk"})
				break
			}
		}

		if len(currentChunk.Chunk) > 0 {
			select {
			case <-s.stopRequest:
				return
			case s.readyChunks <- currentChunk:
				backoff.Reset()
			}
		} else {
			select {
			case <-s.stopRequest:
				return
			case <-time.After(backoff.Next()):
				grohl.Log(grohl.Data{"msg": "no lines available to send", "resolution": "backing off"})
			}
		}
	}
}

// sendReadyChunksToClient reads from the readyChunks channel for a particular
// client, sending those chunks to the remote system. This function is also
// responsible for snapshotting progress and unlocking the readers after it has
// successfully sent.
func (s *Supervisor) sendReadyChunksToClient(client Client) {
	backoff := &ExponentialBackoff{Minimum: 50 * time.Millisecond, Maximum: 5000 * time.Millisecond}
	for {
		var readyChunk *readyChunk
		select {
		case <-s.stopRequest:
			return
		case readyChunk = <-s.retryChunks:
			// got a retry chunk; use it
		default:
			// pull from the default readyChunk queue
			select {
			case <-s.stopRequest:
				return
			case readyChunk = <-s.readyChunks:
				// got a chunk
			}
		}

		if readyChunk != nil {
			GlobalStatistics.SetClientStatus(client.Name(), clientStatusSending)
			if err := s.sendChunk(client, readyChunk.Chunk); err != nil {
				grohl.Report(err, grohl.Data{"msg": "failed to send chunk", "resolution": "retrying"})
				GlobalStatistics.SetClientStatus(client.Name(), clientStatusRetrying)

				// Put the chunk back on the queue for someone else to try
				select {
				case <-s.stopRequest:
					return
				case s.retryChunks <- readyChunk:
					// continue
				}

				// Backoff
				select {
				case <-s.stopRequest:
					return
				case <-time.After(backoff.Next()):
					// continue
				}
			} else {
				backoff.Reset()
				GlobalStatistics.IncrementClientLinesSent(client.Name(), len(readyChunk.Chunk))

				// Snapshot progress
				if err := s.acknowledgeChunk(readyChunk.Chunk); err != nil {
					grohl.Report(err, grohl.Data{"msg": "failed to acknowledge progress", "resolution": "skipping"})
				}

				s.readerPool.UnlockAll(readyChunk.LockedReaders)
			}
		}
	}
}

func (s *Supervisor) sendChunk(client Client, chunk []*FileData) error {
	lines := make([]Data, 0, len(chunk))
	for _, fileData := range chunk {
		lines = append(lines, fileData.Data)
	}

	return client.Send(lines)
}

func (s *Supervisor) acknowledgeChunk(chunk []*FileData) error {
	marks := make([]*HighWaterMark, 0, len(chunk))
	for _, fileData := range chunk {
		marks = append(marks, fileData.HighWaterMark)
	}

	err := s.snapshotter.SetHighWaterMarks(marks)
	if err == nil {
		// Update statistics
		for _, mark := range marks {
			GlobalStatistics.SetFileSnapshotPosition(mark.FilePath, mark.Position)
		}
	}

	return err
}

// populateReaderPool periodically globs for new files or files that previously
// hit EOF and creates file readers for them.
func (s *Supervisor) populateReaderPool() {
	logger := grohl.NewContext(grohl.Data{"ns": "Supervisor", "fn": "populateReaderPool"})

	timer := time.NewTimer(0)
	for {
		select {
		case <-s.stopRequest:
			return
		case <-timer.C:
			logTimer := logger.Timer(grohl.Data{})
			for _, config := range s.files {
				for _, path := range config.Paths {
					matches, err := filepath.Glob(path)
					if err != nil {
						logger.Report(err, grohl.Data{"path": path, "msg": "failed to glob", "resolution": "skipping path"})
						continue
					}

					for _, filePath := range matches {
						if err = s.startFileReader(filePath, config.Fields); err != nil {
							logger.Report(err, grohl.Data{"path": path, "filePath": filePath, "msg": "failed to start reader", "resolution": "skipping file"})
						}
					}
				}
			}
			logTimer.Finish()
			timer.Reset(s.GlobRefresh)
		}
	}
}

// startFileReader starts an individual file reader at a given path, if one
// isn't already running.
func (s *Supervisor) startFileReader(filePath string, fields map[string]string) error {
	// There's already a reader in the pool for this path
	if s.readerPool.IsPathInPool(filePath) {
		return nil
	}

	highWaterMark, err := s.snapshotter.HighWaterMark(filePath)
	if err != nil {
		return err
	}

	file, err := os.Open(filePath)
	if err != nil {
		return err
	}

	_, err = file.Seek(highWaterMark.Position, os.SEEK_SET)
	if err != nil {
		file.Close()
		return err
	}

	reader, err := NewFileReader(file, fields, supervisorReaderChunkSize)
	if err != nil {
		file.Close()
		return err
	}

	s.readerPool.Add(reader)
	return nil
}
<commit_msg>Adds logging for EOF<commit_after>package main

import (
	"github.com/technoweenie/grohl"
	"os"
	"path/filepath"
	"sync"
	"time"
)

const (
	supervisorReaderChunkSize = 64
)

type Supervisor struct {
	files       []FileConfiguration
	clients     []Client
	snapshotter Snapshotter

	// Optional settings
	SpoolSize int

	// How frequently to glob for new files that may have appeared
	GlobRefresh time.Duration
	globTimer   *time.Timer

	readerPool  *FileReaderPool
	readyChunks chan *readyChunk
	// A separate channel for retries to avoid deadlocking when multiple clients
	// need to retry.
	retryChunks chan *readyChunk

	stopRequest chan interface{}
	routineWg   sync.WaitGroup
}

type readyChunk struct {
	Chunk         []*FileData
	LockedReaders []*FileReader
}

func NewSupervisor(files []FileConfiguration, clients []Client, snapshotter Snapshotter) *Supervisor {
	spoolSize := 1024

	return &Supervisor{
		files:       files,
		clients:     clients,
		snapshotter: snapshotter,

		// Can be adjusted by clients later before calling Start
		SpoolSize:   spoolSize,
		GlobRefresh: 10 * time.Second,
	}
}

// Start pulls things together and plays match-maker.
func (s *Supervisor) Start() {
	s.stopRequest = make(chan interface{})

	s.readerPool = NewFileReaderPool()
	s.readyChunks = make(chan *readyChunk, len(s.clients))
	s.retryChunks = make(chan *readyChunk, len(s.clients))

	s.routineWg.Add(1)
	go func() {
		s.populateReaderPool()
		s.routineWg.Done()
	}()

	s.routineWg.Add(1)
	go func() {
		s.populateReadyChunks()
		s.routineWg.Done()
	}()

	for _, client := range s.clients {
		s.routineWg.Add(1)
		go func(client Client) {
			s.sendReadyChunksToClient(client)
			s.routineWg.Done()
		}(client)
	}
}

// Stop stops the supervisor cleanly, making sure all progress has been snapshotted
// before exiting.
func (s *Supervisor) Stop() {
	close(s.stopRequest)
	s.routineWg.Wait()
}

// Reads chunks from available file readers, putting together ready 'chunks'
// that can be sent to clients.
func (s *Supervisor) populateReadyChunks() {
	logger := grohl.NewContext(grohl.Data{"ns": "Supervisor", "fn": "populateReadyChunks"})

	backoff := &ExponentialBackoff{Minimum: 50 * time.Millisecond, Maximum: 5000 * time.Millisecond}
	for {
		available, locked := s.readerPool.Counts()
		GlobalStatistics.UpdateFileReaderPoolStatistics(available, locked)

		currentChunk := &readyChunk{
			Chunk:         make([]*FileData, 0),
			LockedReaders: make([]*FileReader, 0),
		}

		for len(currentChunk.Chunk) < s.SpoolSize {
			if reader := s.readerPool.LockNext(); reader != nil {
				select {
				case <-s.stopRequest:
					return
				case chunk := <-reader.C:
					if chunk != nil {
						currentChunk.Chunk = append(currentChunk.Chunk, chunk...)
						currentChunk.LockedReaders = append(currentChunk.LockedReaders, reader)

						if len(chunk) > 0 {
							if hwm := chunk[len(chunk)-1].HighWaterMark; hwm != nil {
								GlobalStatistics.SetFilePosition(hwm.FilePath, hwm.Position)
							}
						}
					} else {
						// The reader hit EOF or another error. Remove it and it'll get
						// picked up by populateReaderPool again if it still needs to be
						// read.
						logger.Log(grohl.Data{"status": "EOF", "file": reader.FilePath()})

						s.readerPool.Remove(reader)
						GlobalStatistics.DeleteFileStatistics(reader.FilePath())
					}
				default:
					// The reader didn't have anything queued up for us. Unlock the
					// reader and move on.
					s.readerPool.Unlock(reader)
				}
			} else {
				// If there are no more readers, send the chunk ASAP so we can get
				// the next chunk in line
				logger.Log(grohl.Data{"msg": "no readers available", "resolution": "sending current chunk"})
				break
			}
		}

		if len(currentChunk.Chunk) > 0 {
			select {
			case <-s.stopRequest:
				return
			case s.readyChunks <- currentChunk:
				backoff.Reset()
			}
		} else {
			select {
			case <-s.stopRequest:
				return
			case <-time.After(backoff.Next()):
				grohl.Log(grohl.Data{"msg": "no lines available to send", "resolution": "backing off"})
			}
		}
	}
}

// sendReadyChunksToClient reads from the readyChunks channel for a particular
// client, sending those chunks to the remote system. This function is also
// responsible for snapshotting progress and unlocking the readers after it has
// successfully sent.
func (s *Supervisor) sendReadyChunksToClient(client Client) {
	backoff := &ExponentialBackoff{Minimum: 50 * time.Millisecond, Maximum: 5000 * time.Millisecond}
	for {
		var readyChunk *readyChunk
		select {
		case <-s.stopRequest:
			return
		case readyChunk = <-s.retryChunks:
			// got a retry chunk; use it
		default:
			// pull from the default readyChunk queue
			select {
			case <-s.stopRequest:
				return
			case readyChunk = <-s.readyChunks:
				// got a chunk
			}
		}

		if readyChunk != nil {
			GlobalStatistics.SetClientStatus(client.Name(), clientStatusSending)
			if err := s.sendChunk(client, readyChunk.Chunk); err != nil {
				grohl.Report(err, grohl.Data{"msg": "failed to send chunk", "resolution": "retrying"})
				GlobalStatistics.SetClientStatus(client.Name(), clientStatusRetrying)

				// Put the chunk back on the queue for someone else to try
				select {
				case <-s.stopRequest:
					return
				case s.retryChunks <- readyChunk:
					// continue
				}

				// Backoff
				select {
				case <-s.stopRequest:
					return
				case <-time.After(backoff.Next()):
					// continue
				}
			} else {
				backoff.Reset()
				GlobalStatistics.IncrementClientLinesSent(client.Name(), len(readyChunk.Chunk))

				// Snapshot progress
				if err := s.acknowledgeChunk(readyChunk.Chunk); err != nil {
					grohl.Report(err, grohl.Data{"msg": "failed to acknowledge progress", "resolution": "skipping"})
				}

				s.readerPool.UnlockAll(readyChunk.LockedReaders)
			}
		}
	}
}

func (s *Supervisor) sendChunk(client Client, chunk []*FileData) error {
	lines := make([]Data, 0, len(chunk))
	for _, fileData := range chunk {
		lines = append(lines, fileData.Data)
	}

	return client.Send(lines)
}

func (s *Supervisor) acknowledgeChunk(chunk []*FileData) error {
	marks := make([]*HighWaterMark, 0, len(chunk))
	for _, fileData := range chunk {
		marks = append(marks, fileData.HighWaterMark)
	}

	err := s.snapshotter.SetHighWaterMarks(marks)
	if err == nil {
		// Update statistics
		for _, mark := range marks {
			GlobalStatistics.SetFileSnapshotPosition(mark.FilePath, mark.Position)
		}
	}

	return err
}

// populateReaderPool periodically globs for new files or files that previously
// hit EOF and creates file readers for them.
func (s *Supervisor) populateReaderPool() {
	logger := grohl.NewContext(grohl.Data{"ns": "Supervisor", "fn": "populateReaderPool"})

	timer := time.NewTimer(0)
	for {
		select {
		case <-s.stopRequest:
			return
		case <-timer.C:
			logTimer := logger.Timer(grohl.Data{})
			for _, config := range s.files {
				for _, path := range config.Paths {
					matches, err := filepath.Glob(path)
					if err != nil {
						logger.Report(err, grohl.Data{"path": path, "msg": "failed to glob", "resolution": "skipping path"})
						continue
					}

					for _, filePath := range matches {
						if err = s.startFileReader(filePath, config.Fields); err != nil {
							logger.Report(err, grohl.Data{"path": path, "filePath": filePath, "msg": "failed to start reader", "resolution": "skipping file"})
						}
					}
				}
			}
			logTimer.Finish()
			timer.Reset(s.GlobRefresh)
		}
	}
}

// startFileReader starts an individual file reader at a given path, if one
// isn't already running.
func (s *Supervisor) startFileReader(filePath string, fields map[string]string) error {
	// There's already a reader in the pool for this path
	if s.readerPool.IsPathInPool(filePath) {
		return nil
	}

	highWaterMark, err := s.snapshotter.HighWaterMark(filePath)
	if err != nil {
		return err
	}

	file, err := os.Open(filePath)
	if err != nil {
		return err
	}

	_, err = file.Seek(highWaterMark.Position, os.SEEK_SET)
	if err != nil {
		file.Close()
		return err
	}

	reader, err := NewFileReader(file, fields, supervisorReaderChunkSize)
	if err != nil {
		file.Close()
		return err
	}

	s.readerPool.Add(reader)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

const (
	SW_ID_FindSw    = 1
	SW_ID_FindSwAck = 2
)

const DISPLAY_NAME_LENGTH = 33

type SwApi_FindSwAck struct {
	Cmd         uint32
	CommandPort uint16
	TcpPort     uint16
	PreviewPort uint16
	Dummy       uint16
	IsWiFiAP    uint32
	DisplayName [DISPLAY_NAME_LENGTH]byte
}

type AddrOfVSw struct {
	address     string
	displayName string
}

var LE = binary.LittleEndian

func read(conn net.PacketConn) (SwApi_FindSwAck, net.Addr, error) {
	var pkt SwApi_FindSwAck
	conn.SetReadDeadline(time.Now().Add(3 * time.Second))
	buf := make([]byte, 4096)
	len, peer, err := conn.ReadFrom(buf)
	if err != nil {
		return pkt, peer, err
	}
	//log.Println(len, "bytes read from", peer)
	buffer := bytes.NewBuffer(buf[:len])
	err = binary.Read(buffer, LE, &pkt)
	if err != nil {
		log.Fatal(err)
	}

	//log.Printf("adr=%s\n", peer.String())
	//log.Printf("cmd=%d\n", pkt.Cmd)
	//log.Printf("commandPort=%d\n", pkt.CommandPort)
	//log.Printf("tcpPort=%d\n", pkt.TcpPort)
	//log.Printf("previewPort=%d\n", pkt.PreviewPort)
	//log.Printf("isWiFiAP=%08x\n", pkt.IsWiFiAP)
	//log.Printf("displayName=%s\n", pkt.DisplayName)
	//log.Printf("\n")
	return pkt, peer, nil
}

func find0() []AddrOfVSw {
	conn, err := net.ListenPacket("udp", ":0")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	dst, err := net.ResolveUDPAddr("udp", "224.0.0.250:8888")
	if err != nil {
		log.Fatal(err)
	}

	if _, err := conn.WriteTo([]byte{1, 0, 0, 0}, dst); err != nil {
		log.Fatal(err)
	}
	pkts := []AddrOfVSw{}
	for {
		pkt, peer, err := read(conn)
		if err != nil {
			break
		}
		a := AddrOfVSw{}
		a.address = strings.Split(peer.String(), ":")[0]
		n := bytes.Index(pkt.DisplayName[:], []byte{0})
		a.displayName = string(pkt.DisplayName[:n])
		pkts = append(pkts, a)
	}
	return pkts
}

func main() {
	items := find0()
	for _, v := range items {
		fmt.Printf("%s:\t%s\n", v.address, v.displayName)
	}
}
<commit_msg>find0: Check timeout<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

const (
	SW_ID_FindSw    = 1
	SW_ID_FindSwAck = 2
)

const DISPLAY_NAME_LENGTH = 33

type SwApi_FindSwAck struct {
	Cmd         uint32
	CommandPort uint16
	TcpPort     uint16
	PreviewPort uint16
	Dummy       uint16
	IsWiFiAP    uint32
	DisplayName [DISPLAY_NAME_LENGTH]byte
}

type AddrOfVSw struct {
	address     string
	displayName string
}

var LE = binary.LittleEndian

func read(conn net.PacketConn) (SwApi_FindSwAck, net.Addr, error) {
	var pkt SwApi_FindSwAck
	conn.SetReadDeadline(time.Now().Add(3 * time.Second))
	buf := make([]byte, 4096)
	len, peer, err := conn.ReadFrom(buf)
	if err != nil {
		if opErr, ok := err.(*net.OpError); ok {
			if opErr.Timeout() {
				return pkt, peer, err
			}
		}
		log.Fatal(err)
	}
	//log.Println(len, "bytes read from", peer)
	buffer := bytes.NewBuffer(buf[:len])
	err = binary.Read(buffer, LE, &pkt)
	if err != nil {
		log.Fatal(err)
	}

	//log.Printf("adr=%s\n", peer.String())
	//log.Printf("cmd=%d\n", pkt.Cmd)
	//log.Printf("commandPort=%d\n", pkt.CommandPort)
	//log.Printf("tcpPort=%d\n", pkt.TcpPort)
	//log.Printf("previewPort=%d\n", pkt.PreviewPort)
	//log.Printf("isWiFiAP=%08x\n", pkt.IsWiFiAP)
	//log.Printf("displayName=%s\n", pkt.DisplayName)
	//log.Printf("\n")
	return pkt, peer, nil
}

func find0() []AddrOfVSw {
	conn, err := net.ListenPacket("udp", ":0")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	dst, err := net.ResolveUDPAddr("udp", "224.0.0.250:8888")
	if err != nil {
		log.Fatal(err)
	}

	if _, err := conn.WriteTo([]byte{1, 0, 0, 0}, dst); err != nil {
		log.Fatal(err)
	}
	pkts := []AddrOfVSw{}
	for {
		pkt, peer, err := read(conn)
		if err != nil {
			break
		}
		a := AddrOfVSw{}
		a.address = strings.Split(peer.String(), ":")[0]
		n := bytes.Index(pkt.DisplayName[:], []byte{0})
		a.displayName = string(pkt.DisplayName[:n])
		pkts = append(pkts, a)
	}
	return pkts
}

func main() {
	items := find0()
	for _, v := range items {
		fmt.Printf("%s:\t%s\n", v.address, v.displayName)
	}
}
<|endoftext|>


<commit_before>package system

import (
	"fmt"
	redis "go-server/cache"
	"net/http"
	"time"

	"github.com/shirou/gopsutil/cpu"
	"golang.org/x/net/websocket"
)

/**
  This will read system memory
**/
func readcpu() {
	v, _ := cpu.Percent(0, false)
	redis.Client.LPush("cpuusage", v[0])
}

func CPUIterator() {
	for {
		time.Sleep(time.Second)
		readcpu()
	}
}

func EchoCPU(w http.ResponseWriter, r *http.Request) {
	// fmt.Print("this is called")
	// c, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	// if err != nil {
	// 	log.Print("upgrade:", err)
	// 	return
	// }
	// defer c.Close()
	// for {
	// 	mt, message, err := c.ReadMessage()
	// 	if err != nil {
	// 		log.Println("read:", err)
	// 		break
	// 	}
	// 	log.Printf("recv: %s", message)
	// 	err = c.WriteMessage(mt, message)
	// 	if err != nil {
	// 		log.Println("write:", err)
	// 		break
	// 	}
	// }
}

func EchoWS(ws *websocket.Conn) {
	var err error

	for {
		var reply string

		if err = websocket.Message.Receive(ws, &reply); err != nil {
			fmt.Println("Can't receive")
			break
		}

		fmt.Println("Received back from client: " + reply)

		msg := reply
		fmt.Println("Sending to client: " + msg)

		switch msg {
		case "cpu":
			for {
				time.Sleep(time.Second)
				per, error := redis.Client.RPop("cpuusage").Result()
				if error != nil {
					fmt.Print("some error")
				} else {
					fmt.Println(per)
					if err = websocket.Message.Send(ws, per); err != nil {
						fmt.Println("Can't send", err)
						break
					}
				}
			}
		default:
			if err = websocket.Message.Send(ws, msg); err != nil {
				fmt.Println("Can't send")
				break
			}
		}
	}
}
<commit_msg>adding json to send data;<commit_after>package system

import (
	"fmt"
	redis "go-server/cache"
	"net/http"
	"strconv"
	"time"

	"github.com/shirou/gopsutil/cpu"
	"golang.org/x/net/websocket"
)

/**
  This will read system memory
**/
func readcpu() {
	v, _ := cpu.Percent(0, false)
	redis.Client.LPush("cpuusage", v[0])
}

func CPUIterator() {
	for {
		time.Sleep(time.Second)
		readcpu()
	}
}

func EchoCPU(w http.ResponseWriter, r *http.Request) {
	// fmt.Print("this is called")
	// c, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	// if err != nil {
	// 	log.Print("upgrade:", err)
	// 	return
	// }
	// defer c.Close()
	// for {
	// 	mt, message, err := c.ReadMessage()
	// 	if err != nil {
	// 		log.Println("read:", err)
	// 		break
	// 	}
	// 	log.Printf("recv: %s", message)
	// 	err = c.WriteMessage(mt, message)
	// 	if err != nil {
	// 		log.Println("write:", err)
	// 		break
	// 	}
	// }
}

type message struct {
	// the json tag means this will serialize as a lowercased field
	TimeStamp time.Time `json:"timeStamp"`
	Perct     float64   `json:"perct"`
}

func EchoWS(ws *websocket.Conn) {
	var err error

	for {
		var reply string

		if err = websocket.Message.Receive(ws, &reply); err != nil {
			fmt.Println("Can't receive")
			break
		}

		fmt.Println("Received back from client: " + reply)

		msg := reply
		fmt.Println("Sending to client: " + msg)

		switch msg {
		case "cpu":
			for {
				time.Sleep(time.Second)
				per, error := redis.Client.RPop("cpuusage").Result()
				if error != nil {
					fmt.Print("some error")
				} else {
					per, er := strconv.ParseFloat(per, 64)
					value := message{
						Perct:     per,
						TimeStamp: time.Now(),
					}
					// jsonValue, eerr := json.Marshal(value)
					if er == nil {
						// fmt.Println(value)
						if err = websocket.JSON.Send(ws, value); err != nil {
							fmt.Println("Can't send", err)
							break
						}
					}
				}
			}
		default:
			if err = websocket.Message.Send(ws, msg); err != nil {
				fmt.Println("Can't send")
				break
			}
		}
	}
}
<|endoftext|>