<commit_before>package boardgame

import (
	"container/heap"
	"time"
)

//A Timer is a type of property that can be used in states that represents a
//countdown. See the package documentation for more on timers.
type Timer struct {
	//Id will be an opaque identifier that is used to keep track of the
	//corresponding underlying Timer object in the game engine. It is not
	//meaningful to inspect yourself and should not be modified.
	Id       int
	statePtr *state
}

func NewTimer() *Timer {
	return &Timer{}
}

func (t *Timer) Copy() *Timer {
	var result Timer
	result = *t
	return &result
}

func (t *Timer) MarshalJSON() ([]byte, error) {
	obj := map[string]interface{}{
		"Id":       t.Id,
		"TimeLeft": t.TimeLeft(),
	}

	return DefaultMarshalJSON(obj)
}

//Active returns true if the timer is active and counting down.
func (t *Timer) Active() bool {
	return t.statePtr.game.manager.timers.TimerActive(t.Id)
}

//TimeLeft returns the number of nanoseconds left until this timer fires.
func (t *Timer) TimeLeft() time.Duration {

	return t.statePtr.game.manager.timers.GetTimerRemaining(t.Id)
}

//Start starts the timer. After duration has passed, the Move
//will be proposed via proposeMove.
func (t *Timer) Start(duration time.Duration, move Move) {
	game := t.statePtr.game
	manager := game.manager

	t.Id = manager.timers.PrepareTimer(duration, game, move)

	t.statePtr.timersToStart = append(t.statePtr.timersToStart, t.Id)
}

//Cancel cancels an active timer. If the timer is not active, it has no
//effect. Returns true if the timer was active and canceled, false if the
//timer was not active.
func (t *Timer) Cancel() bool {

	wasActive := t.Active()

	manager := t.statePtr.game.manager

	manager.timers.CancelTimer(t.Id)

	//Technically there's a case where Start() was called, but the state was
	//never fully committed. However, StartTimer() on a canceled timer is a
	//no-op so it's fine.

	t.Id = 0

	return wasActive
}

type timerRecord struct {
	id    int
	index int
	//When the timer should fire. Set after the timer is fully Started().
	//Before that it is impossibly far in the future.
	fireTime time.Time
	//The duration we were configured with. Only set when the timer is
	//Prepared() but not yet Started().
	duration time.Duration
	game     *Game
	move     Move
}

func (t *timerRecord) TimeRemaining() time.Duration {

	//Before a timer is Started(), just say its duration as the time
	//remaining.
	if t.duration > 0 {
		return t.duration
	}

	duration := t.fireTime.Sub(time.Now())

	if duration < 0 {
		duration = 0
	}

	return duration
}

type timerQueue []*timerRecord

type timerManager struct {
	nextId      int
	records     timerQueue
	recordsById map[int]*timerRecord
}

func newTimerManager() *timerManager {
	return &timerManager{
		//the default id in TimerProps is 0, so we should start beyond that.
		nextId:      1,
		records:     make(timerQueue, 0),
		recordsById: make(map[int]*timerRecord),
	}
}

//PrepareTimer creates a timer entry and gets it ready and an Id allocated.
//However, the timer doesn't actually start counting down until
//manager.StartTimer(id) is called.
func (t *timerManager) PrepareTimer(duration time.Duration, game *Game, move Move) int {
	record := &timerRecord{
		id:       t.nextId,
		index:    -1,
		duration: duration,
		//fireTime will be set when StartTimer is called. For now, set it to
		//something impossibly far in the future.
		fireTime: time.Now().Add(time.Hour * 100000),
		game:     game,
		move:     move,
	}
	t.nextId++

	t.recordsById[record.id] = record

	heap.Push(&t.records, record)

	return record.id
}

//StartTimer actually triggers a timer that was previously PrepareTimer'd to
//start counting down.
func (t *timerManager) StartTimer(id int) {

	if t.TimerActive(id) {
		return
	}

	record := t.recordsById[id]

	if record == nil {
		return
	}

	record.fireTime = time.Now().Add(record.duration)
	record.duration = 0

	heap.Fix(&t.records, record.index)
}

//TimerActive returns if the timer is active and counting down.
func (t *timerManager) TimerActive(id int) bool {
	record := t.recordsById[id]

	if record == nil {
		return false
	}

	if record.duration > 0 {
		return false
	}

	return true
}

func (t *timerManager) GetTimerRemaining(id int) time.Duration {
	record := t.recordsById[id]

	if record == nil {
		return 0
	}

	return record.TimeRemaining()
}

func (t *timerManager) CancelTimer(id int) {
	record := t.recordsById[id]

	if record == nil {
		return
	}

	heap.Remove(&t.records, record.index)

	record.index = -1

	delete(t.recordsById, record.id)

}

//Should be called regularly by the manager to tell this to check and see if
//any timers have fired, and execute them if so.
func (t *timerManager) Tick() {
	for t.nextTimerFired() {
		record := t.popNext()
		if record == nil {
			continue
		}
		if err := <-record.game.ProposeMove(record.move); err != nil {
			//TODO: log the error or something
			panic(err)
		}
	}
}

//Whether the next timer in the queue is already fired
func (t *timerManager) nextTimerFired() bool {
	if len(t.records) == 0 {
		return false
	}

	record := t.records[0]

	return record.TimeRemaining() <= 0
}

func (t *timerManager) popNext() *timerRecord {
	if !t.nextTimerFired() {
		return nil
	}

	x := heap.Pop(&t.records)

	record := x.(*timerRecord)

	delete(t.recordsById, record.id)

	return record
}

func (t timerQueue) Len() int {
	return len(t)
}

func (t timerQueue) Less(i, j int) bool {
	return t[i].fireTime.Sub(t[j].fireTime) < 0
}

func (t timerQueue) Swap(i, j int) {
	t[i], t[j] = t[j], t[i]
	t[i].index = i
	t[j].index = j
}

//DO NOT USE THIS DIRECTLY. Use heap.Push(t)
func (t *timerQueue) Push(x interface{}) {
	n := len(*t)
	item := x.(*timerRecord)
	item.index = n
	*t = append(*t, item)
}

//DO NOT USE THIS DIRECTLY. Use heap.Pop()
func (t *timerQueue) Pop() interface{} {
	old := *t
	n := len(old)
	item := old[n-1]
	item.index = -1
	*t = old[0 : n-1]
	return item
}
<commit_msg>Calling Start on an active timer will cancel the existing one and start the new one. Part of #178.<commit_after>package boardgame

import (
	"container/heap"
	"time"
)

//A Timer is a type of property that can be used in states that represents a
//countdown. See the package documentation for more on timers.
type Timer struct {
	//Id will be an opaque identifier that is used to keep track of the
	//corresponding underlying Timer object in the game engine. It is not
	//meaningful to inspect yourself and should not be modified.
	Id       int
	statePtr *state
}

func NewTimer() *Timer {
	return &Timer{}
}

func (t *Timer) Copy() *Timer {
	var result Timer
	result = *t
	return &result
}

func (t *Timer) MarshalJSON() ([]byte, error) {
	obj := map[string]interface{}{
		"Id":       t.Id,
		"TimeLeft": t.TimeLeft(),
	}

	return DefaultMarshalJSON(obj)
}

//Active returns true if the timer is active and counting down.
func (t *Timer) Active() bool {
	return t.statePtr.game.manager.timers.TimerActive(t.Id)
}

//TimeLeft returns the number of nanoseconds left until this timer fires.
func (t *Timer) TimeLeft() time.Duration {

	return t.statePtr.game.manager.timers.GetTimerRemaining(t.Id)
}

//Start starts the timer. After duration has passed, the Move
//will be proposed via proposeMove.
func (t *Timer) Start(duration time.Duration, move Move) {

	if t.Active() {
		t.Cancel()
	}

	game := t.statePtr.game
	manager := game.manager

	t.Id = manager.timers.PrepareTimer(duration, game, move)

	t.statePtr.timersToStart = append(t.statePtr.timersToStart, t.Id)
}

//Cancel cancels an active timer. If the timer is not active, it has no
//effect. Returns true if the timer was active and canceled, false if the
//timer was not active.
func (t *Timer) Cancel() bool {

	wasActive := t.Active()

	manager := t.statePtr.game.manager

	manager.timers.CancelTimer(t.Id)

	//Technically there's a case where Start() was called, but the state was
	//never fully committed. However, StartTimer() on a canceled timer is a
	//no-op so it's fine.

	t.Id = 0

	return wasActive
}

type timerRecord struct {
	id    int
	index int
	//When the timer should fire. Set after the timer is fully Started().
	//Before that it is impossibly far in the future.
	fireTime time.Time
	//The duration we were configured with. Only set when the timer is
	//Prepared() but not yet Started().
	duration time.Duration
	game     *Game
	move     Move
}

func (t *timerRecord) TimeRemaining() time.Duration {

	//Before a timer is Started(), just say its duration as the time
	//remaining.
	if t.duration > 0 {
		return t.duration
	}

	duration := t.fireTime.Sub(time.Now())

	if duration < 0 {
		duration = 0
	}

	return duration
}

type timerQueue []*timerRecord

type timerManager struct {
	nextId      int
	records     timerQueue
	recordsById map[int]*timerRecord
}

func newTimerManager() *timerManager {
	return &timerManager{
		//the default id in TimerProps is 0, so we should start beyond that.
		nextId:      1,
		records:     make(timerQueue, 0),
		recordsById: make(map[int]*timerRecord),
	}
}

//PrepareTimer creates a timer entry and gets it ready and an Id allocated.
//However, the timer doesn't actually start counting down until
//manager.StartTimer(id) is called.
func (t *timerManager) PrepareTimer(duration time.Duration, game *Game, move Move) int {
	record := &timerRecord{
		id:       t.nextId,
		index:    -1,
		duration: duration,
		//fireTime will be set when StartTimer is called. For now, set it to
		//something impossibly far in the future.
		fireTime: time.Now().Add(time.Hour * 100000),
		game:     game,
		move:     move,
	}
	t.nextId++

	t.recordsById[record.id] = record

	heap.Push(&t.records, record)

	return record.id
}

//StartTimer actually triggers a timer that was previously PrepareTimer'd to
//start counting down.
func (t *timerManager) StartTimer(id int) {

	if t.TimerActive(id) {
		return
	}

	record := t.recordsById[id]

	if record == nil {
		return
	}

	record.fireTime = time.Now().Add(record.duration)
	record.duration = 0

	heap.Fix(&t.records, record.index)
}

//TimerActive returns if the timer is active and counting down.
func (t *timerManager) TimerActive(id int) bool {
	record := t.recordsById[id]

	if record == nil {
		return false
	}

	if record.duration > 0 {
		return false
	}

	return true
}

func (t *timerManager) GetTimerRemaining(id int) time.Duration {
	record := t.recordsById[id]

	if record == nil {
		return 0
	}

	return record.TimeRemaining()
}

func (t *timerManager) CancelTimer(id int) {
	record := t.recordsById[id]

	if record == nil {
		return
	}

	heap.Remove(&t.records, record.index)

	record.index = -1

	delete(t.recordsById, record.id)

}

//Should be called regularly by the manager to tell this to check and see if
//any timers have fired, and execute them if so.
func (t *timerManager) Tick() {
	for t.nextTimerFired() {
		record := t.popNext()
		if record == nil {
			continue
		}
		if err := <-record.game.ProposeMove(record.move); err != nil {
			//TODO: log the error or something
			panic(err)
		}
	}
}

//Whether the next timer in the queue is already fired
func (t *timerManager) nextTimerFired() bool {
	if len(t.records) == 0 {
		return false
	}

	record := t.records[0]

	return record.TimeRemaining() <= 0
}

func (t *timerManager) popNext() *timerRecord {
	if !t.nextTimerFired() {
		return nil
	}

	x := heap.Pop(&t.records)

	record := x.(*timerRecord)

	delete(t.recordsById, record.id)

	return record
}

func (t timerQueue) Len() int {
	return len(t)
}

func (t timerQueue) Less(i, j int) bool {
	return t[i].fireTime.Sub(t[j].fireTime) < 0
}

func (t timerQueue) Swap(i, j int) {
	t[i], t[j] = t[j], t[i]
	t[i].index = i
	t[j].index = j
}

//DO NOT USE THIS DIRECTLY. Use heap.Push(t)
func (t *timerQueue) Push(x interface{}) {
	n := len(*t)
	item := x.(*timerRecord)
	item.index = n
	*t = append(*t, item)
}

//DO NOT USE THIS DIRECTLY. Use heap.Pop()
func (t *timerQueue) Pop() interface{} {
	old := *t
	n := len(old)
	item := old[n-1]
	item.index = -1
	*t = old[0 : n-1]
	return item
}
<|endoftext|>


<commit_before>// Copyright 2014 Dizitart. All rights reserved.
// Use of this source code is governed by a Apache License V2
// that can be found in the LICENSE file.
//
// Author - Anindya Chatterjee (axchatt@dizitart.com)

package trace

import (
	"fmt"
	"time"
	"runtime"
	"os"
	"path/filepath"
	"runtime/debug"
)

// Use these configuration variables to set tracing parameters
var (
	// Flag to enable or disable the Tracing
	ENABLE_TRACE		bool 	= false
	// Flag to set the tracer to print in Stdout
	PRINT_TO_STDOUT		bool 	= true
	// Flag to set the tracer to print in Stdout
	PRINT_TO_FILE		bool 	= false
	// Trace log file path
	TRACE_OUT_FILE		string
	// Trace message format
	TRACE_FORMAT		string	= "TRACE [%v] <%s> (%s:%d) - %v"
)

// Writes information about current source file, line number and input variable
func Write(variable interface {}) {
	if ENABLE_TRACE {
		msg := createTraceMessage(variable)
		trace(msg, false)
	}
}

// Writes information about current source file, line number and input variable after
// formatting it according to a format specifier
func Writef(format string, variables ...interface{}) {
	if ENABLE_TRACE {
		msg := createTraceMessagef(format, variables...)
		trace(msg, false)
	}
}

// Checks for a condition; if the condition is false, writes
// a trace message that shows the call stack.
func Assert (condition bool) {
	if ENABLE_TRACE {
		if !condition {
			msg := createTraceMessage("Assertion Failed!")
			trace(msg, true)
		}
	}
}

// Checks for a condition; if the condition is false, writes a
// specified message after formatting it according to a format specifier
// that shows the call stack.
func Assertf (condition bool, format string, variables ...interface{}) {
	if ENABLE_TRACE {
		if !condition {
			msg := createTraceMessagef(format, variables...)
			trace(msg, true)
		}
	}
}

// Prints the message and stack trace if set to true
func trace(msg string, printStack bool) {
	if PRINT_TO_STDOUT {
		fmt.Println(msg)
		if printStack {
			debug.PrintStack()
		}
	}

	if PRINT_TO_FILE {
		if TRACE_OUT_FILE == "" {
			return
		} else {
			file, _ := os.OpenFile(TRACE_OUT_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
			defer file.Close()
			file.WriteString(msg + "\n")
			if printStack {
				file.WriteString(string(debug.Stack()))
			}
		}
	}
}

// Creates the trace message
func createTraceMessage(variable interface {}) string {
	pc, path, line, ok := runtime.Caller(2)
	if ok {
		fun := runtime.FuncForPC(pc)
		name := fun.Name()

		sourceFile := filepath.Base(path)
		msg := fmt.Sprintf(TRACE_FORMAT, time.Now(), name, sourceFile, line, variable)
		return msg
	}
	return ""
}

// Creates the trace message after
// formatting it according to a format specifier
func createTraceMessagef(format string, variables ...interface{}) string {
	pc, path, line, ok := runtime.Caller(2)
	if ok {
		fun := runtime.FuncForPC(pc)
		name := fun.Name()

		sourceFile := filepath.Base(path)
		umsg := fmt.Sprintf(format, variables...)
		msg := fmt.Sprintf(TRACE_FORMAT, time.Now(), name, sourceFile, line, umsg)
		return msg
	}
	return ""
}
<commit_msg>Work In Progress<commit_after>// Copyright 2014 Dizitart. All rights reserved.
// Use of this source code is governed by a Apache License V2
// that can be found in the LICENSE file.
//
// Author - Anindya Chatterjee (axchatt@dizitart.com)

package trace

import (
	"fmt"
	"time"
	"runtime"
	"os"
	"path/filepath"
	"runtime/debug"
)

const (
	PRINT_NONE		byte = 0
	PRINT_TIME		byte = 1
	PRINT_PROC		byte = 2
	PRINT_FILE		byte = 4
	PRINT_LINE		byte = 8
	PRINT_ALL		byte = 15
)

// Use these configuration variables to set tracing parameters
var (
	// Flag to enable or disable the Tracing
	ENABLE_TRACE		bool 	= false
	// Flag to set the tracer to print in Stdout
	PRINT_TO_STDOUT		bool 	= true
	// Flag to set the tracer to write in a file
	PRINT_TO_FILE		bool 	= false
	// Trace log file path
	TRACE_OUT_FILE		string
	// Trace flag
	TRACE_FLAG			byte

)

// Writes information about current source file, line number and input variable
func Write(variable interface {}) {
	if ENABLE_TRACE {
		msg := createTraceMessage(variable)
		trace(msg, false)
	}
}

// Writes information about current source file, line number and input variable after
// formatting it according to a format specifier
func Writef(format string, variables ...interface{}) {
	if ENABLE_TRACE {
		msg := createTraceMessagef(format, variables...)
		trace(msg, false)
	}
}

// Checks for a condition; if the condition is false, writes
// a trace message that shows the call stack.
func Assert (condition bool) {
	if ENABLE_TRACE {
		if !condition {
			msg := createTraceMessage("Assertion Failed!")
			trace(msg, true)
		}
	}
}

// Checks for a condition; if the condition is false, writes a
// specified message after formatting it according to a format specifier
// that shows the call stack.
func Assertf (condition bool, format string, variables ...interface{}) {
	if ENABLE_TRACE {
		if !condition {
			msg := createTraceMessagef(format, variables...)
			trace(msg, true)
		}
	}
}

// Prints the message and stack trace if set to true
func trace(msg string, printStack bool) {
	if PRINT_TO_STDOUT {
		fmt.Println(msg)
		if printStack {
			debug.PrintStack()
		}
	}

	if PRINT_TO_FILE {
		if TRACE_OUT_FILE == "" {
			return
		} else {
			file, _ := os.OpenFile(TRACE_OUT_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
			defer file.Close()
			file.WriteString(msg + "\n")
			if printStack {
				file.WriteString(string(debug.Stack()))
			}
		}
	}
}

// Creates the trace message
func createTraceMessage(variable interface {}) string {
	pc, path, line, ok := runtime.Caller(2)
	if ok {
		fun := runtime.FuncForPC(pc)
		name := fun.Name()

		sourceFile := filepath.Base(path)
		var msg string = "TRACE"
		if TRACE_FLAG & PRINT_NONE == PRINT_NONE {
			msg = msg + ""
		}
		if TRACE_FLAG & PRINT_TIME == PRINT_TIME {
			msg = fmt.Sprintf(msg + " [%v]", time.Now())
		}
		if TRACE_FLAG & PRINT_PROC == PRINT_PROC {
			msg = fmt.Sprintf(msg + " <%s>", name)
		}
		if TRACE_FLAG & PRINT_FILE == PRINT_FILE && TRACE_FLAG & PRINT_LINE == PRINT_LINE {
			msg = fmt.Sprintf(msg + " (%s:%d)", sourceFile, line)
		} else if TRACE_FLAG & PRINT_FILE == PRINT_FILE {
			msg = fmt.Sprintf(msg + " (%s)", sourceFile)
		} else if TRACE_FLAG & PRINT_LINE == PRINT_LINE {
			msg = fmt.Sprintf(msg + " (%d)", line)
		}

		msg := fmt.Sprintf(msg + " - %v", variable)
		return msg
	}
	return ""
}

// Creates the trace message after
// formatting it according to a format specifier
func createTraceMessagef(format string, variables ...interface{}) string {
	pc, path, line, ok := runtime.Caller(2)
	if ok {
		fun := runtime.FuncForPC(pc)
		name := fun.Name()

		sourceFile := filepath.Base(path)
		umsg := fmt.Sprintf(format, variables...)
		msg := fmt.Sprintf(trace_format, time.Now(), name, sourceFile, line, umsg)
		return msg
	}
	return ""
}

func createMessageFormat() string {
	var trace_format		string	= "TRACE [%v] <%s> (%s:%d) - %v"
	if TRACE_FLAG & PRINT_NONE == PRINT_NONE {
		trace_format = trace_format + " - %v"
	}

	if TRACE_FLAG & PRINT_TIME == PRINT_TIME {
		trace_format = trace_format + " [%v]"
	}

}
<|endoftext|>


<commit_before>package chipmunk

import "time"

type tranx struct {
	ID       int       `json:"id"`
	Cost     float64   `json:"cost"`
	Store    string    `json:"store"`
	Info     string    `json:"info"`
	Date     time.Time `json:"date"`
	User     int       `json:"user"`
	Category int       `json:"category"`
}
<commit_msg>updated tranx<commit_after>package chipmunk

import "time"

type tranx struct {
	ID       int       `json:"id"`
	Cost     float64   `json:"cost"`
	Store    string    `json:"store"`
	Info     string    `json:"info"`
	Date     time.Time `json:"date"`
	User     string    `json:"user"`
	Category string    `json:"category"`
}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2016 tech0522.tk
 */
package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"

	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/line/line-bot-sdk-go/linebot/httphandler"
)

const ButtonLabel = "レシピを開く"
const MaxRecipesToReply = "5"
const MaxRecipeDescriptionLength = 60
const RecipeDescriptionTailIfTooLong = "..."
const RecipeCarouselAltTextTailing = "..."

type RecipeDBSearchResult struct {
	Hits struct {
		Total int `json:"total"`
		Hits  []struct {
			Source struct {
				Title       string `json:"title"`
				Description string `json:"description"`
				ImageUrl    string `json:"image_url"`
				Url         string `json:"detail_url"`
			} `json:"_source"`
		} `json:"hits"`
	} `json:"hits"`
}

func replyRecipe(bot *linebot.Client, replyToken string, phrase string, config *RecipeLinebotConfig) {
	apiUrl := url.URL{Scheme: "http", Host: config.RecipeDB.Host,
		Path: path.Join(config.RecipeDB.Index, config.RecipeDB.RecipeDoctype, "_search")}
	resp, err := http.Post(apiUrl.String(), "application/json",
		bytes.NewBuffer([]byte(`{"size": `+MaxRecipesToReply+`, "query": {"multi_match": {"query": "`+phrase+`", "type": "phrase", "fields": ["materials", "title", "description"]}}}`)))
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		body, _ := ioutil.ReadAll(resp.Body)
		log.Fatal("Bad status code: code=" + resp.Status + " body=" + string(body))
	}
	var result RecipeDBSearchResult
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		log.Fatal(err)
	}
	if result.Hits.Total == 0 {
		return
	}
	var cols []*linebot.CarouselColumn
	for _, hit := range result.Hits.Hits {
		desc := hit.Source.Description
		if len(desc) > MaxRecipeDescriptionLength {
			offset_to_shorten := MaxRecipeDescriptionLength - len(RecipeDescriptionTailIfTooLong)
			desc = desc[0:offset_to_shorten] + RecipeDescriptionTailIfTooLong
		}
		cols = append(cols, linebot.NewCarouselColumn(hit.Source.ImageUrl, hit.Source.Title, desc,
			linebot.NewURITemplateAction(ButtonLabel, hit.Source.Url)))
	}
	altText := result.Hits.Hits[0].Source.Title + RecipeCarouselAltTextTailing
	tmpl := linebot.NewCarouselTemplate(cols...)
	replyMsg := linebot.NewTemplateMessage(altText, tmpl)
	if _, err = bot.ReplyMessage(replyToken, replyMsg).Do(); err != nil {
		log.Fatal(err)
	}
}

func onMessageEvent(bot *linebot.Client, event *linebot.Event, config *RecipeLinebotConfig) {
	resp, err := bot.GetProfile((*event.Source).UserID).Do()
	if err != nil {
		log.Fatal(err)
	}
	switch recvMsg := event.Message.(type) {
	case *linebot.TextMessage:
		log.Printf("receive text message: from=%s, text=%s\n", resp.DisplayName, recvMsg.Text)
		replyRecipe(bot, (*event).ReplyToken, recvMsg.Text, config)
	default:
		log.Printf("receive a some kind of event: from=%s\n", resp.DisplayName)
	}
}

func serveAsBot(config *RecipeLinebotConfig) {
	log.Printf("start bot server: addr=%s, path=%s", config.BotServer.ListenAddr, config.BotServer.APIPath)
	handler, err := httphandler.New(config.BotServer.ChSecret, config.BotServer.ChToken)
	if err != nil {
		log.Fatal(err)
	}
	handler.HandleEvents(func(events []*linebot.Event, req *http.Request) {
		bot, err := handler.NewClient()
		if err != nil {
			log.Fatal(err)
			return
		}
		for _, event := range events {
			if event.Type == linebot.EventTypeMessage {
				onMessageEvent(bot, event, config)
			} else {
				log.Printf("%s\n", event.Timestamp.String())
			}
		}
	})
	http.Handle(config.BotServer.APIPath, handler)
	if err := http.ListenAndServeTLS(config.BotServer.ListenAddr, config.BotServer.CertFilePath,
		config.BotServer.KeyFilePath, nil); err != nil {
		log.Fatal(err)
	}
	log.Print("bot server finished")
}
<commit_msg>:heavy_plus_sign: レシピが見つからなかった場合も応答する<commit_after>/**
 * Copyright (C) 2016 tech0522.tk
 */
package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"

	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/line/line-bot-sdk-go/linebot/httphandler"
)

const ButtonLabel = "レシピを開く"
const NotFoundReplyStickerPackageID = "2"
const NotFoundReplyStickerID = "38"
const MaxRecipesToReply = "5"
const MaxRecipeDescriptionLength = 60
const RecipeDescriptionTailIfTooLong = "..."
const RecipeCarouselAltTextTailing = "..."

type RecipeDBSearchResult struct {
	Hits struct {
		Total int `json:"total"`
		Hits  []struct {
			Source struct {
				Title       string `json:"title"`
				Description string `json:"description"`
				ImageUrl    string `json:"image_url"`
				Url         string `json:"detail_url"`
			} `json:"_source"`
		} `json:"hits"`
	} `json:"hits"`
}

func replyRecipe(bot *linebot.Client, replyToken string, phrase string, config *RecipeLinebotConfig) {
	apiUrl := url.URL{Scheme: "http", Host: config.RecipeDB.Host,
		Path: path.Join(config.RecipeDB.Index, config.RecipeDB.RecipeDoctype, "_search")}
	resp, err := http.Post(apiUrl.String(), "application/json",
		bytes.NewBuffer([]byte(`{"size": `+MaxRecipesToReply+`, "query": {"multi_match": {"query": "`+phrase+`", "type": "phrase", "fields": ["materials", "title", "description"]}}}`)))
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		body, _ := ioutil.ReadAll(resp.Body)
		log.Fatal("Bad status code: code=" + resp.Status + " body=" + string(body))
	}
	var result RecipeDBSearchResult
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		log.Fatal(err)
	}
	var replyMsg linebot.Message
	if result.Hits.Total == 0 {
		replyMsg = linebot.NewStickerMessage(NotFoundReplyStickerPackageID, NotFoundReplyStickerID)
	} else {
		var cols []*linebot.CarouselColumn
		for _, hit := range result.Hits.Hits {
			desc := hit.Source.Description
			if len(desc) > MaxRecipeDescriptionLength {
				offset_to_shorten := MaxRecipeDescriptionLength - len(RecipeDescriptionTailIfTooLong)
				desc = desc[0:offset_to_shorten] + RecipeDescriptionTailIfTooLong
			}
			cols = append(cols, linebot.NewCarouselColumn(hit.Source.ImageUrl, hit.Source.Title, desc,
				linebot.NewURITemplateAction(ButtonLabel, hit.Source.Url)))
		}
		altText := result.Hits.Hits[0].Source.Title + RecipeCarouselAltTextTailing
		tmpl := linebot.NewCarouselTemplate(cols...)
		replyMsg = linebot.NewTemplateMessage(altText, tmpl)
	}
	if _, err = bot.ReplyMessage(replyToken, replyMsg).Do(); err != nil {
		log.Fatal(err)
	}
}

func onMessageEvent(bot *linebot.Client, event *linebot.Event, config *RecipeLinebotConfig) {
	resp, err := bot.GetProfile((*event.Source).UserID).Do()
	if err != nil {
		log.Fatal(err)
	}
	switch recvMsg := event.Message.(type) {
	case *linebot.TextMessage:
		log.Printf("receive text message: from=%s, text=%s\n", resp.DisplayName, recvMsg.Text)
		replyRecipe(bot, (*event).ReplyToken, recvMsg.Text, config)
	default:
		log.Printf("receive a some kind of event: from=%s\n", resp.DisplayName)
	}
}

func serveAsBot(config *RecipeLinebotConfig) {
	log.Printf("start bot server: addr=%s, path=%s", config.BotServer.ListenAddr, config.BotServer.APIPath)
	handler, err := httphandler.New(config.BotServer.ChSecret, config.BotServer.ChToken)
	if err != nil {
		log.Fatal(err)
	}
	handler.HandleEvents(func(events []*linebot.Event, req *http.Request) {
		bot, err := handler.NewClient()
		if err != nil {
			log.Fatal(err)
			return
		}
		for _, event := range events {
			if event.Type == linebot.EventTypeMessage {
				onMessageEvent(bot, event, config)
			} else {
				log.Printf("%s\n", event.Timestamp.String())
			}
		}
	})
	http.Handle(config.BotServer.APIPath, handler)
	if err := http.ListenAndServeTLS(config.BotServer.ListenAddr, config.BotServer.CertFilePath,
		config.BotServer.KeyFilePath, nil); err != nil {
		log.Fatal(err)
	}
	log.Print("bot server finished")
}
<|endoftext|>


<commit_before>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2019-06-03 05:54:49.226605 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "68c9104f300b201659a93d5ea43261c1e4745716"
<commit_msg>"Autogenerated build info"<commit_after>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2019-06-03 06:02:15.298118 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "cfd44e28f030bd8ca138bda125927bd6a7aaf2f3"
<|endoftext|>


<commit_before>package cluster

import (
	"fmt"
	"net"
	"testing"
	"time"
)

func Test_NewServiceOpenClose(t *testing.T) {
	ml := mustNewMockListener()
	ms := &mockStore{}
	s := NewService(ml, ms)
	if s == nil {
		t.Fatalf("failed to create cluster service")
	}

	if err := s.Open(); err != nil {
		t.Fatalf("failed to open cluster service")
	}
	if err := s.Close(); err != nil {
		t.Fatalf("failed to close cluster service")
	}
}

func Test_SetAPIPeer(t *testing.T) {
	raftAddr, apiAddr := "localhost:4002", "localhost:4001"

	s, _, ms := mustNewOpenService()
	defer s.Close()
	if err := s.SetPeer(raftAddr, apiAddr); err != nil {
		t.Fatalf("failed to set peer: %s", err.Error())
	}

	if ms.peers[raftAddr] != apiAddr {
		t.Fatalf("peer not set correctly, exp %s, got %s", apiAddr, ms.peers[raftAddr])
	}
}

func Test_SerAPIPeerNetwork(t *testing.T) {
    t.Skip("service not responding correctly")

	raftAddr, apiAddr := "localhost:4002", "localhost:4001"

	s, _, ms := mustNewOpenService()
	defer s.Close()

	raddr, err := net.ResolveTCPAddr("tcp", s.Addr())
	if err != nil {
		t.Fatalf("failed to resolve remote uster ervice address: %s", err.Error())
	}

	conn, err := net.DialTCP("tcp4", nil, raddr)
	if err != nil {
		t.Fatalf("failed to connect to remote cluster service: %s", err.Error())
	}
	conn.Write([]byte(fmt.Sprintf(`{"%s": "%d"}`, raftAddr, apiAddr)))
	if err != nil {
		t.Fatalf("failed to write to remote cluster service: %s", err.Error())
	}
    // XXX Check response

	if ms.peers[raftAddr] != apiAddr {
		t.Fatalf("peer not set correctly, exp %s, got %s", apiAddr, ms.peers[raftAddr])
	}
}

func mustNewOpenService() (*Service, *mockListener, *mockStore) {
	ml := mustNewMockListener()
	ms := newMockStore()
	s := NewService(ml, ms)
	if err := s.Open(); err != nil {
		panic("failed to open new service")
	}
	return s, ml, ms
}

type mockListener struct {
	ln net.Listener
}

func mustNewMockListener() *mockListener {
	ln, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		panic("failed to create mock listener")
	}
	return &mockListener{
		ln: ln,
	}
}

func (ml *mockListener) Accept() (c net.Conn, err error) {
	return ml.ln.Accept()
}

func (ml *mockListener) Addr() net.Addr {
	return ml.ln.Addr()
}

func (ml *mockListener) Close() (err error) {
	return ml.ln.Close()
}

func (ml *mockListener) Dial(addr string, t time.Duration) (net.Conn, error) {
	return nil, nil
}

type mockStore struct {
	leader string
	peers  map[string]string
}

func newMockStore() *mockStore {
	return &mockStore{
		peers: make(map[string]string),
	}
}

func (ms *mockStore) Leader() string {
	return ms.leader
}

func (ms *mockStore) UpdateAPIPeers(peers map[string]string) error {
	for k, v := range peers {
		ms.peers[k] = v
	}
	return nil
}
<commit_msg>'go fmt' fixes<commit_after>package cluster

import (
	"fmt"
	"net"
	"testing"
	"time"
)

func Test_NewServiceOpenClose(t *testing.T) {
	ml := mustNewMockListener()
	ms := &mockStore{}
	s := NewService(ml, ms)
	if s == nil {
		t.Fatalf("failed to create cluster service")
	}

	if err := s.Open(); err != nil {
		t.Fatalf("failed to open cluster service")
	}
	if err := s.Close(); err != nil {
		t.Fatalf("failed to close cluster service")
	}
}

func Test_SetAPIPeer(t *testing.T) {
	raftAddr, apiAddr := "localhost:4002", "localhost:4001"

	s, _, ms := mustNewOpenService()
	defer s.Close()
	if err := s.SetPeer(raftAddr, apiAddr); err != nil {
		t.Fatalf("failed to set peer: %s", err.Error())
	}

	if ms.peers[raftAddr] != apiAddr {
		t.Fatalf("peer not set correctly, exp %s, got %s", apiAddr, ms.peers[raftAddr])
	}
}

func Test_SerAPIPeerNetwork(t *testing.T) {
	t.Skip("service not responding correctly")

	raftAddr, apiAddr := "localhost:4002", "localhost:4001"

	s, _, ms := mustNewOpenService()
	defer s.Close()

	raddr, err := net.ResolveTCPAddr("tcp", s.Addr())
	if err != nil {
		t.Fatalf("failed to resolve remote uster ervice address: %s", err.Error())
	}

	conn, err := net.DialTCP("tcp4", nil, raddr)
	if err != nil {
		t.Fatalf("failed to connect to remote cluster service: %s", err.Error())
	}
	conn.Write([]byte(fmt.Sprintf(`{"%s": "%d"}`, raftAddr, apiAddr)))
	if err != nil {
		t.Fatalf("failed to write to remote cluster service: %s", err.Error())
	}
	// XXX Check response

	if ms.peers[raftAddr] != apiAddr {
		t.Fatalf("peer not set correctly, exp %s, got %s", apiAddr, ms.peers[raftAddr])
	}
}

func mustNewOpenService() (*Service, *mockListener, *mockStore) {
	ml := mustNewMockListener()
	ms := newMockStore()
	s := NewService(ml, ms)
	if err := s.Open(); err != nil {
		panic("failed to open new service")
	}
	return s, ml, ms
}

type mockListener struct {
	ln net.Listener
}

func mustNewMockListener() *mockListener {
	ln, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		panic("failed to create mock listener")
	}
	return &mockListener{
		ln: ln,
	}
}

func (ml *mockListener) Accept() (c net.Conn, err error) {
	return ml.ln.Accept()
}

func (ml *mockListener) Addr() net.Addr {
	return ml.ln.Addr()
}

func (ml *mockListener) Close() (err error) {
	return ml.ln.Close()
}

func (ml *mockListener) Dial(addr string, t time.Duration) (net.Conn, error) {
	return nil, nil
}

type mockStore struct {
	leader string
	peers  map[string]string
}

func newMockStore() *mockStore {
	return &mockStore{
		peers: make(map[string]string),
	}
}

func (ms *mockStore) Leader() string {
	return ms.leader
}

func (ms *mockStore) UpdateAPIPeers(peers map[string]string) error {
	for k, v := range peers {
		ms.peers[k] = v
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpc

import (
	"crypto/tls"
	"github.com/bitmark-inc/bitmarkd/announce"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/listener"
	"github.com/bitmark-inc/logger"
	"golang.org/x/crypto/sha3"
	"net"
	"net/http"
	"net/rpc"
	"strings"
	"sync"
	"time"
)

type RPCConfiguration struct {
	MaximumConnections int      `libucl:"maximum_connections" json:"maximum_connections"`
	Listen             []string `libucl:"listen" json:"listen"`
	Certificate        string   `libucl:"certificate" json:"certificate"`
	PrivateKey         string   `libucl:"private_key" json:"private_key"`
	Announce           []string `libucl:"announce" json:"announce"`
}

type HTTPSConfiguration struct {
	MaximumConnections int      `libucl:"maximum_connections" json:"maximum_connections"`
	Listen             []string `libucl:"listen" json:"listen"`
	Certificate        string   `libucl:"certificate" json:"certificate"`
	PrivateKey         string   `libucl:"private_key" json:"private_key"`
	LocalAllow         []string `libucl:"local_allow" json:"local_allow"`
}

// globals
type rpcData struct {
	sync.RWMutex // to allow locking

	log *logger.L // logger

	listener *listener.MultiListener

	httpServer *httpHandler

	// set once during initialise
	initialised bool
}

// global data
var globalData rpcData

// initialise peer backgrouds processes
func Initialise(rpcConfiguration *RPCConfiguration, httpsConfiguration *HTTPSConfiguration, version string) error {

	globalData.Lock()
	defer globalData.Unlock()

	// no need to start if already started
	if globalData.initialised {
		return fault.ErrAlreadyInitialised
	}

	log := logger.New("rpc")
	globalData.log = log
	log.Info("starting…")

	// servers
	err := initialiseRPC(rpcConfiguration, version)
	if nil != err {
		return err
	}
	err = initialiseHTTPS(httpsConfiguration, version)
	if nil != err {
		return err
	}

	// all data initialised
	globalData.initialised = true

	return nil
}

// finialise - stop all background tasks
func Finalise() error {
	globalData.Lock()
	defer globalData.Unlock()

	if !globalData.initialised {
		return fault.ErrNotInitialised
	}

	globalData.log.Info("shutting down…")
	globalData.log.Flush()

	// stop background
	globalData.listener.Stop()

	// finally...
	globalData.initialised = false

	globalData.log.Info("finished")
	globalData.log.Flush()

	return nil
}

func initialiseRPC(configuration *RPCConfiguration, version string) error {
	name := "client_rpc"
	log := globalData.log

	if configuration.MaximumConnections <= 0 {
		log.Errorf("invalid %s maximum connection limit: %d", name, configuration.MaximumConnections)
		return fault.ErrMissingParameters
	}

	if 0 == len(configuration.Listen) {
		log.Errorf("missing %s listen", name)
		return fault.ErrMissingParameters
	}

	// create limiter
	limiter := listener.NewLimiter(configuration.MaximumConnections)

	tlsConfiguration, fingerprint, err := getCertificate(log, name, configuration.Certificate, configuration.PrivateKey)
	if nil != err {
		return err
	}

	log.Infof("%s: SHA3-256 fingerprint: %x", name, fingerprint)

	log.Infof("multi listener for: %s", name)
	ml, err := listener.NewMultiListener(name, configuration.Listen, tlsConfiguration, limiter, Callback)
	if nil != err {
		log.Errorf("invalid %s listen addresses", name)
		return err
	}
	globalData.listener = ml

	// setup announce
	rpcs := make([]byte, 0, 100) // ***** FIX THIS: need a better default size
process_rpcs:
	for _, address := range configuration.Announce {
		if "" == address {
			continue process_rpcs
		}
		c, err := util.NewConnection(address)
		if nil != err {
			log.Errorf("invalid %s listen announce: %q  error: %v", name, address, err)
			return err
		}
		rpcs = append(rpcs, c.Pack()...)
	}
	err = announce.SetRPC(fingerprint, rpcs)
	if nil != err {
		log.Criticalf("announce.SetRPC error: %s", err)
		return err
	}

	server, _ := createRPCServer(log, version)
	argument := &serverArgument{
		Log:    log,
		Server: server,
	}

	log.Infof("starting server: %s  with: %v", name, argument)
	globalData.listener.Start(argument)

	return nil
}

// Start server with Test instance as a service
func initialiseHTTPS(configuration *HTTPSConfiguration, version string) error {

	name := "http_rpc"
	log := globalData.log

	if 0 == len(configuration.Listen) {
		log.Infof("disable: %s", name)
		return nil
	}

	if configuration.MaximumConnections <= 0 {
		log.Errorf("invalid %s maximum connection limit: %d", name, configuration.MaximumConnections)
		return fault.ErrMissingParameters
	}

	tlsConfiguration, fingerprint, err := getCertificate(globalData.log, name, configuration.Certificate, configuration.PrivateKey)
	if nil != err {
		return err
	}

	log.Infof("%s: SHA3-256 fingerprint: %x", name, fingerprint)

	// create access control and format strings to match http.Request.RemoteAddr
	local := make(map[string]struct{})
local_loop:
	for _, la := range configuration.LocalAllow {
		ip := net.ParseIP(strings.Trim(la, " "))
		if nil == ip {
			continue local_loop
		}
		if nil != ip.To4() {
			local[ip.String()] = struct{}{}
		} else {

			local["["+ip.String()+"]"] = struct{}{}
		}
	}

	server, node := createRPCServer(log, version)
	handler := &httpHandler{
		Log:        log,
		Server:     server,
		Node:       node,
		LocalAllow: local,
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/bitmarkd/rpc", handler.rpc)
	mux.HandleFunc("/bitmarkd/info", handler.info)
	mux.HandleFunc("/bitmarkd/info/connectors", handler.connectors)
	mux.HandleFunc("/bitmarkd/info/subscribers", handler.subscribers)
	mux.HandleFunc("/bitmarkd/local/peers", handler.peers)
	mux.HandleFunc("/", handler.root)

	for _, listen := range configuration.Listen {
		log.Infof("starting server: %s on: %q", name, listen)
		s := &http.Server{
			Addr:           listen,
			Handler:        mux,
			ReadTimeout:    10 * time.Second,
			WriteTimeout:   10 * time.Second,
			MaxHeaderBytes: 1 << 20,
			TLSConfig:      tlsConfiguration,
		}

		go func() {
			err := s.ListenAndServeTLS(configuration.Certificate, configuration.PrivateKey)
			log.Errorf("server: %s on: %q  error: %s", name, listen, err)
		}()
	}

	return nil
}

func createRPCServer(log *logger.L, version string) (*rpc.Server, *Node) {

	start := time.Now().UTC()

	assets := &Assets{
		log: log,
	}

	bitmark := &Bitmark{
		log: log,
	}

	bitmarks := &Bitmarks{
		log: log,
	}

	owner := &Owner{
		log: log,
	}

	node := &Node{
		log:     log,
		start:   start,
		version: version,
	}

	transaction := &Transaction{
		log:   log,
		start: start,
	}

	server := rpc.NewServer()

	server.Register(assets)
	server.Register(bitmark)
	server.Register(bitmarks)
	server.Register(owner)
	server.Register(node)
	server.Register(transaction)

	return server, node
}

// Verify that a set of listener parameters are valid
// and return the certificate
func getCertificate(log *logger.L, name string, certificateFileName string, keyFileName string) (*tls.Config, [32]byte, error) {

	var fingerprint [32]byte

	if !util.EnsureFileExists(certificateFileName) {
		log.Errorf("certificate: %q does not exist", certificateFileName)
		return nil, fingerprint, fault.ErrCertificateFileNotFound
	}

	if !util.EnsureFileExists(keyFileName) {
		log.Errorf("private key: %q does not exist", keyFileName)
		return nil, fingerprint, fault.ErrKeyFileNotFound
	}

	// set up TLS
	keyPair, err := tls.LoadX509KeyPair(certificateFileName, keyFileName)
	if err != nil {
		log.Errorf("%s failed to load keypair: %v", name, err)
		return nil, fingerprint, err
	}

	tlsConfiguration := &tls.Config{
		Certificates: []tls.Certificate{
			keyPair,
		},
	}

	fingerprint = CertificateFingerprint(keyPair.Certificate[0])

	return tlsConfiguration, fingerprint, nil
}

// compute the fingerprint of a certificate
//
// FreeBSD: openssl x509 -outform DER -in bitmarkd-local-rpc.crt | sha3sum -a 256
func CertificateFingerprint(certificate []byte) [32]byte {
	return sha3.Sum256(certificate)
}
<commit_msg>[rpc] fix closure problem<commit_after>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpc

import (
	"crypto/tls"
	"github.com/bitmark-inc/bitmarkd/announce"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/listener"
	"github.com/bitmark-inc/logger"
	"golang.org/x/crypto/sha3"
	"net"
	"net/http"
	"net/rpc"
	"strings"
	"sync"
	"time"
)

type RPCConfiguration struct {
	MaximumConnections int      `libucl:"maximum_connections" json:"maximum_connections"`
	Listen             []string `libucl:"listen" json:"listen"`
	Certificate        string   `libucl:"certificate" json:"certificate"`
	PrivateKey         string   `libucl:"private_key" json:"private_key"`
	Announce           []string `libucl:"announce" json:"announce"`
}

type HTTPSConfiguration struct {
	MaximumConnections int      `libucl:"maximum_connections" json:"maximum_connections"`
	Listen             []string `libucl:"listen" json:"listen"`
	Certificate        string   `libucl:"certificate" json:"certificate"`
	PrivateKey         string   `libucl:"private_key" json:"private_key"`
	LocalAllow         []string `libucl:"local_allow" json:"local_allow"`
}

// globals
type rpcData struct {
	sync.RWMutex // to allow locking

	log *logger.L // logger

	listener *listener.MultiListener

	httpServer *httpHandler

	// set once during initialise
	initialised bool
}

// global data
var globalData rpcData

// initialise peer backgrouds processes
func Initialise(rpcConfiguration *RPCConfiguration, httpsConfiguration *HTTPSConfiguration, version string) error {

	globalData.Lock()
	defer globalData.Unlock()

	// no need to start if already started
	if globalData.initialised {
		return fault.ErrAlreadyInitialised
	}

	log := logger.New("rpc")
	globalData.log = log
	log.Info("starting…")

	// servers
	err := initialiseRPC(rpcConfiguration, version)
	if nil != err {
		return err
	}
	err = initialiseHTTPS(httpsConfiguration, version)
	if nil != err {
		return err
	}

	// all data initialised
	globalData.initialised = true

	return nil
}

// finialise - stop all background tasks
func Finalise() error {
	globalData.Lock()
	defer globalData.Unlock()

	if !globalData.initialised {
		return fault.ErrNotInitialised
	}

	globalData.log.Info("shutting down…")
	globalData.log.Flush()

	// stop background
	globalData.listener.Stop()

	// finally...
	globalData.initialised = false

	globalData.log.Info("finished")
	globalData.log.Flush()

	return nil
}

func initialiseRPC(configuration *RPCConfiguration, version string) error {
	name := "client_rpc"
	log := globalData.log

	if configuration.MaximumConnections <= 0 {
		log.Errorf("invalid %s maximum connection limit: %d", name, configuration.MaximumConnections)
		return fault.ErrMissingParameters
	}

	if 0 == len(configuration.Listen) {
		log.Errorf("missing %s listen", name)
		return fault.ErrMissingParameters
	}

	// create limiter
	limiter := listener.NewLimiter(configuration.MaximumConnections)

	tlsConfiguration, fingerprint, err := getCertificate(log, name, configuration.Certificate, configuration.PrivateKey)
	if nil != err {
		return err
	}

	log.Infof("%s: SHA3-256 fingerprint: %x", name, fingerprint)

	log.Infof("multi listener for: %s", name)
	ml, err := listener.NewMultiListener(name, configuration.Listen, tlsConfiguration, limiter, Callback)
	if nil != err {
		log.Errorf("invalid %s listen addresses", name)
		return err
	}
	globalData.listener = ml

	// setup announce
	rpcs := make([]byte, 0, 100) // ***** FIX THIS: need a better default size
process_rpcs:
	for _, address := range configuration.Announce {
		if "" == address {
			continue process_rpcs
		}
		c, err := util.NewConnection(address)
		if nil != err {
			log.Errorf("invalid %s listen announce: %q  error: %v", name, address, err)
			return err
		}
		rpcs = append(rpcs, c.Pack()...)
	}
	err = announce.SetRPC(fingerprint, rpcs)
	if nil != err {
		log.Criticalf("announce.SetRPC error: %s", err)
		return err
	}

	server, _ := createRPCServer(log, version)
	argument := &serverArgument{
		Log:    log,
		Server: server,
	}

	log.Infof("starting server: %s  with: %v", name, argument)
	globalData.listener.Start(argument)

	return nil
}

// Start server with Test instance as a service
func initialiseHTTPS(configuration *HTTPSConfiguration, version string) error {

	name := "http_rpc"
	log := globalData.log

	if 0 == len(configuration.Listen) {
		log.Infof("disable: %s", name)
		return nil
	}

	if configuration.MaximumConnections <= 0 {
		log.Errorf("invalid %s maximum connection limit: %d", name, configuration.MaximumConnections)
		return fault.ErrMissingParameters
	}

	tlsConfiguration, fingerprint, err := getCertificate(globalData.log, name, configuration.Certificate, configuration.PrivateKey)
	if nil != err {
		return err
	}

	log.Infof("%s: SHA3-256 fingerprint: %x", name, fingerprint)

	// create access control and format strings to match http.Request.RemoteAddr
	local := make(map[string]struct{})
local_loop:
	for _, la := range configuration.LocalAllow {
		ip := net.ParseIP(strings.Trim(la, " "))
		if nil == ip {
			continue local_loop
		}
		if nil != ip.To4() {
			local[ip.String()] = struct{}{}
		} else {

			local["["+ip.String()+"]"] = struct{}{}
		}
	}

	server, node := createRPCServer(log, version)
	handler := &httpHandler{
		Log:        log,
		Server:     server,
		Node:       node,
		LocalAllow: local,
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/bitmarkd/rpc", handler.rpc)
	mux.HandleFunc("/bitmarkd/info", handler.info)
	mux.HandleFunc("/bitmarkd/info/connectors", handler.connectors)
	mux.HandleFunc("/bitmarkd/info/subscribers", handler.subscribers)
	mux.HandleFunc("/bitmarkd/local/peers", handler.peers)
	mux.HandleFunc("/", handler.root)

	for _, listen := range configuration.Listen {
		log.Infof("starting server: %s on: %q", name, listen)
		s := &http.Server{
			Addr:           listen,
			Handler:        mux,
			ReadTimeout:    10 * time.Second,
			WriteTimeout:   10 * time.Second,
			MaxHeaderBytes: 1 << 20,
			TLSConfig:      tlsConfiguration,
		}

		go func(s *http.Server) {
			err := s.ListenAndServeTLS(configuration.Certificate, configuration.PrivateKey)
			log.Errorf("server: %s on: %q  error: %s", name, s.Addr, err)
		}(s)
	}

	return nil
}

func createRPCServer(log *logger.L, version string) (*rpc.Server, *Node) {

	start := time.Now().UTC()

	assets := &Assets{
		log: log,
	}

	bitmark := &Bitmark{
		log: log,
	}

	bitmarks := &Bitmarks{
		log: log,
	}

	owner := &Owner{
		log: log,
	}

	node := &Node{
		log:     log,
		start:   start,
		version: version,
	}

	transaction := &Transaction{
		log:   log,
		start: start,
	}

	server := rpc.NewServer()

	server.Register(assets)
	server.Register(bitmark)
	server.Register(bitmarks)
	server.Register(owner)
	server.Register(node)
	server.Register(transaction)

	return server, node
}

// Verify that a set of listener parameters are valid
// and return the certificate
func getCertificate(log *logger.L, name string, certificateFileName string, keyFileName string) (*tls.Config, [32]byte, error) {

	var fingerprint [32]byte

	if !util.EnsureFileExists(certificateFileName) {
		log.Errorf("certificate: %q does not exist", certificateFileName)
		return nil, fingerprint, fault.ErrCertificateFileNotFound
	}

	if !util.EnsureFileExists(keyFileName) {
		log.Errorf("private key: %q does not exist", keyFileName)
		return nil, fingerprint, fault.ErrKeyFileNotFound
	}

	// set up TLS
	keyPair, err := tls.LoadX509KeyPair(certificateFileName, keyFileName)
	if err != nil {
		log.Errorf("%s failed to load keypair: %v", name, err)
		return nil, fingerprint, err
	}

	tlsConfiguration := &tls.Config{
		Certificates: []tls.Certificate{
			keyPair,
		},
	}

	fingerprint = CertificateFingerprint(keyPair.Certificate[0])

	return tlsConfiguration, fingerprint, nil
}

// compute the fingerprint of a certificate
//
// FreeBSD: openssl x509 -outform DER -in bitmarkd-local-rpc.crt | sha3sum -a 256
func CertificateFingerprint(certificate []byte) [32]byte {
	return sha3.Sum256(certificate)
}
<|endoftext|>


<commit_before>package rpcc

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"sync"

	"github.com/gorilla/websocket"
)

var (
	// ErrConnClosing indicates that the operation is illegal because
	// the connection is closing.
	ErrConnClosing = errors.New("rpcc: the connection is closing")
)

const (
	defaultWriteBufferSize = 4096

	// Fixed header size used by gorilla/websocket.
	websocketMaxHeaderSize = 2 + 8 + 4

	// Maximum message size accepted by Chrome is 1MB. It silently
	// drops the websocket connection for larger messages.
	chromeMessageSizeLimit = 1024 * 1024
)

// DialOption represents a dial option passed to Dial.
type DialOption func(*dialOptions)

// WithCodec returns a DialOption that sets the codec responsible for
// encoding and decoding requests and responses onto the connection.
// This option overrides the default json codec.
func WithCodec(f func(conn io.ReadWriter) Codec) DialOption {
	return func(o *dialOptions) {
		o.codec = f
	}
}

// WithDialer returns a DialOption that sets the dialer for the underlying
// net.Conn. This option overrides the default WebSocket dialer.
func WithDialer(f func(ctx context.Context, addr string) (net.Conn, error)) DialOption {
	return func(o *dialOptions) {
		o.dialer = f
	}
}

// WithWriteBufferSize returns a DialOption that sets the size of the write
// buffer for the underlying websocket connection. Messages larger than this
// size are fragmented according to the websocket specification.
func WithWriteBufferSize(n int) DialOption {
	return func(o *dialOptions) {
		o.wsDialer.WriteBufferSize = n
	}
}

// WithCompression returns a DialOption that enables compression for the
// underlying websocket connection. Use SetCompressionLevel on Conn to
// change the default compression level for subsequent writes.
func WithCompression() DialOption {
	return func(o *dialOptions) {
		o.wsDialer.EnableCompression = true
	}
}

type dialOptions struct {
	codec    func(io.ReadWriter) Codec
	dialer   func(context.Context, string) (net.Conn, error)
	wsDialer websocket.Dialer
}

// Dial connects to target and returns an active connection.
// The target should be a WebSocket URL, format:
// "ws://localhost:9222/target".
func Dial(target string, opts ...DialOption) (*Conn, error) {
	return DialContext(context.Background(), target, opts...)
}

// DialContext is like Dial, with a caller provided Context.
// A nil Context will panic.
func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *Conn, err error) {
	if ctx == nil {
		panic("nil Context")
	}

	c := &Conn{
		pending: make(map[uint64]*rpcCall),
		streams: make(map[string]*streamClients),
	}
	c.ctx, c.cancel = context.WithCancel(context.Background())

	defer func() {
		select {
		case <-ctx.Done():
			conn, err = nil, ctx.Err()
		default:
		}
		if err != nil {
			c.Close()
		}
	}()

	for _, o := range opts {
		o(&c.dialOpts)
	}

	netDial := c.dialOpts.dialer
	if netDial == nil {
		netDial = func(ctx context.Context, addr string) (net.Conn, error) {
			ws := &c.dialOpts.wsDialer

			if ws.WriteBufferSize == 0 {
				// Set the default size for use in writeLimiter.
				ws.WriteBufferSize = defaultWriteBufferSize
			}

			// Base writeLimit on the buffer size allocated by the
			// websocket package, we assume a message of this size
			// is fragmented and subtract one.
			writeLimit := ws.WriteBufferSize + websocketMaxHeaderSize - 1
			if writeLimit > chromeMessageSizeLimit {
				writeLimit = chromeMessageSizeLimit
			}

			// Set NetDial to dial with context, this action will
			// override the HandshakeTimeout setting.
			ws.NetDial = func(network, addr string) (net.Conn, error) {
				conn, err := (&net.Dialer{}).DialContext(ctx, network, addr)
				return &writeLimiter{
					limit: writeLimit,
					Conn:  conn,
				}, err
			}

			wsConn, _, err := ws.Dial(addr, nil)
			if err != nil {
				return nil, err
			}

			if ws.EnableCompression {
				c.compressionLevel = wsConn.SetCompressionLevel
			}

			return &wsNetConn{conn: wsConn}, nil
		}
	}

	c.conn, err = netDial(ctx, target)
	if err != nil {
		return nil, err
	}
	newCodec := c.dialOpts.codec
	if newCodec == nil {
		newCodec = func(conn io.ReadWriter) Codec {
			return &jsonCodec{
				enc: json.NewEncoder(conn),
				dec: json.NewDecoder(conn),
			}
		}
	}
	c.codec = newCodec(c.conn)

	recvDone := func(err error) {
		// When we receive Inspector.detached the remote will close
		// the connection afterwards and recvDone will return. Maybe
		// we could give the user time to react to the event before
		// closing?
		// TODO(mafredri): Do we want to close here, like this?
		c.close(err)
	}
	go c.recv(c.notify, recvDone)

	return c, nil
}

// writeLimiter wraps a net.Conn and prevents writes of greater length
// than limit. Works around Chrome's lack of support for large or
// fragmented websocket messages and prevents sudden termination of the
// websocket connection. Gives the user an actionable error message when
// writes exceed limit.
type writeLimiter struct {
	limit int
	net.Conn
}

// BUG(mafredri): Chrome does not support websocket fragmentation
// (continuation messages) or messages that exceed 1 MB in size.
// See https://github.com/mafredri/cdp/issues/4.
func (c *writeLimiter) Write(b []byte) (n int, err error) {
	if len(b) > c.limit {
		return 0, errors.New("rpcc: message too large (increase write buffer size or enable compression)")
	}
	return c.Conn.Write(b)
}
func (c *writeLimiter) Read(b []byte) (n int, err error) {
	return c.Conn.Read(b)
}

// Codec is used by recv and dispatcher to
// send and receive RPC communication.
type Codec interface {
	// WriteRequest encodes and writes the request onto the
	// underlying connection. Request is re-used between writes and
	// references to it should not be kept.
	WriteRequest(*Request) error
	// ReadResponse decodes a response from the underlying
	// connection. Response is re-used between reads and references
	// to it should not be kept.
	ReadResponse(*Response) error
}

// jsonCodec implements codec.
type jsonCodec struct {
	enc *json.Encoder
	dec *json.Decoder
}

func (c *jsonCodec) WriteRequest(r *Request) error  { return c.enc.Encode(r) }
func (c *jsonCodec) ReadResponse(r *Response) error { return c.dec.Decode(r) }

// Conn represents an active RPC connection.
type Conn struct {
	ctx    context.Context
	cancel context.CancelFunc

	dialOpts dialOptions
	conn     net.Conn

	compressionLevel func(level int) error

	mu      sync.Mutex // Protects following.
	closed  bool
	reqSeq  uint64
	pending map[uint64]*rpcCall

	reqMu sync.Mutex // Protects following.
	req   Request
	// Encodes and decodes JSON onto conn. Encoding is
	// guarded by mutex and decoding is done by recv.
	codec Codec

	streamMu sync.Mutex // Protects following.
	streams  map[string]*streamClients
}

// Response represents an RPC response or notification sent by the server.
type Response struct {
	// RPC response to a Request.
	ID     uint64          `json:"id"`     // Echoes that of the Request.
	Result json.RawMessage `json:"result"` // Result from invokation, if any.
	Error  *ResponseError  `json:"error"`  // Error, if any.

	// RPC notification from remote.
	Method string          `json:"method"` // Method invokation requested by remote.
	Args   json.RawMessage `json:"params"` // Method parameters, if any.
}

func (r *Response) reset() {
	r.ID = 0
	r.Result = nil
	r.Error = nil
	r.Method = ""
	r.Args = nil
}

func (r *Response) String() string {
	if r.Method != "" {
		return fmt.Sprintf("Method = %s, Params = %s", r.Method, r.Args)
	}
	if r.Error != nil {
		return fmt.Sprintf("ID = %d, Error = %s", r.ID, r.Error.Error())
	}
	return fmt.Sprintf("ID = %d, Result = %s", r.ID, r.Result)
}

// ResponseError represents the RPC response error sent by the server.
type ResponseError struct {
	Code    int64  `json:"code"`
	Message string `json:"message"`
	Data    string `json:"data"`
}

func (e *ResponseError) Error() string {
	var data string
	if e.Data != "" {
		data = ", data = " + e.Data
	}
	return fmt.Sprintf("rpc error: %s (code = %d%s)", e.Message, e.Code, data)
}

var (
	_ error = (*ResponseError)(nil)
)

// recv decodes and handles RPC responses. Responses to RPC requests
// are forwarded to the pending call, if any. RPC Notifications are
// forwarded by calling notify, synchronously.
func (c *Conn) recv(notify func(string, []byte), done func(error)) {
	var resp Response
	var err error
	for {
		resp.reset()
		if err = c.codec.ReadResponse(&resp); err != nil {
			done(err)
			return
		}

		// Check if this is an RPC notification from the server.
		if resp.Method != "" {
			// Method represents the event that was triggered over the
			// Chrome Debugging Protocol. We do not expect to receive
			// RPC requests, if this was one, the ID field would be set.
			notify(resp.Method, resp.Args)
			continue
		}

		c.mu.Lock()
		call := c.pending[resp.ID]
		delete(c.pending, resp.ID)
		c.mu.Unlock()

		switch {
		case call == nil:
			// No pending call, this could mean there was an error during
			// send or the server sent an unexpected response.
			if enableDebug {
				log.Println("rpcc: no pending call: " + resp.String())
			}
		case resp.Error != nil:
			call.done(resp.Error)
		default:
			var err error
			if call.Reply != nil {
				if err = json.Unmarshal(resp.Result, call.Reply); err != nil {
					err = fmt.Errorf("rpcc: decoding %s: %s", call.Method, err.Error())
				}
			}
			call.done(err)
		}
	}
}

// Request represents an RPC request to be sent to the server.
type Request struct {
	ID     uint64      `json:"id"`               // ID chosen by client.
	Method string      `json:"method"`           // Method invoked on remote.
	Args   interface{} `json:"params,omitempty"` // Method parameters, if any.
}

// send returns after the call has successfully been dispatched over
// the RPC connection.
func (c *Conn) send(ctx context.Context, call *rpcCall) (err error) {
	defer func() {
		// Give precedence for user cancellation.
		select {
		case <-ctx.Done():
			err = ctx.Err()
		default:
		}
	}()

	c.mu.Lock()
	if c.closed {
		c.mu.Unlock()
		return ErrConnClosing
	}
	c.reqSeq++
	reqID := c.reqSeq
	c.pending[reqID] = call
	c.mu.Unlock()

	done := make(chan error, 1)
	go func() {
		c.reqMu.Lock()
		c.req.ID = reqID
		c.req.Method = call.Method
		c.req.Args = call.Args

		err := c.codec.WriteRequest(&c.req)

		c.req.Args = nil
		c.reqMu.Unlock()
		done <- err
	}()

	// Abort on user or connection cancellation.
	select {
	case <-ctx.Done():
		err = ctx.Err()
	case err = <-done:
	}

	if err != nil {
		// Remove reference on error, avoid
		// unnecessary work in recv.
		c.mu.Lock()
		delete(c.pending, reqID)
		c.mu.Unlock()
		return err
	}

	return nil
}

// notify handles RPC notifications and sends them
// to the appropriate stream listeners.
func (c *Conn) notify(method string, data []byte) {
	c.streamMu.Lock()
	stream := c.streams[method]
	if stream != nil {
		stream.send(data)
	}
	c.streamMu.Unlock()
}

// listen registers a new stream listener (chan) for the RPC notification
// method. Returns a function for removing the listener. Error if the
// connection is closed.
func (c *Conn) listen(method string, client *streamClient) (func(), error) {
	c.streamMu.Lock()
	defer c.streamMu.Unlock()

	if c.streams == nil {
		return nil, ErrConnClosing
	}

	stream, ok := c.streams[method]
	if !ok {
		stream = newStreamService()
		c.streams[method] = stream
	}
	seq := stream.add(client)

	return func() { stream.remove(seq) }, nil
}

// Close closes the connection.
func (c *Conn) close(err error) error {
	c.cancel()

	c.mu.Lock()
	if c.closed {
		c.mu.Unlock()
		return ErrConnClosing
	}
	c.closed = true
	if err == nil {
		err = ErrConnClosing
	}
	for id, call := range c.pending {
		delete(c.pending, id)
		call.done(err)
	}
	c.mu.Unlock()

	// Stop sending on all streams.
	c.streamMu.Lock()
	c.streams = nil
	c.streamMu.Unlock()

	// Conn can be nil if DialContext did not complete.
	if c.conn != nil {
		err = c.conn.Close()
	}

	return err
}

// SetCompressionLevel sets the flate compressions level for writes. Valid level
// range is [-2, 9]. Returns error if compression is not eanbled for Conn. See
// package compress/flate for a description of compression levels.
func (c *Conn) SetCompressionLevel(level int) error {
	if c.compressionLevel == nil {
		return errors.New("rpcc: compression is not enabled for Conn")
	}
	return c.compressionLevel(level)
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.close(nil)
}

// Debugging, enabled in tests.
var enableDebug = false
<commit_msg>rpcc: Remove hard-coded 1MB write buffer size limit<commit_after>package rpcc

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"sync"

	"github.com/gorilla/websocket"
)

var (
	// ErrConnClosing indicates that the operation is illegal because
	// the connection is closing.
	ErrConnClosing = errors.New("rpcc: the connection is closing")
)

const (
	defaultWriteBufferSize = 4096

	// Fixed header size used by gorilla/websocket.
	websocketMaxHeaderSize = 2 + 8 + 4
)

// DialOption represents a dial option passed to Dial.
type DialOption func(*dialOptions)

// WithCodec returns a DialOption that sets the codec responsible for
// encoding and decoding requests and responses onto the connection.
// This option overrides the default json codec.
func WithCodec(f func(conn io.ReadWriter) Codec) DialOption {
	return func(o *dialOptions) {
		o.codec = f
	}
}

// WithDialer returns a DialOption that sets the dialer for the underlying
// net.Conn. This option overrides the default WebSocket dialer.
func WithDialer(f func(ctx context.Context, addr string) (net.Conn, error)) DialOption {
	return func(o *dialOptions) {
		o.dialer = f
	}
}

// WithWriteBufferSize returns a DialOption that sets the size of the write
// buffer for the underlying websocket connection. Messages larger than this
// size are fragmented according to the websocket specification.
//
// The maximum buffer size for recent versions of Chrome is 104857586 (~100MB),
// for older versions a maximum of 1048562 (~1MB) can be used. This is because
// Chrome does not support websocket fragmentation.
func WithWriteBufferSize(n int) DialOption {
	return func(o *dialOptions) {
		o.wsDialer.WriteBufferSize = n
	}
}

// WithCompression returns a DialOption that enables compression for the
// underlying websocket connection. Use SetCompressionLevel on Conn to
// change the default compression level for subsequent writes.
func WithCompression() DialOption {
	return func(o *dialOptions) {
		o.wsDialer.EnableCompression = true
	}
}

type dialOptions struct {
	codec    func(io.ReadWriter) Codec
	dialer   func(context.Context, string) (net.Conn, error)
	wsDialer websocket.Dialer
}

// Dial connects to target and returns an active connection.
// The target should be a WebSocket URL, format:
// "ws://localhost:9222/target".
func Dial(target string, opts ...DialOption) (*Conn, error) {
	return DialContext(context.Background(), target, opts...)
}

// DialContext is like Dial, with a caller provided Context.
// A nil Context will panic.
func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *Conn, err error) {
	if ctx == nil {
		panic("nil Context")
	}

	c := &Conn{
		pending: make(map[uint64]*rpcCall),
		streams: make(map[string]*streamClients),
	}
	c.ctx, c.cancel = context.WithCancel(context.Background())

	defer func() {
		select {
		case <-ctx.Done():
			conn, err = nil, ctx.Err()
		default:
		}
		if err != nil {
			c.Close()
		}
	}()

	for _, o := range opts {
		o(&c.dialOpts)
	}

	netDial := c.dialOpts.dialer
	if netDial == nil {
		netDial = func(ctx context.Context, addr string) (net.Conn, error) {
			ws := &c.dialOpts.wsDialer

			if ws.WriteBufferSize == 0 {
				// Set the default size for use in writeLimiter.
				ws.WriteBufferSize = defaultWriteBufferSize
			}

			// Base writeLimit on the buffer size allocated by the
			// websocket package, we assume a message of this size
			// is fragmented and subtract one.
			writeLimit := ws.WriteBufferSize + websocketMaxHeaderSize - 1

			// Set NetDial to dial with context, this action will
			// override the HandshakeTimeout setting.
			ws.NetDial = func(network, addr string) (net.Conn, error) {
				conn, err := (&net.Dialer{}).DialContext(ctx, network, addr)
				return &writeLimiter{
					limit: writeLimit,
					Conn:  conn,
				}, err
			}

			wsConn, _, err := ws.Dial(addr, nil)
			if err != nil {
				return nil, err
			}

			if ws.EnableCompression {
				c.compressionLevel = wsConn.SetCompressionLevel
			}

			return &wsNetConn{conn: wsConn}, nil
		}
	}

	c.conn, err = netDial(ctx, target)
	if err != nil {
		return nil, err
	}
	newCodec := c.dialOpts.codec
	if newCodec == nil {
		newCodec = func(conn io.ReadWriter) Codec {
			return &jsonCodec{
				enc: json.NewEncoder(conn),
				dec: json.NewDecoder(conn),
			}
		}
	}
	c.codec = newCodec(c.conn)

	recvDone := func(err error) {
		// When we receive Inspector.detached the remote will close
		// the connection afterwards and recvDone will return. Maybe
		// we could give the user time to react to the event before
		// closing?
		// TODO(mafredri): Do we want to close here, like this?
		c.close(err)
	}
	go c.recv(c.notify, recvDone)

	return c, nil
}

// writeLimiter wraps a net.Conn and prevents writes of greater length
// than limit. Works around Chrome's lack of support for large or
// fragmented websocket messages and prevents sudden termination of the
// websocket connection. Gives the user an actionable error message when
// writes exceed limit.
type writeLimiter struct {
	limit int
	net.Conn
}

// BUG(mafredri): Chrome does not support websocket fragmentation
// (continuation messages) or messages that exceed 1MB in size.
// This limit was bumped in more recent versions of Chrome which can
// receive messages up to 100MB in size.
// See https://github.com/mafredri/cdp/issues/4 and
// https://github.com/ChromeDevTools/devtools-protocol/issues/24.
func (c *writeLimiter) Write(b []byte) (n int, err error) {
	if len(b) > c.limit {
		return 0, errors.New("rpcc: message too large (increase write buffer size or enable compression)")
	}
	return c.Conn.Write(b)
}
func (c *writeLimiter) Read(b []byte) (n int, err error) {
	return c.Conn.Read(b)
}

// Codec is used by recv and dispatcher to
// send and receive RPC communication.
type Codec interface {
	// WriteRequest encodes and writes the request onto the
	// underlying connection. Request is re-used between writes and
	// references to it should not be kept.
	WriteRequest(*Request) error
	// ReadResponse decodes a response from the underlying
	// connection. Response is re-used between reads and references
	// to it should not be kept.
	ReadResponse(*Response) error
}

// jsonCodec implements codec.
type jsonCodec struct {
	enc *json.Encoder
	dec *json.Decoder
}

func (c *jsonCodec) WriteRequest(r *Request) error  { return c.enc.Encode(r) }
func (c *jsonCodec) ReadResponse(r *Response) error { return c.dec.Decode(r) }

// Conn represents an active RPC connection.
type Conn struct {
	ctx    context.Context
	cancel context.CancelFunc

	dialOpts dialOptions
	conn     net.Conn

	compressionLevel func(level int) error

	mu      sync.Mutex // Protects following.
	closed  bool
	reqSeq  uint64
	pending map[uint64]*rpcCall

	reqMu sync.Mutex // Protects following.
	req   Request
	// Encodes and decodes JSON onto conn. Encoding is
	// guarded by mutex and decoding is done by recv.
	codec Codec

	streamMu sync.Mutex // Protects following.
	streams  map[string]*streamClients
}

// Response represents an RPC response or notification sent by the server.
type Response struct {
	// RPC response to a Request.
	ID     uint64          `json:"id"`     // Echoes that of the Request.
	Result json.RawMessage `json:"result"` // Result from invokation, if any.
	Error  *ResponseError  `json:"error"`  // Error, if any.

	// RPC notification from remote.
	Method string          `json:"method"` // Method invokation requested by remote.
	Args   json.RawMessage `json:"params"` // Method parameters, if any.
}

func (r *Response) reset() {
	r.ID = 0
	r.Result = nil
	r.Error = nil
	r.Method = ""
	r.Args = nil
}

func (r *Response) String() string {
	if r.Method != "" {
		return fmt.Sprintf("Method = %s, Params = %s", r.Method, r.Args)
	}
	if r.Error != nil {
		return fmt.Sprintf("ID = %d, Error = %s", r.ID, r.Error.Error())
	}
	return fmt.Sprintf("ID = %d, Result = %s", r.ID, r.Result)
}

// ResponseError represents the RPC response error sent by the server.
type ResponseError struct {
	Code    int64  `json:"code"`
	Message string `json:"message"`
	Data    string `json:"data"`
}

func (e *ResponseError) Error() string {
	var data string
	if e.Data != "" {
		data = ", data = " + e.Data
	}
	return fmt.Sprintf("rpc error: %s (code = %d%s)", e.Message, e.Code, data)
}

var (
	_ error = (*ResponseError)(nil)
)

// recv decodes and handles RPC responses. Responses to RPC requests
// are forwarded to the pending call, if any. RPC Notifications are
// forwarded by calling notify, synchronously.
func (c *Conn) recv(notify func(string, []byte), done func(error)) {
	var resp Response
	var err error
	for {
		resp.reset()
		if err = c.codec.ReadResponse(&resp); err != nil {
			done(err)
			return
		}

		// Check if this is an RPC notification from the server.
		if resp.Method != "" {
			// Method represents the event that was triggered over the
			// Chrome Debugging Protocol. We do not expect to receive
			// RPC requests, if this was one, the ID field would be set.
			notify(resp.Method, resp.Args)
			continue
		}

		c.mu.Lock()
		call := c.pending[resp.ID]
		delete(c.pending, resp.ID)
		c.mu.Unlock()

		switch {
		case call == nil:
			// No pending call, this could mean there was an error during
			// send or the server sent an unexpected response.
			if enableDebug {
				log.Println("rpcc: no pending call: " + resp.String())
			}
		case resp.Error != nil:
			call.done(resp.Error)
		default:
			var err error
			if call.Reply != nil {
				if err = json.Unmarshal(resp.Result, call.Reply); err != nil {
					err = fmt.Errorf("rpcc: decoding %s: %s", call.Method, err.Error())
				}
			}
			call.done(err)
		}
	}
}

// Request represents an RPC request to be sent to the server.
type Request struct {
	ID     uint64      `json:"id"`               // ID chosen by client.
	Method string      `json:"method"`           // Method invoked on remote.
	Args   interface{} `json:"params,omitempty"` // Method parameters, if any.
}

// send returns after the call has successfully been dispatched over
// the RPC connection.
func (c *Conn) send(ctx context.Context, call *rpcCall) (err error) {
	defer func() {
		// Give precedence for user cancellation.
		select {
		case <-ctx.Done():
			err = ctx.Err()
		default:
		}
	}()

	c.mu.Lock()
	if c.closed {
		c.mu.Unlock()
		return ErrConnClosing
	}
	c.reqSeq++
	reqID := c.reqSeq
	c.pending[reqID] = call
	c.mu.Unlock()

	done := make(chan error, 1)
	go func() {
		c.reqMu.Lock()
		c.req.ID = reqID
		c.req.Method = call.Method
		c.req.Args = call.Args

		err := c.codec.WriteRequest(&c.req)

		c.req.Args = nil
		c.reqMu.Unlock()
		done <- err
	}()

	// Abort on user or connection cancellation.
	select {
	case <-ctx.Done():
		err = ctx.Err()
	case err = <-done:
	}

	if err != nil {
		// Remove reference on error, avoid
		// unnecessary work in recv.
		c.mu.Lock()
		delete(c.pending, reqID)
		c.mu.Unlock()
		return err
	}

	return nil
}

// notify handles RPC notifications and sends them
// to the appropriate stream listeners.
func (c *Conn) notify(method string, data []byte) {
	c.streamMu.Lock()
	stream := c.streams[method]
	if stream != nil {
		stream.send(data)
	}
	c.streamMu.Unlock()
}

// listen registers a new stream listener (chan) for the RPC notification
// method. Returns a function for removing the listener. Error if the
// connection is closed.
func (c *Conn) listen(method string, client *streamClient) (func(), error) {
	c.streamMu.Lock()
	defer c.streamMu.Unlock()

	if c.streams == nil {
		return nil, ErrConnClosing
	}

	stream, ok := c.streams[method]
	if !ok {
		stream = newStreamService()
		c.streams[method] = stream
	}
	seq := stream.add(client)

	return func() { stream.remove(seq) }, nil
}

// Close closes the connection.
func (c *Conn) close(err error) error {
	c.cancel()

	c.mu.Lock()
	if c.closed {
		c.mu.Unlock()
		return ErrConnClosing
	}
	c.closed = true
	if err == nil {
		err = ErrConnClosing
	}
	for id, call := range c.pending {
		delete(c.pending, id)
		call.done(err)
	}
	c.mu.Unlock()

	// Stop sending on all streams.
	c.streamMu.Lock()
	c.streams = nil
	c.streamMu.Unlock()

	// Conn can be nil if DialContext did not complete.
	if c.conn != nil {
		err = c.conn.Close()
	}

	return err
}

// SetCompressionLevel sets the flate compressions level for writes. Valid level
// range is [-2, 9]. Returns error if compression is not eanbled for Conn. See
// package compress/flate for a description of compression levels.
func (c *Conn) SetCompressionLevel(level int) error {
	if c.compressionLevel == nil {
		return errors.New("rpcc: compression is not enabled for Conn")
	}
	return c.compressionLevel(level)
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.close(nil)
}

// Debugging, enabled in tests.
var enableDebug = false
<|endoftext|>


<commit_before>/*
RpcClient for Go RPC Servers
Copyright (C) 2012-2014 ITsysCOM GmbH

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package rpcclient

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
	"strings"
	"time"
)

var JSON_RPC = "json"
var JSON_HTTP = "http_jsonrpc"
var GOB_RPC = "gob"
var ReqUnsynchronized = errors.New("REQ_UNSYNCHRONIZED")

func NewRpcClient(transport, addr string, reconnects int, codec string) (*RpcClient, error) {
	rpcClient := &RpcClient{transport: transport, address: addr, reconnects: reconnects, codec: codec}
	if err := rpcClient.connect(); err != nil { // No point in configuring if not possible to establish a connection
		return nil, err
	}
	return rpcClient, nil
}

type RpcClient struct {
	transport  string
	address    string
	reconnects int
	codec      string // JSON_RPC or GOB_RPC
	connection RpcClientConnection
}

func (self *RpcClient) connect() (err error) {
	switch self.codec {
	case JSON_RPC:
		self.connection, err = jsonrpc.Dial(self.transport, self.address)
	case JSON_HTTP:
		self.connection = &HttpJsonRpcClient{httpClient: new(http.Client), url: self.address}
	default:
		self.connection, err = rpc.Dial(self.transport, self.address)
	}
	return nil
}

func (self *RpcClient) reconnect() (err error) {
	if self.codec == JSON_HTTP { // http client has automatic reconnects in place
		return self.connect()
	}
	i := 0
	for {
		if i != -1 && i >= self.reconnects { // Maximum reconnects reached, -1 for infinite reconnects
			break
		}
		if err = self.connect(); err == nil { // No error on connect, succcess
			return nil
		}
		time.Sleep(time.Duration(i/2) * time.Second) // Cound not reconnect, retry
	}
	return errors.New("RECONNECT_FAIL")
}

func (self *RpcClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
	err := self.connection.Call(serviceMethod, args, reply)
	if err != nil && (err == rpc.ErrShutdown || err == ReqUnsynchronized) && self.reconnects != 0 {
		if errReconnect := self.reconnect(); errReconnect != nil {
			return err
		} else { // Run command after reconnect
			return self.connection.Call(serviceMethod, args, reply)
		}
	}
	return err
}

// Connection used in RpcClient, as interface so we can combine the rpc.RpcClient with http one or websocket
type RpcClientConnection interface {
	Call(string, interface{}, interface{}) error
}

// Response received for
type JsonRpcResponse struct {
	Id     uint64
	Result *json.RawMessage
	Error  interface{}
}

type HttpJsonRpcClient struct {
	httpClient *http.Client
	id         uint64
	url        string
}

func (self *HttpJsonRpcClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
	self.id += 1
	id := self.id
	data, err := json.Marshal(map[string]interface{}{
		"method": serviceMethod,
		"id":     self.id,
		"params": [1]interface{}{args},
	})
	if err != nil {
		return err
	}
	resp, err := self.httpClient.Post(self.url, "application/json", ioutil.NopCloser(strings.NewReader(string(data)))) // Closer so we automatically have close after response
	if err != nil {
		return err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	var jsonRsp JsonRpcResponse
	err = json.Unmarshal(body, &jsonRsp)
	if err != nil {
		return err
	}
	if jsonRsp.Id != id {
		return ReqUnsynchronized
	}
	if jsonRsp.Error != nil || jsonRsp.Result == nil {
		x, ok := jsonRsp.Error.(string)
		if !ok {
			return fmt.Errorf("invalid error %v", jsonRsp.Error)
		}
		if x == "" {
			x = "unspecified error"
		}
		return errors.New(x)
	}
	return json.Unmarshal(*jsonRsp.Result, reply)
}
<commit_msg>Pass error from connect back to caller<commit_after>/*
RpcClient for Go RPC Servers
Copyright (C) 2012-2014 ITsysCOM GmbH

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package rpcclient

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
	"strings"
	"time"
)

var JSON_RPC = "json"
var JSON_HTTP = "http_jsonrpc"
var GOB_RPC = "gob"
var ReqUnsynchronized = errors.New("REQ_UNSYNCHRONIZED")

func NewRpcClient(transport, addr string, reconnects int, codec string) (*RpcClient, error) {
	rpcClient := &RpcClient{transport: transport, address: addr, reconnects: reconnects, codec: codec}
	if err := rpcClient.connect(); err != nil { // No point in configuring if not possible to establish a connection
		return nil, err
	}
	return rpcClient, nil
}

type RpcClient struct {
	transport  string
	address    string
	reconnects int
	codec      string // JSON_RPC or GOB_RPC
	connection RpcClientConnection
}

func (self *RpcClient) connect() (err error) {
	switch self.codec {
	case JSON_RPC:
		self.connection, err = jsonrpc.Dial(self.transport, self.address)
	case JSON_HTTP:
		self.connection = &HttpJsonRpcClient{httpClient: new(http.Client), url: self.address}
	default:
		self.connection, err = rpc.Dial(self.transport, self.address)
	}
	if err != nil {
		return err
	}
	return nil
}

func (self *RpcClient) reconnect() (err error) {
	if self.codec == JSON_HTTP { // http client has automatic reconnects in place
		return self.connect()
	}
	i := 0
	for {
		if i != -1 && i >= self.reconnects { // Maximum reconnects reached, -1 for infinite reconnects
			break
		}
		if err = self.connect(); err == nil { // No error on connect, succcess
			return nil
		}
		time.Sleep(time.Duration(i/2) * time.Second) // Cound not reconnect, retry
	}
	return errors.New("RECONNECT_FAIL")
}

func (self *RpcClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
	err := self.connection.Call(serviceMethod, args, reply)
	if err != nil && (err == rpc.ErrShutdown || err == ReqUnsynchronized) && self.reconnects != 0 {
		if errReconnect := self.reconnect(); errReconnect != nil {
			return err
		} else { // Run command after reconnect
			return self.connection.Call(serviceMethod, args, reply)
		}
	}
	return err
}

// Connection used in RpcClient, as interface so we can combine the rpc.RpcClient with http one or websocket
type RpcClientConnection interface {
	Call(string, interface{}, interface{}) error
}

// Response received for
type JsonRpcResponse struct {
	Id     uint64
	Result *json.RawMessage
	Error  interface{}
}

type HttpJsonRpcClient struct {
	httpClient *http.Client
	id         uint64
	url        string
}

func (self *HttpJsonRpcClient) Call(serviceMethod string, args interface{}, reply interface{}) error {
	self.id += 1
	id := self.id
	data, err := json.Marshal(map[string]interface{}{
		"method": serviceMethod,
		"id":     self.id,
		"params": [1]interface{}{args},
	})
	if err != nil {
		return err
	}
	resp, err := self.httpClient.Post(self.url, "application/json", ioutil.NopCloser(strings.NewReader(string(data)))) // Closer so we automatically have close after response
	if err != nil {
		return err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	var jsonRsp JsonRpcResponse
	err = json.Unmarshal(body, &jsonRsp)
	if err != nil {
		return err
	}
	if jsonRsp.Id != id {
		return ReqUnsynchronized
	}
	if jsonRsp.Error != nil || jsonRsp.Result == nil {
		x, ok := jsonRsp.Error.(string)
		if !ok {
			return fmt.Errorf("invalid error %v", jsonRsp.Error)
		}
		if x == "" {
			x = "unspecified error"
		}
		return errors.New(x)
	}
	return json.Unmarshal(*jsonRsp.Result, reply)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"flag"
	"fmt"
	"os"
	"path/filepath"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"

	"gopkg.in/reform.v1"
	"gopkg.in/reform.v1/internal"
)

var (
	logger *internal.Logger

	debugF  = flag.Bool("debug", false, "Enable debug logging")
	driverF = flag.String("db-driver", "", "database driver (required)")
	sourceF = flag.String("db-source", "", "database connection string (required)")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "reform-db. %s.\n\n", reform.Version)
		fmt.Fprintf(os.Stderr, "Usage:\n")
		fmt.Fprintf(os.Stderr, "  %s [global flags] [command] [command flags] [arguments]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Global flags:\n")
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nCommands:\n")
		fmt.Fprintf(os.Stderr, "  exec  - executes SQL queries from given files or stdin\n")
		fmt.Fprintf(os.Stderr, "  query - executes SQL queries from given files or stdin, and returns results\n")
		fmt.Fprintf(os.Stderr, "  init  - generates Go model files for existing database schema\n")
	}
}

func getDB() *reform.DB {
	if *driverF == "" || *sourceF == "" {
		logger.Fatalf("please set both -db-driver and -db-source flags.")
	}
	sqlDB, err := sql.Open(*driverF, *sourceF)
	if err != nil {
		logger.Fatalf("failed to connect to %s %q: %s", *driverF, *sourceF, err)
	}

	// Use single connection so various session-related variables work.
	// For example: "PRAGMA foreign_keys" for SQLite3, "SET IDENTITY_INSERT" for MS SQL, etc.
	sqlDB.SetMaxIdleConns(1)
	sqlDB.SetMaxOpenConns(1)
	sqlDB.SetConnMaxLifetime(0)

	err = sqlDB.Ping()
	if err != nil {
		logger.Fatalf("failed to ping database: %s", err)
	}

	dialect := internal.DialectForDriver(*driverF)
	return reform.NewDB(sqlDB, dialect, reform.NewPrintfLogger(logger.Debugf))
}

func main() {
	flag.Parse()

	logger = internal.NewLogger("reform-db: ", *debugF)

	if flag.NArg() == 0 {
		flag.Usage()
		os.Exit(1)
	}

	switch flag.Arg(0) {
	case "exec":
		execFlags.Parse(flag.Args()[1:])
		cmdExec(getDB(), execFlags.Args())

	case "query":
		queryFlags.Parse(flag.Args()[1:])
		cmdQuery(getDB(), queryFlags.Args())

	case "init":
		initFlags.Parse(flag.Args()[1:])

		if initFlags.NArg() > 1 {
			logger.Fatalf("Expected zero or one argument for %q, got %d", "init", initFlags.NArg())
		}

		dir := initFlags.Arg(0)
		var err error
		if dir == "" {
			if dir, err = os.Getwd(); err != nil {
				logger.Fatalf("%s", err)
			}
		}
		if dir, err = filepath.Abs(dir); err != nil {
			logger.Fatalf("%s", err)
		}
		fi, err := os.Stat(dir)
		if os.IsNotExist(err) {
			logger.Fatalf("%q should be existing directory", dir)
		}
		if err != nil {
			logger.Fatalf("%s", err)
		}
		if !fi.IsDir() {
			logger.Fatalf("%q should be existing directory", dir)
		}

		cmdInit(getDB(), dir)

	default:
		flag.Usage()
		logger.Fatalf("Unexpected command %q", flag.Arg(0))
	}
}
<commit_msg>Print registered drivers.<commit_after>package main

import (
	"database/sql"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"

	"gopkg.in/reform.v1"
	"gopkg.in/reform.v1/internal"
)

var (
	logger *internal.Logger

	debugF  = flag.Bool("debug", false, "Enable debug logging")
	driverF = flag.String("db-driver", "", "database driver (required)")
	sourceF = flag.String("db-source", "", "database connection string (required)")
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "reform-db. %s.\n\n", reform.Version)
		fmt.Fprintf(os.Stderr, "Usage:\n")
		fmt.Fprintf(os.Stderr, "  %s [global flags] [command] [command flags] [arguments]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Global flags:\n")
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nCommands:\n")
		fmt.Fprintf(os.Stderr, "  exec  - executes SQL queries from given files or stdin\n")
		fmt.Fprintf(os.Stderr, "  query - executes SQL queries from given files or stdin, and returns results\n")
		fmt.Fprintf(os.Stderr, "  init  - generates Go model files for existing database schema\n\n")
		fmt.Fprintf(os.Stderr, "Registered database drivers: %s.", strings.Join(sql.Drivers(), ", "))
	}
}

func getDB() *reform.DB {
	if *driverF == "" || *sourceF == "" {
		logger.Fatalf("please set both -db-driver and -db-source flags.")
	}
	sqlDB, err := sql.Open(*driverF, *sourceF)
	if err != nil {
		logger.Fatalf("failed to connect to %s %q: %s", *driverF, *sourceF, err)
	}

	// Use single connection so various session-related variables work.
	// For example: "PRAGMA foreign_keys" for SQLite3, "SET IDENTITY_INSERT" for MS SQL, etc.
	sqlDB.SetMaxIdleConns(1)
	sqlDB.SetMaxOpenConns(1)
	sqlDB.SetConnMaxLifetime(0)

	err = sqlDB.Ping()
	if err != nil {
		logger.Fatalf("failed to ping database: %s", err)
	}

	dialect := internal.DialectForDriver(*driverF)
	return reform.NewDB(sqlDB, dialect, reform.NewPrintfLogger(logger.Debugf))
}

func main() {
	flag.Parse()

	logger = internal.NewLogger("reform-db: ", *debugF)

	if flag.NArg() == 0 {
		flag.Usage()
		os.Exit(1)
	}

	switch flag.Arg(0) {
	case "exec":
		execFlags.Parse(flag.Args()[1:])
		cmdExec(getDB(), execFlags.Args())

	case "query":
		queryFlags.Parse(flag.Args()[1:])
		cmdQuery(getDB(), queryFlags.Args())

	case "init":
		initFlags.Parse(flag.Args()[1:])

		if initFlags.NArg() > 1 {
			logger.Fatalf("Expected zero or one argument for %q, got %d", "init", initFlags.NArg())
		}

		dir := initFlags.Arg(0)
		var err error
		if dir == "" {
			if dir, err = os.Getwd(); err != nil {
				logger.Fatalf("%s", err)
			}
		}
		if dir, err = filepath.Abs(dir); err != nil {
			logger.Fatalf("%s", err)
		}
		fi, err := os.Stat(dir)
		if os.IsNotExist(err) {
			logger.Fatalf("%q should be existing directory", dir)
		}
		if err != nil {
			logger.Fatalf("%s", err)
		}
		if !fi.IsDir() {
			logger.Fatalf("%q should be existing directory", dir)
		}

		cmdInit(getDB(), dir)

	default:
		flag.Usage()
		logger.Fatalf("Unexpected command %q", flag.Arg(0))
	}
}
<|endoftext|>