<commit_before>package pool

import (
	"io"
)

// A LimitedConnPool is a connection pool, with the property that
// the total number of live connections is limited to the size
// parameter passed to NewLimited. In order to make this guarantee,
// we assume that all new connections are introduced by calls to the
// Get method, and return to the pool by the Put method (whether
// or not the connection is dead)
type LimitedConnPool struct {
	conns  chan io.WriteCloser // Available connections in the pool
	live   chan struct{}       // Keep a count of living connections (in our hands, or the client)
	signal chan struct{}       // Used to wake up the connection producer
	err    chan error          // Send dial errors back to the client
}

// NewLimited returns a new LimitedConnPool with the given size limit and dial function.
func NewLimited(size int, dial func() (io.WriteCloser, error)) (*LimitedConnPool, error) {
	// Tentative first try - if this doesn't work, we assume it never will
	// and fail to initialize.
	w, err := dial()
	if err != nil {
		return nil, err
	}

	p := LimitedConnPool{
		conns:  make(chan io.WriteCloser, size),
		live:   make(chan struct{}, size),
		signal: make(chan struct{}),

		// try to make this large enough to avoid dropping
		// errors if clients only check errors occasionally
		err: make(chan error, size),
	}

	p.conns <- w
	p.live <- struct{}{}

	// keep p.conns populated
	go func() {
		for range p.signal {
			for len(p.live) < size {
				w, err := dial()
				if err != nil {
					select {
					case p.err <- err:
					default:
						// error channel is full, drop this error
					}
					continue
				}
				p.conns <- w
				p.live <- struct{}{}
			}
		}
	}()

	// kick off the producer
	p.signal <- struct{}{}

	return &p, nil
}

// Put returns a connection to the pool. If dead is true, the
// connection is removed from the pool so that a new connection
// can be dialed.
func (p *LimitedConnPool) Put(w io.WriteCloser, dead bool) error {
	if dead {
		<-p.live               // decrement the live count
		p.signal <- struct{}{} // signal the connection dialer
		return w.Close()
	}
	p.conns <- w
	return nil
}

// Get retrieves a connection from the pool, if available.
// A new connection will only be dialed if the total number
// of live connections is below the configured size limit.
func (p *LimitedConnPool) Get() io.WriteCloser {
	return <-p.conns
}

// Errors returns a channel of errors encountered when dialing new
// connections. Errors will be dropped if this channel is not
// consumed.
func (p *LimitedConnPool) Errors() <-chan error {
	return p.err
}
<commit_msg>lib/syslog: fix typo<commit_after>package pool

import (
	"io"
)

// A LimitedConnPool is a connection pool, with the property that
// the total number of live connections is limited to the size
// parameter passed to NewLimited. In order to make this guarantee,
// we assume that all new connections are introduced by calls to the
// Get method, and returned to the pool by the Put method (whether
// or not the connection is dead)
type LimitedConnPool struct {
	conns  chan io.WriteCloser // Available connections in the pool
	live   chan struct{}       // Keep a count of living connections (in our hands, or the client)
	signal chan struct{}       // Used to wake up the connection producer
	err    chan error          // Send dial errors back to the client
}

// NewLimited returns a new LimitedConnPool with the given size limit and dial function.
func NewLimited(size int, dial func() (io.WriteCloser, error)) (*LimitedConnPool, error) {
	// Tentative first try - if this doesn't work, we assume it never will
	// and fail to initialize.
	w, err := dial()
	if err != nil {
		return nil, err
	}

	p := LimitedConnPool{
		conns:  make(chan io.WriteCloser, size),
		live:   make(chan struct{}, size),
		signal: make(chan struct{}),

		// try to make this large enough to avoid dropping
		// errors if clients only check errors occasionally
		err: make(chan error, size),
	}

	p.conns <- w
	p.live <- struct{}{}

	// keep p.conns populated
	go func() {
		for range p.signal {
			for len(p.live) < size {
				w, err := dial()
				if err != nil {
					select {
					case p.err <- err:
					default:
						// error channel is full, drop this error
					}
					continue
				}
				p.conns <- w
				p.live <- struct{}{}
			}
		}
	}()

	// kick off the producer
	p.signal <- struct{}{}

	return &p, nil
}

// Put returns a connection to the pool. If dead is true, the
// connection is removed from the pool so that a new connection
// can be dialed.
func (p *LimitedConnPool) Put(w io.WriteCloser, dead bool) error {
	if dead {
		<-p.live               // decrement the live count
		p.signal <- struct{}{} // signal the connection dialer
		return w.Close()
	}
	p.conns <- w
	return nil
}

// Get retrieves a connection from the pool, if available.
// A new connection will only be dialed if the total number
// of live connections is below the configured size limit.
func (p *LimitedConnPool) Get() io.WriteCloser {
	return <-p.conns
}

// Errors returns a channel of errors encountered when dialing new
// connections. Errors will be dropped if this channel is not
// consumed.
func (p *LimitedConnPool) Errors() <-chan error {
	return p.err
}
<|endoftext|>


<commit_before>// Package form provides an easy to use way to parse form values from an HTTP
// request into a struct or other data object
package form // import "vimagination.zapto.org/form"

import (
	"net/http"
	"reflect"
	"sync"
)

type processorDetails struct {
	processor
	Post, Required bool
	Index          []int
}

type typeMap map[string]processorDetails

var (
	tmMu     sync.RWMutex
	typeMaps = make(map[reflect.Type]typeMap)
)

func getTypeMap(t reflect.Type) typeMap {
	tmMu.RLock()
	tm, ok := typeMaps[t]
	tmMu.RUnlock()
	if ok {
		return tm
	}
	tmMu.Lock()
	tm = createTypeMap(t)
	tmMu.Unlock()
	return tm
}

func createTypeMap(t reflect.Type) typeMap {
	tm, ok := typeMaps[t]
	if ok {
		return tm
	}
	tm = make(typeMap)
	for i := 0; i < t.Len(); i++ {
		f := t.Field(i)
		if f.PkgPath != "" {
			continue
		}
		name := f.Name
		if n := f.Tag.Get("form"); n != "" {
			name = n
		}
		switch f.Type.Kind() {
		case reflect.Int8:
			tm[name] = newInum8(f.Type)
		case reflect.Int16:
			tm[name] = newInum16(f.Type)
		case reflect.Int32:
			tm[name] = newInum32(f.Type)
		case reflect.Int64:
			tm[name] = newInum64(f.Type)
		case reflect.Int:
			tm[name] = newInum(f.Type)
		case reflect.Uint8:
			tm[name] = newUnum8(f.Type)
		case reflect.Uint16:
			tm[name] = newUnum16(f.Type)
		case reflect.Uint32:
			tm[name] = newUnum32(f.Type)
		case reflect.Uint64:
			tm[name] = newUnum64(f.Type)
		case reflect.Uint:
			tm[name] = newUnum(f.Type)
		}
	}
	typeMaps[t] = tm
	return tm
}

func ProcessForm(r *http.Request, fv interface{}) error {
	v := reflect.ValueOf(fv)
	if v.Kind() != reflect.Ptr {
		return ErrNeedPointer
	}
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return ErrNeedStruct
	}
	tm := getTypeMap(v.Type())
	if err := r.ParseForm(); err != nil {
		return err
	}
	var errors Errors
	for key, pd := range tm {
		var (
			val []string
			ok  bool
		)
		if pd.Post {
			val, ok = r.PostForm[key]
		} else {
			val, ok = r.Form[key]
		}
		if ok {
			if err := pd.processor.process(v.FieldByIndex(pd.Index), val); err != nil {
				errors = append(errors, ErrProcessingFailed{
					Key:   key,
					Error: err,
				})
			}
		} else if pd.Required {
			errors = append(errors, ErrRequiredMissing(key))
		}
	}
	if len(errors) > 0 {
		return errors
	}
	return nil
}
<commit_msg>alternate name can be specified in struct tag<commit_after>// Package form provides an easy to use way to parse form values from an HTTP
// request into a struct or other data object
package form // import "vimagination.zapto.org/form"

import (
	"net/http"
	"reflect"
	"sync"
)

type processorDetails struct {
	processor
	Post, Required bool
	Index          []int
}

type typeMap map[string]processorDetails

var (
	tmMu     sync.RWMutex
	typeMaps = make(map[reflect.Type]typeMap)
)

func getTypeMap(t reflect.Type) typeMap {
	tmMu.RLock()
	tm, ok := typeMaps[t]
	tmMu.RUnlock()
	if ok {
		return tm
	}
	tmMu.Lock()
	tm = createTypeMap(t)
	tmMu.Unlock()
	return tm
}

func createTypeMap(t reflect.Type) typeMap {
	tm, ok := typeMaps[t]
	if ok {
		return tm
	}
	tm = make(typeMap)
	for i := 0; i < t.Len(); i++ {
		f := t.Field(i)
		if f.PkgPath != "" {
			continue
		}
		name := f.Name
		if n := f.Tag.Get("form"); n == "-" {
			continue
		} else if n != "" {
			name = n
		}
		switch f.Type.Kind() {
		case reflect.Int8:
			tm[name] = newInum8(f.Type)
		case reflect.Int16:
			tm[name] = newInum16(f.Type)
		case reflect.Int32:
			tm[name] = newInum32(f.Type)
		case reflect.Int64:
			tm[name] = newInum64(f.Type)
		case reflect.Int:
			tm[name] = newInum(f.Type)
		case reflect.Uint8:
			tm[name] = newUnum8(f.Type)
		case reflect.Uint16:
			tm[name] = newUnum16(f.Type)
		case reflect.Uint32:
			tm[name] = newUnum32(f.Type)
		case reflect.Uint64:
			tm[name] = newUnum64(f.Type)
		case reflect.Uint:
			tm[name] = newUnum(f.Type)
		}
	}
	typeMaps[t] = tm
	return tm
}

func ProcessForm(r *http.Request, fv interface{}) error {
	v := reflect.ValueOf(fv)
	if v.Kind() != reflect.Ptr {
		return ErrNeedPointer
	}
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return ErrNeedStruct
	}
	tm := getTypeMap(v.Type())
	if err := r.ParseForm(); err != nil {
		return err
	}
	var errors Errors
	for key, pd := range tm {
		var (
			val []string
			ok  bool
		)
		if pd.Post {
			val, ok = r.PostForm[key]
		} else {
			val, ok = r.Form[key]
		}
		if ok {
			if err := pd.processor.process(v.FieldByIndex(pd.Index), val); err != nil {
				errors = append(errors, ErrProcessingFailed{
					Key:   key,
					Error: err,
				})
			}
		} else if pd.Required {
			errors = append(errors, ErrRequiredMissing(key))
		}
	}
	if len(errors) > 0 {
		return errors
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"time"

	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/command"
	"github.com/otoolep/rqlite/server"
)

var host string
var port int
var join string
var dbfile string

func init() {
	flag.StringVar(&host, "h", "localhost", "hostname")
	flag.IntVar(&port, "p", 4001, "port")
	flag.StringVar(&join, "join", "", "host:port of leader to join")
	flag.StringVar(&dbfile, "dbfile", "db.sqlite", "sqlite filename")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [arguments] <data-path> \n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	rand.Seed(time.Now().UnixNano())

	// Setup commands.
	raft.RegisterCommand(&command.WriteCommand{})

	// Set the data directory.
	if flag.NArg() == 0 {
		flag.Usage()
		log.Fatal("Data path argument required")
	}
	path := flag.Arg(0)
	if err := os.MkdirAll(path, 0744); err != nil {
		log.Fatalf("Unable to create path: %v", err)
	}

	s := server.New(path, dbfile, host, port)
	log.Fatal(s.ListenAndServe(join))
}
<commit_msg>Add support for pprof profiling<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"runtime/pprof"
	"time"

	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/command"
	"github.com/otoolep/rqlite/server"
)

var host string
var port int
var join string
var dbfile string
var cpuprofile string

func init() {
	flag.StringVar(&host, "h", "localhost", "hostname")
	flag.IntVar(&port, "p", 4001, "port")
	flag.StringVar(&join, "join", "", "host:port of leader to join")
	flag.StringVar(&dbfile, "dbfile", "db.sqlite", "sqlite filename")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write CPU profile to file")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [arguments] <data-path> \n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	// Set up profiling, if requested.
	if cpuprofile != "" {
		log.Printf("Profiling enabled")
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal("Unable to create path: %w", err)
		}
		defer f.Close()

		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Raft requires randomness.
	rand.Seed(time.Now().UnixNano())

	// Setup commands.
	raft.RegisterCommand(&command.WriteCommand{})

	// Set the data directory.
	if flag.NArg() == 0 {
		flag.Usage()
		log.Fatal("Data path argument required")
	}
	path := flag.Arg(0)
	if err := os.MkdirAll(path, 0744); err != nil {
		log.Fatalf("Unable to create path: %v", err)
	}

	s := server.New(path, dbfile, host, port)
	go func() {
		log.Fatal(s.ListenAndServe(join))
	}()

	terminate := make(chan os.Signal, 1)
	signal.Notify(terminate, os.Interrupt)
	<-terminate
	log.Printf("rqlite server stopped")
}
<|endoftext|>


<commit_before>package ast

import "bytes"

type Program struct {
	Statements []Statement
}

func (p *Program) TokenLiteral() string {
	if len(p.Statements) > 0 {
		return p.Statements[0].TokenLiteral()
	} else {
		return ""
	}
}

func (p *Program) String() string {
	var out bytes.Buffer

	for _, s := range p.Statements {
		out.WriteString(s.String())
	}

	return out.String()
}
<commit_msg>added program doc comments<commit_after>package ast

import "bytes"

// Program : Top level construct containing all parsed AST nodes
type Program struct {
	Statements []Statement
}

// TokenLiteral : Returns the literal representations of the tokens for each of the program's statements
func (p *Program) TokenLiteral() string {
	if len(p.Statements) > 0 {
		return p.Statements[0].TokenLiteral()
	}
	return ""
}

func (p *Program) String() string {
	var out bytes.Buffer

	for _, s := range p.Statements {
		out.WriteString(s.String())
	}

	return out.String()
}
<|endoftext|>


<commit_before>package oldstatus

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"sync"

	"github.com/fsnotify/fsnotify"
)

// Opts contains command line parameters for the 'oldstatus' command
type Opts struct {
	Port         int    `short:"p" long:"port" description:"Port on which to listen" default:"7887"`
	StatusFile   string `long:"status-file" description:"Path to old platform-configure status file" default:"/etc/protonet/system/configure-script-status"`
	StatusSocket string `long:"status-socket" description:"Path to status socket" default:"/var/run/platconf-status.sock"`
}

// StatusData is the data structure sent to the status page
type StatusData struct {
	Status       string   `json:"status"`
	Progress     *float32 `json:"progress"`
	What         *string  `json:"what"`
	sync.RWMutex `json:"-"`
}

func updateStatusFromFile(status *StatusData, filePath string) error {
	var tempStatus StatusData
	f, err := os.Open(filePath)
	if err != nil {
		return err
	}

	decoder := json.NewDecoder(f)
	err = decoder.Decode(&tempStatus)
	if err != nil {
		return err
	}

	status.Lock()
	defer status.Unlock()
	status.Status = tempStatus.Status
	status.Progress = tempStatus.Progress
	status.What = tempStatus.What
	return nil
}

func watchStatusFileForChange(status *StatusData, filePath string) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatalf("Failed to initalize a file watcher: %s", err.Error())
	}
	defer watcher.Close()

	err = watcher.Add(filePath)
	if err != nil {
		log.Println("Failed to add file '%s' to the file watcher: %s", filePath, err.Error())
		return err
	}

	log.Println("Status file watcher started on", filePath)

	for {
		select {
		case event := <-watcher.Events:
			if event.Op&fsnotify.Write == fsnotify.Write {
				err := updateStatusFromFile(status, filePath)
				if err != nil {
					log.Println("ERROR: failed to read status from SKVS file:", err.Error())
				}
			}
		case err := <-watcher.Errors:
			log.Println("ERROR: failed while watching SKVS update status file:", err.Error())
		}
	}
}

func listenOnUnixSocket(status *StatusData, path string) error {
	os.Remove(path)
	listener, err := net.Listen("unix", path)
	if err != nil {
		return err
	}

	putStatusMux := http.NewServeMux()
	putStatusMux.HandleFunc("/status", func(rw http.ResponseWriter, req *http.Request) {
		if req.Method != "PUT" {
			http.Error(rw, "Method not allowed.", http.StatusMethodNotAllowed)
			return
		}

		var tempStatus StatusData
		decoder := json.NewDecoder(req.Body)
		defer req.Body.Close()

		err := decoder.Decode(&tempStatus)
		if err != nil {
			log.Println("ERROR: failed to decode status from UNIX domain socket", err.Error())
			http.Error(rw, "Couldn't decode status.", http.StatusBadRequest)
			return
		}

		status.Lock()
		defer status.Unlock()
		status.Status = tempStatus.Status
		status.Progress = tempStatus.Progress
		status.What = tempStatus.What

		http.Error(rw, "OK", http.StatusAccepted)
	})

	server := &http.Server{
		Handler: putStatusMux,
	}

	go server.Serve(listener)
	return nil
}

func getStatusReadMux(status *StatusData) *http.ServeMux {
	mux := http.NewServeMux()
	mux.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		status.RLock()
		defer status.RUnlock()
		w.Header().Set("Content-Type", "application/json")
		encoder := json.NewEncoder(w)
		encoder.Encode(&status)
	})

	mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Not found.", http.StatusNotFound)
	})

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		w.Write([]byte(htmlBody))
		log.Printf("Serving the status HTML page to '%s'", r.RemoteAddr)
	})

	return mux
}

// Execute is the function ran when the 'oldstatus' command is used
func (o *Opts) Execute(args []string) error {
	var status StatusData

	err := updateStatusFromFile(&status, o.StatusFile)
	if err != nil {
		log.Printf("ERROR: failed to read status from SKVS file: %s", err.Error())
	}
	go watchStatusFileForChange(&status, o.StatusFile)

	server := &http.Server{
		Handler: getStatusReadMux(&status),
	}

	log.Println("Starting platform-install-status")
	// We're explicitly opening a listener first to check if there is already
	// an instance running. If we could bind to the port successfully then
	// we can also safely remove the UNIX domain socket.
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", o.Port))
	if err != nil {
		return err
	}

	err = listenOnUnixSocket(&status, o.StatusSocket)
	if err != nil {
		return err
	}

	err = server.Serve(listener)
	return err
}
<commit_msg>fix da fix<commit_after>package oldstatus

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"sync"

	"github.com/fsnotify/fsnotify"
)

// Opts contains command line parameters for the 'oldstatus' command
type Opts struct {
	Port         int    `short:"p" long:"port" description:"Port on which to listen" default:"7887"`
	StatusFile   string `long:"status-file" description:"Path to old platform-configure status file" default:"/etc/protonet/system/configure-script-status"`
	StatusSocket string `long:"status-socket" description:"Path to status socket" default:"/var/run/platconf-status.sock"`
}

// StatusData is the data structure sent to the status page
type StatusData struct {
	Status       string   `json:"status"`
	Progress     *float32 `json:"progress"`
	What         *string  `json:"what"`
	sync.RWMutex `json:"-"`
}

func updateStatusFromFile(status *StatusData, filePath string) error {
	var tempStatus StatusData
	f, err := os.Open(filePath)
	if err != nil {
		return err
	}

	decoder := json.NewDecoder(f)
	err = decoder.Decode(&tempStatus)
	if err != nil {
		return err
	}

	status.Lock()
	defer status.Unlock()
	status.Status = tempStatus.Status
	status.Progress = tempStatus.Progress
	status.What = tempStatus.What
	return nil
}

func watchStatusFileForChange(status *StatusData, filePath string) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatalf("Failed to initalize a file watcher: %s", err.Error())
	}
	defer watcher.Close()

	err = watcher.Add(filePath)
	if err != nil {
		log.Printf("Failed to add file '%s' to the file watcher: %s\n", filePath, err.Error())
		return err
	}

	log.Println("Status file watcher started on", filePath)

	for {
		select {
		case event := <-watcher.Events:
			if event.Op&fsnotify.Write == fsnotify.Write {
				err := updateStatusFromFile(status, filePath)
				if err != nil {
					log.Println("ERROR: failed to read status from SKVS file:", err.Error())
				}
			}
		case err := <-watcher.Errors:
			log.Println("ERROR: failed while watching SKVS update status file:", err.Error())
		}
	}
}

func listenOnUnixSocket(status *StatusData, path string) error {
	os.Remove(path)
	listener, err := net.Listen("unix", path)
	if err != nil {
		return err
	}

	putStatusMux := http.NewServeMux()
	putStatusMux.HandleFunc("/status", func(rw http.ResponseWriter, req *http.Request) {
		if req.Method != "PUT" {
			http.Error(rw, "Method not allowed.", http.StatusMethodNotAllowed)
			return
		}

		var tempStatus StatusData
		decoder := json.NewDecoder(req.Body)
		defer req.Body.Close()

		err := decoder.Decode(&tempStatus)
		if err != nil {
			log.Println("ERROR: failed to decode status from UNIX domain socket", err.Error())
			http.Error(rw, "Couldn't decode status.", http.StatusBadRequest)
			return
		}

		status.Lock()
		defer status.Unlock()
		status.Status = tempStatus.Status
		status.Progress = tempStatus.Progress
		status.What = tempStatus.What

		http.Error(rw, "OK", http.StatusAccepted)
	})

	server := &http.Server{
		Handler: putStatusMux,
	}

	go server.Serve(listener)
	return nil
}

func getStatusReadMux(status *StatusData) *http.ServeMux {
	mux := http.NewServeMux()
	mux.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		status.RLock()
		defer status.RUnlock()
		w.Header().Set("Content-Type", "application/json")
		encoder := json.NewEncoder(w)
		encoder.Encode(&status)
	})

	mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Not found.", http.StatusNotFound)
	})

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		w.Write([]byte(htmlBody))
		log.Printf("Serving the status HTML page to '%s'", r.RemoteAddr)
	})

	return mux
}

// Execute is the function ran when the 'oldstatus' command is used
func (o *Opts) Execute(args []string) error {
	var status StatusData

	err := updateStatusFromFile(&status, o.StatusFile)
	if err != nil {
		log.Printf("ERROR: failed to read status from SKVS file: %s", err.Error())
	}
	go watchStatusFileForChange(&status, o.StatusFile)

	server := &http.Server{
		Handler: getStatusReadMux(&status),
	}

	log.Println("Starting platform-install-status")
	// We're explicitly opening a listener first to check if there is already
	// an instance running. If we could bind to the port successfully then
	// we can also safely remove the UNIX domain socket.
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", o.Port))
	if err != nil {
		return err
	}

	err = listenOnUnixSocket(&status, o.StatusSocket)
	if err != nil {
		return err
	}

	err = server.Serve(listener)
	return err
}
<|endoftext|>


<commit_before>package jest

import (
	"encoding/json"
	"github.com/kr/secureheader"
	"net/http"
	"os"
	"regexp"
	"strings"
)

var (
	config      *secureheader.Config
	routes      []route
	authorize   func(http.ResponseWriter, *http.Request) *Status
	contentType string
)

func init() {
	contentType = "application/json"
	config = secureheader.DefaultConfig
	http.HandleFunc("/", serveResponses)
}

// public

func Handler() *secureheader.Config {
	config.HTTPSRedirect = os.Getenv("JEST_HTTPS") != "false"
	return config
}

func Auth(fn func(http.ResponseWriter, *http.Request) *Status) {
	authorize = fn
}

func Get(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("GET", uri, fn)
}

func Post(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("POST", uri, fn)
}

func Put(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PUT", uri, fn)
}

func Patch(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PATCH", uri, fn)
}

func Delete(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("DELETE", uri, fn)
}

// private

func request(m, u string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	rs := &response{fn: fn}
	for _, r := range routes {
		if r.URI == u {
			r.Responses[m] = rs
			return rs
		}
	}

	v := "([a-zA-Z0-9_-]+)"
	rx := regexp.MustCompile(":" + v)
	r := route{
		URI:       u,
		Responses: make(map[string]*response),
	}

	mr := regexp.MustCompile("^" + rx.ReplaceAllString(u, v) + "$")
	pr := regexp.MustCompile("^" + rx.ReplaceAllString(u, ":"+v) + "$")

	r.Responses[m] = rs
	r.URIMatcher = mr
	r.ParamMatcher = pr

	routes = append(routes, r)
	return rs
}

func serveResponses(ow http.ResponseWriter, r *http.Request) {
	w := &responseWriter{rw: ow}
	w.Header().Set("Content-Type", contentType)
	defer r.Body.Close()

	header := r.Header.Get("Content-Type")
	if header != "" && header != contentType {
		write(w, BadRequest)
		return
	}

	for _, route := range routes {
		if !route.URIMatcher.MatchString(r.URL.Path) {
			continue
		}

		m, mOK := route.Responses[r.Method]
		switch {
		default:
			write(w, MethodNotAllowed)
			return
		case r.Method == "OPTIONS":
			var methods []string
			for m, _ := range route.Responses {
				methods = append(methods, m)
			}

			methods = append(methods, "OPTIONS")

			w.Header().Set("Content-Length", "0")
			w.Header().Set("Allow", strings.Join(methods, ", "))
			return
		case mOK:
			if !m.public {
				if authorize == nil {
					write(w, Forbidden)
					return
				}

				s := authorize(w, r)
				if s != nil && (s.Code < 200 || s.Code > 299) {
					write(w, s)
					return
				}
			}

			write(w, m.fn(w, r))
			return
		}
	}

	write(w, NotFound)
}

func write(w *responseWriter, s *Status) {
	if s == nil {
		s = OK
	}

	if !w.written {
		if !w.writtenHeader {
			w.WriteHeader(s.Code)
		}

		if s != NoContent {
			json.NewEncoder(w).Encode(s)
		}
	}
}
<commit_msg>added docs for project level, Auth and Handler methods<commit_after>// Package jest provides a minimal wrapper to net/http for building JSON in/out
// API's. Jest assumes all routes require authorization unless stated otherwise
// and conveniences such as secure response headers and `OPTIONS` responses.
// Jest also respects routes declared on net/http directly.
//
//  package main
//
//  import (
//    "encoding/json"
//    "github.com/daneharrigan/jest"
//    "net/http"
//  )
//
//  func main() {
//    jest.Auth(handleAuth)
//    jest.Get("/", serveIndex)
//    http.ListenAndServe(":5000", jest.Handler())
//  }
//
//  func handleAuth(w http.ResponseWriter, r *http.Request) *jest.Status {
//    if loggedIn() {
//      return jest.OK
//    }
//
//    return jest.Forbidden
//  }
//
//  func serveIndex(w http.ResponseWriter, r *http.Request) *jest.Status {
//    json.NewEncoder(w).Encode(getItems())
//    return jest.OK
//  }

package jest

import (
	"encoding/json"
	"github.com/kr/secureheader"
	"net/http"
	"os"
	"regexp"
	"strings"
)

var (
	config      *secureheader.Config
	routes      []route
	authorize   func(http.ResponseWriter, *http.Request) *Status
	contentType string
)

func init() {
	contentType = "application/json"
	config = secureheader.DefaultConfig
	http.HandleFunc("/", serveResponses)
}

/* public */

// Handler returns an http handler for http.ListenAndServe. The handler is
// provided by github.com/kr/secureheader and decorates HTTP response with
// a series of secure header information.
func Handler() *secureheader.Config {
	config.HTTPSRedirect = os.Getenv("JEST_HTTPS") != "false"
	return config
}

// Auth accepts a method for granting/denying access to protected routes.
// Returning a jest.Status struct is used to determine whether authorization
// should be allowed or denied.
func Auth(fn func(http.ResponseWriter, *http.Request) *Status) {
	authorize = fn
}

func Get(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("GET", uri, fn)
}

func Post(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("POST", uri, fn)
}

func Put(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PUT", uri, fn)
}

func Patch(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PATCH", uri, fn)
}

func Delete(uri string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("DELETE", uri, fn)
}

/* private */

func request(m, u string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	rs := &response{fn: fn}
	for _, r := range routes {
		if r.URI == u {
			r.Responses[m] = rs
			return rs
		}
	}

	v := "([a-zA-Z0-9_-]+)"
	rx := regexp.MustCompile(":" + v)
	r := route{
		URI:       u,
		Responses: make(map[string]*response),
	}

	mr := regexp.MustCompile("^" + rx.ReplaceAllString(u, v) + "$")
	pr := regexp.MustCompile("^" + rx.ReplaceAllString(u, ":"+v) + "$")

	r.Responses[m] = rs
	r.URIMatcher = mr
	r.ParamMatcher = pr

	routes = append(routes, r)
	return rs
}

func serveResponses(ow http.ResponseWriter, r *http.Request) {
	w := &responseWriter{rw: ow}
	w.Header().Set("Content-Type", contentType)
	defer r.Body.Close()

	header := r.Header.Get("Content-Type")
	if header != "" && header != contentType {
		write(w, BadRequest)
		return
	}

	for _, route := range routes {
		if !route.URIMatcher.MatchString(r.URL.Path) {
			continue
		}

		m, mOK := route.Responses[r.Method]
		switch {
		default:
			write(w, MethodNotAllowed)
			return
		case r.Method == "OPTIONS":
			var methods []string
			for m, _ := range route.Responses {
				methods = append(methods, m)
			}

			methods = append(methods, "OPTIONS")

			w.Header().Set("Content-Length", "0")
			w.Header().Set("Allow", strings.Join(methods, ", "))
			return
		case mOK:
			if !m.public {
				if authorize == nil {
					write(w, Forbidden)
					return
				}

				s := authorize(w, r)
				if s != nil && (s.Code < 200 || s.Code > 299) {
					write(w, s)
					return
				}
			}

			write(w, m.fn(w, r))
			return
		}
	}

	write(w, NotFound)
}

func write(w *responseWriter, s *Status) {
	if s == nil {
		s = OK
	}

	if !w.written {
		if !w.writtenHeader {
			w.WriteHeader(s.Code)
		}

		if s != NoContent {
			json.NewEncoder(w).Encode(s)
		}
	}
}
<|endoftext|>


<commit_before>// This function allows to pass any struct/map, and creates json from it, then writes to http.ResponseWriter
func WriteJson(w http.ResponseWriter, i interface{}) error {

	defer Recover("WriteJson")

	var j []byte

	j, err := json.Marshal(i)
	if err != nil {
		http.Error(w, "Error marshalling JSON", http.StatusInternalServerError)
		return err
	}

	// set Headers
	w.Header().Set("Content-Type", "application/json")
	// write to writer
	w.Write(j)
	return nil
}
<commit_msg>fix json.go<commit_after>package httpUtil

// This function allows to pass any struct/map, and creates json from it, then writes to http.ResponseWriter
func WriteJson(w http.ResponseWriter, i interface{}) error {

	defer Recover("WriteJson")

	var j []byte

	j, err := json.Marshal(i)
	if err != nil {
		http.Error(w, "Error marshalling JSON", http.StatusInternalServerError)
		return err
	}

	// set Headers
	w.Header().Set("Content-Type", "application/json")
	// write to writer
	w.Write(j)
	return nil
}
<|endoftext|>


<commit_before>// Package juno implements the messaging spec of the Jupyter Messaging Protocol,
// just for you.
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
package juno

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"os"

	zmq "github.com/zeromq/goczmq"
)

// MessageHeader is a Jupyter message header
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
type MessageHeader struct {
	MessageID   string `json:"msg_id"`
	Username    string `json:"username"`
	Session     string `json:"session"`
	MessageType string `json:"msg_type"`
	Version     string `json:"version"`
}

// Message is a generic Jupyter message (not a wire message)
// http://jupyter-client.readthedocs.org/en/latest/messaging.html#general-message-format
type Message struct {
	Header       MessageHeader          `json:"header"`
	ParentHeader MessageHeader          `json:"parent_header"`
	Metadata     map[string]interface{} `json:"metadata"`
	Content      map[string]interface{} `json:"content"`
}

// MimeBundle is a collection of `mimetypes -> data`
// Example:
//     'text/html' -> '
Hey!
'
//     'image/png' -> 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
type MimeBundle map[string]string

// ConnectionInfo represents the runtime connection data used by Jupyter kernels
type ConnectionInfo struct {
	IOPubPort       int    `json:"iopub_port"`
	StdinPort       int    `json:"stdin_port"`
	IP              string `json:"ip"`
	Transport       string `json:"transport"`
	HBPort          int    `json:"hb_port"`
	SignatureScheme string `json:"signature_scheme"`
	ShellPort       int    `json:"shell_port"`
	ControlPort     int    `json:"control_port"`
	Key             string `json:"key"`
}

// DELIMITER denotes the Jupyter multipart message
const DELIMITER = "<IDS|MSG>"

// ParseWireProtocol fills a Message with all the juicy Jupyter bits
func (m *Message) ParseWireProtocol(wireMessage [][]byte, key []byte) (err error) {
	var i int
	var el []byte

	// Wire protocol
	// http://jupyter-client.readthedocs.org/en/latest/messaging.html#the-wire-protocol
	/**
		[
	  		b'u-u-i-d',         # zmq identity(ies)
	  		b'<IDS|MSG>',       # delimiter
	  		b'baddad42',        # HMAC signature
			b'{header}',        # serialized header dict
			b'{parent_header}', # serialized parent header dict
			b'{metadata}',      # serialized metadata dict
			b'{content}',       # serialized content dict
			b'blob',            # extra raw data buffer(s)
	  		...
		]
	*/
	// Determine where the delimiter is
	for i, el = range wireMessage {
		if string(el) == DELIMITER {
			break // Found our delimiter
		}
	}

	if i >= len(wireMessage) {
		return errors.New("Couldn't find delimeter")
	}

	// Extract the zmq identiti(es)
	//identities := wireMessage[:delimiterLocation]

	// If the message was signed
	if len(key) != 0 {
		// TODO: Programmatic selection of scheme
		mac := hmac.New(sha256.New, key)
		for _, msgpart := range wireMessage[i+2 : i+6] {
			mac.Write(msgpart)
		}
		signature := make([]byte, hex.DecodedLen(len(wireMessage[i+1])))
		hex.Decode(signature, wireMessage[i+1])
		if !hmac.Equal(mac.Sum(nil), signature) {
			return errors.New("Invalid signature")
		}
	}

	json.Unmarshal(wireMessage[i+2], &m.Header)
	json.Unmarshal(wireMessage[i+3], &m.ParentHeader)
	json.Unmarshal(wireMessage[i+4], &m.Metadata)
	json.Unmarshal(wireMessage[i+5], &m.Content)

	return nil
}

// NewConnectionInfo reads in a connection file and creates a ConnectionInfo
// struct
func NewConnectionInfo(filename string) (ConnectionInfo, error) {
	var connInfo ConnectionInfo
	connFile, err := os.Open(filename)

	if err != nil {
		return connInfo, fmt.Errorf("Couldn't open connection file: %v", err)
	}
	defer connFile.Close()

	jsonParser := json.NewDecoder(connFile)

	if err = jsonParser.Decode(&connInfo); err != nil {
		return connInfo, fmt.Errorf("Couldn't parse connection file: %v", err)
	}

	return connInfo, nil
}

// OpenConnectionFile wraps NewConnectionInfo for backwards compatiblity
func OpenConnectionFile(filename string) (ConnectionInfo, error) {
	return NewConnectionInfo(filename)
}

// JupyterSocket is a zmq.Socket coupled with connection information
type JupyterSocket struct {
	ZMQSocket *zmq.Sock
	ConnInfo  ConnectionInfo
}

// ReadMessage reads a Jupyter Protocol Message
func (s *JupyterSocket) ReadMessage() (Message, error) {
	var message Message
	wireMessage, err := s.ZMQSocket.RecvMessage()
	if err != nil {
		return message, fmt.Errorf("Error on receive: %v", err)
	}

	message.ParseWireProtocol(wireMessage, []byte(s.ConnInfo.Key))

	return message, nil
}

// NewMessage creates a new message from a wire message using the key from this
// socket's connection info
func (s *JupyterSocket) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	message.ParseWireProtocol(wireMessage, []byte(s.ConnInfo.Key))
	return message, nil
}

// Destroy obliterates zmq sockets
func (s *JupyterSocket) Destroy() {
	s.ZMQSocket.Destroy()
}

// NewIOPubSocket creates a new IOPub socket (on SUB) with the connInfo given
// subscribe is a comma delimited list of topics to subscribe to
func NewIOPubSocket(connInfo ConnectionInfo, subscribe string) (*JupyterSocket, error) {
	connectionString := connInfo.IOPubConnection()

	rawIOPubSocket, err := zmq.NewSub(connectionString, subscribe)
	if err != nil {
		return nil, err
	}

	iopub := &JupyterSocket{
		ZMQSocket: rawIOPubSocket,
		ConnInfo:  connInfo,
	}

	return iopub, nil
}

// ConnectionString forms the string for zmq libraries to connect
func (connInfo *ConnectionInfo) ConnectionString(port int) string {
	connectionString := fmt.Sprintf("%s://%s:%d",
		connInfo.Transport,
		connInfo.IP,
		port)
	return connectionString
}

// IOPubConnection forms the connection string for the IOPub socket
func (connInfo *ConnectionInfo) IOPubConnection() string {
	return connInfo.ConnectionString(connInfo.IOPubPort)
}
<commit_msg>Create messages relying only on conninfo<commit_after>// Package juno implements the messaging spec of the Jupyter Messaging Protocol,
// just for you.
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
package juno

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"os"

	zmq "github.com/zeromq/goczmq"
)

// MessageHeader is a Jupyter message header
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
type MessageHeader struct {
	MessageID   string `json:"msg_id"`
	Username    string `json:"username"`
	Session     string `json:"session"`
	MessageType string `json:"msg_type"`
	Version     string `json:"version"`
}

// Message is a generic Jupyter message (not a wire message)
// http://jupyter-client.readthedocs.org/en/latest/messaging.html#general-message-format
type Message struct {
	Header       MessageHeader          `json:"header"`
	ParentHeader MessageHeader          `json:"parent_header"`
	Metadata     map[string]interface{} `json:"metadata"`
	Content      map[string]interface{} `json:"content"`
}

// MimeBundle is a collection of `mimetypes -> data`
// Example:
//     'text/html' -> '
Hey!
'
//     'image/png' -> 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
type MimeBundle map[string]string

// ConnectionInfo represents the runtime connection data used by Jupyter kernels
type ConnectionInfo struct {
	IOPubPort       int    `json:"iopub_port"`
	StdinPort       int    `json:"stdin_port"`
	IP              string `json:"ip"`
	Transport       string `json:"transport"`
	HBPort          int    `json:"hb_port"`
	SignatureScheme string `json:"signature_scheme"`
	ShellPort       int    `json:"shell_port"`
	ControlPort     int    `json:"control_port"`
	Key             string `json:"key"`
}

// DELIMITER denotes the Jupyter multipart message
const DELIMITER = "<IDS|MSG>"

// ParseWireProtocol fills a Message with all the juicy Jupyter bits
func (m *Message) ParseWireProtocol(wireMessage [][]byte, key []byte) (err error) {
	var i int
	var el []byte

	// Wire protocol
	// http://jupyter-client.readthedocs.org/en/latest/messaging.html#the-wire-protocol
	/**
		[
	  		b'u-u-i-d',         # zmq identity(ies)
	  		b'<IDS|MSG>',       # delimiter
	  		b'baddad42',        # HMAC signature
			b'{header}',        # serialized header dict
			b'{parent_header}', # serialized parent header dict
			b'{metadata}',      # serialized metadata dict
			b'{content}',       # serialized content dict
			b'blob',            # extra raw data buffer(s)
	  		...
		]
	*/
	// Determine where the delimiter is
	for i, el = range wireMessage {
		if string(el) == DELIMITER {
			break // Found our delimiter
		}
	}

	if i >= len(wireMessage) {
		return errors.New("Couldn't find delimeter")
	}

	// Extract the zmq identiti(es)
	//identities := wireMessage[:delimiterLocation]

	// If the message was signed
	if len(key) != 0 {
		// TODO: Programmatic selection of scheme
		mac := hmac.New(sha256.New, key)
		for _, msgpart := range wireMessage[i+2 : i+6] {
			mac.Write(msgpart)
		}
		signature := make([]byte, hex.DecodedLen(len(wireMessage[i+1])))
		hex.Decode(signature, wireMessage[i+1])
		if !hmac.Equal(mac.Sum(nil), signature) {
			return errors.New("Invalid signature")
		}
	}

	json.Unmarshal(wireMessage[i+2], &m.Header)
	json.Unmarshal(wireMessage[i+3], &m.ParentHeader)
	json.Unmarshal(wireMessage[i+4], &m.Metadata)
	json.Unmarshal(wireMessage[i+5], &m.Content)

	return nil
}

// NewConnectionInfo reads in a connection file and creates a ConnectionInfo
// struct
func NewConnectionInfo(filename string) (ConnectionInfo, error) {
	var connInfo ConnectionInfo
	connFile, err := os.Open(filename)

	if err != nil {
		return connInfo, fmt.Errorf("Couldn't open connection file: %v", err)
	}
	defer connFile.Close()

	jsonParser := json.NewDecoder(connFile)

	if err = jsonParser.Decode(&connInfo); err != nil {
		return connInfo, fmt.Errorf("Couldn't parse connection file: %v", err)
	}

	return connInfo, nil
}

// OpenConnectionFile wraps NewConnectionInfo for backwards compatiblity
func OpenConnectionFile(filename string) (ConnectionInfo, error) {
	return NewConnectionInfo(filename)
}

// JupyterSocket is a zmq.Socket coupled with connection information
type JupyterSocket struct {
	ZMQSocket *zmq.Sock
	ConnInfo  ConnectionInfo
}

// ReadMessage reads a Jupyter Protocol Message
func (s *JupyterSocket) ReadMessage() (Message, error) {
	var message Message
	wireMessage, err := s.ZMQSocket.RecvMessage()
	if err != nil {
		return message, fmt.Errorf("Error on receive: %v", err)
	}

	message.ParseWireProtocol(wireMessage, []byte(s.ConnInfo.Key))

	return message, nil
}

// NewMessage creates a new message from a wire message using the key from this
// socket's connection info
func (s *JupyterSocket) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	message.ParseWireProtocol(wireMessage, []byte(s.ConnInfo.Key))
	return message, nil
}

// Destroy obliterates zmq sockets
func (s *JupyterSocket) Destroy() {
	s.ZMQSocket.Destroy()
}

// NewIOPubSocket creates a new IOPub socket (on SUB) with the connInfo given
// subscribe is a comma delimited list of topics to subscribe to
func NewIOPubSocket(connInfo ConnectionInfo, subscribe string) (*JupyterSocket, error) {
	connectionString := connInfo.IOPubConnection()

	rawIOPubSocket, err := zmq.NewSub(connectionString, subscribe)
	if err != nil {
		return nil, err
	}

	iopub := &JupyterSocket{
		ZMQSocket: rawIOPubSocket,
		ConnInfo:  connInfo,
	}

	return iopub, nil
}

// ConnectionString forms the string for zmq libraries to connect
func (connInfo *ConnectionInfo) ConnectionString(port int) string {
	connectionString := fmt.Sprintf("%s://%s:%d",
		connInfo.Transport,
		connInfo.IP,
		port)
	return connectionString
}

// IOPubConnection forms the connection string for the IOPub socket
func (connInfo *ConnectionInfo) IOPubConnection() string {
	return connInfo.ConnectionString(connInfo.IOPubPort)
}

// NewMessage creates a new message based on
func (connInfo *ConnectionInfo) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	err := message.ParseWireProtocol(wireMessage, []byte(connInfo.Key))
	return message, err
}
<|endoftext|>


<commit_before>package db

import (
	"database/sql"
	"encoding/json"
	"errors"
	"log"
	"os"
	"time"
	//driver for sqlite
	_ "github.com/mattn/go-sqlite3"
)

//SQLDB database
var SQLDB *sql.DB

//SQLPath path do db
var SQLPath string

//Query type
type Query struct {
	Key      int64     `json:"key"`
	Text     string    `json:"text"`
	Type     string    `json:"type"`
	Answer   string    `json:"answer"`
	List     []string  `json:"list"`
	Position int64     `json:"-"`
	Token    string    `json:"token"`
	Priority time.Time `json:"-"`
}

//Charge type
type Charge struct {
	ID    string `json:"charge"`
	Query int64  `json:"query"`
}

//InitDB init sql
func Init() {
	var err error
	var created = false
	//check for the sqlite file
	if _, err := os.Stat("./db.sqlite"); os.IsNotExist(err) {
		log.Println("Creating database file")
		_, err := os.Create("./db.sqlite")
		if err != nil {
			log.Fatal("Failed to create SQLite file")
		}
		created = true
	}
	//Prepare DB
	SQLPath = "./db.sqlite"
	SQLDB, err = sql.Open("sqlite3", SQLPath)
	if err != nil {
		log.Fatal(err)
		log.Fatal("Database setup failed.")
	}
	//create tables if necessary
	if created {
		CreateTables()
	}
	//load links
	initLinks()
}

//ResetDB remove existing database and recreate tables
func ResetDB() {
	//remove existing dataBasePath file
	os.Remove("./db.sqlite")
	Init()
}

//CreateTables create the user and posts tables
func CreateTables() {
	createTables := `
	CREATE TABLE queries (
		key integer primary key autoincrement,
		text varchar(255) not null,
		type varchar(20) not null,
		priority timestamp
	);
	CREATE TABLE resolved (
		key integer primary key not null,
		text varchar(255) not null,
		type varchar(20) not null,
		answer varchar(800) null,
		list varchar(2400) null
	);
	CREATE TABLE charges (
		key varchar(255) primary key
	);
	DELETE from queries;
  DELETE from resolved;
	DELETE from charges;
	`
	//Create the users table
	_, err := SQLDB.Exec(createTables)
	if err != nil {
		log.Println(err)
		log.Fatal("Unable to create database")
	}
	log.Println("Created SQL Tables")
}

//AddQuery add a new query to the db
func AddQuery(q Query) (int64, error) {
	//prepare the insert statement for adding a user
	insert, err := SQLDB.Prepare("INSERT into queries(text, type, priority) values(?, ?, ?)")
	if err != nil {
		return 0, errors.New("Error creating Query insert")
	}
	//insert
	result, err := insert.Exec(q.Text, q.Type, nil)
	if err != nil {
		return 0, errors.New("Failed to add Query")
	}
	//get ID to return
	id, err := result.LastInsertId()
	return id, nil
}

//GetQueue get the n top queries in the queue
func GetQueue(num int) ([]Query, error) {
	queries := []Query{}
	q := Query{}
	//create sql query
	rows, err := SQLDB.Query("SELECT key,text,type FROM queries ORDER BY datetime(priority) DESC LIMIT (?)", num)
	defer rows.Close() //close query connection when function returns
	if err != nil {
		return queries, errors.New("Error getting queue")
	}
	for rows.Next() {
		err = rows.Scan(&q.Key, &q.Text, &q.Type)
		if err != nil {
			return queries, errors.New("Error scanning row")
		}
		queries = append(queries, q)
	}

	return queries, nil
}

//AnswerQuery move a query to the resolved table with jimmy's answer
func AnswerQuery(key int64, answer string, list string) error {
	q := Query{}

	tx, err := SQLDB.Begin() //start transaction
	if err != nil {
		return errors.New("Could not establish transaction")
	}
	//get the query
	err = tx.QueryRow("SELECT text,type FROM queries WHERE key=(?)", key).Scan(&q.Text, &q.Type)
	if err != nil {
		tx.Rollback()
		return errors.New("Could not find query")
	}
	//add to resolved
	insert, err := tx.Prepare("INSERT into resolved(key, text, type, answer, list) values(?, ?, ?, ?, ?)")
	if err != nil {
		tx.Rollback()
		return errors.New("Error creating Resolved insert")
	}
	_, err = insert.Exec(key, q.Text, q.Type, answer, list)
	if err != nil {
		tx.Rollback()
		return errors.New("Failed to add to resolved")
	}
	//delete from queries
	delete, err := tx.Prepare("DELETE from queries WHERE key=(?)")
	_, err = delete.Exec(key)
	if err != nil {
		tx.Rollback()
		return errors.New("Failed to delete query")
	}
	tx.Commit()
	return nil
}

//AddCharge adds a charge to the database and errors if charge exists
func AddCharge(key string) error {
	var c Charge
	err := SQLDB.QueryRow("SELECT key FROM charges WHERE key=?", key, 1).Scan(&c.ID)

	if err == nil {
		return errors.New("Charge already exists")
	}

	insert, err := SQLDB.Prepare("INSERT into charges(key) values(?)")
	if err != nil {
		return errors.New("Error creating Charge insert")
	}
	//insert
	_, err = insert.Exec(key)
	if err != nil {
		return errors.New("Failed to add Charge")
	}

	return nil
}

//MoveToFront moves a query to the front of the queue
func MoveToFront(key int64) error {
	update, err := SQLDB.Prepare("UPDATE queries SET priority=? WHERE key=?")
	if err != nil {
		return err
	}

	timestamp := time.Now()
	_, err = update.Exec(timestamp, key)
	log.Println("A user has paid.")

	if err != nil {
		return errors.New("Failed to move query to the pront of the queue")
	}

	return nil
}

//getQueuePosition return the queue position of a query
func getQueuePosition(key int64) (int64, error) {
	var err error
	var count int64
	var priority sql.NullString

	SQLDB.QueryRow("SELECT priority FROM queries WHERE key = (?)", key).Scan(&priority)

	if priority.Valid {
		// This is a paid query and can be compared as such
		err = SQLDB.QueryRow("SELECT COUNT(1) FROM queries WHERE datetime(priority) > datetime((?))", priority).Scan(&count)
	} else {
		// This is an unpaid query and need to be
		err = SQLDB.QueryRow("SELECT COUNT(1) FROM queries WHERE priority IS NOT NULL OR key < (?)", key).Scan(&count)
	}

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

	return count, nil
}

//CheckQuery see if a query is resolved and return the answer
func CheckQuery(key int64) (Query, error) {
	var list string
	q := Query{}
	//select from resolved
	err := SQLDB.QueryRow("SELECT * FROM resolved WHERE key=(?)", key).Scan(&q.Key, &q.Text, &q.Type, &q.Answer, &list)
	if err != nil {
		//get position
		q.Position, err = getQueuePosition(key)
		if err != nil {
			//we did not get the position
			return q, errors.New("Error getting queue position")
		}
		return q, errors.New("Query is not resolved")
	}
	//convert list to actual list
	err = json.Unmarshal([]byte(list), &q.List)
	if err != nil {
		q.List = nil
	}
	return q, nil
}

//GetRecent get the recently resolved posts
func GetRecent(num int) ([]Query, error) {
	var list string
	resolved := []Query{}
	r := Query{}
	//create sql query
	rows, err := SQLDB.Query("SELECT key,text,type,answer,list FROM resolved ORDER BY key DESC LIMIT (?)", num)
	defer rows.Close() //close query connection when function returns
	if err != nil {
		return resolved, errors.New("Error getting recently resolved")
	}
	for rows.Next() {
		r = Query{}
		err = rows.Scan(&r.Key, &r.Text, &r.Type, &r.Answer, &list)
		if err != nil {
			return resolved, errors.New("Error scanning row")
		}
		//convert list to actual list
		err = json.Unmarshal([]byte(list), &r.List)
		if err != nil {
			r.List = nil
		}
		resolved = append(resolved, r)
	}

	return resolved, nil
}

//GetQuestion get a question by query id
func GetQuestion(key int64) (Query, error) {
	q := Query{}
	//get the query
	err := SQLDB.QueryRow("SELECT key,text,type FROM queries WHERE key=(?)", key).Scan(&q.Key, &q.Text, &q.Type)
	if err != nil {
		//not found in queries table so check resolved table
		err := SQLDB.QueryRow("SELECT key,text,type FROM resolved WHERE key=(?)", key).Scan(&q.Key, &q.Text, &q.Type)
		if err != nil {
			//the query is not in either table
			return q, errors.New("Could not find question")
		}
	}
	return q, nil
}
<commit_msg>Add 'paid' flag to /queue response<commit_after>package db

import (
	"database/sql"
	"encoding/json"
	"errors"
	"log"
	"os"
	"time"
	//driver for sqlite
	_ "github.com/mattn/go-sqlite3"
)

//SQLDB database
var SQLDB *sql.DB

//SQLPath path do db
var SQLPath string

//Query type
type Query struct {
	Key      int64     `json:"key"`
	Text     string    `json:"text"`
	Type     string    `json:"type"`
	Answer   string    `json:"answer"`
	List     []string  `json:"list"`
	Position int64     `json:"-"`
	Token    string    `json:"token"`
	Priority time.Time `json:"-"`
	Paid     bool      `json:"paid"`
}

//Charge type
type Charge struct {
	ID    string `json:"charge"`
	Query int64  `json:"query"`
}

//InitDB init sql
func Init() {
	var err error
	var created = false
	//check for the sqlite file
	if _, err := os.Stat("./db.sqlite"); os.IsNotExist(err) {
		log.Println("Creating database file")
		_, err := os.Create("./db.sqlite")
		if err != nil {
			log.Fatal("Failed to create SQLite file")
		}
		created = true
	}
	//Prepare DB
	SQLPath = "./db.sqlite"
	SQLDB, err = sql.Open("sqlite3", SQLPath)
	if err != nil {
		log.Fatal(err)
		log.Fatal("Database setup failed.")
	}
	//create tables if necessary
	if created {
		CreateTables()
	}
	//load links
	initLinks()
}

//ResetDB remove existing database and recreate tables
func ResetDB() {
	//remove existing dataBasePath file
	os.Remove("./db.sqlite")
	Init()
}

//CreateTables create the user and posts tables
func CreateTables() {
	createTables := `
	CREATE TABLE queries (
		key integer primary key autoincrement,
		text varchar(255) not null,
		type varchar(20) not null,
		priority timestamp
	);
	CREATE TABLE resolved (
		key integer primary key not null,
		text varchar(255) not null,
		type varchar(20) not null,
		answer varchar(800) null,
		list varchar(2400) null
	);
	CREATE TABLE charges (
		key varchar(255) primary key
	);
	DELETE from queries;
  DELETE from resolved;
	DELETE from charges;
	`
	//Create the users table
	_, err := SQLDB.Exec(createTables)
	if err != nil {
		log.Println(err)
		log.Fatal("Unable to create database")
	}
	log.Println("Created SQL Tables")
}

//AddQuery add a new query to the db
func AddQuery(q Query) (int64, error) {
	//prepare the insert statement for adding a user
	insert, err := SQLDB.Prepare("INSERT into queries(text, type, priority) values(?, ?, ?)")
	if err != nil {
		return 0, errors.New("Error creating Query insert")
	}
	//insert
	result, err := insert.Exec(q.Text, q.Type, nil)
	if err != nil {
		return 0, errors.New("Failed to add Query")
	}
	//get ID to return
	id, err := result.LastInsertId()
	return id, nil
}

//GetQueue get the n top queries in the queue
func GetQueue(num int) ([]Query, error) {
	queries := []Query{}
	q := Query{}
	var priority sql.NullString
	//create sql query
	rows, err := SQLDB.Query("SELECT key,text,type,priority FROM queries ORDER BY datetime(priority) DESC LIMIT (?)", num)
	defer rows.Close() //close query connection when function returns
	if err != nil {
		return queries, errors.New("Error getting queue")
	}
	for rows.Next() {
		q = Query{}
		err = rows.Scan(&q.Key, &q.Text, &q.Type, &priority)
		if err != nil {
			return queries, errors.New("Error scanning row")
		}
		// set the priority timestamp if the user has paid
		if priority.Valid {
			q.Paid = true
		}
		queries = append(queries, q)
	}

	return queries, nil
}

//AnswerQuery move a query to the resolved table with jimmy's answer
func AnswerQuery(key int64, answer string, list string) error {
	q := Query{}

	tx, err := SQLDB.Begin() //start transaction
	if err != nil {
		return errors.New("Could not establish transaction")
	}
	//get the query
	err = tx.QueryRow("SELECT text,type FROM queries WHERE key=(?)", key).Scan(&q.Text, &q.Type)
	if err != nil {
		tx.Rollback()
		return errors.New("Could not find query")
	}
	//add to resolved
	insert, err := tx.Prepare("INSERT into resolved(key, text, type, answer, list) values(?, ?, ?, ?, ?)")
	if err != nil {
		tx.Rollback()
		return errors.New("Error creating Resolved insert")
	}
	_, err = insert.Exec(key, q.Text, q.Type, answer, list)
	if err != nil {
		tx.Rollback()
		return errors.New("Failed to add to resolved")
	}
	//delete from queries
	delete, err := tx.Prepare("DELETE from queries WHERE key=(?)")
	_, err = delete.Exec(key)
	if err != nil {
		tx.Rollback()
		return errors.New("Failed to delete query")
	}
	tx.Commit()
	return nil
}

//AddCharge adds a charge to the database and errors if charge exists
func AddCharge(key string) error {
	var c Charge
	err := SQLDB.QueryRow("SELECT key FROM charges WHERE key=?", key, 1).Scan(&c.ID)

	if err == nil {
		return errors.New("Charge already exists")
	}

	insert, err := SQLDB.Prepare("INSERT into charges(key) values(?)")
	if err != nil {
		return errors.New("Error creating Charge insert")
	}
	//insert
	_, err = insert.Exec(key)
	if err != nil {
		return errors.New("Failed to add Charge")
	}

	return nil
}

//MoveToFront moves a query to the front of the queue
func MoveToFront(key int64) error {
	update, err := SQLDB.Prepare("UPDATE queries SET priority=? WHERE key=?")
	if err != nil {
		return err
	}

	timestamp := time.Now()
	_, err = update.Exec(timestamp, key)
	log.Println("A user has paid.")

	if err != nil {
		return errors.New("Failed to move query to the pront of the queue")
	}

	return nil
}

//getQueuePosition return the queue position of a query
func getQueuePosition(key int64) (int64, error) {
	var err error
	var count int64
	var priority sql.NullString

	SQLDB.QueryRow("SELECT priority FROM queries WHERE key = (?)", key).Scan(&priority)

	if priority.Valid {
		// This is a paid query and can be compared as such
		err = SQLDB.QueryRow("SELECT COUNT(1) FROM queries WHERE datetime(priority) > datetime((?))", priority).Scan(&count)
	} else {
		// This is an unpaid query and need to be
		err = SQLDB.QueryRow("SELECT COUNT(1) FROM queries WHERE priority IS NOT NULL OR key < (?)", key).Scan(&count)
	}

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

	return count, nil
}

//CheckQuery see if a query is resolved and return the answer
func CheckQuery(key int64) (Query, error) {
	var list string
	q := Query{}
	//select from resolved
	err := SQLDB.QueryRow("SELECT * FROM resolved WHERE key=(?)", key).Scan(&q.Key, &q.Text, &q.Type, &q.Answer, &list)
	if err != nil {
		//get position
		q.Position, err = getQueuePosition(key)
		if err != nil {
			//we did not get the position
			return q, errors.New("Error getting queue position")
		}
		return q, errors.New("Query is not resolved")
	}
	//convert list to actual list
	err = json.Unmarshal([]byte(list), &q.List)
	if err != nil {
		q.List = nil
	}
	return q, nil
}

//GetRecent get the recently resolved posts
func GetRecent(num int) ([]Query, error) {
	var list string
	resolved := []Query{}
	r := Query{}
	//create sql query
	rows, err := SQLDB.Query("SELECT key,text,type,answer,list FROM resolved ORDER BY key DESC LIMIT (?)", num)
	defer rows.Close() //close query connection when function returns
	if err != nil {
		return resolved, errors.New("Error getting recently resolved")
	}
	for rows.Next() {
		r = Query{}
		err = rows.Scan(&r.Key, &r.Text, &r.Type, &r.Answer, &list)
		if err != nil {
			return resolved, errors.New("Error scanning row")
		}
		//convert list to actual list
		err = json.Unmarshal([]byte(list), &r.List)
		if err != nil {
			r.List = nil
		}
		resolved = append(resolved, r)
	}

	return resolved, nil
}

//GetQuestion get a question by query id
func GetQuestion(key int64) (Query, error) {
	q := Query{}
	//get the query
	err := SQLDB.QueryRow("SELECT key,text,type FROM queries WHERE key=(?)", key).Scan(&q.Key, &q.Text, &q.Type)
	if err != nil {
		//not found in queries table so check resolved table
		err := SQLDB.QueryRow("SELECT key,text,type FROM resolved WHERE key=(?)", key).Scan(&q.Key, &q.Text, &q.Type)
		if err != nil {
			//the query is not in either table
			return q, errors.New("Could not find question")
		}
	}
	return q, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Geofrey Ernest <geofreyernest@live.com>. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

/*
Package kemi helps you win at unpacking archive files. Kemi supports .tar, .tar.gz
.zip out of the box, with option to extend and add more support with your own or your
neighbor's  implementations.
*/
package kemi

import (
	"errors"
	"io"
	"os"
	"path/filepath"
	"strings"
)

var registeredUnpackers = map[string]Unpacker{
	"tar": &Tar{},
	"gz":  &Gz{},
	"zip": &Zip{},
}

var (
	directoryPerm os.FileMode = 0755

	// ErrNotSupported is the error used for files whose unpackers are not registered
	ErrNotSupported = errors.New("kemi: File not supported")
)

// Unpacker is an interface that wraps methods for initializing Copier implementations.
type Unpacker interface {

	// Support returns the file extension supported
	// by this unpacker without the  dot  e.g tar
	Support() string

	// Open  psses the archive filepath as a string
	Open(string) (Copier, error)

	// uses the io.Reader to return the Copier
	OpenFromReader(io.Reader) Copier
}

// Copier is the interface that wraps methods for copying extracted archive files.
type Copier interface {

	// CopyTo copies the unpacked archive to dest, it depends on what
	CopyTo(dest string) error

	// Reader returns an io.Reader that can be used by other unpackers.
	Reader() io.Reader

	// Close closes the underlying reader. It is up to the implementation to make sure
	// when reading is done to close the reader.
	Close()
}

// Unpack unpacks contents of src into dest. Where src if the path to an archive file.
func Unpack(src, dest string) error {
	unPackers, err := listUnpackers(src)
	if err != nil {
		return err
	}
	var copier Copier

	for k, v := range unPackers {
		if k == 0 {
			cp, err := v.Open(src)
			if err != nil {
				return err
			}
			copier = cp
		}
		copier = v.OpenFromReader(copier.Reader())
	}
	defer copier.Close()
	err = copier.CopyTo(dest)
	if err != nil {
		return err
	}
	return nil
}

// Optain the list of packers by observing the file extensions.
// this means, .tar.gz will have a gz and tar unpackers in the order.
func listUnpackers(src string) (rst []Unpacker, err error) {
	base := filepath.Base(src)
	c := strings.Split(base, ".")
	cLen := len(c)
	switch {
	case cLen == 2:
		outer, ok := registeredUnpackers[c[cLen-1]]
		if !ok {
			err = ErrNotSupported
			return
		}
		rst = append(rst, outer)
	case cLen > 2:
		outer, ok := registeredUnpackers[c[cLen-1]]
		if !ok {
			err = ErrNotSupported
			return
		}
		rst = append(rst, outer)
		if len(c[cLen-2]) <= 3 {
			inner, ok := registeredUnpackers[c[cLen-2]]
			if !ok {
				err = ErrNotSupported
				return
			}
			rst = append(rst, inner)
		}
	}
	return
}

// Creates a new file name, and copies what is read from data.
func writeFile(name string, data io.Reader, perm os.FileMode) error {
	out, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	defer out.Close()
	if _, cerr := io.Copy(out, data); cerr != nil {
		return cerr
	}
	return nil
}

//Register registers u as  Unpacker for whatever format u supports.
func Register(u Unpacker) {
	registeredUnpackers[u.Support()] = u
}
<commit_msg>Ignore if not more than one  unpacker is found<commit_after>// Copyright 2015 Geofrey Ernest <geofreyernest@live.com>. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

/*
Package kemi helps you win at unpacking archive files. Kemi supports .tar, .tar.gz
.zip out of the box, with option to extend and add more support with your own or your
neighbor's  implementations.
*/
package kemi

import (
	"errors"
	"io"
	"os"
	"path/filepath"
	"strings"
)

var registeredUnpackers = map[string]Unpacker{
	"tar": &Tar{},
	"gz":  &Gz{},
	"zip": &Zip{},
}

var (
	directoryPerm os.FileMode = 0755

	// ErrNotSupported is the error used for files whose unpackers are not registered
	ErrNotSupported = errors.New("kemi: File not supported")
)

// Unpacker is an interface that wraps methods for initializing Copier implementations.
type Unpacker interface {

	// Support returns the file extension supported
	// by this unpacker without the  dot  e.g tar
	Support() string

	// Open  psses the archive filepath as a string
	Open(string) (Copier, error)

	// uses the io.Reader to return the Copier
	OpenFromReader(io.Reader) Copier
}

// Copier is the interface that wraps methods for copying extracted archive files.
type Copier interface {

	// CopyTo copies the unpacked archive to dest, it depends on what
	CopyTo(dest string) error

	// Reader returns an io.Reader that can be used by other unpackers.
	Reader() io.Reader

	// Close closes the underlying reader. It is up to the implementation to make sure
	// when reading is done to close the reader.
	Close()
}

// Unpack unpacks contents of src into dest. Where src if the path to an archive file.
func Unpack(src, dest string) error {
	unPackers, err := listUnpackers(src)
	if err != nil {
		return err
	}
	var copier Copier

	for k, v := range unPackers {
		if k == 0 {
			cp, err := v.Open(src)
			if err != nil {
				return err
			}
			copier = cp
		}
		copier = v.OpenFromReader(copier.Reader())
	}
	defer copier.Close()
	err = copier.CopyTo(dest)
	if err != nil {
		return err
	}
	return nil
}

// Optain the list of packers by observing the file extensions.
// this means, .tar.gz will have a gz and tar unpackers in the order.
func listUnpackers(src string) (rst []Unpacker, err error) {
	base := filepath.Base(src)
	c := strings.Split(base, ".")
	cLen := len(c)
	switch {
	case cLen == 2:
		outer, ok := registeredUnpackers[c[cLen-1]]
		if !ok {
			err = ErrNotSupported
			return
		}
		rst = append(rst, outer)
	case cLen > 2:
		outer, ok := registeredUnpackers[c[cLen-1]]
		if !ok {
			err = ErrNotSupported
			return
		}
		rst = append(rst, outer)
		if len(c[cLen-2]) <= 3 {
			inner, ok := registeredUnpackers[c[cLen-2]]
			if !ok {
				//err = ErrNotSupported
				return
			}
			rst = append(rst, inner)
		}
	}
	return
}

// Creates a new file name, and copies what is read from data.
func writeFile(name string, data io.Reader, perm os.FileMode) error {
	out, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	defer out.Close()
	if _, cerr := io.Copy(out, data); cerr != nil {
		return cerr
	}
	return nil
}

//Register registers u as  Unpacker for whatever format u supports.
func Register(u Unpacker) {
	registeredUnpackers[u.Support()] = u
}
<|endoftext|>


<commit_before>// File: ./blockfreight/lib/bft.go
// Summary: Application code for Blockfreight™ | The blockchain of global freight.
// License: MIT License
// Company: Blockfreight, Inc.
// Author: Julian Nunez, Neil Tran, Julian Smith, Gian Felipe & contributors
// Site: https://blockfreight.com
// Support: <support@blockfreight.com>

// Copyright © 2017 Blockfreight, Inc. All Rights Reserved.

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// =================================================================================================================================================
// =================================================================================================================================================
//
// BBBBBBBBBBBb     lll                                kkk             ffff                         iii                  hhh            ttt
// BBBB``````BBBB   lll                                kkk            fff                           ```                  hhh            ttt
// BBBB      BBBB   lll      oooooo        ccccccc     kkk    kkkk  fffffff  rrr  rrr    eeeee      iii     gggggg ggg   hhh  hhhhh   tttttttt
// BBBBBBBBBBBB     lll    ooo    oooo    ccc    ccc   kkk   kkk    fffffff  rrrrrrrr eee    eeee   iii   gggg   ggggg   hhhh   hhhh  tttttttt
// BBBBBBBBBBBBBB   lll   ooo      ooo   ccc           kkkkkkk        fff    rrrr    eeeeeeeeeeeee  iii  gggg      ggg   hhh     hhh    ttt
// BBBB       BBB   lll   ooo      ooo   ccc           kkkk kkkk      fff    rrr     eeeeeeeeeeeee  iii   ggg      ggg   hhh     hhh    ttt
// BBBB      BBBB   lll   oooo    oooo   cccc    ccc   kkk   kkkk     fff    rrr      eee      eee  iii    ggg    gggg   hhh     hhh    tttt    ....
// BBBBBBBBBBBBB    lll     oooooooo       ccccccc     kkk     kkkk   fff    rrr       eeeeeeeee    iii     gggggg ggg   hhh     hhh     ttttt  ....
//                                                                                ggg      ggg
//   Blockfreight™ | The blockchain of global freight.                                                      ggggggggg
//
// =================================================================================================================================================
// =================================================================================================================================================

// Package bft implements the main functions to work with the Blockfreight™ Network.
package bft

import (
	// =======================
	// Golang Standard library
	// =======================
	// Implements simple functions to manipulate UTF-8 encoded strings.

	// ===============
	// Tendermint Core
	// ===============

	"bytes"

	"github.com/tendermint/abci/types"
	tendermint "github.com/tendermint/go-common"
	wire "github.com/tendermint/go-wire"
	"github.com/tendermint/iavl"
	dbm "github.com/tendermint/tmlibs/db"
)

// BftApplication struct
type BftApplication struct {
	types.BaseApplication

	state *iavl.VersionedTree
}

// NewBftApplication creates a new application
func NewBftApplication() *BftApplication {
	state := iavl.NewVersionedTree(0, dbm.NewMemDB())
	return &BftApplication{state: state}
}

// Info returns information
func (app *BftApplication) Info() (resInfo types.ResponseInfo) {
	return types.ResponseInfo{Data: tendermint.Fmt("{\"size\":%v}", app.state.Size()), LastBlockAppHash: app.state.Hash(), LastBlockHeight: uint64(app.state.Height())}
}

// DeliverTx delivers transactions.Transactions are either "key=value" or just arbitrary bytes
func (app *BftApplication) DeliverTx(tx []byte) types.Result {
	var key, value []byte
	parts := bytes.Split(tx, []byte("="))
	if len(parts) == 2 {
		key, value = parts[0], parts[1]
	} else {
		key, value = tx, tx
	}
	app.state.Set(key, value)

	return types.NewResult(0, []byte(""), "")
}

// CheckTx checks a transaction
func (app *BftApplication) CheckTx(tx []byte) types.Result {
	return app.CheckTx(tx)
}

// Commit commits transactions
func (app *BftApplication) Commit() types.Result {
	// Save a new version
	var hash []byte
	var err error

	if app.state.Size() > 0 {
		// just add one more to height (kind of arbitrarily stupid)
		height := app.state.LatestVersion() + 1
		hash, err = app.state.SaveVersion(height)
		if err != nil {
			// if this wasn't a dummy app, we'd do something smarter
			panic(err)
		}
	}

	return types.NewResult(0, hash, "")
}

func (app *BftApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
	if reqQuery.Prove {
		value, proof, err := app.state.GetWithProof(reqQuery.Data)
		// if this wasn't a dummy app, we'd do something smarter
		if err != nil {
			panic(err)
		}
		resQuery.Index = -1 // TODO make Proof return index
		resQuery.Key = reqQuery.Data
		resQuery.Value = value
		resQuery.Proof = wire.BinaryBytes(proof)
		if value != nil {
			resQuery.Log = "exists"
		} else {
			resQuery.Log = "does not exist"
		}
		return
	} else {
		index, value := app.state.Get(reqQuery.Data)
		resQuery.Index = int64(index)
		resQuery.Value = value
		if value != nil {
			resQuery.Log = "exists"
		} else {
			resQuery.Log = "does not exist"
		}
		return
	}
}

// =================================================
// Blockfreight™ | The blockchain of global freight.
// =================================================

// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBB                    BBBBBBBBBBBBBBBBBBB
// BBBBBBB                       BBBBBBBBBBBBBBBB
// BBBBBBB                        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBB        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBB        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBB         BBBBBBBBBBBBBBBB
// BBBBBBB                     BBBBBBBBBBBBBBBBBB
// BBBBBBB                        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBBB        BBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBBBB       BBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBBB        BBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBB        BBB       BBBBB
// BBBBBBB                       BBBB       BBBBB
// BBBBBBB                    BBBBBBB       BBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

// ==================================================
// Blockfreight™ | The blockchain for global freight.
// ==================================================
<commit_msg>Changing Info function<commit_after>// File: ./blockfreight/lib/bft.go
// Summary: Application code for Blockfreight™ | The blockchain of global freight.
// License: MIT License
// Company: Blockfreight, Inc.
// Author: Julian Nunez, Neil Tran, Julian Smith, Gian Felipe & contributors
// Site: https://blockfreight.com
// Support: <support@blockfreight.com>

// Copyright © 2017 Blockfreight, Inc. All Rights Reserved.

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// =================================================================================================================================================
// =================================================================================================================================================
//
// BBBBBBBBBBBb     lll                                kkk             ffff                         iii                  hhh            ttt
// BBBB``````BBBB   lll                                kkk            fff                           ```                  hhh            ttt
// BBBB      BBBB   lll      oooooo        ccccccc     kkk    kkkk  fffffff  rrr  rrr    eeeee      iii     gggggg ggg   hhh  hhhhh   tttttttt
// BBBBBBBBBBBB     lll    ooo    oooo    ccc    ccc   kkk   kkk    fffffff  rrrrrrrr eee    eeee   iii   gggg   ggggg   hhhh   hhhh  tttttttt
// BBBBBBBBBBBBBB   lll   ooo      ooo   ccc           kkkkkkk        fff    rrrr    eeeeeeeeeeeee  iii  gggg      ggg   hhh     hhh    ttt
// BBBB       BBB   lll   ooo      ooo   ccc           kkkk kkkk      fff    rrr     eeeeeeeeeeeee  iii   ggg      ggg   hhh     hhh    ttt
// BBBB      BBBB   lll   oooo    oooo   cccc    ccc   kkk   kkkk     fff    rrr      eee      eee  iii    ggg    gggg   hhh     hhh    tttt    ....
// BBBBBBBBBBBBB    lll     oooooooo       ccccccc     kkk     kkkk   fff    rrr       eeeeeeeee    iii     gggggg ggg   hhh     hhh     ttttt  ....
//                                                                                ggg      ggg
//   Blockfreight™ | The blockchain of global freight.                                                      ggggggggg
//
// =================================================================================================================================================
// =================================================================================================================================================

// Package bft implements the main functions to work with the Blockfreight™ Network.
package bft

import (
	// =======================
	// Golang Standard library
	// =======================
	// Implements simple functions to manipulate UTF-8 encoded strings.

	// ===============
	// Tendermint Core
	// ===============

	"bytes"

	"github.com/tendermint/abci/types"
	tendermint "github.com/tendermint/go-common"
	wire "github.com/tendermint/go-wire"
	"github.com/tendermint/iavl"
	dbm "github.com/tendermint/tmlibs/db"
)

// BftApplication struct
type BftApplication struct {
	types.BaseApplication

	state *iavl.VersionedTree
}

// NewBftApplication creates a new application
func NewBftApplication() *BftApplication {
	state := iavl.NewVersionedTree(0, dbm.NewMemDB())
	return &BftApplication{state: state}
}

// Info returns information
func (app *BftApplication) Info() (resInfo types.ResponseInfo) {
	return types.ResponseInfo{Data: tendermint.Fmt("{\"size\":%v}", app.state.Size())}
}

// DeliverTx delivers transactions.Transactions are either "key=value" or just arbitrary bytes
func (app *BftApplication) DeliverTx(tx []byte) types.Result {
	var key, value []byte
	parts := bytes.Split(tx, []byte("="))
	if len(parts) == 2 {
		key, value = parts[0], parts[1]
	} else {
		key, value = tx, tx
	}
	app.state.Set(key, value)

	return types.NewResult(0, []byte(""), "")
}

// CheckTx checks a transaction
func (app *BftApplication) CheckTx(tx []byte) types.Result {
	return app.CheckTx(tx)
}

// Commit commits transactions
func (app *BftApplication) Commit() types.Result {
	// Save a new version
	var hash []byte
	var err error

	if app.state.Size() > 0 {
		// just add one more to height (kind of arbitrarily stupid)
		height := app.state.LatestVersion() + 1
		hash, err = app.state.SaveVersion(height)
		if err != nil {
			// if this wasn't a dummy app, we'd do something smarter
			panic(err)
		}
	}

	return types.NewResult(0, hash, "")
}

func (app *BftApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
	if reqQuery.Prove {
		value, proof, err := app.state.GetWithProof(reqQuery.Data)
		// if this wasn't a dummy app, we'd do something smarter
		if err != nil {
			panic(err)
		}
		resQuery.Index = -1 // TODO make Proof return index
		resQuery.Key = reqQuery.Data
		resQuery.Value = value
		resQuery.Proof = wire.BinaryBytes(proof)
		if value != nil {
			resQuery.Log = "exists"
		} else {
			resQuery.Log = "does not exist"
		}
		return
	} else {
		index, value := app.state.Get(reqQuery.Data)
		resQuery.Index = int64(index)
		resQuery.Value = value
		if value != nil {
			resQuery.Log = "exists"
		} else {
			resQuery.Log = "does not exist"
		}
		return
	}
}

// =================================================
// Blockfreight™ | The blockchain of global freight.
// =================================================

// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBB                    BBBBBBBBBBBBBBBBBBB
// BBBBBBB                       BBBBBBBBBBBBBBBB
// BBBBBBB                        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBB        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBB        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBB         BBBBBBBBBBBBBBBB
// BBBBBBB                     BBBBBBBBBBBBBBBBBB
// BBBBBBB                        BBBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBBB        BBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBBBB       BBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBBB        BBBBBBBBBBBBBB
// BBBBBBB       BBBBBBBBB        BBB       BBBBB
// BBBBBBB                       BBBB       BBBBB
// BBBBBBB                    BBBBBBB       BBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

// ==================================================
// Blockfreight™ | The blockchain for global freight.
// ==================================================
<|endoftext|>


<commit_before>// Package db handles new connections and transactions with timeouts.
//
// Timeouts that can be defined:
//    Connect timeout         - sets the maximum wait for creating a new connection
//    Statement timeout       - sets the maximum wait for queries completion
//    New transaction timeout - sets the maximum wait for opening a new transaction
//
// This feature is useful when the servers must be kept up, even though your database servers are
// not stable. So the database clients can respond their users with kindly error messages or look
// for other database servers - fail fast is usually better than keep server resources busy.
package db

import (
	"database/sql"
	"errors"
	"fmt"
	"time"
)

// ErrNewTxTimedOut returned when takes too long to retrieve a transaction from the database server.
var ErrNewTxTimedOut = errors.New("new transaction timed out")

// PostgresDriver holds the postgres driver name. You should import the driver somewhere in your
// code. The default value for PostgresDriver was get from https://github.com/lib/pq. This driver
// isn't directly imported here to don't stick this library with only one type of Postgres driver,
// and to make it more flexible for testing.
//
//     import (
//       _ "github.com/lib/pq"
//     )
var PostgresDriver = "postgres"

// ConnParams is all the data needed to create a new connection with database.
// If you are looking for default values see NewConnParams() function that set
// defaults values to Data structure.
type ConnParams struct {
	Username     string
	Password     string
	DatabaseName string
	Host         string

	// ConnectTimeout is the timeout utilized to creating a new connection with database. It is not
	// recommended to use a timeout of less than 2 seconds.
	ConnectTimeout time.Duration
	// StatementTimeout is the timeout utilized to invalidate queries that last more than the
	// configured timeout.
	StatementTimeout time.Duration

	MaxIdleConnections int
	MaxOpenConnections int
}

// NewConnParams returns the database connection parameters with some default
// values.
func NewConnParams() ConnParams {
	return ConnParams{
		Host:               "127.0.0.1",
		ConnectTimeout:     3 * time.Second,
		StatementTimeout:   10 * time.Second,
		MaxIdleConnections: 16,
		MaxOpenConnections: 32,
	}
}

// ConnectPostgres connects to a postgres database using the values from d. In case of a successfully
// connection it returns a sql.DB and a nil error. In case of problem it returns a nil sql.DB and an
// error from sql.Open (standard library, see https://golang.org/pkg/database/sql/#Open)
func ConnectPostgres(d ConnParams) (db *sql.DB, err error) {
	// connect_timeout
	//
	// https://www.postgresql.org/docs/9.6/static/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT
	// Maximum wait for connection, in seconds (write as a decimal integer string). Zero or not
	// specified means wait indefinitely. It is not recommended to use a timeout of less than 2
	// seconds.
	//
	// statement_timeout
	//
	// https://www.postgresql.org/docs/9.6/static/runtime-config-client.html#GUC-STATEMENT-TIMEOUT
	// Abort any statement that takes more than the specified number of milliseconds, starting from
	// the time the command arrives at the server from the client.
	connParams := fmt.Sprintf(
		"user=%s password=%s dbname=%s sslmode=disable host=%s connect_timeout=%d statement_timeout=%d",
		d.Username,
		d.Password,
		d.DatabaseName,
		d.Host,
		int(d.ConnectTimeout.Seconds()),
		int(d.StatementTimeout.Seconds()*1000),
	)

	if db, err = sql.Open(PostgresDriver, connParams); err != nil {
		return nil, err
	}

	db.SetMaxIdleConns(d.MaxIdleConnections)
	db.SetMaxOpenConns(d.MaxOpenConnections)
	return
}

// NewTx starts a new database transaction with a timeout. Starting a new transaction is not
// supposed to last too long, so a timeout of more than 3 seconds it's usually not necessary.
func NewTx(db *sql.DB, timeout time.Duration) (*sql.Tx, error) {
	// The channels has size of 1 (buffered) to avoid keeping an unnecessary goroutine blocked in
	// memory. For example: a goroutine is spawn, and it returns via channel a new transaction or
	// an error. After spawning a goroutine the program blocks in the select statement waiting
	// until the first channel message. In case of a timeout message, the spawned goroutine will
	// put a message in one of this two channels (ch and chErr) and simply returns (die), the
	// program don't care about the messages, because it has already timed out. If the channels
	// were not buffered the goroutine would be blocked trying to put a message into the channel
	// until the program dies.
	ch := make(chan *sql.Tx, 1)
	chErr := make(chan error, 1)

	go func() {
		tx, err := db.Begin()
		if err != nil {
			chErr <- err
			return
		}

		ch <- tx
	}()

	select {
	case tx := <-ch:
		return tx, nil
	case err := <-chErr:
		return nil, err
	case <-time.After(timeout):
		return nil, ErrNewTxTimedOut
	}
}
<commit_msg>Fail fast when a new database transaction cannot be started.<commit_after>// Package db handles new connections and transactions with timeouts.
//
// Timeouts that can be defined:
//    Connect timeout         - sets the maximum wait for creating a new connection
//    Statement timeout       - sets the maximum wait for queries completion
//    New transaction timeout - sets the maximum wait for opening a new transaction
//
// This feature is useful when the servers must be kept up, even though your database servers are
// not stable. So the database clients can respond their users with kindly error messages or look
// for other database servers - fail fast is usually better than keep server resources busy.
package db

import (
	"database/sql"
	"errors"
	"fmt"
	"sync"
	"time"
)

// ErrNewTxTimedOut returned when takes too long to retrieve a transaction from the database server.
var ErrNewTxTimedOut = errors.New("new transaction timed out")

// PostgresDriver holds the postgres driver name. You should import the driver somewhere in your
// code. The default value for PostgresDriver was get from https://github.com/lib/pq. This driver
// isn't directly imported here to don't stick this library with only one type of Postgres driver,
// and to make it more flexible for testing.
//
//     import (
//       _ "github.com/lib/pq"
//     )
var PostgresDriver = "postgres"

// ConnParams is all the data needed to create a new connection with database.
// If you are looking for default values see NewConnParams() function that set
// defaults values to Data structure.
type ConnParams struct {
	Username     string
	Password     string
	DatabaseName string
	Host         string

	// ConnectTimeout is the timeout utilized to creating a new connection with database. It is not
	// recommended to use a timeout of less than 2 seconds.
	ConnectTimeout time.Duration
	// StatementTimeout is the timeout utilized to invalidate queries that last more than the
	// configured timeout.
	StatementTimeout time.Duration

	MaxIdleConnections int
	MaxOpenConnections int
}

// NewConnParams returns the database connection parameters with some default
// values.
func NewConnParams() ConnParams {
	return ConnParams{
		Host:               "127.0.0.1",
		ConnectTimeout:     3 * time.Second,
		StatementTimeout:   10 * time.Second,
		MaxIdleConnections: 16,
		MaxOpenConnections: 32,
	}
}

// ConnectPostgres connects to a postgres database using the values from d. In case of a successfully
// connection it returns a sql.DB and a nil error. In case of problem it returns a nil sql.DB and an
// error from sql.Open (standard library, see https://golang.org/pkg/database/sql/#Open)
func ConnectPostgres(d ConnParams) (db *sql.DB, err error) {
	// connect_timeout
	//
	// https://www.postgresql.org/docs/9.6/static/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT
	// Maximum wait for connection, in seconds (write as a decimal integer string). Zero or not
	// specified means wait indefinitely. It is not recommended to use a timeout of less than 2
	// seconds.
	//
	// statement_timeout
	//
	// https://www.postgresql.org/docs/9.6/static/runtime-config-client.html#GUC-STATEMENT-TIMEOUT
	// Abort any statement that takes more than the specified number of milliseconds, starting from
	// the time the command arrives at the server from the client.
	connParams := fmt.Sprintf(
		"user=%s password=%s dbname=%s sslmode=disable host=%s connect_timeout=%d statement_timeout=%d",
		d.Username,
		d.Password,
		d.DatabaseName,
		d.Host,
		int(d.ConnectTimeout.Seconds()),
		int(d.StatementTimeout.Seconds()*1000),
	)

	if db, err = sql.Open(PostgresDriver, connParams); err != nil {
		return nil, err
	}

	db.SetMaxIdleConns(d.MaxIdleConnections)
	db.SetMaxOpenConns(d.MaxOpenConnections)
	return
}

// NewTx starts a new database transaction with a timeout. Starting a new transaction is not
// supposed to last too long, so a timeout of more than 3 seconds it's usually not necessary.
func NewTx(db *sql.DB, timeout time.Duration) (*sql.Tx, error) {
	if checker.Checking() {
		return nil, ErrNewTxTimedOut // TODO change error type (?)
	}

	// The channels has size of 1 (buffered) to avoid keeping an unnecessary goroutine blocked in
	// memory. For example: a goroutine is spawn, and it returns via channel a new transaction or
	// an error. After spawning a goroutine the program blocks in the select statement waiting
	// until the first channel message. In case of a timeout message, the spawned goroutine will
	// put a message in one of this two channels (ch and chErr) and simply returns (die), the
	// program don't care about the messages, because it has already timed out. If the channels
	// were not buffered the goroutine would be blocked trying to put a message into the channel
	// until the program dies.
	ch := make(chan *sql.Tx, 1)
	chErr := make(chan error, 1)

	go func() {
		tx, err := db.Begin()
		if err != nil {
			chErr <- err
			return
		}

		ch <- tx
	}()

	select {
	case tx := <-ch:
		return tx, nil
	case err := <-chErr:
		return nil, err
	case <-time.After(timeout):
		go func() {
			checker.Check(db)
		}()
		return nil, ErrNewTxTimedOut
	}
}

type dbChecker struct {
	sync.RWMutex
	checking bool
}

func (d *dbChecker) Checking() bool {
	d.RLock()
	defer d.RUnlock()
	return d.checking
}

func (d *dbChecker) Start() {
	d.Lock()
	defer d.Unlock()
	d.checking = true
}

func (d *dbChecker) Stop() {
	d.Lock()
	defer d.Unlock()
	d.checking = false
}

func (d *dbChecker) Check(db *sql.DB) {
	if d.Checking() {
		// already checking
		return
	}

	d.Start()
	for range time.Tick(2 * time.Second) {
		tx, err := db.Begin()
		if err != nil {
			continue
		}

		// db is back!
		d.Stop()
		tx.Commit()
		return
	}
}

var checker = new(dbChecker)
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"github.com/JacobHayes/locus"
	"log"
	"os"
	"strings"
)

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func open(filename string) *os.File {
	file, err := os.Open(filename)
	check(err)

	return file
}

func readLine(scanner *bufio.Scanner) string {
	check(scanner.Err())
	scanner.Scan()
	line := scanner.Text()
	check(scanner.Err())

	return line
}

func main() {
	stdin := bufio.NewScanner(os.Stdin)

	key_file := open(`api`)
	defer key_file.Close()
	key := readLine(bufio.NewScanner(key_file))

	fmt.Print("Enter an IP address to lookup: ")
	ip := readLine(stdin)

	fmt.Print("Location Precision - City/[Country]: ")

	if precision := strings.ToLower(readLine(stdin)); precision == "city" {
		fmt.Println(locus.LookupLocation(ip, "City", key))
	} else {
		fmt.Println(locus.LookupLocation(ip, "Country", key))
	}
}
<commit_msg>Implement bulk lookup<commit_after>package main

import (
	"bufio"
	"fmt"
	"github.com/JacobHayes/locus"
	"log"
	"os"
	"strings"
)

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func open(filename string) *os.File {
	file, err := os.Open(filename)
	check(err)

	return file
}

func readLine(scanner *bufio.Scanner) string {
	check(scanner.Err())
	scanner.Scan()
	line := scanner.Text()
	check(scanner.Err())

	return line
}

func main() {
	stdin := bufio.NewScanner(os.Stdin)

	key_file := open(`api`)
	defer key_file.Close()
	key := readLine(bufio.NewScanner(key_file))

	ips := make([]string, 5)
	for i := 0; i < 5; i++ {
		fmt.Print("Enter an IP address to lookup: ")
		ips[i] = readLine(stdin)
	}

	fmt.Print("Location Precision - City/[Country]: ")
	locations, err := locus.BulkLookupLocation(ips, strings.ToLower(readLine(stdin)), key)
	check(err)

	for _, location := range locations {
		fmt.Println(location)
	}
}
<|endoftext|>