<commit_before>package mixpanel

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

var IgnoreTime *time.Time = &time.Time{}

type MixpanelError struct {
	URL string
	Err error
}

func (err *MixpanelError) Cause() error {
	return err.Err
}

func (err *MixpanelError) Error() string {
	return "mixpanel: " + err.Err.Error()
}

type ErrTrackFailed struct {
	Body string
	Resp *http.Response
}

func (err *ErrTrackFailed) Error() string {
	return fmt.Sprintf("Mixpanel did not return 1 when tracking: %s", err.Body)
}

// The Mixapanel struct store the mixpanel endpoint and the project token
type Mixpanel interface {
	// Create a mixpanel event
	Track(distinctId, eventName string, e *Event) error

	// Set properties for a mixpanel user.
	Update(distinctId string, u *Update) error

	// Create an alias for an existing distinct id
	Alias(distinctId, newId string) error
}

// The Mixapanel struct store the mixpanel endpoint and the project token
type mixpanel struct {
	Client *http.Client
	Token  string
	ApiURL string
}

// A mixpanel event
type Event struct {
	// IP-address of the user. Leave empty to use autodetect, or set to "0" to
	// not specify an ip-address.
	IP string

	// Timestamp. Set to nil to use the current time.
	Timestamp *time.Time

	// Custom properties. At least one must be specified.
	Properties map[string]interface{}
}

// An update of a user in mixpanel
type Update struct {
	// IP-address of the user. Leave empty to use autodetect, or set to "0" to
	// not specify an ip-address at all.
	IP string

	// Timestamp. Set to nil to use the current time, or IgnoreTime to not use a
	// timestamp.
	Timestamp *time.Time

	// Update operation such as "$set", "$update" etc.
	Operation string

	// Custom properties. At least one must be specified.
	Properties map[string]interface{}
}

// Alias create an alias for an existing distinct id
func (m *mixpanel) Alias(distinctId, newId string) error {
	props := map[string]interface{}{
		"token":       m.Token,
		"distinct_id": distinctId,
		"alias":       newId,
	}

	params := map[string]interface{}{
		"event":      "$create_alias",
		"properties": props,
	}

	return m.send("track", params, false)
}

// Track create an event for an existing distinct id
func (m *mixpanel) Track(distinctId, eventName string, e *Event) error {
	props := map[string]interface{}{
		"token":       m.Token,
		"distinct_id": distinctId,
	}
	if e.IP != "" {
		props["ip"] = e.IP
	}
	if e.Timestamp != nil {
		props["time"] = e.Timestamp.Unix()
	}

	for key, value := range e.Properties {
		props[key] = value
	}

	params := map[string]interface{}{
		"event":      eventName,
		"properties": props,
	}

	autoGeolocate := e.IP == ""

	return m.send("track", params, autoGeolocate)
}

// Update updates a user in mixpanel. See
// https://mixpanel.com/help/reference/http#people-analytics-updates
func (m *mixpanel) Update(distinctId string, u *Update) error {
	params := map[string]interface{}{
		"$token":       m.Token,
		"$distinct_id": distinctId,
	}

	if u.IP != "" {
		params["$ip"] = u.IP
	}
	if u.Timestamp == IgnoreTime {
		params["$ignore_time"] = true
	} else if u.Timestamp != nil {
		params["$time"] = u.Timestamp.Unix()
	}

	params[u.Operation] = u.Properties

	autoGeolocate := u.IP == ""

	return m.send("engage", params, autoGeolocate)
}

func (m *mixpanel) to64(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

func (m *mixpanel) send(eventType string, params interface{}, autoGeolocate bool) error {
	data, err := json.Marshal(params)

	if err != nil {
		return err
	}

	url := m.ApiURL + "/" + eventType + "?data=" + m.to64(data)

	if autoGeolocate {
		url += "&ip=1"
	}

	wrapErr := func(err error) error {
		return &MixpanelError{URL: url, Err: err}
	}

	resp, err := m.Client.Get(url)

	if err != nil {
		return wrapErr(err)
	}

	defer resp.Body.Close()

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

	if bodyErr != nil {
		return wrapErr(bodyErr)
	}

	if strBody := string(body); strBody != "1" && strBody != "1\n" {
		return wrapErr(&ErrTrackFailed{Body: strBody, Resp: resp})
	}

	return nil
}

// New returns the client instance. If apiURL is blank, the default will be used
// ("https://api.mixpanel.com").
func New(token, apiURL string) Mixpanel {
	return NewFromClient(http.DefaultClient, token, apiURL)
}

// Creates a client instance using the specified client instance. This is useful
// when using a proxy.
func NewFromClient(c *http.Client, token, apiURL string) Mixpanel {
	if apiURL == "" {
		apiURL = "https://api.mixpanel.com"
	}

	return &mixpanel{
		Client: c,
		Token:  token,
		ApiURL: apiURL,
	}
}
<commit_msg>Get verbose response and return detailed error message<commit_after>package mixpanel

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

var IgnoreTime *time.Time = &time.Time{}

type MixpanelError struct {
	URL string
	Err error
}

func (err *MixpanelError) Cause() error {
	return err.Err
}

func (err *MixpanelError) Error() string {
	return "mixpanel: " + err.Err.Error()
}

type ErrTrackFailed struct {
	Message string
}

func (err *ErrTrackFailed) Error() string {
	return fmt.Sprintf("Mixpanel did not return 1 when tracking: %s", err.Message)
}

// The Mixapanel struct store the mixpanel endpoint and the project token
type Mixpanel interface {
	// Create a mixpanel event
	Track(distinctId, eventName string, e *Event) error

	// Set properties for a mixpanel user.
	Update(distinctId string, u *Update) error

	// Create an alias for an existing distinct id
	Alias(distinctId, newId string) error
}

// The Mixapanel struct store the mixpanel endpoint and the project token
type mixpanel struct {
	Client *http.Client
	Token  string
	ApiURL string
}

// A mixpanel event
type Event struct {
	// IP-address of the user. Leave empty to use autodetect, or set to "0" to
	// not specify an ip-address.
	IP string

	// Timestamp. Set to nil to use the current time.
	Timestamp *time.Time

	// Custom properties. At least one must be specified.
	Properties map[string]interface{}
}

// An update of a user in mixpanel
type Update struct {
	// IP-address of the user. Leave empty to use autodetect, or set to "0" to
	// not specify an ip-address at all.
	IP string

	// Timestamp. Set to nil to use the current time, or IgnoreTime to not use a
	// timestamp.
	Timestamp *time.Time

	// Update operation such as "$set", "$update" etc.
	Operation string

	// Custom properties. At least one must be specified.
	Properties map[string]interface{}
}

// Alias create an alias for an existing distinct id
func (m *mixpanel) Alias(distinctId, newId string) error {
	props := map[string]interface{}{
		"token":       m.Token,
		"distinct_id": distinctId,
		"alias":       newId,
	}

	params := map[string]interface{}{
		"event":      "$create_alias",
		"properties": props,
	}

	return m.send("track", params, false)
}

// Track create an event for an existing distinct id
func (m *mixpanel) Track(distinctId, eventName string, e *Event) error {
	props := map[string]interface{}{
		"token":       m.Token,
		"distinct_id": distinctId,
	}
	if e.IP != "" {
		props["ip"] = e.IP
	}
	if e.Timestamp != nil {
		props["time"] = e.Timestamp.Unix()
	}

	for key, value := range e.Properties {
		props[key] = value
	}

	params := map[string]interface{}{
		"event":      eventName,
		"properties": props,
	}

	autoGeolocate := e.IP == ""

	return m.send("track", params, autoGeolocate)
}

// Update updates a user in mixpanel. See
// https://mixpanel.com/help/reference/http#people-analytics-updates
func (m *mixpanel) Update(distinctId string, u *Update) error {
	params := map[string]interface{}{
		"$token":       m.Token,
		"$distinct_id": distinctId,
	}

	if u.IP != "" {
		params["$ip"] = u.IP
	}
	if u.Timestamp == IgnoreTime {
		params["$ignore_time"] = true
	} else if u.Timestamp != nil {
		params["$time"] = u.Timestamp.Unix()
	}

	params[u.Operation] = u.Properties

	autoGeolocate := u.IP == ""

	return m.send("engage", params, autoGeolocate)
}

func (m *mixpanel) to64(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

func (m *mixpanel) send(eventType string, params interface{}, autoGeolocate bool) error {
	data, err := json.Marshal(params)

	if err != nil {
		return err
	}

	url := m.ApiURL + "/" + eventType + "?data=" + m.to64(data) + "&verbose=1"

	if autoGeolocate {
		url += "&ip=1"
	}

	wrapErr := func(err error) error {
		return &MixpanelError{URL: url, Err: err}
	}

	resp, err := m.Client.Get(url)

	if err != nil {
		return wrapErr(err)
	}

	defer resp.Body.Close()

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

	if bodyErr != nil {
		return wrapErr(bodyErr)
	}

	type verboseResponse struct {
		Error  string `json:"error"`
		Status int    `json:"status"`
	}

	var jsonBody verboseResponse
	json.Unmarshal(body, &jsonBody)

	if jsonBody.Status != 1 {
		return wrapErr(&ErrTrackFailed{Message: jsonBody.Error})
	}

	return nil
}

// New returns the client instance. If apiURL is blank, the default will be used
// ("https://api.mixpanel.com").
func New(token, apiURL string) Mixpanel {
	return NewFromClient(http.DefaultClient, token, apiURL)
}

// Creates a client instance using the specified client instance. This is useful
// when using a proxy.
func NewFromClient(c *http.Client, token, apiURL string) Mixpanel {
	if apiURL == "" {
		apiURL = "https://api.mixpanel.com"
	}

	return &mixpanel{
		Client: c,
		Token:  token,
		ApiURL: apiURL,
	}
}
<|endoftext|>


<commit_before>package model

import (
	"database/sql"
	"fmt"
	"log"

	// Not referenced but needed for database/sql
	_ "github.com/lib/pq"
)

var db *sql.DB

// InitDB start DB connection
func InitDB(dbHost string, dbPort int, dbUser string, dbPass string, dbName string) {
	database, err := sql.Open(`postgres`, fmt.Sprintf(`host=%s port=%d user=%s password=%s dbname=%s sslmode=disable`, dbHost, dbPort, dbUser, dbPass, dbName))
	if err != nil {
		log.Fatal(err)
	}

	err = database.Ping()
	if err != nil {
		log.Fatal(err)
	}

	log.Printf(`Connected to %s database`, dbName)
	db = database
}

// RetrieveByID retrieve Performance from database by isin
func RetrieveByID(isin string) (*Performance, error) {
	var score float64
	err := db.QueryRow(`SELECT score FROM funds WHERE isin=$1`, isin).Scan(&score)

	if err != nil {
		return nil, err
	}

	return &Performance{Isin: isin, Score: score}, nil
}

// SaveAll create or update all given Performances
func SaveAll(performances []Performance, tx *sql.Tx) error {
	var err error
	var usedTx *sql.Tx

	defer func() {
		deferTx(tx, usedTx, err)
	}()

	if usedTx, err = getTx(tx); err != nil {
		return err
	}

	for _, performance := range performances {
		if err = Save(performance, usedTx); err != nil {
			return err
		}
	}

	return nil
}

// Save create or update given Performance
func Save(perf Performance, tx *sql.Tx) error {
	var err error
	var usedTx *sql.Tx

	defer func() {
		deferTx(tx, usedTx, err)
	}()

	if usedTx, err = getTx(tx); err != nil {
		return err
	}

	if _, err = RetrieveByID(perf.Isin); err != nil {
		err = create(perf, usedTx)
	} else {
		err = update(perf, usedTx)
	}

	return err
}

func create(perf Performance, tx *sql.Tx) error {
	_, err := tx.Exec(`INSERT INTO funds (isin, score) VALUES ($1, $2)`, perf.Isin, perf.Score)

	return err
}

func update(perf Performance, tx *sql.Tx) error {
	_, err := tx.Exec(`UPDATE funds SET score=$1, update_date=$2 WHERE isin=$3`, perf.Score, `now()`, perf.Isin)

	return err
}

func getTx(tx *sql.Tx) (*sql.Tx, error) {
	if tx == nil {
		return db.Begin()
	}

	return tx, nil
}

func deferTx(tx *sql.Tx, usedTx *sql.Tx, err error) {
	if usedTx != tx {
		if err != nil {
			usedTx.Rollback()
		} else {
			usedTx.Commit()
		}
	}
}
<commit_msg>Update db.go<commit_after>package model

import (
	"database/sql"
	"fmt"
	"log"

	// Not referenced but needed for database/sql
	_ "github.com/lib/pq"
)

var db *sql.DB

// InitDB start DB connection
func InitDB(dbHost string, dbPort int, dbUser string, dbPass string, dbName string) {
	database, err := sql.Open(`postgres`, fmt.Sprintf(`host=%s port=%d user=%s password=%s dbname=%s sslmode=disable`, dbHost, dbPort, dbUser, dbPass, dbName))
	if err != nil {
		log.Fatal(err)
	}

	err = database.Ping()
	if err != nil {
		log.Fatal(err)
	}

	log.Printf(`Connected to %s database`, dbName)
	db = database
}

// RetrieveByID retrieve Performance from database by isin
func RetrieveByID(isin string) (*Performance, error) {
	var score float64
	err := db.QueryRow(`SELECT score FROM funds WHERE isin=$1`, isin).Scan(&score)

	if err != nil {
		return nil, err
	}

	return &Performance{Isin: isin, Score: score}, nil
}

// SaveAll create or update all given Performances
func SaveAll(performances []Performance, tx *sql.Tx) error {
	var err error
	var usedTx *sql.Tx

	defer func() {
		deferTx(tx, usedTx, err)
	}()

	if usedTx, err = getTx(tx); err != nil {
		return err
	}

	for _, performance := range performances {
		if err = Save(performance, usedTx); err != nil {
			return err
		}
	}

	return nil
}

// Save create or update given Performance
func Save(perf Performance, tx *sql.Tx) error {
	var err error
	var usedTx *sql.Tx

	defer func() {
		deferTx(tx, usedTx, err)
	}()

	if usedTx, err = getTx(tx); err != nil {
		return err
	}

	if _, err = RetrieveByID(perf.Isin); err != nil {
		err = create(perf, usedTx)
	} else {
		err = update(perf, usedTx)
	}

	return err
}

func create(perf Performance, tx *sql.Tx) error {
	_, err := tx.Exec(`INSERT INTO funds (isin, score) VALUES ($1, $2)`, perf.Isin, perf.Score)

	return err
}

func update(perf Performance, tx *sql.Tx) error {
	_, err := tx.Exec(`UPDATE funds SET score=$1, update_date=$2 WHERE isin=$3`, perf.Score, `now()`, perf.Isin)

	return err
}

func getTx(tx *sql.Tx) (*sql.Tx, error) {
	if tx == nil {
		return db.Begin()
	}

	return tx, nil
}

func deferTx(tx *sql.Tx, usedTx *sql.Tx, err error) {
	if usedTx != tx {
		log.Printf(`Ending transaction with %v`, err)
		if err != nil {
			usedTx.Rollback()
		} else {
			usedTx.Commit()
		}
	}
}
<|endoftext|>


<commit_before>/*
 * MumbleDJ
 * By Matthieu Grieger
 * youtube_dl.go
 * Copyright (c) 2014, 2015 Matthieu Grieger (MIT License)
 */

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/jmoiron/jsonq"
	"github.com/layeh/gumble/gumble"
	"github.com/layeh/gumble/gumble_ffmpeg"
)

// AudioTrack implements the Song interface
type AudioTrack struct {
	id        string
	title     string
	thumbnail string
	submitter *gumble.User
	duration  int
	url       string
	offset    int
	format    string
	playlist  Playlist
	skippers  []string
	dontSkip  bool
	service   Service
}

// AudioPlaylist implements the Playlist interface
type AudioPlaylist struct {
	id    string
	title string
}

// ------------
// YOUTUBEDL SONG
// ------------

// Download downloads the song via youtube-dl if it does not already exist on disk.
// All downloaded songs are stored in ~/.mumbledj/songs and should be automatically cleaned.
func (dl *AudioTrack) Download() error {

	// Checks to see if song is already downloaded
	if _, err := os.Stat(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename())); os.IsNotExist(err) {
		cmd := exec.Command("youtube-dl", "--verbose", "--no-mtime", "--output", fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename()), "--format", dl.format, "--prefer-ffmpeg", dl.url)
		output, err := cmd.CombinedOutput()
		if err == nil {
			if dj.conf.Cache.Enabled {
				dj.cache.CheckMaximumDirectorySize()
			}
			return nil
		} else {
			args := ""
			for s := range cmd.Args {
				args += cmd.Args[s] + " "
			}
			fmt.Printf(args + "\n" + string(output) + "\n" + "youtube-dl: " + err.Error() + "\n")
			return errors.New("Song download failed.")
		}
	}
	return nil
}

// Play plays the song. Once the song is playing, a notification is displayed in a text message that features the song
// thumbnail, URL, title, duration, and submitter.
func (dl *AudioTrack) Play() {
	if dl.offset != 0 {
		offsetDuration, _ := time.ParseDuration(fmt.Sprintf("%ds", dl.offset))
		dj.audioStream.Offset = offsetDuration
	}
	dj.audioStream.Source = gumble_ffmpeg.SourceFile(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename()))
	if err := dj.audioStream.Play(); err != nil {
		panic(err)
	} else {
		message := `<table><tr><td align="center"><img src="%s" width=150 /></td></tr><tr><td align="center"><b><a href="%s">%s</a> (%s)</b></td></tr><tr><td align="center">Added by %s</td></tr>`
		message = fmt.Sprintf(message, dl.thumbnail, dl.url, dl.title, dl.Duration().String(), dl.submitter.Name)
		if !isNil(dl.playlist) {
			message = fmt.Sprintf(message+`<tr><td align="center">From playlist "%s"</td></tr>`, dl.Playlist().Title())
		}
		if dj.conf.General.AnnounceNewTrack {
			dj.client.Self.Channel.Send(message+`</table>`, false)
		}
		go func() {
			dj.audioStream.Wait()
			dj.queue.OnSongFinished()
		}()
	}
}

// Delete deletes the song from ~/.mumbledj/songs if the cache is disabled.
func (dl *AudioTrack) Delete() error {
	if dj.conf.Cache.Enabled == false {
		filePath := fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename())
		if _, err := os.Stat(filePath); err == nil {
			if err := os.Remove(filePath); err == nil {
				return nil
			}
			return errors.New("Error occurred while deleting audio file.")
		}
		return nil
	}
	return nil
}

// AddSkip adds a skip to the skippers slice. If the user is already in the slice, AddSkip
// returns an error and does not add a duplicate skip.
func (dl *AudioTrack) AddSkip(username string) error {
	for _, user := range dl.skippers {
		if username == user {
			return errors.New("This user has already skipped the current song.")
		}
	}
	dl.skippers = append(dl.skippers, username)
	return nil
}

// RemoveSkip removes a skip from the skippers slice. If username is not in slice, an error is
// returned.
func (dl *AudioTrack) RemoveSkip(username string) error {
	for i, user := range dl.skippers {
		if username == user {
			dl.skippers = append(dl.skippers[:i], dl.skippers[i+1:]...)
			return nil
		}
	}
	return errors.New("This user has not skipped the song.")
}

// SkipReached calculates the current skip ratio based on the number of users within MumbleDJ's
// channel and the number of usernames in the skippers slice. If the value is greater than or equal
// to the skip ratio defined in the config, the function returns true, and returns false otherwise.
func (dl *AudioTrack) SkipReached(channelUsers int) bool {
	if float32(len(dl.skippers))/float32(channelUsers) >= dj.conf.General.SkipRatio {
		return true
	}
	return false
}

// Submitter returns the name of the submitter of the Song.
func (dl *AudioTrack) Submitter() string {
	return dl.submitter.Name
}

// Title returns the title of the Song.
func (dl *AudioTrack) Title() string {
	return dl.title
}

// ID returns the id of the Song.
func (dl *AudioTrack) ID() string {
	return dl.id
}

// Filename returns the filename of the Song.
func (dl *AudioTrack) Filename() string {
	return dl.id + ".m4a"
}

// Duration returns duration for the Song.
func (dl *AudioTrack) Duration() time.Duration {
	timeDuration, _ := time.ParseDuration(strconv.Itoa(dl.duration) + "s")
	return timeDuration
}

// Thumbnail returns the thumbnail URL for the Song.
func (dl *AudioTrack) Thumbnail() string {
	return dl.thumbnail
}

// Playlist returns the playlist type for the Song (may be nil).
func (dl *AudioTrack) Playlist() Playlist {
	return dl.playlist
}

// DontSkip returns the DontSkip boolean value for the Song.
func (dl *AudioTrack) DontSkip() bool {
	return dl.dontSkip
}

// SetDontSkip sets the DontSkip boolean value for the Song.
func (dl *AudioTrack) SetDontSkip(value bool) {
	dl.dontSkip = value
}

// ----------------
// YOUTUBEDL PLAYLIST
// ----------------

// AddSkip adds a skip to the playlist's skippers slice.
func (p *AudioPlaylist) AddSkip(username string) error {
	for _, user := range dj.playlistSkips[p.ID()] {
		if username == user {
			return errors.New("This user has already skipped the current song.")
		}
	}
	dj.playlistSkips[p.ID()] = append(dj.playlistSkips[p.ID()], username)
	return nil
}

// RemoveSkip removes a skip from the playlist's skippers slice. If username is not in the slice
// an error is returned.
func (p *AudioPlaylist) RemoveSkip(username string) error {
	for i, user := range dj.playlistSkips[p.ID()] {
		if username == user {
			dj.playlistSkips[p.ID()] = append(dj.playlistSkips[p.ID()][:i], dj.playlistSkips[p.ID()][i+1:]...)
			return nil
		}
	}
	return errors.New("This user has not skipped the song.")
}

// DeleteSkippers removes the skippers entry in dj.playlistSkips.
func (p *AudioPlaylist) DeleteSkippers() {
	delete(dj.playlistSkips, p.ID())
}

// SkipReached calculates the current skip ratio based on the number of users within MumbleDJ's
// channel and the number of usernames in the skippers slice. If the value is greater than or equal
// to the skip ratio defined in the config, the function returns true, and returns false otherwise.
func (p *AudioPlaylist) SkipReached(channelUsers int) bool {
	if float32(len(dj.playlistSkips[p.ID()]))/float32(channelUsers) >= dj.conf.General.PlaylistSkipRatio {
		return true
	}
	return false
}

// ID returns the id of the AudioPlaylist.
func (p *AudioPlaylist) ID() string {
	return p.id
}

// Title returns the title of the AudioPlaylist.
func (p *AudioPlaylist) Title() string {
	return p.title
}

// PerformGetRequest does all the grunt work for HTTPS GET request.
func PerformGetRequest(url string) (*jsonq.JsonQuery, error) {
	jsonString := ""

	if response, err := http.Get(url); err == nil {
		defer response.Body.Close()
		if response.StatusCode == 200 {
			if body, err := ioutil.ReadAll(response.Body); err == nil {
				jsonString = string(body)
			}
		} else {
			if response.StatusCode == 403 {
				return nil, errors.New("Invalid API key supplied.")
			}
			return nil, errors.New("Invalid ID supplied.")
		}
	} else {
		return nil, errors.New("An error occurred while receiving HTTP GET response.")
	}

	jsonData := map[string]interface{}{}
	decoder := json.NewDecoder(strings.NewReader(jsonString))
	decoder.Decode(&jsonData)
	jq := jsonq.NewQuery(jsonData)

	return jq, nil
}
<commit_msg>realized that having bestaudio as a file extension is perfectly valid in this case so there is no need to tack m4a on arbitrarily<commit_after>/*
 * MumbleDJ
 * By Matthieu Grieger
 * youtube_dl.go
 * Copyright (c) 2014, 2015 Matthieu Grieger (MIT License)
 */

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/jmoiron/jsonq"
	"github.com/layeh/gumble/gumble"
	"github.com/layeh/gumble/gumble_ffmpeg"
)

// AudioTrack implements the Song interface
type AudioTrack struct {
	id        string
	title     string
	thumbnail string
	submitter *gumble.User
	duration  int
	url       string
	offset    int
	format    string
	playlist  Playlist
	skippers  []string
	dontSkip  bool
	service   Service
}

// AudioPlaylist implements the Playlist interface
type AudioPlaylist struct {
	id    string
	title string
}

// ------------
// YOUTUBEDL SONG
// ------------

// Download downloads the song via youtube-dl if it does not already exist on disk.
// All downloaded songs are stored in ~/.mumbledj/songs and should be automatically cleaned.
func (dl *AudioTrack) Download() error {

	// Checks to see if song is already downloaded
	if _, err := os.Stat(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename())); os.IsNotExist(err) {
		cmd := exec.Command("youtube-dl", "--verbose", "--no-mtime", "--output", fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename()), "--format", dl.format, "--prefer-ffmpeg", dl.url)
		output, err := cmd.CombinedOutput()
		if err == nil {
			if dj.conf.Cache.Enabled {
				dj.cache.CheckMaximumDirectorySize()
			}
			return nil
		} else {
			args := ""
			for s := range cmd.Args {
				args += cmd.Args[s] + " "
			}
			fmt.Printf(args + "\n" + string(output) + "\n" + "youtube-dl: " + err.Error() + "\n")
			return errors.New("Song download failed.")
		}
	}
	return nil
}

// Play plays the song. Once the song is playing, a notification is displayed in a text message that features the song
// thumbnail, URL, title, duration, and submitter.
func (dl *AudioTrack) Play() {
	if dl.offset != 0 {
		offsetDuration, _ := time.ParseDuration(fmt.Sprintf("%ds", dl.offset))
		dj.audioStream.Offset = offsetDuration
	}
	dj.audioStream.Source = gumble_ffmpeg.SourceFile(fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename()))
	if err := dj.audioStream.Play(); err != nil {
		panic(err)
	} else {
		message := `<table><tr><td align="center"><img src="%s" width=150 /></td></tr><tr><td align="center"><b><a href="%s">%s</a> (%s)</b></td></tr><tr><td align="center">Added by %s</td></tr>`
		message = fmt.Sprintf(message, dl.thumbnail, dl.url, dl.title, dl.Duration().String(), dl.submitter.Name)
		if !isNil(dl.playlist) {
			message = fmt.Sprintf(message+`<tr><td align="center">From playlist "%s"</td></tr>`, dl.Playlist().Title())
		}
		if dj.conf.General.AnnounceNewTrack {
			dj.client.Self.Channel.Send(message+`</table>`, false)
		}
		go func() {
			dj.audioStream.Wait()
			dj.queue.OnSongFinished()
		}()
	}
}

// Delete deletes the song from ~/.mumbledj/songs if the cache is disabled.
func (dl *AudioTrack) Delete() error {
	if dj.conf.Cache.Enabled == false {
		filePath := fmt.Sprintf("%s/.mumbledj/songs/%s", dj.homeDir, dl.Filename())
		if _, err := os.Stat(filePath); err == nil {
			if err := os.Remove(filePath); err == nil {
				return nil
			}
			return errors.New("Error occurred while deleting audio file.")
		}
		return nil
	}
	return nil
}

// AddSkip adds a skip to the skippers slice. If the user is already in the slice, AddSkip
// returns an error and does not add a duplicate skip.
func (dl *AudioTrack) AddSkip(username string) error {
	for _, user := range dl.skippers {
		if username == user {
			return errors.New("This user has already skipped the current song.")
		}
	}
	dl.skippers = append(dl.skippers, username)
	return nil
}

// RemoveSkip removes a skip from the skippers slice. If username is not in slice, an error is
// returned.
func (dl *AudioTrack) RemoveSkip(username string) error {
	for i, user := range dl.skippers {
		if username == user {
			dl.skippers = append(dl.skippers[:i], dl.skippers[i+1:]...)
			return nil
		}
	}
	return errors.New("This user has not skipped the song.")
}

// SkipReached calculates the current skip ratio based on the number of users within MumbleDJ's
// channel and the number of usernames in the skippers slice. If the value is greater than or equal
// to the skip ratio defined in the config, the function returns true, and returns false otherwise.
func (dl *AudioTrack) SkipReached(channelUsers int) bool {
	if float32(len(dl.skippers))/float32(channelUsers) >= dj.conf.General.SkipRatio {
		return true
	}
	return false
}

// Submitter returns the name of the submitter of the Song.
func (dl *AudioTrack) Submitter() string {
	return dl.submitter.Name
}

// Title returns the title of the Song.
func (dl *AudioTrack) Title() string {
	return dl.title
}

// ID returns the id of the Song.
func (dl *AudioTrack) ID() string {
	return dl.id
}

// Filename returns the filename of the Song.
func (dl *AudioTrack) Filename() string {
	return dl.id + "." + dl.format
}

// Duration returns duration for the Song.
func (dl *AudioTrack) Duration() time.Duration {
	timeDuration, _ := time.ParseDuration(strconv.Itoa(dl.duration) + "s")
	return timeDuration
}

// Thumbnail returns the thumbnail URL for the Song.
func (dl *AudioTrack) Thumbnail() string {
	return dl.thumbnail
}

// Playlist returns the playlist type for the Song (may be nil).
func (dl *AudioTrack) Playlist() Playlist {
	return dl.playlist
}

// DontSkip returns the DontSkip boolean value for the Song.
func (dl *AudioTrack) DontSkip() bool {
	return dl.dontSkip
}

// SetDontSkip sets the DontSkip boolean value for the Song.
func (dl *AudioTrack) SetDontSkip(value bool) {
	dl.dontSkip = value
}

// ----------------
// YOUTUBEDL PLAYLIST
// ----------------

// AddSkip adds a skip to the playlist's skippers slice.
func (p *AudioPlaylist) AddSkip(username string) error {
	for _, user := range dj.playlistSkips[p.ID()] {
		if username == user {
			return errors.New("This user has already skipped the current song.")
		}
	}
	dj.playlistSkips[p.ID()] = append(dj.playlistSkips[p.ID()], username)
	return nil
}

// RemoveSkip removes a skip from the playlist's skippers slice. If username is not in the slice
// an error is returned.
func (p *AudioPlaylist) RemoveSkip(username string) error {
	for i, user := range dj.playlistSkips[p.ID()] {
		if username == user {
			dj.playlistSkips[p.ID()] = append(dj.playlistSkips[p.ID()][:i], dj.playlistSkips[p.ID()][i+1:]...)
			return nil
		}
	}
	return errors.New("This user has not skipped the song.")
}

// DeleteSkippers removes the skippers entry in dj.playlistSkips.
func (p *AudioPlaylist) DeleteSkippers() {
	delete(dj.playlistSkips, p.ID())
}

// SkipReached calculates the current skip ratio based on the number of users within MumbleDJ's
// channel and the number of usernames in the skippers slice. If the value is greater than or equal
// to the skip ratio defined in the config, the function returns true, and returns false otherwise.
func (p *AudioPlaylist) SkipReached(channelUsers int) bool {
	if float32(len(dj.playlistSkips[p.ID()]))/float32(channelUsers) >= dj.conf.General.PlaylistSkipRatio {
		return true
	}
	return false
}

// ID returns the id of the AudioPlaylist.
func (p *AudioPlaylist) ID() string {
	return p.id
}

// Title returns the title of the AudioPlaylist.
func (p *AudioPlaylist) Title() string {
	return p.title
}

// PerformGetRequest does all the grunt work for HTTPS GET request.
func PerformGetRequest(url string) (*jsonq.JsonQuery, error) {
	jsonString := ""

	if response, err := http.Get(url); err == nil {
		defer response.Body.Close()
		if response.StatusCode == 200 {
			if body, err := ioutil.ReadAll(response.Body); err == nil {
				jsonString = string(body)
			}
		} else {
			if response.StatusCode == 403 {
				return nil, errors.New("Invalid API key supplied.")
			}
			return nil, errors.New("Invalid ID supplied.")
		}
	} else {
		return nil, errors.New("An error occurred while receiving HTTP GET response.")
	}

	jsonData := map[string]interface{}{}
	decoder := json.NewDecoder(strings.NewReader(jsonString))
	decoder.Decode(&jsonData)
	jq := jsonq.NewQuery(jsonData)

	return jq, nil
}
<|endoftext|>


<commit_before>package libp2pquic

import (
	"net"
	"sync"
	"time"

	"github.com/vishvananda/netlink"
)

// Constants. Defined as variables to simplify testing.
var (
	garbageCollectInterval = 30 * time.Second
	maxUnusedDuration      = 10 * time.Second
)

type reuseConn struct {
	net.PacketConn

	mutex       sync.Mutex
	refCount    int
	unusedSince time.Time
}

func newReuseConn(conn net.PacketConn) *reuseConn {
	return &reuseConn{PacketConn: conn}
}

func (c *reuseConn) IncreaseCount() {
	c.mutex.Lock()
	c.refCount++
	c.unusedSince = time.Time{}
	c.mutex.Unlock()
}

func (c *reuseConn) DecreaseCount() {
	c.mutex.Lock()
	c.refCount--
	if c.refCount == 0 {
		c.unusedSince = time.Now()
	}
	c.mutex.Unlock()
}

func (c *reuseConn) ShouldGarbageCollect(now time.Time) bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return !c.unusedSince.IsZero() && c.unusedSince.Add(maxUnusedDuration).Before(now)
}

type reuse struct {
	mutex sync.Mutex

	garbageCollectorRunning bool

	handle *netlink.Handle // Only set on Linux. nil on other systems.

	unicast map[string] /* IP.String() */ map[int] /* port */ *reuseConn
	// global contains connections that are listening on 0.0.0.0 / ::
	global map[int]*reuseConn
}

func newReuse() (*reuse, error) {
	// On non-Linux systems, this will return ErrNotImplemented.
	handle, err := netlink.NewHandle()
	if err == netlink.ErrNotImplemented {
		handle = nil
	} else if err != nil {
		return nil, err
	}
	return &reuse{
		unicast: make(map[string]map[int]*reuseConn),
		global:  make(map[int]*reuseConn),
		handle:  handle,
	}, nil
}

func (r *reuse) runGarbageCollector() {
	ticker := time.NewTicker(garbageCollectInterval)
	defer ticker.Stop()

	for now := range ticker.C {
		var shouldExit bool
		r.mutex.Lock()
		for key, conn := range r.global {
			if conn.ShouldGarbageCollect(now) {
				delete(r.global, key)
			}
		}
		for ukey, conns := range r.unicast {
			for key, conn := range conns {
				if conn.ShouldGarbageCollect(now) {
					delete(conns, key)
				}
			}
			if len(conns) == 0 {
				delete(r.unicast, ukey)
			}
		}

		// stop the garbage collector if we're not tracking any connections
		if len(r.global) == 0 && len(r.unicast) == 0 {
			r.garbageCollectorRunning = false
			shouldExit = true
		}
		r.mutex.Unlock()

		if shouldExit {
			return
		}
	}
}

// must be called while holding the mutex
func (r *reuse) maybeStartGarbageCollector() {
	if !r.garbageCollectorRunning {
		r.garbageCollectorRunning = true
		go r.runGarbageCollector()
	}
}

// Get the source IP that the kernel would use for dialing.
// This only works on Linux.
// On other systems, this returns an empty slice of IP addresses.
func (r *reuse) getSourceIPs(network string, raddr *net.UDPAddr) ([]net.IP, error) {
	if r.handle == nil {
		return nil, nil
	}

	routes, err := r.handle.RouteGet(raddr.IP)
	if err != nil {
		return nil, err
	}

	ips := make([]net.IP, 0, len(routes))
	for _, route := range routes {
		ips = append(ips, route.Src)
	}
	return ips, nil
}

func (r *reuse) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
	ips, err := r.getSourceIPs(network, raddr)
	if err != nil {
		return nil, err
	}

	r.mutex.Lock()
	defer r.mutex.Unlock()

	conn, err := r.dialLocked(network, raddr, ips)
	if err != nil {
		return nil, err
	}
	conn.IncreaseCount()
	r.maybeStartGarbageCollector()
	return conn, nil
}

func (r *reuse) dialLocked(network string, raddr *net.UDPAddr, ips []net.IP) (*reuseConn, error) {
	for _, ip := range ips {
		// We already have at least one suitable connection...
		if conns, ok := r.unicast[ip.String()]; ok {
			// ... we don't care which port we're dialing from. Just use the first.
			for _, c := range conns {
				return c, nil
			}
		}
	}

	// Use a connection listening on 0.0.0.0 (or ::).
	// Again, we don't care about the port number.
	for _, conn := range r.global {
		return conn, nil
	}

	// We don't have a connection that we can use for dialing.
	// Dial a new connection from a random port.
	var addr *net.UDPAddr
	switch network {
	case "udp4":
		addr = &net.UDPAddr{IP: net.IPv4zero, Port: 0}
	case "udp6":
		addr = &net.UDPAddr{IP: net.IPv6zero, Port: 0}
	}
	conn, err := net.ListenUDP(network, addr)
	if err != nil {
		return nil, err
	}
	rconn := newReuseConn(conn)
	r.global[conn.LocalAddr().(*net.UDPAddr).Port] = rconn
	return rconn, nil
}

func (r *reuse) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
	conn, err := net.ListenUDP(network, laddr)
	if err != nil {
		return nil, err
	}
	localAddr := conn.LocalAddr().(*net.UDPAddr)

	rconn := newReuseConn(conn)
	rconn.IncreaseCount()

	r.mutex.Lock()
	defer r.mutex.Unlock()

	r.maybeStartGarbageCollector()

	// Deal with listen on a global address
	if localAddr.IP.IsUnspecified() {
		// The kernel already checked that the laddr is not already listen
		// so we need not check here (when we create ListenUDP).
		r.global[localAddr.Port] = rconn
		return rconn, err
	}

	// Deal with listen on a unicast address
	if _, ok := r.unicast[localAddr.IP.String()]; !ok {
		r.unicast[localAddr.IP.String()] = make(map[int]*reuseConn)
	}

	// The kernel already checked that the laddr is not already listen
	// so we need not check here (when we create ListenUDP).
	r.unicast[localAddr.IP.String()][localAddr.Port] = rconn
	return rconn, err
}
<commit_msg>close reuse-connections before deleting them<commit_after>package libp2pquic

import (
	"net"
	"sync"
	"time"

	"github.com/vishvananda/netlink"
)

// Constants. Defined as variables to simplify testing.
var (
	garbageCollectInterval = 30 * time.Second
	maxUnusedDuration      = 10 * time.Second
)

type reuseConn struct {
	net.PacketConn

	mutex       sync.Mutex
	refCount    int
	unusedSince time.Time
}

func newReuseConn(conn net.PacketConn) *reuseConn {
	return &reuseConn{PacketConn: conn}
}

func (c *reuseConn) IncreaseCount() {
	c.mutex.Lock()
	c.refCount++
	c.unusedSince = time.Time{}
	c.mutex.Unlock()
}

func (c *reuseConn) DecreaseCount() {
	c.mutex.Lock()
	c.refCount--
	if c.refCount == 0 {
		c.unusedSince = time.Now()
	}
	c.mutex.Unlock()
}

func (c *reuseConn) ShouldGarbageCollect(now time.Time) bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return !c.unusedSince.IsZero() && c.unusedSince.Add(maxUnusedDuration).Before(now)
}

type reuse struct {
	mutex sync.Mutex

	garbageCollectorRunning bool

	handle *netlink.Handle // Only set on Linux. nil on other systems.

	unicast map[string] /* IP.String() */ map[int] /* port */ *reuseConn
	// global contains connections that are listening on 0.0.0.0 / ::
	global map[int]*reuseConn
}

func newReuse() (*reuse, error) {
	// On non-Linux systems, this will return ErrNotImplemented.
	handle, err := netlink.NewHandle()
	if err == netlink.ErrNotImplemented {
		handle = nil
	} else if err != nil {
		return nil, err
	}
	return &reuse{
		unicast: make(map[string]map[int]*reuseConn),
		global:  make(map[int]*reuseConn),
		handle:  handle,
	}, nil
}

func (r *reuse) runGarbageCollector() {
	ticker := time.NewTicker(garbageCollectInterval)
	defer ticker.Stop()

	for now := range ticker.C {
		var shouldExit bool
		r.mutex.Lock()
		for key, conn := range r.global {
			if conn.ShouldGarbageCollect(now) {
				conn.Close()
				delete(r.global, key)
			}
		}
		for ukey, conns := range r.unicast {
			for key, conn := range conns {
				if conn.ShouldGarbageCollect(now) {
					conn.Close()
					delete(conns, key)
				}
			}
			if len(conns) == 0 {
				delete(r.unicast, ukey)
			}
		}

		// stop the garbage collector if we're not tracking any connections
		if len(r.global) == 0 && len(r.unicast) == 0 {
			r.garbageCollectorRunning = false
			shouldExit = true
		}
		r.mutex.Unlock()

		if shouldExit {
			return
		}
	}
}

// must be called while holding the mutex
func (r *reuse) maybeStartGarbageCollector() {
	if !r.garbageCollectorRunning {
		r.garbageCollectorRunning = true
		go r.runGarbageCollector()
	}
}

// Get the source IP that the kernel would use for dialing.
// This only works on Linux.
// On other systems, this returns an empty slice of IP addresses.
func (r *reuse) getSourceIPs(network string, raddr *net.UDPAddr) ([]net.IP, error) {
	if r.handle == nil {
		return nil, nil
	}

	routes, err := r.handle.RouteGet(raddr.IP)
	if err != nil {
		return nil, err
	}

	ips := make([]net.IP, 0, len(routes))
	for _, route := range routes {
		ips = append(ips, route.Src)
	}
	return ips, nil
}

func (r *reuse) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
	ips, err := r.getSourceIPs(network, raddr)
	if err != nil {
		return nil, err
	}

	r.mutex.Lock()
	defer r.mutex.Unlock()

	conn, err := r.dialLocked(network, raddr, ips)
	if err != nil {
		return nil, err
	}
	conn.IncreaseCount()
	r.maybeStartGarbageCollector()
	return conn, nil
}

func (r *reuse) dialLocked(network string, raddr *net.UDPAddr, ips []net.IP) (*reuseConn, error) {
	for _, ip := range ips {
		// We already have at least one suitable connection...
		if conns, ok := r.unicast[ip.String()]; ok {
			// ... we don't care which port we're dialing from. Just use the first.
			for _, c := range conns {
				return c, nil
			}
		}
	}

	// Use a connection listening on 0.0.0.0 (or ::).
	// Again, we don't care about the port number.
	for _, conn := range r.global {
		return conn, nil
	}

	// We don't have a connection that we can use for dialing.
	// Dial a new connection from a random port.
	var addr *net.UDPAddr
	switch network {
	case "udp4":
		addr = &net.UDPAddr{IP: net.IPv4zero, Port: 0}
	case "udp6":
		addr = &net.UDPAddr{IP: net.IPv6zero, Port: 0}
	}
	conn, err := net.ListenUDP(network, addr)
	if err != nil {
		return nil, err
	}
	rconn := newReuseConn(conn)
	r.global[conn.LocalAddr().(*net.UDPAddr).Port] = rconn
	return rconn, nil
}

func (r *reuse) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
	conn, err := net.ListenUDP(network, laddr)
	if err != nil {
		return nil, err
	}
	localAddr := conn.LocalAddr().(*net.UDPAddr)

	rconn := newReuseConn(conn)
	rconn.IncreaseCount()

	r.mutex.Lock()
	defer r.mutex.Unlock()

	r.maybeStartGarbageCollector()

	// Deal with listen on a global address
	if localAddr.IP.IsUnspecified() {
		// The kernel already checked that the laddr is not already listen
		// so we need not check here (when we create ListenUDP).
		r.global[localAddr.Port] = rconn
		return rconn, err
	}

	// Deal with listen on a unicast address
	if _, ok := r.unicast[localAddr.IP.String()]; !ok {
		r.unicast[localAddr.IP.String()] = make(map[int]*reuseConn)
	}

	// The kernel already checked that the laddr is not already listen
	// so we need not check here (when we create ListenUDP).
	r.unicast[localAddr.IP.String()][localAddr.Port] = rconn
	return rconn, err
}
<|endoftext|>


<commit_before>package generatorControllers

import (
	. "eaciit/wfdemo-git/processapp/summaryGenerator/controllers"
	"github.com/eaciit/dbox"
	_ "github.com/eaciit/dbox/dbc/mongo"
	tk "github.com/eaciit/toolkit"
	"sync"
	"time"
)

type TurbulenceIntensitySummary struct {
	*BaseController
}

type TurbulenceIntensity struct {
	ID                string ` bson:"_id" , json:"_id" `
	Projectname       string
	Turbine           string
	Timestamp         time.Time
	WindspeedBin      float64
	WindSpeedTotal    float64
	WindSpeedStdTotal float64
	WindSpeedCount    float64
	WindSpeedStdCount float64
	Type              string
}

func (m *TurbulenceIntensity) TableName() string {
	return "rpt_turbulenceintensity"
}

type LatestTurbulence struct {
	ID          string ` bson:"_id" , json:"_id" `
	Projectname string
	LastUpdate  time.Time
	Type        string
}

func (m *LatestTurbulence) TableName() string {
	return "log_latestturbulence"
}

func (ev *TurbulenceIntensitySummary) CreateTurbulenceIntensitySummary(base *BaseController) {
	ev.BaseController = base

	ev.Log.AddLog("===================== Start processing Turbulence Intensity Summary...", sInfo)

	var wg sync.WaitGroup
	wg.Add(2)

	go ev.processDataScada(&wg)
	go ev.processDataMet(&wg)

	wg.Wait()

	ev.Log.AddLog("===================== End processing Turbulence Intensity Summary...", sInfo)
}

func (ev *TurbulenceIntensitySummary) getProjectList() (result []string) {
	ev.Log.AddLog("Get Project List", sInfo)

	projectData := []tk.M{}
	csrt, e := ev.Ctx.Connection.NewQuery().
		From("ref_project").Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor at getProjectList due to : %s", e.Error()), sError)
		return
	}
	defer csrt.Close()
	e = csrt.Fetch(&projectData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on fetch at getProjectList due to : %s", e.Error()), sError)
		return
	}
	result = []string{}
	for _, val := range projectData {
		result = append(result, val.GetString("projectid"))
	}
	ev.Log.AddLog("Finish getting Project List", sInfo)

	return
}

func (ev *TurbulenceIntensitySummary) getLatestData(tipe string) (result map[string]time.Time) {
	ev.Log.AddLog("Get latest data for each turbine", sInfo)

	latestData := []LatestTurbulence{}
	csrt, e := ev.Ctx.Connection.NewQuery().
		From(new(LatestTurbulence).TableName()).
		Where(dbox.Eq("type", tipe)).Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor at getLatestData due to : %s", e.Error()), sError)
		return
	}
	defer csrt.Close()
	e = csrt.Fetch(&latestData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on fetch at getLatestData due to : %s", e.Error()), sError)
		return
	}
	result = map[string]time.Time{}
	for _, val := range latestData {
		result[val.Projectname] = val.LastUpdate
	}
	ev.Log.AddLog("Finish getting latest data for each turbine", sInfo)

	return
}

func (ev *TurbulenceIntensitySummary) updateLastData(projectname, tipe string, maxTimeStamp time.Time) {
	if !maxTimeStamp.IsZero() {
		data := LatestTurbulence{}
		data.Projectname = projectname
		data.ID = tk.Sprintf("%s_%s", data.Projectname, tipe)
		data.LastUpdate = maxTimeStamp
		data.Type = tipe

		e := ev.Ctx.Connection.NewQuery().SetConfig("multiexec", true).
			From(new(LatestTurbulence).TableName()).Save().Exec(tk.M{"data": data})

		if e != nil {
			ev.Log.AddLog(tk.Sprintf("Error on Save at updateLastData due to : %s", e.Error()), sError)
		}
	}
	ev.Log.AddLog(tk.Sprintf("Finish updating last data for %s on %s at %s", projectname, tipe, maxTimeStamp.String()), sInfo)
}

func (ev *TurbulenceIntensitySummary) processDataScada(wgScada *sync.WaitGroup) {
	defer wgScada.Done()

	t0 := time.Now()
	projectList := ev.getProjectList()
	lastUpdatePerProject := ev.getLatestData("SCADA")

	var wg sync.WaitGroup
	wg.Add(len(projectList))
	for _, _project := range projectList {
		go ev.projectWorker(_project, lastUpdatePerProject[_project], &wg)
	}
	wg.Wait()

	ev.Log.AddLog(tk.Sprintf("Duration processing scada data %f minutes", time.Since(t0).Minutes()), sInfo)
}

func (ev *TurbulenceIntensitySummary) projectWorker(projectname string, lastUpdate time.Time, wgProject *sync.WaitGroup) {
	defer wgProject.Done()

	countWS := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeed", false}},
				tk.M{"$gte": []interface{}{"$windspeed", -200}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}
	countWSStd := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeedstddev", false}},
				tk.M{"$gte": []interface{}{"$windspeedstddev", -200}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}

	ev.Log.AddLog(tk.Sprintf("Update data %s from %s", projectname, lastUpdate.String()), sInfo)
	pipe := []tk.M{
		tk.M{"$match": tk.M{
			"$and": []tk.M{
				tk.M{"dateinfo.dateid": tk.M{"$gte": lastUpdate}},
				tk.M{"projectname": projectname},
				tk.M{"type": "SCADA"},
			},
		}},
		tk.M{"$group": tk.M{
			"_id": tk.M{
				"projectname":  "$projectname",
				"turbine":      "$turbine",
				"windspeedbin": "$windspeedbin",
				"timestamp":    "$dateinfo.dateid",
			},
			"windspeedtotal":    tk.M{"$sum": "$windspeed"},
			"windspeedstdtotal": tk.M{"$sum": "$windspeedstddev"},
			"windspeedcount":    tk.M{"$sum": countWS},
			"windspeedstdcount": tk.M{"$sum": countWSStd},
		}},
	}

	csr, e := ev.Ctx.Connection.NewQuery().
		From("TurbulenceIntensity10Min").
		Command("pipe", pipe).Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor : %s", e.Error()), sError)
	}
	defer csr.Close()

	turbulenceData := []tk.M{}
	e = csr.Fetch(&turbulenceData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on fetch : %s", e.Error()), sError)
	}

	var wg sync.WaitGroup
	totalData := len(turbulenceData)
	totalWorker := 4
	dataChan := make(chan TurbulenceIntensity, totalData)

	wg.Add(totalWorker)
	for i := 0; i < totalWorker; i++ {
		go func() {
			defer wg.Done()
			ctxWorker, e := PrepareConnection()
			if e != nil {
				ev.Log.AddLog(e.Error(), sError)
			}
			defer ctxWorker.Close()
			csrSave := ctxWorker.NewQuery().SetConfig("multiexec", true).
				From(new(TurbulenceIntensity).TableName()).Save()
			defer csrSave.Close()
			for data := range dataChan {
				e = csrSave.Exec(tk.M{"data": data})
				if e != nil {
					ev.Log.AddLog(tk.Sprintf("Error on Save : %s", e.Error()), sError)
				}
			}
		}()
	}

	data := TurbulenceIntensity{}
	maxTimeStamp := time.Time{}

	for _, _data := range turbulenceData {
		data = TurbulenceIntensity{}
		ids := _data.Get("_id", tk.M{}).(tk.M)
		data.Projectname = ids.GetString("projectname")
		data.Turbine = ids.GetString("turbine")
		data.Timestamp = ids.Get("timestamp", time.Time{}).(time.Time).UTC()
		data.WindspeedBin = ids.GetFloat64("windspeedbin")
		data.ID = tk.Sprintf("%s_%s_%s_%s", data.Projectname, data.Turbine, tk.Sprintf("%.1f", data.WindspeedBin), data.Timestamp.Format("20060102"))

		data.WindSpeedTotal = _data.GetFloat64("windspeedtotal")
		data.WindSpeedStdTotal = _data.GetFloat64("windspeedstdtotal")
		data.WindSpeedCount = _data.GetFloat64("windspeedcount")
		data.WindSpeedStdCount = _data.GetFloat64("windspeedstdcount")
		data.Type = "SCADA"

		if data.Timestamp.After(maxTimeStamp) {
			maxTimeStamp = data.Timestamp
		}

		dataChan <- data
	}

	close(dataChan)
	wg.Wait()

	ev.updateLastData(projectname, "SCADA", maxTimeStamp)
}

func (ev *TurbulenceIntensitySummary) projectWorkerMet(projectname string, lastupdate time.Time, wgProject *sync.WaitGroup) {
	defer wgProject.Done()

	countWS := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeed", false}},
				tk.M{"$gte": []interface{}{"$windspeed", -200}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}
	countWSStd := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeedstddev", false}},
				tk.M{"$gte": []interface{}{"$windspeedstddev", -200}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}
	pipe := []tk.M{
		tk.M{"$match": tk.M{
			"$and": []tk.M{
				tk.M{"dateinfo.dateid": tk.M{"$gte": lastupdate}},
				tk.M{"projectname": projectname},
				tk.M{"type": "MET"},
			},
		}},
		tk.M{"$group": tk.M{
			"_id": tk.M{
				"projectname":  "$projectname",
				"windspeedbin": "$windspeedbin",
				"timestamp":    "$dateinfo.dateid",
			},
			"windspeedtotal":    tk.M{"$sum": "$windspeed"},
			"windspeedstdtotal": tk.M{"$sum": "$windspeedstddev"},
			"windspeedcount":    tk.M{"$sum": countWS},
			"windspeedstdcount": tk.M{"$sum": countWSStd},
		}},
	}

	turbulenceData := []tk.M{}
	csr, e := ev.Ctx.Connection.NewQuery().
		From("TurbulenceIntensity10Min").
		Command("pipe", pipe).Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor : %s", e.Error()), sError)
	}
	defer csr.Close()

	e = csr.Fetch(&turbulenceData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on Fetch : %s", e.Error()), sError)
	}

	var wg sync.WaitGroup
	totalData := len(turbulenceData)
	totalWorker := 4
	dataChan := make(chan TurbulenceIntensity, totalData)

	wg.Add(totalWorker)
	for i := 0; i < totalWorker; i++ {
		go func() {
			defer wg.Done()
			ctxWorker, e := PrepareConnection()
			if e != nil {
				ev.Log.AddLog(e.Error(), sError)
			}
			defer ctxWorker.Close()
			csrSave := ctxWorker.NewQuery().SetConfig("multiexec", true).
				From(new(TurbulenceIntensity).TableName()).Save()
			defer csrSave.Close()
			for data := range dataChan {
				e = csrSave.Exec(tk.M{"data": data})
				if e != nil {
					ev.Log.AddLog(tk.Sprintf("Error on Save : %s", e.Error()), sError)
				}
			}
		}()
	}

	data := TurbulenceIntensity{}
	maxTimeStamp := time.Time{}

	for _, _data := range turbulenceData {
		data = TurbulenceIntensity{}
		ids := _data.Get("_id", tk.M{}).(tk.M)
		data.Projectname = ids.GetString("projectname")
		data.Timestamp = ids.Get("timestamp", time.Time{}).(time.Time).UTC()
		data.WindspeedBin = ids.GetFloat64("windspeedbin")
		data.ID = tk.Sprintf("%s_%s_%s", data.Projectname, tk.Sprintf("%.1f", data.WindspeedBin), data.Timestamp.Format("20060102"))

		data.WindSpeedTotal = _data.GetFloat64("windspeedtotal")
		data.WindSpeedStdTotal = _data.GetFloat64("windspeedstdtotal")
		data.WindSpeedCount = _data.GetFloat64("windspeedcount")
		data.WindSpeedStdCount = _data.GetFloat64("windspeedstdcount")
		data.Type = "MET"

		if data.Timestamp.After(maxTimeStamp) {
			maxTimeStamp = data.Timestamp
		}

		dataChan <- data
	}

	close(dataChan)
	wg.Wait()

	ev.updateLastData(projectname, "MET", maxTimeStamp)
}

func (ev *TurbulenceIntensitySummary) processDataMet(wgMet *sync.WaitGroup) {
	defer wgMet.Done()

	t0 := time.Now()

	projectList := ev.getProjectList()
	lastUpdatePerProject := ev.getLatestData("MET")

	var wg sync.WaitGroup
	wg.Add(len(projectList))
	for _, _project := range projectList {
		go ev.projectWorkerMet(_project, lastUpdatePerProject[_project], &wg)
	}
	wg.Wait()

	ev.Log.AddLog(tk.Sprintf("Duration process met tower data %f minutes", time.Since(t0).Minutes()), sInfo)
}
<commit_msg>adding condition for windspeed<commit_after>package generatorControllers

import (
	. "eaciit/wfdemo-git/processapp/summaryGenerator/controllers"
	"github.com/eaciit/dbox"
	_ "github.com/eaciit/dbox/dbc/mongo"
	tk "github.com/eaciit/toolkit"
	"sync"
	"time"
)

type TurbulenceIntensitySummary struct {
	*BaseController
}

type TurbulenceIntensity struct {
	ID                string ` bson:"_id" , json:"_id" `
	Projectname       string
	Turbine           string
	Timestamp         time.Time
	WindspeedBin      float64
	WindSpeedTotal    float64
	WindSpeedStdTotal float64
	WindSpeedCount    float64
	WindSpeedStdCount float64
	Type              string
}

func (m *TurbulenceIntensity) TableName() string {
	return "rpt_turbulenceintensity"
}

type LatestTurbulence struct {
	ID          string ` bson:"_id" , json:"_id" `
	Projectname string
	LastUpdate  time.Time
	Type        string
}

func (m *LatestTurbulence) TableName() string {
	return "log_latestturbulence"
}

func (ev *TurbulenceIntensitySummary) CreateTurbulenceIntensitySummary(base *BaseController) {
	ev.BaseController = base

	ev.Log.AddLog("===================== Start processing Turbulence Intensity Summary...", sInfo)

	var wg sync.WaitGroup
	wg.Add(2)

	go ev.processDataScada(&wg)
	go ev.processDataMet(&wg)

	wg.Wait()

	ev.Log.AddLog("===================== End processing Turbulence Intensity Summary...", sInfo)
}

func (ev *TurbulenceIntensitySummary) getProjectList() (result []string) {
	ev.Log.AddLog("Get Project List", sInfo)

	projectData := []tk.M{}
	csrt, e := ev.Ctx.Connection.NewQuery().
		From("ref_project").Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor at getProjectList due to : %s", e.Error()), sError)
		return
	}
	defer csrt.Close()
	e = csrt.Fetch(&projectData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on fetch at getProjectList due to : %s", e.Error()), sError)
		return
	}
	result = []string{}
	for _, val := range projectData {
		result = append(result, val.GetString("projectid"))
	}
	ev.Log.AddLog("Finish getting Project List", sInfo)

	return
}

func (ev *TurbulenceIntensitySummary) getLatestData(tipe string) (result map[string]time.Time) {
	ev.Log.AddLog("Get latest data for each turbine", sInfo)

	latestData := []LatestTurbulence{}
	csrt, e := ev.Ctx.Connection.NewQuery().
		From(new(LatestTurbulence).TableName()).
		Where(dbox.Eq("type", tipe)).Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor at getLatestData due to : %s", e.Error()), sError)
		return
	}
	defer csrt.Close()
	e = csrt.Fetch(&latestData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on fetch at getLatestData due to : %s", e.Error()), sError)
		return
	}
	result = map[string]time.Time{}
	for _, val := range latestData {
		result[val.Projectname] = val.LastUpdate
	}
	ev.Log.AddLog("Finish getting latest data for each turbine", sInfo)

	return
}

func (ev *TurbulenceIntensitySummary) updateLastData(projectname, tipe string, maxTimeStamp time.Time) {
	if !maxTimeStamp.IsZero() {
		data := LatestTurbulence{}
		data.Projectname = projectname
		data.ID = tk.Sprintf("%s_%s", data.Projectname, tipe)
		data.LastUpdate = maxTimeStamp
		data.Type = tipe

		e := ev.Ctx.Connection.NewQuery().SetConfig("multiexec", true).
			From(new(LatestTurbulence).TableName()).Save().Exec(tk.M{"data": data})

		if e != nil {
			ev.Log.AddLog(tk.Sprintf("Error on Save at updateLastData due to : %s", e.Error()), sError)
		}
	}
	ev.Log.AddLog(tk.Sprintf("Finish updating last data for %s on %s at %s", projectname, tipe, maxTimeStamp.String()), sInfo)
}

func (ev *TurbulenceIntensitySummary) processDataScada(wgScada *sync.WaitGroup) {
	defer wgScada.Done()

	t0 := time.Now()
	projectList := ev.getProjectList()
	lastUpdatePerProject := ev.getLatestData("SCADA")

	var wg sync.WaitGroup
	wg.Add(len(projectList))
	for _, _project := range projectList {
		go ev.projectWorker(_project, lastUpdatePerProject[_project], &wg)
	}
	wg.Wait()

	ev.Log.AddLog(tk.Sprintf("Duration processing scada data %f minutes", time.Since(t0).Minutes()), sInfo)
}

func (ev *TurbulenceIntensitySummary) projectWorker(projectname string, lastUpdate time.Time, wgProject *sync.WaitGroup) {
	defer wgProject.Done()

	countWS := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeed", false}},
				tk.M{"$gte": []interface{}{"$windspeed", -200}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}
	countWSStd := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeedstddev", false}},
				tk.M{"$gte": []interface{}{"$windspeedstddev", -200}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}

	ev.Log.AddLog(tk.Sprintf("Update data %s from %s", projectname, lastUpdate.String()), sInfo)
	pipe := []tk.M{
		tk.M{"$match": tk.M{
			"$and": []tk.M{
				tk.M{"dateinfo.dateid": tk.M{"$gte": lastUpdate}},
				tk.M{"projectname": projectname},
				tk.M{"type": "SCADA"},
			},
		}},
		tk.M{"$group": tk.M{
			"_id": tk.M{
				"projectname":  "$projectname",
				"turbine":      "$turbine",
				"windspeedbin": "$windspeedbin",
				"timestamp":    "$dateinfo.dateid",
			},
			"windspeedtotal":    tk.M{"$sum": "$windspeed"},
			"windspeedstdtotal": tk.M{"$sum": "$windspeedstddev"},
			"windspeedcount":    tk.M{"$sum": countWS},
			"windspeedstdcount": tk.M{"$sum": countWSStd},
		}},
	}

	csr, e := ev.Ctx.Connection.NewQuery().
		From("TurbulenceIntensity10Min").
		Command("pipe", pipe).Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor : %s", e.Error()), sError)
	}
	defer csr.Close()

	turbulenceData := []tk.M{}
	e = csr.Fetch(&turbulenceData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on fetch : %s", e.Error()), sError)
	}

	var wg sync.WaitGroup
	totalData := len(turbulenceData)
	totalWorker := 4
	dataChan := make(chan TurbulenceIntensity, totalData)

	wg.Add(totalWorker)
	for i := 0; i < totalWorker; i++ {
		go func() {
			defer wg.Done()
			ctxWorker, e := PrepareConnection()
			if e != nil {
				ev.Log.AddLog(e.Error(), sError)
			}
			defer ctxWorker.Close()
			csrSave := ctxWorker.NewQuery().SetConfig("multiexec", true).
				From(new(TurbulenceIntensity).TableName()).Save()
			defer csrSave.Close()
			for data := range dataChan {
				e = csrSave.Exec(tk.M{"data": data})
				if e != nil {
					ev.Log.AddLog(tk.Sprintf("Error on Save : %s", e.Error()), sError)
				}
			}
		}()
	}

	data := TurbulenceIntensity{}
	maxTimeStamp := time.Time{}

	for _, _data := range turbulenceData {
		data = TurbulenceIntensity{}
		ids := _data.Get("_id", tk.M{}).(tk.M)
		data.Projectname = ids.GetString("projectname")
		data.Turbine = ids.GetString("turbine")
		data.Timestamp = ids.Get("timestamp", time.Time{}).(time.Time).UTC()
		data.WindspeedBin = ids.GetFloat64("windspeedbin")
		data.ID = tk.Sprintf("%s_%s_%s_%s", data.Projectname, data.Turbine, tk.Sprintf("%.1f", data.WindspeedBin), data.Timestamp.Format("20060102"))

		data.WindSpeedTotal = _data.GetFloat64("windspeedtotal")
		data.WindSpeedStdTotal = _data.GetFloat64("windspeedstdtotal")
		data.WindSpeedCount = _data.GetFloat64("windspeedcount")
		data.WindSpeedStdCount = _data.GetFloat64("windspeedstdcount")
		data.Type = "SCADA"

		if data.Timestamp.After(maxTimeStamp) {
			maxTimeStamp = data.Timestamp
		}

		dataChan <- data
	}

	close(dataChan)
	wg.Wait()

	ev.updateLastData(projectname, "SCADA", maxTimeStamp)
}

func (ev *TurbulenceIntensitySummary) projectWorkerMet(projectname string, lastupdate time.Time, wgProject *sync.WaitGroup) {
	defer wgProject.Done()

	countWS := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeed", false}},
				tk.M{"$gte": []interface{}{"$windspeed", -200}},
				tk.M{"$lte": []interface{}{"$windspeed", 100}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}
	countWSStd := tk.M{"$cond": tk.M{}.
		Set("if", tk.M{
			"$and": []tk.M{
				tk.M{"$ifNull": []interface{}{"$windspeedstddev", false}},
				tk.M{"$gte": []interface{}{"$windspeedstddev", -200}},
				tk.M{"$lte": []interface{}{"$windspeedstddev", 100}},
			},
		}).
		Set("then", 1).
		Set("else", 0)}
	pipe := []tk.M{
		tk.M{"$match": tk.M{
			"$and": []tk.M{
				tk.M{"dateinfo.dateid": tk.M{"$gte": lastupdate}},
				tk.M{"projectname": projectname},
				tk.M{"type": "MET"},
			},
		}},
		tk.M{"$group": tk.M{
			"_id": tk.M{
				"projectname":  "$projectname",
				"windspeedbin": "$windspeedbin",
				"timestamp":    "$dateinfo.dateid",
			},
			"windspeedtotal":    tk.M{"$sum": "$windspeed"},
			"windspeedstdtotal": tk.M{"$sum": "$windspeedstddev"},
			"windspeedcount":    tk.M{"$sum": countWS},
			"windspeedstdcount": tk.M{"$sum": countWSStd},
		}},
	}

	turbulenceData := []tk.M{}
	csr, e := ev.Ctx.Connection.NewQuery().
		From("TurbulenceIntensity10Min").
		Command("pipe", pipe).Cursor(nil)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on cursor : %s", e.Error()), sError)
	}
	defer csr.Close()

	e = csr.Fetch(&turbulenceData, 0, false)
	if e != nil {
		ev.Log.AddLog(tk.Sprintf("Error on Fetch : %s", e.Error()), sError)
	}

	var wg sync.WaitGroup
	totalData := len(turbulenceData)
	totalWorker := 4
	dataChan := make(chan TurbulenceIntensity, totalData)

	wg.Add(totalWorker)
	for i := 0; i < totalWorker; i++ {
		go func() {
			defer wg.Done()
			ctxWorker, e := PrepareConnection()
			if e != nil {
				ev.Log.AddLog(e.Error(), sError)
			}
			defer ctxWorker.Close()
			csrSave := ctxWorker.NewQuery().SetConfig("multiexec", true).
				From(new(TurbulenceIntensity).TableName()).Save()
			defer csrSave.Close()
			for data := range dataChan {
				e = csrSave.Exec(tk.M{"data": data})
				if e != nil {
					ev.Log.AddLog(tk.Sprintf("Error on Save : %s", e.Error()), sError)
				}
			}
		}()
	}

	data := TurbulenceIntensity{}
	maxTimeStamp := time.Time{}

	for _, _data := range turbulenceData {
		data = TurbulenceIntensity{}
		ids := _data.Get("_id", tk.M{}).(tk.M)
		data.Projectname = ids.GetString("projectname")
		data.Timestamp = ids.Get("timestamp", time.Time{}).(time.Time).UTC()
		data.WindspeedBin = ids.GetFloat64("windspeedbin")
		data.ID = tk.Sprintf("%s_%s_%s", data.Projectname, tk.Sprintf("%.1f", data.WindspeedBin), data.Timestamp.Format("20060102"))

		data.WindSpeedTotal = _data.GetFloat64("windspeedtotal")
		data.WindSpeedStdTotal = _data.GetFloat64("windspeedstdtotal")
		data.WindSpeedCount = _data.GetFloat64("windspeedcount")
		data.WindSpeedStdCount = _data.GetFloat64("windspeedstdcount")
		data.Type = "MET"

		if data.Timestamp.After(maxTimeStamp) {
			maxTimeStamp = data.Timestamp
		}

		dataChan <- data
	}

	close(dataChan)
	wg.Wait()

	ev.updateLastData(projectname, "MET", maxTimeStamp)
}

func (ev *TurbulenceIntensitySummary) processDataMet(wgMet *sync.WaitGroup) {
	defer wgMet.Done()

	t0 := time.Now()

	projectList := ev.getProjectList()
	lastUpdatePerProject := ev.getLatestData("MET")

	var wg sync.WaitGroup
	wg.Add(len(projectList))
	for _, _project := range projectList {
		go ev.projectWorkerMet(_project, lastUpdatePerProject[_project], &wg)
	}
	wg.Wait()

	ev.Log.AddLog(tk.Sprintf("Duration process met tower data %f minutes", time.Since(t0).Minutes()), sInfo)
}
<|endoftext|>


<commit_before>package provider

import (
	"koding/kites/kloud/stack"
	"koding/kites/kloud/terraformer"
	tf "koding/kites/terraformer"

	"golang.org/x/net/context"
)

func (bs *BaseStack) HandlePlan(ctx context.Context) (interface{}, error) {
	arg, ok := ctx.Value(stack.PlanRequestKey).(*stack.PlanRequest)
	if !ok {
		arg = &stack.PlanRequest{}

		if err := bs.Req.Args.One().Unmarshal(arg); err != nil {
			return nil, err
		}
	}

	if err := arg.Valid(); err != nil {
		return nil, err
	}

	bs.Arg = arg

	bs.Log.Debug("Fetching template for id %s", arg.StackTemplateID)

	if err := bs.Builder.BuildStackTemplate(arg.StackTemplateID); err != nil {
		return nil, err
	}

	bs.Log.Debug("Fetching credentials for id %v", bs.Builder.StackTemplate.Credentials)

	credIDs := FlattenValues(bs.Builder.StackTemplate.Credentials)

	if err := bs.Builder.BuildCredentials(bs.Req.Method, bs.Req.Username, arg.GroupName, credIDs); err != nil {
		return nil, err
	}

	bs.Log.Debug("Fetched terraform data: koding=%+v, template=%+v", bs.Builder.Koding, bs.Builder.Template)

	contentID := bs.Req.Username + "-" + arg.StackTemplateID

	bs.Log.Debug("Parsing template (%s):\n%s", contentID, bs.Builder.StackTemplate.Template.Content)

	if err := bs.Builder.BuildTemplate(bs.Builder.StackTemplate.Template.Content, contentID); err != nil {
		return nil, err
	}

	if cred, err := bs.Builder.CredentialByProvider(bs.Provider.Name); err == nil {
		if _, err := bs.stack.ApplyTemplate(cred); err != nil {
			return nil, err
		}
	} else {
		bs.Log.Debug("no credentials found for %q: %s", bs.Provider.Name, err)

		if err := bs.Builder.Template.FillVariables(bs.Provider.Name + "_"); err != nil {
			return nil, err
		}
	}

	// Plan request is made right away the template is saved, it may
	// not have all the credentials provided yet. We set them all to
	// to dummy values to make the template pass terraform parsing.
	if err := bs.Builder.Template.FillVariables("userInput_"); err != nil {
		return nil, err
	}

	machines, err := bs.plan()
	if err != nil {
		return nil, err
	}

	bs.Log.Debug("Machines planned to be created: %+v", machines)

	return &stack.PlanResponse{
		Machines: machines.Slice(),
	}, nil
}

func (bs *BaseStack) Plan() (stack.Machines, error) {
	out, err := bs.Builder.Template.JsonOutput()
	if err != nil {
		return nil, err
	}

	tfKite, err := terraformer.Connect(bs.Session.Terraformer)
	if err != nil {
		return nil, err
	}
	defer tfKite.Close()

	tfReq := &tf.TerraformRequest{
		Content:   out,
		ContentID: bs.Req.Username + "-" + bs.Arg.(*stack.PlanRequest).StackTemplateID,
		TraceID:   bs.TraceID,
	}

	bs.Log.Debug("Calling plan with content: %+v", tfReq)

	plan, err := tfKite.Plan(tfReq)
	if err != nil {
		return nil, err
	}

	return bs.Planner.MachinesFromPlan(plan)
}
<commit_msg>stack: require a credential for plan method<commit_after>package provider

import (
	"koding/kites/kloud/stack"
	"koding/kites/kloud/terraformer"
	tf "koding/kites/terraformer"
	"koding/tools/util"

	"golang.org/x/net/context"
)

func (bs *BaseStack) HandlePlan(ctx context.Context) (interface{}, error) {
	arg, ok := ctx.Value(stack.PlanRequestKey).(*stack.PlanRequest)
	if !ok {
		arg = &stack.PlanRequest{}

		if err := bs.Req.Args.One().Unmarshal(arg); err != nil {
			return nil, err
		}
	}

	if err := arg.Valid(); err != nil {
		return nil, err
	}

	bs.Arg = arg

	bs.Log.Debug("Fetching template for id %s", arg.StackTemplateID)

	if err := bs.Builder.BuildStackTemplate(arg.StackTemplateID); err != nil {
		return nil, err
	}

	bs.Log.Debug("Fetching credentials for id %v", bs.Builder.StackTemplate.Credentials)

	credIDs := FlattenValues(bs.Builder.StackTemplate.Credentials)

	if err := bs.Builder.BuildCredentials(bs.Req.Method, bs.Req.Username, arg.GroupName, credIDs); err != nil {
		return nil, err
	}

	bs.Log.Debug("Fetched terraform data: koding=%+v, template=%+v", bs.Builder.Koding, bs.Builder.Template)

	contentID := bs.Req.Username + "-" + arg.StackTemplateID

	bs.Log.Debug("Stack template before plan: %s", contentID, util.PrettyJSON(bs.Builder.StackTemplate.Template.Content))

	if err := bs.Builder.BuildTemplate(bs.Builder.StackTemplate.Template.Content, contentID); err != nil {
		return nil, err
	}

	cred, err := bs.Builder.CredentialByProvider(bs.Provider.Name)
	if err != nil {
		return nil, err
	}

	t, err := bs.stack.ApplyTemplate(cred)
	if err != nil {
		return nil, err
	}

	bs.Log.Debug("Stack template after injecting Koding data: %s", t)

	// Plan request is made right away the template is saved, it may
	// not have all the credentials provided yet. We set them all to
	// to dummy values to make the template pass terraform parsing.
	if err := bs.Builder.Template.FillVariables("userInput_"); err != nil {
		return nil, err
	}

	machines, err := bs.plan()
	if err != nil {
		return nil, err
	}

	bs.Log.Debug("Machines planned to be created: %+v", machines)

	return &stack.PlanResponse{
		Machines: machines.Slice(),
	}, nil
}

func (bs *BaseStack) Plan() (stack.Machines, error) {
	out, err := bs.Builder.Template.JsonOutput()
	if err != nil {
		return nil, err
	}

	tfKite, err := terraformer.Connect(bs.Session.Terraformer)
	if err != nil {
		return nil, err
	}
	defer tfKite.Close()

	tfReq := &tf.TerraformRequest{
		Content:   out,
		ContentID: bs.Req.Username + "-" + bs.Arg.(*stack.PlanRequest).StackTemplateID,
		TraceID:   bs.TraceID,
	}

	bs.Log.Debug("Calling plan with content: %+v", tfReq)

	plan, err := tfKite.Plan(tfReq)
	if err != nil {
		return nil, err
	}

	return bs.Planner.MachinesFromPlan(plan)
}
<|endoftext|>


<commit_before>package TGBotApi

type Update struct {
	UpdateId          int     `json:"update_id"`
	Message           Message `json:"message, omitempty"`
	EditedMessage     Message `json:"edited_message, omitempty"`
	ChannelPost       Message `json:"channel_post, omitempty"`
	EditedChannelPost Message `json:"edited_channel_post, omitempty"`
}

type Message struct {
	MessageId int             `json:"message_id"`
	From      User            `json:"from, omitempty"`
	Date      int             `json:"date"`
	Chat      Chat            `json:"chat"`
	Text      string          `json:"text"`
	Entities  []MessageEntity `json:"entities,omitempty"`
	Photo     []PhotoSize     `json:"photo, omitempty"`
}

type MessageEntity struct {
	Type   string `json:"type"`
	Offset int    `json:"offset"`
	Length int    `json:"length"`
}

type PhotoSize struct {
	FileId   string `json:"file_id"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	FileSize int    `json:"file_size, omitempty"`
}

type User struct {
	Id           int `json:"id"`
	FirstName    string `json:"first_name"`
	LastName     string `json:"last_name,omitempty"`
	UserName     string `json:"user_name, omitempty"`
	LanguageCode int `json:"language_code, omitempty"`
}

type Chat struct {
	Id                          int64     `json:"id"`
	Type                        string    `json:"type"`
	Title                       string    `json:"title, omitempty"`
	Username                    string    `json:"username, omitempty"`
	FirstName                   string    `json:"first_name, omitempty"`
	LastName                    string    `json:"last_name, omitempty"`
	AllMembersAreAdministrators bool      `json:"all_members_are_administrators, omitempty"`
	Photo                       ChatPhoto `json:"photo, omitempty"`
	Description                 string    `json:"description, omitempty"`
	InviteLink                  string    `json:"invite_link, omitempty"`
}

type ChatPhoto struct {
	SmallFileId string `json:"small_file_id, omitempty"`
	BigFileId   string `json:"big_file_id, omitempty"`
}

type File struct {
	FileId   string `json:"file_id"`
	FileSize int    `json:"file_size, omitempty"`
	FilePath string `json:"file_path, omitempty"`
}
<commit_msg>quickfix<commit_after>package TGBotApi

type Update struct {
	UpdateId          int     `json:"update_id"`
	Message           Message `json:"message, omitempty"`
	EditedMessage     Message `json:"edited_message, omitempty"`
	ChannelPost       Message `json:"channel_post, omitempty"`
	EditedChannelPost Message `json:"edited_channel_post, omitempty"`
}

type Message struct {
	MessageId int             `json:"message_id"`
	From      User            `json:"from, omitempty"`
	Date      int             `json:"date"`
	Chat      Chat            `json:"chat"`
	Text      string          `json:"text"`
	Entities  []MessageEntity `json:"entities,omitempty"`
	Photo     []PhotoSize     `json:"photo, omitempty"`
}

type MessageEntity struct {
	Type   string `json:"type"`
	Offset int    `json:"offset"`
	Length int    `json:"length"`
}

type PhotoSize struct {
	FileId   string `json:"file_id"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	FileSize int    `json:"file_size, omitempty"`
}

type User struct {
	Id           int `json:"id"`
	FirstName    string `json:"first_name"`
	LastName     string `json:"last_name,omitempty"`
	UserName     string `json:"user_name, omitempty"`
	LanguageCode string `json:"language_code, omitempty"`
}

type Chat struct {
	Id                          int64     `json:"id"`
	Type                        string    `json:"type"`
	Title                       string    `json:"title, omitempty"`
	Username                    string    `json:"username, omitempty"`
	FirstName                   string    `json:"first_name, omitempty"`
	LastName                    string    `json:"last_name, omitempty"`
	AllMembersAreAdministrators bool      `json:"all_members_are_administrators, omitempty"`
	Photo                       ChatPhoto `json:"photo, omitempty"`
	Description                 string    `json:"description, omitempty"`
	InviteLink                  string    `json:"invite_link, omitempty"`
}

type ChatPhoto struct {
	SmallFileId string `json:"small_file_id, omitempty"`
	BigFileId   string `json:"big_file_id, omitempty"`
}

type File struct {
	FileId   string `json:"file_id"`
	FileSize int    `json:"file_size, omitempty"`
	FilePath string `json:"file_path, omitempty"`
}
<|endoftext|>


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

// Package signals exposes signal handler.
package signals

import (
	"os"
	"os/signal"
	"runtime/debug"
	"syscall"
	"time"

	"github.com/kris-nova/kubicorn/cutil/logger"
)

const (
	// signalAbort is used to gracefully exit program.
	signalAbort = 1 << iota
	// signalTerminate is used to terminate program.
	signalTerminate
)

// Signal is an interface that implements signal handling.
type Signal interface {
	GetState() int
	Register()
}

// Handler defines signal handler properties.
type Handler struct {

	// todo (@xmudrii) Can we move these to package level vars instead of in the Handler{}

	// timeoutSeconds defines when handler will timeout in seconds.
	timeoutSeconds int
	// signals stores signals recieved from the system.
	signals chan os.Signal
	// signalReceived is used to store signal handler state.
	signalReceived int
	// Timer to handle timeout correctly
	timer *time.Timer
}

// NewSignalHandler creates a new Handler using given properties.
func NewSignalHandler(timeoutSeconds int) *Handler {
	signals := make(chan os.Signal)
	signal.Notify(signals, os.Interrupt, os.Kill)
	return &Handler{
		timeoutSeconds: timeoutSeconds,
		signals:        signals,
		signalReceived: 0,
	}
}

// GetState returns has signal been recieved.
func (h *Handler) GetState() int {
	return h.signalReceived
}

func (h *Handler) Reset() {
	if !h.timer.Stop() {
		<-h.timer.C
	}
}

// Register starts handling signals.
func (h *Handler) Register() {
	go func() {
		h.timer = time.NewTimer(time.Duration(h.timeoutSeconds) * time.Second)
		for {
			select {
			case s := <-h.signals:
				switch {
				case s == os.Interrupt:
					if h.signalReceived == 0 {
						h.signalReceived = 1
						logger.Debug("SIGINT Received")
						continue
					}
					h.signalReceived = signalTerminate
					debug.PrintStack()
					os.Exit(130)
					break
				case s == syscall.SIGQUIT:
					h.signalReceived = signalAbort
					break
				case s == syscall.SIGTERM:
					h.signalReceived = signalTerminate
					os.Exit(3)
					break
				}
			case <-h.timer.C:
				os.Exit(4)
				break
			}
		}

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

// Package signals exposes signal handler.
package signals

import (
	"os"
	"os/signal"
	"runtime/debug"
	"syscall"
	"time"

	"github.com/kris-nova/kubicorn/cutil/logger"
)

const (
	// signalAbort is used to gracefully exit program.
	signalAbort = 1 << iota
	// signalTerminate is used to terminate program.
	signalTerminate
)

// Signal is an interface that implements signal handling.
type Signal interface {
	GetState() int
	Register()
}

// Handler defines signal handler properties.
type Handler struct {

	// todo (@xmudrii) Can we move these to package level vars instead of in the Handler{}

	// timeoutSeconds defines when handler will timeout in seconds.
	timeoutSeconds int
	// signals stores signals recieved from the system.
	signals chan os.Signal
	// signalReceived is used to store signal handler state.
	signalReceived int
	// Timer to handle timeout correctly
	timer *time.Timer
}

// NewSignalHandler creates a new Handler using given properties.
func NewSignalHandler(timeoutSeconds int) *Handler {
	signals := make(chan os.Signal)
	signal.Notify(signals, os.Interrupt, os.Kill)
	return &Handler{
		timeoutSeconds: timeoutSeconds,
		signals:        signals,
		signalReceived: 0,
	}
}

// GetState returns has signal been recieved.
func (h *Handler) GetState() int {
	return h.signalReceived
}

func (h *Handler) Reset() {
	h.timer.Stop()
}

// Register starts handling signals.
func (h *Handler) Register() {
	go func() {
		h.timer = time.NewTimer(time.Duration(h.timeoutSeconds) * time.Second)
		for {
			select {
			case s := <-h.signals:
				switch {
				case s == os.Interrupt:
					if h.signalReceived == 0 {
						h.signalReceived = 1
						logger.Debug("SIGINT Received")
						continue
					}
					h.signalReceived = signalTerminate
					debug.PrintStack()
					os.Exit(130)
					break
				case s == syscall.SIGQUIT:
					h.signalReceived = signalAbort
					break
				case s == syscall.SIGTERM:
					h.signalReceived = signalTerminate
					os.Exit(3)
					break
				}
			case <-h.timer.C:
				os.Exit(4)
				break
			}
		}

	}()
}
<|endoftext|>