<commit_before>/* Code based on project https://github.com/heroku/force
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type ConfigRecord map[string]interface{}

func Defaults(configurationType string) (defaults ConfigRecord, err error) {

	server, session := getServerAndSession()

	body, err := httpGet(server + "/icws/" + session + "/configuration/defaults/" + configurationType)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &defaults)
	return

}

func Get(configurationType, id, properties string) (defaults ConfigRecord, err error) {

	server, session := getServerAndSession()

	if !strings.HasSuffix(configurationType, "s") {
		configurationType += "s"
	}

	body, err := httpGet(server + "/icws/" + session + "/configuration/" + configurationType + "/" + id + "?select=" + properties)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &defaults)
	return

}

func GetStatus(userId string) (defaults ConfigRecord, err error) {

	server, session := getServerAndSession()

	body, err := httpGet(server + "/icws/" + session + "/status/user-statuses/" + userId)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &defaults)
	return

}

func SetStatus(userId, statusKey string) (err error) {

	server, session := getServerAndSession()

	var statusData = map[string]string{
		"statusId": statusKey,
	}
	_, err = httpPut(server+"/icws/"+session+"/status/user-statuses/"+userId, statusData)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	return

}

func GetVersion() (version ConfigRecord, err error) {

	server, err := Config.Load("current", "server")
	if err != nil {
		ErrorAndExit(err.Error())
	}

	body, err := httpGet(server + "/icws/connection/version")

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &version)

	return

}

func GetFeatures() (features []string, err error) {

	server, err := Config.Load("current", "server")
	if err != nil {
		ErrorAndExit(err.Error())
	}

	body, err := httpGet(server + "/icws/connection/features")

	if err != nil {
		ErrorAndExit(err.Error())
	}

	var featureMap map[string][]map[string]interface{}
	err = json.Unmarshal(body, &featureMap)

	features = make([]string, len(featureMap["featureInfoList"]))

	i := 0
	for _, value := range featureMap["featureInfoList"] {
		features[i] = fmt.Sprintf("%v", value["featureId"])
		i++
	}

	return

}

func Select(objectType, selectFields, where string) (records []ConfigRecord, err error) {

	if !strings.HasSuffix(objectType, "s") {
		objectType += "s"
	}

	server, session := getServerAndSession()

	var selectString string
	if selectFields == "*" {
		selectString = ""
	} else {
		selectString = "select=" + selectFields
	}

	var whereString string
	if len(where) == 0 {
		whereString = ""
	} else {
		whereString = "&where=" + where
	}

	body, err := httpGet(server + "/icws/" + session + "/configuration/" + objectType + "?" + selectString + whereString)
	if err != nil {
		return
	}

	var result map[string][]ConfigRecord
	err = json.Unmarshal(body, &result)

	records = result["items"]
	return

}

func Whoami() (me ConfigRecord, err error) {

	server, session := getServerAndSession()

	username, err := Config.Load("current", "username")
	if err != nil {
		return
	}

	body, err := httpGet(server + "/icws/" + session + "/configuration/users/" + username + "?select=extension,defaultWorkstation,statusText,roles,skills,workgroups")

	if err != nil {
		return
	}

	err = json.Unmarshal(body, &me)
	return

}

func MakeCall(target string) (result ConfigRecord, err error) {

	server, session := getServerAndSession()

	var callData = map[string]string{
		"__type": "urn:inin.com:interactions:createCallParameters",
		"target": target,
	}
	body, err, _ := httpPost(server+"/icws/"+session+"/interactions", callData)

	if err != nil {
		return
	}

	err = json.Unmarshal(body, &result)
	return

}

func InteractionAction(action, interactionId, attribute string) (result ConfigRecord, err error) {

	server, session := getServerAndSession()
	var body []byte
	if action == "get" {
		body, err = httpGet(server + "/icws/" + session + "/interactions/" + interactionId + "?select=" + attribute)

		if err != nil {
			return
		}

		err = json.Unmarshal(body, &result)

	} else if action == "set" {
		/*body, err, _ := httpPost(server + "/icws/" + session + "/interactions/" + interactionId " , callData)

		  err = json.Unmarshal(body, &result)
		*/
	} else {
		var isOn = "false"
		if attribute == "on" || attribute == "yes" || attribute == "1" {
			isOn = "true"
		}
		var callData = map[string]string{
			"on": isOn,
		}

		if len(attribute) == 0 {
			callData = nil
		}

		_, err, _ = httpPost(server+"/icws/"+session+"/interactions/"+interactionId+"/"+action, callData)

	}

	return

}

func Login(server, username, password string) (token string, session string, cookie string, err error) {

	var loginData = map[string]string{
		"__type":          "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName": "CLI",
		"userID":          username,
		"password":        password,
	}
	body, err, cookie := httpPost(server+"/icws/connection", loginData)

	if err == nil {
		var returnData map[string]string
		json.Unmarshal(body, &returnData)
		token = returnData["csrfToken"]
		session = returnData["sessionId"]
	} else {
		fmt.Println(fmt.Sprintf("ERROR: %s\n", err.Error()))
	}
	return
}

func getServerAndSession() (server, session string) {
	var err error
	server, err = Config.Load("current", "server")
	if err != nil {
		ErrorAndExit(err.Error())
	}

	session, err = Config.Load("current", "session")
	if err != nil {
		ErrorAndExit(err.Error())
	}
	return
}

func httpGet(url string) (body []byte, err error) {

	req, err := httpRequest("GET", url, nil)

	if err != nil {
		return
	}

	response, err := httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired, please run `cic login`")
		return
	}
	body, err = ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func createErrorMessage(statusCode int, body []byte) string {

	var errorDescription string

	switch statusCode {
	case 400:
		errorDescription = "Bad Request (400)"
	case 401:
		errorDescription = "Unauthorized (401)"
	case 403:
		errorDescription = "Forbidden (403)"
	case 404:
		errorDescription = "Not Found (404)"
	case 410:
		errorDescription = "Gone (410)"
	case 500:
		errorDescription = "Internal Server Error (500)"
	}

	var message map[string]string
	json.Unmarshal(body, &message)

	return errorDescription + ": " + message["errorId"] + " " + message["message"]
}

func httpPost(url string, attrs map[string]string) (body []byte, err error, cookie string) {

	rbody, _ := json.Marshal(attrs)
	req, err := httpRequest("POST", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired, please run `cic login`")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	if response.Header["Set-Cookie"] != nil {
		cookie = response.Header["Set-Cookie"][0]
	}
	return
}

func httpPut(url string, attrs map[string]string) (body []byte, err error) {

	rbody, _ := json.Marshal(attrs)
	req, err := httpRequest("PUT", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired, please run `cic login`")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func httpClient() (client *http.Client) {

	client = &http.Client{}
	return
}

func httpRequest(method, url string, body io.Reader) (request *http.Request, err error) {
	request, err = http.NewRequest(method, url, body)
	if err != nil {
		return
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept-Language", "en-us")

	cookie, configerr := Config.Load("current", "cookie")
	if configerr == nil {
		request.Header.Add("Cookie", cookie)
	} else {
		return
	}

	token, configerr := Config.Load("current", "token")

	if configerr == nil {
		request.Header.Add("ININ-ICWS-CSRF-Token", token)
	} else {
		return
	}

	// request.Header.Add("User-Agent", fmt.Sprintf("cic cli (%s-%s)", runtime.GOOS, runtime.GOARCH))
	return
}
<commit_msg>bug fixes<commit_after>/* Code based on project https://github.com/heroku/force
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type ConfigRecord map[string]interface{}

func Defaults(configurationType string) (defaults ConfigRecord, err error) {

	server, session := getServerAndSession()

	body, err := httpGet(server + "/icws/" + session + "/configuration/defaults/" + configurationType)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &defaults)
	return

}

func Get(configurationType, id, properties string) (defaults ConfigRecord, err error) {

	server, session := getServerAndSession()

	if !strings.HasSuffix(configurationType, "s") {
		configurationType += "s"
	}

	body, err := httpGet(server + "/icws/" + session + "/configuration/" + configurationType + "/" + id + "?select=" + properties)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &defaults)
	return

}

func GetStatus(userId string) (defaults ConfigRecord, err error) {

	server, session := getServerAndSession()

	body, err := httpGet(server + "/icws/" + session + "/status/user-statuses/" + userId)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &defaults)
	return

}

func SetStatus(userId, statusKey string) (err error) {

	server, session := getServerAndSession()

	var statusData = map[string]string{
		"statusId": statusKey,
	}
	_, err = httpPut(server+"/icws/"+session+"/status/user-statuses/"+userId, statusData)

	if err != nil {
		ErrorAndExit(err.Error())
	}

	return

}

func GetVersion() (version ConfigRecord, err error) {

	server, err := Config.Load("current", "server")
	if err != nil {
		ErrorAndExit(err.Error())
	}

	body, err := httpGet(server + "/icws/connection/version")

	if err != nil {
		ErrorAndExit(err.Error())
	}

	err = json.Unmarshal(body, &version)

	return

}

func GetFeatures() (features []string, err error) {

	server, err := Config.Load("current", "server")
	if err != nil {
		ErrorAndExit(err.Error())
	}

	body, err := httpGet(server + "/icws/connection/features")

	if err != nil {
		ErrorAndExit(err.Error())
	}

	var featureMap map[string][]map[string]interface{}
	err = json.Unmarshal(body, &featureMap)

	features = make([]string, len(featureMap["featureInfoList"]))

	i := 0
	for _, value := range featureMap["featureInfoList"] {
		features[i] = fmt.Sprintf("%v", value["featureId"])
		i++
	}

	return

}

func Select(objectType, selectFields, where string) (records []ConfigRecord, err error) {

	if !strings.HasSuffix(objectType, "s") {
		objectType += "s"
	}

	server, session := getServerAndSession()

	var selectString string
	if selectFields == "*" {
		selectString = ""
	} else {
		selectString = "select=" + selectFields
	}

	var whereString string
	if len(where) == 0 {
		whereString = ""
	} else {
		whereString = "&where=" + where
	}

	body, err := httpGet(server + "/icws/" + session + "/configuration/" + objectType + "?" + selectString + whereString)
	if err != nil {
		return
	}

	var result map[string][]ConfigRecord
	err = json.Unmarshal(body, &result)

	records = result["items"]
	return

}

func Whoami() (me ConfigRecord, err error) {

	server, session := getServerAndSession()

	username, err := Config.Load("current", "username")
	if err != nil {
		return
	}

	body, err := httpGet(server + "/icws/" + session + "/configuration/users/" + username + "?select=extension,defaultWorkstation,statusText,roles,skills,workgroups")

	if err != nil {
		return
	}

	err = json.Unmarshal(body, &me)
	return

}

func MakeCall(target string) (result ConfigRecord, err error) {

	server, session := getServerAndSession()

	var callData = map[string]string{
		"__type": "urn:inin.com:interactions:createCallParameters",
		"target": target,
	}
	body, err, _ := httpPost(server+"/icws/"+session+"/interactions", callData)

	if err != nil {
		return
	}

	err = json.Unmarshal(body, &result)
	return

}

func InteractionAction(action, interactionId, attribute string) (result ConfigRecord, err error) {

	server, session := getServerAndSession()
	var body []byte
	if action == "get" {
		body, err = httpGet(server + "/icws/" + session + "/interactions/" + interactionId + "?select=" + attribute)

		if err != nil {
			return
		}

		err = json.Unmarshal(body, &result)

	} else if action == "set" {
		/*body, err, _ := httpPost(server + "/icws/" + session + "/interactions/" + interactionId " , callData)

		  err = json.Unmarshal(body, &result)
		*/
	} else {
		var isOn = "false"
		if attribute == "on" || attribute == "yes" || attribute == "1" {
			isOn = "true"
		}
		var callData = map[string]string{
			"on": isOn,
		}

		if len(attribute) == 0 {
			callData = nil
		}

		_, err, _ = httpPost(server+"/icws/"+session+"/interactions/"+interactionId+"/"+action, callData)

	}

	return

}

func Login(server, username, password string) (token string, session string, cookie string, err error) {

	var loginData = map[string]string{
		"__type":          "urn:inin.com:connection:icAuthConnectionRequestSettings",
		"applicationName": "CLI",
		"userID":          username,
		"password":        password,
	}
	body, err, cookie := httpPost(server+"/icws/connection", loginData)

	if err == nil {
		var returnData map[string]string
		json.Unmarshal(body, &returnData)
		token = returnData["csrfToken"]
		session = returnData["sessionId"]
	} else {
		fmt.Println(fmt.Sprintf("ERROR: %s\n", err.Error()))
	}
	return
}

func getServerAndSession() (server, session string) {
	var err error
	server, err = Config.Load("current", "server")
	if err != nil {
		ErrorAndExit(err.Error())
	}

	session, err = Config.Load("current", "session")
	if err != nil {
		ErrorAndExit(err.Error())
	}
	return
}

func httpGet(url string) (body []byte, err error) {

	req, err := httpRequest("GET", url, nil)

	if err != nil {
		return
	}

	response, err := httpClient().Do(req)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired, please run `cic login`")
		return
	}
	body, err = ioutil.ReadAll(response.Body)
	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func createErrorMessage(statusCode int, body []byte) string {

	var errorDescription string

	switch statusCode {
	case 400:
		errorDescription = "Bad Request (400)"
	case 401:
		errorDescription = "Unauthorized (401)"
	case 403:
		errorDescription = "Forbidden (403)"
	case 404:
		errorDescription = "Not Found (404)"
	case 410:
		errorDescription = "Gone (410)"
	case 500:
		errorDescription = "Internal Server Error (500)"
	}

	var message map[string]interface{}
	json.Unmarshal(body, &message)

	return errorDescription + ": " + message["errorId"].(string) + " " + message["message"].(string)
}

func httpPost(url string, attrs map[string]string) (body []byte, err error, cookie string) {

	rbody, _ := json.Marshal(attrs)
	req, err := httpRequest("POST", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired, please run `cic login`")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	if response.Header["Set-Cookie"] != nil {
		cookie = response.Header["Set-Cookie"][0]
	}
	return
}

func httpPut(url string, attrs map[string]string) (body []byte, err error) {

	rbody, _ := json.Marshal(attrs)
	req, err := httpRequest("PUT", url, bytes.NewReader(rbody))
	if err != nil {
		return
	}

	response, err := httpClient().Do(req)
	if err != nil {
		return

	}
	defer response.Body.Close()
	if response.StatusCode == 401 {
		err = errors.New("authorization expired, please run `cic login`")
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	if response.StatusCode/100 != 2 {
		err = errors.New(createErrorMessage(response.StatusCode, body))

		return
	}

	return
}

func httpClient() (client *http.Client) {

	client = &http.Client{}
	return
}

func httpRequest(method, url string, body io.Reader) (request *http.Request, err error) {
	request, err = http.NewRequest(method, url, body)
	if err != nil {
		return
	}

	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept-Language", "en-us")

	cookie, configerr := Config.Load("current", "cookie")
	if configerr == nil {
		request.Header.Add("Cookie", cookie)
	} else {
		return
	}

	token, configerr := Config.Load("current", "token")

	if configerr == nil {
		request.Header.Add("ININ-ICWS-CSRF-Token", token)
	} else {
		return
	}

	// request.Header.Add("User-Agent", fmt.Sprintf("cic cli (%s-%s)", runtime.GOOS, runtime.GOARCH))
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
)

func (a analyser) listenredischannel(which string) chan []byte {
	pubsubcon := redis.PubSubConn{a.pool.Get()}
	pubsubcon.Subscribe(which)
	retval := make(chan []byte)

	go func() {
		for {
			switch n := pubsubcon.Receive().(type) {
			case redis.Message:
				// TODO: remove after debugging
				println(n.Channel, which, n.Data)
				if n.Channel == which {
					println("Same channel, signaling")
					retval <- n.Data
				}
			case error:
				fmt.Printf("Listining on redis channel %s failed: %v", which, n)
				return
			}
		}
	}()
	return retval
}
<commit_msg>remove debugging code<commit_after>package main

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
)

func (a analyser) listenredischannel(which string) chan []byte {
	pubsubcon := redis.PubSubConn{a.pool.Get()}
	pubsubcon.Subscribe(which)
	retval := make(chan []byte)

	go func() {
		for {
			switch n := pubsubcon.Receive().(type) {
			case redis.Message:
				if n.Channel == which {
					retval <- n.Data
				}
			case error:
				fmt.Printf("Listining on redis channel %s failed: %v", which, n)
				return
			}
		}
	}()
	return retval
}
<|endoftext|>


<commit_before>package model

// Admins is a list of admins for this Team
var Admins []Admin

// Admin is the model representing a Team admin
type Admin struct {
	ID       string
	RealName string
}
<commit_msg>Adding a function to load admins from slack<commit_after>package model

import (
	"github.com/shomali11/slacker"
	log "github.com/sirupsen/logrus"
)

// Admins is a list of admins for this Team
var Admins []Admin

// Admin is the model representing a Team admin
type Admin struct {
	ID       string
	RealName string
}

// LoadAdmins
func LoadAdmins(bot *slacker.Slacker) {
	log.Info("Loading admins...")
	users, _ := bot.Client.GetUsers()
	for _, user := range users {
		log.Debugf("%s %s isAdmin [%t]", user.ID, user.RealName, (user.IsAdmin || user.IsOwner))
		if user.IsAdmin || user.IsOwner {
			Admins = append(Admins, Admin{ID: user.ID, RealName: user.RealName})
		}
	}
	log.Infof("%d admins loaded.", len(Admins))
}
<|endoftext|>


<commit_before>package model

import (
	"bytes"
	"database/sql"
	"log"
	"net/http"
	"regexp"
	"time"

	"github.com/ViBiOh/funds/crawler"
	"github.com/ViBiOh/funds/db"
	"github.com/ViBiOh/funds/jsonHttp"
	"github.com/ViBiOh/funds/tools"
)

const refreshDelayInHours = 6

var listRequest = regexp.MustCompile(`^/list$`)
var performanceURL string
var performanceMap *tools.ConcurrentMap

type results struct {
	Results interface{} `json:"results"`
}

// Init start concurrent map and init it from crawling
func Init(url string) {
	performanceURL = url
	performanceMap = tools.CreateConcurrentMap(len(performanceIds), crawler.MaxConcurrentFetcher)

	go func() {
		refreshData()
		c := time.Tick(refreshDelayInHours * time.Hour)
		for range c {
			refreshData()
		}
	}()
}

func refreshData() {
	log.Print(`Data refresh - start`)
	defer log.Print(`Data refresh - end`)

	results, errors := crawler.Crawl(performanceIds, func(ID []byte) (interface{}, error) {
		return fetchPerformance(ID)
	})

	go func() {
		ids := make([][]byte, 0)

		for id := range errors {
			ids = append(ids, id)
		}

		if len(ids) > 0 {
			log.Printf(`Errors while refreshing ids %s`, bytes.Join(ids, []byte(`, `)))
		}
	}()

	for performance := range results {
		performanceMap.Push(performance.(tools.MapContent))
	}

	if db.DB != nil {
		if err := saveData(); err != nil {
			log.Printf(`Error while saving data: %v`, err)
		}
	}
}

func saveData() error {
	var (
		tx *sql.Tx
		err error
		count int
	)

	if tx, err = db.GetTx(nil); err != nil {
		return err
	}

	defer func() {
		db.EndTx(tx, err)
	}()

	for performance := range performanceMap.List() {
		if err != nil {
			err = SavePerformance(performance.(Performance), tx)

			count += 1
			if count % db.CommitStep == 0 {
				tx.Commit()
			}
		}
	}

	return err
}

// ListPerformances return content of performances' map
func ListPerformances() []Performance {
	performances := make([]Performance, 0, len(performanceIds))
	for perf := range performanceMap.List() {
		performances = append(performances, perf.(Performance))
	}

	return performances
}

func listHandler(w http.ResponseWriter, r *http.Request) {
	jsonHttp.ResponseJSON(w, results{ListPerformances()})
}

// Handler for model request. Should be use with net/http
type Handler struct {
}

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add(`Access-Control-Allow-Origin`, `*`)
	w.Header().Add(`Access-Control-Allow-Headers`, `Content-Type`)
	w.Header().Add(`Access-Control-Allow-Methods`, `GET`)
	w.Header().Add(`X-Content-Type-Options`, `nosniff`)

	if r.Method == http.MethodOptions {
		w.Write(nil)
		return
	}

	urlPath := []byte(r.URL.Path)

	if listRequest.Match(urlPath) {
		if r.Method == http.MethodGet {
			listHandler(w, r)
		} else {
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}
<commit_msg>Update model.go<commit_after>package model

import (
	"bytes"
	"database/sql"
	"log"
	"net/http"
	"regexp"
	"time"

	"github.com/ViBiOh/funds/crawler"
	"github.com/ViBiOh/funds/db"
	"github.com/ViBiOh/funds/jsonHttp"
	"github.com/ViBiOh/funds/tools"
)

const refreshDelayInHours = 6

var listRequest = regexp.MustCompile(`^/list$`)
var performanceURL string
var performanceMap *tools.ConcurrentMap

type results struct {
	Results interface{} `json:"results"`
}

// Init start concurrent map and init it from crawling
func Init(url string) {
	performanceURL = url
	performanceMap = tools.CreateConcurrentMap(len(performanceIds), crawler.MaxConcurrentFetcher)

	go func() {
		refreshData()
		c := time.Tick(refreshDelayInHours * time.Hour)
		for range c {
			refreshData()
		}
	}()
}

func refreshData() {
	log.Print(`Data refresh - start`)
	defer log.Print(`Data refresh - end`)

	results, errors := crawler.Crawl(performanceIds, func(ID []byte) (interface{}, error) {
		return fetchPerformance(ID)
	})

	go func() {
		ids := make([][]byte, 0)

		for id := range errors {
			ids = append(ids, id)
		}

		if len(ids) > 0 {
			log.Printf(`Errors while refreshing ids %s`, bytes.Join(ids, []byte(`, `)))
		}
	}()

	for performance := range results {
		performanceMap.Push(performance.(tools.MapContent))
	}

	if db.DB != nil {
		if err := saveData(); err != nil {
			log.Printf(`Error while saving data: %v`, err)
		}
	}
}

func saveData() error {
	var (
		tx *sql.Tx
		err error
		count int
	)

	if tx, err = db.GetTx(nil); err != nil {
		return err
	}

	defer func() {
		db.EndTx(tx, err)
	}()

	for performance := range performanceMap.List() {
		if err != nil {
			err = SavePerformance(performance.(Performance), tx)

			if count++ % db.CommitStep == 0 {
				tx.Commit()
			}
		}
	}

	return err
}

// ListPerformances return content of performances' map
func ListPerformances() []Performance {
	performances := make([]Performance, 0, len(performanceIds))
	for perf := range performanceMap.List() {
		performances = append(performances, perf.(Performance))
	}

	return performances
}

func listHandler(w http.ResponseWriter, r *http.Request) {
	jsonHttp.ResponseJSON(w, results{ListPerformances()})
}

// Handler for model request. Should be use with net/http
type Handler struct {
}

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add(`Access-Control-Allow-Origin`, `*`)
	w.Header().Add(`Access-Control-Allow-Headers`, `Content-Type`)
	w.Header().Add(`Access-Control-Allow-Methods`, `GET`)
	w.Header().Add(`X-Content-Type-Options`, `nosniff`)

	if r.Method == http.MethodOptions {
		w.Write(nil)
		return
	}

	urlPath := []byte(r.URL.Path)

	if listRequest.Match(urlPath) {
		if r.Method == http.MethodGet {
			listHandler(w, r)
		} else {
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}
<|endoftext|>


<commit_before>package cert

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"fmt"
	"math/big"
	"time"
)

var KeyBits = 1024

// ParseCert parses the given PEM-formatted X509 certificate.
func ParseCert(certPEM []byte) (*x509.Certificate, error) {
	for len(certPEM) > 0 {
		var certBlock *pem.Block
		certBlock, certPEM = pem.Decode(certPEM)
		if certBlock == nil {
			break
		}
		if certBlock.Type == "CERTIFICATE" {
			cert, err := x509.ParseCertificate(certBlock.Bytes)
			return cert, err
		}
	}
	return nil, errors.New("no certificates found")
}

// ParseCert parses the given PEM-formatted X509 certificate
// and RSA private key.
func ParseCertAndKey(certPEM, keyPEM []byte) (*x509.Certificate, *rsa.PrivateKey, error) {
	tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
	if err != nil {
		return nil, nil, err
	}

	cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
	if err != nil {
		return nil, nil, err
	}

	key, ok := tlsCert.PrivateKey.(*rsa.PrivateKey)
	if !ok {
		return nil, nil, fmt.Errorf("private key with unexpected type %T", key)
	}
	return cert, key, nil
}

// Verify verifies that the given server certificate is valid with
// respect to the given CA certificate at the given time.
func Verify(srvCertPEM, caCertPEM []byte, when time.Time) error {
	caCert, err := ParseCert(caCertPEM)
	if err != nil {
		return fmt.Errorf("cannot parse CA certificate: %v", err)
	}
	srvCert, err := ParseCert(srvCertPEM)
	if err != nil {
		return fmt.Errorf("cannot parse server certificate: %v", err)
	}
	pool := x509.NewCertPool()
	pool.AddCert(caCert)
	opts := x509.VerifyOptions{
		DNSName:     "anyServer",
		Roots:       pool,
		CurrentTime: when,
	}
	_, err = srvCert.Verify(opts)
	return err
}

// NewCA generates a CA certificate/key pair suitable for signing server
// keys for an environment with the given name.
func NewCA(envName string, expiry time.Time) (certPEM, keyPEM []byte, err error) {
	key, err := rsa.GenerateKey(rand.Reader, KeyBits)
	if err != nil {
		return nil, nil, err
	}
	now := time.Now()
	template := &x509.Certificate{
		SerialNumber: new(big.Int),
		Subject: pkix.Name{
			// TODO quote the environment name when we start using
			// Go version 1.1. See Go issue 3791.
			CommonName:   fmt.Sprintf("juju-generated CA for environment %s", envName),
			Organization: []string{"juju"},
		},
		NotBefore:             now.UTC().Add(-5 * time.Minute),
		NotAfter:              expiry,
		SubjectKeyId:          bigIntHash(key.N),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
		IsCA:                  true,
		MaxPathLen:            0, // Disallow delegation for now.
	}
	certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
	if err != nil {
		return nil, nil, fmt.Errorf("canot create certificate: %v", err)
	}
	certPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: certDER,
	})
	keyPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key),
	})
	return certPEM, keyPEM, nil
}

// NewServer generates a certificate/key pair suitable for use by a
// server for an environment with the given name.
func NewServer(envName string, caCertPEM, caKeyPEM []byte, expiry time.Time) (certPEM, keyPEM []byte, err error) {
	tlsCert, err := tls.X509KeyPair(caCertPEM, caKeyPEM)
	if err != nil {
		return nil, nil, err
	}
	if len(tlsCert.Certificate) != 1 {
		return nil, nil, fmt.Errorf("more than one certificate for CA")
	}
	caCert, err := x509.ParseCertificate(tlsCert.Certificate[0])
	if err != nil {
		return nil, nil, err
	}
	if !caCert.BasicConstraintsValid || !caCert.IsCA {
		return nil, nil, fmt.Errorf("CA certificate is not a valid CA")
	}
	caKey, ok := tlsCert.PrivateKey.(*rsa.PrivateKey)
	if !ok {
		return nil, nil, fmt.Errorf("CA private key has unexpected type %T", tlsCert.PrivateKey)
	}
	key, err := rsa.GenerateKey(rand.Reader, KeyBits)
	if err != nil {
		return nil, nil, fmt.Errorf("cannot generate key: %v", err)
	}
	now := time.Now()
	template := &x509.Certificate{
		SerialNumber: new(big.Int),
		Subject: pkix.Name{
			// This won't match host names with dots. The hostname
			// is hardcoded when connecting to avoid the issue.
			CommonName:   "*",
			Organization: []string{"juju"},
		},
		NotBefore: now.UTC().Add(-5 * time.Minute),
		NotAfter:  expiry,

		SubjectKeyId: bigIntHash(key.N),
		KeyUsage:     x509.KeyUsageDataEncipherment,
	}
	certDER, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
	if err != nil {
		return nil, nil, err
	}
	certPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: certDER,
	})
	keyPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key),
	})
	return certPEM, keyPEM, nil
}

func bigIntHash(n *big.Int) []byte {
	h := sha1.New()
	h.Write(n.Bytes())
	return h.Sum(nil)
}
<commit_msg>cert: reapply UTC fix<commit_after>package cert

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"fmt"
	"math/big"
	"time"
)

var KeyBits = 1024

// ParseCert parses the given PEM-formatted X509 certificate.
func ParseCert(certPEM []byte) (*x509.Certificate, error) {
	for len(certPEM) > 0 {
		var certBlock *pem.Block
		certBlock, certPEM = pem.Decode(certPEM)
		if certBlock == nil {
			break
		}
		if certBlock.Type == "CERTIFICATE" {
			cert, err := x509.ParseCertificate(certBlock.Bytes)
			return cert, err
		}
	}
	return nil, errors.New("no certificates found")
}

// ParseCert parses the given PEM-formatted X509 certificate
// and RSA private key.
func ParseCertAndKey(certPEM, keyPEM []byte) (*x509.Certificate, *rsa.PrivateKey, error) {
	tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
	if err != nil {
		return nil, nil, err
	}

	cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
	if err != nil {
		return nil, nil, err
	}

	key, ok := tlsCert.PrivateKey.(*rsa.PrivateKey)
	if !ok {
		return nil, nil, fmt.Errorf("private key with unexpected type %T", key)
	}
	return cert, key, nil
}

// Verify verifies that the given server certificate is valid with
// respect to the given CA certificate at the given time.
func Verify(srvCertPEM, caCertPEM []byte, when time.Time) error {
	caCert, err := ParseCert(caCertPEM)
	if err != nil {
		return fmt.Errorf("cannot parse CA certificate: %v", err)
	}
	srvCert, err := ParseCert(srvCertPEM)
	if err != nil {
		return fmt.Errorf("cannot parse server certificate: %v", err)
	}
	pool := x509.NewCertPool()
	pool.AddCert(caCert)
	opts := x509.VerifyOptions{
		DNSName:     "anyServer",
		Roots:       pool,
		CurrentTime: when,
	}
	_, err = srvCert.Verify(opts)
	return err
}

// NewCA generates a CA certificate/key pair suitable for signing server
// keys for an environment with the given name.
func NewCA(envName string, expiry time.Time) (certPEM, keyPEM []byte, err error) {
	key, err := rsa.GenerateKey(rand.Reader, KeyBits)
	if err != nil {
		return nil, nil, err
	}
	now := time.Now()
	template := &x509.Certificate{
		SerialNumber: new(big.Int),
		Subject: pkix.Name{
			// TODO quote the environment name when we start using
			// Go version 1.1. See Go issue 3791.
			CommonName:   fmt.Sprintf("juju-generated CA for environment %s", envName),
			Organization: []string{"juju"},
		},
		NotBefore:             now.UTC().Add(-5 * time.Minute),
		NotAfter:              expiry.UTC(),
		SubjectKeyId:          bigIntHash(key.N),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
		IsCA:                  true,
		MaxPathLen:            0, // Disallow delegation for now.
	}
	certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
	if err != nil {
		return nil, nil, fmt.Errorf("canot create certificate: %v", err)
	}
	certPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: certDER,
	})
	keyPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key),
	})
	return certPEM, keyPEM, nil
}

// NewServer generates a certificate/key pair suitable for use by a
// server for an environment with the given name.
func NewServer(envName string, caCertPEM, caKeyPEM []byte, expiry time.Time) (certPEM, keyPEM []byte, err error) {
	tlsCert, err := tls.X509KeyPair(caCertPEM, caKeyPEM)
	if err != nil {
		return nil, nil, err
	}
	if len(tlsCert.Certificate) != 1 {
		return nil, nil, fmt.Errorf("more than one certificate for CA")
	}
	caCert, err := x509.ParseCertificate(tlsCert.Certificate[0])
	if err != nil {
		return nil, nil, err
	}
	if !caCert.BasicConstraintsValid || !caCert.IsCA {
		return nil, nil, fmt.Errorf("CA certificate is not a valid CA")
	}
	caKey, ok := tlsCert.PrivateKey.(*rsa.PrivateKey)
	if !ok {
		return nil, nil, fmt.Errorf("CA private key has unexpected type %T", tlsCert.PrivateKey)
	}
	key, err := rsa.GenerateKey(rand.Reader, KeyBits)
	if err != nil {
		return nil, nil, fmt.Errorf("cannot generate key: %v", err)
	}
	now := time.Now()
	template := &x509.Certificate{
		SerialNumber: new(big.Int),
		Subject: pkix.Name{
			// This won't match host names with dots. The hostname
			// is hardcoded when connecting to avoid the issue.
			CommonName:   "*",
			Organization: []string{"juju"},
		},
		NotBefore: now.UTC().Add(-5 * time.Minute),
		NotAfter:  expiry.UTC(),

		SubjectKeyId: bigIntHash(key.N),
		KeyUsage:     x509.KeyUsageDataEncipherment,
	}
	certDER, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
	if err != nil {
		return nil, nil, err
	}
	certPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: certDER,
	})
	keyPEM = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(key),
	})
	return certPEM, keyPEM, nil
}

func bigIntHash(n *big.Int) []byte {
	h := sha1.New()
	h.Write(n.Bytes())
	return h.Sum(nil)
}
<|endoftext|>


<commit_before>package golf

import (
	"errors"
	"github.com/satori/go.uuid"
	"io"
	"math"
)

type chunker struct {
	chunkSize int
	buff      []byte
	w         io.Writer
}

func newChunker(w io.Writer, chunkSize int) (*chunker, error) {
	if chunkSize < 13 {
		return nil, errors.New("Chunk size must be at least 13.")
	}

	c := &chunker{
		chunkSize: chunkSize,
		buff:      make([]byte, 0),
		w:         w,
	}

	return c, nil
}

func (c *chunker) reset() {
	c.buff = make([]byte, 0)
}
func (c *chunker) Write(p []byte) (int, error) {
	c.buff = append(c.buff, p...)
	return len(p), nil
}

func (c *chunker) Flush() error {
	idFull, err := uuid.NewV4()
	if err != nil {
		return err
	}

	err = c.flushWithId(idFull.Bytes()[0:8])
	return err
}

func (c *chunker) flushWithId(id []byte) error {
	if len(id) < 8 || len(id) > 8 {
		return errors.New("id length must be equal to 8")
	}

	offset := 0
	buffLen := len(c.buff)
	chunkSize := c.chunkSize - 12

	// Reusing this buffer may cause problems with duplicate data being sent
	// if the data isn't written to something else by the io.Writer before
	// the chunk's data is updated.
	chunkBuff := make([]byte, c.chunkSize)
	copy(chunkBuff[0:2], []byte{0x1e, 0x0f})
	copy(chunkBuff[2:10], id)

	totalChunks := int(math.Ceil(float64(buffLen) / float64(chunkSize)))
	chunkBuff[11] = byte(totalChunks)

	for {
		left := buffLen - offset
		if left > chunkSize {
			copy(chunkBuff[12:], c.buff[offset:offset+chunkSize])
			c.w.Write(chunkBuff)
		} else {
			copy(chunkBuff[12:], c.buff[offset:offset+left])
			c.w.Write(chunkBuff[0 : left+12])
			break
		}

		offset += chunkSize
		chunkBuff[10] += 1
	}

	c.reset()
	return nil
}
<commit_msg>Move to google's uuid library. Closes #6<commit_after>package golf

import (
	"errors"
	"io"
	"math"

	"github.com/google/uuid"
)

type chunker struct {
	chunkSize int
	buff      []byte
	w         io.Writer
}

func newChunker(w io.Writer, chunkSize int) (*chunker, error) {
	if chunkSize < 13 {
		return nil, errors.New("Chunk size must be at least 13.")
	}

	c := &chunker{
		chunkSize: chunkSize,
		buff:      make([]byte, 0),
		w:         w,
	}

	return c, nil
}

func (c *chunker) reset() {
	c.buff = make([]byte, 0)
}
func (c *chunker) Write(p []byte) (int, error) {
	c.buff = append(c.buff, p...)
	return len(p), nil
}

func (c *chunker) Flush() error {
	idFull, err := uuid.NewRandom()
	if err != nil {
		return err
	}

	idBytes, err := idFull.MarshalBinary()
	if err != nil {
		return err
	}
	err = c.flushWithId(idBytes[0:8])
	return err
}

func (c *chunker) flushWithId(id []byte) error {
	if len(id) < 8 || len(id) > 8 {
		return errors.New("id length must be equal to 8")
	}

	offset := 0
	buffLen := len(c.buff)
	chunkSize := c.chunkSize - 12

	// Reusing this buffer may cause problems with duplicate data being sent
	// if the data isn't written to something else by the io.Writer before
	// the chunk's data is updated.
	chunkBuff := make([]byte, c.chunkSize)
	copy(chunkBuff[0:2], []byte{0x1e, 0x0f})
	copy(chunkBuff[2:10], id)

	totalChunks := int(math.Ceil(float64(buffLen) / float64(chunkSize)))
	chunkBuff[11] = byte(totalChunks)

	for {
		left := buffLen - offset
		if left > chunkSize {
			copy(chunkBuff[12:], c.buff[offset:offset+chunkSize])
			c.w.Write(chunkBuff)
		} else {
			copy(chunkBuff[12:], c.buff[offset:offset+left])
			c.w.Write(chunkBuff[0 : left+12])
			break
		}

		offset += chunkSize
		chunkBuff[10] += 1
	}

	c.reset()
	return nil
}
<|endoftext|>


<commit_before>package circbuf

import (
	"fmt"
)

func properMod(x, y int64) int64 {
	return ((x % y) + y) % y
}

// Buffer implements a circular buffer. It is a fixed size, but
// new writes will not overwrite unread data
type Buffer struct {
	data []byte
	size int64

	writeCursor int64
	writeCount  int64
	readCursor  int64
	readCount   int64
}

// NewBuffer creates a new buffer of a given size. The size
// must be greater tha n 0
func NewBuffer(size int64) (*Buffer, error) {
	if size <= 0 {
		return nil, fmt.Errorf("Size must be positive")
	}

	b := &Buffer{
		size: size + 1, // +1 to allow for non-overlapping reading & writing
		data: make([]byte, size),
	}
	return b, nil
}

func (b *Buffer) Read(p []byte) (int, error) {
	bytes_read := 0
	for i, pb := range b.nonCopyRead(int64(len(p))) {
		if pb != nil {
			p[i] = *pb
			bytes_read++
		}
	}

	return bytes_read, nil
}

func (b *Buffer) nonCopyRead(n int64) []*byte {
	buf := make([]*byte, n)
	bytesRead := int64(0)

	for r := b.readCursor; r-b.readCursor < n && b.readCount+(r-b.readCursor) < b.writeCount; r++ {
		buf[r-b.readCursor] = &b.data[r%b.size]
		bytesRead++
	}

	b.readCount += bytesRead
	b.readCursor = (b.readCursor + n) % b.size

	return buf
}

// Write writes up to len(buf) bytes to the internal ring,
// overriding older data if necessary.
func (b *Buffer) Write(buf []byte) (int, error) {

	n := int64(len(buf))

	bytesWritten := int64(0)
	for wc := b.writeCursor; bytesWritten < n && wc != properMod((b.readCursor-1), b.size); wc, bytesWritten = (wc+1)%b.size, bytesWritten+1 {
		b.data[wc%b.size] = buf[bytesWritten]
	}

	// Update location of the cursor
	b.writeCount += bytesWritten
	b.writeCursor = ((b.writeCursor + bytesWritten) % b.size)

	if bytesWritten != n {
		return int(bytesWritten), fmt.Errorf("Unable to write all the bytes")
	}
	return int(bytesWritten), nil
}

// Capacity returns the capacity of the buffer
func (b *Buffer) Capacity() int64 {
	return b.size - 1
}

// Bytes provides a slice of the bytes written. This
// slice should not be written to.
func (b *Buffer) Bytes() []byte {
	switch {
	case b.writeCursor < b.readCursor:
		out := make([]byte, b.size)
		copy(out, b.data[b.writeCursor:])
		copy(out[b.size-b.writeCursor:], b.data[:b.readCursor])
		return out
	case b.writeCursor > b.readCursor:
		out := make([]byte, b.writeCursor-b.readCursor)
		copy(out, b.data[b.readCursor:b.writeCursor])
		return out
	default:
		return make([]byte, 0)
	}
}

// String returns the contents of the buffer as a string
func (b *Buffer) String() string {
	return string(b.Bytes())
}
<commit_msg>Refactor Read<commit_after>package circbuf

import (
	"fmt"
)

func properMod(x, y int64) int64 {
	return ((x % y) + y) % y
}

// Buffer implements a circular buffer. It is a fixed size, but
// new writes will not overwrite unread data
type Buffer struct {
	data []byte
	size int64

	writeCursor int64
	writeCount  int64
	readCursor  int64
	readCount   int64
}

// NewBuffer creates a new buffer of a given size. The size
// must be greater tha n 0
func NewBuffer(size int64) (*Buffer, error) {
	if size <= 0 {
		return nil, fmt.Errorf("Size must be positive")
	}

	b := &Buffer{
		size: size + 1, // +1 to allow for non-overlapping reading & writing
		data: make([]byte, size),
	}
	return b, nil
}

func (b *Buffer) Read(p []byte) (int, error) {
	bytes_read := 0

	switch {
	case b.readCursor < b.writeCursor:
		bytes_read += copy(p, b.data[b.readCursor:b.writeCursor])
	case b.readCursor > b.writeCursor: // We wrapped around the end of the buffer, we need to read around
		bytes_read += copy(p, b.data[b.readCursor:])               // Read to the end
		bytes_read += copy(p[bytes_read:], b.data[:b.writeCursor]) // Copy from the beginning to the last read byte
	default:
		return 0, nil
	}

	b.readCursor += int64(bytes_read)

	return bytes_read, nil
}

// Write writes up to len(buf) bytes to the internal ring,
// overriding older data if necessary.
func (b *Buffer) Write(buf []byte) (int, error) {

	n := int64(len(buf))

	bytesWritten := int64(0)
	for wc := b.writeCursor; bytesWritten < n && wc != properMod((b.readCursor-1), b.size); wc, bytesWritten = (wc+1)%b.size, bytesWritten+1 {
		b.data[wc%b.size] = buf[bytesWritten]
	}

	// Update location of the cursor
	b.writeCount += bytesWritten
	b.writeCursor = ((b.writeCursor + bytesWritten) % b.size)

	if bytesWritten != n {
		return int(bytesWritten), fmt.Errorf("Unable to write all the bytes")
	}
	return int(bytesWritten), nil
}

// Capacity returns the capacity of the buffer
func (b *Buffer) Capacity() int64 {
	return b.size - 1
}

// Bytes provides a slice of the bytes written. This
// slice should not be written to.
func (b *Buffer) Bytes() []byte {
	switch {
	case b.writeCursor < b.readCursor:
		out := make([]byte, b.size)
		copy(out, b.data[b.writeCursor:])
		copy(out[b.size-b.writeCursor:], b.data[:b.readCursor])
		return out
	case b.writeCursor > b.readCursor:
		out := make([]byte, b.writeCursor-b.readCursor)
		copy(out, b.data[b.readCursor:b.writeCursor])
		return out
	default:
		return make([]byte, 0)
	}
}

// String returns the contents of the buffer as a string
func (b *Buffer) String() string {
	return string(b.Bytes())
}
<|endoftext|>


<commit_before>package deepcopier

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

const (
	// TagName is struct field tag name.
	TagName = "deepcopier"
	// FieldOptionName is the from field option name for struct tag.
	FieldOptionName = "field"
	// ContextOptionName is the context option name for struct tag.
	ContextOptionName = "context"
	// SkipOptionName is the skip option name for struct tag.
	SkipOptionName = "skip"
)

// TagOptions are struct tag options.
type TagOptions map[string]string

// Options are copier options.
type Options struct {
	// Context given to WithContext() method.
	Context map[string]interface{}
	// Reversed reverses struct tag checkings.
	Reversed bool
}

// DeepCopier deep copies a struct to/from a struct.
type DeepCopier struct {
	dst interface{}
	src interface{}
	ctx map[string]interface{}
}

// Copy sets source or destination.
func Copy(src interface{}) *DeepCopier {
	return &DeepCopier{src: src}
}

// WithContext injects the given context into the builder instance.
func (dc *DeepCopier) WithContext(ctx map[string]interface{}) *DeepCopier {
	dc.ctx = ctx
	return dc
}

// To sets the given the destination.
func (dc *DeepCopier) To(dst interface{}) error {
	dc.dst = dst
	return cp(dc.dst, dc.src, Options{
		Context: dc.ctx,
	})
}

// From sets the given the source as destination and destination as source.
func (dc *DeepCopier) From(src interface{}) error {
	dc.dst = dc.src
	dc.src = src
	return cp(dc.dst, dc.src, Options{
		Context:  dc.ctx,
		Reversed: true,
	})
}

// cp is the brand new way to process copy.
func cp(dst interface{}, src interface{}, args ...Options) error {
	var (
		options        = Options{}
		srcValue       = reflect.Indirect(reflect.ValueOf(src))
		dstValue       = reflect.Indirect(reflect.ValueOf(dst))
		srcFieldNames  = getFieldNames(src)
		srcMethodNames = getMethodNames(src)
	)

	if len(args) > 0 {
		options = args[0]
	}

	if !dstValue.CanAddr() {
		return errors.New("dst value is unaddressable")
	}

	for _, m := range srcMethodNames {
		name, opts := getRelatedField(dst, m)
		if name == "" {
			continue
		}

		method := reflect.ValueOf(src).MethodByName(m)
		if !method.IsValid() {
			return fmt.Errorf("method %s is invalid", m)
		}

		var (
			dstFieldType, _ = dstValue.Type().FieldByName(name)
			dstFieldValue   = dstValue.FieldByName(name)
			withContext     = false
		)

		if _, ok := opts[ContextOptionName]; ok {
			withContext = true
		}

		var args []reflect.Value
		if withContext {
			args = []reflect.Value{reflect.ValueOf(options.Context)}
		}

		result := method.Call(args)[0]
		if result.Type().AssignableTo(dstFieldType.Type) {
			dstFieldValue.Set(result)
		}
	}

	for _, f := range srcFieldNames {
		var (
			srcFieldValue                = srcValue.FieldByName(f)
			srcFieldType, srcFieldTypeOK = srcValue.Type().FieldByName(f)
			srcFieldName                 = srcFieldType.Name
			dstFieldName                 = srcFieldName
			tagOptions                   TagOptions
		)

		if options.Reversed {
			tagOptions = getTagOptions(srcFieldType.Tag.Get(TagName))
			if v, ok := tagOptions[FieldOptionName]; ok && v != "" {
				dstFieldName = v
			}
		} else {
			if name, opts := getRelatedField(dst, srcFieldName); name != "" {
				dstFieldName, tagOptions = name, opts
			}
		}

		if _, ok := tagOptions[SkipOptionName]; ok {
			continue
		}

		var (
			dstFieldType, dstFieldTypeOK = dstValue.Type().FieldByName(dstFieldName)
			dstFieldValue                = dstValue.FieldByName(dstFieldName)
		)

		// Ptr -> Value
		if srcFieldType.Type.Kind() == reflect.Ptr && !srcFieldValue.IsNil() && dstFieldType.Type.Kind() != reflect.Ptr {
			dstFieldValue.Set(reflect.Indirect(srcFieldValue))
			continue
		}

		if srcFieldTypeOK && dstFieldTypeOK && srcFieldType.Type.AssignableTo(dstFieldType.Type) {
			dstFieldValue.Set(srcFieldValue)
		}
	}

	return nil
}

// getTagOptions parses deepcopier tag field and returns options.
func getTagOptions(value string) TagOptions {
	options := TagOptions{}

	for _, opt := range strings.Split(value, ";") {
		o := strings.Split(opt, ":")

		// deepcopier:"keyword; without; value;"
		if len(o) == 1 {
			k := o[0]
			options[k] = ""
		}

		// deepcopier:"key:value; anotherkey:anothervalue"
		if len(o) == 2 {
			k, v := o[0], o[1]
			k = strings.TrimSpace(k)
			v = strings.TrimSpace(v)
			options[k] = v
		}
	}

	return options
}

// getRelatedField returns first matching field.
func getRelatedField(instance interface{}, name string) (string, TagOptions) {
	var (
		value      = reflect.Indirect(reflect.ValueOf(instance))
		fieldName  string
		tagOptions TagOptions
	)

	for i := 0; i < value.NumField(); i++ {
		var (
			v          = value.Field(i)
			t          = value.Type().Field(i)
			tagOptions = getTagOptions(t.Tag.Get(TagName))
		)

		if t.Type.Kind() == reflect.Struct && t.Anonymous {
			if n, o := getRelatedField(v.Interface(), name); n != "" {
				return n, o
			}
		}

		if v, ok := tagOptions[FieldOptionName]; ok && v == name {
			return t.Name, tagOptions
		}

		if t.Name == name {
			return t.Name, tagOptions
		}
	}

	return fieldName, tagOptions
}

// getMethodNames returns instance's method names.
func getMethodNames(instance interface{}) []string {
	var (
		t       = reflect.TypeOf(instance)
		methods []string
	)

	for i := 0; i < t.NumMethod(); i++ {
		methods = append(methods, t.Method(i).Name)
	}

	return methods
}

// getFieldNames returns instance's field names.
func getFieldNames(instance interface{}) []string {
	var (
		v      = reflect.Indirect(reflect.ValueOf(instance))
		t      = v.Type()
		fields []string
	)

	if t.Kind() != reflect.Struct {
		return nil
	}

	for i := 0; i < v.NumField(); i++ {
		var (
			vField = v.Field(i)
			tField = v.Type().Field(i)
		)

		if tField.Type.Kind() == reflect.Struct && tField.Anonymous {
			fields = append(fields, getFieldNames(vField.Interface())...)
			continue
		}

		fields = append(fields, tField.Name)
	}

	return fields
}
<commit_msg>Refacto: clean code.<commit_after>package deepcopier

import (
	"fmt"
	"reflect"
	"strings"
)

const (
	// TagName is the deepcopier struct tag name.
	TagName = "deepcopier"
	// FieldOptionName is the from field option name for struct tag.
	FieldOptionName = "field"
	// ContextOptionName is the context option name for struct tag.
	ContextOptionName = "context"
	// SkipOptionName is the skip option name for struct tag.
	SkipOptionName = "skip"
)

type (
	// TagOptions is a map that contains extracted struct tag options.
	TagOptions map[string]string

	// Options are copier options.
	Options struct {
		// Context given to WithContext() method.
		Context map[string]interface{}
		// Reversed reverses struct tag checkings.
		Reversed bool
	}
)

// DeepCopier deep copies a struct to/from a struct.
type DeepCopier struct {
	dst interface{}
	src interface{}
	ctx map[string]interface{}
}

// Copy sets source or destination.
func Copy(src interface{}) *DeepCopier {
	return &DeepCopier{src: src}
}

// WithContext injects the given context into the builder instance.
func (dc *DeepCopier) WithContext(ctx map[string]interface{}) *DeepCopier {
	dc.ctx = ctx
	return dc
}

// To sets the destination.
func (dc *DeepCopier) To(dst interface{}) error {
	dc.dst = dst
	return cp(dc.dst, dc.src, Options{Context: dc.ctx})
}

// From sets the given the source as destination and destination as source.
func (dc *DeepCopier) From(src interface{}) error {
	dc.dst = dc.src
	dc.src = src
	return cp(dc.dst, dc.src, Options{Context: dc.ctx, Reversed: true})
}

// cp is the brand new way to process copy.
func cp(dst interface{}, src interface{}, args ...Options) error {
	var (
		options        = Options{}
		srcValue       = reflect.Indirect(reflect.ValueOf(src))
		dstValue       = reflect.Indirect(reflect.ValueOf(dst))
		srcFieldNames  = getFieldNames(src)
		srcMethodNames = getMethodNames(src)
	)

	if len(args) > 0 {
		options = args[0]
	}

	if !dstValue.CanAddr() {
		return fmt.Errorf("destination %+v is unaddressable", dstValue.Interface())
	}

	for _, m := range srcMethodNames {
		name, opts := getRelatedField(dst, m)
		if name == "" {
			continue
		}

		method := reflect.ValueOf(src).MethodByName(m)
		if !method.IsValid() {
			return fmt.Errorf("method %s is invalid", m)
		}

		var (
			dstFieldType, _ = dstValue.Type().FieldByName(name)
			dstFieldValue   = dstValue.FieldByName(name)
		)

		withContext := false
		if _, ok := opts[ContextOptionName]; ok {
			withContext = true
		}

		args := []reflect.Value{}
		if withContext {
			args = []reflect.Value{reflect.ValueOf(options.Context)}
		}

		result := method.Call(args)[0]
		if result.Type().AssignableTo(dstFieldType.Type) {
			dstFieldValue.Set(result)
		}
	}

	for _, f := range srcFieldNames {
		var (
			srcFieldValue               = srcValue.FieldByName(f)
			srcFieldType, srcFieldFound = srcValue.Type().FieldByName(f)
			srcFieldName                = srcFieldType.Name
			dstFieldName                = srcFieldName
			tagOptions                  TagOptions
		)

		if options.Reversed {
			tagOptions = getTagOptions(srcFieldType.Tag.Get(TagName))
			if v, ok := tagOptions[FieldOptionName]; ok && v != "" {
				dstFieldName = v
			}
		} else {
			if name, opts := getRelatedField(dst, srcFieldName); name != "" {
				dstFieldName, tagOptions = name, opts
			}
		}

		if _, ok := tagOptions[SkipOptionName]; ok {
			continue
		}

		var (
			dstFieldType, dstFieldFound = dstValue.Type().FieldByName(dstFieldName)
			dstFieldValue               = dstValue.FieldByName(dstFieldName)
		)

		// Ptr -> Value
		if srcFieldType.Type.Kind() == reflect.Ptr && !srcFieldValue.IsNil() && dstFieldType.Type.Kind() != reflect.Ptr {
			dstFieldValue.Set(reflect.Indirect(srcFieldValue))
			continue
		}

		if srcFieldFound && dstFieldFound && srcFieldType.Type.AssignableTo(dstFieldType.Type) {
			dstFieldValue.Set(srcFieldValue)
		}
	}

	return nil
}

// getTagOptions parses deepcopier tag field and returns options.
func getTagOptions(value string) TagOptions {
	options := TagOptions{}

	for _, opt := range strings.Split(value, ";") {
		o := strings.Split(opt, ":")

		// deepcopier:"keyword; without; value;"
		if len(o) == 1 {
			options[o[0]] = ""
		}

		// deepcopier:"key:value; anotherkey:anothervalue"
		if len(o) == 2 {
			options[strings.TrimSpace(o[0])] = strings.TrimSpace(o[1])
		}
	}

	return options
}

// getRelatedField returns first matching field.
func getRelatedField(instance interface{}, name string) (string, TagOptions) {
	var (
		value      = reflect.Indirect(reflect.ValueOf(instance))
		fieldName  string
		tagOptions TagOptions
	)

	for i := 0; i < value.NumField(); i++ {
		var (
			vField     = value.Field(i)
			tField     = value.Type().Field(i)
			tagOptions = getTagOptions(tField.Tag.Get(TagName))
		)

		if tField.Type.Kind() == reflect.Struct && tField.Anonymous {
			if n, o := getRelatedField(vField.Interface(), name); n != "" {
				return n, o
			}
		}

		if v, ok := tagOptions[FieldOptionName]; ok && v == name {
			return tField.Name, tagOptions
		}

		if tField.Name == name {
			return tField.Name, tagOptions
		}
	}

	return fieldName, tagOptions
}

// getMethodNames returns instance's method names.
func getMethodNames(instance interface{}) []string {
	var methods []string

	t := reflect.TypeOf(instance)
	for i := 0; i < t.NumMethod(); i++ {
		methods = append(methods, t.Method(i).Name)
	}

	return methods
}

// getFieldNames returns instance's field names.
func getFieldNames(instance interface{}) []string {
	var (
		fields []string
		v      = reflect.Indirect(reflect.ValueOf(instance))
		t      = v.Type()
	)

	if t.Kind() != reflect.Struct {
		return nil
	}

	for i := 0; i < v.NumField(); i++ {
		var (
			vField = v.Field(i)
			tField = v.Type().Field(i)
		)

		if tField.Type.Kind() == reflect.Struct && tField.Anonymous {
			fields = append(fields, getFieldNames(vField.Interface())...)
			continue
		}

		fields = append(fields, tField.Name)
	}

	return fields
}
<|endoftext|>


<commit_before>package db

import (
	"encoding/json"
	"fmt"
	"os"
	"testing"
)

func runQueryV2(query string, col *Col) (map[uint64]struct{}, error) {
	result := make(map[uint64]struct{})
	var jq interface{}
	if err := json.Unmarshal([]byte(query), &jq); err != nil {
		fmt.Println(err)
	}
	return result, EvalQueryV2(jq, col, &result)
}

func TestQueryV2(t *testing.T) {
	// prepare a collection of documents
	tmp := "/tmp/tiedot_queryv2_test"
	os.RemoveAll(tmp)
	defer os.RemoveAll(tmp)
	col, err := OpenCol(tmp)
	if err != nil {
		t.Fatal(err)
		return
	}
	defer col.Close()
	docs := []string{
		`{"a": {"b": [1]}, "c": 1, "d": 1, "f": 1, "g": 1, "special": {"thing": null} }`,
		`{"a": {"b": 1}, "c": [1], "d": 2, "f": 2, "g": 2}`,
		`{"a": {"b": [2]}, "c": 2, "d": 1, "f": 3, "g": 3}`,
		`{"a": {"b": 3}, "c": [3], "d": 2, "f": 4, "g": 4}`,
		`{"a": {"b": [4]}, "c": 4, "d": 1, "f": 5, "g": 5}`}
	ids := [5]uint64{}
	for i, doc := range docs {
		var jsonDoc interface{}
		json.Unmarshal([]byte(doc), &jsonDoc)
		if ids[i], err = col.Insert(jsonDoc); err != nil {
			fmt.Println(err)
			return
		}
	}
	col.Index([]string{"a", "b"})
	col.Index([]string{"f"})
	// expand numbers
	q, err := runQueryV2(`[1, 2, [3, 4], 5]`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, 1, 2, 3, 4, 5) {
		t.Fatal(q)
	}
	// hash scan
	q, err = runQueryV2(`{"eq": 1, "in": ["a", "b"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"eq": 1, "limit": 1, "in": ["a", "b"]}`, col)
	if err != nil {
		fmt.Println(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		t.Fatal(q)
	}
	// collection scan
	q, err = runQueryV2(`{"eq": 1, "in": ["c"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"eq": 1, "limit": 1, "in": ["c"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		t.Fatal(q)
	}
	// all documents
	q, err = runQueryV2(`"all"`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2], ids[3], ids[4]) {
		t.Fatal(q)
	}
	// union
	q, err = runQueryV2(`[{"eq": 4, "limit": 1, "in": ["a", "b"]}, {"eq": 1, "limit": 1, "in": ["c"]}]`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[4]) {
		t.Fatal(q)
	}
	// intersection
	q, err = runQueryV2(`{"n": [{"eq": 2, "in": ["d"]}, "all"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[3]) {
		t.Fatal(q)
	}
	// complement
	q, err = runQueryV2(`{"c": [{"eq": 4,  "in": ["c"]}, {"eq": 2, "in": ["d"]}, "all"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[2]) {
		t.Fatal(q)
	}
	// lookup on "special"
	q, err = runQueryV2(`{"eq": {"thing": null},  "in": ["special"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		t.Fatal(q)
	}
	// "e" should not exist
	q, err = runQueryV2(`{"has": ["e"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q) {
		t.Fatal(q)
	}
	// existence test, hash scan, with limit
	q, err = runQueryV2(`{"has": ["a", "b"], "limit": 3}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2]) {
		t.Fatal(q)
	}
	// existence test, collection scan, with limit
	q, err = runQueryV2(`{"has": ["c"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1]) {
		t.Fatal(q)
	}
	// int hash scan
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["f"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2], ids[3]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["f"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2]) {
		t.Fatal(q)
	}
	// int collection scan
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["g"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2], ids[3]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["g"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2]) {
		t.Fatal(q)
	}
	// int collection scan with reversed range and limit
	q, err = runQueryV2(`{"int-from": 10, "int-to": 0, "in": ["f"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[4], ids[3], ids[2], ids[1], ids[0]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"int-from": 10, "int-to": 0, "in": ["f"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[4], ids[3]) {
		t.Fatal(q)
	}

	q, err = runQueryV2(`{"re": "^[0-9]*$", "in": ["f"], "limit": 5}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2], ids[3], ids[4]) {
		fmt.Printf("%+v\n", q)
		t.Fatal(q)
	}
}
<commit_msg>several more regex test cases<commit_after>package db

import (
	"encoding/json"
	"fmt"
	"os"
	"testing"
)

func runQueryV2(query string, col *Col) (map[uint64]struct{}, error) {
	result := make(map[uint64]struct{})
	var jq interface{}
	if err := json.Unmarshal([]byte(query), &jq); err != nil {
		fmt.Println(err)
	}
	return result, EvalQueryV2(jq, col, &result)
}

func TestQueryV2(t *testing.T) {
	// prepare a collection of documents
	tmp := "/tmp/tiedot_queryv2_test"
	os.RemoveAll(tmp)
	defer os.RemoveAll(tmp)
	col, err := OpenCol(tmp)
	if err != nil {
		t.Fatal(err)
		return
	}
	defer col.Close()
	docs := []string{
		`{"a": {"b": [1]}, "c": 1, "d": 1, "f": 1, "g": 1, "special": {"thing": null} }`,
		`{"a": {"b": 1}, "c": [1], "d": 2, "f": 2, "g": 2}`,
		`{"a": {"b": [2]}, "c": 2, "d": 1, "f": 3, "g": 3}`,
		`{"a": {"b": 3}, "c": [3], "d": 2, "f": 4, "g": 4}`,
		`{"a": {"b": [4]}, "c": 4, "d": 1, "f": 5, "g": 5}`}
	ids := [5]uint64{}
	for i, doc := range docs {
		var jsonDoc interface{}
		json.Unmarshal([]byte(doc), &jsonDoc)
		if ids[i], err = col.Insert(jsonDoc); err != nil {
			fmt.Println(err)
			return
		}
	}
	col.Index([]string{"a", "b"})
	col.Index([]string{"f"})
	// expand numbers
	q, err := runQueryV2(`[1, 2, [3, 4], 5]`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, 1, 2, 3, 4, 5) {
		t.Fatal(q)
	}
	// hash scan
	q, err = runQueryV2(`{"eq": 1, "in": ["a", "b"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"eq": 1, "limit": 1, "in": ["a", "b"]}`, col)
	if err != nil {
		fmt.Println(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		t.Fatal(q)
	}
	// collection scan
	q, err = runQueryV2(`{"eq": 1, "in": ["c"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"eq": 1, "limit": 1, "in": ["c"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		t.Fatal(q)
	}
	// all documents
	q, err = runQueryV2(`"all"`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2], ids[3], ids[4]) {
		t.Fatal(q)
	}
	// union
	q, err = runQueryV2(`[{"eq": 4, "limit": 1, "in": ["a", "b"]}, {"eq": 1, "limit": 1, "in": ["c"]}]`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[4]) {
		t.Fatal(q)
	}
	// intersection
	q, err = runQueryV2(`{"n": [{"eq": 2, "in": ["d"]}, "all"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[3]) {
		t.Fatal(q)
	}
	// complement
	q, err = runQueryV2(`{"c": [{"eq": 4,  "in": ["c"]}, {"eq": 2, "in": ["d"]}, "all"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[2]) {
		t.Fatal(q)
	}
	// lookup on "special"
	q, err = runQueryV2(`{"eq": {"thing": null},  "in": ["special"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		t.Fatal(q)
	}
	// "e" should not exist
	q, err = runQueryV2(`{"has": ["e"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q) {
		t.Fatal(q)
	}
	// existence test, hash scan, with limit
	q, err = runQueryV2(`{"has": ["a", "b"], "limit": 3}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2]) {
		t.Fatal(q)
	}
	// existence test, collection scan, with limit
	q, err = runQueryV2(`{"has": ["c"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1]) {
		t.Fatal(q)
	}
	// int hash scan
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["f"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2], ids[3]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["f"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2]) {
		t.Fatal(q)
	}
	// int collection scan
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["g"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2], ids[3]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"int-from": 2, "int-to": 4, "in": ["g"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2]) {
		t.Fatal(q)
	}
	// int collection scan with reversed range and limit
	q, err = runQueryV2(`{"int-from": 10, "int-to": 0, "in": ["f"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[4], ids[3], ids[2], ids[1], ids[0]) {
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"int-from": 10, "int-to": 0, "in": ["f"], "limit": 2}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[4], ids[3]) {
		t.Fatal(q)
	}
	// regexes
	q, err = runQueryV2(`{"re": "^[0-9]*$", "in": ["f"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2], ids[3], ids[4]) {
		fmt.Printf("%+v\n", q)
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"re": ".*", "in": ["a"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0], ids[1], ids[2], ids[3], ids[4]) {
		fmt.Printf("%+v\n", q)
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"re": "thing", "in": ["special"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		fmt.Printf("%+v\n", q)
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"re": "thing", "in": ["special"]}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[0]) {
		fmt.Printf("%+v\n", q)
		t.Fatal(q)
	}
	q, err = runQueryV2(`{"re": "^[2345]$", "in": ["f"], "limit": 3}`, col)
	if err != nil {
		t.Fatal(err)
	}
	if !ensureMapHasKeys(q, ids[1], ids[2], ids[3]) {
		fmt.Printf("%+v\n", q)
		t.Fatal(q)
	}
}
<|endoftext|>


<commit_before>// Find local, non-loopback IP address
//
// Skips docker bridge address and IPv6 addresses, unless it can't find another
package main

import (
  "flag"
  "fmt"
  "io/ioutil"
  "log"
  "net"
  "net/http"
  "os"
  "sort"
  "strings"
)

const (
  fallbackService = "http://benizi.com/ip?raw=1"
)

type namedAddr struct {
  name string
  ip   net.IP
}

func getExternal() []net.Addr {
  res, err := http.Get(fallbackService)
  if err != nil {
    os.Exit(1)
  }
  defer res.Body.Close()

  ip, err := ioutil.ReadAll(res.Body)
  if err != nil {
    os.Exit(1)
  }

  _, network, err := net.ParseCIDR(fmt.Sprintf("%s/32", ip[0:len(ip)-1]))
  if err != nil {
    os.Exit(1)
  }

  return []net.Addr{network}
}

func findIPs(addrs []net.Addr) []net.IP {
  ips := []net.IP{}
  for _, addr := range addrs {
    if network, ok := addr.(*net.IPNet); ok {
      ips = append(ips, network.IP)
    }
  }
  return ips
}

func namedIPs(name string, addrs []net.Addr) []namedAddr {
  named := []namedAddr{}
  for _, ip := range findIPs(addrs) {
    named = append(named, namedAddr{name: name, ip: ip})
  }
  return named
}

func getExternalNamedAddrs() []namedAddr {
  return namedIPs("external", getExternal())
}

func getInterfaceNamedAddrs() []namedAddr {
  namedAddrs := []namedAddr{}
  ifis, err := net.Interfaces()
  if err != nil {
    if true {
      return []namedAddr{{ip: net.IP{}, name: err.Error()}}
    }
    return namedAddrs
  }
  for _, ifi := range ifis {
    addrs, err := ifi.Addrs()
    if err != nil {
      continue
    }
    namedAddrs = append(namedAddrs, namedIPs(ifi.Name, addrs)...)
  }
  return namedAddrs
}

type foundAddr struct {
  ip net.IP
  preferred bool
  rejected bool
  loopback bool
  isRfc1918 bool
  v6 bool
  original int
  name string
  wireless bool
}

var wirelessCache = make(map[string]bool)

func isWirelessInterface(dev string) bool {
  isWireless, cached := wirelessCache[dev]
  if !cached {
    isWireless = isWirelessInterfaceImpl(dev)
    wirelessCache[dev] = isWireless
  }
  return isWireless
}

// Dumb, Linux-specific detection of whether a network interface is wireless
func isWirelessInterfaceImpl(dev string) bool {
  stat, err := os.Stat(fmt.Sprintf("/sys/class/net/%s/wireless", dev))
  return err == nil && stat.Mode().IsDir()
}

func xor(a, b bool) bool {
  return (a && !b) || (!a && b)
}

type ByAttributes struct {
  addrs []foundAddr
}

func (v ByAttributes) Len() int { return len(v.addrs) }
func (v ByAttributes) Swap(i, j int) { v.addrs[i], v.addrs[j] = v.addrs[j], v.addrs[i] }
func (v ByAttributes) Less(i, j int) bool {
  a := v.addrs[i]
  b := v.addrs[j]
  if xor(a.wireless, b.wireless) {
    return a.wireless
  }
  if xor(a.v6, b.v6) {
    return !a.v6
  }
  if xor(a.preferred, b.preferred) {
    return a.preferred
  }
  if xor(a.rejected, b.rejected) {
    return !a.rejected
  }
  if xor(a.loopback, b.loopback) {
    return !a.loopback
  }
  if xor(a.isRfc1918, b.isRfc1918) {
    return !a.isRfc1918
  }
  if a.original != b.original {
    return a.original < b.original
  }
  return a.ip.String() < b.ip.String()
}

func anyContains(networks []net.IPNet, ip net.IP) bool {
  for _, network := range networks {
    if network.Contains(ip) {
      return true
    }
  }
  return false
}

func parseNetwork(cidr string) (*net.IPNet, error) {
  _, network, err := net.ParseCIDR(cidr)
  if err == nil {
    return network, nil
  }

  // Try parsing it as an octet or octets
  // e.g. "10" => "10.0.0.0/8", "192.168" => "192.168.0.0/16"
  dots := strings.Count(cidr, ".")
  needed := 3 - dots
  if needed < 0 {
    return nil, err
  }
  cidr = fmt.Sprintf("%s%s/%d", cidr, strings.Repeat(".0", needed), 32 - 8 * needed)
  _, network, e := net.ParseCIDR(cidr)
  if e == nil {
    return network, nil
  }

  // return the original error
  return nil, err
}

func main() {
  print4 := false
  print6 := false
  external := false
  iface := false
  excludeDocker := true
  docker := "172.17.0.0/16"
  printName := false
  printAll := false

  flag.BoolVar(&print4, "4", print4, "Print IPv4")
  flag.BoolVar(&print6, "6", print6, "Print IPv6")
  flag.BoolVar(&external, "x", external, "Fetch external address")
  flag.BoolVar(&iface, "i", iface, "Fetch addresses per interface")
  flag.BoolVar(&excludeDocker, "nodocker", excludeDocker, "Exclude Docker interface")
  flag.StringVar(&docker, "dockernet", docker, "Docker network to exclude")
  flag.BoolVar(&printName, "name", printName, "Print interface name")
  flag.BoolVar(&printName, "n", printName, "Print interface name (alias)")
  flag.BoolVar(&printAll, "all", printAll, "Print all addresses")
  flag.BoolVar(&printAll, "a", printAll, "Print all addresses (alias)")
  flag.Parse()

  if !external && !iface {
    iface = true
  }

  var acceptable []net.IPNet
  var rejectable []net.IPNet
  rfc1918 := []net.IPNet{}

  for _, cidr := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
    _, parsed, err := net.ParseCIDR(cidr)
    if err != nil {
      log.Fatalln("Failed to parse RFC 1918 network", cidr)
    }
    rfc1918 = append(rfc1918, *parsed)
  }

  if excludeDocker {
    _, dockerNet, err := net.ParseCIDR(docker)
    if err != nil {
      log.Fatalln("Failed to parse Docker network", docker)
    }

    rejectable = append(rejectable, *dockerNet)
  }

  for _, arg := range flag.Args() {
    if len(arg) == 0 {
      continue
    }

    addTo := &acceptable
    if arg[0] == '!' || arg[0] == 'x' {
      addTo = &rejectable
      arg = arg[1:len(arg)]
    }

    network, err := parseNetwork(arg)
    if err != nil {
      log.Fatal(err)
    }

    *addTo = append(*addTo, *network)
  }

  found := make([]foundAddr, 0)

  var namedAddrs []namedAddr
  if external {
    namedAddrs = getExternalNamedAddrs()
  }
  if iface {
    namedAddrs = append(namedAddrs, getInterfaceNamedAddrs()...)
  }

  for _, addr := range namedAddrs {
    ip := addr.ip
    v6 := ip.To4() == nil
    if xor(print4, print6) && xor(print6, v6) {
      continue
    }
    found = append(found, foundAddr{
      ip: ip,
      preferred: anyContains(acceptable, ip),
      rejected: anyContains(rejectable, ip),
      isRfc1918: anyContains(rfc1918, ip),
      loopback: ip.IsLoopback(),
      v6: v6,
      original: len(found),
      name: addr.name,
      wireless: isWirelessInterface(addr.name),
    })
  }

  if len(found) == 0 {
    os.Exit(1)
  }

  sort.Sort(ByAttributes{found})

  for _, addr := range found {
    if printName {
      fmt.Printf("%s\t", addr.name)
    }
    fmt.Println(addr.ip.String())
    if !printAll {
      break
    }
  }
}
<commit_msg>Update `myip` to allow external format string<commit_after>// Find local, non-loopback IP address
//
// Skips docker bridge address and IPv6 addresses, unless it can't find another
package main

import (
  "flag"
  "fmt"
  "io/ioutil"
  "log"
  "net"
  "net/http"
  "os"
  "sort"
  "strings"
  "text/template"
)

const (
  fallbackService = "http://benizi.com/ip?raw=1"
)

type namedAddr struct {
  name string
  ip   net.IP
}

func getExternal() []net.Addr {
  res, err := http.Get(fallbackService)
  if err != nil {
    os.Exit(1)
  }
  defer res.Body.Close()

  ip, err := ioutil.ReadAll(res.Body)
  if err != nil {
    os.Exit(1)
  }

  _, network, err := net.ParseCIDR(fmt.Sprintf("%s/32", ip[0:len(ip)-1]))
  if err != nil {
    os.Exit(1)
  }

  return []net.Addr{network}
}

func findIPs(addrs []net.Addr) []net.IP {
  ips := []net.IP{}
  for _, addr := range addrs {
    if network, ok := addr.(*net.IPNet); ok {
      ips = append(ips, network.IP)
    }
  }
  return ips
}

func namedIPs(name string, addrs []net.Addr) []namedAddr {
  named := []namedAddr{}
  for _, ip := range findIPs(addrs) {
    named = append(named, namedAddr{name: name, ip: ip})
  }
  return named
}

func getExternalNamedAddrs() []namedAddr {
  return namedIPs("external", getExternal())
}

func getInterfaceNamedAddrs() []namedAddr {
  namedAddrs := []namedAddr{}
  ifis, err := net.Interfaces()
  if err != nil {
    if true {
      return []namedAddr{{ip: net.IP{}, name: err.Error()}}
    }
    return namedAddrs
  }
  for _, ifi := range ifis {
    addrs, err := ifi.Addrs()
    if err != nil {
      continue
    }
    namedAddrs = append(namedAddrs, namedIPs(ifi.Name, addrs)...)
  }
  return namedAddrs
}

type foundAddr struct {
  IP net.IP
  preferred bool
  rejected bool
  Loopback bool
  isRfc1918 bool
  V6 bool
  original int
  Name string
  Wireless bool
}

var wirelessCache = make(map[string]bool)

func isWirelessInterface(dev string) bool {
  isWireless, cached := wirelessCache[dev]
  if !cached {
    isWireless = isWirelessInterfaceImpl(dev)
    wirelessCache[dev] = isWireless
  }
  return isWireless
}

// Dumb, Linux-specific detection of whether a network interface is wireless
func isWirelessInterfaceImpl(dev string) bool {
  stat, err := os.Stat(fmt.Sprintf("/sys/class/net/%s/wireless", dev))
  return err == nil && stat.Mode().IsDir()
}

func xor(a, b bool) bool {
  return (a && !b) || (!a && b)
}

type ByAttributes struct {
  addrs []foundAddr
}

func (v ByAttributes) Len() int { return len(v.addrs) }
func (v ByAttributes) Swap(i, j int) { v.addrs[i], v.addrs[j] = v.addrs[j], v.addrs[i] }
func (v ByAttributes) Less(i, j int) bool {
  a := v.addrs[i]
  b := v.addrs[j]
  if xor(a.Wireless, b.Wireless) {
    return a.Wireless
  }
  if xor(a.V6, b.V6) {
    return !a.V6
  }
  if xor(a.preferred, b.preferred) {
    return a.preferred
  }
  if xor(a.rejected, b.rejected) {
    return !a.rejected
  }
  if xor(a.Loopback, b.Loopback) {
    return !a.Loopback
  }
  if xor(a.isRfc1918, b.isRfc1918) {
    return !a.isRfc1918
  }
  if a.original != b.original {
    return a.original < b.original
  }
  return a.IP.String() < b.IP.String()
}

func anyContains(networks []net.IPNet, ip net.IP) bool {
  for _, network := range networks {
    if network.Contains(ip) {
      return true
    }
  }
  return false
}

func parseNetwork(cidr string) (*net.IPNet, error) {
  _, network, err := net.ParseCIDR(cidr)
  if err == nil {
    return network, nil
  }

  // Try parsing it as an octet or octets
  // e.g. "10" => "10.0.0.0/8", "192.168" => "192.168.0.0/16"
  dots := strings.Count(cidr, ".")
  needed := 3 - dots
  if needed < 0 {
    return nil, err
  }
  cidr = fmt.Sprintf("%s%s/%d", cidr, strings.Repeat(".0", needed), 32 - 8 * needed)
  _, network, e := net.ParseCIDR(cidr)
  if e == nil {
    return network, nil
  }

  // return the original error
  return nil, err
}

func main() {
  print4 := false
  print6 := false
  external := false
  iface := false
  excludeDocker := true
  docker := "172.17.0.0/16"
  printName := false
  printAll := false
  format := ""
  raw := false

  flag.BoolVar(&print4, "4", print4, "Print IPv4")
  flag.BoolVar(&print6, "6", print6, "Print IPv6")
  flag.BoolVar(&external, "x", external, "Fetch external address")
  flag.BoolVar(&iface, "i", iface, "Fetch addresses per interface")
  flag.BoolVar(&excludeDocker, "nodocker", excludeDocker, "Exclude Docker interface")
  flag.StringVar(&docker, "dockernet", docker, "Docker network to exclude")
  flag.BoolVar(&printName, "name", printName, "Print interface name")
  flag.BoolVar(&printName, "n", printName, "Print interface name (alias)")
  flag.BoolVar(&printAll, "all", printAll, "Print all addresses")
  flag.BoolVar(&printAll, "a", printAll, "Print all addresses (alias)")
  flag.StringVar(&format, "fmt", format, "Output format")
  flag.BoolVar(&raw, "raw", raw, "Accept format string as-is (no newline)")
  flag.Parse()

  if !external && !iface {
    iface = true
  }

  var acceptable []net.IPNet
  var rejectable []net.IPNet
  rfc1918 := []net.IPNet{}

  for _, cidr := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
    _, parsed, err := net.ParseCIDR(cidr)
    if err != nil {
      log.Fatalln("Failed to parse RFC 1918 network", cidr)
    }
    rfc1918 = append(rfc1918, *parsed)
  }

  if excludeDocker {
    _, dockerNet, err := net.ParseCIDR(docker)
    if err != nil {
      log.Fatalln("Failed to parse Docker network", docker)
    }

    rejectable = append(rejectable, *dockerNet)
  }

  for _, arg := range flag.Args() {
    if len(arg) == 0 {
      continue
    }

    addTo := &acceptable
    if arg[0] == '!' || arg[0] == 'x' {
      addTo = &rejectable
      arg = arg[1:len(arg)]
    }

    network, err := parseNetwork(arg)
    if err != nil {
      log.Fatal(err)
    }

    *addTo = append(*addTo, *network)
  }

  found := make([]foundAddr, 0)

  var namedAddrs []namedAddr
  if external {
    namedAddrs = getExternalNamedAddrs()
  }
  if iface {
    namedAddrs = append(namedAddrs, getInterfaceNamedAddrs()...)
  }

  for _, addr := range namedAddrs {
    ip := addr.ip
    v6 := ip.To4() == nil
    if xor(print4, print6) && xor(print6, v6) {
      continue
    }
    found = append(found, foundAddr{
      IP: ip,
      preferred: anyContains(acceptable, ip),
      rejected: anyContains(rejectable, ip),
      isRfc1918: anyContains(rfc1918, ip),
      Loopback: ip.IsLoopback(),
      V6: v6,
      original: len(found),
      Name: addr.name,
      Wireless: isWirelessInterface(addr.name),
    })
  }

  if len(found) == 0 {
    os.Exit(1)
  }

  sort.Sort(ByAttributes{found})

  if format == "" {
    if printName {
      format = "{{.Name}}\t"
    }
    format += "{{.IP}}"
  }
  if !raw {
    format += "\n"
  }

  tmpl := template.Must(template.New("line").Parse(format))
  for _, addr := range found {
    err := tmpl.Execute(os.Stdout, addr)
    if err != nil {
      log.Fatal(err)
    }
    if !printAll {
      break
    }
  }
}
<|endoftext|>


<commit_before>package buffalo

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/gobuffalo/buffalo/binding"
	"github.com/gobuffalo/buffalo/render"
	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
)

// assert that DefaultContext is implementing Context
var _ Context = &DefaultContext{}
var _ context.Context = &DefaultContext{}

// DefaultContext is, as its name implies, a default
// implementation of the Context interface.
type DefaultContext struct {
	context.Context
	response    http.ResponseWriter
	request     *http.Request
	params      url.Values
	logger      Logger
	session     *Session
	contentType string
	data        map[string]interface{}
	flash       *Flash
}

// Response returns the original Response for the request.
func (d *DefaultContext) Response() http.ResponseWriter {
	return d.response
}

// Request returns the original Request.
func (d *DefaultContext) Request() *http.Request {
	return d.request
}

// Params returns all of the parameters for the request,
// including both named params and query string parameters.
func (d *DefaultContext) Params() ParamValues {
	return d.params
}

// Logger returns the Logger for this context.
func (d *DefaultContext) Logger() Logger {
	return d.logger
}

// Param returns a param, either named or query string,
// based on the key.
func (d *DefaultContext) Param(key string) string {
	return d.Params().Get(key)
}

// Set a value onto the Context. Any value set onto the Context
// will be automatically available in templates.
func (d *DefaultContext) Set(key string, value interface{}) {
	d.data[key] = value
}

// Value that has previously stored on the context.
func (d *DefaultContext) Value(key interface{}) interface{} {
	if k, ok := key.(string); ok {
		if v, ok := d.data[k]; ok {
			return v
		}
	}
	return d.Context.Value(key)
}

// Session for the associated Request.
func (d *DefaultContext) Session() *Session {
	return d.session
}

// Cookies for the associated request and response.
func (d *DefaultContext) Cookies() *Cookies {
	return &Cookies{d.request, d.response}
}

// Flash messages for the associated Request.
func (d *DefaultContext) Flash() *Flash {
	return d.flash
}

// Render a status code and render.Renderer to the associated Response.
// The request parameters will be made available to the render.Renderer
// "{{.params}}". Any values set onto the Context will also automatically
// be made available to the render.Renderer. To render "no content" pass
// in a nil render.Renderer.
func (d *DefaultContext) Render(status int, rr render.Renderer) error {
	start := time.Now()
	defer func() {
		d.LogField("render", time.Since(start))
	}()
	if rr != nil {
		data := d.data
		pp := map[string]string{}
		for k, v := range d.params {
			pp[k] = v[0]
		}
		data["params"] = pp
		data["flash"] = d.Flash().data
		data["session"] = d.Session()
		data["request"] = d.Request()
		bb := &bytes.Buffer{}

		err := rr.Render(bb, data)
		if err != nil {
			return HTTPError{Status: 500, Cause: errors.WithStack(err)}
		}

		if d.Session() != nil {
			d.Flash().Clear()
			d.Flash().persist(d.Session())
		}

		d.Response().Header().Set("Content-Type", rr.ContentType())
		d.Response().WriteHeader(status)
		_, err = io.Copy(d.Response(), bb)
		if err != nil {
			return HTTPError{Status: 500, Cause: errors.WithStack(err)}
		}

		return nil
	}
	d.Response().WriteHeader(status)
	return nil
}

// Bind the interface to the request.Body. The type of binding
// is dependent on the "Content-Type" for the request. If the type
// is "application/json" it will use "json.NewDecoder". If the type
// is "application/xml" it will use "xml.NewDecoder". See the
// github.com/gobuffalo/buffalo/binding package for more details.
func (d *DefaultContext) Bind(value interface{}) error {
	return binding.Exec(d.Request(), value)
}

// LogField adds the key/value pair onto the Logger to be printed out
// as part of the request logging. This allows you to easily add things
// like metrics (think DB times) to your request.
func (d *DefaultContext) LogField(key string, value interface{}) {
	d.logger = d.logger.WithField(key, value)
}

// LogFields adds the key/value pairs onto the Logger to be printed out
// as part of the request logging. This allows you to easily add things
// like metrics (think DB times) to your request.
func (d *DefaultContext) LogFields(values map[string]interface{}) {
	d.logger = d.logger.WithFields(values)
}

func (d *DefaultContext) Error(status int, err error) error {
	return HTTPError{Status: status, Cause: errors.WithStack(err)}
}

// Websocket returns an upgraded github.com/gorilla/websocket.Conn
// that can then be used to work with websockets easily.
func (d *DefaultContext) Websocket() (*websocket.Conn, error) {
	return defaultUpgrader.Upgrade(d.Response(), d.Request(), nil)
}

// Redirect a request with the given status to the given URL.
func (d *DefaultContext) Redirect(status int, url string, args ...interface{}) error {
	d.Flash().persist(d.Session())

	if len(args) > 0 {
		url = fmt.Sprintf(url, args...)
	}
	http.Redirect(d.Response(), d.Request(), url, status)
	return nil
}

// Data contains all the values set through Get/Set.
func (d *DefaultContext) Data() map[string]interface{} {
	return d.data
}

func (d *DefaultContext) String() string {
	bb := make([]string, 0, len(d.data))

	for k, v := range d.data {
		if _, ok := v.(RouteHelperFunc); !ok {
			bb = append(bb, fmt.Sprintf("%s: %s", k, v))
		}
	}
	sort.Strings(bb)
	return strings.Join(bb, "\n\n")
}

// File returns an uploaded file by name, or an error
func (d *DefaultContext) File(name string) (binding.File, error) {
	req := d.Request()
	if err := req.ParseMultipartForm(5 * 1024 * 1024); err != nil {
		return binding.File{}, err
	}
	f, h, err := req.FormFile(name)
	bf := binding.File{
		File:       f,
		FileHeader: h,
	}
	if err != nil {
		return bf, errors.WithStack(err)
	}
	return bf, nil
}

var defaultUpgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}
<commit_msg>deprecated Websocket on the context<commit_after>package buffalo

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"runtime"
	"sort"
	"strings"
	"time"

	"github.com/gobuffalo/buffalo/binding"
	"github.com/gobuffalo/buffalo/render"
	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
)

// assert that DefaultContext is implementing Context
var _ Context = &DefaultContext{}
var _ context.Context = &DefaultContext{}

// DefaultContext is, as its name implies, a default
// implementation of the Context interface.
type DefaultContext struct {
	context.Context
	response    http.ResponseWriter
	request     *http.Request
	params      url.Values
	logger      Logger
	session     *Session
	contentType string
	data        map[string]interface{}
	flash       *Flash
}

// Response returns the original Response for the request.
func (d *DefaultContext) Response() http.ResponseWriter {
	return d.response
}

// Request returns the original Request.
func (d *DefaultContext) Request() *http.Request {
	return d.request
}

// Params returns all of the parameters for the request,
// including both named params and query string parameters.
func (d *DefaultContext) Params() ParamValues {
	return d.params
}

// Logger returns the Logger for this context.
func (d *DefaultContext) Logger() Logger {
	return d.logger
}

// Param returns a param, either named or query string,
// based on the key.
func (d *DefaultContext) Param(key string) string {
	return d.Params().Get(key)
}

// Set a value onto the Context. Any value set onto the Context
// will be automatically available in templates.
func (d *DefaultContext) Set(key string, value interface{}) {
	d.data[key] = value
}

// Value that has previously stored on the context.
func (d *DefaultContext) Value(key interface{}) interface{} {
	if k, ok := key.(string); ok {
		if v, ok := d.data[k]; ok {
			return v
		}
	}
	return d.Context.Value(key)
}

// Session for the associated Request.
func (d *DefaultContext) Session() *Session {
	return d.session
}

// Cookies for the associated request and response.
func (d *DefaultContext) Cookies() *Cookies {
	return &Cookies{d.request, d.response}
}

// Flash messages for the associated Request.
func (d *DefaultContext) Flash() *Flash {
	return d.flash
}

// Render a status code and render.Renderer to the associated Response.
// The request parameters will be made available to the render.Renderer
// "{{.params}}". Any values set onto the Context will also automatically
// be made available to the render.Renderer. To render "no content" pass
// in a nil render.Renderer.
func (d *DefaultContext) Render(status int, rr render.Renderer) error {
	start := time.Now()
	defer func() {
		d.LogField("render", time.Since(start))
	}()
	if rr != nil {
		data := d.data
		pp := map[string]string{}
		for k, v := range d.params {
			pp[k] = v[0]
		}
		data["params"] = pp
		data["flash"] = d.Flash().data
		data["session"] = d.Session()
		data["request"] = d.Request()
		bb := &bytes.Buffer{}

		err := rr.Render(bb, data)
		if err != nil {
			return HTTPError{Status: 500, Cause: errors.WithStack(err)}
		}

		if d.Session() != nil {
			d.Flash().Clear()
			d.Flash().persist(d.Session())
		}

		d.Response().Header().Set("Content-Type", rr.ContentType())
		d.Response().WriteHeader(status)
		_, err = io.Copy(d.Response(), bb)
		if err != nil {
			return HTTPError{Status: 500, Cause: errors.WithStack(err)}
		}

		return nil
	}
	d.Response().WriteHeader(status)
	return nil
}

// Bind the interface to the request.Body. The type of binding
// is dependent on the "Content-Type" for the request. If the type
// is "application/json" it will use "json.NewDecoder". If the type
// is "application/xml" it will use "xml.NewDecoder". See the
// github.com/gobuffalo/buffalo/binding package for more details.
func (d *DefaultContext) Bind(value interface{}) error {
	return binding.Exec(d.Request(), value)
}

// LogField adds the key/value pair onto the Logger to be printed out
// as part of the request logging. This allows you to easily add things
// like metrics (think DB times) to your request.
func (d *DefaultContext) LogField(key string, value interface{}) {
	d.logger = d.logger.WithField(key, value)
}

// LogFields adds the key/value pairs onto the Logger to be printed out
// as part of the request logging. This allows you to easily add things
// like metrics (think DB times) to your request.
func (d *DefaultContext) LogFields(values map[string]interface{}) {
	d.logger = d.logger.WithFields(values)
}

func (d *DefaultContext) Error(status int, err error) error {
	return HTTPError{Status: status, Cause: errors.WithStack(err)}
}

// Websocket is deprecated, and will be removed in v0.12.0. Use github.com/gorilla/websocket directly instead.
func (d *DefaultContext) Websocket() (*websocket.Conn, error) {
	warningMsg := "Websocket is deprecated, and will be removed in v0.12.0. Use github.com/gorilla/websocket directly instead."
	_, file, no, ok := runtime.Caller(1)
	if ok {
		warningMsg = fmt.Sprintf("%s Called from %s:%d", warningMsg, file, no)
	}
	return defaultUpgrader.Upgrade(d.Response(), d.Request(), nil)
}

// Redirect a request with the given status to the given URL.
func (d *DefaultContext) Redirect(status int, url string, args ...interface{}) error {
	d.Flash().persist(d.Session())

	if len(args) > 0 {
		url = fmt.Sprintf(url, args...)
	}
	http.Redirect(d.Response(), d.Request(), url, status)
	return nil
}

// Data contains all the values set through Get/Set.
func (d *DefaultContext) Data() map[string]interface{} {
	return d.data
}

func (d *DefaultContext) String() string {
	bb := make([]string, 0, len(d.data))

	for k, v := range d.data {
		if _, ok := v.(RouteHelperFunc); !ok {
			bb = append(bb, fmt.Sprintf("%s: %s", k, v))
		}
	}
	sort.Strings(bb)
	return strings.Join(bb, "\n\n")
}

// File returns an uploaded file by name, or an error
func (d *DefaultContext) File(name string) (binding.File, error) {
	req := d.Request()
	if err := req.ParseMultipartForm(5 * 1024 * 1024); err != nil {
		return binding.File{}, err
	}
	f, h, err := req.FormFile(name)
	bf := binding.File{
		File:       f,
		FileHeader: h,
	}
	if err != nil {
		return bf, errors.WithStack(err)
	}
	return bf, nil
}

var defaultUpgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}
<|endoftext|>


<commit_before>package unusedaccounts

import (
	"time"

	"github.com/trackit/trackit/db"
	"github.com/trackit/trackit/models"
)

const unusedThreshold = time.Second * 15
const deleteThreshold = unusedThreshold + time.Second*45

var remaindersThresholds = []time.Duration{unusedThreshold, unusedThreshold + time.Second*15, unusedThreshold + time.Second*30}

// CheckUnusedAccounts checks for unused accounts, sends reminders and delete unused data
func CheckUnusedAccounts() error {
	users, err := models.GetUnusedAccounts(db.Db, unusedThreshold)

	if err != nil {
		return err
	}

	for _, user := range users {
		if user != nil {
			checkUnusedAccount(*user)
		}
	}

	return nil
}

func checkUnusedAccount(user models.User) error {
	unusedTime := time.Now().Sub(user.LastSeen)

	if unusedTime > deleteThreshold {
		return deleteData(user)
	}

	thresholdStage := 0
	for i, remainderThreshold := range remaindersThresholds {
		if unusedTime > remainderThreshold {
			thresholdStage = i
		} else {
			break
		}
	}

	var err error = nil

	if user.LastUnusedReminder.Sub(user.LastSeen) < remaindersThresholds[thresholdStage] {
		err = sendRemainder(user)

		user.LastUnusedReminder = time.Now()
		user.Update(db.Db)
	}

	return err
}
<commit_msg>Defined realistic thresholds for unused accounts<commit_after>package unusedaccounts

import (
	"time"

	"github.com/trackit/trackit/db"
	"github.com/trackit/trackit/models"
)

const day = time.Hour * 24
const month = day * 30

const unusedThreshold = month
const deleteThreshold = unusedThreshold + month

var remaindersThresholds = []time.Duration{unusedThreshold, unusedThreshold + (month - day*7), unusedThreshold + (month - day*3), unusedThreshold + (month - day*1)}

// CheckUnusedAccounts checks for unused accounts, sends reminders and delete unused data
func CheckUnusedAccounts() error {
	users, err := models.GetUnusedAccounts(db.Db, unusedThreshold)

	if err != nil {
		return err
	}

	for _, user := range users {
		if user != nil {
			checkUnusedAccount(*user)
		}
	}

	return nil
}

func checkUnusedAccount(user models.User) error {
	unusedTime := time.Now().Sub(user.LastSeen)

	if unusedTime > deleteThreshold {
		return deleteData(user)
	}

	thresholdStage := 0
	for i, remainderThreshold := range remaindersThresholds {
		if unusedTime > remainderThreshold {
			thresholdStage = i
		} else {
			break
		}
	}

	var err error = nil

	if user.LastUnusedReminder.Sub(user.LastSeen) < remaindersThresholds[thresholdStage] {
		err = sendRemainder(user)

		user.LastUnusedReminder = time.Now()
		user.Update(db.Db)
	}

	return err
}
<|endoftext|>