<commit_before>package cqrs

import (
	"errors"
	"fmt"
)

const MESSAGE_TYPE_MASK = 0x80000000
// http://crc32-checksum.waraxe.us/

func C(version uint32, commandId uint32) uint32 {
	return MESSAGE_TYPE_MASK | (version << 16) | (commandId & 0xFF)
}

func E(version uint32, commandId uint32) uint32 {
	return (MESSAGE_TYPE_MASK-1) | (version << 16) | (commandId & 0xFF)
}

type AggregateLoader interface {
	Load(events []Event)
}

type Aggregate interface {
	GetDomain() uint32
	GetId() uint64
	GetVersion() int32
	MatchById(domain uint32, id uint64) bool
}

type AggregateMemento struct {
	Domain uint32 `json:"__domain"`		// Aggregate Domain
	Id uint64 `json:"__id"`				// Aggregate Id
	Version int32 `json:"__version"`	// Aggregate Version
}

func NewAggregate(domain uint32, id uint64, version int32) AggregateMemento {
	return AggregateMemento {
		Domain: domain,
		Id: id,
		Version: version,
	}
}

func (aggregate AggregateMemento) GetDomain() uint32 {
	return aggregate.Domain
}

func (aggregate AggregateMemento) GetId() uint64 {
	return aggregate.Id
}

func (aggregate AggregateMemento) GetVersion() int32 {
	return aggregate.Version
}

func (aggregate AggregateMemento) String() string {
	return fmt.Sprintf("DM[%d] ID[%d] V[%d]", aggregate.Domain, aggregate.Id, aggregate.Version)
}

type Command interface {
	GetCommandType() uint32
}

type CommandMemento struct {
	AggregateMemento					// Aggregate
	CommandType uint32 `json:"__ctype"`	// Command Type
}

func NewCommand(domain uint32, commandType uint32, id uint64, version int32) CommandMemento {
	return CommandMemento {
		AggregateMemento: NewAggregate(domain, id, version),
		CommandType: commandType,
	}
}

func (command CommandMemento) GetCommandType() uint32 {
	return command.CommandType
}

func (command CommandMemento) String() string {
	return fmt.Sprintf(" <C [ %s -> C[%d] ] C\\> ", command.AggregateMemento.String(), command.CommandType)
}

type Event interface {
	GetEventType() uint32
}

type EventMemento struct {
	AggregateMemento					// Aggregate
	EventType uint32 `json:"__etype"`	// Event Type
}

func NewEvent(domain uint32, eventType uint32, id uint64, version int32) EventMemento {
	return EventMemento {
		AggregateMemento: NewAggregate(domain, id, version),
		EventType: eventType,
	}
}

func (event EventMemento) GetEventType() uint32 {
	return event.EventType
}

func (event EventMemento) String() string {
	return fmt.Sprintf(" <E [ %s -> E[%d] ] E\\> ", event.AggregateMemento.String(), event.EventType)
}

type EventStorer interface {
	StoreEvent(event Event)
	ReadAllEvents() (int, []Event, error)
	ReadEventsFrom(index int) (int, []Event, error)
	ReadAggregateEvents(aggregate Aggregate) ([]Event, error)
}

type MemoryEventStore struct {
	Snapshot interface{}
	Data []Event
}

func (eventstore *MemoryEventStore) StoreEvent(event Event) {
	eventstore.Data = append(eventstore.Data, event)
}

func (eventstore *MemoryEventStore) ReadAllEvents() (int, []Event, error) {
	return len(eventstore.Data), eventstore.Data, nil
}

func (eventstore *MemoryEventStore) ReadEventsFrom(index int) (int, []Event, error) {
	if index < len(eventstore.Data) {
		events := make([]Event, 0)
		for i := index; i < len(eventstore.Data); i++ {
			events = append(events, eventstore.Data[i])
		}
		return len(eventstore.Data), events, nil
	} else {
		return 0, nil, errors.New("Index position out of range")
	}
}

func (eventstore *MemoryEventStore) ReadAggregateEvents(aggregate Aggregate) ([]Event, error) {
	matching := make([]Event, 0)
	for _, item := range eventstore.Data {
		switch event := item.(type) {
			case Aggregate: {
				if (event.GetDomain() != aggregate.GetDomain() || event.GetId() != aggregate.GetId())) {
					break
				}
				matching = append(matching, item.(Event))
			}
			default: {
				return nil, errors.New(fmt.Sprintf("Item in MemoryEventStore isn't an event [ %s ]\n", item))
			}
		}
	}
	return matching, nil
}

<commit_msg>Refactored temp in-memory event store<commit_after>package cqrs

import (
	"errors"
	"fmt"
)

const MESSAGE_TYPE_MASK = 0x80000000
// http://crc32-checksum.waraxe.us/

func C(version uint32, commandId uint32) uint32 {
	return MESSAGE_TYPE_MASK | (version << 16) | (commandId & 0xFF)
}

func E(version uint32, commandId uint32) uint32 {
	return (MESSAGE_TYPE_MASK-1) | (version << 16) | (commandId & 0xFF)
}

type AggregateLoader interface {
	Load(events []Event)
}

type Aggregate interface {
	GetDomain() uint32
	GetId() uint64
	GetVersion() int32
	MatchById(domain uint32, id uint64) bool
}

type AggregateMemento struct {
	Domain uint32 `json:"__domain"`		// Aggregate Domain
	Id uint64 `json:"__id"`				// Aggregate Id
	Version int32 `json:"__version"`	// Aggregate Version
}

func NewAggregate(domain uint32, id uint64, version int32) AggregateMemento {
	return AggregateMemento {
		Domain: domain,
		Id: id,
		Version: version,
	}
}

func (aggregate AggregateMemento) GetDomain() uint32 {
	return aggregate.Domain
}

func (aggregate AggregateMemento) GetId() uint64 {
	return aggregate.Id
}

func (aggregate AggregateMemento) GetVersion() int32 {
	return aggregate.Version
}

func (aggregate AggregateMemento) String() string {
	return fmt.Sprintf("DM[%d] ID[%d] V[%d]", aggregate.Domain, aggregate.Id, aggregate.Version)
}

type Command interface {
	GetCommandType() uint32
}

type CommandMemento struct {
	AggregateMemento					// Aggregate
	CommandType uint32 `json:"__ctype"`	// Command Type
}

func NewCommand(domain uint32, commandType uint32, id uint64, version int32) CommandMemento {
	return CommandMemento {
		AggregateMemento: NewAggregate(domain, id, version),
		CommandType: commandType,
	}
}

func (command CommandMemento) GetCommandType() uint32 {
	return command.CommandType
}

func (command CommandMemento) String() string {
	return fmt.Sprintf(" <C [ %s -> C[%d] ] C\\> ", command.AggregateMemento.String(), command.CommandType)
}

type Event interface {
	GetEventType() uint32
}

type EventMemento struct {
	AggregateMemento					// Aggregate
	EventType uint32 `json:"__etype"`	// Event Type
}

func NewEvent(domain uint32, eventType uint32, id uint64, version int32) EventMemento {
	return EventMemento {
		AggregateMemento: NewAggregate(domain, id, version),
		EventType: eventType,
	}
}

func (event EventMemento) GetEventType() uint32 {
	return event.EventType
}

func (event EventMemento) String() string {
	return fmt.Sprintf(" <E [ %s -> E[%d] ] E\\> ", event.AggregateMemento.String(), event.EventType)
}

type EventStorer interface {
	PersistEvent(event Event)
	ReadAllEvents() (int, []Event, error)
//	ReadAllEventsFrom(index int) (int, []Event, error)
	ReadAggregateEvents(aggregate Aggregate) ([]Event, error)
	ReadAggregateEventsFromSnapshot(aggregate Aggregate) ([]Event, error)
}

type MemoryEventStore struct {
	Snapshot []Aggregate
	EventsChan chan Event
	Data []Event
}

func (eventstore *MemoryEventStore) PersistEvent(event Event) {
	eventstore.Data = append(eventstore.Data, event)
}

func (eventstore *MemoryEventStore) ReadAllEvents() (int, []Event, error) {
	return len(eventstore.Data), eventstore.Data, nil
}

func (eventstore *MemoryEventStore) ReadAllEventsFrom(index int) (int, []Event, error) {
	if index < len(eventstore.Data) {
		events := make([]Event, 0)
		for i := index; i < len(eventstore.Data); i++ {
			events = append(events, eventstore.Data[i])
		}
		return len(eventstore.Data), events, nil
	} else {
		return 0, nil, errors.New("Index position out of range")
	}
}

func (eventstore *MemoryEventStore) ReadAggregateEvents(aggregate Aggregate) ([]Event, error) {
	matching := make([]Event, 0)
	for _, item := range eventstore.Data {
		switch event := item.(type) {
			case Aggregate: {
				if (event.GetDomain() != aggregate.GetDomain() || event.GetId() != aggregate.GetId())) {
					break
				}
				matching = append(matching, item.(Event))
			}
			default: {
				return nil, errors.New(fmt.Sprintf("Item in MemoryEventStore isn't an event [ %s ]\n", item))
			}
		}
	}
	return matching, nil
}

func (eventstore *MemoryEventStore) ReadAggregateEventsFromSnapshot(aggregate Aggregate) ([]Event, error) {
	matching := make([]Event, 0)
	for _, item := range eventstore.Data {
		switch event := item.(type) {
			case Aggregate: {
				if (event.GetDomain() != aggregate.GetDomain() || event.GetId() != aggregate.GetId() || event.GetVersion() < aggregate.GetVersion()) {
					break
				}
				matching = append(matching, item.(Event))
			}
			default: {
				return nil, errors.New(fmt.Sprintf("Item in MemoryEventStore isn't an event [ %s ]\n", item))
			}
		}
	}
	return matching, nil
}

func (eventstore *cqrs.MemoryEventStore) PersistenceLayer(eventBus chan cqrs.Event) {
	for {
		select {
		case event := <- eventstore.EventsChan:
			eventstore.StoreEvent(event)
			eventBus <- event
		}
	}
}

<|endoftext|>


<commit_before>// gorm_handlers provides basic methods to interact with
// database using GORM. https://github.com/jinzhu/gorm

package goal

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

	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"

	_ "github.com/go-sql-driver/mysql" // Driver for mysql
	_ "github.com/lib/pq"              // Driver for postgres
	_ "github.com/mattn/go-sqlite3"    // Driver for sqlite
)

// Global variable to interact with database
var db *gorm.DB

// InitGormDb initializes global variable db
func InitGormDb(newDb *gorm.DB) {
	db = newDb
}

// DB returns global variable db
func DB() *gorm.DB {
	return db
}

// Read provides basic implementation to retrieve object
// based on request parameters
func Read(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Get assumes url requests always has "id" parameters
	vars := mux.Vars(request)

	// Retrieve id parameter
	id := vars["id"]

	// Attempt to retrieve from redis first, if not exist, retrieve from
	// database and cache it
	var err error
	if SharedCache != nil {
		name := TableName(resource)
		redisKey := DefaultCacheKey(name, id)
		err = SharedCache.Get(redisKey, resource)
		if err == nil && resource != nil {
			// Check if resource is authorized
			err = CanPerform(resource, request, true)
			if err != nil {
				return 403, nil, err
			}

			return 200, resource, nil
		}
	}

	// Retrieve from database
	err = db.First(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	// Save to redis
	if SharedCache != nil {
		key := CacheKey(resource)
		SharedCache.Set(key, resource)
	}

	// Check if resource is authorized
	err = CanPerform(resource, request, true)
	if err != nil {
		return 403, nil, err
	}

	return 200, resource, nil
}

// Create provides basic implementation to create a record
// into the database
func Create(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	err := decoder.Decode(resource)
	if err != nil {
		fmt.Println(err)
		return 500, nil, err
	}

	// Save to database
	err = db.Create(resource).Error
	if err != nil {
		return 500, nil, err
	}

	return 200, resource, nil
}

// Update provides basic implementation to update a record
// inside database
func Update(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Get assumes url requests always has "id" parameters
	vars := mux.Vars(request)

	// Retrieve id parameter, if error return 400 HTTP error code
	id := vars["id"]

	// Retrieve from database
	err := db.First(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	// Check permission
	err = CanPerform(resource, request, false)
	if err != nil {
		return 403, nil, err
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	err = decoder.Decode(resource)
	if err != nil {
		fmt.Println(err)
		return 500, nil, err
	}

	// Save to database
	err = db.Save(resource).Error
	if err != nil {
		return 500, nil, err
	}

	return 200, resource, err
}

// Delete provides basic implementation to delete a record inside
// a database
func Delete(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Get assumes url requests always has "id" parameters
	vars := mux.Vars(request)

	// Retrieve id parameter, if error return 400 HTTP error code
	id := vars["id"]

	// Retrieve from database
	err := db.First(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	// Check permission
	err = CanPerform(resource, request, false)
	if err != nil {
		return 403, nil, err
	}

	// Delete record, if failed show 500 error code
	err = db.Delete(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	return 200, nil, nil
}
<commit_msg>Test travis<commit_after>// gorm_handlers provides basic methods to interact with
// database using GORM. https://github.com/jinzhu/gorm

package goal

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

	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"

	_ "github.com/go-sql-driver/mysql" // Driver for mysql
	_ "github.com/lib/pq"              // Driver for postgres
	_ "github.com/mattn/go-sqlite3"    // Driver for sqlite
)

// Global variable to interact with database
var db *gorm.DB

// InitGormDb initializes global variable db
func InitGormDb(newDb *gorm.DB) {
	db = newDb
}

// DB returns global variable db
func DB() *gorm.DB {
	return db
}

// Read provides basic implementation to retrieve object
// based on request parameters
func Read(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Get assumes url requests always has "id" parameters
	vars := mux.Vars(request)

	// Retrieve id parameter
	id := vars["id"]

	// Attempt to retrieve from redis first, if not exist, retrieve from
	// database and cache it
	var err error
	if SharedCache != nil {
		name := TableName(resource)
		redisKey := DefaultCacheKey(name, id)
		err = SharedCache.Get(redisKey, resource)
		if err == nil && resource != nil {
			// Check if resource is authorized
			err = CanPerform(resource, request, true)
			if err != nil {
				return 403, nil, err
			}

			return 200, resource, nil
		}
	}

	// Retrieve from database
	fmt.Println("resource ", resource)
	err = db.First(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	// Save to redis
	if SharedCache != nil {
		key := CacheKey(resource)
		SharedCache.Set(key, resource)
	}

	// Check if resource is authorized
	err = CanPerform(resource, request, true)
	if err != nil {
		return 403, nil, err
	}

	return 200, resource, nil
}

// Create provides basic implementation to create a record
// into the database
func Create(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	err := decoder.Decode(resource)
	if err != nil {
		fmt.Println(err)
		return 500, nil, err
	}

	// Save to database
	err = db.Create(resource).Error
	if err != nil {
		return 500, nil, err
	}

	return 200, resource, nil
}

// Update provides basic implementation to update a record
// inside database
func Update(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Get assumes url requests always has "id" parameters
	vars := mux.Vars(request)

	// Retrieve id parameter, if error return 400 HTTP error code
	id := vars["id"]

	// Retrieve from database
	err := db.First(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	// Check permission
	err = CanPerform(resource, request, false)
	if err != nil {
		return 403, nil, err
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	err = decoder.Decode(resource)
	if err != nil {
		fmt.Println(err)
		return 500, nil, err
	}

	// Save to database
	err = db.Save(resource).Error
	if err != nil {
		return 500, nil, err
	}

	return 200, resource, err
}

// Delete provides basic implementation to delete a record inside
// a database
func Delete(resource interface{}, request *http.Request) (int, interface{}, error) {
	if db == nil {
		panic("Database is not initialized yet")
	}

	// Get assumes url requests always has "id" parameters
	vars := mux.Vars(request)

	// Retrieve id parameter, if error return 400 HTTP error code
	id := vars["id"]

	// Retrieve from database
	err := db.First(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	// Check permission
	err = CanPerform(resource, request, false)
	if err != nil {
		return 403, nil, err
	}

	// Delete record, if failed show 500 error code
	err = db.Delete(resource, id).Error
	if err != nil {
		return 500, nil, err
	}

	return 200, nil, nil
}
<|endoftext|>


<commit_before>package composition

import (
	"github.com/tarent/lib-compose/logging"
	"strings"
	"time"
)

type CachingContentLoader struct {
	httpContentLoader ContentLoader
	fileContentLoader ContentLoader
	cache             Cache
}

func NewCachingContentLoader(cache Cache) *CachingContentLoader {
	return &CachingContentLoader{
		httpContentLoader: NewHttpContentLoader(),
		fileContentLoader: NewFileContentLoader(),
		cache:             cache,
	}
}

func (loader *CachingContentLoader) Load(fd *FetchDefinition) (Content, error) {
	hash := fd.Hash()

	if cFromCache, exist := loader.cache.Get(hash); exist {
		logging.Cacheinfo(fd.URL, true)
		return cFromCache.(Content), nil
	}
	logging.Cacheinfo(fd.URL, false)
	c, err := loader.load(fd)
	if err == nil {
		if fd.IsCachable(c.HttpStatusCode(), c.HttpHeader()) {
			loader.cache.Set(hash, fd.URL, c.MemorySize(), c)
		}
	}
	return c, err
}

func (loader *CachingContentLoader) load(fd *FetchDefinition) (Content, error) {
	if strings.HasPrefix(fd.URL, FileURLPrefix) {
		return loader.fileContentLoader.Load(fd)
	}
	return loader.httpContentLoader.Load(fd)
}
<commit_msg>changed cache_loader constructor<commit_after>package composition

import (
	"github.com/tarent/lib-compose/logging"
	"strings"
)

type CachingContentLoader struct {
	httpContentLoader ContentLoader
	fileContentLoader ContentLoader
	cache             Cache
}

func NewCachingContentLoader(cache Cache) *CachingContentLoader {
	return &CachingContentLoader{
		httpContentLoader: NewHttpContentLoader(),
		fileContentLoader: NewFileContentLoader(),
		cache:             cache,
	}
}

func (loader *CachingContentLoader) Load(fd *FetchDefinition) (Content, error) {
	hash := fd.Hash()

	if cFromCache, exist := loader.cache.Get(hash); exist {
		logging.Cacheinfo(fd.URL, true)
		return cFromCache.(Content), nil
	}
	logging.Cacheinfo(fd.URL, false)
	c, err := loader.load(fd)
	if err == nil {
		if fd.IsCachable(c.HttpStatusCode(), c.HttpHeader()) {
			loader.cache.Set(hash, fd.URL, c.MemorySize(), c)
		}
	}
	return c, err
}

func (loader *CachingContentLoader) load(fd *FetchDefinition) (Content, error) {
	if strings.HasPrefix(fd.URL, FileURLPrefix) {
		return loader.fileContentLoader.Load(fd)
	}
	return loader.httpContentLoader.Load(fd)
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

package ini

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"
)

func TestGetKeysAlpha(t *testing.T) {
	input := map[string]string{
		"a": "a",
		"b": "b",
		"f": "f",
		"e": "e",
		"d": "d",
		"c": "c",
	}

	got := getMapsKeysAlpha(input)
	expects := []string{"a", "b", "c", "d", "e", "f"}

	if len(got) != len(expects) {
		t.Fatalf("Expected getMapsKeysAlpha(%v) to return %v, got %v",
			input, expects, got)
	}

	for i, k := range got {
		if expected := expects[i]; k != expected {
			t.Fatalf("Expected getMapsKeysAlpha(%v) to return %v, got %v",
				input, expects, got)
		}
	}
}

func TestLoad(t *testing.T) {
	const input = "testdata/config.ini"
	c, err := Load(input)
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		section  string
		key      string
		expected string
	}{
		{Global, "name", "http server"},
		{Global, "msg", "Welcome \"Bob\""},
		{"http", "port", "8080"},
		{"http", "url", "example.com"},
		{"database", "user", "bob"},
		{"database", "password", "password"},
	}

	for _, test := range tests {
		if got := c[test.section][test.key]; got != test.expected {
			t.Fatalf("Expected Load(%q) to return config[%q][%q] to be %q, but got %q",
				input, test.section, test.key, test.expected, got)
		}
	}
}

func TestLoadErrors(t *testing.T) {
	tests := []struct {
		input    string
		expected Config
		err      error
		altCheck bool
	}{
		{"testdata/malformed.cfg", nil,
			newSynthaxError(2, "error = 'oops!\"", "qoute not closed"), false},
		{"testdata", nil, errors.New("ini: only loading files is supported"), false},
		{"testdata/notfound", nil, nil, true},
	}

	for _, test := range tests {
		c, err := Load(test.input)

		if test.altCheck {
			if !os.IsNotExist(err) {
				t.Fatalf("Expected Load(%q) the return error to be file doesn't exists, but got %q",
					test.input, err.Error())
			}
		} else {
			if err == nil && test.err != nil {
				t.Fatalf(`Expected Load(%q) to return error "%v", but didn't got one`,
					test.input, test.err)
			} else if err.Error() != test.err.Error() {
				t.Fatalf(`Expected Load(%q) to return error "%v", but got "%v"`,
					test.input, test.err, err)
			}
		}

		if c != nil {
			t.Fatalf("Expected Load(%q) the return config to be nil, got %v",
				test.input, c)
		}
	}
}

func TestConfigString(t *testing.T) {
	var expectedConfigString = `key1=value1` + "\n" +
		`key2"=value2` + "\n" +
		`key3=value"3` + "\n\n" +

		`[Section1]` + "\n" +
		`key1=value1` + "\n" +
		`key2"=value2` + "\n" +
		`key3=value"3` + "\n\n" +

		`[Section2]` + "\n" +
		`key1=value1` + "\n" +
		`key2"=value2` + "\n" +
		`key3=value"3` + "\n\n"

	section := map[string]string{
		"key1":  "value1",
		`key2"`: "value2",
		"key3":  `value"3`,
	}

	c := Config{
		Global:     section,
		"Section1": section,
		"Section2": section,
	}

	if got := c.String(); got != expectedConfigString {
		t.Fatalf("Expected Config{}.String() to return %q, but got %q",
			expectedConfigString, got)
	}
}

func TestComplete(t *testing.T) {
	t.Skip()
	c, err := Load("testdata/config.ini")
	if err != nil {
		t.Fatal(err)
	}

	// Create a temp file
	tmpF, err := ioutil.TempFile("", "INI-TEST")
	if err != nil {
		t.Fatal(err)
	}

	tmpPath := tmpF.Name()

	// Write our config and close the file
	tmpF.WriteString(c.String())
	tmpF.Close()

	// Reopen the tmp config
	f, err := os.Open(tmpPath)
	if err != nil {
		t.Fatal(err)
	}

	// Parse the temp config file
	c2, err := Parse(f)
	if err != nil {
		t.Fatal(err)
	}
	f.Close()

	// Compare configurations
	if len(c) != len(c2) {
		t.Fatalf("Length doesn't match, got %d and %d", len(c), len(c2))
	}

	for sectionName, loadedSection := range c {
		for key, loadedValue := range loadedSection {
			parsedValue := c2[sectionName][key]
			if loadedValue != parsedValue {
				t.Fatalf("Expected, in section %q, the keys %q to be the same, but got %q and %q",
					sectionName, key, loadedValue, parsedValue)
			}
		}
	}

	// Cleanup
	if err := os.Remove(tmpPath); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Add test for getConfigSectionsAlpha<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

package ini

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"
)

func TestGetKeysAlpha(t *testing.T) {
	input := map[string]string{
		"a": "a",
		"b": "b",
		"f": "f",
		"e": "e",
		"d": "d",
		"c": "c",
	}

	got := getMapsKeysAlpha(input)
	expects := []string{"a", "b", "c", "d", "e", "f"}

	if len(got) != len(expects) {
		t.Fatalf("Expected getMapsKeysAlpha(%v) to return %v, got %v",
			input, expects, got)
	}

	for i, k := range got {
		if expected := expects[i]; k != expected {
			t.Fatalf("Expected getMapsKeysAlpha(%v) to return %v, got %v",
				input, expects, got)
		}
	}
}

func TestGetConfigSectionsAlpha(t *testing.T) {
	c := Config{Global: {}, "section1": {}, "section2": {}}

	got := getConfigSectionsAlpha(c)
	expects := []string{Global, "section1", "section2"}

	if len(got) != len(expects) {
		t.Fatalf("Expected getConfigSectionsAlpha(%v) to return %v, got %v",
			c, expects, got)
	}

	for i, k := range got {
		if expected := expects[i]; k != expected {
			t.Fatalf("Expected getConfigSectionsAlpha(%v) to return %v, got %v",
				c, expects, got)
		}
	}
}

func TestLoad(t *testing.T) {
	const input = "testdata/config.ini"
	c, err := Load(input)
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		section  string
		key      string
		expected string
	}{
		{Global, "name", "http server"},
		{Global, "msg", "Welcome \"Bob\""},
		{"http", "port", "8080"},
		{"http", "url", "example.com"},
		{"database", "user", "bob"},
		{"database", "password", "password"},
	}

	for _, test := range tests {
		if got := c[test.section][test.key]; got != test.expected {
			t.Fatalf("Expected Load(%q) to return config[%q][%q] to be %q, but got %q",
				input, test.section, test.key, test.expected, got)
		}
	}
}

func TestLoadErrors(t *testing.T) {
	tests := []struct {
		input    string
		expected Config
		err      error
		altCheck bool
	}{
		{"testdata/malformed.cfg", nil,
			newSynthaxError(2, "error = 'oops!\"", "qoute not closed"), false},
		{"testdata", nil, errors.New("ini: only loading files is supported"), false},
		{"testdata/notfound", nil, nil, true},
	}

	for _, test := range tests {
		c, err := Load(test.input)

		if test.altCheck {
			if !os.IsNotExist(err) {
				t.Fatalf("Expected Load(%q) the return error to be file doesn't exists, but got %q",
					test.input, err.Error())
			}
		} else {
			if err == nil && test.err != nil {
				t.Fatalf(`Expected Load(%q) to return error "%v", but didn't got one`,
					test.input, test.err)
			} else if err.Error() != test.err.Error() {
				t.Fatalf(`Expected Load(%q) to return error "%v", but got "%v"`,
					test.input, test.err, err)
			}
		}

		if c != nil {
			t.Fatalf("Expected Load(%q) the return config to be nil, got %v",
				test.input, c)
		}
	}
}

func TestConfigString(t *testing.T) {
	var expectedConfigString = `key1=value1` + "\n" +
		`key2"=value2` + "\n" +
		`key3=value"3` + "\n\n" +

		`[Section1]` + "\n" +
		`key1=value1` + "\n" +
		`key2"=value2` + "\n" +
		`key3=value"3` + "\n\n" +

		`[Section2]` + "\n" +
		`key1=value1` + "\n" +
		`key2"=value2` + "\n" +
		`key3=value"3` + "\n\n"

	section := map[string]string{
		"key1":  "value1",
		`key2"`: "value2",
		"key3":  `value"3`,
	}

	c := Config{
		Global:     section,
		"Section1": section,
		"Section2": section,
	}

	if got := c.String(); got != expectedConfigString {
		t.Fatalf("Expected Config{}.String() to return %q, but got %q",
			expectedConfigString, got)
	}
}

func TestComplete(t *testing.T) {
	t.Skip()
	c, err := Load("testdata/config.ini")
	if err != nil {
		t.Fatal(err)
	}

	// Create a temp file
	tmpF, err := ioutil.TempFile("", "INI-TEST")
	if err != nil {
		t.Fatal(err)
	}

	tmpPath := tmpF.Name()

	// Write our config and close the file
	tmpF.WriteString(c.String())
	tmpF.Close()

	// Reopen the tmp config
	f, err := os.Open(tmpPath)
	if err != nil {
		t.Fatal(err)
	}

	// Parse the temp config file
	c2, err := Parse(f)
	if err != nil {
		t.Fatal(err)
	}
	f.Close()

	// Compare configurations
	if len(c) != len(c2) {
		t.Fatalf("Length doesn't match, got %d and %d", len(c), len(c2))
	}

	for sectionName, loadedSection := range c {
		for key, loadedValue := range loadedSection {
			parsedValue := c2[sectionName][key]
			if loadedValue != parsedValue {
				t.Fatalf("Expected, in section %q, the keys %q to be the same, but got %q and %q",
					sectionName, key, loadedValue, parsedValue)
			}
		}
	}

	// Cleanup
	if err := os.Remove(tmpPath); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package tunnel

import (
	"fmt"
	"io"
	"net"
	"time"

	logger "github.com/ije/gox/log"
	"github.com/ije/gox/net/aestcp"
)

var log = &logger.Logger{}

func init() {
	log.SetLevel(logger.L_INFO)
}

func SetLogger(l *logger.Logger) {
	if l != nil {
		log = l
	}
}

func SetLogLevel(level string) {
	log.SetLevelByName(level)
}

func dial(network string, address string, aes string) (conn net.Conn, err error) {
	for i := 0; i < 10; i++ {
		if len(aes) > 0 {
			conn, err = aestcp.Dial(network, address, []byte(aes))
		} else {
			conn, err = net.Dial(network, address)
		}
		if err == nil {
			return
		}
		time.Sleep(100 * time.Millisecond)
	}
	return
}

func listen(l net.Listener, connHandler func(net.Conn)) error {
	defer l.Close()

	var tempDelay time.Duration
	for {
		conn, e := l.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if tempDelay > time.Second {
					tempDelay = time.Second
				}
				time.Sleep(tempDelay)
				log.Warnf("net: Accept error: %v; retrying in %v", e, tempDelay)
				continue
			}
			return e
		}
		tempDelay = 0
		go connHandler(conn)
	}
}

func proxy(conn net.Conn, proxyConn net.Conn) {
	defer conn.Close()
	defer proxyConn.Close()

	closeChan := make(chan struct{}, 1)

	go func(conn net.Conn, proxyConn net.Conn, cc chan struct{}) {
		io.Copy(proxyConn, conn)
		cc <- struct{}{}
	}(proxyConn, conn, closeChan)

	go func(conn net.Conn, proxyConn net.Conn, cc chan struct{}) {
		io.Copy(conn, proxyConn)
		cc <- struct{}{}
	}(proxyConn, conn, closeChan)

	<-closeChan
}

func errf(format string, a ...interface{}) error {
	return fmt.Errorf(format, a...)
}

func strf(format string, a ...interface{}) string {
	return fmt.Sprintf(format, a...)
}
<commit_msg>must dial by aestcp<commit_after>package tunnel

import (
	"fmt"
	"io"
	"net"
	"time"

	logger "github.com/ije/gox/log"
	"github.com/ije/gox/net/aestcp"
)

var log = &logger.Logger{}

func init() {
	log.SetLevel(logger.L_INFO)
}

func SetLogger(l *logger.Logger) {
	if l != nil {
		log = l
	}
}

func SetLogLevel(level string) {
	log.SetLevelByName(level)
}

func dial(network string, address string, aes string) (conn net.Conn, err error) {
	for i := 0; i < 10; i++ {
		conn, err = aestcp.Dial(network, address, []byte(aes))
		if err == nil {
			return
		}
		time.Sleep(100 * time.Millisecond)
	}
	return
}

func listen(l net.Listener, connHandler func(net.Conn)) error {
	defer l.Close()

	var tempDelay time.Duration
	for {
		conn, e := l.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if tempDelay > time.Second {
					tempDelay = time.Second
				}
				time.Sleep(tempDelay)
				log.Warnf("net: Accept error: %v; retrying in %v", e, tempDelay)
				continue
			}
			return e
		}
		tempDelay = 0
		go connHandler(conn)
	}
}

func proxy(conn net.Conn, proxyConn net.Conn) {
	defer conn.Close()
	defer proxyConn.Close()

	closeChan := make(chan struct{}, 1)

	go func(conn net.Conn, proxyConn net.Conn, cc chan struct{}) {
		io.Copy(proxyConn, conn)
		cc <- struct{}{}
	}(proxyConn, conn, closeChan)

	go func(conn net.Conn, proxyConn net.Conn, cc chan struct{}) {
		io.Copy(conn, proxyConn)
		cc <- struct{}{}
	}(proxyConn, conn, closeChan)

	<-closeChan
}

func errf(format string, a ...interface{}) error {
	return fmt.Errorf(format, a...)
}

func strf(format string, a ...interface{}) string {
	return fmt.Sprintf(format, a...)
}
<|endoftext|>


<commit_before>package network

import (
	"golang.org/x/time/rate"
	"math"
	"math/rand"
	"time"
)

type Throttler struct {
	limiter   *rate.Limiter
	onBackOff func(int)
}

func NewThrottler(throttleLimit int, onBackOffFn func(int)) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: onBackOffFn,
	}
}

func NewStaticBackoffThrottler(throttleLimit int, backOffDuration time.Duration) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: staticBackoffFn(backOffDuration),
	}
}

func staticBackoffFn(backOffDuration time.Duration) func(attempt int) {
	return func(attempt int) {
		time.Sleep(backOffDuration)
	}
}

func NewIncrementalBackoffThrottler(throttleLimit int, backOffDuration time.Duration, incrementDuration time.Duration) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: incrementalBackoffFn(backOffDuration, incrementDuration),
	}
}

func incrementalBackoffFn(backOffDuration time.Duration, incrementDuration time.Duration) func(attempt int) {
	return func(attempt int) {
		sleepMillis := float64(backOffDuration.Milliseconds()) + math.Pow(float64(incrementDuration), float64(attempt))
		time.Sleep(time.Duration(sleepMillis) * time.Millisecond)
	}
}

func NewRandomisedBackoffThrottler(throttleLimit int, minDuration, maxDuration time.Duration) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: randomisedBackoffFn(maxDuration, minDuration),
	}
}

func randomisedBackoffFn(maxDuration time.Duration, minDuration time.Duration) func(attempt int) {
	return func(attempt int) {
		randMillis := (rand.Int63() * (maxDuration.Milliseconds() - minDuration.Milliseconds())) + minDuration.Milliseconds()
		time.Sleep(time.Duration(randMillis) * time.Millisecond)
	}
}

func (t *Throttler) Acquire() {
	attempt := 0
	for {
		if t.limiter.Allow() {
			break
		}

		attempt += 1
		t.onBackOff(attempt)
	}
}
<commit_msg>Discard unused parameter<commit_after>package network

import (
	"golang.org/x/time/rate"
	"math"
	"math/rand"
	"time"
)

type Throttler struct {
	limiter   *rate.Limiter
	onBackOff func(int)
}

func NewThrottler(throttleLimit int, onBackOffFn func(int)) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: onBackOffFn,
	}
}

func NewStaticBackoffThrottler(throttleLimit int, backOffDuration time.Duration) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: staticBackoffFn(backOffDuration),
	}
}

func staticBackoffFn(backOffDuration time.Duration) func(attempt int) {
	return func(_ int) {
		time.Sleep(backOffDuration)
	}
}

func NewIncrementalBackoffThrottler(throttleLimit int, backOffDuration time.Duration, incrementDuration time.Duration) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: incrementalBackoffFn(backOffDuration, incrementDuration),
	}
}

func incrementalBackoffFn(backOffDuration time.Duration, incrementDuration time.Duration) func(attempt int) {
	return func(attempt int) {
		sleepMillis := float64(backOffDuration.Milliseconds()) + math.Pow(float64(incrementDuration), float64(attempt))
		time.Sleep(time.Duration(sleepMillis) * time.Millisecond)
	}
}

func NewRandomisedBackoffThrottler(throttleLimit int, minDuration, maxDuration time.Duration) Throttler {
	return Throttler{
		limiter:   rate.NewLimiter(rate.Limit(throttleLimit), throttleLimit),
		onBackOff: randomisedBackoffFn(maxDuration, minDuration),
	}
}

func randomisedBackoffFn(maxDuration time.Duration, minDuration time.Duration) func(attempt int) {
	return func(attempt int) {
		randMillis := (rand.Int63() * (maxDuration.Milliseconds() - minDuration.Milliseconds())) + minDuration.Milliseconds()
		time.Sleep(time.Duration(randMillis) * time.Millisecond)
	}
}

func (t *Throttler) Acquire() {
	attempt := 0
	for {
		if t.limiter.Allow() {
			break
		}

		attempt += 1
		t.onBackOff(attempt)
	}
}
<|endoftext|>


<commit_before>package secp256k1

// TODO: set USE_SCALAR_4X64 depending on platform?

/*
#cgo CFLAGS: -I./secp256k1
#define USE_NUM_GMP
#define USE_FIELD_10X26
#define USE_FIELD_INV_BUILTIN
#define USE_SCALAR_8X32
#define USE_SCALAR_INV_BUILTIN
#include "./secp256k1/src/secp256k1.c"
*/
import "C"

import (
	"bytes"
	"errors"
	"unsafe"

	"github.com/ethereum/go-ethereum/crypto/randentropy"
)

//#define USE_FIELD_5X64

/*
   Todo:
   > Centralize key management in module
   > add pubkey/private key struct
   > Dont let keys leave module; address keys as ints

   > store private keys in buffer and shuffle (deters persistance on swap disc)
   > Byte permutation (changing)
   > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)

   On Disk
   > Store keys in wallets
   > use slow key derivation function for wallet encryption key (2 seconds)
*/

func init() {
	//takes 10ms to 100ms
	C.secp256k1_start(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
}

func Stop() {
	C.secp256k1_stop()
}

func GenerateKeyPair() ([]byte, []byte) {

	pubkey_len := C.int(65)
	const seckey_len = 32

	var pubkey []byte = make([]byte, pubkey_len)
	var seckey []byte = randentropy.GetEntropyMixed(seckey_len)

	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))

	ret := C.secp256k1_ec_pubkey_create(
		pubkey_ptr, &pubkey_len,
		seckey_ptr, 0)

	if ret != C.int(1) {
		return GenerateKeyPair() //invalid secret, try again
	}
	return pubkey, seckey
}

func GeneratePubKey(seckey []byte) ([]byte, error) {
	if err := VerifySeckeyValidity(seckey); err != nil {
		return nil, err
	}

	pubkey_len := C.int(65)
	const seckey_len = 32

	var pubkey []byte = make([]byte, pubkey_len)

	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))

	ret := C.secp256k1_ec_pubkey_create(
		pubkey_ptr, &pubkey_len,
		seckey_ptr, 0)

	if ret != C.int(1) {
		return nil, errors.New("Unable to generate pubkey from seckey")
	}

	return pubkey, nil
}

func Sign(msg []byte, seckey []byte) ([]byte, error) {
	nonce := randentropy.GetEntropyMixed(32)

	var sig []byte = make([]byte, 65)
	var recid C.int

	var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
	var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))

	var noncefp_ptr = &(*C.secp256k1_nonce_function_default)
	var ndata_ptr = unsafe.Pointer(&nonce[0])

	if C.secp256k1_ec_seckey_verify(seckey_ptr) != C.int(1) {
		return nil, errors.New("Invalid secret key")
	}

	ret := C.secp256k1_ecdsa_sign_compact(
		msg_ptr,
		sig_ptr,
		seckey_ptr,
		noncefp_ptr,
		ndata_ptr,
		&recid)

	sig[64] = byte(int(recid))

	if ret != C.int(1) {
		// nonce invalid, retry
		return Sign(msg, seckey)
	}

	return sig, nil

}

func VerifySeckeyValidity(seckey []byte) error {
	if len(seckey) != 32 {
		return errors.New("priv key is not 32 bytes")
	}
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
	ret := C.secp256k1_ec_seckey_verify(seckey_ptr)
	if int(ret) != 1 {
		return errors.New("invalid seckey")
	}
	return nil
}

func VerifyPubkeyValidity(pubkey []byte) error {
	if len(pubkey) != 65 {
		return errors.New("pub key is not 65 bytes")
	}
	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
	ret := C.secp256k1_ec_pubkey_verify(pubkey_ptr, 65)
	if int(ret) != 1 {
		return errors.New("invalid pubkey")
	}

	return nil
}

func VerifySignatureValidity(sig []byte) bool {
	//64+1
	if len(sig) != 65 {
		return false
	}
	//malleability check, highest bit must be 1
	if (sig[32] & 0x80) == 0x80 {
		return false
	}
	//recovery id check
	if sig[64] >= 4 {
		return false
	}

	return true
}

//for compressed signatures, does not need pubkey
func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error {
	if msg == nil || sig == nil || pubkey1 == nil {
		return errors.New("inputs must be non-nil")
	}
	if len(sig) != 65 {
		return errors.New("invalid signature length")
	}
	if len(pubkey1) != 65 {
		return errors.New("Invalid public key length")
	}

	//to enforce malleability, highest bit of S must be 0
	//S starts at 32nd byte
	if (sig[32] & 0x80) == 0x80 { //highest bit must be 1
		return errors.New("Signature not malleable")
	}

	if sig[64] >= 4 {
		return errors.New("Recover byte invalid")
	}

	// if pubkey recovered, signature valid
	pubkey2, err := RecoverPubkey(msg, sig)
	if err != nil {
		return err
	}
	if len(pubkey2) != 65 {
		return errors.New("Invalid recovered public key length")
	}
	if !bytes.Equal(pubkey1, pubkey2) {
		return errors.New("Public key does not match recovered public key")
	}

	return nil
}

//recovers the public key from the signature
//recovery of pubkey means correct signature
func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
	if len(sig) != 65 {
		return nil, errors.New("Invalid signature length")
	}

	var pubkey []byte = make([]byte, 65)

	var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
	var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))

	var pubkeylen C.int

	ret := C.secp256k1_ecdsa_recover_compact(
		msg_ptr,
		sig_ptr,
		pubkey_ptr,
		&pubkeylen,
		C.int(0),
		C.int(sig[64]),
	)

	if ret == C.int(0) {
		return nil, errors.New("Failed to recover public key")
	} else if pubkeylen != C.int(65) {
		return nil, errors.New("Impossible Error: Invalid recovered public key length")
	} else {
		return pubkey, nil
	}
	return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state")
}
<commit_msg>Link GMP<commit_after>package secp256k1

// TODO: set USE_SCALAR_4X64 depending on platform?

/*
#cgo CFLAGS: -I./secp256k1
#cgo darwin CFLAGS: -I/usr/local/include
#cgo LDFLAGS: -lgmp
#cgo darwin LDFLAGS: -L/usr/local/lib
#define USE_NUM_GMP
#define USE_FIELD_10X26
#define USE_FIELD_INV_BUILTIN
#define USE_SCALAR_8X32
#define USE_SCALAR_INV_BUILTIN
#include "./secp256k1/src/secp256k1.c"
*/
import "C"

import (
	"bytes"
	"errors"
	"unsafe"

	"github.com/ethereum/go-ethereum/crypto/randentropy"
)

//#define USE_FIELD_5X64

/*
   Todo:
   > Centralize key management in module
   > add pubkey/private key struct
   > Dont let keys leave module; address keys as ints

   > store private keys in buffer and shuffle (deters persistance on swap disc)
   > Byte permutation (changing)
   > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)

   On Disk
   > Store keys in wallets
   > use slow key derivation function for wallet encryption key (2 seconds)
*/

func init() {
	//takes 10ms to 100ms
	C.secp256k1_start(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
}

func Stop() {
	C.secp256k1_stop()
}

func GenerateKeyPair() ([]byte, []byte) {

	pubkey_len := C.int(65)
	const seckey_len = 32

	var pubkey []byte = make([]byte, pubkey_len)
	var seckey []byte = randentropy.GetEntropyMixed(seckey_len)

	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))

	ret := C.secp256k1_ec_pubkey_create(
		pubkey_ptr, &pubkey_len,
		seckey_ptr, 0)

	if ret != C.int(1) {
		return GenerateKeyPair() //invalid secret, try again
	}
	return pubkey, seckey
}

func GeneratePubKey(seckey []byte) ([]byte, error) {
	if err := VerifySeckeyValidity(seckey); err != nil {
		return nil, err
	}

	pubkey_len := C.int(65)
	const seckey_len = 32

	var pubkey []byte = make([]byte, pubkey_len)

	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))

	ret := C.secp256k1_ec_pubkey_create(
		pubkey_ptr, &pubkey_len,
		seckey_ptr, 0)

	if ret != C.int(1) {
		return nil, errors.New("Unable to generate pubkey from seckey")
	}

	return pubkey, nil
}

func Sign(msg []byte, seckey []byte) ([]byte, error) {
	nonce := randentropy.GetEntropyMixed(32)

	var sig []byte = make([]byte, 65)
	var recid C.int

	var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
	var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))

	var noncefp_ptr = &(*C.secp256k1_nonce_function_default)
	var ndata_ptr = unsafe.Pointer(&nonce[0])

	if C.secp256k1_ec_seckey_verify(seckey_ptr) != C.int(1) {
		return nil, errors.New("Invalid secret key")
	}

	ret := C.secp256k1_ecdsa_sign_compact(
		msg_ptr,
		sig_ptr,
		seckey_ptr,
		noncefp_ptr,
		ndata_ptr,
		&recid)

	sig[64] = byte(int(recid))

	if ret != C.int(1) {
		// nonce invalid, retry
		return Sign(msg, seckey)
	}

	return sig, nil

}

func VerifySeckeyValidity(seckey []byte) error {
	if len(seckey) != 32 {
		return errors.New("priv key is not 32 bytes")
	}
	var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
	ret := C.secp256k1_ec_seckey_verify(seckey_ptr)
	if int(ret) != 1 {
		return errors.New("invalid seckey")
	}
	return nil
}

func VerifyPubkeyValidity(pubkey []byte) error {
	if len(pubkey) != 65 {
		return errors.New("pub key is not 65 bytes")
	}
	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
	ret := C.secp256k1_ec_pubkey_verify(pubkey_ptr, 65)
	if int(ret) != 1 {
		return errors.New("invalid pubkey")
	}

	return nil
}

func VerifySignatureValidity(sig []byte) bool {
	//64+1
	if len(sig) != 65 {
		return false
	}
	//malleability check, highest bit must be 1
	if (sig[32] & 0x80) == 0x80 {
		return false
	}
	//recovery id check
	if sig[64] >= 4 {
		return false
	}

	return true
}

//for compressed signatures, does not need pubkey
func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error {
	if msg == nil || sig == nil || pubkey1 == nil {
		return errors.New("inputs must be non-nil")
	}
	if len(sig) != 65 {
		return errors.New("invalid signature length")
	}
	if len(pubkey1) != 65 {
		return errors.New("Invalid public key length")
	}

	//to enforce malleability, highest bit of S must be 0
	//S starts at 32nd byte
	if (sig[32] & 0x80) == 0x80 { //highest bit must be 1
		return errors.New("Signature not malleable")
	}

	if sig[64] >= 4 {
		return errors.New("Recover byte invalid")
	}

	// if pubkey recovered, signature valid
	pubkey2, err := RecoverPubkey(msg, sig)
	if err != nil {
		return err
	}
	if len(pubkey2) != 65 {
		return errors.New("Invalid recovered public key length")
	}
	if !bytes.Equal(pubkey1, pubkey2) {
		return errors.New("Public key does not match recovered public key")
	}

	return nil
}

//recovers the public key from the signature
//recovery of pubkey means correct signature
func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
	if len(sig) != 65 {
		return nil, errors.New("Invalid signature length")
	}

	var pubkey []byte = make([]byte, 65)

	var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
	var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
	var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))

	var pubkeylen C.int

	ret := C.secp256k1_ecdsa_recover_compact(
		msg_ptr,
		sig_ptr,
		pubkey_ptr,
		&pubkeylen,
		C.int(0),
		C.int(sig[64]),
	)

	if ret == C.int(0) {
		return nil, errors.New("Failed to recover public key")
	} else if pubkeylen != C.int(65) {
		return nil, errors.New("Impossible Error: Invalid recovered public key length")
	} else {
		return pubkey, nil
	}
	return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state")
}
<|endoftext|>


<commit_before>package orm

import (
	"testing"
)

func TestDeleteByID(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest := DSLTest{FieldString: "teststring", FieldInt: 123}
	err = ormTest.Save(&dslTest)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	id := dslTest.ID
	if id != 1 {
		t.Fatalf("\ndslTest.ID got:\t %v\nWant:\t\t\t 1\n", id)
	}

	n, err := ormTest.Delete().ByID(id)

	if n != 1 {
		t.Fatalf("\ndeleted got:\t %v\nWant:\t\t\t 1\n", n)
	}

	if err != nil {
		t.Fatalf("\nerr got:\t %v\nWant:\t\t\t nil\n", err)
	}

	dslTestFind, err := ormTest.Select().ByID(id)
	if dslTestFind != nil {
		t.Fatalf("\ndslTest got:\t %v\nWant:\t\t\t nil\n", dslTest)
	}

	if err.Error() != "sql: no rows in result set" {
		t.Fatalf("want: `sql: no rows in result set`, got: `%v`", err)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().ByID(id)
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteWhere(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 2 {
		t.Fatalf("want: 2, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 2 {
		t.Fatalf("want: 2, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().Where("FieldString like 'teststring%'")
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteAll(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest3 := DSLTest{FieldString: "teststring3", FieldInt: 333}
	err = ormTest.Save(&dslTest3)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().All()
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 3 {
		t.Fatalf("want: 3, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().All()
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 3 {
		t.Fatalf("want: 3, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().All()
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}
<commit_msg>Add unit test for assembleSQLDelete<commit_after>package orm

import (
	"testing"
)

func TestAssembleSQLDelete(t *testing.T) {
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if ormTest.deleteSQL != "delete from DSLTest" {
		t.Fatalf("want: 'delete from DSLTest', got: '%v'", ormTest.deleteSQL)
	}
}

func TestDeleteByID(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest := DSLTest{FieldString: "teststring", FieldInt: 123}
	err = ormTest.Save(&dslTest)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	id := dslTest.ID
	if id != 1 {
		t.Fatalf("\ndslTest.ID got:\t %v\nWant:\t\t\t 1\n", id)
	}

	n, err := ormTest.Delete().ByID(id)

	if n != 1 {
		t.Fatalf("\ndeleted got:\t %v\nWant:\t\t\t 1\n", n)
	}

	if err != nil {
		t.Fatalf("\nerr got:\t %v\nWant:\t\t\t nil\n", err)
	}

	dslTestFind, err := ormTest.Select().ByID(id)
	if dslTestFind != nil {
		t.Fatalf("\ndslTest got:\t %v\nWant:\t\t\t nil\n", dslTest)
	}

	if err.Error() != "sql: no rows in result set" {
		t.Fatalf("want: `sql: no rows in result set`, got: `%v`", err)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().ByID(id)
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteWhere(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 2 {
		t.Fatalf("want: 2, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 2 {
		t.Fatalf("want: 2, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().Where("FieldString like 'teststring%'")
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteAll(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest3 := DSLTest{FieldString: "teststring3", FieldInt: 333}
	err = ormTest.Save(&dslTest3)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().All()
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 3 {
		t.Fatalf("want: 3, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().All()
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 3 {
		t.Fatalf("want: 3, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().All()
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}
<|endoftext|>


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

// +build appengine

package build

import (
	"net/http"
	"strings"

	"appengine"
)

func handleFunc(path string, h http.HandlerFunc) {
	for _, d := range dashboards {
		http.HandleFunc(d.Prefix+path, h)
	}
}

// Dashboard describes a unique build dashboard.
type Dashboard struct {
	Name     string     // This dashboard's name and namespace
	Prefix   string     // The path prefix (no trailing /)
	Packages []*Package // The project's packages to build
}

// dashboardForRequest returns the appropriate dashboard for a given URL path.
func dashboardForRequest(r *http.Request) *Dashboard {
	if strings.HasPrefix(r.URL.Path, gccgoDash.Prefix) {
		return gccgoDash
	}
	if strings.HasPrefix(r.URL.Path, gitDash.Prefix) {
		return gitDash
	}
	return goDash
}

// Context returns a namespaced context for this dashboard, or panics if it
// fails to create a new context.
func (d *Dashboard) Context(c appengine.Context) appengine.Context {
	// No namespace needed for the original Go dashboard.
	if d.Name == "Go" {
		return c
	}
	n, err := appengine.Namespace(c, d.Name)
	if err != nil {
		panic(err)
	}
	return n
}

// the currently known dashboards.
var dashboards = []*Dashboard{goDash, gitDash, gccgoDash}

// goDash is the dashboard for the main go repository.
var goDash = &Dashboard{
	Name:     "Go",
	Prefix:   "",
	Packages: goPackages,
}

// goPackages is a list of all of the packages built by the main go repository.
var goPackages = []*Package{
	{
		Kind: "go",
		Name: "Go",
	},
	{
		Kind: "subrepo",
		Name: "go.blog",
		Path: "code.google.com/p/go.blog",
	},
	{
		Kind: "subrepo",
		Name: "go.codereview",
		Path: "code.google.com/p/go.codereview",
	},
	{
		Kind: "subrepo",
		Name: "go.crypto",
		Path: "code.google.com/p/go.crypto",
	},
	{
		Kind: "subrepo",
		Name: "go.exp",
		Path: "code.google.com/p/go.exp",
	},
	{
		Kind: "subrepo",
		Name: "go.image",
		Path: "code.google.com/p/go.image",
	},
	{
		Kind: "subrepo",
		Name: "go.net",
		Path: "code.google.com/p/go.net",
	},
	{
		Kind: "subrepo",
		Name: "go.sys",
		Path: "code.google.com/p/go.sys",
	},
	{
		Kind: "subrepo",
		Name: "go.talks",
		Path: "code.google.com/p/go.talks",
	},
	{
		Kind: "subrepo",
		Name: "go.tools",
		Path: "code.google.com/p/go.tools",
	},
}

// gitDash is the dashboard for the main go repository on git.
var gitDash = &Dashboard{
	Name:     "Git",
	Prefix:   "/git",
	Packages: gitPackages,
}

// gitPackages is a list of all of the packages built by the main go repository
// on git.
var gitPackages = []*Package{
	{
		Kind: "go",
		Name: "Go",
	},
	{
		Kind: "subrepo",
		Name: "blog",
		Path: "golang.org/x/blog",
	},
	{
		Kind: "subrepo",
		Name: "codereview",
		Path: "golang.org/x/codereview",
	},
	{
		Kind: "subrepo",
		Name: "crypto",
		Path: "golang.org/x/crypto",
	},
	{
		Kind: "subrepo",
		Name: "exp",
		Path: "golang.org/x/exp",
	},
	{
		Kind: "subrepo",
		Name: "image",
		Path: "golang.org/x/image",
	},
	{
		Kind: "subrepo",
		Name: "net",
		Path: "golang.org/x/net",
	},
	{
		Kind: "subrepo",
		Name: "sys",
		Path: "golang.org/x/sys",
	},
	{
		Kind: "subrepo",
		Name: "talks",
		Path: "golang.org/x/talks",
	},
	{
		Kind: "subrepo",
		Name: "tools",
		Path: "golang.org/x/tools",
	},
}

// gccgoDash is the dashboard for gccgo.
var gccgoDash = &Dashboard{
	Name:   "Gccgo",
	Prefix: "/gccgo",
	Packages: []*Package{
		{
			Kind: "gccgo",
			Name: "Gccgo",
		},
	},
}
<commit_msg>x/dashboard/app: update sub-repo list (+mobile, +text, -codereview)<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build appengine

package build

import (
	"net/http"
	"strings"

	"appengine"
)

func handleFunc(path string, h http.HandlerFunc) {
	for _, d := range dashboards {
		http.HandleFunc(d.Prefix+path, h)
	}
}

// Dashboard describes a unique build dashboard.
type Dashboard struct {
	Name     string     // This dashboard's name and namespace
	Prefix   string     // The path prefix (no trailing /)
	Packages []*Package // The project's packages to build
}

// dashboardForRequest returns the appropriate dashboard for a given URL path.
func dashboardForRequest(r *http.Request) *Dashboard {
	if strings.HasPrefix(r.URL.Path, gccgoDash.Prefix) {
		return gccgoDash
	}
	if strings.HasPrefix(r.URL.Path, gitDash.Prefix) {
		return gitDash
	}
	return goDash
}

// Context returns a namespaced context for this dashboard, or panics if it
// fails to create a new context.
func (d *Dashboard) Context(c appengine.Context) appengine.Context {
	// No namespace needed for the original Go dashboard.
	if d.Name == "Go" {
		return c
	}
	n, err := appengine.Namespace(c, d.Name)
	if err != nil {
		panic(err)
	}
	return n
}

// the currently known dashboards.
var dashboards = []*Dashboard{goDash, gitDash, gccgoDash}

// goDash is the dashboard for the main go repository.
var goDash = &Dashboard{
	Name:     "Go",
	Prefix:   "",
	Packages: goPackages,
}

// goPackages is a list of all of the packages built by the main go repository.
var goPackages = []*Package{
	{
		Kind: "go",
		Name: "Go",
	},
	{
		Kind: "subrepo",
		Name: "go.blog",
		Path: "code.google.com/p/go.blog",
	},
	{
		Kind: "subrepo",
		Name: "go.codereview",
		Path: "code.google.com/p/go.codereview",
	},
	{
		Kind: "subrepo",
		Name: "go.crypto",
		Path: "code.google.com/p/go.crypto",
	},
	{
		Kind: "subrepo",
		Name: "go.exp",
		Path: "code.google.com/p/go.exp",
	},
	{
		Kind: "subrepo",
		Name: "go.image",
		Path: "code.google.com/p/go.image",
	},
	{
		Kind: "subrepo",
		Name: "go.net",
		Path: "code.google.com/p/go.net",
	},
	{
		Kind: "subrepo",
		Name: "go.sys",
		Path: "code.google.com/p/go.sys",
	},
	{
		Kind: "subrepo",
		Name: "go.talks",
		Path: "code.google.com/p/go.talks",
	},
	{
		Kind: "subrepo",
		Name: "go.tools",
		Path: "code.google.com/p/go.tools",
	},
}

// gitDash is the dashboard for the main go repository on git.
var gitDash = &Dashboard{
	Name:     "Git",
	Prefix:   "/git",
	Packages: gitPackages,
}

// gitPackages is a list of all of the packages built by the main go repository
// on git.
var gitPackages = []*Package{
	{
		Kind: "go",
		Name: "Go",
	},
	{
		Kind: "subrepo",
		Name: "blog",
		Path: "golang.org/x/blog",
	},
	{
		Kind: "subrepo",
		Name: "crypto",
		Path: "golang.org/x/crypto",
	},
	{
		Kind: "subrepo",
		Name: "exp",
		Path: "golang.org/x/exp",
	},
	{
		Kind: "subrepo",
		Name: "image",
		Path: "golang.org/x/image",
	},
	{
		Kind: "subrepo",
		Name: "mobile",
		Path: "golang.org/x/mobile",
	},
	{
		Kind: "subrepo",
		Name: "net",
		Path: "golang.org/x/net",
	},
	{
		Kind: "subrepo",
		Name: "sys",
		Path: "golang.org/x/sys",
	},
	{
		Kind: "subrepo",
		Name: "talks",
		Path: "golang.org/x/talks",
	},
	{
		Kind: "subrepo",
		Name: "text",
		Path: "golang.org/x/text",
	},
	{
		Kind: "subrepo",
		Name: "tools",
		Path: "golang.org/x/tools",
	},
}

// gccgoDash is the dashboard for gccgo.
var gccgoDash = &Dashboard{
	Name:   "Gccgo",
	Prefix: "/gccgo",
	Packages: []*Package{
		{
			Kind: "gccgo",
			Name: "Gccgo",
		},
	},
}
<|endoftext|>


<commit_before>package provider

import (
	"database/sql"
	"encoding/json"
	"sync"

	"github.com/cznic/ql"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/model"

	"github.com/prometheus/alertmanager/types"
)

func init() {
	ql.RegisterDriver()
}

type SQLNotifyInfo struct {
	db *sql.DB
}

func NewSQLNotifyInfo(db *sql.DB) (*SQLNotifyInfo, error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	if _, err := tx.Exec(createNotifyInfoTable); err != nil {
		tx.Rollback()
		return nil, err
	}
	tx.Commit()

	return &SQLNotifyInfo{db: db}, nil
}

const createNotifyInfoTable = `
CREATE TABLE IF NOT EXISTS notify_info (
	alert       uint64
	destination string
	resolved    bool
	delivered   bool
	timestamp   time
);
CREATE UNIQUE INDEX IF NOT EXISTS notify_alert
	ON notify_info (alert, destination);
CREATE INDEX IF NOT EXISTS notify_delivered
	ON notify_info (delivered);
`

func (n *SQLNotifyInfo) Get(dest string, fps ...model.Fingerprint) ([]*types.Notify, error) {
	var result []*types.Notify

	for _, fp := range fps {
		row := n.db.QueryRow(`
			SELECT alert, destination, resolved, delivered, timestamp
			FROM notify_info
			WHERE destination == $1 AND fingerprint == $1
		`, fp)

		var ni types.Notify
		if err := row.Scan(
			&ni.Alert,
			&ni.SendTo,
			&ni.Resolved,
			&ni.Delivered,
			&ni.Timestamp,
		); err != nil {
			return nil, err
		}

		result = append(result, &ni)
	}

	return result, nil
}

func (n *SQLNotifyInfo) Set(ns ...*types.Notify) error {
	tx, err := n.db.Begin()
	if err != nil {
		return err
	}

	insert, err := tx.Prepare(`
		INSERT INTO notify_info(alert, destination, resolved, delivered, timestamp)
		VALUES ($1, $2, $3, $4, $5);
	`)
	if err != nil {
		return err
	}
	defer insert.Close()

	del, err := tx.Prepare(`
		DELETE FROM notify_info
		WHERE alert == $1 AND destination == $2
	`)
	if err != nil {
		return err
	}
	defer del.Close()

	for _, ni := range ns {
		if _, err := del.Exec(ni.Alert, ni.SendTo); err != nil {
			tx.Rollback()
			return err
		}
		if _, err := insert.Exec(
			ni.Alert,
			ni.SendTo,
			ni.Resolved,
			ni.Delivered,
			ni.Timestamp,
		); err != nil {
			tx.Rollback()
			return err
		}
	}

	tx.Commit()

	return nil
}

type SQLAlerts struct {
	db *sql.DB

	mtx       sync.RWMutex
	listeners map[int]chan *types.Alert
	next      int
}

func NewSQLAlerts(db *sql.DB) (*SQLAlerts, error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	if _, err := tx.Exec(createAlertsTable); err != nil {
		tx.Rollback()
		return nil, err
	}
	tx.Commit()

	return &SQLAlerts{
		db:        db,
		listeners: map[int]chan *types.Alert{},
	}, nil
}

const createAlertsTable = `
CREATE TABLE IF NOT EXISTS alerts (
	fingerprint uint64
	labels      string
	annotations string
	starts_at   time
	ends_at     time
	updated_at  time
	timeout     bool
);
CREATE INDEX IF NOT EXISTS alerts_start ON alerts (starts_at);
CREATE INDEX IF NOT EXISTS alerts_end   ON alerts (ends_at);
`

func (a *SQLAlerts) Subscribe() AlertIterator {
	var (
		ch   = make(chan *types.Alert, 200)
		done = make(chan struct{})
	)
	alerts, err := a.getPending()

	i := a.next
	a.next++

	a.listeners[i] = ch

	go func() {
		defer func() {
			a.mtx.Lock()
			delete(a.listeners, i)
			close(ch)
			a.mtx.Unlock()
		}()

		for _, a := range alerts {
			select {
			case ch <- a:
			case <-done:
				return
			}
		}

		<-done
	}()

	return memAlertIterator{
		ch:   ch,
		done: done,
		err:  err,
	}
}

func (a *SQLAlerts) GetPending() AlertIterator {
	var (
		ch   = make(chan *types.Alert, 200)
		done = make(chan struct{})
	)

	alerts, err := a.getPending()

	go func() {
		defer close(ch)

		for _, a := range alerts {
			select {
			case ch <- a:
			case <-done:
				return
			}
		}
	}()

	return memAlertIterator{
		ch:   ch,
		done: done,
		err:  err,
	}
}

func (a *SQLAlerts) getPending() ([]*types.Alert, error) {
	rows, err := a.db.Query(`
		SELECT a.labels, a.annotations, a.starts_at, a.ends_at, a.updated_at, a.timeout
		FROM
			alerts AS a LEFT OUTER JOIN notify_info AS n
			ON a.fingerprint == n.fingerprint
		WHERE
			NOT (n.delivered AND n.resolved)
	`)
	if err != nil {
		return nil, err
	}

	var alerts []*types.Alert
	for rows.Next() {
		var (
			labels      string
			annotations string
			al          types.Alert
		)
		if err := rows.Scan(
			&labels,
			&annotations,
			&al.StartsAt,
			&al.EndsAt,
			&al.UpdatedAt,
			&al.Timeout,
		); err != nil {
			return nil, err
		}

		if err := json.Unmarshal([]byte(labels), &al.Labels); err != nil {
			return nil, err
		}
		if err := json.Unmarshal([]byte(annotations), &al.Annotations); err != nil {
			return nil, err
		}

		alerts = append(alerts, &al)
	}

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

func (a *SQLAlerts) Get(model.Fingerprint) (*types.Alert, error) {
	return nil, nil
}

func (a *SQLAlerts) Put(alerts ...*types.Alert) error {
	tx, err := a.db.Begin()
	if err != nil {
		return err
	}

	// The insert invariant requires that there are no two alerts with the same
	// fingerprint that have overlapping activity range ([StartsAt:EndsAt]).
	// Such alerts are merged into a single one with the union of both intervals
	// as its new activity interval.
	// The exact merge procedure is defined on the Alert structure. Here, we just
	// care about finding intersecting alerts for each new inserts, deleting them
	// if existant, and insert the new alert we retrieved by merging.
	overlap, err := tx.Prepare(`
		SELECT id(), annotations, starts_at, ends_at, updated_at, timeout FROM alerts
		WHERE fingerprint = $1 AND $2 =< ends_at OR $3 >= starts_at
	`)
	if err != nil {
		return err
	}
	defer overlap.Close()

	delOverlap, err := tx.Prepare(`
		DELETE FROM alerts WHERE id() IN (
			SELECT id() FROM alerts
			WHERE fingerprint = $1 AND $2 =< ends_at OR $3 >= starts_at
		)
	`)
	if err != nil {
		return err
	}
	defer delOverlap.Close()

	insert, err := tx.Prepare(`
		INSERT INTO alerts(fingerprint, labels, annotations, starts_at, ends_at, updated_at, timeout)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
	`)
	if err != nil {
		return err
	}
	defer insert.Close()

	for _, alert := range alerts {
		fp := alert.Fingerprint()

		// Retrieve all intersecting alerts and delete them.
		olaps, err := overlap.Query(fp, alert.StartsAt, alert.EndsAt)
		if err != nil {
			tx.Rollback()
			return err
		}

		var (
			overlapIDs []int64
			merges     []*types.Alert
		)
		for olaps.Next() {
			var (
				id  int64
				na  types.Alert
				ann string
			)
			if err := olaps.Scan(
				&id,
				&ann,
				&na.StartsAt,
				&na.EndsAt,
				&na.UpdatedAt,
				&na.Timeout,
			); err != nil {
				tx.Rollback()
				return err
			}
			if err := json.Unmarshal([]byte(ann), &na.Annotations); err != nil {
				tx.Rollback()
				return err
			}
			na.Labels = alert.Labels

			merges = append(merges, &na)
			overlapIDs = append(overlapIDs, id)
		}
		if err := olaps.Err(); err != nil {
			tx.Rollback()
			return err
		}

		// Merge them.
		for _, ma := range merges {
			alert = alert.Merge(ma)
		}

		// Delete the old ones.
		if _, err := delOverlap.Exec(fp, alert.StartsAt, alert.EndsAt); err != nil {
			tx.Rollback()
			return err
		}

		// Insert the final alert.
		labels, err := json.Marshal(alert.Labels)
		if err != nil {
			tx.Rollback()
			return err
		}
		annotations, err := json.Marshal(alert.Annotations)
		if err != nil {
			tx.Rollback()
			return err
		}

		_, err = insert.Exec(
			fp,
			string(labels),
			string(annotations),
			alert.StartsAt,
			alert.EndsAt,
			alert.UpdatedAt,
			alert.Timeout,
		)
		if err != nil {
			tx.Rollback()
			return err
		}

		a.mtx.RLock()
		for _, ch := range a.listeners {
			ch <- alert
		}
		a.mtx.RUnlock()
	}

	tx.Commit()

	return nil
}

type SQLSilences struct {
	db *sql.DB
}

func NewSQLSilences(db *sql.DB) (*SQLSilences, error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	if _, err := tx.Exec(createSilencesTable); err != nil {
		tx.Rollback()
		return nil, err
	}
	tx.Commit()

	return &SQLSilences{db: db}, nil
}

const createSilencesTable = `
CREATE TABLE IF NOT EXISTS silences (
	matchers   string,
	starts_at  time,
	ends_at    time,
	created_at time,
	created_by string,
	comment    string
);
CREATE INDEX IF NOT EXISTS silences_start ON silences (starts_at);
CREATE INDEX IF NOT EXISTS silences_end   ON silences (ends_at);
CREATE INDEX IF NOT EXISTS silences_id    ON silences (id());
`

func (s *SQLSilences) Mutes(lset model.LabelSet) bool {
	sils, err := s.All()
	if err != nil {
		log.Errorf("retrieving silences failed: %s", err)
		// In doubt, do not silence anything.
		return false
	}

	for _, sil := range sils {
		if sil.Mutes(lset) {
			return true
		}
	}
	return false
}

func (s *SQLSilences) All() ([]*types.Silence, error) {
	rows, err := s.db.Query(`
		SELECT id(), matchers, starts_at, ends_at, created_at, created_by, comment
		FROM silences
		ORDER BY starts_at DESC
	`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var silences []*types.Silence

	for rows.Next() {
		var (
			sil      model.Silence
			matchers string
		)

		if err := rows.Scan(
			&sil.ID,
			&matchers,
			&sil.StartsAt,
			&sil.EndsAt,
			&sil.CreatedAt,
			&sil.CreatedBy,
			&sil.Comment,
		); err != nil {
			return nil, err
		}

		if err := json.Unmarshal([]byte(matchers), &sil.Matchers); err != nil {
			return nil, err
		}

		silences = append(silences, types.NewSilence(&sil))
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return silences, nil
}

func (s *SQLSilences) Set(sil *types.Silence) (uint64, error) {
	mb, err := json.Marshal(sil.Silence.Matchers)
	if err != nil {
		return 0, err
	}

	tx, err := s.db.Begin()
	if err != nil {
		return 0, err
	}

	res, err := tx.Exec(`
		INSERT INTO silences(matchers, starts_at, ends_at, created_at, created_by. comment)
		VALUES ($1, $2, $3, $4, $5, $6)
	`,
		string(mb),
		sil.StartsAt,
		sil.EndsAt,
		sil.CreatedAt,
		sil.CreatedBy,
		sil.Comment,
	)
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	sid, err := res.LastInsertId()
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	tx.Commit()

	return uint64(sid), nil
}

func (s *SQLSilences) Del(sid uint64) error {
	tx, err := s.db.Begin()
	if err != nil {
		return err
	}

	if _, err := tx.Exec(`DELETE FROM silences WHERE id() == $1`, sid); err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()

	return nil
}

func (s *SQLSilences) Get(sid uint64) (*types.Silence, error) {
	row := s.db.QueryRow(`
		SELECT id(), matchers, starts_at, ends_at, created_at, created_by, comment
		FROM silences
		WHERE id() == $1
	`, sid)

	var (
		sil      model.Silence
		matchers string
	)
	err := row.Scan(
		&sil.ID,
		&matchers,
		&sil.StartsAt,
		&sil.EndsAt,
		&sil.CreatedAt,
		&sil.CreatedBy,
		&sil.Comment,
	)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	}
	if err != nil {
		return nil, err
	}
	if err := json.Unmarshal([]byte(matchers), &sil.Matchers); err != nil {
		return nil, err
	}

	return types.NewSilence(&sil), nil
}
<commit_msg>Fix various SQL statements<commit_after>package provider

import (
	"database/sql"
	"encoding/json"
	"sync"

	"github.com/cznic/ql"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/model"

	"github.com/prometheus/alertmanager/types"
)

func init() {
	ql.RegisterDriver()
}

type SQLNotifyInfo struct {
	db *sql.DB
}

func NewSQLNotifyInfo(db *sql.DB) (*SQLNotifyInfo, error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	if _, err := tx.Exec(createNotifyInfoTable); err != nil {
		tx.Rollback()
		return nil, err
	}
	tx.Commit()

	return &SQLNotifyInfo{db: db}, nil
}

const createNotifyInfoTable = `
CREATE TABLE IF NOT EXISTS notify_info (
	alert       int64,
	destination string,
	resolved    bool,
	delivered   bool,
	timestamp   time
);
CREATE UNIQUE INDEX IF NOT EXISTS notify_alert
	ON notify_info (alert, destination);
CREATE INDEX IF NOT EXISTS notify_delivered
	ON notify_info (delivered);
`

func (n *SQLNotifyInfo) Get(dest string, fps ...model.Fingerprint) ([]*types.Notify, error) {
	var result []*types.Notify

	for _, fp := range fps {
		row := n.db.QueryRow(`
			SELECT alert, destination, resolved, delivered, timestamp
			FROM notify_info
			WHERE destination == $1 AND alert == $2
		`, dest, fp)

		var ni types.Notify
		err := row.Scan(
			&ni.Alert,
			&ni.SendTo,
			&ni.Resolved,
			&ni.Delivered,
			&ni.Timestamp,
		)
		if err == sql.ErrNoRows {
			result = append(result, nil)
			continue
		}
		if err != nil {
			return nil, err
		}

		result = append(result, &ni)
	}

	return result, nil
}

func (n *SQLNotifyInfo) Set(ns ...*types.Notify) error {
	tx, err := n.db.Begin()
	if err != nil {
		return err
	}

	insert, err := tx.Prepare(`
		INSERT INTO notify_info(alert, destination, resolved, delivered, timestamp)
		VALUES ($1, $2, $3, $4, $5);
	`)
	if err != nil {
		return err
	}
	defer insert.Close()

	del, err := tx.Prepare(`
		DELETE FROM notify_info
		WHERE alert == $1 AND destination == $2
	`)
	if err != nil {
		return err
	}
	defer del.Close()

	for _, ni := range ns {
		if _, err := del.Exec(ni.Alert, ni.SendTo); err != nil {
			tx.Rollback()
			return err
		}
		if _, err := insert.Exec(
			ni.Alert,
			ni.SendTo,
			ni.Resolved,
			ni.Delivered,
			ni.Timestamp,
		); err != nil {
			tx.Rollback()
			return err
		}
	}

	tx.Commit()

	return nil
}

type SQLAlerts struct {
	db *sql.DB

	mtx       sync.RWMutex
	listeners map[int]chan *types.Alert
	next      int
}

func NewSQLAlerts(db *sql.DB) (*SQLAlerts, error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	if _, err := tx.Exec(createAlertsTable); err != nil {
		tx.Rollback()
		return nil, err
	}
	tx.Commit()

	return &SQLAlerts{
		db:        db,
		listeners: map[int]chan *types.Alert{},
	}, nil
}

const createAlertsTable = `
CREATE TABLE IF NOT EXISTS alerts (
	fingerprint int64,
	labels      string,
	annotations string,
	starts_at   time,
	ends_at     time,
	updated_at  time,
	timeout     bool
);
CREATE INDEX IF NOT EXISTS alerts_start ON alerts (starts_at);
CREATE INDEX IF NOT EXISTS alerts_end   ON alerts (ends_at);
`

func (a *SQLAlerts) Subscribe() AlertIterator {
	var (
		ch   = make(chan *types.Alert, 200)
		done = make(chan struct{})
	)
	alerts, err := a.getPending()

	i := a.next
	a.next++

	a.listeners[i] = ch

	go func() {
		defer func() {
			a.mtx.Lock()
			delete(a.listeners, i)
			close(ch)
			a.mtx.Unlock()
		}()

		for _, a := range alerts {
			select {
			case ch <- a:
			case <-done:
				return
			}
		}

		<-done
	}()

	return memAlertIterator{
		ch:   ch,
		done: done,
		err:  err,
	}
}

func (a *SQLAlerts) GetPending() AlertIterator {
	var (
		ch   = make(chan *types.Alert, 200)
		done = make(chan struct{})
	)

	alerts, err := a.getPending()

	go func() {
		defer close(ch)

		for _, a := range alerts {
			select {
			case ch <- a:
			case <-done:
				return
			}
		}
	}()

	return memAlertIterator{
		ch:   ch,
		done: done,
		err:  err,
	}
}

func (a *SQLAlerts) getPending() ([]*types.Alert, error) {
	rows, err := a.db.Query(`
		SELECT a.labels, a.annotations, a.starts_at, a.ends_at, a.updated_at, a.timeout
		FROM
			alerts AS a LEFT OUTER JOIN notify_info AS n
			ON a.fingerprint == n.fingerprint
		WHERE
			!n.delivered OR !n.resolved
	`)
	if err != nil {
		return nil, err
	}

	var alerts []*types.Alert
	for rows.Next() {
		var (
			labels      string
			annotations string
			al          types.Alert
		)
		if err := rows.Scan(
			&labels,
			&annotations,
			&al.StartsAt,
			&al.EndsAt,
			&al.UpdatedAt,
			&al.Timeout,
		); err != nil {
			return nil, err
		}

		if err := json.Unmarshal([]byte(labels), &al.Labels); err != nil {
			return nil, err
		}
		if err := json.Unmarshal([]byte(annotations), &al.Annotations); err != nil {
			return nil, err
		}

		alerts = append(alerts, &al)
	}

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

func (a *SQLAlerts) Get(model.Fingerprint) (*types.Alert, error) {
	return nil, nil
}

func (a *SQLAlerts) Put(alerts ...*types.Alert) error {
	tx, err := a.db.Begin()
	if err != nil {
		return err
	}

	// The insert invariant requires that there are no two alerts with the same
	// fingerprint that have overlapping activity range ([StartsAt:EndsAt]).
	// Such alerts are merged into a single one with the union of both intervals
	// as its new activity interval.
	// The exact merge procedure is defined on the Alert structure. Here, we just
	// care about finding intersecting alerts for each new inserts, deleting them
	// if existant, and insert the new alert we retrieved by merging.
	overlap, err := tx.Prepare(`
		SELECT id(), annotations, starts_at, ends_at, updated_at, timeout FROM alerts
		WHERE fingerprint == $1 AND
			(starts_at >= $2 AND ends_at <= $2) OR
			(starts_at >= $3 AND ends_at <= $3)
	`)
	if err != nil {
		tx.Rollback()
		return err
	}
	defer overlap.Close()

	delOverlap, err := tx.Prepare(`
		DELETE FROM alerts WHERE id() IN (
			SELECT id() FROM alerts
			WHERE fingerprint == $1 AND
				(starts_at >= $2 AND ends_at <= $2) OR
				(starts_at >= $3 AND ends_at <= $3)
		)
	`)
	if err != nil {
		tx.Rollback()
		return err
	}
	defer delOverlap.Close()

	insert, err := tx.Prepare(`
		INSERT INTO alerts(fingerprint, labels, annotations, starts_at, ends_at, updated_at, timeout)
		VALUES ($1, $2, $3, $4, $5, $6, $7)
	`)
	if err != nil {
		tx.Rollback()
		return err
	}
	defer insert.Close()

	for _, alert := range alerts {
		fp := alert.Fingerprint()

		// Retrieve all intersecting alerts and delete them.
		olaps, err := overlap.Query(fp, alert.StartsAt, alert.EndsAt)
		if err != nil {
			tx.Rollback()
			return err
		}

		var (
			overlapIDs []int64
			merges     []*types.Alert
		)
		for olaps.Next() {
			var (
				id  int64
				na  types.Alert
				ann string
			)
			if err := olaps.Scan(
				&id,
				&ann,
				&na.StartsAt,
				&na.EndsAt,
				&na.UpdatedAt,
				&na.Timeout,
			); err != nil {
				tx.Rollback()
				return err
			}
			if err := json.Unmarshal([]byte(ann), &na.Annotations); err != nil {
				tx.Rollback()
				return err
			}
			na.Labels = alert.Labels

			merges = append(merges, &na)
			overlapIDs = append(overlapIDs, id)
		}
		if err := olaps.Err(); err != nil {
			tx.Rollback()
			return err
		}

		// Merge them.
		for _, ma := range merges {
			alert = alert.Merge(ma)
		}

		// Delete the old ones.
		if _, err := delOverlap.Exec(fp, alert.StartsAt, alert.EndsAt); err != nil {
			tx.Rollback()
			return err
		}

		// Insert the final alert.
		labels, err := json.Marshal(alert.Labels)
		if err != nil {
			tx.Rollback()
			return err
		}
		annotations, err := json.Marshal(alert.Annotations)
		if err != nil {
			tx.Rollback()
			return err
		}

		_, err = insert.Exec(
			uint64(fp),
			string(labels),
			string(annotations),
			alert.StartsAt,
			alert.EndsAt,
			alert.UpdatedAt,
			alert.Timeout,
		)
		if err != nil {
			tx.Rollback()
			return err
		}

		a.mtx.RLock()
		for _, ch := range a.listeners {
			ch <- alert
		}
		a.mtx.RUnlock()
	}

	tx.Commit()

	return nil
}

type SQLSilences struct {
	db *sql.DB
}

func NewSQLSilences(db *sql.DB) (*SQLSilences, error) {
	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}
	if _, err := tx.Exec(createSilencesTable); err != nil {
		tx.Rollback()
		return nil, err
	}
	tx.Commit()

	return &SQLSilences{db: db}, nil
}

const createSilencesTable = `
CREATE TABLE IF NOT EXISTS silences (
	matchers   string,
	starts_at  time,
	ends_at    time,
	created_at time,
	created_by string,
	comment    string
);
CREATE INDEX IF NOT EXISTS silences_start ON silences (starts_at);
CREATE INDEX IF NOT EXISTS silences_end   ON silences (ends_at);
CREATE INDEX IF NOT EXISTS silences_id    ON silences (id());
`

func (s *SQLSilences) Mutes(lset model.LabelSet) bool {
	sils, err := s.All()
	if err != nil {
		log.Errorf("retrieving silences failed: %s", err)
		// In doubt, do not silence anything.
		return false
	}

	for _, sil := range sils {
		if sil.Mutes(lset) {
			return true
		}
	}
	return false
}

func (s *SQLSilences) All() ([]*types.Silence, error) {
	rows, err := s.db.Query(`
		SELECT id(), matchers, starts_at, ends_at, created_at, created_by, comment
		FROM silences
		ORDER BY starts_at DESC
	`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var silences []*types.Silence

	for rows.Next() {
		var (
			sil      model.Silence
			matchers string
		)

		if err := rows.Scan(
			&sil.ID,
			&matchers,
			&sil.StartsAt,
			&sil.EndsAt,
			&sil.CreatedAt,
			&sil.CreatedBy,
			&sil.Comment,
		); err != nil {
			return nil, err
		}

		if err := json.Unmarshal([]byte(matchers), &sil.Matchers); err != nil {
			return nil, err
		}

		silences = append(silences, types.NewSilence(&sil))
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return silences, nil
}

func (s *SQLSilences) Set(sil *types.Silence) (uint64, error) {
	mb, err := json.Marshal(sil.Silence.Matchers)
	if err != nil {
		return 0, err
	}

	tx, err := s.db.Begin()
	if err != nil {
		return 0, err
	}

	res, err := tx.Exec(`
		INSERT INTO silences(matchers, starts_at, ends_at, created_at, created_by, comment)
		VALUES ($1, $2, $3, $4, $5, $6)
	`,
		string(mb),
		sil.StartsAt,
		sil.EndsAt,
		sil.CreatedAt,
		sil.CreatedBy,
		sil.Comment,
	)
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	sid, err := res.LastInsertId()
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	tx.Commit()

	return uint64(sid), nil
}

func (s *SQLSilences) Del(sid uint64) error {
	tx, err := s.db.Begin()
	if err != nil {
		return err
	}

	if _, err := tx.Exec(`DELETE FROM silences WHERE id() == $1`, sid); err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()

	return nil
}

func (s *SQLSilences) Get(sid uint64) (*types.Silence, error) {
	row := s.db.QueryRow(`
		SELECT id(), matchers, starts_at, ends_at, created_at, created_by, comment
		FROM silences
		WHERE id() == $1
	`, sid)

	var (
		sil      model.Silence
		matchers string
	)
	err := row.Scan(
		&sil.ID,
		&matchers,
		&sil.StartsAt,
		&sil.EndsAt,
		&sil.CreatedAt,
		&sil.CreatedBy,
		&sil.Comment,
	)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	}
	if err != nil {
		return nil, err
	}
	if err := json.Unmarshal([]byte(matchers), &sil.Matchers); err != nil {
		return nil, err
	}

	return types.NewSilence(&sil), nil
}
<|endoftext|>