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

package gcbench

import (
	"fmt"
	"math"
	"os"
	"reflect"
	"sort"
	"time"
)

type Metric struct {
	Label string
	Fn    func(GCTrace) float64
	Check func(name string, value float64)
}

var metrics = []Metric{
	{"GCs/sec", gcsPerSec, nil},
	{"95%ile-ns/sweepTerm", distMetric(nsPerSweepTerm, 0.95), warnIf(">=", 5e6)},
	{"95%ile-ns/markTerm", distMetric(nsPerMarkTerm, 0.95), warnIf(">=", 5e6)},
	{"MB-marked/CPU/sec", markedMBPerCPUSec, nil},
	{"95%ile-heap-overshoot", distMetric(heapOvershoot, 0.95), warnIf(">", 0)},
	{"5%ile-heap-overshoot", distMetric(heapOvershoot, 0.05), warnIf("<", -.2)},
	{"95%ile-CPU-util", distMetric(cpuUtil, 0.95), warnIf(">", .3)},
}

func gcsPerSec(t GCTrace) float64 {
	t = t.WithoutForced()
	if len(t) == 0 {
		return 0
	}
	return float64(len(t)) / t[len(t)-1].End.Seconds()
}

func nsPerSweepTerm(t GCTrace) distribution {
	t = t.WithoutForced()
	return distribution(float64s(extract(t, "ClockSweepTerm").([]time.Duration)))
}

func nsPerMarkTerm(t GCTrace) distribution {
	t = t.WithoutForced()
	return distribution(float64s(extract(t, "ClockMarkTerm").([]time.Duration)))
}

func markedMBPerCPUSec(t GCTrace) float64 {
	t = t.WithoutForced()
	// Compute average overall rate.
	markTotal := sum(float64s(extract(t, "CPUMark").([]time.Duration)))
	markedTotal := sum(float64s(extract(t, "HeapMarked").([]Bytes)))
	return markedTotal * 1e9 / (markTotal * 1024 * 1024)
}

func heapOvershoot(t GCTrace) distribution {
	t = t.WithoutForced()
	var over distribution
	actual := extract(t, "HeapActual").([]Bytes)
	goal := extract(t, "HeapGoal").([]Bytes)
	for i := range actual {
		// Ignore very small heaps.
		if goal[i] < 10*MB {
			continue
		}
		over = append(over, float64(actual[i])/float64(goal[i])-1)
	}
	return over
}

func cpuUtil(t GCTrace) distribution {
	t = t.WithoutForced()
	var util distribution
	cpuAssist := extract(t, "CPUAssist").([]time.Duration)
	cpuBackground := extract(t, "CPUBackground").([]time.Duration)
	clockMark := extract(t, "ClockMark").([]time.Duration)
	procs := extract(t, "Procs").([]int)
	for i := range cpuAssist {
		if clockMark[i] != 0 {
			util = append(util, (float64(cpuAssist[i])+float64(cpuBackground[i]))/(float64(clockMark[i])*float64(procs[i])))
		}
	}
	return util
}

type distribution []float64

// distMetric transforms a distribution metric into a point metric at
// the specified percentile.
func distMetric(f func(t GCTrace) distribution, pct float64) func(t GCTrace) float64 {
	return func(t GCTrace) float64 {
		return pctile([]float64(f(t)), pct)
	}
}

// extract takes a slice []T where T is a struct and returns a slice
// of T.name.
func extract(slice interface{}, name string) interface{} {
	sv := reflect.ValueOf(slice)
	len := sv.Len()

	field, ok := sv.Type().Elem().FieldByName(name)
	if !ok {
		panic("unknown field: " + name)
	}
	out := reflect.MakeSlice(reflect.SliceOf(field.Type), len, len)
	for i := 0; i < len; i++ {
		out.Index(i).Set(sv.Index(i).FieldByIndex(field.Index))
	}
	return out.Interface()
}

var float64Type = reflect.TypeOf(float64(0.0))

// float64s converts a slice of integer or floating-point values to
// []float64.
func float64s(slice interface{}) []float64 {
	sv := reflect.ValueOf(slice)
	len := sv.Len()
	out := make([]float64, len)
	for i := 0; i < len; i++ {
		out[i] = sv.Index(i).Convert(float64Type).Float()
	}
	return out
}

func pctile(xs []float64, pct float64) float64 {
	sort.Float64s(xs)
	if len(xs) == 0 {
		return math.NaN()
	}
	return xs[int(float64(len(xs)-1)*pct)]
}

func sum(xs []float64) float64 {
	sum := 0.0
	for _, x := range xs {
		sum += x
	}
	return sum
}

// warnIf returns a metric check function that compares the metric
// value to the threshold using the given comparison and prints a
// warning if the comparison is true.
func warnIf(compare string, threshold float64) func(string, float64) {
	var fn func(a, b float64) bool
	switch compare {
	case ">":
		fn = func(a, b float64) bool { return a > b }
	case ">=":
		fn = func(a, b float64) bool { return a >= b }
	case "<=":
		fn = func(a, b float64) bool { return a <= b }
	case "<":
		fn = func(a, b float64) bool { return a < b }
	default:
		panic(fmt.Sprintf("unknown comparison operator %q", compare))
	}
	return func(name string, value float64) {
		if fn(value, threshold) {
			fmt.Fprintf(os.Stderr, "Warning: %s %s %s %s\n", sigfigs(value), name, compare, sigfigs(threshold))
		}
	}
}
<commit_msg>gcbench: be more lax about CPU utilization alert<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gcbench

import (
	"fmt"
	"math"
	"os"
	"reflect"
	"sort"
	"time"
)

type Metric struct {
	Label string
	Fn    func(GCTrace) float64
	Check func(name string, value float64)
}

var metrics = []Metric{
	{"GCs/sec", gcsPerSec, nil},
	{"95%ile-ns/sweepTerm", distMetric(nsPerSweepTerm, 0.95), warnIf(">=", 5e6)},
	{"95%ile-ns/markTerm", distMetric(nsPerMarkTerm, 0.95), warnIf(">=", 5e6)},
	{"MB-marked/CPU/sec", markedMBPerCPUSec, nil},
	{"95%ile-heap-overshoot", distMetric(heapOvershoot, 0.95), warnIf(">", 0)},
	{"5%ile-heap-overshoot", distMetric(heapOvershoot, 0.05), warnIf("<", -.2)},
	{"95%ile-CPU-util", distMetric(cpuUtil, 0.95), warnIf(">", .5)},
}

func gcsPerSec(t GCTrace) float64 {
	t = t.WithoutForced()
	if len(t) == 0 {
		return 0
	}
	return float64(len(t)) / t[len(t)-1].End.Seconds()
}

func nsPerSweepTerm(t GCTrace) distribution {
	t = t.WithoutForced()
	return distribution(float64s(extract(t, "ClockSweepTerm").([]time.Duration)))
}

func nsPerMarkTerm(t GCTrace) distribution {
	t = t.WithoutForced()
	return distribution(float64s(extract(t, "ClockMarkTerm").([]time.Duration)))
}

func markedMBPerCPUSec(t GCTrace) float64 {
	t = t.WithoutForced()
	// Compute average overall rate.
	markTotal := sum(float64s(extract(t, "CPUMark").([]time.Duration)))
	markedTotal := sum(float64s(extract(t, "HeapMarked").([]Bytes)))
	return markedTotal * 1e9 / (markTotal * 1024 * 1024)
}

func heapOvershoot(t GCTrace) distribution {
	t = t.WithoutForced()
	var over distribution
	actual := extract(t, "HeapActual").([]Bytes)
	goal := extract(t, "HeapGoal").([]Bytes)
	for i := range actual {
		// Ignore very small heaps.
		if goal[i] < 10*MB {
			continue
		}
		over = append(over, float64(actual[i])/float64(goal[i])-1)
	}
	return over
}

func cpuUtil(t GCTrace) distribution {
	t = t.WithoutForced()
	var util distribution
	cpuAssist := extract(t, "CPUAssist").([]time.Duration)
	cpuBackground := extract(t, "CPUBackground").([]time.Duration)
	clockMark := extract(t, "ClockMark").([]time.Duration)
	procs := extract(t, "Procs").([]int)
	for i := range cpuAssist {
		if clockMark[i] != 0 {
			util = append(util, (float64(cpuAssist[i])+float64(cpuBackground[i]))/(float64(clockMark[i])*float64(procs[i])))
		}
	}
	return util
}

type distribution []float64

// distMetric transforms a distribution metric into a point metric at
// the specified percentile.
func distMetric(f func(t GCTrace) distribution, pct float64) func(t GCTrace) float64 {
	return func(t GCTrace) float64 {
		return pctile([]float64(f(t)), pct)
	}
}

// extract takes a slice []T where T is a struct and returns a slice
// of T.name.
func extract(slice interface{}, name string) interface{} {
	sv := reflect.ValueOf(slice)
	len := sv.Len()

	field, ok := sv.Type().Elem().FieldByName(name)
	if !ok {
		panic("unknown field: " + name)
	}
	out := reflect.MakeSlice(reflect.SliceOf(field.Type), len, len)
	for i := 0; i < len; i++ {
		out.Index(i).Set(sv.Index(i).FieldByIndex(field.Index))
	}
	return out.Interface()
}

var float64Type = reflect.TypeOf(float64(0.0))

// float64s converts a slice of integer or floating-point values to
// []float64.
func float64s(slice interface{}) []float64 {
	sv := reflect.ValueOf(slice)
	len := sv.Len()
	out := make([]float64, len)
	for i := 0; i < len; i++ {
		out[i] = sv.Index(i).Convert(float64Type).Float()
	}
	return out
}

func pctile(xs []float64, pct float64) float64 {
	sort.Float64s(xs)
	if len(xs) == 0 {
		return math.NaN()
	}
	return xs[int(float64(len(xs)-1)*pct)]
}

func sum(xs []float64) float64 {
	sum := 0.0
	for _, x := range xs {
		sum += x
	}
	return sum
}

// warnIf returns a metric check function that compares the metric
// value to the threshold using the given comparison and prints a
// warning if the comparison is true.
func warnIf(compare string, threshold float64) func(string, float64) {
	var fn func(a, b float64) bool
	switch compare {
	case ">":
		fn = func(a, b float64) bool { return a > b }
	case ">=":
		fn = func(a, b float64) bool { return a >= b }
	case "<=":
		fn = func(a, b float64) bool { return a <= b }
	case "<":
		fn = func(a, b float64) bool { return a < b }
	default:
		panic(fmt.Sprintf("unknown comparison operator %q", compare))
	}
	return func(name string, value float64) {
		if fn(value, threshold) {
			fmt.Fprintf(os.Stderr, "Warning: %s %s %s %s\n", sigfigs(value), name, compare, sigfigs(threshold))
		}
	}
}
<|endoftext|>


<commit_before>package setup

import "github.com/mholt/caddy/middleware"

func TLS(c *Controller) (middleware.Middleware, error) {
	c.TLS.Enabled = true

	for c.Next() {
		if !c.NextArg() {
			return nil, c.ArgErr()
		}
		c.TLS.Certificate = c.Val()

		if !c.NextArg() {
			return nil, c.ArgErr()
		}
		c.TLS.Key = c.Val()
	}

	return nil, nil
}
<commit_msg>Disable tls if the port is http<commit_after>package setup

import "github.com/mholt/caddy/middleware"

func TLS(c *Controller) (middleware.Middleware, error) {
	c.TLS.Enabled = c.Port != "http"

	for c.Next() {
		if !c.NextArg() {
			return nil, c.ArgErr()
		}
		c.TLS.Certificate = c.Val()

		if !c.NextArg() {
			return nil, c.ArgErr()
		}
		c.TLS.Key = c.Val()
	}

	return nil, nil
}
<|endoftext|>


<commit_before>package geo_skeleton

import (
	"fmt"
	"log"
	"math"
	"os"
	"time"
)

import (
	"github.com/paulmach/go.geojson"
	"github.com/sjsafranek/SkeletonDB"
)

// https://gist.github.com/DavidVaini/10308388
func Round(f float64) float64 {
	return math.Floor(f + .5)
}

func RoundToPrecision(f float64, places int) float64 {
	shift := math.Pow(10, float64(places))
	return Round(f*shift) / shift
}

// DB application Database
var (
	COMMIT_LOG_FILE string = "geo_skeleton_commit.log"
)

func NewGeoSkeletonDB(db_file string) Database {
	var geoDb = Database{
		File:  db_file,
		Table: "GeoJsonDatasources",
		DB:    skeleton.Database{File: db_file}}
	geoDb.Init()
	return geoDb
}

// Database strust for application.
type Database struct {
	Table            string
	File             string
	commit_log_queue chan string
	Precision        int
	DB               skeleton.Database
}

func (self Database) Init() {

	self.DB.Init()

	// Set initial data precision
	self.Precision = 8

	// start commit log
	go self.startCommitLog()

	// default table
	if "" == self.Table {
		self.Table = "GeoJSONLayers"
	}

	conn := self.DB.Connect()
	defer conn.Close()

	err := self.DB.CreateTable(conn, self.Table)
	if nil != err {
		panic(err)
	}
}

// Starts Database commit log
func (self *Database) startCommitLog() {
	self.commit_log_queue = make(chan string, 10000)
	// open file to write database commit log
	COMMIT_LOG, err := os.OpenFile(COMMIT_LOG_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		log.Println(err)
	}
	defer COMMIT_LOG.Close()
	// read from chan and write to file
	for {
		if len(self.commit_log_queue) > 0 {
			line := <-self.commit_log_queue
			if _, err := COMMIT_LOG.WriteString(line + "\n"); err != nil {
				panic(err)
			}
		} else {
			time.Sleep(1000 * time.Millisecond)
		}
	}
}

// CommitQueueLength returns length of database commit_log_queue
// @returns int
func (self *Database) CommitQueueLength() int {
	return len(self.commit_log_queue)
}

// NewLayer creates new datasource layer
// @returns string - datasource id
// @returns Error
// TODO: RENAME TO NewDatasource
func (self *Database) NewLayer() (string, error) {
	// create geojson
	datasource_id, _ := NewUUID()
	geojs := geojson.NewFeatureCollection()
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return "", nil
	}
	self.commit_log_queue <- `{"method": "create_datasource", "data": { "datasource": "` + datasource_id + `", "layer": ` + string(value) + `}}`
	// Insert layer into database
	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}
	return datasource_id, err
}

// InsertLayer inserts layer into database
// @param datasource {string}
// @param geojs {Geojson}
// @returns Error
func (self *Database) InsertLayer(datasource_id string, geojs *geojson.FeatureCollection) error {
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return err
	}
	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}

	return err
}

// GetLayer returns layer from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayer(datasource_id string) (*geojson.FeatureCollection, error) {
	val, err := self.DB.Select(self.Table, datasource_id)
	if err != nil {
		return nil, err
	}
	if "" == string(val) {
		return nil, fmt.Errorf("Datasource not found")
	}
	// Read to struct
	geojs, err := geojson.UnmarshalFeatureCollection(val)
	if err != nil {
		return geojs, err
	}
	return geojs, nil
}

// GetLayers returns all datasource_ids from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayers() ([]string, error) {
	val, err := self.DB.SelectAll(self.Table)
	if err != nil {
		return nil, err
	}
	return val, nil
}

// DeleteLayer deletes layer from database
// @param datasource {string}
// @returns Error
func (self *Database) DeleteLayer(datasource_id string) error {
	self.commit_log_queue <- `{"method": "delete_layer", "data": { "datasource": "` + datasource_id + `"}}`
	err := self.DB.Remove(datasource_id, self.Table)
	return err
}

func (self *Database) normalizeGeometry(feat *geojson.Feature) (*geojson.Feature, error) {
	// FIT TO 7 - 8 DECIMAL PLACES OF PRECISION
	if nil == feat.Geometry {
		return nil, fmt.Errorf("Feature has no geometry!")
	}

	switch feat.Geometry.Type {

	case geojson.GeometryPoint:
		// []float64
		feat.Geometry.Point[0] = RoundToPrecision(feat.Geometry.Point[0], self.Precision)
		feat.Geometry.Point[1] = RoundToPrecision(feat.Geometry.Point[1], self.Precision)

	case geojson.GeometryMultiPoint:
		// [][]float64
		for i := range feat.Geometry.MultiPoint {
			for j := range feat.Geometry.MultiPoint[i] {
				feat.Geometry.MultiPoint[i][j] = RoundToPrecision(feat.Geometry.MultiPoint[i][j], self.Precision)
			}
		}

	case geojson.GeometryLineString:
		// [][]float64
		for i := range feat.Geometry.LineString {
			for j := range feat.Geometry.LineString[i] {
				feat.Geometry.LineString[i][j] = RoundToPrecision(feat.Geometry.LineString[i][j], self.Precision)
			}
		}

	case geojson.GeometryMultiLineString:
		// [][][]float64
		for i := range feat.Geometry.MultiLineString {
			for j := range feat.Geometry.MultiLineString[i] {
				for k := range feat.Geometry.MultiLineString[i][j] {
					feat.Geometry.MultiLineString[i][j][k] = RoundToPrecision(feat.Geometry.MultiLineString[i][j][k], self.Precision)
				}
			}
		}

	case geojson.GeometryPolygon:
		// [][][]float64
		for i := range feat.Geometry.Polygon {
			for j := range feat.Geometry.Polygon[i] {
				for k := range feat.Geometry.Polygon[i][j] {
					feat.Geometry.Polygon[i][j][k] = RoundToPrecision(feat.Geometry.Polygon[i][j][k], self.Precision)
				}
			}
		}

	case geojson.GeometryMultiPolygon:
		// [][][][]float64
		for i := range feat.Geometry.MultiPolygon {
			log.Printf("%v\n", feat.Geometry.MultiPolygon[i])
		}

	}

	/*
		//case GeometryCollection:
		//	geo.Geometries = g.Geometries
		//	// log.Printf("%v\n", feat.Geometry.Geometries)

	*/
	return feat, nil
}

func (self *Database) normalizeProperties(feat *geojson.Feature, featCollection *geojson.FeatureCollection) *geojson.Feature {

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	if 0 == len(featCollection.Features) {
		return feat
	}
	// Standardize properties for new feature
	for j := range featCollection.Features[0].Properties {
		if _, ok := feat.Properties[j]; !ok {
			feat.Properties[j] = ""
		}
	}

	// Standardize properties for existing features
	for i := range featCollection.Features {
		for j := range feat.Properties {
			if _, ok := featCollection.Features[i].Properties[j]; !ok {
				featCollection.Features[i].Properties[j] = ""
			}
		}
	}

	return feat
}

// InsertFeature adds feature to layer. Updates layer in Database
// @param datasource {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) InsertFeature(datasource_id string, feat *geojson.Feature) error {

	if nil == feat {
		return fmt.Errorf("feature value is <nil>!")
	}

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	// Apply required columns
	now := time.Now().Unix()

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	feat.Properties["is_active"] = true
	feat.Properties["is_deleted"] = false
	feat.Properties["date_created"] = now
	feat.Properties["date_modified"] = now
	feat.Properties["geo_id"] = fmt.Sprintf("%v", now)

	feat, err = self.normalizeGeometry(feat)
	if nil != err {
		return err
	}

	feat = self.normalizeProperties(feat, featCollection)

	// Write to commit log
	value, err := feat.MarshalJSON()
	if err != nil {
		return err
	}
	self.commit_log_queue <- `{"method": "insert_feature", "data": { "datasource": "` + datasource_id + `", "feature": ` + string(value) + `}}`

	// Add new feature to layer
	featCollection.AddFeature(feat)

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}

// EditFeature Edits feature in layer. Updates layer in Database
// @param datasource {string}
// @param geo_id {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) EditFeature(datasource_id string, geo_id string, feat *geojson.Feature) error {

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	feature_exists := false

	for i := range featCollection.Features {
		if geo_id == fmt.Sprintf("%v", featCollection.Features[i].Properties["geo_id"]) {

			now := time.Now().Unix()
			feat.Properties["date_modified"] = now

			feat, err = self.normalizeGeometry(feat)
			if nil != err {
				return err
			}

			feat = self.normalizeProperties(feat, featCollection)
			featCollection.Features[i] = feat
			// Write to commit log
			value, err := feat.MarshalJSON()
			if err != nil {
				return err
			}
			self.commit_log_queue <- `{"method": "edit_feature", "data": { "datasource": "` + datasource_id + `", "geo_id": "` + geo_id + `", "feature": ` + string(value) + `}}`
			feature_exists = true
		}
	}

	if !feature_exists {
		return fmt.Errorf("feature not found!")
	}

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}
<commit_msg>commit log issue<commit_after>package geo_skeleton

import (
	"fmt"
	"log"
	"math"
	"os"
	"time"
)

import (
	"github.com/paulmach/go.geojson"
	"github.com/sjsafranek/SkeletonDB"
)

// https://gist.github.com/DavidVaini/10308388
func Round(f float64) float64 {
	return math.Floor(f + .5)
}

func RoundToPrecision(f float64, places int) float64 {
	shift := math.Pow(10, float64(places))
	return Round(f*shift) / shift
}

// DB application Database
var (
	COMMIT_LOG_FILE string = "geo_skeleton_commit.log"
)

func NewGeoSkeletonDB(db_file string) Database {
	var geoDb = Database{
		File:  db_file,
		Table: "GeoJsonDatasources",
		DB:    skeleton.Database{File: db_file}}
	geoDb.Init()
	return geoDb
}

// Database strust for application.
type Database struct {
	Table            string
	File             string
	commit_log_queue chan string
	Precision        int
	DB               skeleton.Database
}

func (self Database) Init() {

	self.DB.Init()

	// Set initial data precision
	self.Precision = 8

	// start commit log
	go self.StartCommitLog()

	// default table
	if "" == self.Table {
		self.Table = "GeoJSONLayers"
	}

	conn := self.DB.Connect()
	defer conn.Close()

	err := self.DB.CreateTable(conn, self.Table)
	if nil != err {
		panic(err)
	}
}

// Starts Database commit log
func (self *Database) StartCommitLog() {
	self.commit_log_queue = make(chan string, 10000)
	// open file to write database commit log
	COMMIT_LOG, err := os.OpenFile(COMMIT_LOG_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		log.Println(err)
	}
	defer COMMIT_LOG.Close()
	// read from chan and write to file
	for {
		if len(self.commit_log_queue) > 0 {
			line := <-self.commit_log_queue
			if _, err := COMMIT_LOG.WriteString(line + "\n"); err != nil {
				panic(err)
			}
		} else {
			time.Sleep(1000 * time.Millisecond)
		}
	}
}

// CommitQueueLength returns length of database commit_log_queue
// @returns int
func (self *Database) CommitQueueLength() int {
	return len(self.commit_log_queue)
}

// NewLayer creates new datasource layer
// @returns string - datasource id
// @returns Error
// TODO: RENAME TO NewDatasource
func (self *Database) NewLayer() (string, error) {
	// create geojson
	datasource_id, _ := NewUUID()
	geojs := geojson.NewFeatureCollection()
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return "", nil
	}
	self.commit_log_queue <- `{"method": "create_datasource", "data": { "datasource": "` + datasource_id + `", "layer": ` + string(value) + `}}`
	// Insert layer into database
	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}
	return datasource_id, err
}

// InsertLayer inserts layer into database
// @param datasource {string}
// @param geojs {Geojson}
// @returns Error
func (self *Database) InsertLayer(datasource_id string, geojs *geojson.FeatureCollection) error {
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return err
	}
	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}

	return err
}

// GetLayer returns layer from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayer(datasource_id string) (*geojson.FeatureCollection, error) {
	val, err := self.DB.Select(self.Table, datasource_id)
	if err != nil {
		return nil, err
	}
	if "" == string(val) {
		return nil, fmt.Errorf("Datasource not found")
	}
	// Read to struct
	geojs, err := geojson.UnmarshalFeatureCollection(val)
	if err != nil {
		return geojs, err
	}
	return geojs, nil
}

// GetLayers returns all datasource_ids from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayers() ([]string, error) {
	val, err := self.DB.SelectAll(self.Table)
	if err != nil {
		return nil, err
	}
	return val, nil
}

// DeleteLayer deletes layer from database
// @param datasource {string}
// @returns Error
func (self *Database) DeleteLayer(datasource_id string) error {
	self.commit_log_queue <- `{"method": "delete_layer", "data": { "datasource": "` + datasource_id + `"}}`
	err := self.DB.Remove(datasource_id, self.Table)
	return err
}

func (self *Database) normalizeGeometry(feat *geojson.Feature) (*geojson.Feature, error) {
	// FIT TO 7 - 8 DECIMAL PLACES OF PRECISION
	if nil == feat.Geometry {
		return nil, fmt.Errorf("Feature has no geometry!")
	}

	switch feat.Geometry.Type {

	case geojson.GeometryPoint:
		// []float64
		feat.Geometry.Point[0] = RoundToPrecision(feat.Geometry.Point[0], self.Precision)
		feat.Geometry.Point[1] = RoundToPrecision(feat.Geometry.Point[1], self.Precision)

	case geojson.GeometryMultiPoint:
		// [][]float64
		for i := range feat.Geometry.MultiPoint {
			for j := range feat.Geometry.MultiPoint[i] {
				feat.Geometry.MultiPoint[i][j] = RoundToPrecision(feat.Geometry.MultiPoint[i][j], self.Precision)
			}
		}

	case geojson.GeometryLineString:
		// [][]float64
		for i := range feat.Geometry.LineString {
			for j := range feat.Geometry.LineString[i] {
				feat.Geometry.LineString[i][j] = RoundToPrecision(feat.Geometry.LineString[i][j], self.Precision)
			}
		}

	case geojson.GeometryMultiLineString:
		// [][][]float64
		for i := range feat.Geometry.MultiLineString {
			for j := range feat.Geometry.MultiLineString[i] {
				for k := range feat.Geometry.MultiLineString[i][j] {
					feat.Geometry.MultiLineString[i][j][k] = RoundToPrecision(feat.Geometry.MultiLineString[i][j][k], self.Precision)
				}
			}
		}

	case geojson.GeometryPolygon:
		// [][][]float64
		for i := range feat.Geometry.Polygon {
			for j := range feat.Geometry.Polygon[i] {
				for k := range feat.Geometry.Polygon[i][j] {
					feat.Geometry.Polygon[i][j][k] = RoundToPrecision(feat.Geometry.Polygon[i][j][k], self.Precision)
				}
			}
		}

	case geojson.GeometryMultiPolygon:
		// [][][][]float64
		for i := range feat.Geometry.MultiPolygon {
			log.Printf("%v\n", feat.Geometry.MultiPolygon[i])
		}

	}

	/*
		//case GeometryCollection:
		//	geo.Geometries = g.Geometries
		//	// log.Printf("%v\n", feat.Geometry.Geometries)

	*/
	return feat, nil
}

func (self *Database) normalizeProperties(feat *geojson.Feature, featCollection *geojson.FeatureCollection) *geojson.Feature {

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	if 0 == len(featCollection.Features) {
		return feat
	}
	// Standardize properties for new feature
	for j := range featCollection.Features[0].Properties {
		if _, ok := feat.Properties[j]; !ok {
			feat.Properties[j] = ""
		}
	}

	// Standardize properties for existing features
	for i := range featCollection.Features {
		for j := range feat.Properties {
			if _, ok := featCollection.Features[i].Properties[j]; !ok {
				featCollection.Features[i].Properties[j] = ""
			}
		}
	}

	return feat
}

// InsertFeature adds feature to layer. Updates layer in Database
// @param datasource {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) InsertFeature(datasource_id string, feat *geojson.Feature) error {

	if nil == feat {
		return fmt.Errorf("feature value is <nil>!")
	}

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	// Apply required columns
	now := time.Now().Unix()

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	feat.Properties["is_active"] = true
	feat.Properties["is_deleted"] = false
	feat.Properties["date_created"] = now
	feat.Properties["date_modified"] = now
	feat.Properties["geo_id"] = fmt.Sprintf("%v", now)

	feat, err = self.normalizeGeometry(feat)
	if nil != err {
		return err
	}

	feat = self.normalizeProperties(feat, featCollection)

	// Write to commit log
	value, err := feat.MarshalJSON()
	if err != nil {
		return err
	}
	self.commit_log_queue <- `{"method": "insert_feature", "data": { "datasource": "` + datasource_id + `", "feature": ` + string(value) + `}}`

	// Add new feature to layer
	featCollection.AddFeature(feat)

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}

// EditFeature Edits feature in layer. Updates layer in Database
// @param datasource {string}
// @param geo_id {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) EditFeature(datasource_id string, geo_id string, feat *geojson.Feature) error {

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	feature_exists := false

	for i := range featCollection.Features {
		if geo_id == fmt.Sprintf("%v", featCollection.Features[i].Properties["geo_id"]) {

			now := time.Now().Unix()
			feat.Properties["date_modified"] = now

			feat, err = self.normalizeGeometry(feat)
			if nil != err {
				return err
			}

			feat = self.normalizeProperties(feat, featCollection)
			featCollection.Features[i] = feat
			// Write to commit log
			value, err := feat.MarshalJSON()
			if err != nil {
				return err
			}
			self.commit_log_queue <- `{"method": "edit_feature", "data": { "datasource": "` + datasource_id + `", "geo_id": "` + geo_id + `", "feature": ` + string(value) + `}}`
			feature_exists = true
		}
	}

	if !feature_exists {
		return fmt.Errorf("feature not found!")
	}

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}
<|endoftext|>


<commit_before>package geom

type MultiPoint struct {
	layout     Layout
	stride     int
	flatCoords []float64
}

var _ T = &MultiPoint{}

func NewMultiPoint(layout Layout) *MultiPoint {
	return &MultiPoint{
		layout:     layout,
		stride:     layout.Stride(),
		flatCoords: nil,
	}
}

func NewMultiPointFlat(layout Layout, flatCoords []float64) *MultiPoint {
	return &MultiPoint{
		layout:     layout,
		stride:     layout.Stride(),
		flatCoords: flatCoords,
	}
}

func (mp *MultiPoint) Clone() *MultiPoint {
	flatCoords := make([]float64, len(mp.flatCoords))
	copy(flatCoords, mp.flatCoords)
	return &MultiPoint{
		layout:     mp.layout,
		stride:     mp.stride,
		flatCoords: flatCoords,
	}
}

func (mp *MultiPoint) Bounds() *Bounds {
	return NewBounds().extendFlatCoords(mp.flatCoords, 0, len(mp.flatCoords), mp.stride)
}

func (mp *MultiPoint) Coords() [][]float64 {
	return inflate1(mp.flatCoords, 0, len(mp.flatCoords), mp.stride)
}

func (mp *MultiPoint) Ends() []int {
	return nil
}

func (mp *MultiPoint) Endss() [][]int {
	return nil
}

func (mp *MultiPoint) FlatCoords() []float64 {
	return mp.flatCoords
}

func (mp *MultiPoint) Layout() Layout {
	return mp.layout
}

func (mp *MultiPoint) MustSetCoords(coords1 [][]float64) *MultiPoint {
	if err := mp.SetCoords(coords1); err != nil {
		panic(err)
	}
	return mp
}

func (mp *MultiPoint) NumPoints() int {
	return len(mp.flatCoords) / mp.stride
}

func (mp *MultiPoint) Point(i int) *Point {
	return &Point{
		layout:     mp.layout,
		stride:     mp.stride,
		flatCoords: mp.flatCoords[i*mp.stride : (i+1)*mp.stride],
	}
}

func (mp *MultiPoint) Push(ps ...*Point) error {
	for _, p := range ps {
		if p.layout != mp.layout {
			return ErrLayoutMismatch{Got: p.layout, Want: mp.layout}
		}
		mp.flatCoords = append(mp.flatCoords, p.flatCoords...)
	}
	return nil
}

func (mp *MultiPoint) SetCoords(coords1 [][]float64) error {
	var err error
	if mp.flatCoords, err = deflate1(mp.flatCoords[:0], coords1, mp.stride); err != nil {
		return err
	}
	return nil
}

func (mp *MultiPoint) Stride() int {
	return mp.stride
}
<commit_msg>Add MultiPoint.Coord and NumCoords<commit_after>package geom

type MultiPoint struct {
	layout     Layout
	stride     int
	flatCoords []float64
}

var _ T = &MultiPoint{}

func NewMultiPoint(layout Layout) *MultiPoint {
	return &MultiPoint{
		layout:     layout,
		stride:     layout.Stride(),
		flatCoords: nil,
	}
}

func NewMultiPointFlat(layout Layout, flatCoords []float64) *MultiPoint {
	return &MultiPoint{
		layout:     layout,
		stride:     layout.Stride(),
		flatCoords: flatCoords,
	}
}

func (mp *MultiPoint) Clone() *MultiPoint {
	flatCoords := make([]float64, len(mp.flatCoords))
	copy(flatCoords, mp.flatCoords)
	return &MultiPoint{
		layout:     mp.layout,
		stride:     mp.stride,
		flatCoords: flatCoords,
	}
}

func (mp *MultiPoint) Bounds() *Bounds {
	return NewBounds().extendFlatCoords(mp.flatCoords, 0, len(mp.flatCoords), mp.stride)
}

func (mp *MultiPoint) Coord(i int) []float64 {
	return mp.flatCoords[i*mp.stride : (i+1)*mp.stride]
}

func (mp *MultiPoint) Coords() [][]float64 {
	return inflate1(mp.flatCoords, 0, len(mp.flatCoords), mp.stride)
}

func (mp *MultiPoint) Ends() []int {
	return nil
}

func (mp *MultiPoint) Endss() [][]int {
	return nil
}

func (mp *MultiPoint) FlatCoords() []float64 {
	return mp.flatCoords
}

func (mp *MultiPoint) Layout() Layout {
	return mp.layout
}

func (mp *MultiPoint) MustSetCoords(coords1 [][]float64) *MultiPoint {
	if err := mp.SetCoords(coords1); err != nil {
		panic(err)
	}
	return mp
}

func (mp *MultiPoint) NumCoords() int {
	return len(mp.flatCoords) / mp.stride
}

func (mp *MultiPoint) NumPoints() int {
	return len(mp.flatCoords) / mp.stride
}

func (mp *MultiPoint) Point(i int) *Point {
	return &Point{
		layout:     mp.layout,
		stride:     mp.stride,
		flatCoords: mp.flatCoords[i*mp.stride : (i+1)*mp.stride],
	}
}

func (mp *MultiPoint) Push(ps ...*Point) error {
	for _, p := range ps {
		if p.layout != mp.layout {
			return ErrLayoutMismatch{Got: p.layout, Want: mp.layout}
		}
		mp.flatCoords = append(mp.flatCoords, p.flatCoords...)
	}
	return nil
}

func (mp *MultiPoint) SetCoords(coords1 [][]float64) error {
	var err error
	if mp.flatCoords, err = deflate1(mp.flatCoords[:0], coords1, mp.stride); err != nil {
		return err
	}
	return nil
}

func (mp *MultiPoint) Stride() int {
	return mp.stride
}
<|endoftext|>


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

/*
Package assert 0.1.0

This package helps to compare values of undefined types like interface{}.
Convenient using with JSON values (json.Number/float64, string, bool, nil).
The package is intended not only for testing purposes.
The package allows compare ambiguous values between each other.

Example 1:

	package main

	import (
		"encoding/json"
		"fmt"

		"github.com/takama/assert"
	)

	func main() {
		exampleJSON := `
		{
			"personA": {
				"name": "John",
				"age": 22,
				"height": 178,
				"weight": 82.59,
				"married": true,
				"hobby": ["fishing", "dancing", "cooking"]
			},
			"personB": {
				"name": "Jack",
				"age": 22,
				"height": 170.22,
				"weight": 65,
				"married": false,
				"hobby": ["photography", "singing", "cooking"]
			}
	  	}`

		persons := make(map[string]interface{}, 0)
		if err := json.Unmarshal([]byte(exampleJSON), &persons); err == nil {
			personA := persons["personA"].(map[string]interface{})
			personB := persons["personB"].(map[string]interface{})
			fmt.Println(
				"Comparing of a personal details:",
				personA["name"], "and", personB["name"],
			)
			if assert.Equal(personA["age"], personB["age"]) {
				fmt.Println("Persons of the same age")
			}
			if assert.GreaterThan(personA["height"], personB["height"]) {
				fmt.Println(personA["name"], "higher than", personB["name"])
			}
			if assert.LessThan(personB["weight"], personA["weight"]) {
				fmt.Println(personB["name"], "weighs less than", personA["name"])
			}
			if assert.NotEqual(personA["married"], personB["married"]) {
				fmt.Println("Persons have a different marital status")
			}
			if assert.In("cooking", personA["hobby"]) &&
				assert.In("cooking", personB["hobby"]) {
				fmt.Println("Both persons like to cook")
			}
			if assert.In("dancing", personA["hobby"]) &&
				assert.NotIn("dancing", personB["hobby"]) {
				fmt.Println("Only", personA["name"], "likes to dance")
			}
		}
	}

A simple Assert package for interface/json values
*/
package assert

import (
	"encoding/json"
)

// Equal checks if values equal to each other
func Equal(left, right interface{}) bool {
	return isCompareTrue(equal, left, right)
}

// NotEqual checks if values not equal to each other
func NotEqual(left, right interface{}) bool {
	return isCompareTrue(notEqual, left, right)
}

// LessThan checks if value "left" less than value "right"
func LessThan(left, right interface{}) bool {
	return isCompareTrue(lessThan, left, right)
}

// GreaterThan checks if value "left" greater than value "right"
func GreaterThan(left, right interface{}) bool {
	return isCompareTrue(greaterThan, left, right)
}

// LessEqual checks if value "left" less than value "right" or equal to it
func LessEqual(left, right interface{}) bool {
	return isCompareTrue(lessEqual, left, right)
}

// GreaterEqual checks if value "left" greater than value "right" or equal to it
func GreaterEqual(left, right interface{}) bool {
	return isCompareTrue(greaterEqual, left, right)
}

// In checks if array value "right" contains value "left"
func In(left, right interface{}) bool {
	return isCompareTrue(in, left, right)
}

// In checks if array value "right" not contains value "left"
func NotIn(left, right interface{}) bool {
	return isCompareTrue(notIn, left, right)
}

const (
	equal = iota
	notEqual
	lessThan
	greaterThan
	lessEqual
	greaterEqual
	in
	notIn
)

func isCompareTrue(comparison uint8, valueLeft, valueRight interface{}) bool {
	if valueLeft == nil && valueRight == nil && comparison == equal {
		return true
	}
	switch vLeft := valueLeft.(type) {
	case json.Number:
		if left, err := vLeft.Float64(); err == nil {
			switch vRight := valueRight.(type) {
			case json.Number:
				if right, err := vRight.Float64(); err == nil {
					switch comparison {
					case equal:
						if left == right {
							return true
						}
					case notEqual:
						if left != right {
							return true
						}
					case lessThan:
						if left < right {
							return true
						}
					case greaterThan:
						if left > right {
							return true
						}
					case lessEqual:
						if left <= right {
							return true
						}
					case greaterEqual:
						if left >= right {
							return true
						}
					}
				}
			case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
				right := float(valueRight)
				switch comparison {
				case equal:
					if left == right {
						return true
					}
				case notEqual:
					if left != right {
						return true
					}
				case lessThan:
					if left < right {
						return true
					}
				case greaterThan:
					if left > right {
						return true
					}
				case lessEqual:
					if left <= right {
						return true
					}
				case greaterEqual:
					if left >= right {
						return true
					}
				}
			case []interface{}:
				switch comparison {
				case in:
					for _, v := range vRight {
						switch value := v.(type) {
						case json.Number:
							if item, err := value.Float64(); err == nil && item == left {
								return true
							}
						case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
							item := float(v)
							if item == left {
								return true
							}
						}
					}
				case notIn:
					for _, v := range vRight {
						switch value := v.(type) {
						case json.Number:
							if item, err := value.Float64(); err == nil && item == left {
								return false
							}
						case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
							item := float(v)
							if item == left {
								return false
							}
						}
					}
					return true
				}
			case []json.Number:
				switch comparison {
				case in:
					for _, value := range vRight {
						if item, err := value.Float64(); err == nil && item == left {
							return true
						}
					}
				case notIn:
					for _, value := range vRight {
						if item, err := value.Float64(); err == nil && item == left {
							return false
						}
					}
					return true
				}
			}
		}
	case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
		left := float(valueLeft)
		switch vRight := valueRight.(type) {
		case json.Number:
			if right, err := vRight.Float64(); err == nil {
				switch comparison {
				case equal:
					if left == right {
						return true
					}
				case notEqual:
					if left != right {
						return true
					}
				case lessThan:
					if left < right {
						return true
					}
				case greaterThan:
					if left > right {
						return true
					}
				case lessEqual:
					if left <= right {
						return true
					}
				case greaterEqual:
					if left >= right {
						return true
					}
				}
			}
		case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
			right := float(valueRight)
			switch comparison {
			case equal:
				if left == right {
					return true
				}
			case notEqual:
				if left != right {
					return true
				}
			case lessThan:
				if left < right {
					return true
				}
			case greaterThan:
				if left > right {
					return true
				}
			case lessEqual:
				if left <= right {
					return true
				}
			case greaterEqual:
				if left >= right {
					return true
				}
			}
		case []interface{}:
			switch comparison {
			case in:
				for _, v := range vRight {
					switch value := v.(type) {
					case json.Number:
						if item, err := value.Float64(); err == nil && item == left {
							return true
						}
					case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
						item := float(v)
						if item == left {
							return true
						}
					}
				}
			case notIn:
				for _, v := range vRight {
					switch value := v.(type) {
					case json.Number:
						if item, err := value.Float64(); err == nil && item == left {
							return false
						}
					case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
						item := float(v)
						if item == left {
							return false
						}
					}
				}
				return true
			}
		case []float32, []float64, []int, []uint, []int8, []uint8, []int16, []uint16, []int32, []uint32, []int64, []uint64:
			vr := floatArray(valueRight)
			switch comparison {
			case in:
				for _, v := range vr {
					item := float(v)
					if item == left {
						return true
					}
				}
			case notIn:
				for _, v := range vr {
					item := float(v)
					if item == left {
						return false
					}
				}
				return true
			}
		case []json.Number:
			switch comparison {
			case in:
				for _, value := range vRight {
					if item, err := value.Float64(); err == nil && item == left {
						return true
					}
				}
			case notIn:
				for _, value := range vRight {
					if item, err := value.Float64(); err == nil && item == left {
						return false
					}
				}
				return true
			}
		}
	case string:
		left := vLeft
		switch right := valueRight.(type) {
		case string:
			switch comparison {
			case equal:
				if left == right {
					return true
				}
			case notEqual:
				if left != right {
					return true
				}
			case lessThan:
				if left < right {
					return true
				}
			case greaterThan:
				if left > right {
					return true
				}
			case lessEqual:
				if left <= right {
					return true
				}
			case greaterEqual:
				if left >= right {
					return true
				}
			}
		case []interface{}:
			switch comparison {
			case in:
				for _, v := range right {
					if item, ok := v.(string); ok && item == left {
						return true
					}
				}
			case notIn:
				for _, v := range right {
					if item, ok := v.(string); ok && item == left {
						return false
					}
				}
				return true
			}
		case []string:
			switch comparison {
			case in:
				for _, v := range right {
					if v == left {
						return true
					}
				}
			case notIn:
				for _, v := range right {
					if v == left {
						return false
					}
				}
				return true
			}
		}
	case bool:
		left := vLeft
		switch right := valueRight.(type) {
		case bool:
			switch comparison {
			case equal:
				if left == right {
					return true
				}
			case notEqual:
				if left != right {
					return true
				}
			}
		}
	}

	return false
}

func float(value interface{}) float64 {

	switch v := value.(type) {
	case float32:
		return float64(v)
	case float64:
		return float64(v)
	case int:
		return float64(v)
	case uint:
		return float64(v)
	case int8:
		return float64(v)
	case uint8:
		return float64(v)
	case int16:
		return float64(v)
	case uint16:
		return float64(v)
	case int32:
		return float64(v)
	case uint32:
		return float64(v)
	case int64:
		return float64(v)
	case uint64:
		return float64(v)
	}

	panic("never happen in that implementation")
}

func floatArray(value interface{}) []float64 {
	var result []float64
	switch v := value.(type) {
	case []float32:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []float64:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int8:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint8:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int16:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint16:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int32:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint32:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int64:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint64:
		for _, item := range v {
			result = append(result, float64(item))
		}
	}

	return result
}
<commit_msg>Bumped version number to 0.2.0<commit_after>// Copyright 2014 Igor Dolzhikov. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

/*
Package assert 0.2.0

This package helps to compare values of undefined types like interface{}.
Convenient using with JSON values (json.Number/float64, string, bool, nil).
The package is intended not only for testing purposes.
The package allows compare ambiguous values between each other.

Example 1:

	package main

	import (
		"encoding/json"
		"fmt"

		"github.com/takama/assert"
	)

	func main() {
		exampleJSON := `
		{
			"personA": {
				"name": "John",
				"age": 22,
				"height": 178,
				"weight": 82.59,
				"married": true,
				"hobby": ["fishing", "dancing", "cooking"]
			},
			"personB": {
				"name": "Jack",
				"age": 22,
				"height": 170.22,
				"weight": 65,
				"married": false,
				"hobby": ["photography", "singing", "cooking"]
			}
	  	}`

		persons := make(map[string]interface{}, 0)
		if err := json.Unmarshal([]byte(exampleJSON), &persons); err == nil {
			personA := persons["personA"].(map[string]interface{})
			personB := persons["personB"].(map[string]interface{})
			fmt.Println(
				"Comparing of a personal details:",
				personA["name"], "and", personB["name"],
			)
			if assert.Equal(personA["age"], personB["age"]) {
				fmt.Println("Persons of the same age")
			}
			if assert.GreaterThan(personA["height"], personB["height"]) {
				fmt.Println(personA["name"], "higher than", personB["name"])
			}
			if assert.LessThan(personB["weight"], personA["weight"]) {
				fmt.Println(personB["name"], "weighs less than", personA["name"])
			}
			if assert.NotEqual(personA["married"], personB["married"]) {
				fmt.Println("Persons have a different marital status")
			}
			if assert.In("cooking", personA["hobby"]) &&
				assert.In("cooking", personB["hobby"]) {
				fmt.Println("Both persons like to cook")
			}
			if assert.In("dancing", personA["hobby"]) &&
				assert.NotIn("dancing", personB["hobby"]) {
				fmt.Println("Only", personA["name"], "likes to dance")
			}
		}
	}

A simple Assert package for interface/json values
*/
package assert

import (
	"encoding/json"
)

// Equal checks if values equal to each other
func Equal(left, right interface{}) bool {
	return isCompareTrue(equal, left, right)
}

// NotEqual checks if values not equal to each other
func NotEqual(left, right interface{}) bool {
	return isCompareTrue(notEqual, left, right)
}

// LessThan checks if value "left" less than value "right"
func LessThan(left, right interface{}) bool {
	return isCompareTrue(lessThan, left, right)
}

// GreaterThan checks if value "left" greater than value "right"
func GreaterThan(left, right interface{}) bool {
	return isCompareTrue(greaterThan, left, right)
}

// LessEqual checks if value "left" less than value "right" or equal to it
func LessEqual(left, right interface{}) bool {
	return isCompareTrue(lessEqual, left, right)
}

// GreaterEqual checks if value "left" greater than value "right" or equal to it
func GreaterEqual(left, right interface{}) bool {
	return isCompareTrue(greaterEqual, left, right)
}

// In checks if array value "right" contains value "left"
func In(left, right interface{}) bool {
	return isCompareTrue(in, left, right)
}

// In checks if array value "right" not contains value "left"
func NotIn(left, right interface{}) bool {
	return isCompareTrue(notIn, left, right)
}

const (
	equal = iota
	notEqual
	lessThan
	greaterThan
	lessEqual
	greaterEqual
	in
	notIn
)

func isCompareTrue(comparison uint8, valueLeft, valueRight interface{}) bool {
	if valueLeft == nil && valueRight == nil && comparison == equal {
		return true
	}
	switch vLeft := valueLeft.(type) {
	case json.Number:
		if left, err := vLeft.Float64(); err == nil {
			switch vRight := valueRight.(type) {
			case json.Number:
				if right, err := vRight.Float64(); err == nil {
					switch comparison {
					case equal:
						if left == right {
							return true
						}
					case notEqual:
						if left != right {
							return true
						}
					case lessThan:
						if left < right {
							return true
						}
					case greaterThan:
						if left > right {
							return true
						}
					case lessEqual:
						if left <= right {
							return true
						}
					case greaterEqual:
						if left >= right {
							return true
						}
					}
				}
			case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
				right := float(valueRight)
				switch comparison {
				case equal:
					if left == right {
						return true
					}
				case notEqual:
					if left != right {
						return true
					}
				case lessThan:
					if left < right {
						return true
					}
				case greaterThan:
					if left > right {
						return true
					}
				case lessEqual:
					if left <= right {
						return true
					}
				case greaterEqual:
					if left >= right {
						return true
					}
				}
			case []interface{}:
				switch comparison {
				case in:
					for _, v := range vRight {
						switch value := v.(type) {
						case json.Number:
							if item, err := value.Float64(); err == nil && item == left {
								return true
							}
						case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
							item := float(v)
							if item == left {
								return true
							}
						}
					}
				case notIn:
					for _, v := range vRight {
						switch value := v.(type) {
						case json.Number:
							if item, err := value.Float64(); err == nil && item == left {
								return false
							}
						case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
							item := float(v)
							if item == left {
								return false
							}
						}
					}
					return true
				}
			case []json.Number:
				switch comparison {
				case in:
					for _, value := range vRight {
						if item, err := value.Float64(); err == nil && item == left {
							return true
						}
					}
				case notIn:
					for _, value := range vRight {
						if item, err := value.Float64(); err == nil && item == left {
							return false
						}
					}
					return true
				}
			}
		}
	case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
		left := float(valueLeft)
		switch vRight := valueRight.(type) {
		case json.Number:
			if right, err := vRight.Float64(); err == nil {
				switch comparison {
				case equal:
					if left == right {
						return true
					}
				case notEqual:
					if left != right {
						return true
					}
				case lessThan:
					if left < right {
						return true
					}
				case greaterThan:
					if left > right {
						return true
					}
				case lessEqual:
					if left <= right {
						return true
					}
				case greaterEqual:
					if left >= right {
						return true
					}
				}
			}
		case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
			right := float(valueRight)
			switch comparison {
			case equal:
				if left == right {
					return true
				}
			case notEqual:
				if left != right {
					return true
				}
			case lessThan:
				if left < right {
					return true
				}
			case greaterThan:
				if left > right {
					return true
				}
			case lessEqual:
				if left <= right {
					return true
				}
			case greaterEqual:
				if left >= right {
					return true
				}
			}
		case []interface{}:
			switch comparison {
			case in:
				for _, v := range vRight {
					switch value := v.(type) {
					case json.Number:
						if item, err := value.Float64(); err == nil && item == left {
							return true
						}
					case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
						item := float(v)
						if item == left {
							return true
						}
					}
				}
			case notIn:
				for _, v := range vRight {
					switch value := v.(type) {
					case json.Number:
						if item, err := value.Float64(); err == nil && item == left {
							return false
						}
					case float32, float64, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64:
						item := float(v)
						if item == left {
							return false
						}
					}
				}
				return true
			}
		case []float32, []float64, []int, []uint, []int8, []uint8, []int16, []uint16, []int32, []uint32, []int64, []uint64:
			vr := floatArray(valueRight)
			switch comparison {
			case in:
				for _, v := range vr {
					item := float(v)
					if item == left {
						return true
					}
				}
			case notIn:
				for _, v := range vr {
					item := float(v)
					if item == left {
						return false
					}
				}
				return true
			}
		case []json.Number:
			switch comparison {
			case in:
				for _, value := range vRight {
					if item, err := value.Float64(); err == nil && item == left {
						return true
					}
				}
			case notIn:
				for _, value := range vRight {
					if item, err := value.Float64(); err == nil && item == left {
						return false
					}
				}
				return true
			}
		}
	case string:
		left := vLeft
		switch right := valueRight.(type) {
		case string:
			switch comparison {
			case equal:
				if left == right {
					return true
				}
			case notEqual:
				if left != right {
					return true
				}
			case lessThan:
				if left < right {
					return true
				}
			case greaterThan:
				if left > right {
					return true
				}
			case lessEqual:
				if left <= right {
					return true
				}
			case greaterEqual:
				if left >= right {
					return true
				}
			}
		case []interface{}:
			switch comparison {
			case in:
				for _, v := range right {
					if item, ok := v.(string); ok && item == left {
						return true
					}
				}
			case notIn:
				for _, v := range right {
					if item, ok := v.(string); ok && item == left {
						return false
					}
				}
				return true
			}
		case []string:
			switch comparison {
			case in:
				for _, v := range right {
					if v == left {
						return true
					}
				}
			case notIn:
				for _, v := range right {
					if v == left {
						return false
					}
				}
				return true
			}
		}
	case bool:
		left := vLeft
		switch right := valueRight.(type) {
		case bool:
			switch comparison {
			case equal:
				if left == right {
					return true
				}
			case notEqual:
				if left != right {
					return true
				}
			}
		}
	}

	return false
}

func float(value interface{}) float64 {

	switch v := value.(type) {
	case float32:
		return float64(v)
	case float64:
		return float64(v)
	case int:
		return float64(v)
	case uint:
		return float64(v)
	case int8:
		return float64(v)
	case uint8:
		return float64(v)
	case int16:
		return float64(v)
	case uint16:
		return float64(v)
	case int32:
		return float64(v)
	case uint32:
		return float64(v)
	case int64:
		return float64(v)
	case uint64:
		return float64(v)
	}

	panic("never happen in that implementation")
}

func floatArray(value interface{}) []float64 {
	var result []float64
	switch v := value.(type) {
	case []float32:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []float64:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int8:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint8:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int16:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint16:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int32:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint32:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []int64:
		for _, item := range v {
			result = append(result, float64(item))
		}
	case []uint64:
		for _, item := range v {
			result = append(result, float64(item))
		}
	}

	return result
}
<|endoftext|>


<commit_before>package assets

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/go-playground/bundler"
	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/js"
)

const (
	oldNewSeparator = " --> "
	manifestFile    = "/manifest.txt"
	cssHTMLTag      = "css_tag"
	jsHTMLTag       = "js_tag"
)

// RunMode is the type that determines which mode the template.FuncMap functions whould run in.
type RunMode int

// RunMode's
const (
	Development RunMode = iota
	Production
)

const (
	jsTag  = `<script type="text/javascript" src="%s"></script>`
	cssTag = `<link type="text/css" rel="stylesheet" href="%s">`
)

var m *minify.M

func initMinifier() {

	if m != nil {
		return
	}

	m = minify.New()
	m.AddFunc("text/css", css.Minify)
	m.AddFunc("text/javascript", js.Minify)
}

// Generate processes (bundles, compresses...) the assets for use and creates the Manifest file
// NOTE: no compression yet until there is a native and establishes compressor written in Go
func Generate(dirname string, outputDir string, relativeToDir bool, leftDelim string, rightDelim string, extensions map[string]struct{}) ([]*bundler.ProcessedFile, string, error) {

	initMinifier()

	dirname = filepath.Clean(dirname)
	outputDir = filepath.Clean(outputDir) + string(filepath.Separator)

	abs, err := filepath.Abs(outputDir)
	if err != nil {
		return nil, "", err
	}

	if err = os.MkdirAll(abs, os.FileMode(0777)); err != nil {
		return nil, "", err
	}

	// verify dirname is actually a DIR + do symlink check
	fi, err := os.Lstat(dirname)
	if err != nil {
		return nil, "", err
	}

	if !fi.IsDir() {

		// check if symlink
		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {

			link, err := filepath.EvalSymlinks(dirname)
			if err != nil {
				return nil, "", errors.New("Error Resolving Symlink:" + err.Error())
			}

			fi, err = os.Stat(link)
			if err != nil {
				return nil, "", err
			}

			if !fi.IsDir() {
				return nil, "", errors.New("dirname passed in is not a directory")
			}

			dirname = link

		} else {
			return nil, "", errors.New("dirname passed in is not a directory")
		}
	}

	var manifest string

	if outputDir == "" {
		manifest = dirname + manifestFile
	} else {
		manifest = outputDir + dirname + manifestFile
	}

	f, err := os.Open(manifest)
	if err == nil {
		defer f.Close()
		scanner := bufio.NewScanner(f)

		for scanner.Scan() {
			files := strings.SplitN(scanner.Text(), oldNewSeparator, 2)

			fmt.Println("Removing Existing File:", files[1])
			os.Remove(files[1])
		}

		os.Remove(manifest)
	}

	processed, err := bundleDir(dirname, "", false, "", extensions, outputDir, relativeToDir, dirname, leftDelim, rightDelim)
	if err != nil {
		return nil, "", err
	}

	var buff bytes.Buffer

	for _, file := range processed {
		buff.WriteString(filepath.FromSlash(file.OriginalFilename))
		buff.WriteString(oldNewSeparator)
		buff.WriteString(filepath.FromSlash(file.NewFilename))
		buff.WriteString("\n")
	}

	if err = ioutil.WriteFile(manifest, buff.Bytes(), 0644); err != nil {
		return nil, "", err
	}

	return processed, manifest, nil
}

func bundleDir(path string, dir string, isSymlinkDir bool, symlinkDir string, extensions map[string]struct{}, output string, relativeToDir bool, relativeDir string, leftDelim string, rightDelim string) ([]*bundler.ProcessedFile, error) {

	var p string
	var ext string
	var processed []*bundler.ProcessedFile

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	files, err := f.Readdir(0)
	if err != nil {
		return nil, err
	}

	for _, file := range files {

		info := file
		p = path + string(os.PathSeparator) + file.Name()
		fPath := p

		if isSymlinkDir {
			fPath = strings.Replace(p, dir, symlinkDir, 1)
		}

		if file.IsDir() {

			processedFiles, err := bundleDir(p, p, isSymlinkDir, symlinkDir+string(os.PathSeparator)+info.Name(), extensions, output, relativeToDir, relativeDir, leftDelim, rightDelim)
			if err != nil {
				return nil, err
			}

			processed = append(processed, processedFiles...)

			continue
		}

		if file.Mode()&os.ModeSymlink == os.ModeSymlink {

			link, err := filepath.EvalSymlinks(p)
			if err != nil {
				log.Panic("Error Resolving Symlink", err)
			}

			fi, err := os.Stat(link)
			if err != nil {
				log.Panic(err)
			}

			info = fi

			if fi.IsDir() {

				processedFiles, err := bundleDir(link, link, true, fPath, extensions, output, relativeToDir, relativeDir, leftDelim, rightDelim)
				if err != nil {
					return nil, err
				}

				processed = append(processed, processedFiles...)

				continue
			}
		}

		// if we get here, it's a file
		ext = filepath.Ext(fPath)

		if _, ok := extensions[ext]; !ok {

			// just copy file to final location
			if err := copyFile(fPath, output); err != nil {
				return nil, err
			}
			continue
		}

		// process file
		file, err := bundleFile(p, output, relativeToDir, relativeDir, leftDelim, rightDelim, ext)
		if err != nil {
			return nil, err
		}

		processed = append(processed, file)
	}

	return processed, nil
}

func copyFile(path string, output string) error {

	dirname := output + string(filepath.Separator) + path

	if err := os.MkdirAll(filepath.Dir(dirname), os.FileMode(0777)); err != nil {
		return err
	}

	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	out, err := os.Create(dirname)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, f)
	if err != nil {
		return err
	}

	return nil
}

func bundleFile(path string, output string, relativeToDir bool, relativeDir string, leftDelim string, rightDelim string, extension string) (*bundler.ProcessedFile, error) {

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	newFile, err := ioutil.TempFile("", filepath.Base(f.Name()))
	if err != nil {
		return nil, err
	}

	defer newFile.Close()

	if err = bundler.Bundle(f, newFile, filepath.Dir(path), relativeToDir, relativeDir, leftDelim, rightDelim); err != nil {
		return nil, err
	}

	var newName string

	dirname, filename := filepath.Split(path)
	origDir := dirname
	ext := filepath.Ext(filename)
	filename = filepath.Base(filename)

	if output != "" {
		dirname = output + string(filepath.Separator) + dirname + string(filepath.Separator)
	}

	newName = dirname + filename[0:strings.LastIndex(filename, ext)]
	origDir += filename[0:strings.LastIndex(filename, ext)]

	b, err := ioutil.ReadFile(newFile.Name())
	if err != nil {
		return nil, err
	}

	h := md5.New()
	h.Write(b)
	hash := string(h.Sum(nil))

	hashName := "-" + fmt.Sprintf("%x", hash) + ext
	newName += hashName
	origDir += hashName

	if err = os.MkdirAll(filepath.Dir(newName), os.FileMode(0777)); err != nil {
		return nil, err
	}

	buff := new(bytes.Buffer)

	// perform minification
	if extension == ".js" {

		fmt.Println("Minifying JS")

		if err := m.Minify("text/javascript", buff, bytes.NewReader(b)); err != nil {
			return nil, err
		}

		// if strings.Contains(newName, "app-") {
		// 	fmt.Println(buff.String())
		// }

	} else if extension == ".css" {
		if err := m.Minify("text/css", buff, bytes.NewReader(b)); err != nil {
			return nil, err
		}
	}

	if err := os.Remove(newFile.Name()); err != nil {
		return nil, err
	}

	if err := ioutil.WriteFile(newName, buff.Bytes(), 0644); err != nil {
		return nil, err
	}

	// if err = os.Rename(newFile.Name(), newName); err != nil {
	// 	return nil, err
	// }

	return &bundler.ProcessedFile{OriginalFilename: path, NewFilename: origDir}, nil
}

// LoadManifestFiles reads the manifest file generated by the Generate() command
// in Production mode and returns template.FuncMap for the provided RunMode
func LoadManifestFiles(dirname string, mode RunMode, relativeToDir bool, leftDelim string, rightDelim string) (template.FuncMap, error) {

	var f *os.File
	var err error

	if mode == Production {
		f, err = os.Open(dirname + manifestFile)
		if err != nil {
			return nil, err
		}
		defer f.Close()
	}

	return ProcessManifestFiles(f, dirname, mode, relativeToDir, leftDelim, rightDelim)
}

// ProcessManifestFiles reads an existing manifest file generated by the Generate() command
// in Production mode and returns template.FuncMap for the provided RunMode
func ProcessManifestFiles(manifest io.Reader, dirname string, mode RunMode, relativeToDir bool, leftDelim string, rightDelim string) (template.FuncMap, error) {

	mapped := map[string]string{}
	dirname = filepath.Clean(dirname) + string(os.PathSeparator)

	if mode == Production {

		var files []string

		scanner := bufio.NewScanner(manifest)

		for scanner.Scan() {

			files = strings.SplitN(scanner.Text(), oldNewSeparator, 2)
			mapped[strings.TrimLeft(files[0], dirname)] = "/" + files[1]
		}
	}

	return loadMapFuncs(dirname, mode, relativeToDir, leftDelim, rightDelim, mapped), nil
}

func loadMapFuncs(dirname string, mode RunMode, relativeToDir bool, leftDelim string, rightDelim string, mapped map[string]string) template.FuncMap {

	funcs := template.FuncMap{}

	if mode == Production {
		funcs[cssHTMLTag] = createProdCSSTemplateFunc(mapped)
		funcs[jsHTMLTag] = createProdJSTemplateFunc(mapped)

		return funcs
	}

	funcs[cssHTMLTag] = createDevCSSTemplateFunc(dirname, relativeToDir, leftDelim, rightDelim)
	funcs[jsHTMLTag] = createDevJSTemplateFunc(dirname, relativeToDir, leftDelim, rightDelim)

	return funcs
}

func createProdCSSTemplateFunc(mapped map[string]string) interface{} {
	return func(name string) template.HTML {
		return template.HTML(fmt.Sprintf(cssTag, mapped[name]))
	}
}

func createProdJSTemplateFunc(mapped map[string]string) interface{} {
	return func(name string) template.HTML {
		return template.HTML(fmt.Sprintf(jsTag, mapped[name]))
	}
}

func createDevCSSTemplateFunc(dirname string, relativeToDir bool, leftDelim string, rightDelim string) interface{} {
	// custom lexer, bytesBuffer

	return func(name string) template.HTML {
		buff := new(bytes.Buffer)

		files, err := loadFromDelims(dirname, name, relativeToDir, dirname, leftDelim, rightDelim)
		if err != nil {
			panic(err)
		}

		for _, file := range files {
			buff.WriteString(fmt.Sprintf(cssTag, "/"+filepath.Clean(dirname)+file))
		}

		buff.WriteString(fmt.Sprintf(cssTag, "/"+dirname+name))

		return template.HTML(buff.String())
	}
}

func createDevJSTemplateFunc(dirname string, relativeToDir bool, leftDelim string, rightDelim string) interface{} {
	// custom lexer, bytesBuffer

	return func(name string) template.HTML {
		buff := new(bytes.Buffer)

		files, err := loadFromDelims(dirname, name, relativeToDir, dirname, leftDelim, rightDelim)
		if err != nil {
			panic(err)
		}

		for _, file := range files {
			buff.WriteString(fmt.Sprintf(jsTag, "/"+filepath.Clean(dirname)+file))
		}

		buff.WriteString(fmt.Sprintf(jsTag, "/"+dirname+name))

		return template.HTML(buff.String())
	}
}

func loadFromDelims(dirname string, name string, relativeToDir bool, relativeDir string, leftDelim string, rightDelim string) ([]string, error) {
	var err error
	var files []string
	var ok bool
	var path string

	existing := map[string]struct{}{}

	f, err := os.Open(dirname + name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	l, err := bundler.NewLexer("assets-bundle", f, leftDelim, rightDelim)
	if err != nil {
		return nil, err
	}

LOOP:
	for {
		itm := l.NextItem()

		switch itm.Type {

		case bundler.ItemFile:

			if relativeToDir {
				path = filepath.FromSlash("/" + itm.Val)
			} else {
				path = filepath.FromSlash("/" + dirname + itm.Val)
			}

			if _, ok = existing[path]; !ok {
				files = append(files, path)
				existing[path] = struct{}{}
			}

			fls, err := loadFromDelims(dirname, itm.Val, relativeToDir, relativeDir, leftDelim, rightDelim)
			if err != nil {
				return nil, err
			}

			files = append(files, fls...)

		case bundler.ItemEOF:
			break LOOP
		case bundler.ItemError:
			return nil, errors.New(itm.Val)
		}
	}

	return files, nil
}
<commit_msg>remove debug<commit_after>package assets

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/go-playground/bundler"
	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/js"
)

const (
	oldNewSeparator = " --> "
	manifestFile    = "/manifest.txt"
	cssHTMLTag      = "css_tag"
	jsHTMLTag       = "js_tag"
)

// RunMode is the type that determines which mode the template.FuncMap functions whould run in.
type RunMode int

// RunMode's
const (
	Development RunMode = iota
	Production
)

const (
	jsTag  = `<script type="text/javascript" src="%s"></script>`
	cssTag = `<link type="text/css" rel="stylesheet" href="%s">`
)

var m *minify.M

func initMinifier() {

	if m != nil {
		return
	}

	m = minify.New()
	m.AddFunc("text/css", css.Minify)
	m.AddFunc("text/javascript", js.Minify)
}

// Generate processes (bundles, compresses...) the assets for use and creates the Manifest file
// NOTE: no compression yet until there is a native and establishes compressor written in Go
func Generate(dirname string, outputDir string, relativeToDir bool, leftDelim string, rightDelim string, extensions map[string]struct{}) ([]*bundler.ProcessedFile, string, error) {

	initMinifier()

	dirname = filepath.Clean(dirname)
	outputDir = filepath.Clean(outputDir) + string(filepath.Separator)

	abs, err := filepath.Abs(outputDir)
	if err != nil {
		return nil, "", err
	}

	if err = os.MkdirAll(abs, os.FileMode(0777)); err != nil {
		return nil, "", err
	}

	// verify dirname is actually a DIR + do symlink check
	fi, err := os.Lstat(dirname)
	if err != nil {
		return nil, "", err
	}

	if !fi.IsDir() {

		// check if symlink
		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {

			link, err := filepath.EvalSymlinks(dirname)
			if err != nil {
				return nil, "", errors.New("Error Resolving Symlink:" + err.Error())
			}

			fi, err = os.Stat(link)
			if err != nil {
				return nil, "", err
			}

			if !fi.IsDir() {
				return nil, "", errors.New("dirname passed in is not a directory")
			}

			dirname = link

		} else {
			return nil, "", errors.New("dirname passed in is not a directory")
		}
	}

	var manifest string

	if outputDir == "" {
		manifest = dirname + manifestFile
	} else {
		manifest = outputDir + dirname + manifestFile
	}

	f, err := os.Open(manifest)
	if err == nil {
		defer f.Close()
		scanner := bufio.NewScanner(f)

		for scanner.Scan() {
			files := strings.SplitN(scanner.Text(), oldNewSeparator, 2)

			fmt.Println("Removing Existing File:", files[1])
			os.Remove(files[1])
		}

		os.Remove(manifest)
	}

	processed, err := bundleDir(dirname, "", false, "", extensions, outputDir, relativeToDir, dirname, leftDelim, rightDelim)
	if err != nil {
		return nil, "", err
	}

	var buff bytes.Buffer

	for _, file := range processed {
		buff.WriteString(filepath.FromSlash(file.OriginalFilename))
		buff.WriteString(oldNewSeparator)
		buff.WriteString(filepath.FromSlash(file.NewFilename))
		buff.WriteString("\n")
	}

	if err = ioutil.WriteFile(manifest, buff.Bytes(), 0644); err != nil {
		return nil, "", err
	}

	return processed, manifest, nil
}

func bundleDir(path string, dir string, isSymlinkDir bool, symlinkDir string, extensions map[string]struct{}, output string, relativeToDir bool, relativeDir string, leftDelim string, rightDelim string) ([]*bundler.ProcessedFile, error) {

	var p string
	var ext string
	var processed []*bundler.ProcessedFile

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	files, err := f.Readdir(0)
	if err != nil {
		return nil, err
	}

	for _, file := range files {

		info := file
		p = path + string(os.PathSeparator) + file.Name()
		fPath := p

		if isSymlinkDir {
			fPath = strings.Replace(p, dir, symlinkDir, 1)
		}

		if file.IsDir() {

			processedFiles, err := bundleDir(p, p, isSymlinkDir, symlinkDir+string(os.PathSeparator)+info.Name(), extensions, output, relativeToDir, relativeDir, leftDelim, rightDelim)
			if err != nil {
				return nil, err
			}

			processed = append(processed, processedFiles...)

			continue
		}

		if file.Mode()&os.ModeSymlink == os.ModeSymlink {

			link, err := filepath.EvalSymlinks(p)
			if err != nil {
				log.Panic("Error Resolving Symlink", err)
			}

			fi, err := os.Stat(link)
			if err != nil {
				log.Panic(err)
			}

			info = fi

			if fi.IsDir() {

				processedFiles, err := bundleDir(link, link, true, fPath, extensions, output, relativeToDir, relativeDir, leftDelim, rightDelim)
				if err != nil {
					return nil, err
				}

				processed = append(processed, processedFiles...)

				continue
			}
		}

		// if we get here, it's a file
		ext = filepath.Ext(fPath)

		if _, ok := extensions[ext]; !ok {

			// just copy file to final location
			if err := copyFile(fPath, output); err != nil {
				return nil, err
			}
			continue
		}

		// process file
		file, err := bundleFile(p, output, relativeToDir, relativeDir, leftDelim, rightDelim, ext)
		if err != nil {
			return nil, err
		}

		processed = append(processed, file)
	}

	return processed, nil
}

func copyFile(path string, output string) error {

	dirname := output + string(filepath.Separator) + path

	if err := os.MkdirAll(filepath.Dir(dirname), os.FileMode(0777)); err != nil {
		return err
	}

	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	out, err := os.Create(dirname)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, f)
	if err != nil {
		return err
	}

	return nil
}

func bundleFile(path string, output string, relativeToDir bool, relativeDir string, leftDelim string, rightDelim string, extension string) (*bundler.ProcessedFile, error) {

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	newFile, err := ioutil.TempFile("", filepath.Base(f.Name()))
	if err != nil {
		return nil, err
	}

	defer newFile.Close()

	if err = bundler.Bundle(f, newFile, filepath.Dir(path), relativeToDir, relativeDir, leftDelim, rightDelim); err != nil {
		return nil, err
	}

	var newName string

	dirname, filename := filepath.Split(path)
	origDir := dirname
	ext := filepath.Ext(filename)
	filename = filepath.Base(filename)

	if output != "" {
		dirname = output + string(filepath.Separator) + dirname + string(filepath.Separator)
	}

	newName = dirname + filename[0:strings.LastIndex(filename, ext)]
	origDir += filename[0:strings.LastIndex(filename, ext)]

	b, err := ioutil.ReadFile(newFile.Name())
	if err != nil {
		return nil, err
	}

	h := md5.New()
	h.Write(b)
	hash := string(h.Sum(nil))

	hashName := "-" + fmt.Sprintf("%x", hash) + ext
	newName += hashName
	origDir += hashName

	if err = os.MkdirAll(filepath.Dir(newName), os.FileMode(0777)); err != nil {
		return nil, err
	}

	buff := new(bytes.Buffer)

	// perform minification
	if extension == ".js" {

		if err := m.Minify("text/javascript", buff, bytes.NewReader(b)); err != nil {
			return nil, err
		}

		// if strings.Contains(newName, "app-") {
		// 	fmt.Println(buff.String())
		// }

	} else if extension == ".css" {
		if err := m.Minify("text/css", buff, bytes.NewReader(b)); err != nil {
			return nil, err
		}
	}

	if err := os.Remove(newFile.Name()); err != nil {
		return nil, err
	}

	if err := ioutil.WriteFile(newName, buff.Bytes(), 0644); err != nil {
		return nil, err
	}

	// if err = os.Rename(newFile.Name(), newName); err != nil {
	// 	return nil, err
	// }

	return &bundler.ProcessedFile{OriginalFilename: path, NewFilename: origDir}, nil
}

// LoadManifestFiles reads the manifest file generated by the Generate() command
// in Production mode and returns template.FuncMap for the provided RunMode
func LoadManifestFiles(dirname string, mode RunMode, relativeToDir bool, leftDelim string, rightDelim string) (template.FuncMap, error) {

	var f *os.File
	var err error

	if mode == Production {
		f, err = os.Open(dirname + manifestFile)
		if err != nil {
			return nil, err
		}
		defer f.Close()
	}

	return ProcessManifestFiles(f, dirname, mode, relativeToDir, leftDelim, rightDelim)
}

// ProcessManifestFiles reads an existing manifest file generated by the Generate() command
// in Production mode and returns template.FuncMap for the provided RunMode
func ProcessManifestFiles(manifest io.Reader, dirname string, mode RunMode, relativeToDir bool, leftDelim string, rightDelim string) (template.FuncMap, error) {

	mapped := map[string]string{}
	dirname = filepath.Clean(dirname) + string(os.PathSeparator)

	if mode == Production {

		var files []string

		scanner := bufio.NewScanner(manifest)

		for scanner.Scan() {

			files = strings.SplitN(scanner.Text(), oldNewSeparator, 2)
			mapped[strings.TrimLeft(files[0], dirname)] = "/" + files[1]
		}
	}

	return loadMapFuncs(dirname, mode, relativeToDir, leftDelim, rightDelim, mapped), nil
}

func loadMapFuncs(dirname string, mode RunMode, relativeToDir bool, leftDelim string, rightDelim string, mapped map[string]string) template.FuncMap {

	funcs := template.FuncMap{}

	if mode == Production {
		funcs[cssHTMLTag] = createProdCSSTemplateFunc(mapped)
		funcs[jsHTMLTag] = createProdJSTemplateFunc(mapped)

		return funcs
	}

	funcs[cssHTMLTag] = createDevCSSTemplateFunc(dirname, relativeToDir, leftDelim, rightDelim)
	funcs[jsHTMLTag] = createDevJSTemplateFunc(dirname, relativeToDir, leftDelim, rightDelim)

	return funcs
}

func createProdCSSTemplateFunc(mapped map[string]string) interface{} {
	return func(name string) template.HTML {
		return template.HTML(fmt.Sprintf(cssTag, mapped[name]))
	}
}

func createProdJSTemplateFunc(mapped map[string]string) interface{} {
	return func(name string) template.HTML {
		return template.HTML(fmt.Sprintf(jsTag, mapped[name]))
	}
}

func createDevCSSTemplateFunc(dirname string, relativeToDir bool, leftDelim string, rightDelim string) interface{} {
	// custom lexer, bytesBuffer

	return func(name string) template.HTML {
		buff := new(bytes.Buffer)

		files, err := loadFromDelims(dirname, name, relativeToDir, dirname, leftDelim, rightDelim)
		if err != nil {
			panic(err)
		}

		for _, file := range files {
			buff.WriteString(fmt.Sprintf(cssTag, "/"+filepath.Clean(dirname)+file))
		}

		buff.WriteString(fmt.Sprintf(cssTag, "/"+dirname+name))

		return template.HTML(buff.String())
	}
}

func createDevJSTemplateFunc(dirname string, relativeToDir bool, leftDelim string, rightDelim string) interface{} {
	// custom lexer, bytesBuffer

	return func(name string) template.HTML {
		buff := new(bytes.Buffer)

		files, err := loadFromDelims(dirname, name, relativeToDir, dirname, leftDelim, rightDelim)
		if err != nil {
			panic(err)
		}

		for _, file := range files {
			buff.WriteString(fmt.Sprintf(jsTag, "/"+filepath.Clean(dirname)+file))
		}

		buff.WriteString(fmt.Sprintf(jsTag, "/"+dirname+name))

		return template.HTML(buff.String())
	}
}

func loadFromDelims(dirname string, name string, relativeToDir bool, relativeDir string, leftDelim string, rightDelim string) ([]string, error) {
	var err error
	var files []string
	var ok bool
	var path string

	existing := map[string]struct{}{}

	f, err := os.Open(dirname + name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	l, err := bundler.NewLexer("assets-bundle", f, leftDelim, rightDelim)
	if err != nil {
		return nil, err
	}

LOOP:
	for {
		itm := l.NextItem()

		switch itm.Type {

		case bundler.ItemFile:

			if relativeToDir {
				path = filepath.FromSlash("/" + itm.Val)
			} else {
				path = filepath.FromSlash("/" + dirname + itm.Val)
			}

			if _, ok = existing[path]; !ok {
				files = append(files, path)
				existing[path] = struct{}{}
			}

			fls, err := loadFromDelims(dirname, itm.Val, relativeToDir, relativeDir, leftDelim, rightDelim)
			if err != nil {
				return nil, err
			}

			files = append(files, fls...)

		case bundler.ItemEOF:
			break LOOP
		case bundler.ItemError:
			return nil, errors.New(itm.Val)
		}
	}

	return files, nil
}
<|endoftext|>


<commit_before>package daemon

import (
	log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/bobtfish/AWSnycast/aws"
	"github.com/bobtfish/AWSnycast/config"
	"github.com/bobtfish/AWSnycast/instancemetadata"
	"time"
)

type Daemon struct {
	oneShot           bool
	noop              bool
	ConfigFile        string
	Debug             bool
	Config            *config.Config
	MetadataFetcher   instancemetadata.MetadataFetcher
	RouteTableManager aws.RouteTableManager
	quitChan          chan bool
	loopQuitChan      chan bool
	FetchWait         time.Duration
	instancemetadata.InstanceMetadata
}

func (d *Daemon) setupMetadataFetcher() {
	if d.MetadataFetcher == nil {
		d.MetadataFetcher = instancemetadata.New(d.Debug)
	}
}

func (d *Daemon) Setup() error {
	d.setupMetadataFetcher()
	im, err := instancemetadata.FetchMetadata(d.MetadataFetcher)
	if err != nil {
		return err
	}
	d.InstanceMetadata = im

	if d.RouteTableManager == nil {
		d.RouteTableManager = aws.NewRouteTableManager(d.Region, d.Debug)
	}

	config, err := config.New(d.ConfigFile, d.InstanceMetadata, d.RouteTableManager)
	if err != nil {
		return err
	}
	d.Config = config

	if d.FetchWait == 0 {
		d.FetchWait = time.Second * time.Duration(config.PollTime)
	}

	return setupHealthchecks(d.Config)
}

func setupHealthchecks(c *config.Config) error {
	for _, v := range c.Healthchecks {
		err := v.Setup()
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) runHealthChecks() {
	log.Debug("Starting healthchecks")
	for _, v := range d.Config.Healthchecks {
		v.Run(d.Debug)
	}
	for _, configRouteTables := range d.Config.RouteTables {
		for _, mr := range configRouteTables.ManageRoutes {
			mr.StartHealthcheckListener(d.noop)
		}
	}
	log.Debug("Started all healthchecks")
}

func (d *Daemon) stopHealthChecks() {
	for _, v := range d.Config.Healthchecks {
		v.Stop()
	}
}

func (d *Daemon) RunOneRouteTable(rt []*ec2.RouteTable, name string, configRouteTable *config.RouteTable) error {
	if err := configRouteTable.UpdateEc2RouteTables(rt); err != nil {
		return err
	}
	return configRouteTable.RunEc2Updates(d.RouteTableManager, d.noop)
}

func (d *Daemon) RunRouteTables() error {
	rt, err := d.RouteTableManager.GetRouteTables()
	if err != nil {
		return err
	}
	for name, configRouteTables := range d.Config.RouteTables {
		if err := d.RunOneRouteTable(rt, name, configRouteTables); err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) Run(oneShot bool, noop bool) int {
	d.oneShot = oneShot
	d.noop = noop
	if err := d.Setup(); err != nil {
		log.WithFields(log.Fields{"err": err.Error()}).Error("Error in initial setup")
		return 1
	}

	if !d.RouteTableManager.InstanceIsRouter(d.Instance) {
		log.WithFields(log.Fields{"instance_id": d.Instance}).Error("I am not a router (do not have src/destination checking disabled)")
		return 1
	}

	d.quitChan = make(chan bool, 1)
	err := d.RunRouteTables()
	if err != nil {
		log.WithFields(log.Fields{"err": err.Error()}).Error("Error in initial route table run")
		return 1
	}
	d.loopQuitChan = make(chan bool, 1)
	if oneShot {
		d.quitChan <- true
	} else {
		d.runHealthChecks()
		defer d.stopHealthChecks()
		d.RunSleepLoop()
	}
	<-d.quitChan
	d.loopQuitChan <- true
	return 0
}

func (d *Daemon) RunSleepLoop() {
	go func() {

		ticker := time.NewTicker(d.FetchWai)
		fetch := ticker.C

		for {
			select {
			case <-d.loopQuitChan:
				ticker.Stop()
				return
			case <-fetch:
				err := d.RunRouteTables()
				if err != nil {
					log.WithFields(log.Fields{"err": err.Error()}).Warn("Error in route table poll run")
				}
			}
		}
	}()
}
<commit_msg>fix typo<commit_after>package daemon

import (
	log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/bobtfish/AWSnycast/aws"
	"github.com/bobtfish/AWSnycast/config"
	"github.com/bobtfish/AWSnycast/instancemetadata"
	"time"
)

type Daemon struct {
	oneShot           bool
	noop              bool
	ConfigFile        string
	Debug             bool
	Config            *config.Config
	MetadataFetcher   instancemetadata.MetadataFetcher
	RouteTableManager aws.RouteTableManager
	quitChan          chan bool
	loopQuitChan      chan bool
	FetchWait         time.Duration
	instancemetadata.InstanceMetadata
}

func (d *Daemon) setupMetadataFetcher() {
	if d.MetadataFetcher == nil {
		d.MetadataFetcher = instancemetadata.New(d.Debug)
	}
}

func (d *Daemon) Setup() error {
	d.setupMetadataFetcher()
	im, err := instancemetadata.FetchMetadata(d.MetadataFetcher)
	if err != nil {
		return err
	}
	d.InstanceMetadata = im

	if d.RouteTableManager == nil {
		d.RouteTableManager = aws.NewRouteTableManager(d.Region, d.Debug)
	}

	config, err := config.New(d.ConfigFile, d.InstanceMetadata, d.RouteTableManager)
	if err != nil {
		return err
	}
	d.Config = config

	if d.FetchWait == 0 {
		d.FetchWait = time.Second * time.Duration(config.PollTime)
	}

	return setupHealthchecks(d.Config)
}

func setupHealthchecks(c *config.Config) error {
	for _, v := range c.Healthchecks {
		err := v.Setup()
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) runHealthChecks() {
	log.Debug("Starting healthchecks")
	for _, v := range d.Config.Healthchecks {
		v.Run(d.Debug)
	}
	for _, configRouteTables := range d.Config.RouteTables {
		for _, mr := range configRouteTables.ManageRoutes {
			mr.StartHealthcheckListener(d.noop)
		}
	}
	log.Debug("Started all healthchecks")
}

func (d *Daemon) stopHealthChecks() {
	for _, v := range d.Config.Healthchecks {
		v.Stop()
	}
}

func (d *Daemon) RunOneRouteTable(rt []*ec2.RouteTable, name string, configRouteTable *config.RouteTable) error {
	if err := configRouteTable.UpdateEc2RouteTables(rt); err != nil {
		return err
	}
	return configRouteTable.RunEc2Updates(d.RouteTableManager, d.noop)
}

func (d *Daemon) RunRouteTables() error {
	rt, err := d.RouteTableManager.GetRouteTables()
	if err != nil {
		return err
	}
	for name, configRouteTables := range d.Config.RouteTables {
		if err := d.RunOneRouteTable(rt, name, configRouteTables); err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) Run(oneShot bool, noop bool) int {
	d.oneShot = oneShot
	d.noop = noop
	if err := d.Setup(); err != nil {
		log.WithFields(log.Fields{"err": err.Error()}).Error("Error in initial setup")
		return 1
	}

	if !d.RouteTableManager.InstanceIsRouter(d.Instance) {
		log.WithFields(log.Fields{"instance_id": d.Instance}).Error("I am not a router (do not have src/destination checking disabled)")
		return 1
	}

	d.quitChan = make(chan bool, 1)
	err := d.RunRouteTables()
	if err != nil {
		log.WithFields(log.Fields{"err": err.Error()}).Error("Error in initial route table run")
		return 1
	}
	d.loopQuitChan = make(chan bool, 1)
	if oneShot {
		d.quitChan <- true
	} else {
		d.runHealthChecks()
		defer d.stopHealthChecks()
		d.RunSleepLoop()
	}
	<-d.quitChan
	d.loopQuitChan <- true
	return 0
}

func (d *Daemon) RunSleepLoop() {
	go func() {

		ticker := time.NewTicker(d.FetchWait)
		fetch := ticker.C

		for {
			select {
			case <-d.loopQuitChan:
				ticker.Stop()
				return
			case <-fetch:
				err := d.RunRouteTables()
				if err != nil {
					log.WithFields(log.Fields{"err": err.Error()}).Warn("Error in route table poll run")
				}
			}
		}
	}()
}
<|endoftext|>


<commit_before>package daemon

import (
	"errors"
	"fmt"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/bobtfish/AWSnycast/aws"
	"github.com/bobtfish/AWSnycast/config"
	"log"
	"time"
)

type Daemon struct {
	oneShot           bool
	noop              bool
	ConfigFile        string
	Debug             bool
	Config            *config.Config
	MetadataFetcher   aws.MetadataFetcher
	RouteTableFetcher aws.RouteTableFetcher
	Subnet            string
	Instance          string
	Region            string
	quitChan          <-chan bool
}

func (d *Daemon) Setup() error {
	config, err := config.New(d.ConfigFile)
	if err != nil {
		return err
	}
	d.Config = config
	if d.MetadataFetcher == nil {
		m, err := aws.NewMetadataFetcher(d.Debug)
		if err != nil {
			return err
		}
		d.MetadataFetcher = m
	}
	az, err := d.MetadataFetcher.GetMetadata("placement/availability-zone")
	if err != nil {
		return errors.New(fmt.Sprintf("Error getting AZ: %s", err.Error()))
	}
	d.Region = az[:len(az)-1]
	if d.RouteTableFetcher == nil {
		rtf, err := aws.NewRouteTableFetcher(d.Region, d.Debug)
		if err != nil {
			return err
		}
		d.RouteTableFetcher = rtf
	}
	for _, v := range d.Config.Healthchecks {
		err := v.Setup()
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) GetSubnetId() (string, error) {
	mac, err := d.MetadataFetcher.GetMetadata("mac")
	if err != nil {
		return "", err
	}
	return d.MetadataFetcher.GetMetadata(fmt.Sprintf("network/interfaces/macs/%s/subnet-id", mac))
}

func (d *Daemon) GetInstance() (string, error) {
	return d.MetadataFetcher.GetMetadata("instance-id")
}

func (d *Daemon) runHealthChecks() {
	log.Printf("Starting healthchecks")
	for _, v := range d.Config.Healthchecks {
		v.Run()
	}
	log.Printf("Done starting healthchecks")
}

func (d *Daemon) RunOneRouteTable(rt []*ec2.RouteTable, name string, configRouteTables *config.RouteTable) error {
	filter, err := configRouteTables.Find.GetFilter()
	if err != nil {
		return err
	}
	remaining := aws.FilterRouteTables(filter, rt)
	for _, rtb := range remaining {
		log.Printf("Finder name %s found route table %v", name, rtb)
		for _, upsertRoute := range configRouteTables.UpsertRoutes {
			log.Printf("Trying to upsert route to %s", upsertRoute.Cidr)
			if err := d.RunOneUpsertRoute(rtb, name, upsertRoute); err != nil {
				log.Printf(err.Error())
			}
		}
	}
	return nil
}

func (d *Daemon) RunOneUpsertRoute(rtb *ec2.RouteTable, name string, upsertRoute *config.UpsertRoutesSpec) error {
	destInstance := upsertRoute.Instance
	if upsertRoute.Instance == "SELF" {
		destInstance = d.Instance
	}
	if !d.oneShot && upsertRoute.Healthcheck != "" {
		log.Printf("Checking healthcheck: %s", upsertRoute.Healthcheck)
		if hc, ok := d.Config.Healthchecks[upsertRoute.Healthcheck]; ok {
			if !hc.IsHealthy() {
				log.Printf("Skipping upsert route %s, healthcheck %s isn't healthy yet", name, upsertRoute.Healthcheck)
				return nil
			}
		} else {
			panic("moo")
		}
		log.Printf("Is healthy")
	}

	return d.RouteTableFetcher.(aws.RouteTableFetcherEC2).CreateOrReplaceInstanceRoute(*rtb, upsertRoute.Cidr, destInstance, d.noop)
}

func (d *Daemon) RunRouteTables() error {
	rt, err := d.RouteTableFetcher.GetRouteTables()
	if err != nil {
		return err
	}
	for name, configRouteTables := range d.Config.RouteTables {
		if err := d.RunOneRouteTable(rt, name, configRouteTables); err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) Run(oneShot bool, noop bool) int {
	d.oneShot = oneShot
	d.noop = noop
	if err := d.Setup(); err != nil {
		log.Printf("Error setting up: %s", err.Error())
		return 1
	}
	subnet, err := d.GetSubnetId()
	if err != nil {
		log.Printf("Error getting metadata: %s", err.Error())
		return 1
	}
	d.Subnet = subnet
	instanceId, err := d.GetInstance()
	if err != nil {
		log.Printf("Error getting metadata: %s", err.Error())
		return 1
	}
	d.Instance = instanceId
	d.quitChan = make(chan bool)
	log.Printf(subnet)
	log.Printf(instanceId)
	if !oneShot {
		d.runHealthChecks()
		time.Sleep(time.Second * 3)
	}
	err = d.RunRouteTables()
	if err != nil {
		log.Printf("Error: %v", err)
		return 1
	}
	<-d.quitChan
	return 0
}
<commit_msg>Fix to oneShot<commit_after>package daemon

import (
	"errors"
	"fmt"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/bobtfish/AWSnycast/aws"
	"github.com/bobtfish/AWSnycast/config"
	"log"
	"time"
)

type Daemon struct {
	oneShot           bool
	noop              bool
	ConfigFile        string
	Debug             bool
	Config            *config.Config
	MetadataFetcher   aws.MetadataFetcher
	RouteTableFetcher aws.RouteTableFetcher
	Subnet            string
	Instance          string
	Region            string
	quitChan          chan bool
}

func (d *Daemon) Setup() error {
	config, err := config.New(d.ConfigFile)
	if err != nil {
		return err
	}
	d.Config = config
	if d.MetadataFetcher == nil {
		m, err := aws.NewMetadataFetcher(d.Debug)
		if err != nil {
			return err
		}
		d.MetadataFetcher = m
	}
	az, err := d.MetadataFetcher.GetMetadata("placement/availability-zone")
	if err != nil {
		return errors.New(fmt.Sprintf("Error getting AZ: %s", err.Error()))
	}
	d.Region = az[:len(az)-1]
	if d.RouteTableFetcher == nil {
		rtf, err := aws.NewRouteTableFetcher(d.Region, d.Debug)
		if err != nil {
			return err
		}
		d.RouteTableFetcher = rtf
	}
	for _, v := range d.Config.Healthchecks {
		err := v.Setup()
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) GetSubnetId() (string, error) {
	mac, err := d.MetadataFetcher.GetMetadata("mac")
	if err != nil {
		return "", err
	}
	return d.MetadataFetcher.GetMetadata(fmt.Sprintf("network/interfaces/macs/%s/subnet-id", mac))
}

func (d *Daemon) GetInstance() (string, error) {
	return d.MetadataFetcher.GetMetadata("instance-id")
}

func (d *Daemon) runHealthChecks() {
	log.Printf("Starting healthchecks")
	for _, v := range d.Config.Healthchecks {
		v.Run()
	}
	log.Printf("Done starting healthchecks")
}

func (d *Daemon) RunOneRouteTable(rt []*ec2.RouteTable, name string, configRouteTables *config.RouteTable) error {
	filter, err := configRouteTables.Find.GetFilter()
	if err != nil {
		return err
	}
	remaining := aws.FilterRouteTables(filter, rt)
	for _, rtb := range remaining {
		log.Printf("Finder name %s found route table %v", name, rtb)
		for _, upsertRoute := range configRouteTables.UpsertRoutes {
			log.Printf("Trying to upsert route to %s", upsertRoute.Cidr)
			if err := d.RunOneUpsertRoute(rtb, name, upsertRoute); err != nil {
				log.Printf(err.Error())
			}
		}
	}
	return nil
}

func (d *Daemon) RunOneUpsertRoute(rtb *ec2.RouteTable, name string, upsertRoute *config.UpsertRoutesSpec) error {
	destInstance := upsertRoute.Instance
	if upsertRoute.Instance == "SELF" {
		destInstance = d.Instance
	}
	if !d.oneShot && upsertRoute.Healthcheck != "" {
		log.Printf("Checking healthcheck: %s", upsertRoute.Healthcheck)
		if hc, ok := d.Config.Healthchecks[upsertRoute.Healthcheck]; ok {
			if !hc.IsHealthy() {
				log.Printf("Skipping upsert route %s, healthcheck %s isn't healthy yet", name, upsertRoute.Healthcheck)
				return nil
			}
		} else {
			panic("moo")
		}
		log.Printf("Is healthy")
	}

	return d.RouteTableFetcher.(aws.RouteTableFetcherEC2).CreateOrReplaceInstanceRoute(*rtb, upsertRoute.Cidr, destInstance, d.noop)
}

func (d *Daemon) RunRouteTables() error {
	rt, err := d.RouteTableFetcher.GetRouteTables()
	if err != nil {
		return err
	}
	for name, configRouteTables := range d.Config.RouteTables {
		if err := d.RunOneRouteTable(rt, name, configRouteTables); err != nil {
			return err
		}
	}
	return nil
}

func (d *Daemon) Run(oneShot bool, noop bool) int {
	d.oneShot = oneShot
	d.noop = noop
	if err := d.Setup(); err != nil {
		log.Printf("Error setting up: %s", err.Error())
		return 1
	}
	subnet, err := d.GetSubnetId()
	if err != nil {
		log.Printf("Error getting metadata: %s", err.Error())
		return 1
	}
	d.Subnet = subnet
	instanceId, err := d.GetInstance()
	if err != nil {
		log.Printf("Error getting metadata: %s", err.Error())
		return 1
	}
	d.Instance = instanceId
	d.quitChan = make(chan bool, 1)
	log.Printf(subnet)
	log.Printf(instanceId)
	if !oneShot {
		d.runHealthChecks()
		time.Sleep(time.Second * 3)
	}
	err = d.RunRouteTables()
	if err != nil {
		log.Printf("Error: %v", err)
		return 1
	}
	if oneShot {
		d.quitChan <- true
	}
	<-d.quitChan
	return 0
}
<|endoftext|>