<commit_before>package main

/*

Locking
=======

The model has read and write locks. These must be acquired as appropriate by
public methods. To prevent deadlock situations, private methods should never
acquire locks, but document what locks they require.

*/

import (
	"errors"
	"fmt"
	"os"
	"path"
	"sync"
	"time"

	"github.com/calmh/syncthing/buffers"
	"github.com/calmh/syncthing/protocol"
)

type Model struct {
	sync.RWMutex
	dir     string
	updated int64
	global  map[string]File // the latest version of each file as it exists in the cluster
	local   map[string]File // the files we currently have locally on disk
	remote  map[string]map[string]File
	need    map[string]bool // the files we need to update
	nodes   map[string]*protocol.Connection

	lastIdxBcast        time.Time
	lastIdxBcastRequest time.Time
}

var (
	errNoSuchNode = errors.New("no such node")
)

const (
	FlagDeleted = 1 << 12

	idxBcastHoldtime = 15 * time.Second  // Wait at least this long after the last index modification
	idxBcastMaxDelay = 120 * time.Second // Unless we've already waited this long
)

func NewModel(dir string) *Model {
	m := &Model{
		dir:          dir,
		global:       make(map[string]File),
		local:        make(map[string]File),
		remote:       make(map[string]map[string]File),
		need:         make(map[string]bool),
		nodes:        make(map[string]*protocol.Connection),
		lastIdxBcast: time.Now(),
	}

	go m.printStats()
	go m.broadcastIndexLoop()
	return m
}

func (m *Model) Start() {
	go m.puller()
}

func (m *Model) printStats() {
	for {
		time.Sleep(60 * time.Second)
		m.RLock()
		for node, conn := range m.nodes {
			stats := conn.Statistics()
			if (stats.InBytesPerSec > 0 || stats.OutBytesPerSec > 0) && stats.Latency > 0 {
				infof("%s: %sB/s in, %sB/s out, %0.02f ms", node, toSI(stats.InBytesPerSec), toSI(stats.OutBytesPerSec), stats.Latency.Seconds()*1000)
			} else if stats.InBytesPerSec > 0 || stats.OutBytesPerSec > 0 {
				infof("%s: %sB/s in, %sB/s out", node, toSI(stats.InBytesPerSec), toSI(stats.OutBytesPerSec))
			}
		}
		m.RUnlock()
	}
}

func toSI(n int) string {
	if n > 1<<30 {
		return fmt.Sprintf("%.02f G", float64(n)/(1<<30))
	}
	if n > 1<<20 {
		return fmt.Sprintf("%.02f M", float64(n)/(1<<20))
	}
	if n > 1<<10 {
		return fmt.Sprintf("%.01f K", float64(n)/(1<<10))
	}
	return fmt.Sprintf("%d ", n)
}

func (m *Model) Index(nodeID string, fs []protocol.FileInfo) {
	m.Lock()
	defer m.Unlock()

	if opts.Debug.TraceNet {
		debugf("NET IDX(in): %s: %d files", nodeID, len(fs))
	}

	m.remote[nodeID] = make(map[string]File)
	for _, f := range fs {
		if f.Flags&FlagDeleted != 0 && !opts.Delete {
			// Files marked as deleted do not even enter the model
			continue
		}
		m.remote[nodeID][f.Name] = fileFromProtocol(f)
	}

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) IndexUpdate(nodeID string, fs []protocol.FileInfo) {
	m.Lock()
	defer m.Unlock()

	if opts.Debug.TraceNet {
		debugf("NET IDXUP(in): %s: %d files", nodeID, len(fs))
	}

	repo, ok := m.remote[nodeID]
	if !ok {
		return
	}

	for _, f := range fs {
		if f.Flags&FlagDeleted != 0 && !opts.Delete {
			// Files marked as deleted do not even enter the model
			continue
		}
		repo[f.Name] = fileFromProtocol(f)
	}

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) SeedIndex(fs []protocol.FileInfo) {
	m.Lock()
	defer m.Unlock()

	m.local = make(map[string]File)
	for _, f := range fs {
		mf := File{
			Name:     f.Name,
			Flags:    f.Flags,
			Modified: int64(f.Modified),
		}
		var offset uint64
		for _, b := range f.Blocks {
			mf.Blocks = append(mf.Blocks, Block{
				Offset: offset,
				Length: b.Length,
				Hash:   b.Hash,
			})
			offset += uint64(b.Length)
		}
		m.local[f.Name] = mf
	}

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) Close(node string) {
	m.Lock()
	defer m.Unlock()

	if opts.Debug.TraceNet {
		debugf("NET CLOSE: %s", node)
	}

	delete(m.remote, node)
	delete(m.nodes, node)

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) Request(nodeID, name string, offset uint64, size uint32, hash []byte) ([]byte, error) {
	if opts.Debug.TraceNet && nodeID != "<local>" {
		debugf("NET REQ(in): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
	}
	fn := path.Join(m.dir, name)
	fd, err := os.Open(fn) // XXX: Inefficient, should cache fd?
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	buf := buffers.Get(int(size))
	_, err = fd.ReadAt(buf, int64(offset))
	if err != nil {
		return nil, err
	}

	return buf, nil
}

func (m *Model) RequestGlobal(nodeID, name string, offset uint64, size uint32, hash []byte) ([]byte, error) {
	m.RLock()
	nc, ok := m.nodes[nodeID]
	m.RUnlock()
	if !ok {
		return nil, errNoSuchNode
	}

	if opts.Debug.TraceNet {
		debugf("NET REQ(out): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
	}

	return nc.Request(name, offset, size, hash)
}

func (m *Model) ReplaceLocal(fs []File) {
	m.Lock()
	defer m.Unlock()

	var updated bool
	var newLocal = make(map[string]File)

	for _, f := range fs {
		newLocal[f.Name] = f
		if ef := m.local[f.Name]; ef.Modified != f.Modified {
			updated = true
		}
	}

	if m.markDeletedLocals(newLocal) {
		updated = true
	}

	if len(newLocal) != len(m.local) {
		updated = true
	}

	if updated {
		m.local = newLocal
		m.recomputeGlobal()
		m.recomputeNeed()
		m.updated = time.Now().Unix()
		m.lastIdxBcastRequest = time.Now()
	}
}

func (m *Model) broadcastIndexLoop() {
	for {
		m.RLock()
		bcastRequested := m.lastIdxBcastRequest.After(m.lastIdxBcast)
		holdtimeExceeded := time.Since(m.lastIdxBcastRequest) > idxBcastHoldtime
		m.RUnlock()

		maxDelayExceeded := time.Since(m.lastIdxBcast) > idxBcastMaxDelay
		if bcastRequested && (holdtimeExceeded || maxDelayExceeded) {
			m.Lock()
			var indexWg sync.WaitGroup
			indexWg.Add(len(m.nodes))
			idx := m.protocolIndex()
			m.lastIdxBcast = time.Now()
			for _, node := range m.nodes {
				node := node
				if opts.Debug.TraceNet {
					debugf("NET IDX(out): %s: %d files", node.ID, len(idx))
				}
				go func() {
					node.Index(idx)
					indexWg.Done()
				}()
			}
			m.Unlock()
			indexWg.Wait()
		}
		time.Sleep(idxBcastHoldtime)
	}
}

// markDeletedLocals sets the deleted flag on files that have gone missing locally.
// Must be called with the write lock held.
func (m *Model) markDeletedLocals(newLocal map[string]File) bool {
	// For every file in the existing local table, check if they are also
	// present in the new local table. If they are not, check that we already
	// had the newest version available according to the global table and if so
	// note the file as having been deleted.
	var updated bool
	for n, f := range m.local {
		if _, ok := newLocal[n]; !ok {
			if gf := m.global[n]; gf.Modified <= f.Modified {
				if f.Flags&FlagDeleted == 0 {
					f.Flags = FlagDeleted
					f.Modified = f.Modified + 1
					f.Blocks = nil
					updated = true
				}
				newLocal[n] = f
			}
		}
	}
	return updated
}

func (m *Model) UpdateLocal(f File) {
	m.Lock()
	defer m.Unlock()

	if ef, ok := m.local[f.Name]; !ok || ef.Modified != f.Modified {
		m.local[f.Name] = f
		m.recomputeGlobal()
		m.recomputeNeed()
		m.updated = time.Now().Unix()
		m.lastIdxBcastRequest = time.Now()
	}
}

func (m *Model) Dir() string {
	m.RLock()
	defer m.RUnlock()
	return m.dir
}

func (m *Model) HaveFiles() []File {
	m.RLock()
	defer m.RUnlock()
	var files []File
	for _, file := range m.local {
		files = append(files, file)
	}
	return files
}

func (m *Model) LocalFile(name string) (File, bool) {
	m.RLock()
	defer m.RUnlock()
	f, ok := m.local[name]
	return f, ok
}

func (m *Model) GlobalFile(name string) (File, bool) {
	m.RLock()
	defer m.RUnlock()
	f, ok := m.global[name]
	return f, ok
}

// Must be called with the write lock held.
func (m *Model) recomputeGlobal() {
	var newGlobal = make(map[string]File)

	for n, f := range m.local {
		newGlobal[n] = f
	}

	for _, fs := range m.remote {
		for n, f := range fs {
			if cf, ok := newGlobal[n]; !ok || cf.Modified < f.Modified {
				newGlobal[n] = f
			}
		}
	}

	m.global = newGlobal
}

// Must be called with the write lock held.
func (m *Model) recomputeNeed() {
	m.need = make(map[string]bool)
	for n, f := range m.global {
		hf, ok := m.local[n]
		if !ok || f.Modified > hf.Modified {
			m.need[n] = true
		}
	}
}

// Must be called with the read lock held.
func (m *Model) whoHas(name string) []string {
	var remote []string

	gf := m.global[name]
	for node, files := range m.remote {
		if file, ok := files[name]; ok && file.Modified == gf.Modified {
			remote = append(remote, node)
		}
	}

	return remote
}

func (m *Model) ConnectedTo(nodeID string) bool {
	m.RLock()
	defer m.RUnlock()
	_, ok := m.nodes[nodeID]
	return ok
}

func (m *Model) ProtocolIndex() []protocol.FileInfo {
	m.RLock()
	defer m.RUnlock()
	return m.protocolIndex()
}

// Must be called with the read lock held.
func (m *Model) protocolIndex() []protocol.FileInfo {
	var index []protocol.FileInfo
	for _, f := range m.local {
		mf := protocol.FileInfo{
			Name:     f.Name,
			Flags:    f.Flags,
			Modified: int64(f.Modified),
		}
		for _, b := range f.Blocks {
			mf.Blocks = append(mf.Blocks, protocol.BlockInfo{
				Length: b.Length,
				Hash:   b.Hash,
			})
		}
		if opts.Debug.TraceIdx {
			var flagComment string
			if mf.Flags&FlagDeleted != 0 {
				flagComment = " (deleted)"
			}
			debugf("IDX: %q m=%d f=%o%s (%d blocks)", mf.Name, mf.Modified, mf.Flags, flagComment, len(mf.Blocks))
		}
		index = append(index, mf)
	}
	return index
}

func (m *Model) AddNode(node *protocol.Connection) {
	m.Lock()
	m.nodes[node.ID] = node
	m.Unlock()
	m.RLock()
	idx := m.protocolIndex()
	m.RUnlock()

	if opts.Debug.TraceNet {
		debugf("NET IDX(out): %s: %d files", node.ID, len(idx))
	}

	// Sending the index might take a while if we have many files and a slow
	// uplink. Return from AddNode in the meantime.
	go node.Index(idx)
}

func fileFromProtocol(f protocol.FileInfo) File {
	mf := File{
		Name:     f.Name,
		Flags:    f.Flags,
		Modified: int64(f.Modified),
	}
	var offset uint64
	for _, b := range f.Blocks {
		mf.Blocks = append(mf.Blocks, Block{
			Offset: offset,
			Length: b.Length,
			Hash:   b.Hash,
		})
		offset += uint64(b.Length)
	}
	return mf
}
<commit_msg>Cleanup SeedIndex<commit_after>package main

/*

Locking
=======

The model has read and write locks. These must be acquired as appropriate by
public methods. To prevent deadlock situations, private methods should never
acquire locks, but document what locks they require.

*/

import (
	"errors"
	"fmt"
	"os"
	"path"
	"sync"
	"time"

	"github.com/calmh/syncthing/buffers"
	"github.com/calmh/syncthing/protocol"
)

type Model struct {
	sync.RWMutex
	dir     string
	updated int64
	global  map[string]File // the latest version of each file as it exists in the cluster
	local   map[string]File // the files we currently have locally on disk
	remote  map[string]map[string]File
	need    map[string]bool // the files we need to update
	nodes   map[string]*protocol.Connection

	lastIdxBcast        time.Time
	lastIdxBcastRequest time.Time
}

var (
	errNoSuchNode = errors.New("no such node")
)

const (
	FlagDeleted = 1 << 12

	idxBcastHoldtime = 15 * time.Second  // Wait at least this long after the last index modification
	idxBcastMaxDelay = 120 * time.Second // Unless we've already waited this long
)

func NewModel(dir string) *Model {
	m := &Model{
		dir:          dir,
		global:       make(map[string]File),
		local:        make(map[string]File),
		remote:       make(map[string]map[string]File),
		need:         make(map[string]bool),
		nodes:        make(map[string]*protocol.Connection),
		lastIdxBcast: time.Now(),
	}

	go m.printStats()
	go m.broadcastIndexLoop()
	return m
}

func (m *Model) Start() {
	go m.puller()
}

func (m *Model) printStats() {
	for {
		time.Sleep(60 * time.Second)
		m.RLock()
		for node, conn := range m.nodes {
			stats := conn.Statistics()
			if (stats.InBytesPerSec > 0 || stats.OutBytesPerSec > 0) && stats.Latency > 0 {
				infof("%s: %sB/s in, %sB/s out, %0.02f ms", node, toSI(stats.InBytesPerSec), toSI(stats.OutBytesPerSec), stats.Latency.Seconds()*1000)
			} else if stats.InBytesPerSec > 0 || stats.OutBytesPerSec > 0 {
				infof("%s: %sB/s in, %sB/s out", node, toSI(stats.InBytesPerSec), toSI(stats.OutBytesPerSec))
			}
		}
		m.RUnlock()
	}
}

func toSI(n int) string {
	if n > 1<<30 {
		return fmt.Sprintf("%.02f G", float64(n)/(1<<30))
	}
	if n > 1<<20 {
		return fmt.Sprintf("%.02f M", float64(n)/(1<<20))
	}
	if n > 1<<10 {
		return fmt.Sprintf("%.01f K", float64(n)/(1<<10))
	}
	return fmt.Sprintf("%d ", n)
}

func (m *Model) Index(nodeID string, fs []protocol.FileInfo) {
	m.Lock()
	defer m.Unlock()

	if opts.Debug.TraceNet {
		debugf("NET IDX(in): %s: %d files", nodeID, len(fs))
	}

	m.remote[nodeID] = make(map[string]File)
	for _, f := range fs {
		if f.Flags&FlagDeleted != 0 && !opts.Delete {
			// Files marked as deleted do not even enter the model
			continue
		}
		m.remote[nodeID][f.Name] = fileFromProtocol(f)
	}

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) IndexUpdate(nodeID string, fs []protocol.FileInfo) {
	m.Lock()
	defer m.Unlock()

	if opts.Debug.TraceNet {
		debugf("NET IDXUP(in): %s: %d files", nodeID, len(fs))
	}

	repo, ok := m.remote[nodeID]
	if !ok {
		return
	}

	for _, f := range fs {
		if f.Flags&FlagDeleted != 0 && !opts.Delete {
			// Files marked as deleted do not even enter the model
			continue
		}
		repo[f.Name] = fileFromProtocol(f)
	}

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) SeedIndex(fs []protocol.FileInfo) {
	m.Lock()
	defer m.Unlock()

	m.local = make(map[string]File)
	for _, f := range fs {
		m.local[f.Name] = fileFromProtocol(f)
	}

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) Close(node string) {
	m.Lock()
	defer m.Unlock()

	if opts.Debug.TraceNet {
		debugf("NET CLOSE: %s", node)
	}

	delete(m.remote, node)
	delete(m.nodes, node)

	m.recomputeGlobal()
	m.recomputeNeed()
}

func (m *Model) Request(nodeID, name string, offset uint64, size uint32, hash []byte) ([]byte, error) {
	if opts.Debug.TraceNet && nodeID != "<local>" {
		debugf("NET REQ(in): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
	}
	fn := path.Join(m.dir, name)
	fd, err := os.Open(fn) // XXX: Inefficient, should cache fd?
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	buf := buffers.Get(int(size))
	_, err = fd.ReadAt(buf, int64(offset))
	if err != nil {
		return nil, err
	}

	return buf, nil
}

func (m *Model) RequestGlobal(nodeID, name string, offset uint64, size uint32, hash []byte) ([]byte, error) {
	m.RLock()
	nc, ok := m.nodes[nodeID]
	m.RUnlock()
	if !ok {
		return nil, errNoSuchNode
	}

	if opts.Debug.TraceNet {
		debugf("NET REQ(out): %s: %q o=%d s=%d h=%x", nodeID, name, offset, size, hash)
	}

	return nc.Request(name, offset, size, hash)
}

func (m *Model) ReplaceLocal(fs []File) {
	m.Lock()
	defer m.Unlock()

	var updated bool
	var newLocal = make(map[string]File)

	for _, f := range fs {
		newLocal[f.Name] = f
		if ef := m.local[f.Name]; ef.Modified != f.Modified {
			updated = true
		}
	}

	if m.markDeletedLocals(newLocal) {
		updated = true
	}

	if len(newLocal) != len(m.local) {
		updated = true
	}

	if updated {
		m.local = newLocal
		m.recomputeGlobal()
		m.recomputeNeed()
		m.updated = time.Now().Unix()
		m.lastIdxBcastRequest = time.Now()
	}
}

func (m *Model) broadcastIndexLoop() {
	for {
		m.RLock()
		bcastRequested := m.lastIdxBcastRequest.After(m.lastIdxBcast)
		holdtimeExceeded := time.Since(m.lastIdxBcastRequest) > idxBcastHoldtime
		m.RUnlock()

		maxDelayExceeded := time.Since(m.lastIdxBcast) > idxBcastMaxDelay
		if bcastRequested && (holdtimeExceeded || maxDelayExceeded) {
			m.Lock()
			var indexWg sync.WaitGroup
			indexWg.Add(len(m.nodes))
			idx := m.protocolIndex()
			m.lastIdxBcast = time.Now()
			for _, node := range m.nodes {
				node := node
				if opts.Debug.TraceNet {
					debugf("NET IDX(out): %s: %d files", node.ID, len(idx))
				}
				go func() {
					node.Index(idx)
					indexWg.Done()
				}()
			}
			m.Unlock()
			indexWg.Wait()
		}
		time.Sleep(idxBcastHoldtime)
	}
}

// markDeletedLocals sets the deleted flag on files that have gone missing locally.
// Must be called with the write lock held.
func (m *Model) markDeletedLocals(newLocal map[string]File) bool {
	// For every file in the existing local table, check if they are also
	// present in the new local table. If they are not, check that we already
	// had the newest version available according to the global table and if so
	// note the file as having been deleted.
	var updated bool
	for n, f := range m.local {
		if _, ok := newLocal[n]; !ok {
			if gf := m.global[n]; gf.Modified <= f.Modified {
				if f.Flags&FlagDeleted == 0 {
					f.Flags = FlagDeleted
					f.Modified = f.Modified + 1
					f.Blocks = nil
					updated = true
				}
				newLocal[n] = f
			}
		}
	}
	return updated
}

func (m *Model) UpdateLocal(f File) {
	m.Lock()
	defer m.Unlock()

	if ef, ok := m.local[f.Name]; !ok || ef.Modified != f.Modified {
		m.local[f.Name] = f
		m.recomputeGlobal()
		m.recomputeNeed()
		m.updated = time.Now().Unix()
		m.lastIdxBcastRequest = time.Now()
	}
}

func (m *Model) Dir() string {
	m.RLock()
	defer m.RUnlock()
	return m.dir
}

func (m *Model) HaveFiles() []File {
	m.RLock()
	defer m.RUnlock()
	var files []File
	for _, file := range m.local {
		files = append(files, file)
	}
	return files
}

func (m *Model) LocalFile(name string) (File, bool) {
	m.RLock()
	defer m.RUnlock()
	f, ok := m.local[name]
	return f, ok
}

func (m *Model) GlobalFile(name string) (File, bool) {
	m.RLock()
	defer m.RUnlock()
	f, ok := m.global[name]
	return f, ok
}

// Must be called with the write lock held.
func (m *Model) recomputeGlobal() {
	var newGlobal = make(map[string]File)

	for n, f := range m.local {
		newGlobal[n] = f
	}

	for _, fs := range m.remote {
		for n, f := range fs {
			if cf, ok := newGlobal[n]; !ok || cf.Modified < f.Modified {
				newGlobal[n] = f
			}
		}
	}

	m.global = newGlobal
}

// Must be called with the write lock held.
func (m *Model) recomputeNeed() {
	m.need = make(map[string]bool)
	for n, f := range m.global {
		hf, ok := m.local[n]
		if !ok || f.Modified > hf.Modified {
			m.need[n] = true
		}
	}
}

// Must be called with the read lock held.
func (m *Model) whoHas(name string) []string {
	var remote []string

	gf := m.global[name]
	for node, files := range m.remote {
		if file, ok := files[name]; ok && file.Modified == gf.Modified {
			remote = append(remote, node)
		}
	}

	return remote
}

func (m *Model) ConnectedTo(nodeID string) bool {
	m.RLock()
	defer m.RUnlock()
	_, ok := m.nodes[nodeID]
	return ok
}

func (m *Model) ProtocolIndex() []protocol.FileInfo {
	m.RLock()
	defer m.RUnlock()
	return m.protocolIndex()
}

// Must be called with the read lock held.
func (m *Model) protocolIndex() []protocol.FileInfo {
	var index []protocol.FileInfo
	for _, f := range m.local {
		mf := protocol.FileInfo{
			Name:     f.Name,
			Flags:    f.Flags,
			Modified: int64(f.Modified),
		}
		for _, b := range f.Blocks {
			mf.Blocks = append(mf.Blocks, protocol.BlockInfo{
				Length: b.Length,
				Hash:   b.Hash,
			})
		}
		if opts.Debug.TraceIdx {
			var flagComment string
			if mf.Flags&FlagDeleted != 0 {
				flagComment = " (deleted)"
			}
			debugf("IDX: %q m=%d f=%o%s (%d blocks)", mf.Name, mf.Modified, mf.Flags, flagComment, len(mf.Blocks))
		}
		index = append(index, mf)
	}
	return index
}

func (m *Model) AddNode(node *protocol.Connection) {
	m.Lock()
	m.nodes[node.ID] = node
	m.Unlock()
	m.RLock()
	idx := m.protocolIndex()
	m.RUnlock()

	if opts.Debug.TraceNet {
		debugf("NET IDX(out): %s: %d files", node.ID, len(idx))
	}

	// Sending the index might take a while if we have many files and a slow
	// uplink. Return from AddNode in the meantime.
	go node.Index(idx)
}

func fileFromProtocol(f protocol.FileInfo) File {
	var blocks []Block
	var offset uint64
	for _, b := range f.Blocks {
		blocks = append(blocks, Block{
			Offset: offset,
			Length: b.Length,
			Hash:   b.Hash,
		})
		offset += uint64(b.Length)
	}
	return File{
		Name:     f.Name,
		Flags:    f.Flags,
		Modified: int64(f.Modified),
		Blocks:   blocks,
	}
}
<|endoftext|>


<commit_before><commit_msg>Send keep-alive on /api/v1/events SSE.<commit_after><|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"
)

func swap() (string, error) {
	swaps, err := exec.Command("cat", "/proc/swaps").Output()
	if err != nil {
		log.Fatal(err)
	}

	return string(swaps), nil
}
<commit_msg>Format output of swaps using awk<commit_after>package main

import (
	"log"
	"os/exec"
)

func swap() (string, error) {
	swap := exec.Command("cat", "/proc/swaps")
	awk := exec.Command("awk", "{print $1,$2,$3,$4,$5}")

	out, err := swap.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	swap.Start()
	awk.Stdin = out

	swap_out, err := awk.Output()
	if err != nil {
		log.Fatal(err)
	}

	return string(swap_out), nil
}
<|endoftext|>


<commit_before>package mysql

import (
	"context"
	"database/sql"
	"fmt"
	"math"
	"strings"

	_ "github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/callbacks"
	"gorm.io/gorm/clause"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/migrator"
	"gorm.io/gorm/schema"
)

type Config struct {
	DriverName                string
	DSN                       string
	Conn                      gorm.ConnPool
	SkipInitializeWithVersion bool
	DefaultStringSize         uint
	DisableDatetimePrecision  bool
	DontSupportRenameIndex    bool
	DontSupportRenameColumn   bool
}

type Dialector struct {
	*Config
}

func Open(dsn string) gorm.Dialector {
	return &Dialector{Config: &Config{DSN: dsn}}
}

func New(config Config) gorm.Dialector {
	return &Dialector{Config: &config}
}

func (dialector Dialector) Name() string {
	return "mysql"
}

func (dialector Dialector) Initialize(db *gorm.DB) (err error) {
	ctx := context.Background()

	// register callbacks
	callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{})

	db.Callback().Update().Replace("gorm:update", Update)

	if dialector.DriverName == "" {
		dialector.DriverName = "mysql"
	}

	if dialector.Conn != nil {
		db.ConnPool = dialector.Conn
	} else {
		db.ConnPool, err = sql.Open(dialector.DriverName, dialector.DSN)
		if err != nil {
			return err
		}
	}

	if !dialector.Config.SkipInitializeWithVersion {
		var version string
		err = db.ConnPool.QueryRowContext(ctx, "SELECT VERSION()").Scan(&version)
		if err != nil {
			return err
		}

		if strings.Contains(version, "MariaDB") {
			dialector.Config.DontSupportRenameIndex = true
			dialector.Config.DontSupportRenameColumn = true
		} else if strings.HasPrefix(version, "5.6.") {
			dialector.Config.DontSupportRenameIndex = true
			dialector.Config.DontSupportRenameColumn = true
		} else if strings.HasPrefix(version, "5.7.") {
			dialector.Config.DontSupportRenameColumn = true
		} else if strings.HasPrefix(version, "5.") {
			dialector.Config.DisableDatetimePrecision = true
			dialector.Config.DontSupportRenameIndex = true
			dialector.Config.DontSupportRenameColumn = true
		}
	}

	for k, v := range dialector.ClauseBuilders() {
		db.ClauseBuilders[k] = v
	}
	return
}

func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
	return map[string]clause.ClauseBuilder{
		"ON CONFLICT": func(c clause.Clause, builder clause.Builder) {
			if onConflict, ok := c.Expression.(clause.OnConflict); ok {
				builder.WriteString("ON DUPLICATE KEY UPDATE ")
				if len(onConflict.DoUpdates) == 0 {
					if s := builder.(*gorm.Statement).Schema; s != nil {
						var column clause.Column
						onConflict.DoNothing = false

						if s.PrioritizedPrimaryField != nil {
							column = clause.Column{Name: s.PrioritizedPrimaryField.DBName}
						} else if len(s.DBNames) > 0 {
							column = clause.Column{Name: s.DBNames[0]}
						}

						if column.Name != "" {
							onConflict.DoUpdates = []clause.Assignment{{Column: column, Value: column}}
						}
					}
				}

				for idx, assignment := range onConflict.DoUpdates {
					if idx > 0 {
						builder.WriteByte(',')
					}

					builder.WriteQuoted(assignment.Column)
					builder.WriteByte('=')
					if column, ok := assignment.Value.(clause.Column); ok && column.Table == "excluded" {
						column.Table = ""
						builder.WriteString("VALUES(")
						builder.WriteQuoted(column)
						builder.WriteByte(')')
					} else {
						builder.AddVar(builder, assignment.Value)
					}
				}
			} else {
				c.Build(builder)
			}
		},
		"VALUES": func(c clause.Clause, builder clause.Builder) {
			if values, ok := c.Expression.(clause.Values); ok && len(values.Columns) == 0 {
				builder.WriteString("VALUES()")
				return
			}
			c.Build(builder)
		},
	}
}

func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression {
	return clause.Expr{SQL: "DEFAULT"}
}

func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator {
	return Migrator{
		Migrator: migrator.Migrator{
			Config: migrator.Config{
				DB:        db,
				Dialector: dialector,
			},
		},
		Dialector: dialector,
	}
}

func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) {
	writer.WriteByte('?')
}

func (dialector Dialector) QuoteTo(writer clause.Writer, str string) {
	writer.WriteByte('`')
	if strings.Contains(str, ".") {
		for idx, str := range strings.Split(str, ".") {
			if idx > 0 {
				writer.WriteString(".`")
			}
			writer.WriteString(str)
			writer.WriteByte('`')
		}
	} else {
		writer.WriteString(str)
		writer.WriteByte('`')
	}
}

func (dialector Dialector) Explain(sql string, vars ...interface{}) string {
	return logger.ExplainSQL(sql, nil, `'`, vars...)
}

func (dialector Dialector) DataTypeOf(field *schema.Field) string {
	switch field.DataType {
	case schema.Bool:
		return "boolean"
	case schema.Int, schema.Uint:
		sqlType := "bigint"
		switch {
		case field.Size <= 8:
			sqlType = "tinyint"
		case field.Size <= 16:
			sqlType = "smallint"
		case field.Size <= 24:
			sqlType = "mediumint"
		case field.Size <= 32:
			sqlType = "int"
		}

		if field.DataType == schema.Uint {
			sqlType += " unsigned"
		}

		if field.AutoIncrement {
			sqlType += " AUTO_INCREMENT"
		}
		return sqlType
	case schema.Float:
		if field.Precision > 0 {
			return fmt.Sprintf("decimal(%d, %d)", field.Precision, field.Scale)
		}

		if field.Size <= 32 {
			return "float"
		}
		return "double"
	case schema.String:
		size := field.Size
		defaultSize := dialector.DefaultStringSize

		if size == 0 {
			if defaultSize > 0 {
				size = int(defaultSize)
			} else {
				hasIndex := field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUE"] != ""
				// TEXT, GEOMETRY or JSON column can't have a default value
				if field.PrimaryKey || field.HasDefaultValue || hasIndex {
					size = 191 // utf8mb4
				}
			}
		}

		if size >= 65536 && size <= int(math.Pow(2, 24)) {
			return "mediumtext"
		} else if size > int(math.Pow(2, 24)) || size <= 0 {
			return "longtext"
		}
		return fmt.Sprintf("varchar(%d)", size)
	case schema.Time:
		precision := ""

		if !dialector.DisableDatetimePrecision {
			if field.Precision == 0 {
				field.Precision = 3
			}

			if field.Precision > 0 {
				precision = fmt.Sprintf("(%d)", field.Precision)
			}
		}

		if field.NotNull || field.PrimaryKey {
			return "datetime" + precision
		}
		return "datetime" + precision + " NULL"
	case schema.Bytes:
		if field.Size > 0 && field.Size < 65536 {
			return fmt.Sprintf("varbinary(%d)", field.Size)
		}

		if field.Size >= 65536 && field.Size <= int(math.Pow(2, 24)) {
			return "mediumblob"
		}

		return "longblob"
	}

	return string(field.DataType)
}

func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error {
	tx.Exec("SAVEPOINT " + name)
	return nil
}

func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error {
	tx.Exec("ROLLBACK TO SAVEPOINT " + name)
	return nil
}
<commit_msg>rewrite for share clause for mysql 5.x and mariadb (#11)<commit_after>package mysql

import (
	"context"
	"database/sql"
	"fmt"
	"math"
	"strings"

	_ "github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/callbacks"
	"gorm.io/gorm/clause"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/migrator"
	"gorm.io/gorm/schema"
)

type Config struct {
	DriverName                string
	DSN                       string
	Conn                      gorm.ConnPool
	SkipInitializeWithVersion bool
	DefaultStringSize         uint
	DisableDatetimePrecision  bool
	DontSupportRenameIndex    bool
	DontSupportRenameColumn   bool
	DontSupportForShareClause bool
}

type Dialector struct {
	*Config
}

func Open(dsn string) gorm.Dialector {
	return &Dialector{Config: &Config{DSN: dsn}}
}

func New(config Config) gorm.Dialector {
	return &Dialector{Config: &config}
}

func (dialector Dialector) Name() string {
	return "mysql"
}

func (dialector Dialector) Initialize(db *gorm.DB) (err error) {
	ctx := context.Background()

	// register callbacks
	callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{})

	db.Callback().Update().Replace("gorm:update", Update)

	if dialector.DriverName == "" {
		dialector.DriverName = "mysql"
	}

	if dialector.Conn != nil {
		db.ConnPool = dialector.Conn
	} else {
		db.ConnPool, err = sql.Open(dialector.DriverName, dialector.DSN)
		if err != nil {
			return err
		}
	}

	if !dialector.Config.SkipInitializeWithVersion {
		var version string
		err = db.ConnPool.QueryRowContext(ctx, "SELECT VERSION()").Scan(&version)
		if err != nil {
			return err
		}

		if strings.Contains(version, "MariaDB") {
			dialector.Config.DontSupportRenameIndex = true
			dialector.Config.DontSupportRenameColumn = true
			dialector.Config.DontSupportForShareClause = true
		} else if strings.HasPrefix(version, "5.6.") {
			dialector.Config.DontSupportRenameIndex = true
			dialector.Config.DontSupportRenameColumn = true
			dialector.Config.DontSupportForShareClause = true
		} else if strings.HasPrefix(version, "5.7.") {
			dialector.Config.DontSupportRenameColumn = true
			dialector.Config.DontSupportForShareClause = true
		} else if strings.HasPrefix(version, "5.") {
			dialector.Config.DisableDatetimePrecision = true
			dialector.Config.DontSupportRenameIndex = true
			dialector.Config.DontSupportRenameColumn = true
			dialector.Config.DontSupportForShareClause = true
		}
	}

	for k, v := range dialector.ClauseBuilders() {
		db.ClauseBuilders[k] = v
	}
	return
}

func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
	clauseBuilders := map[string]clause.ClauseBuilder{
		"ON CONFLICT": func(c clause.Clause, builder clause.Builder) {
			if onConflict, ok := c.Expression.(clause.OnConflict); ok {
				builder.WriteString("ON DUPLICATE KEY UPDATE ")
				if len(onConflict.DoUpdates) == 0 {
					if s := builder.(*gorm.Statement).Schema; s != nil {
						var column clause.Column
						onConflict.DoNothing = false

						if s.PrioritizedPrimaryField != nil {
							column = clause.Column{Name: s.PrioritizedPrimaryField.DBName}
						} else if len(s.DBNames) > 0 {
							column = clause.Column{Name: s.DBNames[0]}
						}

						if column.Name != "" {
							onConflict.DoUpdates = []clause.Assignment{{Column: column, Value: column}}
						}
					}
				}

				for idx, assignment := range onConflict.DoUpdates {
					if idx > 0 {
						builder.WriteByte(',')
					}

					builder.WriteQuoted(assignment.Column)
					builder.WriteByte('=')
					if column, ok := assignment.Value.(clause.Column); ok && column.Table == "excluded" {
						column.Table = ""
						builder.WriteString("VALUES(")
						builder.WriteQuoted(column)
						builder.WriteByte(')')
					} else {
						builder.AddVar(builder, assignment.Value)
					}
				}
			} else {
				c.Build(builder)
			}
		},
		"VALUES": func(c clause.Clause, builder clause.Builder) {
			if values, ok := c.Expression.(clause.Values); ok && len(values.Columns) == 0 {
				builder.WriteString("VALUES()")
				return
			}
			c.Build(builder)
		},
	}

	if dialector.Config.DontSupportForShareClause {
		clauseBuilders["FOR"] = func(c clause.Clause, builder clause.Builder) {
			if values, ok := c.Expression.(clause.Locking); ok && strings.EqualFold(values.Strength, "SHARE") {
				builder.WriteString("LOCK IN SHARE MODE")
				return
			}
			c.Build(builder)
		}
	}

	return clauseBuilders
}

func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression {
	return clause.Expr{SQL: "DEFAULT"}
}

func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator {
	return Migrator{
		Migrator: migrator.Migrator{
			Config: migrator.Config{
				DB:        db,
				Dialector: dialector,
			},
		},
		Dialector: dialector,
	}
}

func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) {
	writer.WriteByte('?')
}

func (dialector Dialector) QuoteTo(writer clause.Writer, str string) {
	writer.WriteByte('`')
	if strings.Contains(str, ".") {
		for idx, str := range strings.Split(str, ".") {
			if idx > 0 {
				writer.WriteString(".`")
			}
			writer.WriteString(str)
			writer.WriteByte('`')
		}
	} else {
		writer.WriteString(str)
		writer.WriteByte('`')
	}
}

func (dialector Dialector) Explain(sql string, vars ...interface{}) string {
	return logger.ExplainSQL(sql, nil, `'`, vars...)
}

func (dialector Dialector) DataTypeOf(field *schema.Field) string {
	switch field.DataType {
	case schema.Bool:
		return "boolean"
	case schema.Int, schema.Uint:
		sqlType := "bigint"
		switch {
		case field.Size <= 8:
			sqlType = "tinyint"
		case field.Size <= 16:
			sqlType = "smallint"
		case field.Size <= 24:
			sqlType = "mediumint"
		case field.Size <= 32:
			sqlType = "int"
		}

		if field.DataType == schema.Uint {
			sqlType += " unsigned"
		}

		if field.AutoIncrement {
			sqlType += " AUTO_INCREMENT"
		}
		return sqlType
	case schema.Float:
		if field.Precision > 0 {
			return fmt.Sprintf("decimal(%d, %d)", field.Precision, field.Scale)
		}

		if field.Size <= 32 {
			return "float"
		}
		return "double"
	case schema.String:
		size := field.Size
		defaultSize := dialector.DefaultStringSize

		if size == 0 {
			if defaultSize > 0 {
				size = int(defaultSize)
			} else {
				hasIndex := field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUE"] != ""
				// TEXT, GEOMETRY or JSON column can't have a default value
				if field.PrimaryKey || field.HasDefaultValue || hasIndex {
					size = 191 // utf8mb4
				}
			}
		}

		if size >= 65536 && size <= int(math.Pow(2, 24)) {
			return "mediumtext"
		} else if size > int(math.Pow(2, 24)) || size <= 0 {
			return "longtext"
		}
		return fmt.Sprintf("varchar(%d)", size)
	case schema.Time:
		precision := ""

		if !dialector.DisableDatetimePrecision {
			if field.Precision == 0 {
				field.Precision = 3
			}

			if field.Precision > 0 {
				precision = fmt.Sprintf("(%d)", field.Precision)
			}
		}

		if field.NotNull || field.PrimaryKey {
			return "datetime" + precision
		}
		return "datetime" + precision + " NULL"
	case schema.Bytes:
		if field.Size > 0 && field.Size < 65536 {
			return fmt.Sprintf("varbinary(%d)", field.Size)
		}

		if field.Size >= 65536 && field.Size <= int(math.Pow(2, 24)) {
			return "mediumblob"
		}

		return "longblob"
	}

	return string(field.DataType)
}

func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error {
	tx.Exec("SAVEPOINT " + name)
	return nil
}

func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error {
	tx.Exec("ROLLBACK TO SAVEPOINT " + name)
	return nil
}
<|endoftext|>


<commit_before><commit_msg>added Buffer<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcchain

import (
	"fmt"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwire"
)

// maybeAcceptBlock potentially accepts a block into the memory block chain.
// It performs several validation checks which depend on its position within
// the block chain before adding it.  The block is expected to have already gone
// through ProcessBlock before calling this function with it.
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block) error {
	// Get a block node for the block previous to this one.  Will be nil
	// if this is the genesis block.
	prevNode, err := b.getPrevNodeFromBlock(block)
	if err != nil {
		log.Errorf("getPrevNodeFromBlock: %v", err)
		return err
	}

	// The height of this block one more than the referenced previous block.
	blockHeight := int64(0)
	if prevNode != nil {
		blockHeight = prevNode.height + 1
	}
	block.SetHeight(blockHeight)

	// Ensure the difficulty specified in the block header matches the
	// calculated difficulty based on the previous block and difficulty
	// retarget rules.
	blockHeader := block.MsgBlock().Header
	expectedDifficulty, err := b.calcNextRequiredDifficulty(prevNode, block)
	if err != nil {
		log.Errorf("calcNextRequiredDifficulty: %v", err)
		return err
	}
	blockDifficulty := blockHeader.Bits
	if blockDifficulty != expectedDifficulty {
		str := "block difficulty of %d is not the expected value of %d"
		str = fmt.Sprintf(str, blockDifficulty, expectedDifficulty)
		return RuleError(str)
	}

	// Ensure the timestamp for the block header is after the median time of
	// the last several blocks (medianTimeBlocks).
	medianTime, err := b.calcPastMedianTime(prevNode)
	if err != nil {
		log.Errorf("calcPastMedianTime: %v", err)
		return err
	}
	if !blockHeader.Timestamp.After(medianTime) {
		str := "block timestamp of %v is not after expected %v"
		str = fmt.Sprintf(str, blockHeader.Timestamp, medianTime)
		return RuleError(str)
	}

	// Ensure all transactions in the block are finalized.
	for i, tx := range block.MsgBlock().Transactions {
		if !isFinalizedTransaction(tx, blockHeight, blockHeader.Timestamp) {
			// Use the TxSha function from the block rather
			// than the transaction itself since the block version
			// is cached.  Also, it's safe to ignore the error here
			// since the only reason TxSha can fail is if the index
			// is out of range which is impossible here.
			txSha, _ := block.TxSha(i)
			str := fmt.Sprintf("block contains unfinalized "+
				"transaction %v", txSha)
			return RuleError(str)
		}
	}

	// Ensure chain matches up to predetermined checkpoints.
	// It's safe to ignore the error on Sha since it's already cached.
	blockHash, _ := block.Sha()
	if !b.verifyCheckpoint(blockHeight, blockHash) {
		// TODO(davec): This should probably be a distinct error type
		// (maybe CheckpointError).  Since this error shouldn't happen
		// unless the peer is connected to a rogue network serving up an
		// alternate chain, the caller would likely need to react by
		// disconnecting peers and rolling back the chain to the last
		// known good point.
		str := fmt.Sprintf("block at height %d does not match "+
			"checkpoint hash", blockHeight)
		return RuleError(str)
	}

	// Reject version 1 blocks once a majority of the network has upgraded.
	// Rules:
	//  95% (950 / 1000) for main network
	//  75% (75 / 100) for the test network
	// This is part of BIP_0034.
	if blockHeader.Version == 1 {
		minRequired := uint64(950)
		numToCheck := uint64(1000)
		if b.btcnet == btcwire.TestNet3 || b.btcnet == btcwire.TestNet {
			minRequired = 75
			numToCheck = 100
		}
		if b.isMajorityVersion(2, prevNode, minRequired, numToCheck) {
			str := "new blocks with version %d are no longer valid"
			str = fmt.Sprintf(str, blockHeader.Version)
			return RuleError(str)
		}
	}

	// Ensure coinbase starts with serialized block heights for blocks
	// whose version is the serializedHeightVersion or newer once a majority
	// of the network has upgraded.
	// Rules:
	//  75% (750 / 1000) for main network
	//  51% (51 / 100) for the test network
	// This is part of BIP_0034.
	if blockHeader.Version >= serializedHeightVersion {
		minRequired := uint64(750)
		numToCheck := uint64(1000)
		if b.btcnet == btcwire.TestNet3 || b.btcnet == btcwire.TestNet {
			minRequired = 51
			numToCheck = 100
		}
		if b.isMajorityVersion(serializedHeightVersion, prevNode,
			minRequired, numToCheck) {

			expectedHeight := int64(0)
			if prevNode != nil {
				expectedHeight = prevNode.height + 1
			}
			coinbaseTx := block.MsgBlock().Transactions[0]
			err := checkSerializedHeight(coinbaseTx, expectedHeight)
			if err != nil {
				return err
			}
		}
	}

	// Create a new block node for the block and add it to the in-memory
	// block chain (could be either a side chain or the main chain).
	newNode := newBlockNode(block)
	if prevNode != nil {
		newNode.parent = prevNode
		newNode.height = blockHeight
		newNode.workSum.Add(prevNode.workSum, newNode.workSum)
	}

	// Connect the passed block to the chain while respecting proper chain
	// selection according to the chain with the most proof of work.  This
	// also handles validation of the transaction scripts.
	err = b.connectBestChain(newNode, block)
	if err != nil {
		log.Errorf("connectBestChain: %v", err)
		return err
	}

	// Notify the caller that the new block was accepted into the block
	// chain.  The caller would typically want to react by relaying the
	// inventory to other peers.
	b.sendNotification(NTBlockAccepted, block)

	return nil
}
<commit_msg>Remove a couple of error logs that are not needed.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcchain

import (
	"fmt"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwire"
)

// maybeAcceptBlock potentially accepts a block into the memory block chain.
// It performs several validation checks which depend on its position within
// the block chain before adding it.  The block is expected to have already gone
// through ProcessBlock before calling this function with it.
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block) error {
	// Get a block node for the block previous to this one.  Will be nil
	// if this is the genesis block.
	prevNode, err := b.getPrevNodeFromBlock(block)
	if err != nil {
		log.Errorf("getPrevNodeFromBlock: %v", err)
		return err
	}

	// The height of this block one more than the referenced previous block.
	blockHeight := int64(0)
	if prevNode != nil {
		blockHeight = prevNode.height + 1
	}
	block.SetHeight(blockHeight)

	// Ensure the difficulty specified in the block header matches the
	// calculated difficulty based on the previous block and difficulty
	// retarget rules.
	blockHeader := block.MsgBlock().Header
	expectedDifficulty, err := b.calcNextRequiredDifficulty(prevNode, block)
	if err != nil {
		return err
	}
	blockDifficulty := blockHeader.Bits
	if blockDifficulty != expectedDifficulty {
		str := "block difficulty of %d is not the expected value of %d"
		str = fmt.Sprintf(str, blockDifficulty, expectedDifficulty)
		return RuleError(str)
	}

	// Ensure the timestamp for the block header is after the median time of
	// the last several blocks (medianTimeBlocks).
	medianTime, err := b.calcPastMedianTime(prevNode)
	if err != nil {
		log.Errorf("calcPastMedianTime: %v", err)
		return err
	}
	if !blockHeader.Timestamp.After(medianTime) {
		str := "block timestamp of %v is not after expected %v"
		str = fmt.Sprintf(str, blockHeader.Timestamp, medianTime)
		return RuleError(str)
	}

	// Ensure all transactions in the block are finalized.
	for i, tx := range block.MsgBlock().Transactions {
		if !isFinalizedTransaction(tx, blockHeight, blockHeader.Timestamp) {
			// Use the TxSha function from the block rather
			// than the transaction itself since the block version
			// is cached.  Also, it's safe to ignore the error here
			// since the only reason TxSha can fail is if the index
			// is out of range which is impossible here.
			txSha, _ := block.TxSha(i)
			str := fmt.Sprintf("block contains unfinalized "+
				"transaction %v", txSha)
			return RuleError(str)
		}
	}

	// Ensure chain matches up to predetermined checkpoints.
	// It's safe to ignore the error on Sha since it's already cached.
	blockHash, _ := block.Sha()
	if !b.verifyCheckpoint(blockHeight, blockHash) {
		// TODO(davec): This should probably be a distinct error type
		// (maybe CheckpointError).  Since this error shouldn't happen
		// unless the peer is connected to a rogue network serving up an
		// alternate chain, the caller would likely need to react by
		// disconnecting peers and rolling back the chain to the last
		// known good point.
		str := fmt.Sprintf("block at height %d does not match "+
			"checkpoint hash", blockHeight)
		return RuleError(str)
	}

	// Reject version 1 blocks once a majority of the network has upgraded.
	// Rules:
	//  95% (950 / 1000) for main network
	//  75% (75 / 100) for the test network
	// This is part of BIP_0034.
	if blockHeader.Version == 1 {
		minRequired := uint64(950)
		numToCheck := uint64(1000)
		if b.btcnet == btcwire.TestNet3 || b.btcnet == btcwire.TestNet {
			minRequired = 75
			numToCheck = 100
		}
		if b.isMajorityVersion(2, prevNode, minRequired, numToCheck) {
			str := "new blocks with version %d are no longer valid"
			str = fmt.Sprintf(str, blockHeader.Version)
			return RuleError(str)
		}
	}

	// Ensure coinbase starts with serialized block heights for blocks
	// whose version is the serializedHeightVersion or newer once a majority
	// of the network has upgraded.
	// Rules:
	//  75% (750 / 1000) for main network
	//  51% (51 / 100) for the test network
	// This is part of BIP_0034.
	if blockHeader.Version >= serializedHeightVersion {
		minRequired := uint64(750)
		numToCheck := uint64(1000)
		if b.btcnet == btcwire.TestNet3 || b.btcnet == btcwire.TestNet {
			minRequired = 51
			numToCheck = 100
		}
		if b.isMajorityVersion(serializedHeightVersion, prevNode,
			minRequired, numToCheck) {

			expectedHeight := int64(0)
			if prevNode != nil {
				expectedHeight = prevNode.height + 1
			}
			coinbaseTx := block.MsgBlock().Transactions[0]
			err := checkSerializedHeight(coinbaseTx, expectedHeight)
			if err != nil {
				return err
			}
		}
	}

	// Create a new block node for the block and add it to the in-memory
	// block chain (could be either a side chain or the main chain).
	newNode := newBlockNode(block)
	if prevNode != nil {
		newNode.parent = prevNode
		newNode.height = blockHeight
		newNode.workSum.Add(prevNode.workSum, newNode.workSum)
	}

	// Connect the passed block to the chain while respecting proper chain
	// selection according to the chain with the most proof of work.  This
	// also handles validation of the transaction scripts.
	err = b.connectBestChain(newNode, block)
	if err != nil {
		return err
	}

	// Notify the caller that the new block was accepted into the block
	// chain.  The caller would typically want to react by relaying the
	// inventory to other peers.
	b.sendNotification(NTBlockAccepted, block)

	return nil
}
<|endoftext|>


<commit_before>package somatree

type Action struct {
	Action       string                    `json:"action,omitempty"`
	Type         string                    `json:"type,omitempty"`
	Repository   somaproto.ProtoRepository `json:"repository,omitempty"`
	Bucket       somaproto.ProtoBucket     `json:"bucket,omitempty"`
	Group        somaproto.ProtoGroup      `json:"group,omitempty"`
	Cluster      somaproto.ProtoCluster    `json:"cluster,omitempty"`
	Node         somaproto.ProtoNode       `json:"node,omitempty"`
	Property     somaproto.TreeProperty    `json:"property,omitempty"`
	Check        somaproto.TreeCheck       `json:"check,omitempty"`
	ChildType    string                    `json:"child_type,omitempty"`
	ChildGroup   somaproto.ProtoGroup      `json:"child_group,omitempty"`
	ChildCluster somaproto.ProtoCluster    `json:"child_cluster,omitempty"`
	ChildNode    somaproto.ProtoNode       `json:"child_node,omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Update Action<commit_after>package somatree

type Action struct {
	Action        string                      `json:"action,omitempty"`
	Type          string                      `json:"type,omitempty"`
	Repository    somaproto.ProtoRepository   `json:"repository,omitempty"`
	Bucket        somaproto.ProtoBucket       `json:"bucket,omitempty"`
	Group         somaproto.ProtoGroup        `json:"group,omitempty"`
	Cluster       somaproto.ProtoCluster      `json:"cluster,omitempty"`
	Node          somaproto.ProtoNode         `json:"node,omitempty"`
	Property      somaproto.TreeProperty      `json:"property,omitempty"`
	Check         somaproto.TreeCheck         `json:"check,omitempty"`
	CheckInstance somaproto.TreeCheckInstance `json:"check_instance,omitempty"`
	ChildType     string                      `json:"child_type,omitempty"`
	ChildGroup    somaproto.ProtoGroup        `json:"child_group,omitempty"`
	ChildCluster  somaproto.ProtoCluster      `json:"child_cluster,omitempty"`
	ChildNode     somaproto.ProtoNode         `json:"child_node,omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package structs

import (
	"fmt"
	"time"
)

func ExampleNew() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	server := &Server{
		Name:    "Arslan",
		ID:      123456,
		Enabled: true,
	}

	s := New(server)

	fmt.Printf("Name        : %v\n", s.Name())
	fmt.Printf("Values      : %v\n", s.Values())
	fmt.Printf("Value of ID : %v\n", s.Field("ID").Value())
	// Output:
	// Name        : Server
	// Values      : [Arslan 123456 true]
	// Value of ID : 123456

}

func ExampleMap() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	s := &Server{
		Name:    "Arslan",
		ID:      123456,
		Enabled: true,
	}

	m := Map(s)

	fmt.Printf("%#v\n", m["Name"])
	fmt.Printf("%#v\n", m["ID"])
	fmt.Printf("%#v\n", m["Enabled"])
	// Output:
	// "Arslan"
	// 123456
	// true

}

func ExampleMap_tags() {
	// Custom tags can change the map keys instead of using the fields name
	type Server struct {
		Name    string `structs:"server_name"`
		ID      int32  `structs:"server_id"`
		Enabled bool   `structs:"enabled"`
	}

	s := &Server{
		Name: "Zeynep",
		ID:   789012,
	}

	m := Map(s)

	// access them by the custom tags defined above
	fmt.Printf("%#v\n", m["server_name"])
	fmt.Printf("%#v\n", m["server_id"])
	fmt.Printf("%#v\n", m["enabled"])
	// Output:
	// "Zeynep"
	// 789012
	// false

}

func ExampleMap_omitNested() {
	// By default field with struct types are processed too. We can stop
	// processing them via "omitnested" tag option.
	type Server struct {
		Name string    `structs:"server_name"`
		ID   int32     `structs:"server_id"`
		Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{}
	}

	const shortForm = "2006-Jan-02"
	t, _ := time.Parse("2006-Jan-02", "2013-Feb-03")

	s := &Server{
		Name: "Zeynep",
		ID:   789012,
		Time: t,
	}

	m := Map(s)

	// access them by the custom tags defined above
	fmt.Printf("%v\n", m["server_name"])
	fmt.Printf("%v\n", m["server_id"])
	fmt.Printf("%v\n", m["time"].(time.Time))
	// Output:
	// Zeynep
	// 789012
	// 2013-02-03 00:00:00 +0000 UTC
}

func ExampleMap_omitEmpty() {
	// By default field with struct types of zero values are processed too. We
	// can stop processing them via "omitempty" tag option.
	type Server struct {
		Name     string `structs:",omitempty"`
		ID       int32  `structs:"server_id,omitempty"`
		Location string
	}

	// Only add location
	s := &Server{
		Location: "Tokyo",
	}

	m := Map(s)

	// map contains only the Location field
	fmt.Printf("%v\n", m)
	// Output:
	// map[Location:Tokyo]
}

func ExampleValues() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	s := &Server{
		Name:    "Fatih",
		ID:      135790,
		Enabled: false,
	}

	m := Values(s)

	fmt.Printf("Values: %+v\n", m)
	// Output:
	// Values: [Fatih 135790 false]
}

func ExampleValues_omitEmpty() {
	// By default field with struct types of zero values are processed too. We
	// can stop processing them via "omitempty" tag option.
	type Server struct {
		Name     string `structs:",omitempty"`
		ID       int32  `structs:"server_id,omitempty"`
		Location string
	}

	// Only add location
	s := &Server{
		Location: "Ankara",
	}

	m := Values(s)

	// values contains only the Location field
	fmt.Printf("Values: %+v\n", m)
	// Output:
	// Values: [Ankara]
}

func ExampleValues_tags() {
	type Location struct {
		City    string
		Country string
	}

	type Server struct {
		Name     string
		ID       int32
		Enabled  bool
		Location Location `structs:"-"` // values from location are not included anymore
	}

	s := &Server{
		Name:     "Fatih",
		ID:       135790,
		Enabled:  false,
		Location: Location{City: "Ankara", Country: "Turkey"},
	}

	// Let get all values from the struct s. Note that we don't include values
	// from the Location field
	m := Values(s)

	fmt.Printf("Values: %+v\n", m)
	// Output:
	// Values: [Fatih 135790 false]
}

func ExampleFields() {
	type Access struct {
		Name         string
		LastAccessed time.Time
		Number       int
	}

	s := &Access{
		Name:         "Fatih",
		LastAccessed: time.Now(),
		Number:       1234567,
	}

	fields := Fields(s)

	for i, field := range fields {
		fmt.Printf("[%d] %+v\n", i, field.Name())
	}

	// Output:
	// [0] Name
	// [1] LastAccessed
	// [2] Number
}

func ExampleFields_nested() {
	type Person struct {
		Name   string
		Number int
	}

	type Access struct {
		Person        Person
		HasPermission bool
		LastAccessed  time.Time
	}

	s := &Access{
		Person:        Person{Name: "fatih", Number: 1234567},
		LastAccessed:  time.Now(),
		HasPermission: true,
	}

	// Let's get all fields from the struct s.
	fields := Fields(s)

	for _, field := range fields {
		if field.Name() == "Person" {
			fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value())
		}
	}

	// Output:
	// Access.Person.Name: fatih
}

func ExampleField() {
	type Person struct {
		Name   string
		Number int
	}

	type Access struct {
		Person        Person
		HasPermission bool
		LastAccessed  time.Time
	}

	access := &Access{
		Person:        Person{Name: "fatih", Number: 1234567},
		LastAccessed:  time.Now(),
		HasPermission: true,
	}

	// Create a new Struct type
	s := New(access)

	// Get the Field type for "Person" field
	p := s.Field("Person")

	// Get the underlying "Name field" and print the value of it
	name := p.Field("Name")

	fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value())

	// Output:
	// Value of Person.Access.Name: fatih

}

func ExampleIsZero() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	// Nothing is initalized
	a := &Server{}
	isZeroA := IsZero(a)

	// Name and Enabled is initialized, but not ID
	b := &Server{
		Name:    "Golang",
		Enabled: true,
	}
	isZeroB := IsZero(b)

	fmt.Printf("%#v\n", isZeroA)
	fmt.Printf("%#v\n", isZeroB)
	// Output:
	// true
	// false
}

func ExampleHasZero() {
	// Let's define an Access struct. Note that the "Enabled" field is not
	// going to be checked because we added the "structs" tag to the field.
	type Access struct {
		Name         string
		LastAccessed time.Time
		Number       int
		Enabled      bool `structs:"-"`
	}

	// Name and Number is not initialized.
	a := &Access{
		LastAccessed: time.Now(),
	}
	hasZeroA := HasZero(a)

	// Name and Number is initialized.
	b := &Access{
		Name:         "Fatih",
		LastAccessed: time.Now(),
		Number:       12345,
	}
	hasZeroB := HasZero(b)

	fmt.Printf("%#v\n", hasZeroA)
	fmt.Printf("%#v\n", hasZeroB)
	// Output:
	// true
	// false
}
<commit_msg>Typo fix<commit_after>package structs

import (
	"fmt"
	"time"
)

func ExampleNew() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	server := &Server{
		Name:    "Arslan",
		ID:      123456,
		Enabled: true,
	}

	s := New(server)

	fmt.Printf("Name        : %v\n", s.Name())
	fmt.Printf("Values      : %v\n", s.Values())
	fmt.Printf("Value of ID : %v\n", s.Field("ID").Value())
	// Output:
	// Name        : Server
	// Values      : [Arslan 123456 true]
	// Value of ID : 123456

}

func ExampleMap() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	s := &Server{
		Name:    "Arslan",
		ID:      123456,
		Enabled: true,
	}

	m := Map(s)

	fmt.Printf("%#v\n", m["Name"])
	fmt.Printf("%#v\n", m["ID"])
	fmt.Printf("%#v\n", m["Enabled"])
	// Output:
	// "Arslan"
	// 123456
	// true

}

func ExampleMap_tags() {
	// Custom tags can change the map keys instead of using the fields name
	type Server struct {
		Name    string `structs:"server_name"`
		ID      int32  `structs:"server_id"`
		Enabled bool   `structs:"enabled"`
	}

	s := &Server{
		Name: "Zeynep",
		ID:   789012,
	}

	m := Map(s)

	// access them by the custom tags defined above
	fmt.Printf("%#v\n", m["server_name"])
	fmt.Printf("%#v\n", m["server_id"])
	fmt.Printf("%#v\n", m["enabled"])
	// Output:
	// "Zeynep"
	// 789012
	// false

}

func ExampleMap_omitNested() {
	// By default field with struct types are processed too. We can stop
	// processing them via "omitnested" tag option.
	type Server struct {
		Name string    `structs:"server_name"`
		ID   int32     `structs:"server_id"`
		Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{}
	}

	const shortForm = "2006-Jan-02"
	t, _ := time.Parse("2006-Jan-02", "2013-Feb-03")

	s := &Server{
		Name: "Zeynep",
		ID:   789012,
		Time: t,
	}

	m := Map(s)

	// access them by the custom tags defined above
	fmt.Printf("%v\n", m["server_name"])
	fmt.Printf("%v\n", m["server_id"])
	fmt.Printf("%v\n", m["time"].(time.Time))
	// Output:
	// Zeynep
	// 789012
	// 2013-02-03 00:00:00 +0000 UTC
}

func ExampleMap_omitEmpty() {
	// By default field with struct types of zero values are processed too. We
	// can stop processing them via "omitempty" tag option.
	type Server struct {
		Name     string `structs:",omitempty"`
		ID       int32  `structs:"server_id,omitempty"`
		Location string
	}

	// Only add location
	s := &Server{
		Location: "Tokyo",
	}

	m := Map(s)

	// map contains only the Location field
	fmt.Printf("%v\n", m)
	// Output:
	// map[Location:Tokyo]
}

func ExampleValues() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	s := &Server{
		Name:    "Fatih",
		ID:      135790,
		Enabled: false,
	}

	m := Values(s)

	fmt.Printf("Values: %+v\n", m)
	// Output:
	// Values: [Fatih 135790 false]
}

func ExampleValues_omitEmpty() {
	// By default field with struct types of zero values are processed too. We
	// can stop processing them via "omitempty" tag option.
	type Server struct {
		Name     string `structs:",omitempty"`
		ID       int32  `structs:"server_id,omitempty"`
		Location string
	}

	// Only add location
	s := &Server{
		Location: "Ankara",
	}

	m := Values(s)

	// values contains only the Location field
	fmt.Printf("Values: %+v\n", m)
	// Output:
	// Values: [Ankara]
}

func ExampleValues_tags() {
	type Location struct {
		City    string
		Country string
	}

	type Server struct {
		Name     string
		ID       int32
		Enabled  bool
		Location Location `structs:"-"` // values from location are not included anymore
	}

	s := &Server{
		Name:     "Fatih",
		ID:       135790,
		Enabled:  false,
		Location: Location{City: "Ankara", Country: "Turkey"},
	}

	// Let get all values from the struct s. Note that we don't include values
	// from the Location field
	m := Values(s)

	fmt.Printf("Values: %+v\n", m)
	// Output:
	// Values: [Fatih 135790 false]
}

func ExampleFields() {
	type Access struct {
		Name         string
		LastAccessed time.Time
		Number       int
	}

	s := &Access{
		Name:         "Fatih",
		LastAccessed: time.Now(),
		Number:       1234567,
	}

	fields := Fields(s)

	for i, field := range fields {
		fmt.Printf("[%d] %+v\n", i, field.Name())
	}

	// Output:
	// [0] Name
	// [1] LastAccessed
	// [2] Number
}

func ExampleFields_nested() {
	type Person struct {
		Name   string
		Number int
	}

	type Access struct {
		Person        Person
		HasPermission bool
		LastAccessed  time.Time
	}

	s := &Access{
		Person:        Person{Name: "fatih", Number: 1234567},
		LastAccessed:  time.Now(),
		HasPermission: true,
	}

	// Let's get all fields from the struct s.
	fields := Fields(s)

	for _, field := range fields {
		if field.Name() == "Person" {
			fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value())
		}
	}

	// Output:
	// Access.Person.Name: fatih
}

func ExampleField() {
	type Person struct {
		Name   string
		Number int
	}

	type Access struct {
		Person        Person
		HasPermission bool
		LastAccessed  time.Time
	}

	access := &Access{
		Person:        Person{Name: "fatih", Number: 1234567},
		LastAccessed:  time.Now(),
		HasPermission: true,
	}

	// Create a new Struct type
	s := New(access)

	// Get the Field type for "Person" field
	p := s.Field("Person")

	// Get the underlying "Name field" and print the value of it
	name := p.Field("Name")

	fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value())

	// Output:
	// Value of Person.Access.Name: fatih

}

func ExampleIsZero() {
	type Server struct {
		Name    string
		ID      int32
		Enabled bool
	}

	// Nothing is initialized
	a := &Server{}
	isZeroA := IsZero(a)

	// Name and Enabled is initialized, but not ID
	b := &Server{
		Name:    "Golang",
		Enabled: true,
	}
	isZeroB := IsZero(b)

	fmt.Printf("%#v\n", isZeroA)
	fmt.Printf("%#v\n", isZeroB)
	// Output:
	// true
	// false
}

func ExampleHasZero() {
	// Let's define an Access struct. Note that the "Enabled" field is not
	// going to be checked because we added the "structs" tag to the field.
	type Access struct {
		Name         string
		LastAccessed time.Time
		Number       int
		Enabled      bool `structs:"-"`
	}

	// Name and Number is not initialized.
	a := &Access{
		LastAccessed: time.Now(),
	}
	hasZeroA := HasZero(a)

	// Name and Number is initialized.
	b := &Access{
		Name:         "Fatih",
		LastAccessed: time.Now(),
		Number:       12345,
	}
	hasZeroB := HasZero(b)

	fmt.Printf("%#v\n", hasZeroA)
	fmt.Printf("%#v\n", hasZeroB)
	// Output:
	// true
	// false
}
<|endoftext|>


<commit_before>package requests

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-requests/requests/options"
)

var (
	registeredOptions = map[string]OptionFunc{
		"required":  OptionFunc(options.Required),
		"default":   OptionFunc(options.Default),
		"immutable": OptionFunc(options.Immutable),
	}

	optionDefaults map[string]string
	fallbackTags   []string
)

// FallbackTags returns a list of tag names that are used as fallbacks
// to locate field names.  See AddFallbackTag for more details.
func FallbackTags() []string {
	if fallbackTags == nil {
		fallbackTags = make([]string, 0, 5)
	}
	return fallbackTags
}

// AddFallbackTag adds a tag name to the list of fallback tag names to
// use when locating a field name.  For example, if you use the "db"
// tag and find yourself duplicating the name in both the "db" and
// "request" tags as follows:
//
//     type Example struct {
//         User `db:"user_id" request:"user_id"`
//     }
//
// Then you could update your code to the following:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         User `db:"user_id"`
//     }
//
// Fallback tags will only be added once - duplicates will be ignored.
// Fallbacks will be used in the order that they are added, so if you
// add "db" before "response" (as an example), the "db" tag will be
// preferred over the "response" tag as a fallback.
//
// In all cases, the "request" tag will be preferred over anything
// else.  However, an empty name (but non-empty options) will cause
// the fallbacks to be used, as in the following example:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         // Use the name from the DB, but add the 'required' option
//         // for requests.
//         User `db:"user_id" request:",required"`
//     }
func AddFallbackTag(newTag string) {
	tags := FallbackTags()
	for _, tag := range tags {
		if tag == newTag {
			return
		}
	}
	fallbackTags = append(tags, newTag)
}

// OptionDefaults returns a list of default values for options.  See
// SetOptionDefault for more details.
func OptionDefaults() map[string]string {
	if optionDefaults == nil {
		optionDefaults = make(map[string]string)
	}
	return optionDefaults
}

// SetOptionDefault sets an option to default to a value.  By default,
// OptionFuncs that are excluded from a field's options are never
// called, but if you set a default for that option, it will always be
// called with the default value if the option is not provided on the
// struct field.  An example:
//
//     func init() {
//         SetOptionDefault("required", "true")
//     }
//
//     type Example struct {
//         // user_id will be required in the request
//         User `db:user_id`
//
//         // description will be optional in the request
//         Description `request:",required=false"`
//     }
func SetOptionDefault(option, value string) {
	OptionDefaults()[option] = value
}

// An OptionFunc is a function which takes a field's original value,
// new value (from a request), and a string of option values (anything
// to the right of the = sign in a field's tag option), and returns
// the final new value (parsed from the request value) and any errors encountered.
type OptionFunc func(originalValue, requestValue interface{}, optionValue string) (convertedValue interface{}, err error)

type tagOption struct {
	name  string
	value string
}

func (option tagOption) function() OptionFunc {
	function, _ := registeredOptions[option.name]
	return function
}

// RegisterOption can be used to register functions that should be
// called for struct fields with matching option strings.  For
// example:
//
//     RegisterOption("allow-empty", func(value interface{}, optionValue string) (interface{}, error) {
//         if optionValue == "false" {
//             if value == nil || value.(string) == "" {
//                 return nil, errors.New("Cannot be empty")
//             }
//         }
//         return value, nil
//     })
//
//     type Example struct {
//         Name `request:",allow-empty=false"`
//     }
//
// Any options without a value (e.g. request:",non-empty") will have
// their value set to "true".
//
// An error will be returned if an OptionFunc is already registered
// for the provided name.
func RegisterOption(name string, optionFunc OptionFunc) error {
	if _, ok := registeredOptions[name]; ok {
		return fmt.Errorf(`An OptionFunc is already registered for "%s"`, name)
	}
	registeredOptions[name] = optionFunc
	return nil
}

// ApplyOptions will attempt to apply any OptionFunc values registered
// with RegisterOption to a struct field.  If any of the OptionFuncs
// return an error, the process will immediately return a nil value
// and the returned error.
func ApplyOptions(field reflect.StructField, orig, input interface{}) (value interface{}, optionErr error) {
	value = input
	for _, option := range tagOptions(field) {
		optionFunc := option.function()
		if optionFunc == nil {
			return nil, fmt.Errorf(`Could not find a registered OptionFunc for option "%s"`, option.name)
		}
		if value, optionErr = optionFunc(orig, value, option.value); optionErr != nil {
			return nil, optionErr
		}
	}
	return
}

func tagOptions(field reflect.StructField) []*tagOption {
	remaining := field.Tag.Get("request")
	options := make([]*tagOption, 0, len(optionDefaults)+5)
	for startIdx := strings.IndexRune(remaining, ','); startIdx >= 0; startIdx = strings.IndexRune(remaining, ',') {
		// Skip over the ',' character
		startIdx++
		endIdx := strings.IndexRune(remaining[startIdx:], ',')
		if endIdx < 0 {
			endIdx = len(remaining)
		} else {
			endIdx += startIdx
		}
		currentOption := remaining[startIdx:endIdx]
		remaining = remaining[endIdx:]

		optionNameEnd := strings.IndexRune(currentOption, '=')
		optionNameStart := optionNameEnd + 1
		if optionNameEnd < 0 {
			optionNameEnd = len(currentOption)
			optionNameStart = len(currentOption)
		}

		option := new(tagOption)
		option.name = currentOption[:optionNameEnd]
		option.value = currentOption[optionNameStart:]
		if option.value == "" {
			option.value = "true"
		}
		options = append(options, option)
	}

	for name, defaultValue := range optionDefaults {
		useDefault := true
		for _, option := range options {
			if name == option.name {
				useDefault = false
				break
			}
		}
		if useDefault {
			options = append(options, &tagOption{
				name:  name,
				value: defaultValue,
			})
		}
	}
	return options
}

func name(field reflect.StructField) string {
	name := nameFromTag(field, "request")
	for fallback := 0; len(name) == 0 && fallback < len(fallbackTags); fallback++ {
		name = nameFromTag(field, fallbackTags[fallback])
	}
	if len(name) == 0 {
		name = strings.ToLower(field.Name)
	}
	return name
}

func nameFromTag(field reflect.StructField, tagName string) string {
	name := field.Tag.Get(tagName)
	nameEnd := strings.IndexRune(name, ',')
	if nameEnd == -1 {
		return name
	}
	return name[:nameEnd]
}
<commit_msg>Removed reference to old repository<commit_after>package requests

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/nelsam/requests/options"
)

var (
	registeredOptions = map[string]OptionFunc{
		"required":  OptionFunc(options.Required),
		"default":   OptionFunc(options.Default),
		"immutable": OptionFunc(options.Immutable),
	}

	optionDefaults map[string]string
	fallbackTags   []string
)

// FallbackTags returns a list of tag names that are used as fallbacks
// to locate field names.  See AddFallbackTag for more details.
func FallbackTags() []string {
	if fallbackTags == nil {
		fallbackTags = make([]string, 0, 5)
	}
	return fallbackTags
}

// AddFallbackTag adds a tag name to the list of fallback tag names to
// use when locating a field name.  For example, if you use the "db"
// tag and find yourself duplicating the name in both the "db" and
// "request" tags as follows:
//
//     type Example struct {
//         User `db:"user_id" request:"user_id"`
//     }
//
// Then you could update your code to the following:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         User `db:"user_id"`
//     }
//
// Fallback tags will only be added once - duplicates will be ignored.
// Fallbacks will be used in the order that they are added, so if you
// add "db" before "response" (as an example), the "db" tag will be
// preferred over the "response" tag as a fallback.
//
// In all cases, the "request" tag will be preferred over anything
// else.  However, an empty name (but non-empty options) will cause
// the fallbacks to be used, as in the following example:
//
//     func init() {
//         AddFallbackTag("db")
//     }
//
//     type Example struct {
//         // Use the name from the DB, but add the 'required' option
//         // for requests.
//         User `db:"user_id" request:",required"`
//     }
func AddFallbackTag(newTag string) {
	tags := FallbackTags()
	for _, tag := range tags {
		if tag == newTag {
			return
		}
	}
	fallbackTags = append(tags, newTag)
}

// OptionDefaults returns a list of default values for options.  See
// SetOptionDefault for more details.
func OptionDefaults() map[string]string {
	if optionDefaults == nil {
		optionDefaults = make(map[string]string)
	}
	return optionDefaults
}

// SetOptionDefault sets an option to default to a value.  By default,
// OptionFuncs that are excluded from a field's options are never
// called, but if you set a default for that option, it will always be
// called with the default value if the option is not provided on the
// struct field.  An example:
//
//     func init() {
//         SetOptionDefault("required", "true")
//     }
//
//     type Example struct {
//         // user_id will be required in the request
//         User `db:user_id`
//
//         // description will be optional in the request
//         Description `request:",required=false"`
//     }
func SetOptionDefault(option, value string) {
	OptionDefaults()[option] = value
}

// An OptionFunc is a function which takes a field's original value,
// new value (from a request), and a string of option values (anything
// to the right of the = sign in a field's tag option), and returns
// the final new value (parsed from the request value) and any errors encountered.
type OptionFunc func(originalValue, requestValue interface{}, optionValue string) (convertedValue interface{}, err error)

type tagOption struct {
	name  string
	value string
}

func (option tagOption) function() OptionFunc {
	function, _ := registeredOptions[option.name]
	return function
}

// RegisterOption can be used to register functions that should be
// called for struct fields with matching option strings.  For
// example:
//
//     RegisterOption("allow-empty", func(value interface{}, optionValue string) (interface{}, error) {
//         if optionValue == "false" {
//             if value == nil || value.(string) == "" {
//                 return nil, errors.New("Cannot be empty")
//             }
//         }
//         return value, nil
//     })
//
//     type Example struct {
//         Name `request:",allow-empty=false"`
//     }
//
// Any options without a value (e.g. request:",non-empty") will have
// their value set to "true".
//
// An error will be returned if an OptionFunc is already registered
// for the provided name.
func RegisterOption(name string, optionFunc OptionFunc) error {
	if _, ok := registeredOptions[name]; ok {
		return fmt.Errorf(`An OptionFunc is already registered for "%s"`, name)
	}
	registeredOptions[name] = optionFunc
	return nil
}

// ApplyOptions will attempt to apply any OptionFunc values registered
// with RegisterOption to a struct field.  If any of the OptionFuncs
// return an error, the process will immediately return a nil value
// and the returned error.
func ApplyOptions(field reflect.StructField, orig, input interface{}) (value interface{}, optionErr error) {
	value = input
	for _, option := range tagOptions(field) {
		optionFunc := option.function()
		if optionFunc == nil {
			return nil, fmt.Errorf(`Could not find a registered OptionFunc for option "%s"`, option.name)
		}
		if value, optionErr = optionFunc(orig, value, option.value); optionErr != nil {
			return nil, optionErr
		}
	}
	return
}

func tagOptions(field reflect.StructField) []*tagOption {
	remaining := field.Tag.Get("request")
	options := make([]*tagOption, 0, len(optionDefaults)+5)
	for startIdx := strings.IndexRune(remaining, ','); startIdx >= 0; startIdx = strings.IndexRune(remaining, ',') {
		// Skip over the ',' character
		startIdx++
		endIdx := strings.IndexRune(remaining[startIdx:], ',')
		if endIdx < 0 {
			endIdx = len(remaining)
		} else {
			endIdx += startIdx
		}
		currentOption := remaining[startIdx:endIdx]
		remaining = remaining[endIdx:]

		optionNameEnd := strings.IndexRune(currentOption, '=')
		optionNameStart := optionNameEnd + 1
		if optionNameEnd < 0 {
			optionNameEnd = len(currentOption)
			optionNameStart = len(currentOption)
		}

		option := new(tagOption)
		option.name = currentOption[:optionNameEnd]
		option.value = currentOption[optionNameStart:]
		if option.value == "" {
			option.value = "true"
		}
		options = append(options, option)
	}

	for name, defaultValue := range optionDefaults {
		useDefault := true
		for _, option := range options {
			if name == option.name {
				useDefault = false
				break
			}
		}
		if useDefault {
			options = append(options, &tagOption{
				name:  name,
				value: defaultValue,
			})
		}
	}
	return options
}

func name(field reflect.StructField) string {
	name := nameFromTag(field, "request")
	for fallback := 0; len(name) == 0 && fallback < len(fallbackTags); fallback++ {
		name = nameFromTag(field, fallbackTags[fallback])
	}
	if len(name) == 0 {
		name = strings.ToLower(field.Name)
	}
	return name
}

func nameFromTag(field reflect.StructField, tagName string) string {
	name := field.Tag.Get(tagName)
	nameEnd := strings.IndexRune(name, ',')
	if nameEnd == -1 {
		return name
	}
	return name[:nameEnd]
}
<|endoftext|>


<commit_before>// Package mongo is a REST Layer resource storage handler for MongoDB using mgo
package mongo

import (
	"context"
	"time"

	"github.com/rs/rest-layer/resource"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type key int

// Hkey is now a global exported key so other packages can used this for setting ctx values.
var Hkey key = 1

// mongoItem is a bson representation of a resource.Item
type mongoItem struct {
	ID      interface{}            `bson:"_id"`
	ETag    string                 `bson:"_etag"`
	Updated time.Time              `bson:"_updated"`
	Payload map[string]interface{} `bson:",inline"`
}

// newMongoItem converts a resource.Item into a mongoItem
func newMongoItem(i *resource.Item) *mongoItem {
	// Filter out id from the payload so we don't store it twice
	p := map[string]interface{}{}
	for k, v := range i.Payload {
		if k != "id" {
			p[k] = v
		}
	}
	return &mongoItem{
		ID:      i.ID,
		ETag:    i.ETag,
		Updated: i.Updated,
		Payload: p,
	}
}

// newItem converts a back mongoItem into a resource.Item
func newItem(i *mongoItem) *resource.Item {
	// Add the id back (we use the same map hoping the mongoItem won't be stored back)
	i.Payload["id"] = i.ID
	return &resource.Item{
		ID:      i.ID,
		ETag:    i.ETag,
		Updated: i.Updated,
		Payload: i.Payload,
	}
}

// Handler handles resource storage in a MongoDB collection.
type Handler func(ctx context.Context) (*mgo.Collection, error)

// NewHandler creates an new mongo handler
func NewHandler(s *mgo.Session, db, collection string) Handler {
	s.EnsureSafe(&mgo.Safe{})
	return func(ctx context.Context) (*mgo.Collection, error) {
		// With mgo, session.Copy() pulls a connection from the connection pool
		return s.DB(db).C(collection), nil
	}
}

// C returns the mongo collection managed by this storage handler
// from a Copy() of the mgo session.
func (m Handler) c(ctx context.Context) (*mgo.Collection, error) {
	if err := ctx.Err(); err != nil {
		return nil, err
	}
	c, err := m(ctx)
	if err != nil {
		return nil, err
	}

	// With mgo, session.Copy() pulls a connection from the connection pool
	s := c.Database.Session.Copy()
	// Ensure safe mode is enabled in order to get errors
	s.EnsureSafe(&mgo.Safe{})
	// Set a timeout to match the context deadline if any
	if deadline, ok := ctx.Deadline(); ok {
		timeout := deadline.Sub(time.Now())
		if timeout <= 0 {
			timeout = 0
		}
		s.SetSocketTimeout(timeout)
		s.SetSyncTimeout(timeout)
	}
	return s.DB(c.Database.Name).C(c.Name), nil
}

// close returns a mgo.Collection's session to the connection pool.
func (m Handler) close(c *mgo.Collection) {
	c.Database.Session.Close()
}

// Insert inserts new items in the mongo collection
func (m Handler) Insert(ctx context.Context, items []*resource.Item) error {
	mItems := make([]interface{}, len(items))
	for i, item := range items {
		mItems[i] = newMongoItem(item)
	}
	c, err := m.c(ctx)
	if err != nil {
		return err
	}
	defer m.close(c)
	err = c.Insert(mItems...)
	if mgo.IsDup(err) {
		// Duplicate ID key
		err = resource.ErrConflict
	}
	if ctx.Err() != nil {
		return ctx.Err()
	}
	return err
}

// Update replace an item by a new one in the mongo collection
func (m Handler) Update(ctx context.Context, item *resource.Item, original *resource.Item) error {
	mItem := newMongoItem(item)
	c, err := m.c(ctx)
	if err != nil {
		return err
	}
	defer m.close(c)
	err = c.Update(bson.M{"_id": original.ID, "_etag": original.ETag}, mItem)
	if err == mgo.ErrNotFound {
		// Determine if the item is not found or if the item is found but etag missmatch
		var count int
		count, err = c.FindId(original.ID).Count()
		if err != nil {
			// The find returned an unexpected err, just forward it with no mapping
		} else if count == 0 {
			err = resource.ErrNotFound
		} else if ctx.Err() != nil {
			err = ctx.Err()
		} else {
			// If the item were found, it means that its etag didn't match
			err = resource.ErrConflict
		}
	}
	return err
}

// Delete deletes an item from the mongo collection
func (m Handler) Delete(ctx context.Context, item *resource.Item) error {
	c, err := m.c(ctx)
	if err != nil {
		return err
	}
	defer m.close(c)
	err = c.Remove(bson.M{"_id": item.ID, "_etag": item.ETag})
	if err == mgo.ErrNotFound {
		// Determine if the item is not found or if the item is found but etag missmatch
		var count int
		count, err = c.FindId(item.ID).Count()
		if err != nil {
			// The find returned an unexpected err, just forward it with no mapping
		} else if count == 0 {
			err = resource.ErrNotFound
		} else if ctx.Err() != nil {
			err = ctx.Err()
		} else {
			// If the item were found, it means that its etag didn't match
			err = resource.ErrConflict
		}
	}
	return err
}

// Clear clears all items from the mongo collection matching the lookup
func (m Handler) Clear(ctx context.Context, lookup *resource.Lookup) (int, error) {
	q, err := getQuery(lookup)
	if err != nil {
		return 0, err
	}
	c, err := m.c(ctx)
	if err != nil {
		return 0, err
	}
	defer m.close(c)
	info, err := c.RemoveAll(q)
	if err != nil {
		return 0, err
	}
	if ctx.Err() != nil {
		return 0, ctx.Err()
	}
	return info.Removed, nil
}

// Find items from the mongo collection matching the provided lookup
func (m Handler) Find(ctx context.Context, lookup *resource.Lookup, offset, limit int) (*resource.ItemList, error) {
	q, err := getQuery(lookup)
	if err != nil {
		return nil, err
	}
	s := getSort(lookup)
	c, err := m.c(ctx)
	if err != nil {
		return nil, err
	}
	defer m.close(c)
	var mItem mongoItem
	query := c.Find(q).Sort(s...)

	if offset > 0 {
		query.Skip(offset)
	}
	if limit >= 0 {
		query.Limit(limit)
	}
	// Apply context deadline if any
	if dl, ok := ctx.Deadline(); ok {
		dur := dl.Sub(time.Now())
		if dur < 0 {
			dur = 0
		}
		query.SetMaxTime(dur)
	}
	// Perform request
	iter := query.Iter()
	// Total is set to -1 because we have no easy way with Mongodb to to compute this value
	// without performing two requests.
	list := &resource.ItemList{Total: -1, Items: []*resource.Item{}}
	for iter.Next(&mItem) {
		// Check if context is still ok before to continue
		if err = ctx.Err(); err != nil {
			// TODO bench this as net/context is using mutex under the hood
			iter.Close()
			return nil, err
		}
		list.Items = append(list.Items, newItem(&mItem))
	}
	if err := iter.Close(); err != nil {
		return nil, err
	}
	// If the number of returned elements is lower than requested limit, or not
	// limit is requested, we can deduce the total number of element for free.
	if limit == -1 || len(list.Items) < limit {
		list.Total = offset + len(list.Items)
	}
	return list, err
}

// Count counts the number items matching the lookup filter
func (m Handler) Count(ctx context.Context, lookup *resource.Lookup) (int, error) {
	q, err := getQuery(lookup)
	if err != nil {
		return -1, err
	}
	c, err := m.c(ctx)
	if err != nil {
		return -1, err
	}
	defer m.close(c)
	query := c.Find(q)
	// Apply context deadline if any
	if dl, ok := ctx.Deadline(); ok {
		dur := dl.Sub(time.Now())
		if dur < 0 {
			dur = 0
		}
		query.SetMaxTime(dur)
	}
	return query.Count()
}
<commit_msg>remove comment<commit_after>// Package mongo is a REST Layer resource storage handler for MongoDB using mgo
package mongo

import (
	"context"
	"time"

	"github.com/rs/rest-layer/resource"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type key int

// Hkey is now a global exported key so other packages can used this for setting ctx values.
var Hkey key = 1

// mongoItem is a bson representation of a resource.Item
type mongoItem struct {
	ID      interface{}            `bson:"_id"`
	ETag    string                 `bson:"_etag"`
	Updated time.Time              `bson:"_updated"`
	Payload map[string]interface{} `bson:",inline"`
}

// newMongoItem converts a resource.Item into a mongoItem
func newMongoItem(i *resource.Item) *mongoItem {
	// Filter out id from the payload so we don't store it twice
	p := map[string]interface{}{}
	for k, v := range i.Payload {
		if k != "id" {
			p[k] = v
		}
	}
	return &mongoItem{
		ID:      i.ID,
		ETag:    i.ETag,
		Updated: i.Updated,
		Payload: p,
	}
}

// newItem converts a back mongoItem into a resource.Item
func newItem(i *mongoItem) *resource.Item {
	// Add the id back (we use the same map hoping the mongoItem won't be stored back)
	i.Payload["id"] = i.ID
	return &resource.Item{
		ID:      i.ID,
		ETag:    i.ETag,
		Updated: i.Updated,
		Payload: i.Payload,
	}
}

// Handler handles resource storage in a MongoDB collection.
type Handler func(ctx context.Context) (*mgo.Collection, error)

// NewHandler creates an new mongo handler
func NewHandler(s *mgo.Session, db, collection string) Handler {
	s.EnsureSafe(&mgo.Safe{})
	return func(ctx context.Context) (*mgo.Collection, error) {
		return s.DB(db).C(collection), nil
	}
}

// C returns the mongo collection managed by this storage handler
// from a Copy() of the mgo session.
func (m Handler) c(ctx context.Context) (*mgo.Collection, error) {
	if err := ctx.Err(); err != nil {
		return nil, err
	}
	c, err := m(ctx)
	if err != nil {
		return nil, err
	}

	// With mgo, session.Copy() pulls a connection from the connection pool
	s := c.Database.Session.Copy()
	// Ensure safe mode is enabled in order to get errors
	s.EnsureSafe(&mgo.Safe{})
	// Set a timeout to match the context deadline if any
	if deadline, ok := ctx.Deadline(); ok {
		timeout := deadline.Sub(time.Now())
		if timeout <= 0 {
			timeout = 0
		}
		s.SetSocketTimeout(timeout)
		s.SetSyncTimeout(timeout)
	}
	return s.DB(c.Database.Name).C(c.Name), nil
}

// close returns a mgo.Collection's session to the connection pool.
func (m Handler) close(c *mgo.Collection) {
	c.Database.Session.Close()
}

// Insert inserts new items in the mongo collection
func (m Handler) Insert(ctx context.Context, items []*resource.Item) error {
	mItems := make([]interface{}, len(items))
	for i, item := range items {
		mItems[i] = newMongoItem(item)
	}
	c, err := m.c(ctx)
	if err != nil {
		return err
	}
	defer m.close(c)
	err = c.Insert(mItems...)
	if mgo.IsDup(err) {
		// Duplicate ID key
		err = resource.ErrConflict
	}
	if ctx.Err() != nil {
		return ctx.Err()
	}
	return err
}

// Update replace an item by a new one in the mongo collection
func (m Handler) Update(ctx context.Context, item *resource.Item, original *resource.Item) error {
	mItem := newMongoItem(item)
	c, err := m.c(ctx)
	if err != nil {
		return err
	}
	defer m.close(c)
	err = c.Update(bson.M{"_id": original.ID, "_etag": original.ETag}, mItem)
	if err == mgo.ErrNotFound {
		// Determine if the item is not found or if the item is found but etag missmatch
		var count int
		count, err = c.FindId(original.ID).Count()
		if err != nil {
			// The find returned an unexpected err, just forward it with no mapping
		} else if count == 0 {
			err = resource.ErrNotFound
		} else if ctx.Err() != nil {
			err = ctx.Err()
		} else {
			// If the item were found, it means that its etag didn't match
			err = resource.ErrConflict
		}
	}
	return err
}

// Delete deletes an item from the mongo collection
func (m Handler) Delete(ctx context.Context, item *resource.Item) error {
	c, err := m.c(ctx)
	if err != nil {
		return err
	}
	defer m.close(c)
	err = c.Remove(bson.M{"_id": item.ID, "_etag": item.ETag})
	if err == mgo.ErrNotFound {
		// Determine if the item is not found or if the item is found but etag missmatch
		var count int
		count, err = c.FindId(item.ID).Count()
		if err != nil {
			// The find returned an unexpected err, just forward it with no mapping
		} else if count == 0 {
			err = resource.ErrNotFound
		} else if ctx.Err() != nil {
			err = ctx.Err()
		} else {
			// If the item were found, it means that its etag didn't match
			err = resource.ErrConflict
		}
	}
	return err
}

// Clear clears all items from the mongo collection matching the lookup
func (m Handler) Clear(ctx context.Context, lookup *resource.Lookup) (int, error) {
	q, err := getQuery(lookup)
	if err != nil {
		return 0, err
	}
	c, err := m.c(ctx)
	if err != nil {
		return 0, err
	}
	defer m.close(c)
	info, err := c.RemoveAll(q)
	if err != nil {
		return 0, err
	}
	if ctx.Err() != nil {
		return 0, ctx.Err()
	}
	return info.Removed, nil
}

// Find items from the mongo collection matching the provided lookup
func (m Handler) Find(ctx context.Context, lookup *resource.Lookup, offset, limit int) (*resource.ItemList, error) {
	q, err := getQuery(lookup)
	if err != nil {
		return nil, err
	}
	s := getSort(lookup)
	c, err := m.c(ctx)
	if err != nil {
		return nil, err
	}
	defer m.close(c)
	var mItem mongoItem
	query := c.Find(q).Sort(s...)

	if offset > 0 {
		query.Skip(offset)
	}
	if limit >= 0 {
		query.Limit(limit)
	}
	// Apply context deadline if any
	if dl, ok := ctx.Deadline(); ok {
		dur := dl.Sub(time.Now())
		if dur < 0 {
			dur = 0
		}
		query.SetMaxTime(dur)
	}
	// Perform request
	iter := query.Iter()
	// Total is set to -1 because we have no easy way with Mongodb to to compute this value
	// without performing two requests.
	list := &resource.ItemList{Total: -1, Items: []*resource.Item{}}
	for iter.Next(&mItem) {
		// Check if context is still ok before to continue
		if err = ctx.Err(); err != nil {
			// TODO bench this as net/context is using mutex under the hood
			iter.Close()
			return nil, err
		}
		list.Items = append(list.Items, newItem(&mItem))
	}
	if err := iter.Close(); err != nil {
		return nil, err
	}
	// If the number of returned elements is lower than requested limit, or not
	// limit is requested, we can deduce the total number of element for free.
	if limit == -1 || len(list.Items) < limit {
		list.Total = offset + len(list.Items)
	}
	return list, err
}

// Count counts the number items matching the lookup filter
func (m Handler) Count(ctx context.Context, lookup *resource.Lookup) (int, error) {
	q, err := getQuery(lookup)
	if err != nil {
		return -1, err
	}
	c, err := m.c(ctx)
	if err != nil {
		return -1, err
	}
	defer m.close(c)
	query := c.Find(q)
	// Apply context deadline if any
	if dl, ok := ctx.Deadline(); ok {
		dur := dl.Sub(time.Now())
		if dur < 0 {
			dur = 0
		}
		query.SetMaxTime(dur)
	}
	return query.Count()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"net/http"
	"os"
	"strconv"
)

var db *sql.DB
var visitorsStmt *sql.Stmt
var visitStmt *sql.Stmt

type Visit struct {
	timse string
	location string
	ip string
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" || r.Method == "" {
		getCount(w)
	} else if r.Method == "POST" {
		post(w, r)
	}
}

func get(w http.ResponseWriter) {
	w.Header().Set("Access-Control-Allow-Origin", "*")

	rows, err := db.Query("select datetime(time, 'localtime'), location, ip from visits, visitors where visits.visitor = visitors.id;")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	visits := []Visit{}

	// fmt.Fprint(w, "[")
	// first := true
	for rows.Next() {
		// if first {
		// 	first = false
		// } else {
		// 	fmt.Fprint(w, ",")
		// }

		var time string
		var location string
		var ip string

		rows.Scan(&time, &location, &ip)
		v := Visit{time, location, ip}
		visits = append(visits, v)

		// fmt.Fprintf(w, "{\"time\":\"%s\",\"location\":\"%s\",\"ip\":\"%s\"}", time, location, ip)
	}
	// fmt.Fprint(w, "]")
	b, _ := json.Marshal(visits)
	fmt.Fprint(w, b)

	rows.Close()
}

func getCount(w http.ResponseWriter) {
	w.Header().Set("Access-Control-Allow-Origin", "*")

	rows, err := db.Query("select count(id), strftime(\"%Y-%m-%d %H:%M:00\", datetime(time, 'localtime')) from visits where time > datetime('now', '-1000 hours') group by strftime(\"%Y%j%H\", time);")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	// fmt.Fprint(w, "[")
	// first := true
	counts := []map[string]string{}
	for rows.Next() {
		// if first {
		// 	first = false
		// } else {
		// 	fmt.Fprint(w, ",")
		// }

		var count string
		var time string

		rows.Scan(&count, &time)
		counts = append(counts, map[string]string{
			"time": time,
			"count": count,
			})
		// fmt.Fprintf(w, "{\"time\":\"%s UTC\",\"count\":%s}", time, count)
	}
	b, _ := json.Marshal(counts)
	fmt.Fprintf(w, string(b))
	// fmt.Fprint(w, "]")

	rows.Close()
}

func post(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")

	if r.FormValue("action") == "enter" {
		var id int64
		cookie, err := r.Cookie("avid")

		if err != nil {
			result, err := visitorsStmt.Exec(r.RemoteAddr)

			if err != nil {
				log.Print(err)
				return
			}

			id, _ = result.LastInsertId()
			//fmt.Println(id)
		} else {
			id_s, _ := strconv.Atoi(cookie.Value)
			id = int64(id_s)
		}

		_, err = visitStmt.Exec(r.FormValue("url"), r.FormValue("referrer"), id)

		if err != nil {
			log.Print(err)
			return
		}
	}
}

func main() {
	isNew := false

	_, err := os.Open("./alight.db")
	if err != nil {
		isNew = true
	}

	db, err = sql.Open("sqlite3", "./alight.db")
	defer db.Close()

	if isNew {
		sqlStmt := `
		create table visits (id integer primary key, url text, time integer, referrer text, visitor integer);
		create table visitors (id integer primary key, location text, ip text);
		`

		_, err = db.Exec(sqlStmt)
		if err != nil {
			os.Remove("./alight.db")
			log.Printf("%q: %s\n", err, sqlStmt)
			return
		}
	}

	db.Exec("pragma synchronous = OFF")

	visitorsStmt, err = db.Prepare("insert into visitors values (null, 'Vancouver', ?)")
	if err != nil {
		log.Fatal(err)
	}
	visitStmt, err = db.Prepare("insert into visits values (null, ?, datetime('now'), ?, ?);")
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", handler)
	http.ListenAndServe(":8000", nil)
}
<commit_msg>remove minute from count output<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"net/http"
	"os"
	"strconv"
)

var db *sql.DB
var visitorsStmt *sql.Stmt
var visitStmt *sql.Stmt

type Visit struct {
	timse string
	location string
	ip string
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" || r.Method == "" {
		getCount(w)
	} else if r.Method == "POST" {
		post(w, r)
	}
}

func get(w http.ResponseWriter) {
	w.Header().Set("Access-Control-Allow-Origin", "*")

	rows, err := db.Query("select datetime(time, 'localtime'), location, ip from visits, visitors where visits.visitor = visitors.id;")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	visits := []Visit{}

	// fmt.Fprint(w, "[")
	// first := true
	for rows.Next() {
		// if first {
		// 	first = false
		// } else {
		// 	fmt.Fprint(w, ",")
		// }

		var time string
		var location string
		var ip string

		rows.Scan(&time, &location, &ip)
		v := Visit{time, location, ip}
		visits = append(visits, v)

		// fmt.Fprintf(w, "{\"time\":\"%s\",\"location\":\"%s\",\"ip\":\"%s\"}", time, location, ip)
	}
	// fmt.Fprint(w, "]")
	b, _ := json.Marshal(visits)
	fmt.Fprint(w, b)

	rows.Close()
}

func getCount(w http.ResponseWriter) {
	w.Header().Set("Access-Control-Allow-Origin", "*")

	rows, err := db.Query("select count(id), strftime(\"%Y-%m-%d %H:00:00\", datetime(time, 'localtime')) from visits where time > datetime('now', '-1000 hours') group by strftime(\"%Y%j%H\", time);")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	// fmt.Fprint(w, "[")
	// first := true
	counts := []map[string]string{}
	for rows.Next() {
		// if first {
		// 	first = false
		// } else {
		// 	fmt.Fprint(w, ",")
		// }

		var count string
		var time string

		rows.Scan(&count, &time)
		counts = append(counts, map[string]string{
			"time": time,
			"count": count,
			})
		// fmt.Fprintf(w, "{\"time\":\"%s UTC\",\"count\":%s}", time, count)
	}
	b, _ := json.Marshal(counts)
	fmt.Fprintf(w, string(b))
	// fmt.Fprint(w, "]")

	rows.Close()
}

func post(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")

	if r.FormValue("action") == "enter" {
		var id int64
		cookie, err := r.Cookie("avid")

		if err != nil {
			result, err := visitorsStmt.Exec(r.RemoteAddr)

			if err != nil {
				log.Print(err)
				return
			}

			id, _ = result.LastInsertId()
			//fmt.Println(id)
		} else {
			id_s, _ := strconv.Atoi(cookie.Value)
			id = int64(id_s)
		}

		_, err = visitStmt.Exec(r.FormValue("url"), r.FormValue("referrer"), id)

		if err != nil {
			log.Print(err)
			return
		}
	}
}

func main() {
	isNew := false

	_, err := os.Open("./alight.db")
	if err != nil {
		isNew = true
	}

	db, err = sql.Open("sqlite3", "./alight.db")
	defer db.Close()

	if isNew {
		sqlStmt := `
		create table visits (id integer primary key, url text, time integer, referrer text, visitor integer);
		create table visitors (id integer primary key, location text, ip text);
		`

		_, err = db.Exec(sqlStmt)
		if err != nil {
			os.Remove("./alight.db")
			log.Printf("%q: %s\n", err, sqlStmt)
			return
		}
	}

	db.Exec("pragma synchronous = OFF")

	visitorsStmt, err = db.Prepare("insert into visitors values (null, 'Vancouver', ?)")
	if err != nil {
		log.Fatal(err)
	}
	visitStmt, err = db.Prepare("insert into visits values (null, ?, datetime('now'), ?, ?);")
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", handler)
	http.ListenAndServe(":8000", nil)
}
<|endoftext|>