<commit_before>package papaBot

import (
	"fmt"
	"github.com/pawelszydlo/papa-bot/utils"
	"math"
	"strconv"
	"strings"
	"text/template"
	"time"
)

// ExtensionCounters - enables the creation of custom counters.
type ExtensionCounters struct {
	Extension
	counters map[int]*extensionCountersCounter
}

type extensionCountersCounter struct {
	channel  string
	creator  string
	text     string
	textTmp  *template.Template
	interval time.Duration
	date     time.Time
	nextTick time.Time
}

// message will produce an announcement message for the counter.
func (cs *extensionCountersCounter) message() string {
	diff := time.Since(cs.date)
	days := int(math.Abs(diff.Hours())) / 24
	hours := int(math.Abs(diff.Hours())) - days*24
	minutes := int(math.Abs(diff.Minutes())) - hours*60 - days*1440
	vars := map[string]string{
		"days":    fmt.Sprintf("%d", days),
		"hours":   fmt.Sprintf("%d", hours),
		"minutes": fmt.Sprintf("%d", minutes),
		"since":   utils.HumanizedSince(cs.date),
	}
	return utils.Format(cs.textTmp, vars)
}

// Init initializes the extension.
func (ext *ExtensionCounters) Init(bot *Bot) error {
	// Create database table to hold the counters.
	query := `
		-- Main URLs table.
		CREATE TABLE IF NOT EXISTS "counters" (
			"id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL,
			"channel" VARCHAR NOT NULL,
			"creator" VARCHAR NOT NULL,
			"announce_text" VARCHAR NOT NULL,
			"interval" INTEGER NOT NULL,
			"target_date" VARCHAR NOT NULL,
			"created" DATETIME DEFAULT (datetime('now','localtime')),
			FOREIGN KEY(creator) REFERENCES users(nick)
		);`
	if _, err := bot.Db.Exec(query); err != nil {
		bot.log.Panic(err)
	}

	// Add commands for handling the counters.
	bot.commands["counter"] = &BotCommand{
		true, false, true,
		"counter help | list | announce [id] | del [id] | add [date] [time] [interval] [channel] [text]",
		"Controls custom counters.",
		ext.commandCounters}

	// Load counters from the db.
	ext.loadCounters(bot)

	return nil
}

// Tick will announce all the counters if needed.
func (ext *ExtensionCounters) Tick(bot *Bot, daily bool) {
	// Check if it's time to announce the counter.
	for id, c := range ext.counters {
		if time.Since(c.nextTick) > 0 {
			bot.SendNotice(c.channel, c.message())
			c.nextTick = c.nextTick.Add(c.interval * time.Hour)
			bot.log.Debug("Counter %d, next tick: %s", id, c.nextTick)
		}
	}
}

// loadCounters will load the counters from the database.
func (ext *ExtensionCounters) loadCounters(bot *Bot) {
	ext.counters = map[int]*extensionCountersCounter{}

	result, err := bot.Db.Query(
		`SELECT id, channel, creator, announce_text, interval, target_date FROM counters`)
	if err != nil {
		bot.log.Warning("Error while loading counters: %s", err)
		return
	}
	defer result.Close()

	// Get vars.
	for result.Next() {
		var c extensionCountersCounter
		var dateStr string
		var id int
		var interval int
		if err = result.Scan(&id, &c.channel, &c.creator, &c.text, &interval, &dateStr); err != nil {
			bot.log.Warning("Can't load counter: %s", err)
			continue
		}
		c.interval = time.Duration(interval)
		// Parse the text template.
		c.textTmp, err = template.New(fmt.Sprintf("counter_%d", id)).Parse(c.text)
		if err != nil {
			bot.log.Warning("Can't parse counter template '%s': %s", c.text, err)
		}
		// Handle the date.
		c.date, err = time.Parse("2006-01-02 15:04:05", dateStr)
		if err != nil {
			bot.log.Fatal("Can't parse counter date %s: %s", dateStr, err)
		}
		c.date = utils.MustForceLocalTimezone(c.date)
		// Calculate next tick. Start from next daily tick and move backwards.
		nextTick := bot.nextDailyTick
		for {
			c.nextTick = nextTick
			nextTick = nextTick.Add(-time.Duration(c.interval) * time.Hour)
			if time.Since(nextTick) > 0 { // We moved too far back.
				break
			}
		}
		bot.log.Debug("Counter %d, next tick: %s", id, c.nextTick)

		ext.counters[id] = &c
	}
}

// commandCounters is a command for handling the counters.
func (ext *ExtensionCounters) commandCounters(
	bot *Bot, nick, user, channel, receiver string, priv bool, params []string) {

	if len(params) < 1 {
		return
	}
	command := params[0]
	fullName := nick + "!" + user

	// List.
	if command == "list" {
		if len(ext.counters) > 0 {
			bot.SendMessage(receiver, "Counters:")
			for id, c := range ext.counters {
				bot.SendMessage(receiver, fmt.Sprintf(
					"%d: %s | %s | interval %dh | %s", id, c.channel, c.date, c.interval, c.text))
			}
		} else {
			bot.SendMessage(receiver, "No counters yet.")
		}
		return
	}

	if command == "help" {
		bot.SendMessage(nick, "To add a new counter:")
		bot.SendMessage(nick, "add [date] [time] [interval] [channel] [text]")
		bot.SendMessage(nick, `Where: date in format 'YYYY-MM-DD', time in format 'HH:MM:SS', interval is annouce
			interval in hours, channel is the name of the channel to announce on, text is the announcement text.`)
		bot.SendMessage(
			nick, "Announcement text may contain placeholders: {{ .days }}, {{ .hours }}, {{ .minutes }}, {{ .since }}")
		return
	}

	// Force announce.
	if len(params) == 2 && command == "announce" {
		id, err := strconv.Atoi(params[1])
		if err != nil || ext.counters[id] == nil {
			bot.SendMessage(receiver, "Wrong id.")
			return
		}
		bot.SendMessage(receiver, fmt.Sprintf("Announcing counter %d to %s...", id, ext.counters[id].channel))
		bot.SendMessage(ext.counters[id].channel, ext.counters[id].message())
	}

	// Delete.
	if len(params) == 2 && command == "del" {
		id := params[1]
		bot.SendMessage(receiver, fmt.Sprintf("Deleting counter number %s...", id))
		query := ""
		// Bot owner can delete all counters.
		if bot.userIsOwner(fullName) {
			query = `DELETE FROM counters WHERE id=?;`
		} else {
			// User must be an admin, he can delete only his own counters.
			nick := bot.authenticatedAdmins[fullName]
			query = fmt.Sprintf(`DELETE FROM counters WHERE id=? AND creator="%s";`, nick)
		}
		if _, err := bot.Db.Exec(query, id); err != nil {
			bot.log.Warning("Error while deleting a counter: %s", err)
			bot.SendMessage(receiver, fmt.Sprintf("Error: %s", err))
			return
		}
		// Reload  counters.
		ext.loadCounters(bot)
		return
	}

	// Add.
	if len(params) > 5 && command == "add" {
		// Sanity check parameters.
		date, err := time.Parse("2006-01-0215:04:05", params[1]+params[2])
		if err != nil {
			bot.SendMessage(receiver, "Date and time must be in format: 2015-12-31 12:54:00")
			return
		}
		interval, err := strconv.ParseInt(params[3], 10, 32)
		if err != nil {
			bot.SendMessage(receiver, "interval parameter must be a number.")
			return
		}
		channel = params[4]
		if !bot.onChannel[channel] {
			bot.SendMessage(receiver, "I am not on channel: "+channel)
			return
		}

		text := strings.Join(params[5:], " ")
		nick := bot.authenticatedAdmins[fullName]
		// Add counter to database.
		query := `
			INSERT INTO counters (channel, creator, announce_text, interval, target_date)
			VALUES (?, ?, ?, ?, ?);
			`
		if _, err := bot.Db.Exec(query, channel, nick, text, interval, date); err != nil {
			bot.log.Warning("Error while adding a counter: %s", err)
			bot.SendMessage(receiver, fmt.Sprintf("Error: %s", err))
			return
		}
		bot.SendMessage(receiver, "Counter created.")
		// Reload  counters.
		ext.loadCounters(bot)
		return
	}
}
<commit_msg>Fix timezone problems.<commit_after>package papaBot

import (
	"fmt"
	"github.com/pawelszydlo/papa-bot/utils"
	"math"
	"strconv"
	"strings"
	"text/template"
	"time"
)

// ExtensionCounters - enables the creation of custom counters.
type ExtensionCounters struct {
	Extension
	counters map[int]*extensionCountersCounter
}

type extensionCountersCounter struct {
	channel  string
	creator  string
	text     string
	textTmp  *template.Template
	interval time.Duration
	date     time.Time
	nextTick time.Time
}

// message will produce an announcement message for the counter.
func (cs *extensionCountersCounter) message() string {
	diff := time.Since(cs.date)
	days := int(math.Abs(diff.Hours())) / 24
	hours := int(math.Abs(diff.Hours())) - days*24
	minutes := int(math.Abs(diff.Minutes())) - hours*60 - days*1440
	vars := map[string]string{
		"days":    fmt.Sprintf("%d", days),
		"hours":   fmt.Sprintf("%d", hours),
		"minutes": fmt.Sprintf("%d", minutes),
		"since":   utils.HumanizedSince(cs.date),
	}
	return utils.Format(cs.textTmp, vars)
}

// Init initializes the extension.
func (ext *ExtensionCounters) Init(bot *Bot) error {
	// Create database table to hold the counters.
	query := `
		-- Main URLs table.
		CREATE TABLE IF NOT EXISTS "counters" (
			"id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL,
			"channel" VARCHAR NOT NULL,
			"creator" VARCHAR NOT NULL,
			"announce_text" VARCHAR NOT NULL,
			"interval" INTEGER NOT NULL,
			"target_date" VARCHAR NOT NULL,
			"created" DATETIME DEFAULT (datetime('now','localtime')),
			FOREIGN KEY(creator) REFERENCES users(nick)
		);`
	if _, err := bot.Db.Exec(query); err != nil {
		bot.log.Panic(err)
	}

	// Add commands for handling the counters.
	bot.commands["counter"] = &BotCommand{
		true, false, true,
		"counter help | list | announce [id] | del [id] | add [date] [time] [interval] [channel] [text]",
		"Controls custom counters.",
		ext.commandCounters}

	// Load counters from the db.
	ext.loadCounters(bot)

	return nil
}

// Tick will announce all the counters if needed.
func (ext *ExtensionCounters) Tick(bot *Bot, daily bool) {
	// Check if it's time to announce the counter.
	for id, c := range ext.counters {
		if time.Since(c.nextTick) > 0 {
			bot.SendNotice(c.channel, c.message())
			c.nextTick = c.nextTick.Add(c.interval * time.Hour)
			bot.log.Debug("Counter %d, next tick: %s", id, c.nextTick)
		}
	}
}

// loadCounters will load the counters from the database.
func (ext *ExtensionCounters) loadCounters(bot *Bot) {
	ext.counters = map[int]*extensionCountersCounter{}

	result, err := bot.Db.Query(
		`SELECT id, channel, creator, announce_text, interval, target_date FROM counters`)
	if err != nil {
		bot.log.Warning("Error while loading counters: %s", err)
		return
	}
	defer result.Close()

	// Get vars.
	for result.Next() {
		var c extensionCountersCounter
		var dateStr string
		var id int
		var interval int
		if err = result.Scan(&id, &c.channel, &c.creator, &c.text, &interval, &dateStr); err != nil {
			bot.log.Warning("Can't load counter: %s", err)
			continue
		}
		c.interval = time.Duration(interval)
		// Parse the text template.
		c.textTmp, err = template.New(fmt.Sprintf("counter_%d", id)).Parse(c.text)
		if err != nil {
			bot.log.Warning("Can't parse counter template '%s': %s", c.text, err)
		}
		// Handle the date.
		c.date, err = time.Parse("2006-01-02 15:04:05", dateStr)
		if err != nil {
			bot.log.Fatal("Can't parse counter date %s: %s", dateStr, err)
		}
		c.date = utils.MustForceLocalTimezone(c.date)
		// Calculate next tick. Start from next daily tick and move backwards.
		nextTick := bot.nextDailyTick
		for {
			c.nextTick = nextTick
			nextTick = nextTick.Add(-time.Duration(c.interval) * time.Hour)
			if time.Since(nextTick) > 0 { // We moved too far back.
				break
			}
		}
		bot.log.Debug("Counter %d, next tick: %s", id, c.nextTick)

		ext.counters[id] = &c
	}
}

// commandCounters is a command for handling the counters.
func (ext *ExtensionCounters) commandCounters(
	bot *Bot, nick, user, channel, receiver string, priv bool, params []string) {

	if len(params) < 1 {
		return
	}
	command := params[0]
	fullName := nick + "!" + user

	// List.
	if command == "list" {
		if len(ext.counters) > 0 {
			bot.SendMessage(receiver, "Counters:")
			for id, c := range ext.counters {
				bot.SendMessage(receiver, fmt.Sprintf(
					"%d: %s | %s | interval %dh | %s", id, c.channel, c.date, c.interval, c.text))
			}
		} else {
			bot.SendMessage(receiver, "No counters yet.")
		}
		return
	}

	if command == "help" {
		bot.SendMessage(nick, "To add a new counter:")
		bot.SendMessage(nick, "add [date] [time] [interval] [channel] [text]")
		bot.SendMessage(nick, `Where: date in format 'YYYY-MM-DD', time in format 'HH:MM:SS', interval is annouce
			interval in hours, channel is the name of the channel to announce on, text is the announcement text.`)
		bot.SendMessage(
			nick, "Announcement text may contain placeholders: {{ .days }}, {{ .hours }}, {{ .minutes }}, {{ .since }}")
		return
	}

	// Force announce.
	if len(params) == 2 && command == "announce" {
		id, err := strconv.Atoi(params[1])
		if err != nil || ext.counters[id] == nil {
			bot.SendMessage(receiver, "Wrong id.")
			return
		}
		bot.SendMessage(receiver, fmt.Sprintf("Announcing counter %d to %s...", id, ext.counters[id].channel))
		bot.SendMessage(ext.counters[id].channel, ext.counters[id].message())
	}

	// Delete.
	if len(params) == 2 && command == "del" {
		id := params[1]
		bot.SendMessage(receiver, fmt.Sprintf("Deleting counter number %s...", id))
		query := ""
		// Bot owner can delete all counters.
		if bot.userIsOwner(fullName) {
			query = `DELETE FROM counters WHERE id=?;`
		} else {
			// User must be an admin, he can delete only his own counters.
			nick := bot.authenticatedAdmins[fullName]
			query = fmt.Sprintf(`DELETE FROM counters WHERE id=? AND creator="%s";`, nick)
		}
		if _, err := bot.Db.Exec(query, id); err != nil {
			bot.log.Warning("Error while deleting a counter: %s", err)
			bot.SendMessage(receiver, fmt.Sprintf("Error: %s", err))
			return
		}
		// Reload  counters.
		ext.loadCounters(bot)
		return
	}

	// Add.
	if len(params) > 5 && command == "add" {
		// Sanity check parameters.
		if _, err := time.Parse("2006-01-0215:04:05", params[1]+params[2]); err != nil {
			bot.SendMessage(receiver, "Date and time must be in format: 2015-12-31 12:54:00")
			return
		}
		dateStr := params[1] + " " + params[2]
		interval, err := strconv.ParseInt(params[3], 10, 32)
		if err != nil {
			bot.SendMessage(receiver, "interval parameter must be a number.")
			return
		}
		channel = params[4]
		if !bot.onChannel[channel] {
			bot.SendMessage(receiver, "I am not on channel: "+channel)
			return
		}

		text := strings.Join(params[5:], " ")
		nick := bot.authenticatedAdmins[fullName]
		// Add counter to database.
		query := `
			INSERT INTO counters (channel, creator, announce_text, interval, target_date)
			VALUES (?, ?, ?, ?, ?);
			`
		if _, err := bot.Db.Exec(query, channel, nick, text, interval, dateStr); err != nil {
			bot.log.Warning("Error while adding a counter: %s", err)
			bot.SendMessage(receiver, fmt.Sprintf("Error: %s", err))
			return
		}
		bot.SendMessage(receiver, "Counter created.")
		// Reload  counters.
		ext.loadCounters(bot)
		return
	}
}
<|endoftext|>


<commit_before>package controller

import (
	. "eaciit/wfdemo-git/library/core"
	. "eaciit/wfdemo-git/library/models"
	"eaciit/wfdemo-git/web/helper"
	"sort"
	"strings"
	"time"

	"github.com/eaciit/knot/knot.v1"
	tk "github.com/eaciit/toolkit"
)

type XyAnalysis struct {
	App
}

func CreateXyAnalysisController() *XyAnalysis {
	var controller = new(XyAnalysis)
	return controller
}

type FieldAnalysis struct {
	Id    string
	Name  string
	Aggr  string
	Text  string
	Order int
}

type PayloadXyAnalysis struct {
	Period    string
	Project   []string
	Engine    string
	Turbine   []interface{}
	DateStart time.Time
	DateEnd   time.Time
	XAxis     FieldAnalysis
	Y1Axis    FieldAnalysis
	Y2Axis    FieldAnalysis
}

func (m *XyAnalysis) GetXYFieldList(k *knot.WebContext) interface{} {
	k.Config.OutputType = knot.OutputJson
	result := []FieldAnalysis{}

	//manual first
	result = append(result, FieldAnalysis{Id: "ActivePower_kW", Name: "ActivePower", Aggr: "$sum", Order: 1, Text: "ActivePower (MWh)"})
	result = append(result, FieldAnalysis{Id: "WindSpeed_ms", Name: "WindSpeed", Aggr: "$avg", Order: 2, Text: "WindSpeed (m/s)"})
	result = append(result, FieldAnalysis{Id: "NacellePos", Name: "NacellePos", Aggr: "$avg", Order: 3, Text: "NacellePos (-)"})
	result = append(result, FieldAnalysis{Id: "WindDirection", Name: "WindDirection", Aggr: "$avg", Order: 4, Text: "WindDirection (-)"})
	result = append(result, FieldAnalysis{Id: "PitchAngle", Name: "PitchAngle", Aggr: "$avg", Order: 5, Text: "PitchAngle (-)"})
	result = append(result, FieldAnalysis{Id: "TempOutdoor", Name: "TempOutdoor", Aggr: "$avg", Order: 6, Text: "TempOutdoor (°C)"})

	return helper.CreateResult(true, result, "success")
}

func (m *XyAnalysis) GetData(k *knot.WebContext) interface{} {
	k.Config.OutputType = knot.OutputJson

	p := new(PayloadXyAnalysis)
	e := k.GetPayload(&p)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	tStart, tEnd, e := helper.GetStartEndDate(k, p.Period, p.DateStart, p.DateEnd)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	var turbineList []TurbineOut
	if len(p.Project) == 1 {
		turbineList, _ = helper.GetTurbineList([]interface{}{p.Project[0]})
	} else {
		turbineList, _ = helper.GetTurbineList(nil)
	}

	dataSeries := []tk.M{}

	matches := tk.M{"dateinfo.dateid": tk.M{"$gte": tStart, "$lte": tEnd}}
	if len(p.Project) == 1 {
		matches.Set("projectname", p.Project[0])
	} else {
		matches.Set("projectname", tk.M{}.Set("$in", p.Project))
	}
	matches.Set("turbine", tk.M{}.Set("$in", p.Turbine))

	// ids := tk.M{"project": "$projectname", "turbine": "$turbine", "xaxis": "$" + p.XAxis.Id}

	// county1 := tk.M{"$cond": tk.M{}.
	// 	Set("if", tk.M{"$ifNull": []interface{}{"$" + p.Y1Axis.Id, false}}).
	// 	Set("then", 1).
	// 	Set("else", 0)}

	// county2 := tk.M{"$cond": tk.M{}.
	// 	Set("if", tk.M{"$ifNull": []interface{}{"$" + p.Y2Axis.Id, false}}).
	// 	Set("then", 1).
	// 	Set("else", 0)}

	// pipe := []tk.M{{"$match": matches},
	// 	{"$group": tk.M{
	// 		"_id":          ids,
	// 		"y1axis_sum":   tk.M{"$sum": "$" + p.Y1Axis.Id},
	// 		"y1axis_count": tk.M{"$sum": county1},
	// 		"y2axis_sum":   tk.M{"$sum": "$" + p.Y2Axis.Id},
	// 		"y2axis_count": tk.M{"$sum": county2},
	// 	}}}

	pipe := []tk.M{{"$match": matches},
		{"$project": tk.M{"projectname": 1, "turbine": 1, strings.ToLower(p.Y1Axis.Id): 1, strings.ToLower(p.Y2Axis.Id): 1, strings.ToLower(p.XAxis.Id): 1}}}

	csr, e := DB().Connection.NewQuery().
		From("Scada10MinHFD").
		Command("pipe", pipe).
		Cursor(nil)

	// tk.Println(pipe)

	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}
	defer csr.Close()

	alltkm, allturb := tk.M{}, []string{}
	for {
		tkm, ds := tk.M{}, tk.M{}
		e = csr.Fetch(&tkm, 1, false)

		if e != nil {
			break
		}

		// tk.Println(tkm)

		_key := ""
		for _, v := range turbineList {
			if tkm.GetString("turbine") == v.Value {
				// capacity = v.Capacity
				_key = v.Turbine
				// ds.Set("turbine", v.Turbine)
			}
		}

		ds = alltkm.Get(_key, tk.M{}).(tk.M)

		data1y := ds.Get("data1y", map[float64]interface{}{}).(map[float64]interface{})
		data2y := ds.Get("data2y", map[float64]interface{}{}).(map[float64]interface{})

		xaxis := tk.ToFloat64(tkm.Get(strings.ToLower(p.XAxis.Id)), 2, tk.RoundingAuto)

		data1y[xaxis] = tkm.Get(strings.ToLower(p.Y1Axis.Id), nil)
		data2y[xaxis] = tkm.Get(strings.ToLower(p.Y2Axis.Id), nil)

		ds.Set("id", tkm.GetString("turbine"))
		ds.Set("turbine", _key)
		ds.Set("dashType", "solid")
		ds.Set("style", "smooth")
		ds.Set("type", "scatter")
		ds.Set("data1y", data1y)
		ds.Set("data2y", data2y)

		alltkm.Set(_key, ds)
	}

	for key, _ := range alltkm {
		allturb = append(allturb, key)
		ds := alltkm.Get(key, tk.M{}).(tk.M)
		data1y := ds.Get("data1y", map[float64]interface{}{}).(map[float64]interface{})
		data2y := ds.Get("data2y", map[float64]interface{}{}).(map[float64]interface{})

		_data2y := make([][]interface{}, 0)

		// _data1y, _data2y := make([][]float64, 0), make([][]float64, 0)

		for _x, _y := range data1y {
			_y2 := data2y[_x]
			_data2y = append(_data2y, []interface{}{_x, _y, _y2})
		}

		// for _x, _y := range data2y {
		// 	_data2y = append(_data2y, []float64{_x, _y})
		// }

		// ds.Set("data1y", _data1y)
		// ds.Set("data2y", _data2y)

		ds.Set("detail", _data2y)

		ds.Unset("data1y")
		ds.Unset("data2y")

		alltkm.Set(key, ds)
	}

	sort.Strings(allturb)
	for _, turb := range allturb {
		dataSeries = append(dataSeries, alltkm.Get(turb, tk.M{}).(tk.M))
	}

	result := tk.M{}.
		Set("totalturbine", len(p.Turbine)).
		Set("data", dataSeries).
		Set("turbine", allturb).
		Set("axisinfo", []FieldAnalysis{p.XAxis, p.Y1Axis, p.Y2Axis})
	return helper.CreateResult(true, result, "success")
}
<commit_msg>changes into kWh for power measurement<commit_after>package controller

import (
	. "eaciit/wfdemo-git/library/core"
	. "eaciit/wfdemo-git/library/models"
	"eaciit/wfdemo-git/web/helper"
	"sort"
	"strings"
	"time"

	"github.com/eaciit/knot/knot.v1"
	tk "github.com/eaciit/toolkit"
)

type XyAnalysis struct {
	App
}

func CreateXyAnalysisController() *XyAnalysis {
	var controller = new(XyAnalysis)
	return controller
}

type FieldAnalysis struct {
	Id    string
	Name  string
	Aggr  string
	Text  string
	Order int
}

type PayloadXyAnalysis struct {
	Period    string
	Project   []string
	Engine    string
	Turbine   []interface{}
	DateStart time.Time
	DateEnd   time.Time
	XAxis     FieldAnalysis
	Y1Axis    FieldAnalysis
	Y2Axis    FieldAnalysis
}

func (m *XyAnalysis) GetXYFieldList(k *knot.WebContext) interface{} {
	k.Config.OutputType = knot.OutputJson
	result := []FieldAnalysis{}

	//manual first
	result = append(result, FieldAnalysis{Id: "ActivePower_kW", Name: "ActivePower", Aggr: "$sum", Order: 1, Text: "ActivePower (kWh)"})
	result = append(result, FieldAnalysis{Id: "WindSpeed_ms", Name: "WindSpeed", Aggr: "$avg", Order: 2, Text: "WindSpeed (m/s)"})
	result = append(result, FieldAnalysis{Id: "NacellePos", Name: "NacellePos", Aggr: "$avg", Order: 3, Text: "NacellePos (-)"})
	result = append(result, FieldAnalysis{Id: "WindDirection", Name: "WindDirection", Aggr: "$avg", Order: 4, Text: "WindDirection (-)"})
	result = append(result, FieldAnalysis{Id: "PitchAngle", Name: "PitchAngle", Aggr: "$avg", Order: 5, Text: "PitchAngle (-)"})
	result = append(result, FieldAnalysis{Id: "TempOutdoor", Name: "TempOutdoor", Aggr: "$avg", Order: 6, Text: "TempOutdoor (°C)"})

	return helper.CreateResult(true, result, "success")
}

func (m *XyAnalysis) GetData(k *knot.WebContext) interface{} {
	k.Config.OutputType = knot.OutputJson

	p := new(PayloadXyAnalysis)
	e := k.GetPayload(&p)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	tStart, tEnd, e := helper.GetStartEndDate(k, p.Period, p.DateStart, p.DateEnd)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	var turbineList []TurbineOut
	if len(p.Project) == 1 {
		turbineList, _ = helper.GetTurbineList([]interface{}{p.Project[0]})
	} else {
		turbineList, _ = helper.GetTurbineList(nil)
	}

	dataSeries := []tk.M{}

	matches := tk.M{"dateinfo.dateid": tk.M{"$gte": tStart, "$lte": tEnd}}
	if len(p.Project) == 1 {
		matches.Set("projectname", p.Project[0])
	} else {
		matches.Set("projectname", tk.M{}.Set("$in", p.Project))
	}
	matches.Set("turbine", tk.M{}.Set("$in", p.Turbine))

	// ids := tk.M{"project": "$projectname", "turbine": "$turbine", "xaxis": "$" + p.XAxis.Id}

	// county1 := tk.M{"$cond": tk.M{}.
	// 	Set("if", tk.M{"$ifNull": []interface{}{"$" + p.Y1Axis.Id, false}}).
	// 	Set("then", 1).
	// 	Set("else", 0)}

	// county2 := tk.M{"$cond": tk.M{}.
	// 	Set("if", tk.M{"$ifNull": []interface{}{"$" + p.Y2Axis.Id, false}}).
	// 	Set("then", 1).
	// 	Set("else", 0)}

	// pipe := []tk.M{{"$match": matches},
	// 	{"$group": tk.M{
	// 		"_id":          ids,
	// 		"y1axis_sum":   tk.M{"$sum": "$" + p.Y1Axis.Id},
	// 		"y1axis_count": tk.M{"$sum": county1},
	// 		"y2axis_sum":   tk.M{"$sum": "$" + p.Y2Axis.Id},
	// 		"y2axis_count": tk.M{"$sum": county2},
	// 	}}}

	pipe := []tk.M{{"$match": matches},
		{"$project": tk.M{"projectname": 1, "turbine": 1, strings.ToLower(p.Y1Axis.Id): 1, strings.ToLower(p.Y2Axis.Id): 1, strings.ToLower(p.XAxis.Id): 1}}}

	csr, e := DB().Connection.NewQuery().
		From("Scada10MinHFD").
		Command("pipe", pipe).
		Cursor(nil)

	// tk.Println(pipe)

	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}
	defer csr.Close()

	alltkm, allturb := tk.M{}, []string{}
	for {
		tkm, ds := tk.M{}, tk.M{}
		e = csr.Fetch(&tkm, 1, false)

		if e != nil {
			break
		}

		// tk.Println(tkm)

		_key := ""
		for _, v := range turbineList {
			if tkm.GetString("turbine") == v.Value {
				// capacity = v.Capacity
				_key = v.Turbine
				// ds.Set("turbine", v.Turbine)
			}
		}

		ds = alltkm.Get(_key, tk.M{}).(tk.M)

		data1y := ds.Get("data1y", map[float64]interface{}{}).(map[float64]interface{})
		data2y := ds.Get("data2y", map[float64]interface{}{}).(map[float64]interface{})

		xaxis := tk.ToFloat64(tkm.Get(strings.ToLower(p.XAxis.Id)), 2, tk.RoundingAuto)

		data1y[xaxis] = tkm.Get(strings.ToLower(p.Y1Axis.Id), nil)
		data2y[xaxis] = tkm.Get(strings.ToLower(p.Y2Axis.Id), nil)

		ds.Set("id", tkm.GetString("turbine"))
		ds.Set("turbine", _key)
		ds.Set("dashType", "solid")
		ds.Set("style", "smooth")
		ds.Set("type", "scatter")
		ds.Set("data1y", data1y)
		ds.Set("data2y", data2y)

		alltkm.Set(_key, ds)
	}

	for key, _ := range alltkm {
		allturb = append(allturb, key)
		ds := alltkm.Get(key, tk.M{}).(tk.M)
		data1y := ds.Get("data1y", map[float64]interface{}{}).(map[float64]interface{})
		data2y := ds.Get("data2y", map[float64]interface{}{}).(map[float64]interface{})

		_data2y := make([][]interface{}, 0)

		// _data1y, _data2y := make([][]float64, 0), make([][]float64, 0)

		for _x, _y := range data1y {
			_y2 := data2y[_x]
			_data2y = append(_data2y, []interface{}{_x, _y, _y2})
		}

		// for _x, _y := range data2y {
		// 	_data2y = append(_data2y, []float64{_x, _y})
		// }

		// ds.Set("data1y", _data1y)
		// ds.Set("data2y", _data2y)

		ds.Set("detail", _data2y)

		ds.Unset("data1y")
		ds.Unset("data2y")

		alltkm.Set(key, ds)
	}

	sort.Strings(allturb)
	for _, turb := range allturb {
		dataSeries = append(dataSeries, alltkm.Get(turb, tk.M{}).(tk.M))
	}

	result := tk.M{}.
		Set("totalturbine", len(p.Turbine)).
		Set("data", dataSeries).
		Set("turbine", allturb).
		Set("axisinfo", []FieldAnalysis{p.XAxis, p.Y1Axis, p.Y2Axis})
	return helper.CreateResult(true, result, "success")
}
<|endoftext|>


<commit_before>package render_test

import (
	"testing"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
)

func TestMapEndpointIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4"}), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Port: "1234"}), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "1234"}), true},
		{report.MakeNodeMetadataWith(map[string]string{report.HostNodeID: report.MakeHostNodeID("foo"), endpoint.Addr: "10.0.0.1", endpoint.Port: "20001"}), true},
	} {
		testMap(t, render.MapEndpointIdentity, input)
	}
}

func TestMapProcessIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{process.PID: "201"}), true},
	} {
		testMap(t, render.MapProcessIdentity, input)
	}
}

func TestMapContainerIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{docker.ContainerID: "a1b2c3"}), true},
	} {
		testMap(t, render.MapContainerIdentity, input)
	}
}

func TestMapContainerImageIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{docker.ImageID: "a1b2c3"}), true},
	} {
		testMap(t, render.MapContainerImageIdentity, input)
	}
}

func TestMapAddressIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "192.168.1.1"}), true},
	} {
		testMap(t, render.MapAddressIdentity, input)
	}
}

func TestMapHostIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), true}, // TODO it's questionable if this is actually correct
	} {
		testMap(t, render.MapHostIdentity, input)
	}
}

type testcase struct {
	md report.NodeMetadata
	ok bool
}

func testMap(t *testing.T, f render.LeafMapFunc, input testcase) {
	if have := f(input.md, report.Networks{}); input.ok != (len(have) > 0) {
		t.Errorf("%v: want %v, have %v", input.md, input.ok, have)
	}
}
<commit_msg>Add tests to catch bad pseudo node mapping.<commit_after>package render_test

import (
	"net"
	"testing"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
)

func TestMapEndpointIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4"}), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Port: "1234"}), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "1234"}), true},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "1.2.3.4", endpoint.Port: "40000"}), true},
		{report.MakeNodeMetadataWith(map[string]string{report.HostNodeID: report.MakeHostNodeID("foo"), endpoint.Addr: "10.0.0.1", endpoint.Port: "20001"}), true},
	} {
		testMap(t, render.MapEndpointIdentity, input)
	}
}

func TestMapProcessIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{process.PID: "201"}), true},
	} {
		testMap(t, render.MapProcessIdentity, input)
	}
}

func TestMapContainerIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{docker.ContainerID: "a1b2c3"}), true},
	} {
		testMap(t, render.MapContainerIdentity, input)
	}
}

func TestMapContainerImageIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{docker.ImageID: "a1b2c3"}), true},
	} {
		testMap(t, render.MapContainerImageIdentity, input)
	}
}

func TestMapAddressIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), false},
		{report.MakeNodeMetadataWith(map[string]string{endpoint.Addr: "192.168.1.1"}), true},
	} {
		testMap(t, render.MapAddressIdentity, input)
	}
}

func TestMapHostIdentity(t *testing.T) {
	for _, input := range []testcase{
		{report.MakeNodeMetadata(), true}, // TODO it's questionable if this is actually correct
	} {
		testMap(t, render.MapHostIdentity, input)
	}
}

type testcase struct {
	md report.NodeMetadata
	ok bool
}

func testMap(t *testing.T, f render.LeafMapFunc, input testcase) {
	_, ipNet, err := net.ParseCIDR("1.2.3.0/16")
	if err != nil {
		t.Fatalf(err.Error())
	}
	localNetworks := report.Networks([]*net.IPNet{ipNet})
	if have := f(input.md, localNetworks); input.ok != (len(have) > 0) {
		t.Errorf("%v: want %v, have %v", input.md, input.ok, have)
	}
}
<|endoftext|>


<commit_before>package factory

import (
	"os"
	"os/exec"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	//"github.com/huawei-openlab/oct/hostendvalidate"
)

type RKT struct {
	name string
}

func (this *RKT) SetRT(runtime string) {
	this.name = "rkt"
}

func (this *RKT) GetRT() string {
	return "rkt"
}

func (this *RKT) StartRT(specDir string) error {

	logrus.Debugf("Launcing runtime")
	/*rkt run 3.aci --interactive --insecure-skip-verify --mds-register=false --volume proc,kind=host,source=/bin --volume dev,kind=host,source=/bin --volume devpts,kind=host,source=/bin --volume shm,kind=host,source=/bin --volume mqueue,kind=host,source=/bin --volume sysfs,kind=host,source=/bin --volume cgroup,kind=host,source=/bin*/
	aciName := filepath.Base(specDir) + ".aci"
	aciPath := filepath.Dir(specDir)
	cmd := exec.Command("rkt", "run", aciName, "--interactive", "--insecure-skip-verify", "--mds-register=false",
		"--volume", "proc,kind=host,source=/bin", "--volume", "dev,kind=host,source=/bin", "--volume", "devpts,kind=host,source=/bin",
		"--volume", "shm,kind=host,source=/bin", "--volume", "mqueue,kind=host,source=/bin",
		"--volume", "sysfs,kind=host,source=/bin", "--volume", "cgroup,kind=host,source=/bin")
	cmd.Dir = aciPath
	cmd.Stdin = os.Stdin
	out, err := cmd.CombinedOutput()
	/*if err := hostendvalidate.ContainerOutputHandler(string(out)); err != nil {
		return err
	}*/
	logrus.Debugf("Command done")
	if string(out) != "" {
		logrus.Debugf("container output=%s\n", out)
	} else {
		logrus.Debugf("container output= nil\n")
	}
	if err != nil {
		return err
	}
	return nil
}

func (this *RKT) StopRT() error {
	return nil
}
<commit_msg>Add error output of rkt<commit_after>package factory

import (
	"os"
	"os/exec"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	//"github.com/huawei-openlab/oct/hostendvalidate"
)

type RKT struct {
	name string
}

func (this *RKT) SetRT(runtime string) {
	this.name = "rkt"
}

func (this *RKT) GetRT() string {
	return "rkt"
}

func (this *RKT) StartRT(specDir string) error {

	logrus.Debugf("Launcing runtime")
	/*rkt run 3.aci --interactive --insecure-skip-verify --mds-register=false --volume proc,kind=host,source=/bin --volume dev,kind=host,source=/bin --volume devpts,kind=host,source=/bin --volume shm,kind=host,source=/bin --volume mqueue,kind=host,source=/bin --volume sysfs,kind=host,source=/bin --volume cgroup,kind=host,source=/bin*/
	aciName := filepath.Base(specDir) + ".aci"
	aciPath := filepath.Dir(specDir)
	cmd := exec.Command("rkt", "run", aciName, "--interactive", "--insecure-skip-verify", "--mds-register=false",
		"--volume", "proc,kind=host,source=/bin", "--volume", "dev,kind=host,source=/bin", "--volume", "devpts,kind=host,source=/bin",
		"--volume", "shm,kind=host,source=/bin", "--volume", "mqueue,kind=host,source=/bin",
		"--volume", "sysfs,kind=host,source=/bin", "--volume", "cgroup,kind=host,source=/bin")
	cmd.Dir = aciPath
	cmd.Stdin = os.Stdin
	out, err := cmd.CombinedOutput()
	/*if err := hostendvalidate.ContainerOutputHandler(string(out)); err != nil {
		return err
	}*/
	logrus.Debugf("Command done")
	if string(out) != "" {
		logrus.Infof("container output=%s\n", out)
	} else {
		logrus.Debugf("container output= nil\n")
	}
	if err != nil {
		return err
	}
	return nil
}

func (this *RKT) StopRT() error {
	return nil
}
<|endoftext|>


<commit_before>package runtime

import (
	"io"
	"strconv"
	"sync"
	"time"

	"github.com/micro/go-micro/v2/runtime/local/build"
	"github.com/micro/go-micro/v2/runtime/local/process"
	proc "github.com/micro/go-micro/v2/runtime/local/process/os"
	"github.com/micro/go-micro/v2/util/log"
)

type service struct {
	sync.RWMutex

	running bool
	closed  chan bool
	err     error
	updated time.Time

	retries    int
	maxRetries int

	// output for logs
	output io.Writer

	// service to manage
	*Service
	// process creator
	Process *proc.Process
	// Exec
	Exec *process.Executable
	// process pid
	PID *process.PID
}

func newService(s *Service, c CreateOptions) *service {
	var exec string
	var args []string

	// set command
	exec = c.Command[0]
	// set args
	if len(c.Command) > 1 {
		args = c.Command[1:]
	}

	return &service{
		Service: s,
		Process: new(proc.Process),
		Exec: &process.Executable{
			Package: &build.Package{
				Name: s.Name,
				Path: exec,
			},
			Env:  c.Env,
			Args: args,
		},
		closed:     make(chan bool),
		output:     c.Output,
		updated:    time.Now(),
		maxRetries: c.Retries,
	}
}

func (s *service) streamOutput() {
	go io.Copy(s.output, s.PID.Output)
	go io.Copy(s.output, s.PID.Error)
}

func (s *service) ShouldStart() bool {
	s.RLock()
	defer s.RUnlock()

	if s.running {
		return false
	}

	return s.maxRetries < s.retries
}

func (s *service) Running() bool {
	s.RLock()
	defer s.RUnlock()
	return s.running
}

// Start stars the service
func (s *service) Start() error {
	s.Lock()
	defer s.Unlock()

	if !s.ShouldStart() {
		return nil
	}

	// reset
	s.err = nil
	s.closed = make(chan bool)

	if s.Metadata == nil {
		s.Metadata = make(map[string]string)
	}

	s.Metadata["status"] = "starting"
	// delete any existing error
	delete(s.Metadata, "error")

	// TODO: pull source & build binary
	log.Debugf("Runtime service %s forking new process", s.Service.Name)
	p, err := s.Process.Fork(s.Exec)
	if err != nil {
		s.Metadata["status"] = "error"
		s.Metadata["error"] = err.Error()
		return err
	}

	// set the pid
	s.PID = p
	// set to running
	s.running = true
	// set status
	s.Metadata["status"] = "running"

	if s.output != nil {
		s.streamOutput()
	}

	// wait and watch
	go s.Wait()

	return nil
}

// Stop stops the service
func (s *service) Stop() error {
	s.Lock()
	defer s.Unlock()

	select {
	case <-s.closed:
		return nil
	default:
		close(s.closed)
		s.running = false
		if s.PID == nil {
			return nil
		}

		// set status
		s.Metadata["status"] = "stopping"

		// kill the process
		err := s.Process.Kill(s.PID)
		// wait for it to exit
		s.Process.Wait(s.PID)

		// set status
		s.Metadata["status"] = "stopped"

		// return the kill error
		return err
	}
}

// Error returns the last error service has returned
func (s *service) Error() error {
	s.RLock()
	defer s.RUnlock()
	return s.err
}

// Wait waits for the service to finish running
func (s *service) Wait() {
	// wait for process to exit
	err := s.Process.Wait(s.PID)

	s.Lock()
	defer s.Unlock()

	// save the error
	if err != nil {
		s.retries++
		s.Metadata["status"] = "error"
		s.Metadata["error"] = err.Error()
		s.Metadata["retries"] = strconv.Itoa(s.retries)

		s.err = err
	} else {
		s.Metadata["status"] = "done"
	}

	// no longer running
	s.running = false
}
<commit_msg>fix deadlock<commit_after>package runtime

import (
	"io"
	"strconv"
	"sync"
	"time"

	"github.com/micro/go-micro/v2/runtime/local/build"
	"github.com/micro/go-micro/v2/runtime/local/process"
	proc "github.com/micro/go-micro/v2/runtime/local/process/os"
	"github.com/micro/go-micro/v2/util/log"
)

type service struct {
	sync.RWMutex

	running bool
	closed  chan bool
	err     error
	updated time.Time

	retries    int
	maxRetries int

	// output for logs
	output io.Writer

	// service to manage
	*Service
	// process creator
	Process *proc.Process
	// Exec
	Exec *process.Executable
	// process pid
	PID *process.PID
}

func newService(s *Service, c CreateOptions) *service {
	var exec string
	var args []string

	// set command
	exec = c.Command[0]
	// set args
	if len(c.Command) > 1 {
		args = c.Command[1:]
	}

	return &service{
		Service: s,
		Process: new(proc.Process),
		Exec: &process.Executable{
			Package: &build.Package{
				Name: s.Name,
				Path: exec,
			},
			Env:  c.Env,
			Args: args,
		},
		closed:     make(chan bool),
		output:     c.Output,
		updated:    time.Now(),
		maxRetries: c.Retries,
	}
}

func (s *service) streamOutput() {
	go io.Copy(s.output, s.PID.Output)
	go io.Copy(s.output, s.PID.Error)
}

func (s *service) shouldStart() bool {
	if s.running {
		return false
	}
	return s.maxRetries < s.retries
}

func (s *service) ShouldStart() bool {
	s.RLock()
	defer s.RUnlock()
	return s.shouldStart()
}

func (s *service) Running() bool {
	s.RLock()
	defer s.RUnlock()
	return s.running
}

// Start stars the service
func (s *service) Start() error {
	s.Lock()
	defer s.Unlock()

	if !s.shouldStart() {
		return nil
	}

	// reset
	s.err = nil
	s.closed = make(chan bool)

	if s.Metadata == nil {
		s.Metadata = make(map[string]string)
	}

	s.Metadata["status"] = "starting"
	// delete any existing error
	delete(s.Metadata, "error")

	// TODO: pull source & build binary
	log.Debugf("Runtime service %s forking new process", s.Service.Name)
	p, err := s.Process.Fork(s.Exec)
	if err != nil {
		s.Metadata["status"] = "error"
		s.Metadata["error"] = err.Error()
		return err
	}

	// set the pid
	s.PID = p
	// set to running
	s.running = true
	// set status
	s.Metadata["status"] = "running"

	if s.output != nil {
		s.streamOutput()
	}

	// wait and watch
	go s.Wait()

	return nil
}

// Stop stops the service
func (s *service) Stop() error {
	s.Lock()
	defer s.Unlock()

	select {
	case <-s.closed:
		return nil
	default:
		close(s.closed)
		s.running = false
		if s.PID == nil {
			return nil
		}

		// set status
		s.Metadata["status"] = "stopping"

		// kill the process
		err := s.Process.Kill(s.PID)
		// wait for it to exit
		s.Process.Wait(s.PID)

		// set status
		s.Metadata["status"] = "stopped"

		// return the kill error
		return err
	}
}

// Error returns the last error service has returned
func (s *service) Error() error {
	s.RLock()
	defer s.RUnlock()
	return s.err
}

// Wait waits for the service to finish running
func (s *service) Wait() {
	// wait for process to exit
	err := s.Process.Wait(s.PID)

	s.Lock()
	defer s.Unlock()

	// save the error
	if err != nil {
		s.retries++
		s.Metadata["status"] = "error"
		s.Metadata["error"] = err.Error()
		s.Metadata["retries"] = strconv.Itoa(s.retries)

		s.err = err
	} else {
		s.Metadata["status"] = "done"
	}

	// no longer running
	s.running = false
}
<|endoftext|>


<commit_before>// Package runtime is the micro runtime
package runtime

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/micro/cli/v2"
	"github.com/micro/go-micro/v2"
	"github.com/micro/go-micro/v2/config/cmd"
	"github.com/micro/go-micro/v2/runtime"
	srvRuntime "github.com/micro/go-micro/v2/runtime/service"
)

const (
	// RunUsage message for the run command
	RunUsage = "Required usage: micro run [service] [version] [--source github.com/micro/services]"
	// KillUsage message for the kill command
	KillUsage = "Require usage: micro kill [service] [version]"
	// UpdateUsage message for the update command
	UpdateUsage = "Require usage: micro update [service] [version]"
	// GetUsage message for micro get command
	GetUsage = "Require usage: micro ps [service] [version]"
	// ServicesUsage message for micro services command
	ServicesUsage = "Require usage: micro services"
	// CannotWatch message for the run command
	CannotWatch = "Cannot watch filesystem on this runtime"
)

var (
	// DefaultRetries which should be attempted when starting a service
	DefaultRetries = 3
	// Image to specify if none is specified
	Image = "docker.pkg.github.com/micro/services"
)

func defaultEnv() []string {
	var env []string
	for _, evar := range os.Environ() {
		if strings.HasPrefix(evar, "MICRO_") {
			env = append(env, evar)
		}
	}

	return env
}

func runtimeFromContext(ctx *cli.Context) runtime.Runtime {
	if ctx.Bool("platform") {
		os.Setenv("MICRO_PROXY", "service")
		os.Setenv("MICRO_PROXY_ADDRESS", "proxy.micro.mu:443")
		return srvRuntime.NewRuntime()
	}

	return *cmd.DefaultCmd.Options().Runtime
}

func runService(ctx *cli.Context, srvOpts ...micro.Option) {
	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	// we need some args to run
	if ctx.Args().Len() == 0 {
		fmt.Println(RunUsage)
		return
	}

	// set and validate the name (arg 1)
	name := ctx.Args().Get(0)
	version := "latest"
	source := ctx.String("source")
	typ := ctx.String("type")
	image := ctx.String("image")
	command := strings.TrimSpace(ctx.String("command"))
	args := strings.TrimSpace(ctx.String("args"))

	// load the runtime
	r := runtimeFromContext(ctx)

	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(RunUsage)
		return
	}

	// set the version (arg 2, optional)
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	// add environment variable passed in via cli
	environment := defaultEnv()
	for _, evar := range ctx.StringSlice("env") {
		for _, e := range strings.Split(evar, ",") {
			if len(e) > 0 {
				environment = append(environment, strings.TrimSpace(e))
			}
		}
	}

	var retries = DefaultRetries
	if ctx.IsSet("retries") {
		retries = ctx.Int("retries")
	}

	// set the image from our images if its the platform
	if ctx.Bool("platform") && len(image) == 0 {
		formattedName := strings.ReplaceAll(name, "/", "-")
		image = fmt.Sprintf("%v/%v", Image, formattedName)
	}

	// specify the options
	opts := []runtime.CreateOption{
		runtime.WithOutput(os.Stdout),
		runtime.WithEnv(environment),
		runtime.WithRetries(retries),
		runtime.CreateImage(image),
		runtime.CreateType(typ),
	}

	if len(command) > 0 {
		opts = append(opts, runtime.WithCommand(strings.Split(command, " ")...))
	}

	if len(args) > 0 {
		opts = append(opts, runtime.WithArgs(strings.Split(args, " ")...))
	}

	// run the service
	service := &runtime.Service{
		Name:     name,
		Source:   source,
		Version:  version,
		Metadata: make(map[string]string),
	}

	if err := r.Create(service, opts...); err != nil {
		fmt.Println(err)
		return
	}
}

func killService(ctx *cli.Context, srvOpts ...micro.Option) {
	// we need some args to run
	if ctx.Args().Len() == 0 {
		fmt.Println(RunUsage)
		return
	}

	// set and validate the name (arg 1)
	name := ctx.Args().Get(0)
	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(RunUsage)
		return
	}

	// set the version (arg 2, optional)
	version := "latest"
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	service := &runtime.Service{
		Name:    name,
		Version: version,
	}

	if err := runtimeFromContext(ctx).Delete(service); err != nil {
		fmt.Println(err)
		return
	}
}

func updateService(ctx *cli.Context, srvOpts ...micro.Option) {
	// we need some args to run
	if ctx.Args().Len() == 0 {
		fmt.Println(RunUsage)
		return
	}

	// set and validate the name (arg 1)
	name := ctx.Args().Get(0)
	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(RunUsage)
		return
	}

	// set the version (arg 2, optional)
	version := "latest"
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	service := &runtime.Service{
		Name:    name,
		Version: version,
	}

	if err := runtimeFromContext(ctx).Update(service); err != nil {
		fmt.Println(err)
		return
	}
}

func getService(ctx *cli.Context, srvOpts ...micro.Option) {
	name := ctx.Args().Get(0)
	version := "latest"
	runType := ctx.Bool("runtime")
	typ := ctx.String("type")
	r := runtimeFromContext(ctx)

	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(GetUsage)
		return
	}

	// set version as second arg
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	// should we list sevices
	var list bool

	// zero args so list all
	if ctx.Args().Len() == 0 {
		list = true
	}

	var err error
	var services []*runtime.Service

	// return a list of services
	switch list {
	case true:
		// return the runtiem services
		if runType {
			services, err = r.Read(runtime.ReadType("runtime"))
		} else {
			// list all running services
			services, err = r.List()
		}
	// return one service
	default:
		// check if service name was passed in
		if len(name) == 0 {
			fmt.Println(GetUsage)
			return
		}

		// get service with name and version
		opts := []runtime.ReadOption{
			runtime.ReadService(name),
			runtime.ReadVersion(version),
		}

		// return the runtime services
		if runType {
			opts = append(opts, runtime.ReadType("runtime"))
		} else {
			opts = append(opts, runtime.ReadType(typ))
		}

		// read the service
		services, err = r.Read(opts...)
	}

	// check the error
	if err != nil {
		fmt.Println(err)
		return
	}

	// make sure we return UNKNOWN when empty string is supplied
	parse := func(m string) string {
		if len(m) == 0 {
			return "n/a"
		}
		return m
	}

	// don't do anything if there's no services
	if len(services) == 0 {
		return
	}

	sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name })

	writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight)
	fmt.Fprintln(writer, "NAME\tVERSION\tSOURCE\tSTATUS\tBUILD\tMETADATA")
	for _, service := range services {
		status := parse(service.Metadata["status"])
		if status == "error" {
			status = service.Metadata["error"]
		}

		fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%s\t%s\n",
			service.Name,
			parse(service.Version),
			parse(service.Source),
			status,
			parse(service.Metadata["build"]),
			fmt.Sprintf("owner=%s,group=%s", parse(service.Metadata["owner"]), parse(service.Metadata["group"])))
	}
	writer.Flush()
}
<commit_msg>do not pass through env (#634)<commit_after>// Package runtime is the micro runtime
package runtime

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/micro/cli/v2"
	"github.com/micro/go-micro/v2"
	"github.com/micro/go-micro/v2/config/cmd"
	"github.com/micro/go-micro/v2/runtime"
	srvRuntime "github.com/micro/go-micro/v2/runtime/service"
)

const (
	// RunUsage message for the run command
	RunUsage = "Required usage: micro run [service] [version] [--source github.com/micro/services]"
	// KillUsage message for the kill command
	KillUsage = "Require usage: micro kill [service] [version]"
	// UpdateUsage message for the update command
	UpdateUsage = "Require usage: micro update [service] [version]"
	// GetUsage message for micro get command
	GetUsage = "Require usage: micro ps [service] [version]"
	// ServicesUsage message for micro services command
	ServicesUsage = "Require usage: micro services"
	// CannotWatch message for the run command
	CannotWatch = "Cannot watch filesystem on this runtime"
)

var (
	// DefaultRetries which should be attempted when starting a service
	DefaultRetries = 3
	// Image to specify if none is specified
	Image = "docker.pkg.github.com/micro/services"
)

func runtimeFromContext(ctx *cli.Context) runtime.Runtime {
	if ctx.Bool("platform") {
		os.Setenv("MICRO_PROXY", "service")
		os.Setenv("MICRO_PROXY_ADDRESS", "proxy.micro.mu:443")
		return srvRuntime.NewRuntime()
	}

	return *cmd.DefaultCmd.Options().Runtime
}

func runService(ctx *cli.Context, srvOpts ...micro.Option) {
	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	// we need some args to run
	if ctx.Args().Len() == 0 {
		fmt.Println(RunUsage)
		return
	}

	// set and validate the name (arg 1)
	name := ctx.Args().Get(0)
	version := "latest"
	source := ctx.String("source")
	typ := ctx.String("type")
	image := ctx.String("image")
	command := strings.TrimSpace(ctx.String("command"))
	args := strings.TrimSpace(ctx.String("args"))

	// load the runtime
	r := runtimeFromContext(ctx)

	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(RunUsage)
		return
	}

	// set the version (arg 2, optional)
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	// add environment variable passed in via cli
	var environment []string
	for _, evar := range ctx.StringSlice("env") {
		for _, e := range strings.Split(evar, ",") {
			if len(e) > 0 {
				environment = append(environment, strings.TrimSpace(e))
			}
		}
	}

	var retries = DefaultRetries
	if ctx.IsSet("retries") {
		retries = ctx.Int("retries")
	}

	// set the image from our images if its the platform
	if ctx.Bool("platform") && len(image) == 0 {
		formattedName := strings.ReplaceAll(name, "/", "-")
		image = fmt.Sprintf("%v/%v", Image, formattedName)
	}

	// specify the options
	opts := []runtime.CreateOption{
		runtime.WithOutput(os.Stdout),
		runtime.WithRetries(retries),
		runtime.CreateImage(image),
		runtime.CreateType(typ),
	}

	if len(environment) > 0 {
		opts = append(opts, runtime.WithEnv(environment))
	}

	if len(command) > 0 {
		opts = append(opts, runtime.WithCommand(strings.Split(command, " ")...))
	}

	if len(args) > 0 {
		opts = append(opts, runtime.WithArgs(strings.Split(args, " ")...))
	}

	// run the service
	service := &runtime.Service{
		Name:     name,
		Source:   source,
		Version:  version,
		Metadata: make(map[string]string),
	}

	if err := r.Create(service, opts...); err != nil {
		fmt.Println(err)
		return
	}
}

func killService(ctx *cli.Context, srvOpts ...micro.Option) {
	// we need some args to run
	if ctx.Args().Len() == 0 {
		fmt.Println(RunUsage)
		return
	}

	// set and validate the name (arg 1)
	name := ctx.Args().Get(0)
	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(RunUsage)
		return
	}

	// set the version (arg 2, optional)
	version := "latest"
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	service := &runtime.Service{
		Name:    name,
		Version: version,
	}

	if err := runtimeFromContext(ctx).Delete(service); err != nil {
		fmt.Println(err)
		return
	}
}

func updateService(ctx *cli.Context, srvOpts ...micro.Option) {
	// we need some args to run
	if ctx.Args().Len() == 0 {
		fmt.Println(RunUsage)
		return
	}

	// set and validate the name (arg 1)
	name := ctx.Args().Get(0)
	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(RunUsage)
		return
	}

	// set the version (arg 2, optional)
	version := "latest"
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	service := &runtime.Service{
		Name:    name,
		Version: version,
	}

	if err := runtimeFromContext(ctx).Update(service); err != nil {
		fmt.Println(err)
		return
	}
}

func getService(ctx *cli.Context, srvOpts ...micro.Option) {
	name := ctx.Args().Get(0)
	version := "latest"
	runType := ctx.Bool("runtime")
	typ := ctx.String("type")
	r := runtimeFromContext(ctx)

	if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") {
		fmt.Println(GetUsage)
		return
	}

	// set version as second arg
	if ctx.Args().Len() > 1 {
		version = ctx.Args().Get(1)
	}

	// should we list sevices
	var list bool

	// zero args so list all
	if ctx.Args().Len() == 0 {
		list = true
	}

	var err error
	var services []*runtime.Service

	// return a list of services
	switch list {
	case true:
		// return the runtiem services
		if runType {
			services, err = r.Read(runtime.ReadType("runtime"))
		} else {
			// list all running services
			services, err = r.List()
		}
	// return one service
	default:
		// check if service name was passed in
		if len(name) == 0 {
			fmt.Println(GetUsage)
			return
		}

		// get service with name and version
		opts := []runtime.ReadOption{
			runtime.ReadService(name),
			runtime.ReadVersion(version),
		}

		// return the runtime services
		if runType {
			opts = append(opts, runtime.ReadType("runtime"))
		} else {
			opts = append(opts, runtime.ReadType(typ))
		}

		// read the service
		services, err = r.Read(opts...)
	}

	// check the error
	if err != nil {
		fmt.Println(err)
		return
	}

	// make sure we return UNKNOWN when empty string is supplied
	parse := func(m string) string {
		if len(m) == 0 {
			return "n/a"
		}
		return m
	}

	// don't do anything if there's no services
	if len(services) == 0 {
		return
	}

	sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name })

	writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight)
	fmt.Fprintln(writer, "NAME\tVERSION\tSOURCE\tSTATUS\tBUILD\tMETADATA")
	for _, service := range services {
		status := parse(service.Metadata["status"])
		if status == "error" {
			status = service.Metadata["error"]
		}

		fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%s\t%s\n",
			service.Name,
			parse(service.Version),
			parse(service.Source),
			status,
			parse(service.Metadata["build"]),
			fmt.Sprintf("owner=%s,group=%s", parse(service.Metadata["owner"]), parse(service.Metadata["group"])))
	}
	writer.Flush()
}
<|endoftext|>


<commit_before>package runtime

// Version is the current version of the buffalo binary
const Version = "development"
<commit_msg>version bump: v0.14.9<commit_after>package runtime

// Version is the current version of the buffalo binary
const Version = "v0.14.9"
<|endoftext|>


<commit_before>package httpbackend

import (
	"net/http"

	"github.com/khades/servbot/models"
	"github.com/khades/servbot/repos"
)

type sessionHandlerFunc func(w http.ResponseWriter, r *http.Request, s *models.HTTPSession)

func withSession(next sessionHandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		session, err := repos.GetSession(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		val := session.Values["sessions"]
		var sessionObject = &models.HTTPSession{}
		sessionObject, ok := val.(*models.HTTPSession)
		if ok == false {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		next(w, r, sessionObject)
	}
}
<commit_msg>Fixing "with session"<commit_after>package httpbackend

import (
	"log"
	"net/http"

	"github.com/khades/servbot/models"
	"github.com/khades/servbot/repos"
)

type sessionHandlerFunc func(w http.ResponseWriter, r *http.Request, s *models.HTTPSession)

func withSession(next sessionHandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		session, err := repos.GetSession(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		val := session.Values["sessions"]
		var sessionObject = &models.HTTPSession{}

		if val == nil {
			session.Values["sessions"] = models.HTTPSession{}
			session.Save(r, w)
		} else {
			var ok = false
			sessionObject, ok = val.(*models.HTTPSession)
			if ok == false {
				log.Println(val)
				log.Println(ok)
				http.Error(w, "what", http.StatusInternalServerError)
				return
			}
		}
		next(w, r, sessionObject)
	}
}
<|endoftext|>


<commit_before><commit_msg>Create upload-files.go<commit_after><|endoftext|>


<commit_before>package olbermann

import (
	"testing"
	"time"
)

type SampleMetric struct {
	IntVal   int     `type:"counter" report:"iter,total"`
	FloatVal float64 `type:"counter" report:"cum"`
}

func TestSample(t *testing.T) {
	mst, err := newMetricSetTypeOf(SampleMetric{})
	if err != nil {
		t.Error(err)
	}
	var floatTotal float64
	for i := 0; i < 100; i++ {
		mst.update(&SampleMetric{5, float64(i) * 0.1})
		floatTotal += float64(i) * 0.1
		if i%5 == 4 {
			msv := mst.getValues(time.Millisecond, time.Duration(i)*time.Millisecond)
			if msv.metrics[0].name != "IntVal" || msv.metrics[1].name != "FloatVal" {
				t.Error("invalid metric names")
			}
			if msv.metrics[0].reports[0].name != "iter" || msv.metrics[0].reports[1].name != "total" || msv.metrics[1].reports[0].name != "cum" {
				t.Error("invalid report names")
			}
			if msv.metrics[0].reports[0].value != float64(25000) {
				t.Error("expected 25000/s for IntVal iter, got", msv.metrics[0].reports[0].value)
			}
			if msv.metrics[0].reports[1].value != float64((i+1)*5) {
				t.Error("expected", (i+1)*5, " for IntVal total, got", msv.metrics[0].reports[1].value)
			}
			if msv.metrics[1].reports[0].value != floatTotal/(time.Duration(i)*time.Millisecond).Seconds() {
				t.Error("expected", floatTotal/(time.Duration(i)*time.Millisecond).Seconds(), "for FloatVal cum, got", msv.metrics[1].reports[0].value)
			}
		}
	}
}

func BenchmarkUpdateMetricsPtr(b *testing.B) {
	mst, err := newMetricSetTypeOf(SampleMetric{})
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		mst.update(&SampleMetric{5, float64(i) * 0.1})
	}
}

func BenchmarkUpdateMetricsStruct(b *testing.B) {
	mst, err := newMetricSetTypeOf(SampleMetric{})
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		mst.update(SampleMetric{5, float64(i) * 0.1})
	}
}

func BenchmarkIncrements(b *testing.B) {
	var metric SampleMetric
	for i := 0; i < b.N; i++ {
		metric.IntVal += 5
		metric.FloatVal += float64(i) * 0.1
	}
}
<commit_msg>added benchmarks<commit_after>package olbermann

import (
	"testing"
	"time"
)

type SampleMetric struct {
	IntVal   int     `type:"counter" report:"iter,total"`
	FloatVal float64 `type:"counter" report:"cum"`
}

func TestSample(t *testing.T) {
	mst, err := newMetricSetTypeOf(SampleMetric{})
	if err != nil {
		t.Error(err)
	}
	var floatTotal float64
	for i := 0; i < 100; i++ {
		mst.update(&SampleMetric{5, float64(i) * 0.1})
		floatTotal += float64(i) * 0.1
		if i%5 == 4 {
			msv := mst.getValues(time.Millisecond, time.Duration(i)*time.Millisecond)
			if msv.metrics[0].name != "IntVal" || msv.metrics[1].name != "FloatVal" {
				t.Error("invalid metric names")
			}
			if msv.metrics[0].reports[0].name != "iter" || msv.metrics[0].reports[1].name != "total" || msv.metrics[1].reports[0].name != "cum" {
				t.Error("invalid report names")
			}
			if msv.metrics[0].reports[0].value != float64(25000) {
				t.Error("expected 25000/s for IntVal iter, got", msv.metrics[0].reports[0].value)
			}
			if msv.metrics[0].reports[1].value != float64((i+1)*5) {
				t.Error("expected", (i+1)*5, " for IntVal total, got", msv.metrics[0].reports[1].value)
			}
			if msv.metrics[1].reports[0].value != floatTotal/(time.Duration(i)*time.Millisecond).Seconds() {
				t.Error("expected", floatTotal/(time.Duration(i)*time.Millisecond).Seconds(), "for FloatVal cum, got", msv.metrics[1].reports[0].value)
			}
		}
	}
}

func BenchmarkUpdateMetricsPtr(b *testing.B) {
	mst, err := newMetricSetTypeOf(SampleMetric{})
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		mst.update(&SampleMetric{5, float64(i) * 0.1})
	}
}

func BenchmarkUpdateMetricsStruct(b *testing.B) {
	mst, err := newMetricSetTypeOf(SampleMetric{})
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		mst.update(SampleMetric{5, float64(i) * 0.1})
	}
}

// You would think it would be possible to make a generic
// benchmarkUpdateMetricsAgg function that accepts a parameter, but the
// cost of doing i%n == (n-1) is actually pretty significant.  It is much
// better (a factor of 4 or 5 in some cases) to have constants.
func BenchmarkUpdateMetricsAgg10(b *testing.B) {
	var m SampleMetric
	mst, err := newMetricSetTypeOf(m)
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		m.IntVal += 5
		m.FloatVal += float64(i) * 0.1
		if i%10 == 9 {
			mst.update(m)
			m = SampleMetric{}
		}
	}
	mst.update(m)
}

func BenchmarkUpdateMetricsAgg50(b *testing.B) {
	var m SampleMetric
	mst, err := newMetricSetTypeOf(m)
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		m.IntVal += 5
		m.FloatVal += float64(i) * 0.1
		if i%50 == 49 {
			mst.update(m)
			m = SampleMetric{}
		}
	}
	mst.update(m)
}

func BenchmarkUpdateMetricsAgg100(b *testing.B) {
	var m SampleMetric
	mst, err := newMetricSetTypeOf(m)
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		m.IntVal += 5
		m.FloatVal += float64(i) * 0.1
		if i%100 == 99 {
			mst.update(m)
			m = SampleMetric{}
		}
	}
	mst.update(m)
}

func BenchmarkUpdateMetricsAgg1000(b *testing.B) {
	var m SampleMetric
	mst, err := newMetricSetTypeOf(m)
	if err != nil {
		b.Error(err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		m.IntVal += 5
		m.FloatVal += float64(i) * 0.1
		if i%1000 == 999 {
			mst.update(m)
			m = SampleMetric{}
		}
	}
	mst.update(m)
}

func BenchmarkPlainIncrements(b *testing.B) {
	var metric SampleMetric
	for i := 0; i < b.N; i++ {
		metric.IntVal += 5
		metric.FloatVal += float64(i) * 0.1
	}
}
<|endoftext|>


<commit_before>package films

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

type Film struct {
	Adult             bool `json:"adult"`
	AlternativeTitles struct {
		Titles []struct {
			Iso31661 string `json:"iso_3166_1"`
			Title    string `json:"title"`
		} `json:"titles"`
	} `json:"alternative_titles"`
	Availability        *FilmAvailability `json:"availability,omitempty"`
	BackdropPath        string            `json:"backdrop_path"`
	BelongsToCollection struct {
		BackdropPath string `json:"backdrop_path"`
		ID           int    `json:"id"`
		Name         string `json:"name"`
		PosterPath   string `json:"poster_path"`
	} `json:"belongs_to_collection"`
	Budget  int `json:"budget"`
	Credits struct {
		Cast []struct {
			CastID      int    `json:"cast_id"`
			Character   string `json:"character"`
			CreditID    string `json:"credit_id"`
			ID          int    `json:"id"`
			Name        string `json:"name"`
			Order       int    `json:"order"`
			ProfilePath string `json:"profile_path"`
		} `json:"cast"`
		Crew []struct {
			CreditID    string `json:"credit_id"`
			Department  string `json:"department"`
			ID          int    `json:"id"`
			Job         string `json:"job"`
			Name        string `json:"name"`
			ProfilePath string `json:"profile_path"`
		} `json:"crew"`
	} `json:"credits"`
	Genres []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"genres"`
	Homepage string `json:"homepage"`
	ID       int    `json:"id"`
	Images   struct {
		Backdrops []struct {
			AspectRatio float64     `json:"aspect_ratio"`
			FilePath    string      `json:"file_path"`
			Height      int         `json:"height"`
			Iso6391     interface{} `json:"iso_639_1"`
			VoteAverage float64     `json:"vote_average"`
			VoteCount   int         `json:"vote_count"`
			Width       int         `json:"width"`
		} `json:"backdrops"`
		Posters []struct {
			AspectRatio float64 `json:"aspect_ratio"`
			FilePath    string  `json:"file_path"`
			Height      int     `json:"height"`
			ID          string  `json:"id"`
			Iso6391     string  `json:"iso_639_1"`
			VoteAverage float64 `json:"vote_average"`
			VoteCount   int     `json:"vote_count"`
			Width       int     `json:"width"`
		} `json:"posters"`
	} `json:"images"`
	ImdbID   string `json:"imdb_id"`
	Keywords struct {
		Keywords []struct {
			ID   int    `json:"id"`
			Name string `json:"name"`
		} `json:"keywords"`
	} `json:"keywords"`
	OriginalLanguage    string  `json:"original_language"`
	OriginalTitle       string  `json:"original_title"`
	Overview            string  `json:"overview"`
	Popularity          float64 `json:"popularity"`
	PosterPath          string  `json:"poster_path"`
	ProductionCompanies []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"production_companies"`
	ProductionCountries []struct {
		Iso31661 string `json:"iso_3166_1"`
		Name     string `json:"name"`
	} `json:"production_countries"`
	ReleaseDate string `json:"release_date"`
	Releases    struct {
		Countries []struct {
			Certification string `json:"certification"`
			Iso31661      string `json:"iso_3166_1"`
			Primary       bool   `json:"primary"`
			ReleaseDate   string `json:"release_date"`
		} `json:"countries"`
	} `json:"releases"`
	Revenue int `json:"revenue"`
	Runtime int `json:"runtime"`
	Similar struct {
		Page    int `json:"page"`
		Results []struct {
			Adult         bool    `json:"adult"`
			BackdropPath  string  `json:"backdrop_path"`
			ID            int     `json:"id"`
			OriginalTitle string  `json:"original_title"`
			Popularity    float64 `json:"popularity"`
			PosterPath    string  `json:"poster_path"`
			ReleaseDate   string  `json:"release_date"`
			Title         string  `json:"title"`
			Video         bool    `json:"video"`
			VoteAverage   float64 `json:"vote_average"`
			VoteCount     int     `json:"vote_count"`
		} `json:"results"`
		TotalPages   int `json:"total_pages"`
		TotalResults int `json:"total_results"`
	} `json:"similar"`
	SpokenLanguages []struct {
		Iso6391 string `json:"iso_639_1"`
		Name    string `json:"name"`
	} `json:"spoken_languages"`
	Status  string `json:"status"`
	Tagline string `json:"tagline"`
	Title   string `json:"title"`
	Video   bool   `json:"video"`
	Videos  struct {
		Results []struct {
			ID      string `json:"id"`
			Iso6391 string `json:"iso_639_1"`
			Key     string `json:"key"`
			Name    string `json:"name"`
			Site    string `json:"site"`
			Size    int    `json:"size"`
			Type    string `json:"type"`
		} `json:"results"`
	} `json:"videos"`
	VoteAverage float64 `json:"vote_average"`
	VoteCount   int     `json:"vote_count"`
}

type FilmAvailability struct {
	Purchase *struct {
		AmazonVideo *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"amazon_video_purchase,omitempty"`
		GooglePlay *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"android_purchase,omitempty"`
		AppleiTunes *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"apple_itunes_purchase,omitempty"`
		SonyEntertainment *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"sony_purchase,omitempty"`
		Vudu *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"vudu_purchase,omitempty"`
		Youtube *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"youtube_purchase,omitempty"`
		XBOXMarketplace *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"xbox_purchase,omitempty"`
	} `json:"purchase,omitempty"`
	Rental *struct {
		AmazonVideo *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"amazon_video_rental,omitempty"`
		GooglePlay *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"android_rental,omitempty"`
		AppleiTunes *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"apple_itunes_rental,omitempty"`
		SonyEntertainment *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"sony_rental,omitempty"`
		Vudu *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"vudu_rental,omitempty"`
		Youtube *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"youtube_rental,omitempty"`
	} `json:"rental,omitempty"`
}

var (
	api_key string
)

func init() {
	api_key = os.Getenv("TMDB_API_KEY")

	if api_key == "" {
		log.Fatal("Missing API key")
	}
}

func Get(film_id string) (Film, error) {
	film, err := queryTMDb(film_id)

	if err != nil {
		return film, err
	}

	availability, err := determineAvailability(film)

	if err != nil {
		return film, err
	}

	film.Availability = &availability

	return film, nil
}

func queryTMDb(film_id string) (Film, error) {
	var url string
	var film Film

	var buffer bytes.Buffer

	buffer.WriteString("http://api.themoviedb.org/3/movie/")
	buffer.WriteString(film_id)
	buffer.WriteString("?api_key=")
	buffer.WriteString(api_key)
	buffer.WriteString("&append_to_response=")
	buffer.WriteString("alternative_titles,credits,images,keywords,releases,videos,similar")

	url = string(buffer.Bytes())

	resp, err := http.Get(url)

	if err != nil {
		return film, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return film, err
	}

	err = json.Unmarshal(body, &film)

	if err != nil {
		return film, err
	}

	return film, nil
}

func determineAvailability(film Film) (FilmAvailability, error) {
	type searchResult struct {
		Id    string `json:"_id"`
		Links struct {
			IMDb string `json:"imdb"`
		} `json:"links"`
	}

	var availability FilmAvailability
	var results []searchResult

	var cisi_url *url.URL

	cisi_url, err := url.Parse("http://www.canistream.it/services/search")

	if err != nil {
		return availability, err
	}

	parameters := url.Values{}
	parameters.Add("movieName", film.Title)

	cisi_url.RawQuery = parameters.Encode()

	resp, err := http.Get(cisi_url.String())

	if err != nil {
		return availability, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return availability, err
	}

	err = json.Unmarshal(body, &results)

	if err != nil {
		return availability, err
	}

	var canIStreamItID string

	for _, result := range results {
		var imdb_id string

		if result.Links.IMDb != "" {
			imdb_id = strings.Split(result.Links.IMDb, "/")[4]
		}

		if imdb_id == film.ImdbID {
			canIStreamItID = result.Id
		}
	}

	if canIStreamItID == "" {
		// not available
	}

	mediaTypes := []string{"rental", "purchase"}

	for _, mediaType := range mediaTypes {
		var buffer bytes.Buffer

		buffer.WriteString("http://www.canistream.it/services/query?movieId=")
		buffer.WriteString(canIStreamItID)
		buffer.WriteString("&attributes=1&mediaType=")
		buffer.WriteString(mediaType)

		resp, err = http.Get(string(buffer.Bytes()))

		if err != nil {
			return availability, err
		}

		defer resp.Body.Close()

		body, err = ioutil.ReadAll(resp.Body)

		if err != nil {
			return availability, err
		}

		switch mediaType {
		case "rental":
			err = json.Unmarshal(body, &availability.Rental)

			if err != nil {
				return availability, err
			}
		case "purchase":
			err = json.Unmarshal(body, &availability.Purchase)

			if err != nil {
				return availability, err
			}
		}
	}

	return availability, nil
}
<commit_msg>Don't query media types if the film isn't available<commit_after>package films

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

type Film struct {
	Adult             bool `json:"adult"`
	AlternativeTitles struct {
		Titles []struct {
			Iso31661 string `json:"iso_3166_1"`
			Title    string `json:"title"`
		} `json:"titles"`
	} `json:"alternative_titles"`
	Availability        *FilmAvailability `json:"availability,omitempty"`
	BackdropPath        string            `json:"backdrop_path"`
	BelongsToCollection struct {
		BackdropPath string `json:"backdrop_path"`
		ID           int    `json:"id"`
		Name         string `json:"name"`
		PosterPath   string `json:"poster_path"`
	} `json:"belongs_to_collection"`
	Budget  int `json:"budget"`
	Credits struct {
		Cast []struct {
			CastID      int    `json:"cast_id"`
			Character   string `json:"character"`
			CreditID    string `json:"credit_id"`
			ID          int    `json:"id"`
			Name        string `json:"name"`
			Order       int    `json:"order"`
			ProfilePath string `json:"profile_path"`
		} `json:"cast"`
		Crew []struct {
			CreditID    string `json:"credit_id"`
			Department  string `json:"department"`
			ID          int    `json:"id"`
			Job         string `json:"job"`
			Name        string `json:"name"`
			ProfilePath string `json:"profile_path"`
		} `json:"crew"`
	} `json:"credits"`
	Genres []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"genres"`
	Homepage string `json:"homepage"`
	ID       int    `json:"id"`
	Images   struct {
		Backdrops []struct {
			AspectRatio float64     `json:"aspect_ratio"`
			FilePath    string      `json:"file_path"`
			Height      int         `json:"height"`
			Iso6391     interface{} `json:"iso_639_1"`
			VoteAverage float64     `json:"vote_average"`
			VoteCount   int         `json:"vote_count"`
			Width       int         `json:"width"`
		} `json:"backdrops"`
		Posters []struct {
			AspectRatio float64 `json:"aspect_ratio"`
			FilePath    string  `json:"file_path"`
			Height      int     `json:"height"`
			ID          string  `json:"id"`
			Iso6391     string  `json:"iso_639_1"`
			VoteAverage float64 `json:"vote_average"`
			VoteCount   int     `json:"vote_count"`
			Width       int     `json:"width"`
		} `json:"posters"`
	} `json:"images"`
	ImdbID   string `json:"imdb_id"`
	Keywords struct {
		Keywords []struct {
			ID   int    `json:"id"`
			Name string `json:"name"`
		} `json:"keywords"`
	} `json:"keywords"`
	OriginalLanguage    string  `json:"original_language"`
	OriginalTitle       string  `json:"original_title"`
	Overview            string  `json:"overview"`
	Popularity          float64 `json:"popularity"`
	PosterPath          string  `json:"poster_path"`
	ProductionCompanies []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"production_companies"`
	ProductionCountries []struct {
		Iso31661 string `json:"iso_3166_1"`
		Name     string `json:"name"`
	} `json:"production_countries"`
	ReleaseDate string `json:"release_date"`
	Releases    struct {
		Countries []struct {
			Certification string `json:"certification"`
			Iso31661      string `json:"iso_3166_1"`
			Primary       bool   `json:"primary"`
			ReleaseDate   string `json:"release_date"`
		} `json:"countries"`
	} `json:"releases"`
	Revenue int `json:"revenue"`
	Runtime int `json:"runtime"`
	Similar struct {
		Page    int `json:"page"`
		Results []struct {
			Adult         bool    `json:"adult"`
			BackdropPath  string  `json:"backdrop_path"`
			ID            int     `json:"id"`
			OriginalTitle string  `json:"original_title"`
			Popularity    float64 `json:"popularity"`
			PosterPath    string  `json:"poster_path"`
			ReleaseDate   string  `json:"release_date"`
			Title         string  `json:"title"`
			Video         bool    `json:"video"`
			VoteAverage   float64 `json:"vote_average"`
			VoteCount     int     `json:"vote_count"`
		} `json:"results"`
		TotalPages   int `json:"total_pages"`
		TotalResults int `json:"total_results"`
	} `json:"similar"`
	SpokenLanguages []struct {
		Iso6391 string `json:"iso_639_1"`
		Name    string `json:"name"`
	} `json:"spoken_languages"`
	Status  string `json:"status"`
	Tagline string `json:"tagline"`
	Title   string `json:"title"`
	Video   bool   `json:"video"`
	Videos  struct {
		Results []struct {
			ID      string `json:"id"`
			Iso6391 string `json:"iso_639_1"`
			Key     string `json:"key"`
			Name    string `json:"name"`
			Site    string `json:"site"`
			Size    int    `json:"size"`
			Type    string `json:"type"`
		} `json:"results"`
	} `json:"videos"`
	VoteAverage float64 `json:"vote_average"`
	VoteCount   int     `json:"vote_count"`
}

type FilmAvailability struct {
	Purchase *struct {
		AmazonVideo *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"amazon_video_purchase,omitempty"`
		GooglePlay *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"android_purchase,omitempty"`
		AppleiTunes *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"apple_itunes_purchase,omitempty"`
		SonyEntertainment *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"sony_purchase,omitempty"`
		Vudu *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"vudu_purchase,omitempty"`
		Youtube *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"youtube_purchase,omitempty"`
		XBOXMarketplace *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"xbox_purchase,omitempty"`
	} `json:"purchase,omitempty"`
	Rental *struct {
		AmazonVideo *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"amazon_video_rental,omitempty"`
		GooglePlay *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"android_rental,omitempty"`
		AppleiTunes *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"apple_itunes_rental,omitempty"`
		SonyEntertainment *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"sony_rental,omitempty"`
		Vudu *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"vudu_rental,omitempty"`
		Youtube *struct {
			URL     string `json:"direct_url,omitempty"`
			ID      string `json:"external_id,omitempty"`
			Price   string `json:"price,omitempty"`
			Checked int64  `json:"date_checked,omitempty"`
		} `json:"youtube_rental,omitempty"`
	} `json:"rental,omitempty"`
}

var (
	api_key string
)

func init() {
	api_key = os.Getenv("TMDB_API_KEY")

	if api_key == "" {
		log.Fatal("Missing API key")
	}
}

func Get(film_id string) (Film, error) {
	film, err := queryTMDb(film_id)

	if err != nil {
		return film, err
	}

	availability, err := determineAvailability(film)

	if err != nil {
		return film, err
	}

	film.Availability = &availability

	return film, nil
}

func queryTMDb(film_id string) (Film, error) {
	var url string
	var film Film

	var buffer bytes.Buffer

	buffer.WriteString("http://api.themoviedb.org/3/movie/")
	buffer.WriteString(film_id)
	buffer.WriteString("?api_key=")
	buffer.WriteString(api_key)
	buffer.WriteString("&append_to_response=")
	buffer.WriteString("alternative_titles,credits,images,keywords,releases,videos,similar")

	url = string(buffer.Bytes())

	resp, err := http.Get(url)

	if err != nil {
		return film, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return film, err
	}

	err = json.Unmarshal(body, &film)

	if err != nil {
		return film, err
	}

	return film, nil
}

func determineAvailability(film Film) (FilmAvailability, error) {
	type searchResult struct {
		Id    string `json:"_id"`
		Links struct {
			IMDb string `json:"imdb"`
		} `json:"links"`
	}

	var availability FilmAvailability
	var results []searchResult

	var cisi_url *url.URL

	cisi_url, err := url.Parse("http://www.canistream.it/services/search")

	if err != nil {
		return availability, err
	}

	parameters := url.Values{}
	parameters.Add("movieName", film.Title)

	cisi_url.RawQuery = parameters.Encode()

	resp, err := http.Get(cisi_url.String())

	if err != nil {
		return availability, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return availability, err
	}

	err = json.Unmarshal(body, &results)

	if err != nil {
		return availability, err
	}

	var canIStreamItID string

	for _, result := range results {
		var imdb_id string

		if result.Links.IMDb != "" {
			imdb_id = strings.Split(result.Links.IMDb, "/")[4]
		}

		if imdb_id == film.ImdbID {
			canIStreamItID = result.Id
		}
	}

	if canIStreamItID != "" {
		mediaTypes := []string{"rental", "purchase"}

		for _, mediaType := range mediaTypes {
			var buffer bytes.Buffer

			buffer.WriteString("http://www.canistream.it/services/query?movieId=")
			buffer.WriteString(canIStreamItID)
			buffer.WriteString("&attributes=1&mediaType=")
			buffer.WriteString(mediaType)

			resp, err = http.Get(string(buffer.Bytes()))

			if err != nil {
				return availability, err
			}

			defer resp.Body.Close()

			body, err = ioutil.ReadAll(resp.Body)

			if err != nil {
				return availability, err
			}

			switch mediaType {
			case "rental":
				err = json.Unmarshal(body, &availability.Rental)

				if err != nil {
					return availability, err
				}
			case "purchase":
				err = json.Unmarshal(body, &availability.Purchase)

				if err != nil {
					return availability, err
				}
			}
		}
	}

	return availability, nil
}
<|endoftext|>


<commit_before>package main

import (
	"sort"
	"time"

	"github.com/emembrives/dispotrains/dispotrains.webapp/storage"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type dataStatus struct {
	Elevator   string
	State      string
	Lastupdate time.Time
}

func main() {
	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	cStations := session.DB("dispotrains").C("stations")
	cStatuses := session.DB("dispotrains").C("statuses")
	cStatistics := session.DB("dispotrains").C("statistics")

	err = cStatuses.EnsureIndexKey("elevator")
	if err != nil {
		panic(err)
	}
	err = cStatistics.EnsureIndexKey("name")
	if err != nil {
		panic(err)
	}

	stations := make([]storage.Station, 0, 0)
	err = cStations.Find(bson.M{}).All(&stations)
	if err != nil {
		panic(err)
	}

	for _, station := range stations {
		func(currentStation storage.Station) {
			stationStats := statsHandler(currentStation, cStatuses)
			_, err := cStatistics.Upsert(bson.M{"name": currentStation.Name}, stationStats)
			if err != nil {
				panic(err)
			}
		}(station)
	}
}

func statsHandler(station storage.Station, cStatuses *mgo.Collection) storage.StationStats {
	var elevatorIds []string
	for _, stationElevator := range station.Elevators {
		elevatorIds = append(elevatorIds, stationElevator.ID)
	}
	var dbStatuses []dataStatus

	cStatuses.Find(bson.M{"elevator": bson.M{"$in": elevatorIds}}).
		Sort("lastupdate").
		All(&dbStatuses)

	events, reports := statusesToEvents(dbStatuses)
	stats := statusesToStatistics(events, reports, dbStatuses)
	stats.Name = station.Name
	return stats
}

func statusesToEvents(dbStatuses []dataStatus) (map[string][]string, []string) {
	events := make(map[string][]string)
	reportSet := make(map[string]bool)
	for _, status := range dbStatuses {
		dateStr := status.Lastupdate.Format(time.RFC3339)
		reportSet[dateStr] = true
		if _, ok := events[status.Elevator]; !ok {
			events[status.Elevator] = make([]string, 0)
		}
		if status.State != "Disponible" {
			events[status.Elevator] = append(events[status.Elevator], dateStr)
		}
	}

	reports := make(sort.StringSlice, 0, len(reportSet))
	for key := range reportSet {
		reports = append(reports, key)
	}
	reports.Sort()
	return events, reports
}

func statusesToStatistics(events map[string][]string, reports []string, dbStatuses []dataStatus) storage.StationStats {
	stats := storage.StationStats{}
	stats.Reports = len(reports)
	reportDays := make(map[string]bool)
	for _, date := range reports {
		reportDays[date[0:10]] = true
	}
	stats.ReportDays = len(reportDays)
	stats.Elevators = make(map[string]storage.ElevatorStats)
	malfunctionDays := make(map[string]bool)
	for elevatorName, statusDates := range events {
		elevatorStats := storage.ElevatorStats{
			Name:         elevatorName,
			Malfunctions: len(statusDates),
		}
		stats.Malfunctions += len(statusDates)
		malfunctionElevatorDays := make(map[string]bool)
		for _, date := range statusDates {
			malfunctionDays[date[0:10]] = true
			malfunctionElevatorDays[date[0:10]] = true
		}
		elevatorStats.MalfunctionDays = len(malfunctionElevatorDays)
		elevatorStats.FunctionDays = len(reportDays) - len(malfunctionElevatorDays)
		if len(reportDays) != 0 {
			elevatorStats.PercentFunction = float64(elevatorStats.FunctionDays) * 100 / float64(len(reportDays))
		} else {
			elevatorStats.PercentFunction = 100.0
		}
		stats.Elevators[elevatorName] = elevatorStats
	}
	stats.MalfunctionDays = len(malfunctionDays)
	stats.FunctionDays = len(reportDays) - len(malfunctionDays)
	if len(reportDays) != 0 {
		stats.PercentFunction = float64(stats.FunctionDays) * 100 / float64(len(reportDays))
	} else {
		stats.PercentFunction = 100.0
	}
	return stats
}
<commit_msg>Start stats<commit_after>package main

import (
	"sort"
	"time"

	"github.com/emembrives/dispotrains/dispotrains.webapp/storage"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type dataStatus struct {
	Elevator   string
	State      string
	Lastupdate time.Time
}

func main() {
	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	cStations := session.DB("dispotrains").C("stations")
	cStatuses := session.DB("dispotrains").C("statuses")
	cStatistics := session.DB("dispotrains").C("statistics")

	err = cStatuses.EnsureIndexKey("elevator")
	if err != nil {
		panic(err)
	}
	err = cStatistics.EnsureIndexKey("name")
	if err != nil {
		panic(err)
	}

	stations := make([]storage.Station, 0, 0)
	err = cStations.Find(bson.M{}).All(&stations)
	if err != nil {
		panic(err)
	}

	for _, station := range stations {
		func(currentStation storage.Station) {
			stationStats := statsHandler(currentStation, cStatuses)
			_, err := cStatistics.Upsert(bson.M{"name": currentStation.Name}, stationStats)
			if err != nil {
				panic(err)
			}
		}(station)
	}
}

type events struct {
}

func statsHandler(station storage.Station, cStatuses *mgo.Collection) storage.StationStats {
	var elevatorIds []string
	for _, stationElevator := range station.Elevators {
		elevatorIds = append(elevatorIds, stationElevator.ID)
	}
	var dbStatuses []dataStatus

	cStatuses.Find(bson.M{"elevator": bson.M{"$in": elevatorIds}}).
		Sort("lastupdate").
		All(&dbStatuses)

	events, reports := statusesToEvents(dbStatuses)
	stats := statusesToStatistics(events, reports, dbStatuses)
	stats.Name = station.Name
	return stats
}

func statusesToEvents(dbStatuses []dataStatus) (map[string][]string, []string) {
	events := make(map[string][]string)
	reportSet := make(map[string]bool)
	var firstStatus, lastStatus time.Time = dbStatuses[0].Lastupdate, dbStatuses[0].Lastupdate
	for _, status := range dbStatuses {
		if status.State == "Information non disponible" {
			continue
		}
		if lastStatus.Before(status.Lastupdate) {
			lastStatus = status.Lastupdate
		}
		dateStr := status.Lastupdate.Format(time.RFC3339)
		reportSet[dateStr] = true
		if _, ok := events[status.Elevator]; !ok {
			events[status.Elevator] = make([]string, 0)
		}
		if status.State != "Disponible" {
			events[status.Elevator] = append(events[status.Elevator], dateStr)
		}
	}

	reports := make(sort.StringSlice, 0, len(reportSet))
	for key := range reportSet {
		reports = append(reports, key)
	}
	reports.Sort()
	return events, reports
}

func statusesToStatistics(events map[string][]string, reports []string, dbStatuses []dataStatus) storage.StationStats {
	stats := storage.StationStats{}
	stats.Reports = len(reports)
	reportDays := make(map[string]bool)
	for _, date := range reports {
		reportDays[date[0:10]] = true
	}
	stats.ReportDays = len(reportDays)
	stats.Elevators = make(map[string]storage.ElevatorStats)
	malfunctionDays := make(map[string]bool)
	for elevatorName, statusDates := range events {
		elevatorStats := storage.ElevatorStats{
			Name:         elevatorName,
			Malfunctions: len(statusDates),
		}
		stats.Malfunctions += len(statusDates)
		malfunctionElevatorDays := make(map[string]bool)
		for _, date := range statusDates {
			malfunctionDays[date[0:10]] = true
			malfunctionElevatorDays[date[0:10]] = true
		}
		elevatorStats.MalfunctionDays = len(malfunctionElevatorDays)
		elevatorStats.FunctionDays = len(reportDays) - len(malfunctionElevatorDays)
		if len(reportDays) != 0 {
			elevatorStats.PercentFunction = float64(elevatorStats.FunctionDays) * 100 / float64(len(reportDays))
		} else {
			elevatorStats.PercentFunction = 100.0
		}
		stats.Elevators[elevatorName] = elevatorStats
	}
	stats.MalfunctionDays = len(malfunctionDays)
	stats.FunctionDays = len(reportDays) - len(malfunctionDays)
	if len(reportDays) != 0 {
		stats.PercentFunction = float64(stats.FunctionDays) * 100 / float64(len(reportDays))
	} else {
		stats.PercentFunction = 100.0
	}
	return stats
}
<|endoftext|>