<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/go-ini/ini"
	_ "github.com/go-sql-driver/mysql"
)

// HTTPResponse Structure used to define response object of every route request
type HTTPResponse struct {
	Status  bool   `json:"status"`
	Content string `json:"content"`
}

// ResponseType Constant
const ResponseType = "application/json"

// ContentType Constant
const ContentType = "Content-Type"

var db *sql.DB
var lag int

func main() {

	var portstring string

	flag.StringVar(&portstring, "port", "3307", "Listening port")
	flag.Parse()

	cfg, err := ini.Load(os.Getenv("HOME") + "/.my.cnf")

	if err != nil {
		log.Panic(err)
	}

	dbUser := cfg.Section("client").Key("user").String()
	dbPass := cfg.Section("client").Key("password").String()
	dbHost := cfg.Section("client").Key("hostname").String()

	db, err = sql.Open("mysql", dbUser+":"+dbPass+"@"+dbHost+"/mysql")

	if err := db.Ping(); err != nil {
		log.Panic(err)
	}

	defer db.Close()

	router := http.NewServeMux()

	router.HandleFunc("/status/ro", RouteStatusReadOnly)
	router.HandleFunc("/status/rw", RouteStatusReadWritable)
	router.HandleFunc("/status/single", RouteStatusSingle)
	router.HandleFunc("/status/leader", RouteStatusLeader)
	router.HandleFunc("/status/follower", RouteStatusFollower)
	router.HandleFunc("/status/topology", RouteStatusTopology)

	router.HandleFunc("/role/master", RouteRoleMaster)
	router.HandleFunc("/role/replica", RouteRoleReplica)
	router.HandleFunc("/role/replica/", RouteRoleReplicaByLag)
	router.HandleFunc("/role/galera", RouteRoleGalera)

	router.HandleFunc("/read/galera/state", RouteReadGaleraState)
	router.HandleFunc("/read/replication/lag", RouteReadReplicationLag)
	router.HandleFunc("/read/replication/master", RouteReadReplicationMaster)
	router.HandleFunc("/read/replication/replicas_count", RouteReadReplicasCounter)

	log.Printf("Listening on port %s ...", portstring)

	err2 := http.ListenAndServe(":"+portstring, LogRequests(CheckURL(router)))
	log.Fatal(err2)
}

/*
 *	Middleware layers
 */

// LogRequests Middleware level to log API requests
func LogRequests(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		next.ServeHTTP(w, r)

		log.Printf(
			"[%s]\t%s\t%s",
			r.Method,
			r.URL.String(),
			time.Since(start),
		)
	})
}

// CheckURL Middleware level to validate requested URI
func CheckURL(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.String()
		pathLength := len(path)
		matchPath := "/role/replica/"
		matchLength := len(matchPath)

		if strings.Contains(path, matchPath) && pathLength > matchLength {
			lag, _ = strconv.Atoi(strings.Trim(path, matchPath))
		} else if strings.Compare(path, strings.TrimRight(path, "/")) != 0 {
			return
		}

		w.Header().Set(ContentType, ResponseType)

		next.ServeHTTP(w, r)
	})
}

/*
 *	General functions
 */

// int2bool Convert integers to boolean
func int2bool(value int) bool {
	if value != 0 {
		return true
	}

	return false
}

// unknownColumns Used to get value from specific column of a range of unknown columns
func unknownColumns(rows *sql.Rows, column string) string {
	columns, _ := rows.Columns()
	count := len(columns)
	values := make([]interface{}, count)
	valuePtrs := make([]interface{}, count)

	for rows.Next() {
		for i := range columns {
			valuePtrs[i] = &values[i]
		}

		rows.Scan(valuePtrs...)

		for i, col := range columns {

			var value interface{}

			val := values[i]

			b, ok := val.([]byte)

			if ok {
				value = string(b)
			} else {
				value = val
			}

			sNum := value.(string)

			if col == column {
				return sNum
			}
		}
	}

	return ""
}

// routeResponse Used to build response to API requests
func routeResponse(w http.ResponseWriter, httpStatus bool, contents string) {
	res := new(HTTPResponse)

	if httpStatus {
		w.WriteHeader(200)
	} else {
		w.WriteHeader(404)
	}

	res.Status = httpStatus
	res.Content = contents
	response, _ := json.Marshal(res)
	fmt.Fprintf(w, "%s", response)
}

/*
 *	Database functions
 */

// readOnly Check if database is in readonly mode, or not
func readOnly() bool {
	var state string
	var key string

	err := db.QueryRow("show variables like 'read_only'").Scan(&key, &state)

	if state == "OFF" || err != nil {
		return false
	}

	return true
}

// replicaStatus Read database status if it is a replica
func replicaStatus(lagCount int) (bool, int) {
	if lagCount == 0 {
		lagCount = 1<<63 - 1
	}

	rows, err := db.Query("show slave status")

	if err != nil {
		return false, 0
	}

	defer rows.Close()

	secondsBehindMaster := unknownColumns(rows, "Seconds_Behind_Master")

	if secondsBehindMaster == "" {
		secondsBehindMaster = "0"
	}

	lag, _ = strconv.Atoi(secondsBehindMaster)

	if lag > 0 {
		if lagCount > lag {
			return true, lag
		}

		return false, lag
	}

	return false, 0
}

// isReplica Get database's master, in case it is a replica
func isReplica() (bool, string) {
	rows, err := db.Query("show slave status")

	if err != nil {
		return false, ""
	}

	defer rows.Close()

	masterHost := unknownColumns(rows, "Master_Host")

	if masterHost != "" {
		return true, masterHost
	}

	return false, ""
}

// servingBinlogs ...
func servingBinlogs() int {
	var count int

	err := db.QueryRow(
		"select count(*) as n " +
			"from information_schema.processlist " +
			"where command = 'Binlog Dump'").Scan(&count)

	if err != nil {
		return 0
	}

	return count
}

// galeraClusterState ...
func galeraClusterState() (bool, string) {
	var v string

	err := db.QueryRow(
		"select variable_value as v " +
			"from information_schema.global_status " +
			"where variable_name like 'wsrep_local_state' = 4").Scan(&v)

	if err == sql.ErrNoRows || err != nil {
		return false, ""
	}

	return true, v
}

/*
 * Status routes
 */

// RouteStatusReadOnly ...
func RouteStatusReadOnly(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: readOnly...")
	isReadonly := readOnly()

	routeResponse(w, isReadonly, "")
}

// RouteStatusReadWritable ...
func RouteStatusReadWritable(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: readable and writable...")
	isReadonly := readOnly()

	routeResponse(w, !isReadonly, "")
}

// RouteStatusSingle ...
func RouteStatusSingle(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: single...")
	isReadonly := readOnly()
	isReplica, _ := isReplica()
	isServeLogs := int2bool(servingBinlogs())

	routeResponse(w, !isReadonly && !isReplica && !isServeLogs, "")
}

// RouteStatusLeader ...
func RouteStatusLeader(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: leader...")
	isReplica, _ := isReplica()
	isServeLogs := int2bool(servingBinlogs())

	routeResponse(w, !isReplica && isServeLogs, "")
}

// RouteStatusFollower ...
func RouteStatusFollower(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: follower...")
	isReplica, _ := isReplica()

	routeResponse(w, isReplica, "")

}

// RouteStatusTopology ...
func RouteStatusTopology(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: topology...")
	isReplica, _ := isReplica()
	replicaStatus, _ := replicaStatus(0)
	isServeLogs := int2bool(servingBinlogs())

	routeResponse(w, (!replicaStatus && isServeLogs) || isReplica, "")
}

/*
 * Roles routes
 */

// RouteRoleMaster ...
func RouteRoleMaster(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: master...")
	isReadonly := readOnly()
	isReplica, _ := isReplica()

	routeResponse(w, !isReadonly && !isReplica, "")
}

// RouteRoleReplica ...
func RouteRoleReplica(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: replica...")
	isReadonly := readOnly()
	replicaStatus, _ := replicaStatus(0)

	routeResponse(w, isReadonly && replicaStatus, "")
}

// RouteRoleReplicaByLag ...
func RouteRoleReplicaByLag(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: replica by lag...")
	isReadonly := readOnly()
	replicaStatus, _ := replicaStatus(lag)

	routeResponse(w, isReadonly && replicaStatus, "")
}

// RouteRoleGalera ...
func RouteRoleGalera(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: galera...")
	galeraClusterState, _ := galeraClusterState()

	routeResponse(w, galeraClusterState, "")
}

/*
 * Read routes
 */

// RouteReadGaleraState ...
func RouteReadGaleraState(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading database state: galera...")
	galeraClusterState, varValue := galeraClusterState()

	routeResponse(w, galeraClusterState, varValue)
}

// RouteReadReplicationLag ...
func RouteReadReplicationLag(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading database replication: lag...")
	lagString := ""
	isReplica, _ := isReplica()
	_, lagValue := replicaStatus(0)

	if isReplica {
		lagString = strconv.Itoa(lagValue)
	}

	routeResponse(w, isReplica, lagString)
}

// RouteReadReplicationMaster ...
func RouteReadReplicationMaster(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading database status: master...")
	lagString := ""
	isReplica, _ := isReplica()
	_, lagValue := replicaStatus(0)

	if isReplica {
		lagString = strconv.Itoa(lagValue)
	}

	routeResponse(w, isReplica, lagString)
}

// RouteReadReplicasCounter ...
func RouteReadReplicasCounter(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading counter of database replications...")
	lagString := "0"
	isServeLogs := servingBinlogs()

	if int2bool(isServeLogs) {
		lagString = strconv.Itoa(isServeLogs)
	}

	routeResponse(w, int2bool(isServeLogs), lagString)

}
<commit_msg>Changed http returned code on error<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/go-ini/ini"
	_ "github.com/go-sql-driver/mysql"
)

// HTTPResponse Structure used to define response object of every route request
type HTTPResponse struct {
	Status  bool   `json:"status"`
	Content string `json:"content"`
}

// ResponseType Constant
const ResponseType = "application/json"

// ContentType Constant
const ContentType = "Content-Type"

var db *sql.DB
var lag int

func main() {

	var portstring string

	flag.StringVar(&portstring, "port", "3307", "Listening port")
	flag.Parse()

	cfg, err := ini.Load(os.Getenv("HOME") + "/.my.cnf")

	if err != nil {
		log.Panic(err)
	}

	dbUser := cfg.Section("client").Key("user").String()
	dbPass := cfg.Section("client").Key("password").String()
	dbHost := cfg.Section("client").Key("hostname").String()

	db, err = sql.Open("mysql", dbUser+":"+dbPass+"@"+dbHost+"/mysql")

	if err := db.Ping(); err != nil {
		log.Panic(err)
	}

	defer db.Close()

	router := http.NewServeMux()

	router.HandleFunc("/status/ro", RouteStatusReadOnly)
	router.HandleFunc("/status/rw", RouteStatusReadWritable)
	router.HandleFunc("/status/single", RouteStatusSingle)
	router.HandleFunc("/status/leader", RouteStatusLeader)
	router.HandleFunc("/status/follower", RouteStatusFollower)
	router.HandleFunc("/status/topology", RouteStatusTopology)

	router.HandleFunc("/role/master", RouteRoleMaster)
	router.HandleFunc("/role/replica", RouteRoleReplica)
	router.HandleFunc("/role/replica/", RouteRoleReplicaByLag)
	router.HandleFunc("/role/galera", RouteRoleGalera)

	router.HandleFunc("/read/galera/state", RouteReadGaleraState)
	router.HandleFunc("/read/replication/lag", RouteReadReplicationLag)
	router.HandleFunc("/read/replication/master", RouteReadReplicationMaster)
	router.HandleFunc("/read/replication/replicas_count", RouteReadReplicasCounter)

	log.Printf("Listening on port %s ...", portstring)

	err2 := http.ListenAndServe(":"+portstring, LogRequests(CheckURL(router)))
	log.Fatal(err2)
}

/*
 *	Middleware layers
 */

// LogRequests Middleware level to log API requests
func LogRequests(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		next.ServeHTTP(w, r)

		log.Printf(
			"[%s]\t%s\t%s",
			r.Method,
			r.URL.String(),
			time.Since(start),
		)
	})
}

// CheckURL Middleware level to validate requested URI
func CheckURL(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.String()
		pathLength := len(path)
		matchPath := "/role/replica/"
		matchLength := len(matchPath)

		if strings.Contains(path, matchPath) && pathLength > matchLength {
			lag, _ = strconv.Atoi(strings.Trim(path, matchPath))
		} else if strings.Compare(path, strings.TrimRight(path, "/")) != 0 {
			return
		}

		w.Header().Set(ContentType, ResponseType)

		next.ServeHTTP(w, r)
	})
}

/*
 *	General functions
 */

// int2bool Convert integers to boolean
func int2bool(value int) bool {
	if value != 0 {
		return true
	}

	return false
}

// unknownColumns Used to get value from specific column of a range of unknown columns
func unknownColumns(rows *sql.Rows, column string) string {
	columns, _ := rows.Columns()
	count := len(columns)
	values := make([]interface{}, count)
	valuePtrs := make([]interface{}, count)

	for rows.Next() {
		for i := range columns {
			valuePtrs[i] = &values[i]
		}

		rows.Scan(valuePtrs...)

		for i, col := range columns {

			var value interface{}

			val := values[i]

			b, ok := val.([]byte)

			if ok {
				value = string(b)
			} else {
				value = val
			}

			sNum := value.(string)

			if col == column {
				return sNum
			}
		}
	}

	return ""
}

// routeResponse Used to build response to API requests
func routeResponse(w http.ResponseWriter, httpStatus bool, contents string) {
	res := new(HTTPResponse)

	if httpStatus {
		w.WriteHeader(200)
	} else {
		w.WriteHeader(403)
	}

	res.Status = httpStatus
	res.Content = contents
	response, _ := json.Marshal(res)
	fmt.Fprintf(w, "%s", response)
}

/*
 *	Database functions
 */

// readOnly Check if database is in readonly mode, or not
func readOnly() bool {
	var state string
	var key string

	err := db.QueryRow("show variables like 'read_only'").Scan(&key, &state)

	if state == "OFF" || err != nil {
		return false
	}

	return true
}

// replicaStatus Read database status if it is a replica
func replicaStatus(lagCount int) (bool, int) {
	if lagCount == 0 {
		lagCount = 1<<63 - 1
	}

	rows, err := db.Query("show slave status")

	if err != nil {
		return false, 0
	}

	defer rows.Close()

	secondsBehindMaster := unknownColumns(rows, "Seconds_Behind_Master")

	if secondsBehindMaster == "" {
		secondsBehindMaster = "0"
	}

	lag, _ = strconv.Atoi(secondsBehindMaster)

	if lag > 0 {
		if lagCount > lag {
			return true, lag
		}

		return false, lag
	}

	return false, 0
}

// isReplica Get database's master, in case it is a replica
func isReplica() (bool, string) {
	rows, err := db.Query("show slave status")

	if err != nil {
		return false, ""
	}

	defer rows.Close()

	masterHost := unknownColumns(rows, "Master_Host")

	if masterHost != "" {
		return true, masterHost
	}

	return false, ""
}

// servingBinlogs ...
func servingBinlogs() int {
	var count int

	err := db.QueryRow(
		"select count(*) as n " +
			"from information_schema.processlist " +
			"where command = 'Binlog Dump'").Scan(&count)

	if err != nil {
		return 0
	}

	return count
}

// galeraClusterState ...
func galeraClusterState() (bool, string) {
	var v string

	err := db.QueryRow(
		"select variable_value as v " +
			"from information_schema.global_status " +
			"where variable_name like 'wsrep_local_state' = 4").Scan(&v)

	if err == sql.ErrNoRows || err != nil {
		return false, ""
	}

	return true, v
}

/*
 * Status routes
 */

// RouteStatusReadOnly ...
func RouteStatusReadOnly(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: readOnly...")
	isReadonly := readOnly()

	routeResponse(w, isReadonly, "")
}

// RouteStatusReadWritable ...
func RouteStatusReadWritable(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: readable and writable...")
	isReadonly := readOnly()

	routeResponse(w, !isReadonly, "")
}

// RouteStatusSingle ...
func RouteStatusSingle(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: single...")
	isReadonly := readOnly()
	isReplica, _ := isReplica()
	isServeLogs := int2bool(servingBinlogs())

	routeResponse(w, !isReadonly && !isReplica && !isServeLogs, "")
}

// RouteStatusLeader ...
func RouteStatusLeader(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: leader...")
	isReplica, _ := isReplica()
	isServeLogs := int2bool(servingBinlogs())

	routeResponse(w, !isReplica && isServeLogs, "")
}

// RouteStatusFollower ...
func RouteStatusFollower(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: follower...")
	isReplica, _ := isReplica()

	routeResponse(w, isReplica, "")

}

// RouteStatusTopology ...
func RouteStatusTopology(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database status: topology...")
	isReplica, _ := isReplica()
	replicaStatus, _ := replicaStatus(0)
	isServeLogs := int2bool(servingBinlogs())

	routeResponse(w, (!replicaStatus && isServeLogs) || isReplica, "")
}

/*
 * Roles routes
 */

// RouteRoleMaster ...
func RouteRoleMaster(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: master...")
	isReadonly := readOnly()
	isReplica, _ := isReplica()

	routeResponse(w, !isReadonly && !isReplica, "")
}

// RouteRoleReplica ...
func RouteRoleReplica(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: replica...")
	isReadonly := readOnly()
	replicaStatus, _ := replicaStatus(0)

	routeResponse(w, isReadonly && replicaStatus, "")
}

// RouteRoleReplicaByLag ...
func RouteRoleReplicaByLag(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: replica by lag...")
	isReadonly := readOnly()
	replicaStatus, _ := replicaStatus(lag)

	routeResponse(w, isReadonly && replicaStatus, "")
}

// RouteRoleGalera ...
func RouteRoleGalera(w http.ResponseWriter, r *http.Request) {
	log.Print("Checking database role: galera...")
	galeraClusterState, _ := galeraClusterState()

	routeResponse(w, galeraClusterState, "")
}

/*
 * Read routes
 */

// RouteReadGaleraState ...
func RouteReadGaleraState(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading database state: galera...")
	galeraClusterState, varValue := galeraClusterState()

	routeResponse(w, galeraClusterState, varValue)
}

// RouteReadReplicationLag ...
func RouteReadReplicationLag(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading database replication: lag...")
	lagString := ""
	isReplica, _ := isReplica()
	_, lagValue := replicaStatus(0)

	if isReplica {
		lagString = strconv.Itoa(lagValue)
	}

	routeResponse(w, isReplica, lagString)
}

// RouteReadReplicationMaster ...
func RouteReadReplicationMaster(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading database status: master...")
	lagString := ""
	isReplica, _ := isReplica()
	_, lagValue := replicaStatus(0)

	if isReplica {
		lagString = strconv.Itoa(lagValue)
	}

	routeResponse(w, isReplica, lagString)
}

// RouteReadReplicasCounter ...
func RouteReadReplicasCounter(w http.ResponseWriter, r *http.Request) {
	log.Print("Reading counter of database replications...")
	lagString := "0"
	isServeLogs := servingBinlogs()

	if int2bool(isServeLogs) {
		lagString = strconv.Itoa(isServeLogs)
	}

	routeResponse(w, int2bool(isServeLogs), lagString)

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/kch42/gomcmap/mcmap"
	"github.com/mattn/go-gtk/gdk"
	"github.com/mattn/go-gtk/glib"
	"github.com/mattn/go-gtk/gtk"
	"math"
	"unsafe"
)

const (
	zoom          = 2
	tileSize      = zoom * mcmap.ChunkSizeXZ
	halfChunkSize = mcmap.ChunkSizeXZ / 2
)

type tileCmd int

const (
	cmdUpdateTiles tileCmd = iota
	cmdFlushTiles
	cmdSave
)

func renderTile(chunk *mcmap.Chunk) (maptile, biotile *gdk.Pixmap, biocache []mcmap.Biome) {
	maptile = emptyPixmap(tileSize, tileSize, 24)
	mtDrawable := maptile.GetDrawable()
	mtGC := gdk.NewGC(mtDrawable)

	biotile = emptyPixmap(tileSize, tileSize, 24)
	btDrawable := biotile.GetDrawable()
	btGC := gdk.NewGC(btDrawable)

	biocache = make([]mcmap.Biome, mcmap.ChunkRectXZ)

	i := 0
	for z := 0; z < mcmap.ChunkSizeXZ; z++ {
	scanX:
		for x := 0; x < mcmap.ChunkSizeXZ; x++ {
			bio := chunk.Biome(x, z)
			btGC.SetRgbFgColor(bioColors[bio])
			btDrawable.DrawRectangle(btGC, true, x*zoom, z*zoom, zoom, zoom)

			biocache[i] = bio
			i++

			for y := chunk.Height(x, z); y >= 0; y-- {
				if col, ok := blockColors[chunk.Block(x, y, z).ID]; ok {
					mtGC.SetRgbFgColor(col)
					mtDrawable.DrawRectangle(mtGC, true, x*zoom, z*zoom, zoom, zoom)
					continue scanX
				}
			}

			mtGC.SetRgbFgColor(gdk.NewColor("#ffffff"))
			mtDrawable.DrawRectangle(mtGC, true, x*zoom, z*zoom, zoom, zoom)
		}
	}

	return
}

type MapWidget struct {
	dArea *gtk.DrawingArea
	w, h  int

	reportFail func(msg string)
	updateInfo func(x, z int, bio mcmap.Biome)

	isInit bool

	showBiomes bool

	offX, offZ         int
	mx1, mx2, my1, my2 int

	pixmap   *gdk.Pixmap
	pixmapGC *gdk.GC
	gdkwin   *gdk.Window

	bg *gdk.Pixmap

	region *mcmap.Region

	maptiles map[XZPos]*gdk.Pixmap
	biotiles map[XZPos]*gdk.Pixmap
	bioCache map[XZPos][]mcmap.Biome

	redraw   chan bool
	tileCmds chan tileCmd
}

var (
	checker1 = gdk.NewColor("#222222")
	checker2 = gdk.NewColor("#444444")
)

func emptyPixmap(w, h, depth int) *gdk.Pixmap {
	return gdk.NewPixmap(new(gdk.Drawable), w, h, depth)
}

func (mw *MapWidget) SetShowBiomes(b bool) {
	mw.showBiomes = b
	mw.redraw <- true
}

func (mw *MapWidget) DArea() *gtk.DrawingArea { return mw.dArea }

func (mw *MapWidget) doTileCmds() {
	for cmd := range mw.tileCmds {
		switch cmd {
		case cmdSave:
			mw.region.Save()
		case cmdFlushTiles:
			gdk.ThreadsEnter()
			for _, mt := range mw.maptiles {
				mt.Unref()
			}
			for _, bt := range mw.biotiles {
				bt.Unref()
			}
			gdk.ThreadsLeave()

			mw.maptiles = make(map[XZPos]*gdk.Pixmap)
			mw.biotiles = make(map[XZPos]*gdk.Pixmap)
			mw.bioCache = make(map[XZPos][]mcmap.Biome)
		case cmdUpdateTiles:
			todelete := make(map[XZPos]bool)

			startX := int(math.Floor(float64(mw.offX) / tileSize))
			startZ := int(math.Floor(float64(mw.offZ) / tileSize))
			endX := int(math.Ceil(float64(mw.offX+mw.w) / tileSize))
			endZ := int(math.Ceil(float64(mw.offZ+mw.h) / tileSize))

			for pos := range mw.maptiles {
				if (pos.X < startX) || (pos.Z < startZ) || (pos.X >= endX) || (pos.Z >= endZ) {
					todelete[pos] = true
				}
			}

			gdk.ThreadsEnter()
			for pos := range todelete {
				if tile, ok := mw.maptiles[pos]; ok {
					tile.Unref()
					delete(mw.maptiles, pos)
				}

				if tile, ok := mw.biotiles[pos]; ok {
					tile.Unref()
					delete(mw.biotiles, pos)
				}

				if _, ok := mw.bioCache[pos]; ok {
					delete(mw.bioCache, pos)
				}
			}

			for z := startZ; z < endZ; z++ {
			scanX:
				for x := startX; x < endX; x++ {
					pos := XZPos{x, z}

					if _, ok := mw.biotiles[pos]; ok {
						continue scanX
					}

					chunk, err := mw.region.Chunk(x, z)
					switch err {
					case nil:
					case mcmap.NotAvailable:
						continue scanX
					default:
						mw.reportFail(fmt.Sprintf("Could not get chunk %d, %d: %s", x, z, err))
						return
					}

					mw.maptiles[pos], mw.biotiles[pos], mw.bioCache[pos] = renderTile(chunk)
					chunk.MarkUnused()

					gdk.ThreadsLeave()
					mw.redraw <- true
					gdk.ThreadsEnter()
				}
			}

			gdk.ThreadsLeave()
		}
	}
}

func (mw *MapWidget) configure() {
	if mw.pixmap != nil {
		mw.pixmap.Unref()
	}

	alloc := mw.dArea.GetAllocation()
	mw.w = alloc.Width
	mw.h = alloc.Height

	if !mw.isInit {
		mw.offX = -(mw.w / 2)
		mw.offZ = -(mw.h / 2)
		mw.isInit = true
	}

	mw.pixmap = gdk.NewPixmap(mw.dArea.GetWindow().GetDrawable(), mw.w, mw.h, 24)
	mw.pixmapGC = gdk.NewGC(mw.pixmap.GetDrawable())

	mw.drawBg()
	gdk.ThreadsLeave()
	mw.redraw <- true
	gdk.ThreadsEnter()
}

func (mw *MapWidget) drawBg() {
	if mw.bg != nil {
		mw.bg.Unref()
	}

	mw.bg = emptyPixmap(mw.w, mw.h, 24)
	drawable := mw.bg.GetDrawable()
	gc := gdk.NewGC(drawable)

	w := (mw.w + 16) / 32
	h := (mw.h + 16) / 32

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			if (x % 2) == (y % 2) {
				gc.SetRgbFgColor(checker1)
			} else {
				gc.SetRgbFgColor(checker2)
			}
			drawable.DrawRectangle(gc, true, x*32, y*32, 32, 32)
		}
	}
}

func (mw *MapWidget) compose() {
	drawable := mw.pixmap.GetDrawable()
	gc := mw.pixmapGC

	drawable.DrawDrawable(gc, mw.bg.GetDrawable(), 0, 0, 0, 0, -1, -1)

	var tiles map[XZPos]*gdk.Pixmap
	if mw.showBiomes {
		tiles = mw.biotiles
	} else {
		tiles = mw.maptiles
	}

	for pos, tile := range tiles {
		x := (pos.X * tileSize) - mw.offX
		y := (pos.Z * tileSize) - mw.offZ

		drawable.DrawDrawable(gc, tile.GetDrawable(), 0, 0, x, y, tileSize, tileSize)
	}
}

func (mw *MapWidget) movement(ctx *glib.CallbackContext) {
	if mw.gdkwin == nil {
		mw.gdkwin = mw.dArea.GetWindow()
	}
	arg := ctx.Args(0)
	mev := *(**gdk.EventMotion)(unsafe.Pointer(&arg))
	var mt gdk.ModifierType
	if mev.IsHint != 0 {
		mw.gdkwin.GetPointer(&(mw.mx2), &(mw.my2), &mt)
	} else {
		mw.mx2, mw.my2 = int(mev.X), int(mev.Y)
	}

	x := (mw.offX + mw.mx2) / zoom
	z := (mw.offZ + mw.my2) / zoom
	cx, cz, cbx, cbz := mcmap.BlockToChunk(x, z)
	bio := mcmap.Biome(mcmap.BioUncalculated)
	if bc, ok := mw.bioCache[XZPos{cx, cz}]; ok {
		bio = bc[cbz*mcmap.ChunkSizeXZ+cbx]
	}
	mw.updateInfo(x, z, bio)

	switch {
	case mt&gdk.BUTTON1_MASK != 0:
	case mt&gdk.BUTTON2_MASK != 0:
		if (mw.mx1 != -1) && (mw.my1 != -1) {
			mw.offX += mw.mx1 - mw.mx2
			mw.offZ += mw.my1 - mw.my2

			gdk.ThreadsLeave()
			mw.tileCmds <- cmdUpdateTiles
			gdk.ThreadsEnter()
		}
	}

	mw.mx1, mw.my1 = mw.mx2, mw.my2
}

func (mw *MapWidget) expose() {
	mw.dArea.GetWindow().GetDrawable().DrawDrawable(mw.pixmapGC, mw.pixmap.GetDrawable(), 0, 0, 0, 0, -1, -1)
}

func (mw *MapWidget) guiUpdater() {
	for _ = range mw.redraw {
		gdk.ThreadsEnter()
		mw.compose()
		mw.expose()
		mw.dArea.GetWindow().Invalidate(nil, false)
		gdk.ThreadsLeave()
	}
}

func (mw *MapWidget) init() {
	mw.redraw = make(chan bool)
	mw.tileCmds = make(chan tileCmd)

	mw.maptiles = make(map[XZPos]*gdk.Pixmap)
	mw.biotiles = make(map[XZPos]*gdk.Pixmap)
	mw.bioCache = make(map[XZPos][]mcmap.Biome)

	mw.showBiomes = true

	mw.mx1, mw.my1 = -1, -1

	go mw.doTileCmds()
	go mw.guiUpdater()

	mw.dArea = gtk.NewDrawingArea()
	mw.dArea.Connect("configure-event", mw.configure)
	mw.dArea.Connect("expose-event", mw.expose)
	mw.dArea.Connect("motion-notify-event", mw.movement)

	mw.dArea.SetEvents(int(gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK | gdk.BUTTON_PRESS_MASK))
}

func (mw *MapWidget) setRegion(region *mcmap.Region) {
	mw.tileCmds <- cmdFlushTiles
	mw.region = region
	mw.tileCmds <- cmdUpdateTiles
}

func NewMapWidget(reportFail func(msg string), updateInfo func(x, z int, bio mcmap.Biome)) *MapWidget {
	mw := &MapWidget{reportFail: reportFail, updateInfo: updateInfo}
	mw.init()
	return mw
}
<commit_msg>Fixing checkerboard background<commit_after>package main

import (
	"fmt"
	"github.com/kch42/gomcmap/mcmap"
	"github.com/mattn/go-gtk/gdk"
	"github.com/mattn/go-gtk/glib"
	"github.com/mattn/go-gtk/gtk"
	"math"
	"unsafe"
)

const (
	zoom          = 2
	tileSize      = zoom * mcmap.ChunkSizeXZ
	halfChunkSize = mcmap.ChunkSizeXZ / 2
)

type tileCmd int

const (
	cmdUpdateTiles tileCmd = iota
	cmdFlushTiles
	cmdSave
)

func renderTile(chunk *mcmap.Chunk) (maptile, biotile *gdk.Pixmap, biocache []mcmap.Biome) {
	maptile = emptyPixmap(tileSize, tileSize, 24)
	mtDrawable := maptile.GetDrawable()
	mtGC := gdk.NewGC(mtDrawable)

	biotile = emptyPixmap(tileSize, tileSize, 24)
	btDrawable := biotile.GetDrawable()
	btGC := gdk.NewGC(btDrawable)

	biocache = make([]mcmap.Biome, mcmap.ChunkRectXZ)

	i := 0
	for z := 0; z < mcmap.ChunkSizeXZ; z++ {
	scanX:
		for x := 0; x < mcmap.ChunkSizeXZ; x++ {
			bio := chunk.Biome(x, z)
			btGC.SetRgbFgColor(bioColors[bio])
			btDrawable.DrawRectangle(btGC, true, x*zoom, z*zoom, zoom, zoom)

			biocache[i] = bio
			i++

			for y := chunk.Height(x, z); y >= 0; y-- {
				if col, ok := blockColors[chunk.Block(x, y, z).ID]; ok {
					mtGC.SetRgbFgColor(col)
					mtDrawable.DrawRectangle(mtGC, true, x*zoom, z*zoom, zoom, zoom)
					continue scanX
				}
			}

			mtGC.SetRgbFgColor(gdk.NewColor("#ffffff"))
			mtDrawable.DrawRectangle(mtGC, true, x*zoom, z*zoom, zoom, zoom)
		}
	}

	return
}

type MapWidget struct {
	dArea *gtk.DrawingArea
	w, h  int

	reportFail func(msg string)
	updateInfo func(x, z int, bio mcmap.Biome)

	isInit bool

	showBiomes bool

	offX, offZ         int
	mx1, mx2, my1, my2 int

	pixmap   *gdk.Pixmap
	pixmapGC *gdk.GC
	gdkwin   *gdk.Window

	bg *gdk.Pixmap

	region *mcmap.Region

	maptiles map[XZPos]*gdk.Pixmap
	biotiles map[XZPos]*gdk.Pixmap
	bioCache map[XZPos][]mcmap.Biome

	redraw   chan bool
	tileCmds chan tileCmd
}

var (
	checker1 = gdk.NewColor("#222222")
	checker2 = gdk.NewColor("#444444")
)

func emptyPixmap(w, h, depth int) *gdk.Pixmap {
	return gdk.NewPixmap(new(gdk.Drawable), w, h, depth)
}

func (mw *MapWidget) SetShowBiomes(b bool) {
	mw.showBiomes = b
	mw.redraw <- true
}

func (mw *MapWidget) DArea() *gtk.DrawingArea { return mw.dArea }

func (mw *MapWidget) doTileCmds() {
	for cmd := range mw.tileCmds {
		switch cmd {
		case cmdSave:
			mw.region.Save()
		case cmdFlushTiles:
			gdk.ThreadsEnter()
			for _, mt := range mw.maptiles {
				mt.Unref()
			}
			for _, bt := range mw.biotiles {
				bt.Unref()
			}
			gdk.ThreadsLeave()

			mw.maptiles = make(map[XZPos]*gdk.Pixmap)
			mw.biotiles = make(map[XZPos]*gdk.Pixmap)
			mw.bioCache = make(map[XZPos][]mcmap.Biome)
		case cmdUpdateTiles:
			todelete := make(map[XZPos]bool)

			startX := int(math.Floor(float64(mw.offX) / tileSize))
			startZ := int(math.Floor(float64(mw.offZ) / tileSize))
			endX := int(math.Ceil(float64(mw.offX+mw.w) / tileSize))
			endZ := int(math.Ceil(float64(mw.offZ+mw.h) / tileSize))

			for pos := range mw.maptiles {
				if (pos.X < startX) || (pos.Z < startZ) || (pos.X >= endX) || (pos.Z >= endZ) {
					todelete[pos] = true
				}
			}

			gdk.ThreadsEnter()
			for pos := range todelete {
				if tile, ok := mw.maptiles[pos]; ok {
					tile.Unref()
					delete(mw.maptiles, pos)
				}

				if tile, ok := mw.biotiles[pos]; ok {
					tile.Unref()
					delete(mw.biotiles, pos)
				}

				if _, ok := mw.bioCache[pos]; ok {
					delete(mw.bioCache, pos)
				}
			}

			for z := startZ; z < endZ; z++ {
			scanX:
				for x := startX; x < endX; x++ {
					pos := XZPos{x, z}

					if _, ok := mw.biotiles[pos]; ok {
						continue scanX
					}

					chunk, err := mw.region.Chunk(x, z)
					switch err {
					case nil:
					case mcmap.NotAvailable:
						continue scanX
					default:
						mw.reportFail(fmt.Sprintf("Could not get chunk %d, %d: %s", x, z, err))
						return
					}

					mw.maptiles[pos], mw.biotiles[pos], mw.bioCache[pos] = renderTile(chunk)
					chunk.MarkUnused()

					gdk.ThreadsLeave()
					mw.redraw <- true
					gdk.ThreadsEnter()
				}
			}

			gdk.ThreadsLeave()
		}
	}
}

func (mw *MapWidget) configure() {
	if mw.pixmap != nil {
		mw.pixmap.Unref()
	}

	alloc := mw.dArea.GetAllocation()
	mw.w = alloc.Width
	mw.h = alloc.Height

	if !mw.isInit {
		mw.offX = -(mw.w / 2)
		mw.offZ = -(mw.h / 2)
		mw.isInit = true
	}

	mw.pixmap = gdk.NewPixmap(mw.dArea.GetWindow().GetDrawable(), mw.w, mw.h, 24)
	mw.pixmapGC = gdk.NewGC(mw.pixmap.GetDrawable())

	mw.drawBg()
	gdk.ThreadsLeave()
	mw.redraw <- true
	gdk.ThreadsEnter()
}

func (mw *MapWidget) drawBg() {
	if mw.bg != nil {
		mw.bg.Unref()
	}

	mw.bg = emptyPixmap(mw.w, mw.h, 24)
	drawable := mw.bg.GetDrawable()
	gc := gdk.NewGC(drawable)

	w := int(math.Ceil(float64(mw.w) / 32))
	h := int(math.Ceil(float64(mw.h) / 32))

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			if (x % 2) == (y % 2) {
				gc.SetRgbFgColor(checker1)
			} else {
				gc.SetRgbFgColor(checker2)
			}
			drawable.DrawRectangle(gc, true, x*32, y*32, 32, 32)
		}
	}
}

func (mw *MapWidget) compose() {
	drawable := mw.pixmap.GetDrawable()
	gc := mw.pixmapGC

	drawable.DrawDrawable(gc, mw.bg.GetDrawable(), 0, 0, 0, 0, -1, -1)

	var tiles map[XZPos]*gdk.Pixmap
	if mw.showBiomes {
		tiles = mw.biotiles
	} else {
		tiles = mw.maptiles
	}

	for pos, tile := range tiles {
		x := (pos.X * tileSize) - mw.offX
		y := (pos.Z * tileSize) - mw.offZ

		drawable.DrawDrawable(gc, tile.GetDrawable(), 0, 0, x, y, tileSize, tileSize)
	}
}

func (mw *MapWidget) movement(ctx *glib.CallbackContext) {
	if mw.gdkwin == nil {
		mw.gdkwin = mw.dArea.GetWindow()
	}
	arg := ctx.Args(0)
	mev := *(**gdk.EventMotion)(unsafe.Pointer(&arg))
	var mt gdk.ModifierType
	if mev.IsHint != 0 {
		mw.gdkwin.GetPointer(&(mw.mx2), &(mw.my2), &mt)
	} else {
		mw.mx2, mw.my2 = int(mev.X), int(mev.Y)
	}

	x := (mw.offX + mw.mx2) / zoom
	z := (mw.offZ + mw.my2) / zoom
	cx, cz, cbx, cbz := mcmap.BlockToChunk(x, z)
	bio := mcmap.Biome(mcmap.BioUncalculated)
	if bc, ok := mw.bioCache[XZPos{cx, cz}]; ok {
		bio = bc[cbz*mcmap.ChunkSizeXZ+cbx]
	}
	mw.updateInfo(x, z, bio)

	switch {
	case mt&gdk.BUTTON1_MASK != 0:
	case mt&gdk.BUTTON2_MASK != 0:
		if (mw.mx1 != -1) && (mw.my1 != -1) {
			mw.offX += mw.mx1 - mw.mx2
			mw.offZ += mw.my1 - mw.my2

			gdk.ThreadsLeave()
			mw.tileCmds <- cmdUpdateTiles
			gdk.ThreadsEnter()
		}
	}

	mw.mx1, mw.my1 = mw.mx2, mw.my2
}

func (mw *MapWidget) expose() {
	mw.dArea.GetWindow().GetDrawable().DrawDrawable(mw.pixmapGC, mw.pixmap.GetDrawable(), 0, 0, 0, 0, -1, -1)
}

func (mw *MapWidget) guiUpdater() {
	for _ = range mw.redraw {
		gdk.ThreadsEnter()
		mw.compose()
		mw.expose()
		mw.dArea.GetWindow().Invalidate(nil, false)
		gdk.ThreadsLeave()
	}
}

func (mw *MapWidget) init() {
	mw.redraw = make(chan bool)
	mw.tileCmds = make(chan tileCmd)

	mw.maptiles = make(map[XZPos]*gdk.Pixmap)
	mw.biotiles = make(map[XZPos]*gdk.Pixmap)
	mw.bioCache = make(map[XZPos][]mcmap.Biome)

	mw.showBiomes = true

	mw.mx1, mw.my1 = -1, -1

	go mw.doTileCmds()
	go mw.guiUpdater()

	mw.dArea = gtk.NewDrawingArea()
	mw.dArea.Connect("configure-event", mw.configure)
	mw.dArea.Connect("expose-event", mw.expose)
	mw.dArea.Connect("motion-notify-event", mw.movement)

	mw.dArea.SetEvents(int(gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK | gdk.BUTTON_PRESS_MASK))
}

func (mw *MapWidget) setRegion(region *mcmap.Region) {
	mw.tileCmds <- cmdFlushTiles
	mw.region = region
	mw.tileCmds <- cmdUpdateTiles
}

func NewMapWidget(reportFail func(msg string), updateInfo func(x, z int, bio mcmap.Biome)) *MapWidget {
	mw := &MapWidget{reportFail: reportFail, updateInfo: updateInfo}
	mw.init()
	return mw
}
<|endoftext|>


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

package bleve

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/blevesearch/bleve/analysis"
	"github.com/blevesearch/bleve/search"
)

type numericRange struct {
	Name string   `json:"name,omitempty"`
	Min  *float64 `json:"min,omitempty"`
	Max  *float64 `json:"max,omitempty"`
}

type dateTimeRange struct {
	Name        string    `json:"name,omitempty"`
	Start       time.Time `json:"start,omitempty"`
	End         time.Time `json:"end,omitempty"`
	startString *string
	endString   *string
}

func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) {
	if dr.Start.IsZero() && dr.startString != nil {
		start, err := dateTimeParser.ParseDateTime(*dr.startString)
		if err == nil {
			dr.Start = start
		}
	}
	if dr.End.IsZero() && dr.endString != nil {
		end, err := dateTimeParser.ParseDateTime(*dr.endString)
		if err == nil {
			dr.End = end
		}
	}
}

func (dr *dateTimeRange) UnmarshalJSON(input []byte) error {
	var temp struct {
		Name  string  `json:"name,omitempty"`
		Start *string `json:"start,omitempty"`
		End   *string `json:"end,omitempty"`
	}

	err := json.Unmarshal(input, &temp)
	if err != nil {
		return err
	}

	dr.Name = temp.Name
	if temp.Start != nil {
		dr.startString = temp.Start
	}
	if temp.End != nil {
		dr.endString = temp.End
	}

	return nil
}

// A FacetRequest describes a facet or aggregation
// of the result document set you would like to be
// built.
type FacetRequest struct {
	Size           int
	Field          string
	NumericRanges  []*numericRange  `json:"numeric_ranges,omitempty"`
	DateTimeRanges []*dateTimeRange `json:"date_ranges,omitempty"`
}

// NewFacetRequest creates a facet on the specified
// field that limits the number of entries to the
// specified size.
func NewFacetRequest(field string, size int) *FacetRequest {
	return &FacetRequest{
		Field: field,
		Size:  size,
	}
}

// AddDateTimeRange adds a bucket to a field
// containing date values.  Documents with a
// date value falling into this range are tabulated
// as part of this bucket/range.
func (fr *FacetRequest) AddDateTimeRange(name string, start, end time.Time) {
	if fr.DateTimeRanges == nil {
		fr.DateTimeRanges = make([]*dateTimeRange, 0, 1)
	}
	fr.DateTimeRanges = append(fr.DateTimeRanges, &dateTimeRange{Name: name, Start: start, End: end})
}

// AddNumericRange adds a bucket to a field
// containing numeric values.  Documents with a
// numeric value falling into this range are
// tabulated as part of this bucket/range.
func (fr *FacetRequest) AddNumericRange(name string, min, max *float64) {
	if fr.NumericRanges == nil {
		fr.NumericRanges = make([]*numericRange, 0, 1)
	}
	fr.NumericRanges = append(fr.NumericRanges, &numericRange{Name: name, Min: min, Max: max})
}

// FacetsRequest groups together all the
// FacetRequest objects for a single query.
type FacetsRequest map[string]*FacetRequest

// HighlightRequest describes how field matches
// should be highlighted.
type HighlightRequest struct {
	Style  *string  `json:"style"`
	Fields []string `json:"fields"`
}

// NewHighlight creates a default
// HighlightRequest.
func NewHighlight() *HighlightRequest {
	return &HighlightRequest{}
}

// NewHighlightWithStyle creates a HighlightRequest
// with an alternate style.
func NewHighlightWithStyle(style string) *HighlightRequest {
	return &HighlightRequest{
		Style: &style,
	}
}

func (h *HighlightRequest) AddField(field string) {
	if h.Fields == nil {
		h.Fields = make([]string, 0, 1)
	}
	h.Fields = append(h.Fields, field)
}

// A SearchRequest describes all the parameters
// needed to search the index.
// Query is required.
// Size/From describe how much and which part of the
// result set to return.
// Highlight describes optional search result
// highlighting.
// Fields describes a list of field values which
// should be retrieved for result documents.
// Facets describe the set of facets to be computed.
// Explain triggers inclusion of additional search
// result score explanations.
//
// A special field named "*" can be used to return all fields.
type SearchRequest struct {
	Query     Query             `json:"query"`
	Size      int               `json:"size"`
	From      int               `json:"from"`
	Highlight *HighlightRequest `json:"highlight"`
	Fields    []string          `json:"fields"`
	Facets    FacetsRequest     `json:"facets"`
	Explain   bool              `json:"explain"`
}

// AddFacet adds a FacetRequest to this SearchRequest
func (r *SearchRequest) AddFacet(facetName string, f *FacetRequest) {
	if r.Facets == nil {
		r.Facets = make(FacetsRequest, 1)
	}
	r.Facets[facetName] = f
}

// UnmarshalJSON deserializes a JSON representation of
// a SearchRequest
func (r *SearchRequest) UnmarshalJSON(input []byte) error {
	var temp struct {
		Q         json.RawMessage   `json:"query"`
		Size      int               `json:"size"`
		From      int               `json:"from"`
		Highlight *HighlightRequest `json:"highlight"`
		Fields    []string          `json:"fields"`
		Facets    FacetsRequest     `json:"facets"`
		Explain   bool              `json:"explain"`
	}

	err := json.Unmarshal(input, &temp)
	if err != nil {
		return err
	}

	r.Size = temp.Size
	r.From = temp.From
	r.Explain = temp.Explain
	r.Highlight = temp.Highlight
	r.Fields = temp.Fields
	r.Facets = temp.Facets
	r.Query, err = ParseQuery(temp.Q)
	if err != nil {
		return err
	}

	if r.Size < 0 {
		r.Size = 10
	}
	if r.From < 0 {
		r.From = 0
	}

	return nil

}

// NewSearchRequest creates a new SearchRequest
// for the Query, using default values for all
// other search parameters.
func NewSearchRequest(q Query) *SearchRequest {
	return NewSearchRequestOptions(q, 10, 0, false)
}

// NewSearchRequestOptions creates a new SearchRequest
// for the Query, with the requested size, from
// and explanation search parameters.
func NewSearchRequestOptions(q Query, size, from int, explain bool) *SearchRequest {
	return &SearchRequest{
		Query:   q,
		Size:    size,
		From:    from,
		Explain: explain,
	}
}

// A SearchResult describes the results of executing
// a SearchRequest.
type SearchResult struct {
	Request  *SearchRequest                 `json:"request"`
	Hits     search.DocumentMatchCollection `json:"hits"`
	Total    uint64                         `json:"total_hits"`
	MaxScore float64                        `json:"max_score"`
	Took     time.Duration                  `json:"took"`
	Facets   search.FacetResults            `json:"facets"`
}

func (sr *SearchResult) String() string {
	rv := ""
	if sr.Total > 0 {
		if sr.Request.Size > 0 {
			rv = fmt.Sprintf("%d matches, showing %d through %d, took %s\n", sr.Total, sr.Request.From+1, sr.Request.From+len(sr.Hits), sr.Took)
			for i, hit := range sr.Hits {
				rv += fmt.Sprintf("%5d. %s (%f)\n", i+sr.Request.From+1, hit.ID, hit.Score)
				for fragmentField, fragments := range hit.Fragments {
					rv += fmt.Sprintf("\t%s\n", fragmentField)
					for _, fragment := range fragments {
						rv += fmt.Sprintf("\t\t%s\n", fragment)
					}
				}
			}
		} else {
			rv = fmt.Sprintf("%d matches, took %s\n", sr.Total, sr.Took)
		}
	} else {
		rv = "No matches"
	}
	return rv
}

func (sr *SearchResult) Merge(other *SearchResult) {
	sr.Hits = append(sr.Hits, other.Hits...)
	sr.Total += other.Total
	sr.Took += other.Took
	if other.MaxScore > sr.MaxScore {
		sr.MaxScore = other.MaxScore
	}
	sr.Facets.Merge(other.Facets)
}
<commit_msg>also print out the requested stored fields<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package bleve

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/blevesearch/bleve/analysis"
	"github.com/blevesearch/bleve/search"
)

type numericRange struct {
	Name string   `json:"name,omitempty"`
	Min  *float64 `json:"min,omitempty"`
	Max  *float64 `json:"max,omitempty"`
}

type dateTimeRange struct {
	Name        string    `json:"name,omitempty"`
	Start       time.Time `json:"start,omitempty"`
	End         time.Time `json:"end,omitempty"`
	startString *string
	endString   *string
}

func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) {
	if dr.Start.IsZero() && dr.startString != nil {
		start, err := dateTimeParser.ParseDateTime(*dr.startString)
		if err == nil {
			dr.Start = start
		}
	}
	if dr.End.IsZero() && dr.endString != nil {
		end, err := dateTimeParser.ParseDateTime(*dr.endString)
		if err == nil {
			dr.End = end
		}
	}
}

func (dr *dateTimeRange) UnmarshalJSON(input []byte) error {
	var temp struct {
		Name  string  `json:"name,omitempty"`
		Start *string `json:"start,omitempty"`
		End   *string `json:"end,omitempty"`
	}

	err := json.Unmarshal(input, &temp)
	if err != nil {
		return err
	}

	dr.Name = temp.Name
	if temp.Start != nil {
		dr.startString = temp.Start
	}
	if temp.End != nil {
		dr.endString = temp.End
	}

	return nil
}

// A FacetRequest describes a facet or aggregation
// of the result document set you would like to be
// built.
type FacetRequest struct {
	Size           int
	Field          string
	NumericRanges  []*numericRange  `json:"numeric_ranges,omitempty"`
	DateTimeRanges []*dateTimeRange `json:"date_ranges,omitempty"`
}

// NewFacetRequest creates a facet on the specified
// field that limits the number of entries to the
// specified size.
func NewFacetRequest(field string, size int) *FacetRequest {
	return &FacetRequest{
		Field: field,
		Size:  size,
	}
}

// AddDateTimeRange adds a bucket to a field
// containing date values.  Documents with a
// date value falling into this range are tabulated
// as part of this bucket/range.
func (fr *FacetRequest) AddDateTimeRange(name string, start, end time.Time) {
	if fr.DateTimeRanges == nil {
		fr.DateTimeRanges = make([]*dateTimeRange, 0, 1)
	}
	fr.DateTimeRanges = append(fr.DateTimeRanges, &dateTimeRange{Name: name, Start: start, End: end})
}

// AddNumericRange adds a bucket to a field
// containing numeric values.  Documents with a
// numeric value falling into this range are
// tabulated as part of this bucket/range.
func (fr *FacetRequest) AddNumericRange(name string, min, max *float64) {
	if fr.NumericRanges == nil {
		fr.NumericRanges = make([]*numericRange, 0, 1)
	}
	fr.NumericRanges = append(fr.NumericRanges, &numericRange{Name: name, Min: min, Max: max})
}

// FacetsRequest groups together all the
// FacetRequest objects for a single query.
type FacetsRequest map[string]*FacetRequest

// HighlightRequest describes how field matches
// should be highlighted.
type HighlightRequest struct {
	Style  *string  `json:"style"`
	Fields []string `json:"fields"`
}

// NewHighlight creates a default
// HighlightRequest.
func NewHighlight() *HighlightRequest {
	return &HighlightRequest{}
}

// NewHighlightWithStyle creates a HighlightRequest
// with an alternate style.
func NewHighlightWithStyle(style string) *HighlightRequest {
	return &HighlightRequest{
		Style: &style,
	}
}

func (h *HighlightRequest) AddField(field string) {
	if h.Fields == nil {
		h.Fields = make([]string, 0, 1)
	}
	h.Fields = append(h.Fields, field)
}

// A SearchRequest describes all the parameters
// needed to search the index.
// Query is required.
// Size/From describe how much and which part of the
// result set to return.
// Highlight describes optional search result
// highlighting.
// Fields describes a list of field values which
// should be retrieved for result documents.
// Facets describe the set of facets to be computed.
// Explain triggers inclusion of additional search
// result score explanations.
//
// A special field named "*" can be used to return all fields.
type SearchRequest struct {
	Query     Query             `json:"query"`
	Size      int               `json:"size"`
	From      int               `json:"from"`
	Highlight *HighlightRequest `json:"highlight"`
	Fields    []string          `json:"fields"`
	Facets    FacetsRequest     `json:"facets"`
	Explain   bool              `json:"explain"`
}

// AddFacet adds a FacetRequest to this SearchRequest
func (r *SearchRequest) AddFacet(facetName string, f *FacetRequest) {
	if r.Facets == nil {
		r.Facets = make(FacetsRequest, 1)
	}
	r.Facets[facetName] = f
}

// UnmarshalJSON deserializes a JSON representation of
// a SearchRequest
func (r *SearchRequest) UnmarshalJSON(input []byte) error {
	var temp struct {
		Q         json.RawMessage   `json:"query"`
		Size      int               `json:"size"`
		From      int               `json:"from"`
		Highlight *HighlightRequest `json:"highlight"`
		Fields    []string          `json:"fields"`
		Facets    FacetsRequest     `json:"facets"`
		Explain   bool              `json:"explain"`
	}

	err := json.Unmarshal(input, &temp)
	if err != nil {
		return err
	}

	r.Size = temp.Size
	r.From = temp.From
	r.Explain = temp.Explain
	r.Highlight = temp.Highlight
	r.Fields = temp.Fields
	r.Facets = temp.Facets
	r.Query, err = ParseQuery(temp.Q)
	if err != nil {
		return err
	}

	if r.Size < 0 {
		r.Size = 10
	}
	if r.From < 0 {
		r.From = 0
	}

	return nil

}

// NewSearchRequest creates a new SearchRequest
// for the Query, using default values for all
// other search parameters.
func NewSearchRequest(q Query) *SearchRequest {
	return NewSearchRequestOptions(q, 10, 0, false)
}

// NewSearchRequestOptions creates a new SearchRequest
// for the Query, with the requested size, from
// and explanation search parameters.
func NewSearchRequestOptions(q Query, size, from int, explain bool) *SearchRequest {
	return &SearchRequest{
		Query:   q,
		Size:    size,
		From:    from,
		Explain: explain,
	}
}

// A SearchResult describes the results of executing
// a SearchRequest.
type SearchResult struct {
	Request  *SearchRequest                 `json:"request"`
	Hits     search.DocumentMatchCollection `json:"hits"`
	Total    uint64                         `json:"total_hits"`
	MaxScore float64                        `json:"max_score"`
	Took     time.Duration                  `json:"took"`
	Facets   search.FacetResults            `json:"facets"`
}

func (sr *SearchResult) String() string {
	rv := ""
	if sr.Total > 0 {
		if sr.Request.Size > 0 {
			rv = fmt.Sprintf("%d matches, showing %d through %d, took %s\n", sr.Total, sr.Request.From+1, sr.Request.From+len(sr.Hits), sr.Took)
			for i, hit := range sr.Hits {
				rv += fmt.Sprintf("%5d. %s (%f)\n", i+sr.Request.From+1, hit.ID, hit.Score)
				for fragmentField, fragments := range hit.Fragments {
					rv += fmt.Sprintf("\t%s\n", fragmentField)
					for _, fragment := range fragments {
						rv += fmt.Sprintf("\t\t%s\n", fragment)
					}
				}
				for otherFieldName, otherFieldValue := range hit.Fields {
					if _, ok := hit.Fragments[otherFieldName]; !ok {
						rv += fmt.Sprintf("\t%s\n", otherFieldName)
						rv += fmt.Sprintf("\t\t%s\n", otherFieldValue)
					}
				}
			}
		} else {
			rv = fmt.Sprintf("%d matches, took %s\n", sr.Total, sr.Took)
		}
	} else {
		rv = "No matches"
	}
	return rv
}

func (sr *SearchResult) Merge(other *SearchResult) {
	sr.Hits = append(sr.Hits, other.Hits...)
	sr.Total += other.Total
	sr.Took += other.Took
	if other.MaxScore > sr.MaxScore {
		sr.MaxScore = other.MaxScore
	}
	sr.Facets.Merge(other.Facets)
}
<|endoftext|>


<commit_before>package search

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/mholt/caddy/middleware"
	"github.com/pedronasser/caddy-search/indexer"
)

// Handler creates a new handler for the search middleware
func Handler(next middleware.Handler, config *Config, index indexer.Handler, pipeline *Pipeline) middleware.Handler {
	return &Search{next, config, index, pipeline}
}

// Search represents this middleware structure
type Search struct {
	Next middleware.Handler
	*Config
	Indexer indexer.Handler
	*Pipeline
}

// ServerHTTP is the HTTP handler for this middleware
func (s *Search) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	if middleware.Path(r.URL.Path).Matches(s.Config.Endpoint) {
		if r.Header.Get("Accept") == "application/json" {
			return s.SearchJSON(w, r)
		}
		return s.SearchJSON(w, r)
	}

	record := s.Indexer.Record(r.URL.String())
	go s.Pipeline.Pipe(record)
	return s.Next.ServeHTTP(&searchResponseWriter{w, record}, r)
}

// Result is the structure for the search result
type Result struct {
	Path     string
	Title    string
	Body     string
	Modified time.Time
}

// SearchJSON ...
func (s *Search) SearchJSON(w http.ResponseWriter, r *http.Request) (status int, err error) {
	var jresp []byte

	q := r.URL.Query().Get("q")
	indexResult := s.Indexer.Search(q)

	results := make([]Result, len(indexResult))

	for i, result := range indexResult {
		body := result.Body()
		results[i] = Result{
			Path:     result.Path(),
			Title:    result.Title(),
			Modified: result.Modified(),
			Body:     string(body),
		}
	}

	jresp, err = json.Marshal(results)
	if err != nil {
		return 500, err
	}

	w.Write(jresp)
	return 200, err
}

type searchResponseWriter struct {
	w      http.ResponseWriter
	record indexer.Record
}

func (r *searchResponseWriter) Header() http.Header {
	return r.w.Header()
}

func (r *searchResponseWriter) WriteHeader(code int) {
	if code != 200 {
		r.record.Ignore()
	}
	r.w.WriteHeader(code)
}

func (r *searchResponseWriter) Write(p []byte) (int, error) {
	defer r.record.Write(p)
	n, err := r.w.Write(p)
	return n, err
}
<commit_msg>fix infinite loop if response code not 200<commit_after>package search

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/mholt/caddy/middleware"
	"github.com/pedronasser/caddy-search/indexer"
)

// Handler creates a new handler for the search middleware
func Handler(next middleware.Handler, config *Config, index indexer.Handler, pipeline *Pipeline) middleware.Handler {
	return &Search{next, config, index, pipeline}
}

// Search represents this middleware structure
type Search struct {
	Next middleware.Handler
	*Config
	Indexer indexer.Handler
	*Pipeline
}

// ServerHTTP is the HTTP handler for this middleware
func (s *Search) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	if middleware.Path(r.URL.Path).Matches(s.Config.Endpoint) {
		if r.Header.Get("Accept") == "application/json" {
			return s.SearchJSON(w, r)
		}
		return s.SearchJSON(w, r)
	}

	record := s.Indexer.Record(r.URL.String())
	go s.Pipeline.Pipe(record)

	status, err := s.Next.ServeHTTP(&searchResponseWriter{w, record}, r)
	if status != 200 {
		record.Ignore()
	}

	return status, err
}

// Result is the structure for the search result
type Result struct {
	Path     string
	Title    string
	Body     string
	Modified time.Time
}

// SearchJSON ...
func (s *Search) SearchJSON(w http.ResponseWriter, r *http.Request) (status int, err error) {
	var jresp []byte

	q := r.URL.Query().Get("q")
	indexResult := s.Indexer.Search(q)

	results := make([]Result, len(indexResult))

	for i, result := range indexResult {
		body := result.Body()
		results[i] = Result{
			Path:     result.Path(),
			Title:    result.Title(),
			Modified: result.Modified(),
			Body:     string(body),
		}
	}

	jresp, err = json.Marshal(results)
	if err != nil {
		return 500, err
	}

	w.Write(jresp)
	return 200, err
}

type searchResponseWriter struct {
	w      http.ResponseWriter
	record indexer.Record
}

func (r *searchResponseWriter) Header() http.Header {
	return r.w.Header()
}

func (r *searchResponseWriter) WriteHeader(code int) {
	if code != 200 {
		r.record.Ignore()
	}
	r.w.WriteHeader(code)
}

func (r *searchResponseWriter) Write(p []byte) (int, error) {
	defer r.record.Write(p)
	n, err := r.w.Write(p)
	return n, err
}
<|endoftext|>


<commit_before>package intarr

import "encoding/binary"

func Uint64ToBytes(i uint64) []byte {
	data := make([]byte, 8)
	binary.BigEndian.PutUint64(data, i)
	return data
}

func BytesToUint64(bts []byte) uint64 {
	return binary.BigEndian.Uint64(bts)
}
<commit_msg>add util<commit_after>package intarr

import "encoding/binary"

func Uint64ToBytes(i uint64) []byte {
	data := make([]byte, 8)
	binary.BigEndian.PutUint64(data, i)
	return data
}

func BytesToUint64(bts []byte) uint64 {
	return binary.BigEndian.Uint64(bts)
}
func InArray(value int64, array []int64) bool {
	for _, v := range array {
		if v == value {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package gopherneo

import "regexp"

func EscapeStringForCypherRegex(in string) string {
	//fmt.Printf("in: %v\n", in)
	r1 := regexp.MustCompile("(\\')")
	r2 := regexp.MustCompile("(\\(|\\))")
	r3 := regexp.MustCompile("(&)")
	r4 := regexp.MustCompile("(\\*)")

	out := in
	out = r1.ReplaceAllString(out, "\\\\$1")
	out = r2.ReplaceAllString(out, "\\\\$1")
	out = r3.ReplaceAllString(out, "\\\\$1")
	out = r4.ReplaceAllString(out, "\\\\$1")
	//fmt.Printf("out: %v\n", out)
	return out
}
<commit_msg>More improvements to unescaping for regex in cypher<commit_after>package gopherneo

import "regexp"

func EscapeStringForCypherRegex(in string) string {
	//fmt.Printf("in: %v\n", in)
	r1 := regexp.MustCompile("(\\')")
	r2 := regexp.MustCompile("(\\(|\\))")
	r3 := regexp.MustCompile("(&)")
	r4 := regexp.MustCompile("(\\*)")
	r5 := regexp.MustCompile("(\")")
	r6 := regexp.MustCompile("(\\+)")

	out := in
	out = r1.ReplaceAllString(out, "\\\\$1")
	out = r2.ReplaceAllString(out, "\\\\$1")
	out = r3.ReplaceAllString(out, "\\\\$1")
	out = r4.ReplaceAllString(out, "\\\\$1")
	out = r5.ReplaceAllString(out, "\\$1")
	out = r6.ReplaceAllString(out, "\\\\$1")

	//fmt.Printf("out: %v\n", out)
	return out
}
<|endoftext|>


<commit_before>package gg

import (
	"fmt"
	"image"
	"image/draw"
	_ "image/jpeg"
	"image/png"
	"io/ioutil"
	"math"
	"os"
	"strings"

	"github.com/golang/freetype/truetype"

	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

func Radians(degrees float64) float64 {
	return degrees * math.Pi / 180
}

func Degrees(radians float64) float64 {
	return radians * 180 / math.Pi
}

func LoadImage(path string) (image.Image, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	im, _, err := image.Decode(file)
	return im, err
}

func LoadPNG(path string) (image.Image, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return png.Decode(file)
}

func SavePNG(path string, im image.Image) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	return png.Encode(file, im)
}

func imageToRGBA(src image.Image) *image.RGBA {
	bounds := src.Bounds()
	dst := image.NewRGBA(bounds)
	draw.Draw(dst, bounds, src, bounds.Min, draw.Src)
	return dst
}

func parseHexColor(x string) (r, g, b, a int) {
	x = strings.TrimPrefix(x, "#")
	a = 255
	if len(x) == 3 {
		format := "%1x%1x%1x"
		fmt.Sscanf(x, format, &r, &g, &b)
		r |= r << 4
		g |= g << 4
		b |= b << 4
	}
	if len(x) == 6 {
		format := "%02x%02x%02x"
		fmt.Sscanf(x, format, &r, &g, &b)
	}
	if len(x) == 8 {
		format := "%02x%02x%02x%02x"
		fmt.Sscanf(x, format, &r, &g, &b, &a)
	}
	return
}

func fixp(x, y float64) fixed.Point26_6 {
	return fixed.Point26_6{fix(x), fix(y)}
}

func fix(x float64) fixed.Int26_6 {
	return fixed.Int26_6(x * 64)
}

func unfix(x fixed.Int26_6) float64 {
	const shift, mask = 6, 1<<6 - 1
	if x >= 0 {
		return float64(x>>shift) + float64(x&mask)/64
	}
	x = -x
	if x >= 0 {
		return -(float64(x>>shift) + float64(x&mask)/64)
	}
	return 0
}

func LoadFontFace(path string, points float64) (font.Face, error) {
	fontBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	f, err := truetype.Parse(fontBytes)
	if err != nil {
		return nil, err
	}
	face := truetype.NewFace(f, &truetype.Options{
		Size: points,
		// Hinting: font.HintingFull,
	})
	return face, nil
}
<commit_msg>Fix #23 via doc on gg.LoadFontFace function.<commit_after>package gg

import (
	"fmt"
	"image"
	"image/draw"
	_ "image/jpeg"
	"image/png"
	"io/ioutil"
	"math"
	"os"
	"strings"

	"github.com/golang/freetype/truetype"

	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

func Radians(degrees float64) float64 {
	return degrees * math.Pi / 180
}

func Degrees(radians float64) float64 {
	return radians * 180 / math.Pi
}

func LoadImage(path string) (image.Image, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	im, _, err := image.Decode(file)
	return im, err
}

func LoadPNG(path string) (image.Image, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return png.Decode(file)
}

func SavePNG(path string, im image.Image) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	return png.Encode(file, im)
}

func imageToRGBA(src image.Image) *image.RGBA {
	bounds := src.Bounds()
	dst := image.NewRGBA(bounds)
	draw.Draw(dst, bounds, src, bounds.Min, draw.Src)
	return dst
}

func parseHexColor(x string) (r, g, b, a int) {
	x = strings.TrimPrefix(x, "#")
	a = 255
	if len(x) == 3 {
		format := "%1x%1x%1x"
		fmt.Sscanf(x, format, &r, &g, &b)
		r |= r << 4
		g |= g << 4
		b |= b << 4
	}
	if len(x) == 6 {
		format := "%02x%02x%02x"
		fmt.Sscanf(x, format, &r, &g, &b)
	}
	if len(x) == 8 {
		format := "%02x%02x%02x%02x"
		fmt.Sscanf(x, format, &r, &g, &b, &a)
	}
	return
}

func fixp(x, y float64) fixed.Point26_6 {
	return fixed.Point26_6{fix(x), fix(y)}
}

func fix(x float64) fixed.Int26_6 {
	return fixed.Int26_6(x * 64)
}

func unfix(x fixed.Int26_6) float64 {
	const shift, mask = 6, 1<<6 - 1
	if x >= 0 {
		return float64(x>>shift) + float64(x&mask)/64
	}
	x = -x
	if x >= 0 {
		return -(float64(x>>shift) + float64(x&mask)/64)
	}
	return 0
}

// LoadFontFace is a helper function to load the specified font file with
// the specified point size. Note that the returned `font.Face` objects
// are not thread safe and cannot be used in parallel across goroutines.
// You can usually just use the Context.LoadFontFace function instead of
// this package-level function.
func LoadFontFace(path string, points float64) (font.Face, error) {
	fontBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	f, err := truetype.Parse(fontBytes)
	if err != nil {
		return nil, err
	}
	face := truetype.NewFace(f, &truetype.Options{
		Size: points,
		// Hinting: font.HintingFull,
	})
	return face, nil
}
<|endoftext|>


<commit_before>package postgres

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/url"

	"context"

	"github.com/Sirupsen/logrus"
	"github.com/iron-io/functions/api/models"
	"github.com/lib/pq"
	_ "github.com/lib/pq"
)

const routesTableCreate = `
CREATE TABLE IF NOT EXISTS routes (
	app_name character varying(256) NOT NULL,
	path text NOT NULL,
	image character varying(256) NOT NULL,
	format character varying(16) NOT NULL,
	maxc integer NOT NULL,
	memory integer NOT NULL,
	timeout integer NOT NULL,
	type character varying(16) NOT NULL,
	headers text NOT NULL,
	config text NOT NULL,
	PRIMARY KEY (app_name, path)
);`

const appsTableCreate = `CREATE TABLE IF NOT EXISTS apps (
    name character varying(256) NOT NULL PRIMARY KEY,
	config text NOT NULL
);`

const extrasTableCreate = `CREATE TABLE IF NOT EXISTS extras (
    key character varying(256) NOT NULL PRIMARY KEY,
	value character varying(256) NOT NULL
);`

const routeSelector = `SELECT app_name, path, image, format, maxc, memory, type, timeout, headers, config FROM routes`

type rowScanner interface {
	Scan(dest ...interface{}) error
}

type rowQuerier interface {
	QueryRow(query string, args ...interface{}) *sql.Row
}

type PostgresDatastore struct {
	db *sql.DB
}

func New(url *url.URL) (models.Datastore, error) {
	db, err := sql.Open("postgres", url.String())
	if err != nil {
		return nil, err
	}

	err = db.Ping()
	if err != nil {
		return nil, err
	}

	maxIdleConns := 30 // c.MaxIdleConnections
	db.SetMaxIdleConns(maxIdleConns)
	logrus.WithFields(logrus.Fields{"max_idle_connections": maxIdleConns}).Info("Postgres dialed")

	pg := &PostgresDatastore{
		db: db,
	}

	for _, v := range []string{routesTableCreate, appsTableCreate, extrasTableCreate} {
		_, err = db.Exec(v)
		if err != nil {
			return nil, err
		}
	}

	return pg, nil
}

func (ds *PostgresDatastore) InsertApp(ctx context.Context, app *models.App) (*models.App, error) {
	var cbyte []byte
	var err error

	if app == nil {
		return nil, models.ErrDatastoreEmptyApp
	}

	if app.Name == "" {
		return nil, models.ErrDatastoreEmptyAppName
	}

	if app.Config != nil {
		cbyte, err = json.Marshal(app.Config)
		if err != nil {
			return nil, err
		}
	}

	_, err = ds.db.Exec(`INSERT INTO apps (name, config) VALUES ($1, $2);`,
		app.Name,
		string(cbyte),
	)

	if err != nil {
		pqErr := err.(*pq.Error)
		if pqErr.Code == "23505" {
			return nil, models.ErrAppsAlreadyExists
		}
		return nil, err
	}

	return app, nil
}

func (ds *PostgresDatastore) UpdateApp(ctx context.Context, app *models.App) (*models.App, error) {
	if app == nil {
		return nil, models.ErrAppsNotFound
	}

	cbyte, err := json.Marshal(app.Config)
	if err != nil {
		return nil, err
	}

	res, err := ds.db.Exec(`
	  UPDATE apps SET
		config = $2
	  WHERE name = $1
	  RETURNING *;
	`,
		app.Name,
		string(cbyte),
	)

	if err != nil {
		return nil, err
	}

	n, err := res.RowsAffected()
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, models.ErrAppsNotFound
	}

	return app, nil
}

func (ds *PostgresDatastore) RemoveApp(ctx context.Context, appName string) error {
	if appName == "" {
		return models.ErrDatastoreEmptyAppName
	}

	_, err := ds.db.Exec(`
	  DELETE FROM apps
	  WHERE name = $1
	`, appName)

	if err != nil {
		return err
	}

	return nil
}

func (ds *PostgresDatastore) GetApp(ctx context.Context, name string) (*models.App, error) {
	if name == "" {
		return nil, models.ErrDatastoreEmptyAppName
	}

	row := ds.db.QueryRow("SELECT name, config FROM apps WHERE name=$1", name)

	var resName string
	var config string
	err := row.Scan(&resName, &config)

	res := &models.App{
		Name: resName,
	}

	json.Unmarshal([]byte(config), &res.Config)

	if err != nil {
		if err == sql.ErrNoRows {
			return nil, models.ErrAppsNotFound
		}
		return nil, err
	}

	return res, nil
}

func scanApp(scanner rowScanner, app *models.App) error {
	var configStr string

	err := scanner.Scan(
		&app.Name,
		&configStr,
	)

	if configStr == "" {
		return models.ErrAppsNotFound
	}

	json.Unmarshal([]byte(configStr), &app.Config)

	return err
}

func (ds *PostgresDatastore) GetApps(ctx context.Context, filter *models.AppFilter) ([]*models.App, error) {
	res := []*models.App{}

	filterQuery := buildFilterAppQuery(filter)
	rows, err := ds.db.Query(fmt.Sprintf("SELECT DISTINCT * FROM apps %s", filterQuery))

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var app models.App
		err := scanApp(rows, &app)

		if err != nil {
			if err == sql.ErrNoRows {
				return res, nil
			}
			return res, err
		}
		res = append(res, &app)
	}

	if err := rows.Err(); err != nil {
		return res, err
	}
	return res, nil
}

func (ds *PostgresDatastore) InsertRoute(ctx context.Context, route *models.Route) (*models.Route, error) {
	if route == nil {
		return nil, models.ErrDatastoreEmptyRoute
	}

	hbyte, err := json.Marshal(route.Headers)
	if err != nil {
		return nil, err
	}

	cbyte, err := json.Marshal(route.Config)
	if err != nil {
		return nil, err
	}

	_, err = ds.db.Exec(`
		INSERT INTO routes (
			app_name,
			path,
			image,
			format,
			maxc,
			memory,
			type,
			timeout,
			headers,
			config
		)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);`,
		route.AppName,
		route.Path,
		route.Image,
		route.Format,
		route.MaxConcurrency,
		route.Memory,
		route.Type,
		route.Timeout,
		string(hbyte),
		string(cbyte),
	)

	if err != nil {
		pqErr := err.(*pq.Error)
		if pqErr.Code == "23505" {
			return nil, models.ErrRoutesAlreadyExists
		}
		return nil, err
	}
	return route, nil
}

func (ds *PostgresDatastore) UpdateRoute(ctx context.Context, route *models.Route) (*models.Route, error) {
	if route == nil {
		return nil, models.ErrDatastoreEmptyRoute
	}

	hbyte, err := json.Marshal(route.Headers)
	if err != nil {
		return nil, err
	}

	cbyte, err := json.Marshal(route.Config)
	if err != nil {
		return nil, err
	}

	res, err := ds.db.Exec(`
		UPDATE routes SET
			image = $3,
			format = $4,
			memory = $5,
			maxc = $6,
			type = $7,
			timeout = $8,
			headers = $9,
			config = $10
		WHERE app_name = $1 AND path = $2;`,
		route.AppName,
		route.Path,
		route.Image,
		route.Format,
		route.Memory,
		route.MaxConcurrency,
		route.Type,
		route.Timeout,
		string(hbyte),
		string(cbyte),
	)

	if err != nil {
		return nil, err
	}

	n, err := res.RowsAffected()
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, models.ErrRoutesNotFound
	}

	return route, nil
}

func (ds *PostgresDatastore) RemoveRoute(ctx context.Context, appName, routePath string) error {
	if appName == "" {
		return models.ErrDatastoreEmptyAppName
	}

	if routePath == "" {
		return models.ErrDatastoreEmptyRoutePath
	}

	res, err := ds.db.Exec(`
		DELETE FROM routes
		WHERE path = $1 AND app_name = $2
	`, routePath, appName)

	if err != nil {
		return err
	}

	n, err := res.RowsAffected()
	if err != nil {
		return err
	}

	if n == 0 {
		return models.ErrRoutesRemoving
	}

	return nil
}

func scanRoute(scanner rowScanner, route *models.Route) error {
	var headerStr string
	var configStr string

	err := scanner.Scan(
		&route.AppName,
		&route.Path,
		&route.Image,
		&route.Format,
		&route.Memory,
		&route.MaxConcurrency,
		&route.Type,
		&route.Timeout,
		&headerStr,
		&configStr,
	)

	if headerStr == "" {
		return models.ErrRoutesNotFound
	}

	json.Unmarshal([]byte(headerStr), &route.Headers)
	json.Unmarshal([]byte(configStr), &route.Config)

	return err
}

func (ds *PostgresDatastore) GetRoute(ctx context.Context, appName, routePath string) (*models.Route, error) {
	if appName == "" {
		return nil, models.ErrDatastoreEmptyAppName
	}

	if routePath == "" {
		return nil, models.ErrDatastoreEmptyRoutePath
	}

	var route models.Route

	row := ds.db.QueryRow(fmt.Sprintf("%s WHERE app_name=$1 AND path=$2", routeSelector), appName, routePath)
	err := scanRoute(row, &route)

	if err == sql.ErrNoRows {
		return nil, models.ErrRoutesNotFound
	} else if err != nil {
		return nil, err
	}
	return &route, nil
}

func (ds *PostgresDatastore) GetRoutes(ctx context.Context, filter *models.RouteFilter) ([]*models.Route, error) {
	res := []*models.Route{}
	filterQuery := buildFilterRouteQuery(filter)
	rows, err := ds.db.Query(fmt.Sprintf("%s %s", routeSelector, filterQuery))
	// todo: check for no rows so we don't respond with a sql 500 err
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var route models.Route
		err := scanRoute(rows, &route)
		if err != nil {
			continue
		}
		res = append(res, &route)

	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return res, nil
}

func (ds *PostgresDatastore) GetRoutesByApp(ctx context.Context, appName string, filter *models.RouteFilter) ([]*models.Route, error) {
	res := []*models.Route{}
	filter.AppName = appName
	filterQuery := buildFilterRouteQuery(filter)
	rows, err := ds.db.Query(fmt.Sprintf("%s %s", routeSelector, filterQuery))
	// todo: check for no rows so we don't respond with a sql 500 err
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var route models.Route
		err := scanRoute(rows, &route)
		if err != nil {
			continue
		}
		res = append(res, &route)

	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return res, nil
}

func buildFilterAppQuery(filter *models.AppFilter) string {
	filterQuery := ""

	if filter != nil {
		filterQueries := []string{}
		if filter.Name != "" {
			filterQueries = append(filterQueries, fmt.Sprintf("name LIKE '%s'", filter.Name))
		}

		for i, field := range filterQueries {
			if i == 0 {
				filterQuery = fmt.Sprintf("WHERE %s ", field)
			} else {
				filterQuery = fmt.Sprintf("%s AND %s", filterQuery, field)
			}
		}
	}

	return filterQuery
}

func buildFilterRouteQuery(filter *models.RouteFilter) string {
	filterQuery := ""

	filterQueries := []string{}
	if filter.Path != "" {
		filterQueries = append(filterQueries, fmt.Sprintf("path = '%s'", filter.Path))
	}

	if filter.AppName != "" {
		filterQueries = append(filterQueries, fmt.Sprintf("app_name = '%s'", filter.AppName))
	}

	if filter.Image != "" {
		filterQueries = append(filterQueries, fmt.Sprintf("image = '%s'", filter.Image))
	}

	for i, field := range filterQueries {
		if i == 0 {
			filterQuery = fmt.Sprintf("WHERE %s ", field)
		} else {
			filterQuery = fmt.Sprintf("%s AND %s", filterQuery, field)
		}
	}

	return filterQuery
}

func (ds *PostgresDatastore) Put(ctx context.Context, key, value []byte) error {
	_, err := ds.db.Exec(`
	    INSERT INTO extras (
			key,
			value
		)
		VALUES ($1, $2)
		ON CONFLICT (key) DO UPDATE SET
			value = $1;
		`, value)

	if err != nil {
		return err
	}

	return nil
}

func (ds *PostgresDatastore) Get(ctx context.Context, key []byte) ([]byte, error) {
	row := ds.db.QueryRow("SELECT value FROM extras WHERE key=$1", key)

	var value []byte
	err := row.Scan(&value)
	if err == sql.ErrNoRows {
		return nil, nil
	} else if err != nil {
		return nil, err
	}

	return value, nil
}
<commit_msg>minor postgres fix (#392)<commit_after>package postgres

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/url"

	"context"

	"github.com/Sirupsen/logrus"
	"github.com/iron-io/functions/api/models"
	"github.com/lib/pq"
	_ "github.com/lib/pq"
)

const routesTableCreate = `
CREATE TABLE IF NOT EXISTS routes (
	app_name character varying(256) NOT NULL,
	path text NOT NULL,
	image character varying(256) NOT NULL,
	format character varying(16) NOT NULL,
	maxc integer NOT NULL,
	memory integer NOT NULL,
	timeout integer NOT NULL,
	type character varying(16) NOT NULL,
	headers text NOT NULL,
	config text NOT NULL,
	PRIMARY KEY (app_name, path)
);`

const appsTableCreate = `CREATE TABLE IF NOT EXISTS apps (
    name character varying(256) NOT NULL PRIMARY KEY,
	config text NOT NULL
);`

const extrasTableCreate = `CREATE TABLE IF NOT EXISTS extras (
    key character varying(256) NOT NULL PRIMARY KEY,
	value character varying(256) NOT NULL
);`

const routeSelector = `SELECT app_name, path, image, format, maxc, memory, type, timeout, headers, config FROM routes`

type rowScanner interface {
	Scan(dest ...interface{}) error
}

type rowQuerier interface {
	QueryRow(query string, args ...interface{}) *sql.Row
}

type PostgresDatastore struct {
	db *sql.DB
}

func New(url *url.URL) (models.Datastore, error) {
	db, err := sql.Open("postgres", url.String())
	if err != nil {
		return nil, err
	}

	err = db.Ping()
	if err != nil {
		return nil, err
	}

	maxIdleConns := 30 // c.MaxIdleConnections
	db.SetMaxIdleConns(maxIdleConns)
	logrus.WithFields(logrus.Fields{"max_idle_connections": maxIdleConns}).Info("Postgres dialed")

	pg := &PostgresDatastore{
		db: db,
	}

	for _, v := range []string{routesTableCreate, appsTableCreate, extrasTableCreate} {
		_, err = db.Exec(v)
		if err != nil {
			return nil, err
		}
	}

	return pg, nil
}

func (ds *PostgresDatastore) InsertApp(ctx context.Context, app *models.App) (*models.App, error) {
	var cbyte []byte
	var err error

	if app == nil {
		return nil, models.ErrDatastoreEmptyApp
	}

	if app.Name == "" {
		return nil, models.ErrDatastoreEmptyAppName
	}

	if app.Config != nil {
		cbyte, err = json.Marshal(app.Config)
		if err != nil {
			return nil, err
		}
	}

	_, err = ds.db.Exec(`INSERT INTO apps (name, config) VALUES ($1, $2);`,
		app.Name,
		string(cbyte),
	)

	if err != nil {
		pqErr := err.(*pq.Error)
		if pqErr.Code == "23505" {
			return nil, models.ErrAppsAlreadyExists
		}
		return nil, err
	}

	return app, nil
}

func (ds *PostgresDatastore) UpdateApp(ctx context.Context, app *models.App) (*models.App, error) {
	if app == nil {
		return nil, models.ErrAppsNotFound
	}

	cbyte, err := json.Marshal(app.Config)
	if err != nil {
		return nil, err
	}

	res, err := ds.db.Exec(`
	  UPDATE apps SET
		config = $2
	  WHERE name = $1
	  RETURNING *;
	`,
		app.Name,
		string(cbyte),
	)

	if err != nil {
		return nil, err
	}

	n, err := res.RowsAffected()
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, models.ErrAppsNotFound
	}

	return app, nil
}

func (ds *PostgresDatastore) RemoveApp(ctx context.Context, appName string) error {
	if appName == "" {
		return models.ErrDatastoreEmptyAppName
	}

	_, err := ds.db.Exec(`
	  DELETE FROM apps
	  WHERE name = $1
	`, appName)

	if err != nil {
		return err
	}

	return nil
}

func (ds *PostgresDatastore) GetApp(ctx context.Context, name string) (*models.App, error) {
	if name == "" {
		return nil, models.ErrDatastoreEmptyAppName
	}

	row := ds.db.QueryRow("SELECT name, config FROM apps WHERE name=$1", name)

	var resName string
	var config string
	err := row.Scan(&resName, &config)

	res := &models.App{
		Name: resName,
	}

	json.Unmarshal([]byte(config), &res.Config)

	if err != nil {
		if err == sql.ErrNoRows {
			return nil, models.ErrAppsNotFound
		}
		return nil, err
	}

	return res, nil
}

func scanApp(scanner rowScanner, app *models.App) error {
	var configStr string

	err := scanner.Scan(
		&app.Name,
		&configStr,
	)

	json.Unmarshal([]byte(configStr), &app.Config)

	return err
}

func (ds *PostgresDatastore) GetApps(ctx context.Context, filter *models.AppFilter) ([]*models.App, error) {
	res := []*models.App{}

	filterQuery := buildFilterAppQuery(filter)
	rows, err := ds.db.Query(fmt.Sprintf("SELECT DISTINCT * FROM apps %s", filterQuery))

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var app models.App
		err := scanApp(rows, &app)

		if err != nil {
			if err == sql.ErrNoRows {
				return res, nil
			}
			return res, err
		}
		res = append(res, &app)
	}

	if err := rows.Err(); err != nil {
		return res, err
	}
	return res, nil
}

func (ds *PostgresDatastore) InsertRoute(ctx context.Context, route *models.Route) (*models.Route, error) {
	if route == nil {
		return nil, models.ErrDatastoreEmptyRoute
	}

	hbyte, err := json.Marshal(route.Headers)
	if err != nil {
		return nil, err
	}

	cbyte, err := json.Marshal(route.Config)
	if err != nil {
		return nil, err
	}

	_, err = ds.db.Exec(`
		INSERT INTO routes (
			app_name,
			path,
			image,
			format,
			maxc,
			memory,
			type,
			timeout,
			headers,
			config
		)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);`,
		route.AppName,
		route.Path,
		route.Image,
		route.Format,
		route.MaxConcurrency,
		route.Memory,
		route.Type,
		route.Timeout,
		string(hbyte),
		string(cbyte),
	)

	if err != nil {
		pqErr := err.(*pq.Error)
		if pqErr.Code == "23505" {
			return nil, models.ErrRoutesAlreadyExists
		}
		return nil, err
	}
	return route, nil
}

func (ds *PostgresDatastore) UpdateRoute(ctx context.Context, route *models.Route) (*models.Route, error) {
	if route == nil {
		return nil, models.ErrDatastoreEmptyRoute
	}

	hbyte, err := json.Marshal(route.Headers)
	if err != nil {
		return nil, err
	}

	cbyte, err := json.Marshal(route.Config)
	if err != nil {
		return nil, err
	}

	res, err := ds.db.Exec(`
		UPDATE routes SET
			image = $3,
			format = $4,
			memory = $5,
			maxc = $6,
			type = $7,
			timeout = $8,
			headers = $9,
			config = $10
		WHERE app_name = $1 AND path = $2;`,
		route.AppName,
		route.Path,
		route.Image,
		route.Format,
		route.Memory,
		route.MaxConcurrency,
		route.Type,
		route.Timeout,
		string(hbyte),
		string(cbyte),
	)

	if err != nil {
		return nil, err
	}

	n, err := res.RowsAffected()
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, models.ErrRoutesNotFound
	}

	return route, nil
}

func (ds *PostgresDatastore) RemoveRoute(ctx context.Context, appName, routePath string) error {
	if appName == "" {
		return models.ErrDatastoreEmptyAppName
	}

	if routePath == "" {
		return models.ErrDatastoreEmptyRoutePath
	}

	res, err := ds.db.Exec(`
		DELETE FROM routes
		WHERE path = $1 AND app_name = $2
	`, routePath, appName)

	if err != nil {
		return err
	}

	n, err := res.RowsAffected()
	if err != nil {
		return err
	}

	if n == 0 {
		return models.ErrRoutesRemoving
	}

	return nil
}

func scanRoute(scanner rowScanner, route *models.Route) error {
	var headerStr string
	var configStr string

	err := scanner.Scan(
		&route.AppName,
		&route.Path,
		&route.Image,
		&route.Format,
		&route.Memory,
		&route.MaxConcurrency,
		&route.Type,
		&route.Timeout,
		&headerStr,
		&configStr,
	)

	if headerStr == "" {
		return models.ErrRoutesNotFound
	}

	json.Unmarshal([]byte(headerStr), &route.Headers)
	json.Unmarshal([]byte(configStr), &route.Config)

	return err
}

func (ds *PostgresDatastore) GetRoute(ctx context.Context, appName, routePath string) (*models.Route, error) {
	if appName == "" {
		return nil, models.ErrDatastoreEmptyAppName
	}

	if routePath == "" {
		return nil, models.ErrDatastoreEmptyRoutePath
	}

	var route models.Route

	row := ds.db.QueryRow(fmt.Sprintf("%s WHERE app_name=$1 AND path=$2", routeSelector), appName, routePath)
	err := scanRoute(row, &route)

	if err == sql.ErrNoRows {
		return nil, models.ErrRoutesNotFound
	} else if err != nil {
		return nil, err
	}
	return &route, nil
}

func (ds *PostgresDatastore) GetRoutes(ctx context.Context, filter *models.RouteFilter) ([]*models.Route, error) {
	res := []*models.Route{}
	filterQuery := buildFilterRouteQuery(filter)
	rows, err := ds.db.Query(fmt.Sprintf("%s %s", routeSelector, filterQuery))
	// todo: check for no rows so we don't respond with a sql 500 err
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var route models.Route
		err := scanRoute(rows, &route)
		if err != nil {
			continue
		}
		res = append(res, &route)

	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return res, nil
}

func (ds *PostgresDatastore) GetRoutesByApp(ctx context.Context, appName string, filter *models.RouteFilter) ([]*models.Route, error) {
	res := []*models.Route{}
	filter.AppName = appName
	filterQuery := buildFilterRouteQuery(filter)
	rows, err := ds.db.Query(fmt.Sprintf("%s %s", routeSelector, filterQuery))
	// todo: check for no rows so we don't respond with a sql 500 err
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var route models.Route
		err := scanRoute(rows, &route)
		if err != nil {
			continue
		}
		res = append(res, &route)

	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return res, nil
}

func buildFilterAppQuery(filter *models.AppFilter) string {
	filterQuery := ""

	if filter != nil {
		filterQueries := []string{}
		if filter.Name != "" {
			filterQueries = append(filterQueries, fmt.Sprintf("name LIKE '%s'", filter.Name))
		}

		for i, field := range filterQueries {
			if i == 0 {
				filterQuery = fmt.Sprintf("WHERE %s ", field)
			} else {
				filterQuery = fmt.Sprintf("%s AND %s", filterQuery, field)
			}
		}
	}

	return filterQuery
}

func buildFilterRouteQuery(filter *models.RouteFilter) string {
	filterQuery := ""

	filterQueries := []string{}
	if filter.Path != "" {
		filterQueries = append(filterQueries, fmt.Sprintf("path = '%s'", filter.Path))
	}

	if filter.AppName != "" {
		filterQueries = append(filterQueries, fmt.Sprintf("app_name = '%s'", filter.AppName))
	}

	if filter.Image != "" {
		filterQueries = append(filterQueries, fmt.Sprintf("image = '%s'", filter.Image))
	}

	for i, field := range filterQueries {
		if i == 0 {
			filterQuery = fmt.Sprintf("WHERE %s ", field)
		} else {
			filterQuery = fmt.Sprintf("%s AND %s", filterQuery, field)
		}
	}

	return filterQuery
}

func (ds *PostgresDatastore) Put(ctx context.Context, key, value []byte) error {
	_, err := ds.db.Exec(`
	    INSERT INTO extras (
			key,
			value
		)
		VALUES ($1, $2)
		ON CONFLICT (key) DO UPDATE SET
			value = $1;
		`, string(key), string(value))

	if err != nil {
		return err
	}

	return nil
}

func (ds *PostgresDatastore) Get(ctx context.Context, key []byte) ([]byte, error) {
	row := ds.db.QueryRow("SELECT value FROM extras WHERE key=$1", key)

	var value string
	err := row.Scan(&value)
	if err == sql.ErrNoRows {
		return nil, nil
	} else if err != nil {
		return nil, err
	}

	return []byte(value), nil
}
<|endoftext|>


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

package native

import (
	"testing"

	"github.com/gonum/lapack/testlapack"
)

var impl = Implementation{}

func TestDbdsqr(t *testing.T) {
	testlapack.DbdsqrTest(t, impl)
}

func TestDgebd2(t *testing.T) {
	testlapack.Dgebd2Test(t, impl)
}

func TestDgebrd(t *testing.T) {
	testlapack.DgebrdTest(t, impl)
}

func TestDgecon(t *testing.T) {
	testlapack.DgeconTest(t, impl)
}

func TestDgehd2(t *testing.T) {
	testlapack.Dgehd2Test(t, impl)
}

func TestDgehrd(t *testing.T) {
	testlapack.DgehrdTest(t, impl)
}

func TestDgelqf(t *testing.T) {
	testlapack.DgelqfTest(t, impl)
}

func TestDgelq2(t *testing.T) {
	testlapack.Dgelq2Test(t, impl)
}

func TestDgeql2(t *testing.T) {
	testlapack.Dgeql2Test(t, impl)
}

func TestDgels(t *testing.T) {
	testlapack.DgelsTest(t, impl)
}

func TestDgeqr2(t *testing.T) {
	testlapack.Dgeqr2Test(t, impl)
}

func TestDgeqrf(t *testing.T) {
	testlapack.DgeqrfTest(t, impl)
}

func TestDgesvd(t *testing.T) {
	testlapack.DgesvdTest(t, impl)
}

func TestDgetri(t *testing.T) {
	testlapack.DgetriTest(t, impl)
}

func TestDgetf2(t *testing.T) {
	testlapack.Dgetf2Test(t, impl)
}

func TestDgetrf(t *testing.T) {
	testlapack.DgetrfTest(t, impl)
}

func TestDgetrs(t *testing.T) {
	testlapack.DgetrsTest(t, impl)
}

func TestDlabrd(t *testing.T) {
	testlapack.DlabrdTest(t, impl)
}

func TestDlacpy(t *testing.T) {
	testlapack.DlacpyTest(t, impl)
}

func TestDlae2(t *testing.T) {
	testlapack.Dlae2Test(t, impl)
}

func TestDlaev2(t *testing.T) {
	testlapack.Dlaev2Test(t, impl)
}

func TestDlaexc(t *testing.T) {
	testlapack.DlaexcTest(t, impl)
}

func TestDlahqr(t *testing.T) {
	testlapack.DlahqrTest(t, impl)
}

func TestDlahr2(t *testing.T) {
	testlapack.Dlahr2Test(t, impl)
}

func TestDlaln2(t *testing.T) {
	testlapack.Dlaln2Test(t, impl)
}

func TestDlange(t *testing.T) {
	testlapack.DlangeTest(t, impl)
}

func TestDlas2(t *testing.T) {
	testlapack.Dlas2Test(t, impl)
}

func TestDlasy2(t *testing.T) {
	testlapack.Dlasy2Test(t, impl)
}

func TestDlanst(t *testing.T) {
	testlapack.DlanstTest(t, impl)
}

func TestDlansy(t *testing.T) {
	testlapack.DlansyTest(t, impl)
}

func TestDlantr(t *testing.T) {
	testlapack.DlantrTest(t, impl)
}

func TestDlanv2(t *testing.T) {
	testlapack.Dlanv2Test(t, impl)
}

func TestDlaqr1(t *testing.T) {
	testlapack.Dlaqr1Test(t, impl)
}

func TestDlaqr5(t *testing.T) {
	testlapack.Dlaqr5Test(t, impl)
}

func TestDlarf(t *testing.T) {
	testlapack.DlarfTest(t, impl)
}

func TestDlarfb(t *testing.T) {
	testlapack.DlarfbTest(t, impl)
}

func TestDlarfg(t *testing.T) {
	testlapack.DlarfgTest(t, impl)
}

func TestDlarft(t *testing.T) {
	testlapack.DlarftTest(t, impl)
}

func TestDlarfx(t *testing.T) {
	testlapack.DlarfxTest(t, impl)
}

func TestDlartg(t *testing.T) {
	testlapack.DlartgTest(t, impl)
}

func TestDlasq1(t *testing.T) {
	testlapack.Dlasq1Test(t, impl)
}

func TestDlasq2(t *testing.T) {
	testlapack.Dlasq2Test(t, impl)
}

func TestDlasq3(t *testing.T) {
	testlapack.Dlasq3Test(t, impl)
}

func TestDlasq4(t *testing.T) {
	testlapack.Dlasq4Test(t, impl)
}

func TestDlasq5(t *testing.T) {
	testlapack.Dlasq5Test(t, impl)
}

func TestDlasr(t *testing.T) {
	testlapack.DlasrTest(t, impl)
}

func TestDlasv2(t *testing.T) {
	testlapack.Dlasv2Test(t, impl)
}

func TestDlatrd(t *testing.T) {
	testlapack.DlatrdTest(t, impl)
}

func TestDorg2r(t *testing.T) {
	testlapack.Dorg2rTest(t, impl)
}

func TestDorgbr(t *testing.T) {
	testlapack.DorgbrTest(t, impl)
}

func TestDorghr(t *testing.T) {
	testlapack.DorghrTest(t, impl)
}

func TestDorg2l(t *testing.T) {
	testlapack.Dorg2lTest(t, impl)
}

func TestDorgl2(t *testing.T) {
	testlapack.Dorgl2Test(t, impl)
}

func TestDorglq(t *testing.T) {
	testlapack.DorglqTest(t, impl)
}

func TestDorgql(t *testing.T) {
	testlapack.DorgqlTest(t, impl)
}

func TestDorgqr(t *testing.T) {
	testlapack.DorgqrTest(t, impl)
}

func TestDorgtr(t *testing.T) {
	testlapack.DorgtrTest(t, impl)
}

func TestDormbr(t *testing.T) {
	testlapack.DormbrTest(t, impl)
}

func TestDormhr(t *testing.T) {
	testlapack.DormhrTest(t, impl)
}

func TestDorml2(t *testing.T) {
	testlapack.Dorml2Test(t, impl)
}

func TestDormlq(t *testing.T) {
	testlapack.DormlqTest(t, impl)
}

func TestDormqr(t *testing.T) {
	testlapack.DormqrTest(t, impl)
}

func TestDorm2r(t *testing.T) {
	testlapack.Dorm2rTest(t, impl)
}

func TestDpocon(t *testing.T) {
	testlapack.DpoconTest(t, impl)
}

func TestDpotf2(t *testing.T) {
	testlapack.Dpotf2Test(t, impl)
}

func TestDpotrf(t *testing.T) {
	testlapack.DpotrfTest(t, impl)
}

func TestDrscl(t *testing.T) {
	testlapack.DrsclTest(t, impl)
}

func TestDsteqr(t *testing.T) {
	testlapack.DsteqrTest(t, impl)
}

func TestDsterf(t *testing.T) {
	testlapack.DsterfTest(t, impl)
}

func TestDsyev(t *testing.T) {
	testlapack.DsyevTest(t, impl)
}

func TestDsytd2(t *testing.T) {
	testlapack.Dsytd2Test(t, impl)
}

func TestDsytrd(t *testing.T) {
	testlapack.DsytrdTest(t, impl)
}

func TestDtrcon(t *testing.T) {
	testlapack.DtrconTest(t, impl)
}

func TestDtrexc(t *testing.T) {
	testlapack.DtrexcTest(t, impl)
}

func TestDtrti2(t *testing.T) {
	testlapack.Dtrti2Test(t, impl)
}

func TestDtrtri(t *testing.T) {
	testlapack.DtrtriTest(t, impl)
}

func TestIladlc(t *testing.T) {
	testlapack.IladlcTest(t, impl)
}

func TestIladlr(t *testing.T) {
	testlapack.IladlrTest(t, impl)
}
<commit_msg>native: add test for Dlaqr2<commit_after>// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package native

import (
	"testing"

	"github.com/gonum/lapack/testlapack"
)

var impl = Implementation{}

func TestDbdsqr(t *testing.T) {
	testlapack.DbdsqrTest(t, impl)
}

func TestDgebd2(t *testing.T) {
	testlapack.Dgebd2Test(t, impl)
}

func TestDgebrd(t *testing.T) {
	testlapack.DgebrdTest(t, impl)
}

func TestDgecon(t *testing.T) {
	testlapack.DgeconTest(t, impl)
}

func TestDgehd2(t *testing.T) {
	testlapack.Dgehd2Test(t, impl)
}

func TestDgehrd(t *testing.T) {
	testlapack.DgehrdTest(t, impl)
}

func TestDgelqf(t *testing.T) {
	testlapack.DgelqfTest(t, impl)
}

func TestDgelq2(t *testing.T) {
	testlapack.Dgelq2Test(t, impl)
}

func TestDgeql2(t *testing.T) {
	testlapack.Dgeql2Test(t, impl)
}

func TestDgels(t *testing.T) {
	testlapack.DgelsTest(t, impl)
}

func TestDgeqr2(t *testing.T) {
	testlapack.Dgeqr2Test(t, impl)
}

func TestDgeqrf(t *testing.T) {
	testlapack.DgeqrfTest(t, impl)
}

func TestDgesvd(t *testing.T) {
	testlapack.DgesvdTest(t, impl)
}

func TestDgetri(t *testing.T) {
	testlapack.DgetriTest(t, impl)
}

func TestDgetf2(t *testing.T) {
	testlapack.Dgetf2Test(t, impl)
}

func TestDgetrf(t *testing.T) {
	testlapack.DgetrfTest(t, impl)
}

func TestDgetrs(t *testing.T) {
	testlapack.DgetrsTest(t, impl)
}

func TestDlabrd(t *testing.T) {
	testlapack.DlabrdTest(t, impl)
}

func TestDlacpy(t *testing.T) {
	testlapack.DlacpyTest(t, impl)
}

func TestDlae2(t *testing.T) {
	testlapack.Dlae2Test(t, impl)
}

func TestDlaev2(t *testing.T) {
	testlapack.Dlaev2Test(t, impl)
}

func TestDlaexc(t *testing.T) {
	testlapack.DlaexcTest(t, impl)
}

func TestDlahqr(t *testing.T) {
	testlapack.DlahqrTest(t, impl)
}

func TestDlahr2(t *testing.T) {
	testlapack.Dlahr2Test(t, impl)
}

func TestDlaln2(t *testing.T) {
	testlapack.Dlaln2Test(t, impl)
}

func TestDlange(t *testing.T) {
	testlapack.DlangeTest(t, impl)
}

func TestDlas2(t *testing.T) {
	testlapack.Dlas2Test(t, impl)
}

func TestDlasy2(t *testing.T) {
	testlapack.Dlasy2Test(t, impl)
}

func TestDlanst(t *testing.T) {
	testlapack.DlanstTest(t, impl)
}

func TestDlansy(t *testing.T) {
	testlapack.DlansyTest(t, impl)
}

func TestDlantr(t *testing.T) {
	testlapack.DlantrTest(t, impl)
}

func TestDlanv2(t *testing.T) {
	testlapack.Dlanv2Test(t, impl)
}

func TestDlaqr1(t *testing.T) {
	testlapack.Dlaqr1Test(t, impl)
}

func TestDlaqr2(t *testing.T) {
	testlapack.Dlaqr2Test(t, impl)
}

func TestDlaqr5(t *testing.T) {
	testlapack.Dlaqr5Test(t, impl)
}

func TestDlarf(t *testing.T) {
	testlapack.DlarfTest(t, impl)
}

func TestDlarfb(t *testing.T) {
	testlapack.DlarfbTest(t, impl)
}

func TestDlarfg(t *testing.T) {
	testlapack.DlarfgTest(t, impl)
}

func TestDlarft(t *testing.T) {
	testlapack.DlarftTest(t, impl)
}

func TestDlarfx(t *testing.T) {
	testlapack.DlarfxTest(t, impl)
}

func TestDlartg(t *testing.T) {
	testlapack.DlartgTest(t, impl)
}

func TestDlasq1(t *testing.T) {
	testlapack.Dlasq1Test(t, impl)
}

func TestDlasq2(t *testing.T) {
	testlapack.Dlasq2Test(t, impl)
}

func TestDlasq3(t *testing.T) {
	testlapack.Dlasq3Test(t, impl)
}

func TestDlasq4(t *testing.T) {
	testlapack.Dlasq4Test(t, impl)
}

func TestDlasq5(t *testing.T) {
	testlapack.Dlasq5Test(t, impl)
}

func TestDlasr(t *testing.T) {
	testlapack.DlasrTest(t, impl)
}

func TestDlasv2(t *testing.T) {
	testlapack.Dlasv2Test(t, impl)
}

func TestDlatrd(t *testing.T) {
	testlapack.DlatrdTest(t, impl)
}

func TestDorg2r(t *testing.T) {
	testlapack.Dorg2rTest(t, impl)
}

func TestDorgbr(t *testing.T) {
	testlapack.DorgbrTest(t, impl)
}

func TestDorghr(t *testing.T) {
	testlapack.DorghrTest(t, impl)
}

func TestDorg2l(t *testing.T) {
	testlapack.Dorg2lTest(t, impl)
}

func TestDorgl2(t *testing.T) {
	testlapack.Dorgl2Test(t, impl)
}

func TestDorglq(t *testing.T) {
	testlapack.DorglqTest(t, impl)
}

func TestDorgql(t *testing.T) {
	testlapack.DorgqlTest(t, impl)
}

func TestDorgqr(t *testing.T) {
	testlapack.DorgqrTest(t, impl)
}

func TestDorgtr(t *testing.T) {
	testlapack.DorgtrTest(t, impl)
}

func TestDormbr(t *testing.T) {
	testlapack.DormbrTest(t, impl)
}

func TestDormhr(t *testing.T) {
	testlapack.DormhrTest(t, impl)
}

func TestDorml2(t *testing.T) {
	testlapack.Dorml2Test(t, impl)
}

func TestDormlq(t *testing.T) {
	testlapack.DormlqTest(t, impl)
}

func TestDormqr(t *testing.T) {
	testlapack.DormqrTest(t, impl)
}

func TestDorm2r(t *testing.T) {
	testlapack.Dorm2rTest(t, impl)
}

func TestDpocon(t *testing.T) {
	testlapack.DpoconTest(t, impl)
}

func TestDpotf2(t *testing.T) {
	testlapack.Dpotf2Test(t, impl)
}

func TestDpotrf(t *testing.T) {
	testlapack.DpotrfTest(t, impl)
}

func TestDrscl(t *testing.T) {
	testlapack.DrsclTest(t, impl)
}

func TestDsteqr(t *testing.T) {
	testlapack.DsteqrTest(t, impl)
}

func TestDsterf(t *testing.T) {
	testlapack.DsterfTest(t, impl)
}

func TestDsyev(t *testing.T) {
	testlapack.DsyevTest(t, impl)
}

func TestDsytd2(t *testing.T) {
	testlapack.Dsytd2Test(t, impl)
}

func TestDsytrd(t *testing.T) {
	testlapack.DsytrdTest(t, impl)
}

func TestDtrcon(t *testing.T) {
	testlapack.DtrconTest(t, impl)
}

func TestDtrexc(t *testing.T) {
	testlapack.DtrexcTest(t, impl)
}

func TestDtrti2(t *testing.T) {
	testlapack.Dtrti2Test(t, impl)
}

func TestDtrtri(t *testing.T) {
	testlapack.DtrtriTest(t, impl)
}

func TestIladlc(t *testing.T) {
	testlapack.IladlcTest(t, impl)
}

func TestIladlr(t *testing.T) {
	testlapack.IladlrTest(t, impl)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/WhiteHatCP/seclab-listener/backend"
	"github.com/WhiteHatCP/seclab-listener/server"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
)

const (
	maxPacketAge = 10
)

func openSock(path string) (net.Listener, error) {
	if err := syscall.Unlink(path); err != nil && err != syscall.EEXIST {
		return nil, err
	}
	ln, err := net.Listen("unix", socket)
	if err != nil {
		return nil, err
	}
	if err := syscall.Chmod(path, 0770); err != nil {
		return nil, err
	}
	return ln, nil
}

func main() {
	if len(os.Args)%3 != 2 {
		fmt.Fprintf(os.Stderr, "usage: seclab key [dest open closed [..]]\n")
		return
	}
	keypath := os.Args[1]
	s := server.New(keypath, maxPacketAge)

	for i := 2; i+2 < len(os.Args); i += 3 {
		dest := os.Args[i]
		openfile := os.Args[i+1]
		closedfile := os.Args[i+2]
		s.AddBackend(backend.New(dest, openfile, closedfile))
	}

	syscall.Umask(0007)

	socket := "seclab.sock"
	ln, err := openSock(socket)
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()

	// Make sure the socket closes
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		for _ = range c {
			ln.Close()
		}
	}()

	s.Serve(ln)
}
<commit_msg>Fix typo<commit_after>package main

import (
	"fmt"
	"github.com/WhiteHatCP/seclab-listener/backend"
	"github.com/WhiteHatCP/seclab-listener/server"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
)

const (
	maxPacketAge = 10
)

func openSock(path string) (net.Listener, error) {
	if err := syscall.Unlink(path); err != nil && err != syscall.EEXIST {
		return nil, err
	}
	ln, err := net.Listen("unix", path)
	if err != nil {
		return nil, err
	}
	if err := syscall.Chmod(path, 0770); err != nil {
		return nil, err
	}
	return ln, nil
}

func main() {
	if len(os.Args)%3 != 2 {
		fmt.Fprintf(os.Stderr, "usage: seclab key [dest open closed [..]]\n")
		return
	}
	keypath := os.Args[1]
	s := server.New(keypath, maxPacketAge)

	for i := 2; i+2 < len(os.Args); i += 3 {
		dest := os.Args[i]
		openfile := os.Args[i+1]
		closedfile := os.Args[i+2]
		s.AddBackend(backend.New(dest, openfile, closedfile))
	}

	syscall.Umask(0007)

	socket := "seclab.sock"
	ln, err := openSock(socket)
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()

	// Make sure the socket closes
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		for _ = range c {
			ln.Close()
		}
	}()

	s.Serve(ln)
}
<|endoftext|>