<commit_before>// Copyright 2017 Pilosa Corp.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

package pilosa

import (
	"encoding/json"
	"errors"
	"fmt"

	pbuf "github.com/pilosa/go-pilosa/gopilosa_pbuf"
)

// QueryResponse types.
const (
	QueryResultTypeNil uint32 = iota
	QueryResultTypeBitmap
	QueryResultTypePairs
	QueryResultTypeSumCount
	QueryResultTypeUint64
	QueryResultTypeBool
)

// QueryResponse represents the response from a Pilosa query.
type QueryResponse struct {
	ResultList   []QueryResult `json:"results,omitempty"`
	ColumnList   []ColumnItem  `json:"columns,omitempty"`
	ErrorMessage string        `json:"error-message,omitempty"`
	Success      bool          `json:"success,omitempty"`
}

func newQueryResponseFromInternal(response *pbuf.QueryResponse) (*QueryResponse, error) {
	if response.Err != "" {
		return &QueryResponse{
			ErrorMessage: response.Err,
			Success:      false,
		}, nil
	}
	results := make([]QueryResult, 0, len(response.Results))
	for _, r := range response.Results {
		result, err := newQueryResultFromInternal(r)
		if err != nil {
			return nil, err
		}
		results = append(results, result)
	}
	columns := make([]ColumnItem, 0, len(response.ColumnAttrSets))
	for _, p := range response.ColumnAttrSets {
		columnItem, err := newColumnItemFromInternal(p)
		if err != nil {
			return nil, err
		}
		columns = append(columns, columnItem)
	}

	return &QueryResponse{
		ResultList: results,
		ColumnList: columns,
		Success:    true,
	}, nil
}

// Results returns all results in the response.
func (qr *QueryResponse) Results() []QueryResult {
	return qr.ResultList
}

// Result returns the first result or nil.
func (qr *QueryResponse) Result() QueryResult {
	if len(qr.ResultList) == 0 {
		return nil
	}
	return qr.ResultList[0]
}

// Columns returns all columns in the response.
func (qr *QueryResponse) Columns() []ColumnItem {
	return qr.ColumnList
}

// Column returns the first column.
func (qr *QueryResponse) Column() ColumnItem {
	if len(qr.ColumnList) == 0 {
		return ColumnItem{}
	}
	return qr.ColumnList[0]
}

// QueryResult represents one of the results in the response.
type QueryResult interface {
	Type() uint32
	Bitmap() BitmapResult
	CountItems() []CountResultItem
	Count() int64
	Sum() int64
	Changed() bool
}

func newQueryResultFromInternal(result *pbuf.QueryResult) (QueryResult, error) {
	switch result.Type {
	case QueryResultTypeNil:
		return NilResult{}, nil
	case QueryResultTypeBitmap:
		return newBitmapResultFromInternal(result.Bitmap)
	case QueryResultTypePairs:
		return countItemsFromInternal(result.Pairs), nil
	case QueryResultTypeSumCount:
		return &SumCountResult{
			sum:   result.SumCount.Sum,
			count: result.SumCount.Count,
		}, nil
	case QueryResultTypeUint64:
		return IntResult(result.N), nil
	case QueryResultTypeBool:
		return BoolResult(result.Changed), nil
	}
	return nil, ErrUnknownType
}

// CountResultItem represents a result from TopN call.
type CountResultItem struct {
	ID    uint64 `json:"id"`
	Key   string `json:"key,omitempty"`
	Count uint64 `json:"count"`
}

func (c *CountResultItem) String() string {
	if c.Key != "" {
		return fmt.Sprintf("%s:%d", c.Key, c.Count)
	}
	return fmt.Sprintf("%d:%d", c.ID, c.Count)
}

func countItemsFromInternal(items []*pbuf.Pair) TopNResult {
	result := make([]CountResultItem, 0, len(items))
	for _, v := range items {
		result = append(result, CountResultItem{ID: v.ID, Key: v.Key, Count: v.Count})
	}
	return TopNResult(result)
}

type TopNResult []CountResultItem

func (TopNResult) Type() uint32                    { return QueryResultTypePairs }
func (TopNResult) Bitmap() BitmapResult            { return BitmapResult{} }
func (t TopNResult) CountItems() []CountResultItem { return t }
func (TopNResult) Count() int64                    { return 0 }
func (TopNResult) Sum() int64                      { return 0 }
func (TopNResult) Changed() bool                   { return false }

// BitmapResult represents a result from Bitmap, Union, Intersect, Difference and Range PQL calls.
type BitmapResult struct {
	Attributes map[string]interface{} `json:"attrs"`
	Bits       []uint64               `json:"bits"`
	Keys       []string               `json:"keys"`
}

func newBitmapResultFromInternal(bitmap *pbuf.Bitmap) (*BitmapResult, error) {
	attrs, err := convertInternalAttrsToMap(bitmap.Attrs)
	if err != nil {
		return nil, err
	}
	result := &BitmapResult{
		Attributes: attrs,
		Bits:       bitmap.Bits,
		Keys:       bitmap.Keys,
	}
	return result, nil
}

func (BitmapResult) Type() uint32                  { return QueryResultTypeBitmap }
func (b BitmapResult) Bitmap() BitmapResult        { return b }
func (BitmapResult) CountItems() []CountResultItem { return nil }
func (BitmapResult) Count() int64                  { return 0 }
func (BitmapResult) Sum() int64                    { return 0 }
func (BitmapResult) Changed() bool                 { return false }

func (b BitmapResult) MarshalJSON() ([]byte, error) {
	bits := b.Bits
	if bits == nil {
		bits = []uint64{}
	}
	keys := b.Keys
	if keys == nil {
		keys = []string{}
	}
	return json.Marshal(struct {
		Attributes map[string]interface{} `json:"attrs"`
		Bits       []uint64               `json:"bits"`
		Keys       []string               `json:"keys"`
	}{
		Attributes: b.Attributes,
		Bits:       bits,
		Keys:       keys,
	})
}

type SumCountResult struct {
	sum   int64
	count int64
}

func (SumCountResult) Type() uint32                  { return QueryResultTypeSumCount }
func (SumCountResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (SumCountResult) CountItems() []CountResultItem { return nil }
func (c SumCountResult) Count() int64                { return c.count }
func (c SumCountResult) Sum() int64                  { return c.sum }
func (SumCountResult) Changed() bool                 { return false }

func (c SumCountResult) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Sum   int64 `json:"sum"`
		Count int64 `json:"count"`
	}{
		Sum:   c.sum,
		Count: c.count,
	})
}

type IntResult int64

func (IntResult) Type() uint32                  { return QueryResultTypeUint64 }
func (IntResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (IntResult) CountItems() []CountResultItem { return nil }
func (i IntResult) Count() int64                { return int64(i) }
func (IntResult) Sum() int64                    { return 0 }
func (IntResult) Changed() bool                 { return false }

type BoolResult bool

func (BoolResult) Type() uint32                  { return QueryResultTypeBool }
func (BoolResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (BoolResult) CountItems() []CountResultItem { return nil }
func (BoolResult) Count() int64                  { return 0 }
func (BoolResult) Sum() int64                    { return 0 }
func (b BoolResult) Changed() bool               { return bool(b) }

type NilResult struct{}

func (NilResult) Type() uint32                  { return QueryResultTypeNil }
func (NilResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (NilResult) CountItems() []CountResultItem { return nil }
func (NilResult) Count() int64                  { return 0 }
func (NilResult) Sum() int64                    { return 0 }
func (NilResult) Changed() bool                 { return false }

const (
	stringType = 1
	intType    = 2
	boolType   = 3
	floatType  = 4
)

func convertInternalAttrsToMap(attrs []*pbuf.Attr) (attrsMap map[string]interface{}, err error) {
	attrsMap = make(map[string]interface{}, len(attrs))
	for _, attr := range attrs {
		switch attr.Type {
		case stringType:
			attrsMap[attr.Key] = attr.StringValue
		case intType:
			attrsMap[attr.Key] = attr.IntValue
		case boolType:
			attrsMap[attr.Key] = attr.BoolValue
		case floatType:
			attrsMap[attr.Key] = attr.FloatValue
		default:
			return nil, errors.New("Unknown attribute type")
		}
	}

	return attrsMap, nil
}

// ColumnItem represents data about a column.
// Column data is only returned if QueryOptions.Columns was set to true.
type ColumnItem struct {
	ID         uint64                 `json:"id,omitempty"`
	Key        string                 `json:"key,omitempty"`
	Attributes map[string]interface{} `json:"attributes,omitempty"`
}

func newColumnItemFromInternal(column *pbuf.ColumnAttrSet) (ColumnItem, error) {
	attrs, err := convertInternalAttrsToMap(column.Attrs)
	if err != nil {
		return ColumnItem{}, err
	}
	return ColumnItem{
		ID:         column.ID,
		Key:        column.Key,
		Attributes: attrs,
	}, nil
}
<commit_msg>updates<commit_after>// Copyright 2017 Pilosa Corp.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

package pilosa

import (
	"encoding/json"
	"errors"
	"fmt"

	pbuf "github.com/pilosa/go-pilosa/gopilosa_pbuf"
)

// QueryResponse types.
const (
	QueryResultTypeNil uint32 = iota
	QueryResultTypeBitmap
	QueryResultTypePairs
	QueryResultTypeSumCount
	QueryResultTypeUint64
	QueryResultTypeBool
)

// QueryResponse represents the response from a Pilosa query.
type QueryResponse struct {
	ResultList   []QueryResult `json:"results,omitempty"`
	ColumnList   []ColumnItem  `json:"columns,omitempty"`
	ErrorMessage string        `json:"error-message,omitempty"`
	Success      bool          `json:"success,omitempty"`
}

func newQueryResponseFromInternal(response *pbuf.QueryResponse) (*QueryResponse, error) {
	if response.Err != "" {
		return &QueryResponse{
			ErrorMessage: response.Err,
			Success:      false,
		}, nil
	}
	results := make([]QueryResult, 0, len(response.Results))
	for _, r := range response.Results {
		result, err := newQueryResultFromInternal(r)
		if err != nil {
			return nil, err
		}
		results = append(results, result)
	}
	columns := make([]ColumnItem, 0, len(response.ColumnAttrSets))
	for _, p := range response.ColumnAttrSets {
		columnItem, err := newColumnItemFromInternal(p)
		if err != nil {
			return nil, err
		}
		columns = append(columns, columnItem)
	}

	return &QueryResponse{
		ResultList: results,
		ColumnList: columns,
		Success:    true,
	}, nil
}

// Results returns all results in the response.
func (qr *QueryResponse) Results() []QueryResult {
	return qr.ResultList
}

// Result returns the first result or nil.
func (qr *QueryResponse) Result() QueryResult {
	if len(qr.ResultList) == 0 {
		return nil
	}
	return qr.ResultList[0]
}

// Columns returns all columns in the response.
func (qr *QueryResponse) Columns() []ColumnItem {
	return qr.ColumnList
}

// Column returns the first column.
func (qr *QueryResponse) Column() ColumnItem {
	if len(qr.ColumnList) == 0 {
		return ColumnItem{}
	}
	return qr.ColumnList[0]
}

// QueryResult represents one of the results in the response.
type QueryResult interface {
	Type() uint32
	Bitmap() BitmapResult
	CountItems() []CountResultItem
	Count() int64
	Sum() int64
	Changed() bool
}

func newQueryResultFromInternal(result *pbuf.QueryResult) (QueryResult, error) {
	switch result.Type {
	case QueryResultTypeNil:
		return NilResult{}, nil
	case QueryResultTypeBitmap:
		return newBitmapResultFromInternal(result.Bitmap)
	case QueryResultTypePairs:
		return countItemsFromInternal(result.Pairs), nil
	case QueryResultTypeSumCount:
		return &SumCountResult{
			SumValue:   result.SumCount.Sum,
			CountValue: result.SumCount.Count,
		}, nil
	case QueryResultTypeUint64:
		return IntResult(result.N), nil
	case QueryResultTypeBool:
		return BoolResult(result.Changed), nil
	}
	return nil, ErrUnknownType
}

// CountResultItem represents a result from TopN call.
type CountResultItem struct {
	ID    uint64 `json:"id"`
	Key   string `json:"key,omitempty"`
	Count uint64 `json:"count"`
}

func (c *CountResultItem) String() string {
	if c.Key != "" {
		return fmt.Sprintf("%s:%d", c.Key, c.Count)
	}
	return fmt.Sprintf("%d:%d", c.ID, c.Count)
}

func countItemsFromInternal(items []*pbuf.Pair) TopNResult {
	result := make([]CountResultItem, 0, len(items))
	for _, v := range items {
		result = append(result, CountResultItem{ID: v.ID, Key: v.Key, Count: v.Count})
	}
	return TopNResult(result)
}

type TopNResult []CountResultItem

func (TopNResult) Type() uint32                    { return QueryResultTypePairs }
func (TopNResult) Bitmap() BitmapResult            { return BitmapResult{} }
func (t TopNResult) CountItems() []CountResultItem { return t }
func (TopNResult) Count() int64                    { return 0 }
func (TopNResult) Sum() int64                      { return 0 }
func (TopNResult) Changed() bool                   { return false }

// BitmapResult represents a result from Bitmap, Union, Intersect, Difference and Range PQL calls.
type BitmapResult struct {
	Attributes map[string]interface{} `json:"attrs"`
	Bits       []uint64               `json:"bits"`
	Keys       []string               `json:"keys"`
}

func newBitmapResultFromInternal(bitmap *pbuf.Bitmap) (*BitmapResult, error) {
	attrs, err := convertInternalAttrsToMap(bitmap.Attrs)
	if err != nil {
		return nil, err
	}
	result := &BitmapResult{
		Attributes: attrs,
		Bits:       bitmap.Bits,
		Keys:       bitmap.Keys,
	}
	return result, nil
}

func (BitmapResult) Type() uint32                  { return QueryResultTypeBitmap }
func (b BitmapResult) Bitmap() BitmapResult        { return b }
func (BitmapResult) CountItems() []CountResultItem { return nil }
func (BitmapResult) Count() int64                  { return 0 }
func (BitmapResult) Sum() int64                    { return 0 }
func (BitmapResult) Changed() bool                 { return false }

func (b BitmapResult) MarshalJSON() ([]byte, error) {
	bits := b.Bits
	if bits == nil {
		bits = []uint64{}
	}
	keys := b.Keys
	if keys == nil {
		keys = []string{}
	}
	return json.Marshal(struct {
		Attributes map[string]interface{} `json:"attrs"`
		Bits       []uint64               `json:"bits"`
		Keys       []string               `json:"keys"`
	}{
		Attributes: b.Attributes,
		Bits:       bits,
		Keys:       keys,
	})
}

type SumCountResult struct {
	SumValue   int64 `json:"sum"`
	CountValue int64 `json:"count"`
}

func (SumCountResult) Type() uint32                  { return QueryResultTypeSumCount }
func (SumCountResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (SumCountResult) CountItems() []CountResultItem { return nil }
func (c SumCountResult) Count() int64                { return c.CountValue }
func (c SumCountResult) Sum() int64                  { return c.SumValue }
func (SumCountResult) Changed() bool                 { return false }

type IntResult int64

func (IntResult) Type() uint32                  { return QueryResultTypeUint64 }
func (IntResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (IntResult) CountItems() []CountResultItem { return nil }
func (i IntResult) Count() int64                { return int64(i) }
func (IntResult) Sum() int64                    { return 0 }
func (IntResult) Changed() bool                 { return false }

type BoolResult bool

func (BoolResult) Type() uint32                  { return QueryResultTypeBool }
func (BoolResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (BoolResult) CountItems() []CountResultItem { return nil }
func (BoolResult) Count() int64                  { return 0 }
func (BoolResult) Sum() int64                    { return 0 }
func (b BoolResult) Changed() bool               { return bool(b) }

type NilResult struct{}

func (NilResult) Type() uint32                  { return QueryResultTypeNil }
func (NilResult) Bitmap() BitmapResult          { return BitmapResult{} }
func (NilResult) CountItems() []CountResultItem { return nil }
func (NilResult) Count() int64                  { return 0 }
func (NilResult) Sum() int64                    { return 0 }
func (NilResult) Changed() bool                 { return false }

const (
	stringType = 1
	intType    = 2
	boolType   = 3
	floatType  = 4
)

func convertInternalAttrsToMap(attrs []*pbuf.Attr) (attrsMap map[string]interface{}, err error) {
	attrsMap = make(map[string]interface{}, len(attrs))
	for _, attr := range attrs {
		switch attr.Type {
		case stringType:
			attrsMap[attr.Key] = attr.StringValue
		case intType:
			attrsMap[attr.Key] = attr.IntValue
		case boolType:
			attrsMap[attr.Key] = attr.BoolValue
		case floatType:
			attrsMap[attr.Key] = attr.FloatValue
		default:
			return nil, errors.New("Unknown attribute type")
		}
	}

	return attrsMap, nil
}

// ColumnItem represents data about a column.
// Column data is only returned if QueryOptions.Columns was set to true.
type ColumnItem struct {
	ID         uint64                 `json:"id,omitempty"`
	Key        string                 `json:"key,omitempty"`
	Attributes map[string]interface{} `json:"attributes,omitempty"`
}

func newColumnItemFromInternal(column *pbuf.ColumnAttrSet) (ColumnItem, error) {
	attrs, err := convertInternalAttrsToMap(column.Attrs)
	if err != nil {
		return ColumnItem{}, err
	}
	return ColumnItem{
		ID:         column.ID,
		Key:        column.Key,
		Attributes: attrs,
	}, nil
}
<|endoftext|>


<commit_before>package crawl

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"

	"github.com/PuerkitoBio/goquery"
)

// Response - Crawl http response.
// It is expected it to be a HTML response but not required.
// It ALWAYS has to be released using Close() method.
type Response struct {
	*http.Response
	Body []byte

	doc *goquery.Document
}

// ParseHTML - Reads response body and parses it as HTML.
func (r *Response) ParseHTML() (err error) {
	err = r.Read()
	if err != nil {
		return
	}

	rdr := bytes.NewBuffer(r.Body)
	r.doc, err = goquery.NewDocumentFromReader(rdr)
	return
}

// Read - Reads response body into Body.
// If body already was readen it won't do nothing.
func (r *Response) Read() (err error) {
	if r.Body == nil {
		r.Body, err = ioutil.ReadAll(r.Response.Body)
	}
	return
}

// WriteFile - Reads response body to memory and writes to file.
func (r *Response) WriteFile(fname string) (err error) {
	// Read response body
	err = r.Read()
	if err != nil {
		return
	}
	err = ioutil.WriteFile(fname, r.Body, os.ModePerm)
	return

}

// GetURL - Gets response request URL.
func (r *Response) GetURL() *url.URL {
	return r.GetRequest().URL
}

// GetRequest - Gets response http.Request source.
func (r *Response) GetRequest() *http.Request {
	return r.Response.Request
}

// GetStatus - Gets response status.
func (r *Response) GetStatus() string {
	return r.Response.Status
}

// Query - Returns goquery.Document.
func (r *Response) Query() *goquery.Document {
	return r.doc
}

// Close - Closes response body.
func (r *Response) Close() (err error) {
	return r.Response.Body.Close()
}
<commit_msg>crawl.Response: ReadBody() method<commit_after>package crawl

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"

	"github.com/PuerkitoBio/goquery"
)

// Response - Crawl http response.
// It is expected it to be a HTML response but not required.
// It ALWAYS has to be released using Close() method.
type Response struct {
	*http.Response
	Body []byte

	doc *goquery.Document
}

// ParseHTML - Reads response body and parses it as HTML.
func (r *Response) ParseHTML() (err error) {
	body, err := r.ReadBody()
	if err != nil {
		return
	}
	rdr := bytes.NewBuffer(body)
	r.doc, err = goquery.NewDocumentFromReader(rdr)
	return
}

// Read - Reads response body into Body.
// If body already was readen it won't do nothing.
func (r *Response) Read() (err error) {
	if r.Body == nil {
		r.Body, err = ioutil.ReadAll(r.Response.Body)
	}
	return
}

// ReadBody - Runs Read() and returns response Body.
func (r *Response) ReadBody() (body []byte, err error) {
	err = r.Read()
	if err != nil {
		return
	}
	return r.Body, nil
}

// WriteFile - Reads response body to memory and writes to file.
func (r *Response) WriteFile(fname string) (err error) {
	// Read response body
	err = r.Read()
	if err != nil {
		return
	}
	err = ioutil.WriteFile(fname, r.Body, os.ModePerm)
	return

}

// GetURL - Gets response request URL.
func (r *Response) GetURL() *url.URL {
	return r.GetRequest().URL
}

// GetRequest - Gets response http.Request source.
func (r *Response) GetRequest() *http.Request {
	return r.Response.Request
}

// GetStatus - Gets response status.
func (r *Response) GetStatus() string {
	return r.Response.Status
}

// Query - Returns goquery.Document.
func (r *Response) Query() *goquery.Document {
	return r.doc
}

// Close - Closes response body.
func (r *Response) Close() (err error) {
	return r.Response.Body.Close()
}
<|endoftext|>


<commit_before>package gamepaicoresdk // import "gamecenter.mobi/paicode/client/gamepaicoresdk"

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gocraft/web"
	"github.com/hyperledger/fabric/peerex"

	clicore "gamecenter.mobi/paicode/client"
	gamepaicorecommon "gamecenter.mobi/paicode/client/gamepaicorecommon"
)

const defPaicodeName string = "gamepaicore_v01"
const defRegion string = "gamepai01"
const defSDKVersion string = "1.0.0"

var restLogger = peerex.InitLogger("gamepaiREST")

//var debugmode bool = false
var offlinemode bool = false

//var logtostd bool = false
var listenaddr string = ""
var router *web.Router

type GamepaiCoreConfig struct {
	FileSystemPath string
	CrtFileName    string
	YamlFileName   string
	Address        string
	Port           int
}

func StartCoreDaemon(config string) string {
	log.Println("config: ", config)

	var coreConfig GamepaiCoreConfig
	err := json.Unmarshal([]byte(config), &coreConfig)
	if err != nil {
		log.Println("Parse config error: ", err)
		return fmt.Sprintf("failed.")
	}

	log.Println("FileSystemPath: ", coreConfig.FileSystemPath)
	log.Println("CrtFileName: ", coreConfig.CrtFileName)
	log.Println("YamlFileName: ", coreConfig.YamlFileName)
	log.Println("Address: ", coreConfig.Address)
	log.Println("Port: ", coreConfig.Port)
	crtFile := filepath.Join(coreConfig.FileSystemPath, coreConfig.CrtFileName+".crt")
	yamlFile := filepath.Join(coreConfig.FileSystemPath, coreConfig.YamlFileName+".yaml")
	log.Println("CrtFile: ", crtFile)
	log.Println("YamlFile: ", yamlFile)

	globalConfig := &peerex.GlobalConfig{}
	globalConfig.ConfigPath = make([]string, 1, 10)
	globalConfig.ConfigPath[0] = coreConfig.FileSystemPath // Path to look for the config file in
	globalConfig.ConfigFileName = coreConfig.YamlFileName

	defaultViperSetting := make(map[string]string)
	defaultViperSetting["peer.fileSystemPath"] = coreConfig.FileSystemPath
	defaultViperSetting["peer.tls.rootcert.file"] = crtFile

	err = globalConfig.InitGlobalWrapper(true, defaultViperSetting)
	if err != nil {
		log.Println("Init global config error: ", err)
		return fmt.Sprintf("failed.")
	}

	err = os.MkdirAll(globalConfig.GetPeerFS(), 0777)
	if err != nil {
		restLogger.Error("Mkdir error: ", err)
		return fmt.Sprintf("failed.")
	}

	gamepaicorecommon.DefClient = clicore.NewClientCore(globalConfig)

	if !offlinemode {

		conn := peerex.ClientConn{}

		err := conn.Dialdefault()
		if err != nil {
			restLogger.Error("Dial default error: ", err)
			return fmt.Sprintf("failed.")
		}

		gamepaicorecommon.DefClient.PrepareRpc(conn)
		gamepaicorecommon.DefClient.SetRpcRegion(defRegion)
		gamepaicorecommon.DefClient.Rpc.Rpcbuilder.ChaincodeName = defPaicodeName
		restLogger.Infof("Start rpc, chaincode is %s", gamepaicorecommon.DefClient.Rpc.Rpcbuilder.ChaincodeName)
	} else {
		restLogger.Info("Run under off-line mode")
	}

	if listenaddr == "" {
		listenaddr = fmt.Sprintf("%s:%d", coreConfig.Address, coreConfig.Port)
		//listenaddr = "0.0.0.0:7280"
	}

	gamepaicorecommon.DefClient.Accounts.KeyMgr.Load()
	//defer defClient.Accounts.KeyMgr.Persist()

	// Initialize the REST service object
	restLogger.Infof("Initializing the REST service on %s", listenaddr)
	router = gamepaicorecommon.BuildRouter()
	go startHttpServer()

	return "success"
}

func GetSDKVersion() string {
	return defSDKVersion
}

func startHttpServer() {
	restLogger.Info("Starting HTTP Server ...")
	err := http.ListenAndServe(listenaddr, router)
	restLogger.Info("HTTP server is stopped.")
	if err != nil {
		restLogger.Error("Listen and Serve error: ", err)
	}

	if gamepaicorecommon.DefClient.IsRpcReady() {
		gamepaicorecommon.DefClient.ReleaseRpc()
	}
}
<commit_msg>do not export gamepaiCoreConfig<commit_after>package gamepaicoresdk // import "gamecenter.mobi/paicode/client/gamepaicoresdk"

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gocraft/web"
	"github.com/hyperledger/fabric/peerex"

	clicore "gamecenter.mobi/paicode/client"
	gamepaicorecommon "gamecenter.mobi/paicode/client/gamepaicorecommon"
)

const defPaicodeName string = "gamepaicore_v01"
const defRegion string = "gamepai01"
const defSDKVersion string = "1.0.0"

var restLogger = peerex.InitLogger("gamepaiREST")

//var debugmode bool = false
var offlinemode bool = false

//var logtostd bool = false
var listenaddr string = ""
var router *web.Router

type gamepaiCoreConfig struct {
	FileSystemPath string
	CrtFileName    string
	YamlFileName   string
	Address        string
	Port           int
}

func StartCoreDaemon(config string) string {
	log.Println("config: ", config)

	var coreConfig gamepaiCoreConfig
	err := json.Unmarshal([]byte(config), &coreConfig)
	if err != nil {
		log.Println("Parse config error: ", err)
		return fmt.Sprintf("failed.")
	}

	log.Println("FileSystemPath: ", coreConfig.FileSystemPath)
	log.Println("CrtFileName: ", coreConfig.CrtFileName)
	log.Println("YamlFileName: ", coreConfig.YamlFileName)
	log.Println("Address: ", coreConfig.Address)
	log.Println("Port: ", coreConfig.Port)
	crtFile := filepath.Join(coreConfig.FileSystemPath, coreConfig.CrtFileName+".crt")
	yamlFile := filepath.Join(coreConfig.FileSystemPath, coreConfig.YamlFileName+".yaml")
	log.Println("CrtFile: ", crtFile)
	log.Println("YamlFile: ", yamlFile)

	globalConfig := &peerex.GlobalConfig{}
	globalConfig.ConfigPath = make([]string, 1, 10)
	globalConfig.ConfigPath[0] = coreConfig.FileSystemPath // Path to look for the config file in
	globalConfig.ConfigFileName = coreConfig.YamlFileName

	defaultViperSetting := make(map[string]string)
	defaultViperSetting["peer.fileSystemPath"] = coreConfig.FileSystemPath
	defaultViperSetting["peer.tls.rootcert.file"] = crtFile

	err = globalConfig.InitGlobalWrapper(true, defaultViperSetting)
	if err != nil {
		log.Println("Init global config error: ", err)
		return fmt.Sprintf("failed.")
	}

	err = os.MkdirAll(globalConfig.GetPeerFS(), 0777)
	if err != nil {
		restLogger.Error("Mkdir error: ", err)
		return fmt.Sprintf("failed.")
	}

	gamepaicorecommon.DefClient = clicore.NewClientCore(globalConfig)

	if !offlinemode {

		conn := peerex.ClientConn{}

		err := conn.Dialdefault()
		if err != nil {
			restLogger.Error("Dial default error: ", err)
			return fmt.Sprintf("failed.")
		}

		gamepaicorecommon.DefClient.PrepareRpc(conn)
		gamepaicorecommon.DefClient.SetRpcRegion(defRegion)
		gamepaicorecommon.DefClient.Rpc.Rpcbuilder.ChaincodeName = defPaicodeName
		restLogger.Infof("Start rpc, chaincode is %s", gamepaicorecommon.DefClient.Rpc.Rpcbuilder.ChaincodeName)
	} else {
		restLogger.Info("Run under off-line mode")
	}

	if listenaddr == "" {
		listenaddr = fmt.Sprintf("%s:%d", coreConfig.Address, coreConfig.Port)
		//listenaddr = "0.0.0.0:7280"
	}

	gamepaicorecommon.DefClient.Accounts.KeyMgr.Load()
	//defer defClient.Accounts.KeyMgr.Persist()

	// Initialize the REST service object
	restLogger.Infof("Initializing the REST service on %s", listenaddr)
	router = gamepaicorecommon.BuildRouter()
	go startHttpServer()

	return "success"
}

func GetSDKVersion() string {
	return defSDKVersion
}

func startHttpServer() {
	restLogger.Info("Starting HTTP Server ...")
	err := http.ListenAndServe(listenaddr, router)
	restLogger.Info("HTTP server is stopped.")
	if err != nil {
		restLogger.Error("Listen and Serve error: ", err)
	}

	if gamepaicorecommon.DefClient.IsRpcReady() {
		gamepaicorecommon.DefClient.ReleaseRpc()
	}
}
<|endoftext|>


<commit_before>package grequests

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"io"
	"net/http"
	"os"
)

// Response is what is returned to a user when they fire off a request
type Response struct {

	// Ok is a boolean flag that validates that the server returned a 2xx code
	Ok bool

	// This is the Go error flag – if something went wrong within the request, this flag will be set.
	Error error

	// We want to abstract (at least at the moment) the Go http.Response object away. So we are going to make use of it
	// internal but not give the user access
	RawResponse *http.Response

	// StatusCode is the HTTP Status Code returned by the HTTP Response. Taken from resp.StatusCode
	StatusCode int

	// Header is a net/http/Header structure
	Header http.Header

	internalByteBuffer *bytes.Buffer
}

func buildResponse(resp *http.Response, err error) (*Response, error) {
	// If the connection didn't succeed we just return a blank response
	if err != nil {
		return &Response{Error: err}, err
	}

	goodResp := &Response{
		// If your code is within the 2xx range – the response is considered `Ok`
		Ok:                 resp.StatusCode >= 200 && resp.StatusCode < 300,
		Error:              nil,
		RawResponse:        resp,
		StatusCode:         resp.StatusCode,
		Header:             resp.Header,
		internalByteBuffer: bytes.NewBuffer([]byte{}),
	}
	EnsureResponseFinalized(goodResp)
	return goodResp, nil
}

// Read is part of our ability to support io.ReadCloser if someone wants to make use of the raw body
func (r *Response) Read(p []byte) (n int, err error) {

	if r.Error != nil {
		return -1, r.Error
	}

	return r.RawResponse.Body.Read(p)
}

// Close is part of our ability to support io.ReadCloser if someone wants to make use of the raw body
func (r *Response) Close() error {

	if r.Error != nil {
		return r.Error
	}

	return r.RawResponse.Body.Close()
}

// DownloadToFile allows you to download the contents of the response to a file
func (r *Response) DownloadToFile(fileName string) error {

	if r.Error != nil {
		return r.Error
	}

	fd, err := os.Create(fileName)

	if err != nil {
		return err
	}

	defer r.Close() // This is a noop if we use the internal ByteBuffer
	defer fd.Close()

	if _, err := io.Copy(fd, r.getInternalReader()); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// getInternalReader because we implement io.ReadCloser and optionally hold a large buffer of the response (created by
// the user's request)
func (r *Response) getInternalReader() io.Reader {

	if r.internalByteBuffer.Len() != 0 {
		return r.internalByteBuffer
	}
	return r
}

// XML is a method that will populate a struct that is provided `userStruct` with the XML returned within the
// response body
func (r *Response) XML(userStruct interface{}, charsetReader XMLCharDecoder) error {

	if r.Error != nil {
		return r.Error
	}

	xmlDecoder := xml.NewDecoder(r.getInternalReader())

	if charsetReader != nil {
		xmlDecoder.CharsetReader = charsetReader
	}

	defer r.Close()

	if err := xmlDecoder.Decode(&userStruct); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// JSON is a method that will populate a struct that is provided `userStruct` with the JSON returned within the
// response body
func (r *Response) JSON(userStruct interface{}) error {

	if r.Error != nil {
		return r.Error
	}

	jsonDecoder := json.NewDecoder(r.getInternalReader())
	defer r.Close()

	if err := jsonDecoder.Decode(&userStruct); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// createResponseBytesBuffer is a utility method that will populate the internal byte reader – this is largely used for .String()
// and .Bytes()
func (r *Response) populateResponseByteBuffer() {

	// Have I done this already?
	if r.internalByteBuffer.Len() != 0 {
		return
	}

	defer r.Close()

	// Is there any content?
	if r.RawResponse.ContentLength == 0 {
		return
	}

	// Did the server tell us how big the response is going to be?
	if r.RawResponse.ContentLength > 0 {
		r.internalByteBuffer.Grow(int(r.RawResponse.ContentLength))
	}

	if _, err := io.Copy(r.internalByteBuffer, r); err != nil && err != io.EOF {
		r.Error = err
		r.RawResponse.Body.Close()
	}

}

// Bytes returns the response as a byte array
func (r *Response) Bytes() []byte {

	if r.Error != nil {
		return nil
	}

	r.populateResponseByteBuffer()

	// Are we still empty?
	if r.internalByteBuffer.Len() == 0 {
		return nil
	}
	return r.internalByteBuffer.Bytes()

}

// String returns the response as a string
func (r *Response) String() string {
	if r.Error != nil {
		return ""
	}

	r.populateResponseByteBuffer()

	return r.internalByteBuffer.String()
}

// ClearInternalBuffer is a function that will clear the internal buffer that we use to hold the .String() and .Bytes()
// data. Once you have used these functions – you may want to free up the memory.
func (r *Response) ClearInternalBuffer() {

	if r.Error != nil {
		return // This is a noop as we will be dereferencing a null pointer
	}

	r.internalByteBuffer.Reset()
}
<commit_msg>Discard the bytes on close<commit_after>package grequests

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"io"
	"io/ioutil"
	"net/http"
	"os"
)

// Response is what is returned to a user when they fire off a request
type Response struct {

	// Ok is a boolean flag that validates that the server returned a 2xx code
	Ok bool

	// This is the Go error flag – if something went wrong within the request, this flag will be set.
	Error error

	// We want to abstract (at least at the moment) the Go http.Response object away. So we are going to make use of it
	// internal but not give the user access
	RawResponse *http.Response

	// StatusCode is the HTTP Status Code returned by the HTTP Response. Taken from resp.StatusCode
	StatusCode int

	// Header is a net/http/Header structure
	Header http.Header

	internalByteBuffer *bytes.Buffer
}

func buildResponse(resp *http.Response, err error) (*Response, error) {
	// If the connection didn't succeed we just return a blank response
	if err != nil {
		return &Response{Error: err}, err
	}

	goodResp := &Response{
		// If your code is within the 2xx range – the response is considered `Ok`
		Ok:                 resp.StatusCode >= 200 && resp.StatusCode < 300,
		Error:              nil,
		RawResponse:        resp,
		StatusCode:         resp.StatusCode,
		Header:             resp.Header,
		internalByteBuffer: bytes.NewBuffer([]byte{}),
	}
	EnsureResponseFinalized(goodResp)
	return goodResp, nil
}

// Read is part of our ability to support io.ReadCloser if someone wants to make use of the raw body
func (r *Response) Read(p []byte) (n int, err error) {

	if r.Error != nil {
		return -1, r.Error
	}

	return r.RawResponse.Body.Read(p)
}

// Close is part of our ability to support io.ReadCloser if someone wants to make use of the raw body
func (r *Response) Close() error {

	if r.Error != nil {
		return r.Error
	}

	io.Copy(ioutil.Discard, r)

	return r.RawResponse.Body.Close()
}

// DownloadToFile allows you to download the contents of the response to a file
func (r *Response) DownloadToFile(fileName string) error {

	if r.Error != nil {
		return r.Error
	}

	fd, err := os.Create(fileName)

	if err != nil {
		return err
	}

	defer r.Close() // This is a noop if we use the internal ByteBuffer
	defer fd.Close()

	if _, err := io.Copy(fd, r.getInternalReader()); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// getInternalReader because we implement io.ReadCloser and optionally hold a large buffer of the response (created by
// the user's request)
func (r *Response) getInternalReader() io.Reader {

	if r.internalByteBuffer.Len() != 0 {
		return r.internalByteBuffer
	}
	return r
}

// XML is a method that will populate a struct that is provided `userStruct` with the XML returned within the
// response body
func (r *Response) XML(userStruct interface{}, charsetReader XMLCharDecoder) error {

	if r.Error != nil {
		return r.Error
	}

	xmlDecoder := xml.NewDecoder(r.getInternalReader())

	if charsetReader != nil {
		xmlDecoder.CharsetReader = charsetReader
	}

	defer r.Close()

	if err := xmlDecoder.Decode(&userStruct); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// JSON is a method that will populate a struct that is provided `userStruct` with the JSON returned within the
// response body
func (r *Response) JSON(userStruct interface{}) error {

	if r.Error != nil {
		return r.Error
	}

	jsonDecoder := json.NewDecoder(r.getInternalReader())
	defer r.Close()

	if err := jsonDecoder.Decode(&userStruct); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// createResponseBytesBuffer is a utility method that will populate the internal byte reader – this is largely used for .String()
// and .Bytes()
func (r *Response) populateResponseByteBuffer() {

	// Have I done this already?
	if r.internalByteBuffer.Len() != 0 {
		return
	}

	defer r.Close()

	// Is there any content?
	if r.RawResponse.ContentLength == 0 {
		return
	}

	// Did the server tell us how big the response is going to be?
	if r.RawResponse.ContentLength > 0 {
		r.internalByteBuffer.Grow(int(r.RawResponse.ContentLength))
	}

	if _, err := io.Copy(r.internalByteBuffer, r); err != nil && err != io.EOF {
		r.Error = err
		r.RawResponse.Body.Close()
	}

}

// Bytes returns the response as a byte array
func (r *Response) Bytes() []byte {

	if r.Error != nil {
		return nil
	}

	r.populateResponseByteBuffer()

	// Are we still empty?
	if r.internalByteBuffer.Len() == 0 {
		return nil
	}
	return r.internalByteBuffer.Bytes()

}

// String returns the response as a string
func (r *Response) String() string {
	if r.Error != nil {
		return ""
	}

	r.populateResponseByteBuffer()

	return r.internalByteBuffer.String()
}

// ClearInternalBuffer is a function that will clear the internal buffer that we use to hold the .String() and .Bytes()
// data. Once you have used these functions – you may want to free up the memory.
func (r *Response) ClearInternalBuffer() {

	if r.Error != nil {
		return // This is a noop as we will be dereferencing a null pointer
	}

	r.internalByteBuffer.Reset()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

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

var db *sql.DB

func openSQLConnection() {
	conn, err := sql.Open("mysql", fmt.Sprint(config.DbUsername, ":", config.DbPassword, "@tcp(", config.DbHost, ":", config.DbPort, ")/", config.DbDatabase))
	checkErr(err)

	db = conn

	log.Print("Connected to SQL")
}

func dbGetUserToken(user string) string {
	stmt, err := db.Prepare("SELECT token FROM access_token WHERE user = ?")
	checkErr(err)

	row := stmt.QueryRow(user)

	var token string
	row.Scan(&token)

	return token
}

func dbSaveUserToken(user string, token string) {
	stmt, err := db.Prepare("INSERT INTO access_token (user, token) VALUES (?, ?)")
	checkErr(err)

	_, err = stmt.Exec(user, token)
	checkErr(err)
}

func dbSaveNiom(user string) {
	stmt, err := db.Prepare("INSERT INTO nioms (user, date) VALUES (?, ?)")
	checkErr(err)

	_, err = stmt.Exec(user, time.Now().Format("2006-01-02"))
	checkErr(err)
}

func dbGetLastNiom(user string) string {
	stmt, err := db.Prepare("SELECT date FROM nioms WHERE user = ?")
	checkErr(err)

	row := stmt.QueryRow(user)

	var token string
	row.Scan(&token)

	return token
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>track usage<commit_after>package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

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

var db *sql.DB

func openSQLConnection() {
	conn, err := sql.Open("mysql", fmt.Sprint(config.DbUsername, ":", config.DbPassword, "@tcp(", config.DbHost, ":", config.DbPort, ")/", config.DbDatabase))
	checkErr(err)

	db = conn

	log.Print("Connected to SQL")
}

func dbGetUserToken(user string) string {
	stmt, err := db.Prepare("SELECT token FROM access_token WHERE user = ?")
	checkErr(err)

	row := stmt.QueryRow(user)

	var token string
	row.Scan(&token)

	return token
}

func dbSaveUserToken(user string, token string) {
	stmt, err := db.Prepare("INSERT INTO access_token (user, token) VALUES (?, ?)")
	checkErr(err)

	_, err = stmt.Exec(user, token)
	checkErr(err)
}

func dbSaveNiom(user string) {
	stmt, err := db.Prepare("INSERT INTO nioms (user, date) VALUES (?, ?)")
	checkErr(err)

	_, err = stmt.Exec(user, time.Now().Format("2006-01-02"))
	checkErr(err)
}

func dbGetLastNiom(user string) string {
	stmt, err := db.Prepare("SELECT date FROM nioms WHERE user = ? ORDER BY id DESC")
	checkErr(err)

	row := stmt.QueryRow(user)

	var token string
	row.Scan(&token)

	return token
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

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

	// Alias this because we call our connection couchbase
	cb "github.com/couchbaselabs/go-couchbase"
)

var couchbase *cb.Bucket

type viewMarker struct {
	Version   int       `json:"version"`
	Node      string    `json:"node"`
	Timestamp time.Time `json:"timestamp"`
	Type      string    `json:"type"`
}

const ddocKey = "/@ddocVersion"
const ddocVersion = 3
const designDoc = `
{
    "spatialInfos": [],
    "viewInfos": [
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"file\") {\n    var toEmit = {};\n    toEmit[doc.oid] = meta.id;\n    if (doc.older) {\n      for (var i = 0; i < doc.older.length; i++) {\n        toEmit[doc.older[i].oid] = meta.id;\n      }\n    }\n    for (var k in toEmit) {\n      emit([k, \"file\", meta.id], null);\n    }\n  } else if (doc.type === \"blob\") {\n    var replicas=0;\n    for (var node in doc.nodes) {\n      replicas++;\n      emit([doc.oid, \"blob\", node], null);\n    }\n    if (replicas === 0) {\n      emit([doc.oid, \"blob\", \"\"], null);\n    }\n  }\n}",
            "name": "file_blobs",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_blobs",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_blobs"
        },
        {
            "map": "function (doc, meta) {\n  if(doc.type == \"file\") {  \n    var idarr = meta.id.split(\"/\");\n    emit(idarr, doc.length);\n  }\n}",
            "name": "file_browse",
            "reduce": "_stats",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_browse",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_browse"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === 'blob') {\n    emit(doc.garbage ? 'garbage' : 'live', doc.length);\n  }\n}",
            "name": "garbage",
            "reduce": "_stats",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fgarbage",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fgarbage"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, null);\n    }\n  }\n}",
            "name": "node_blobs",
            "reduce": "_count",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_blobs",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_blobs"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"node\") {\n    emit(meta.id.substring(1), 0);\n  } else if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, doc.length);\n    }\n  }\n}",
            "name": "node_size",
            "reduce": "_sum",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_size",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_size"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\" && !doc.garbage) {\n    var nreps = 0;\n    for (var x in doc.nodes) {\n      nreps++;\n    }\n    emit(nreps, null);\n  }\n}",
            "name": "repcounts",
            "reduce": "_count",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Frepcounts",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Frepcounts"
        }
    ],
    "views": {
        "file_blobs": {
            "map": "function (doc, meta) {\n  if (doc.type === \"file\") {\n    var toEmit = {};\n    toEmit[doc.oid] = doc.name ? doc.name : meta.id;\n    if (doc.older) {\n      for (var i = 0; i < doc.older.length; i++) {\n        toEmit[doc.older[i].oid] = doc.name ? doc.name : meta.id;\n      }\n    }\n    for (var k in toEmit) {\n      emit([k, \"file\", doc.name ? doc.name : meta.id], null);\n    }\n  } else if (doc.type === \"blob\") {\n    var replicas=0;\n    for (var node in doc.nodes) {\n      replicas++;\n      emit([doc.oid, \"blob\", node], null);\n    }\n    if (replicas === 0) {\n      emit([doc.oid, \"blob\", \"\"], null);\n    }\n  }\n}"
        },
        "file_browse": {
            "map": "function (doc, meta) {\n  if(doc.type == \"file\") {  \n    var idarr = (doc.name ? doc.name : meta.id).split(\"/\");\n    emit(idarr, doc.length);\n  }\n}",
            "reduce": "_stats"
        },
        "garbage": {
            "map": "function (doc, meta) {\n  if (doc.type === 'blob') {\n    emit(doc.garbage ? 'garbage' : 'live', doc.length);\n  }\n}",
            "reduce": "_stats"
        },
        "node_blobs": {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, null);\n    }\n  }\n}",
            "reduce": "_count"
        },
        "node_size": {
            "map": "function (doc, meta) {\n  if (doc.type === \"node\") {\n    emit(meta.id.substring(1), 0);\n  } else if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, doc.length);\n    }\n  }\n}",
            "reduce": "_sum"
        },
        "repcounts": {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\" && !doc.garbage) {\n    var nreps = 0;\n    for (var x in doc.nodes) {\n      nreps++;\n    }\n    emit(nreps, null);\n  }\n}",
            "reduce": "_count"
        }
    }
}
`

func dbConnect() (*cb.Bucket, error) {

	cb.HttpClient = &http.Client{
		Transport: TimeoutTransport(*viewTimeout),
	}

	log.Printf("Connecting to couchbase bucket %v at %v",
		*couchbaseBucket, *couchbaseServer)
	rv, err := cb.GetBucket(*couchbaseServer, "default", *couchbaseBucket)
	if err != nil {
		return nil, err
	}

	marker := viewMarker{}
	err = rv.Get(ddocKey, &marker)
	if err != nil {
		log.Printf("Error checking view version: %v", err)
	}
	if marker.Version < ddocVersion {
		log.Printf("Installing new version of views (old version=%v)",
			marker.Version)
		doc := json.RawMessage([]byte(designDoc))
		err = rv.PutDDoc("cbfs", &doc)
		if err != nil {
			return nil, err
		}
		marker.Version = ddocVersion
		marker.Node = serverId
		marker.Timestamp = time.Now().UTC()
		marker.Type = "ddocmarker"

		rv.Set(ddocKey, 0, &marker)
	}

	return rv, nil
}
<commit_msg>Use couchbaseutil's view manager.<commit_after>package main

import (
	"log"
	"net/http"

	// Alias this because we call our connection couchbase
	cb "github.com/couchbaselabs/go-couchbase"
	"github.com/couchbaselabs/go-couchbase/util"
)

var couchbase *cb.Bucket

const ddocKey = "/@ddocVersion"
const ddocVersion = 3
const designDoc = `
{
    "spatialInfos": [],
    "viewInfos": [
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"file\") {\n    var toEmit = {};\n    toEmit[doc.oid] = meta.id;\n    if (doc.older) {\n      for (var i = 0; i < doc.older.length; i++) {\n        toEmit[doc.older[i].oid] = meta.id;\n      }\n    }\n    for (var k in toEmit) {\n      emit([k, \"file\", meta.id], null);\n    }\n  } else if (doc.type === \"blob\") {\n    var replicas=0;\n    for (var node in doc.nodes) {\n      replicas++;\n      emit([doc.oid, \"blob\", node], null);\n    }\n    if (replicas === 0) {\n      emit([doc.oid, \"blob\", \"\"], null);\n    }\n  }\n}",
            "name": "file_blobs",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_blobs",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_blobs"
        },
        {
            "map": "function (doc, meta) {\n  if(doc.type == \"file\") {  \n    var idarr = meta.id.split(\"/\");\n    emit(idarr, doc.length);\n  }\n}",
            "name": "file_browse",
            "reduce": "_stats",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_browse",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Ffile_browse"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === 'blob') {\n    emit(doc.garbage ? 'garbage' : 'live', doc.length);\n  }\n}",
            "name": "garbage",
            "reduce": "_stats",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fgarbage",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fgarbage"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, null);\n    }\n  }\n}",
            "name": "node_blobs",
            "reduce": "_count",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_blobs",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_blobs"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"node\") {\n    emit(meta.id.substring(1), 0);\n  } else if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, doc.length);\n    }\n  }\n}",
            "name": "node_size",
            "reduce": "_sum",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_size",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Fnode_size"
        },
        {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\" && !doc.garbage) {\n    var nreps = 0;\n    for (var x in doc.nodes) {\n      nreps++;\n    }\n    emit(nreps, null);\n  }\n}",
            "name": "repcounts",
            "reduce": "_count",
            "removeLink": "#removeView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Frepcounts",
            "viewLink": "#showView=cbfs%2F_design%252Fdev_cbfs%2F_view%2Frepcounts"
        }
    ],
    "views": {
        "file_blobs": {
            "map": "function (doc, meta) {\n  if (doc.type === \"file\") {\n    var toEmit = {};\n    toEmit[doc.oid] = doc.name ? doc.name : meta.id;\n    if (doc.older) {\n      for (var i = 0; i < doc.older.length; i++) {\n        toEmit[doc.older[i].oid] = doc.name ? doc.name : meta.id;\n      }\n    }\n    for (var k in toEmit) {\n      emit([k, \"file\", doc.name ? doc.name : meta.id], null);\n    }\n  } else if (doc.type === \"blob\") {\n    var replicas=0;\n    for (var node in doc.nodes) {\n      replicas++;\n      emit([doc.oid, \"blob\", node], null);\n    }\n    if (replicas === 0) {\n      emit([doc.oid, \"blob\", \"\"], null);\n    }\n  }\n}"
        },
        "file_browse": {
            "map": "function (doc, meta) {\n  if(doc.type == \"file\") {  \n    var idarr = (doc.name ? doc.name : meta.id).split(\"/\");\n    emit(idarr, doc.length);\n  }\n}",
            "reduce": "_stats"
        },
        "garbage": {
            "map": "function (doc, meta) {\n  if (doc.type === 'blob') {\n    emit(doc.garbage ? 'garbage' : 'live', doc.length);\n  }\n}",
            "reduce": "_stats"
        },
        "node_blobs": {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, null);\n    }\n  }\n}",
            "reduce": "_count"
        },
        "node_size": {
            "map": "function (doc, meta) {\n  if (doc.type === \"node\") {\n    emit(meta.id.substring(1), 0);\n  } else if (doc.type === \"blob\") {\n    for (var n in doc.nodes) {\n      emit(n, doc.length);\n    }\n  }\n}",
            "reduce": "_sum"
        },
        "repcounts": {
            "map": "function (doc, meta) {\n  if (doc.type === \"blob\" && !doc.garbage) {\n    var nreps = 0;\n    for (var x in doc.nodes) {\n      nreps++;\n    }\n    emit(nreps, null);\n  }\n}",
            "reduce": "_count"
        }
    }
}
`

func dbConnect() (*cb.Bucket, error) {
	cb.HttpClient = &http.Client{
		Transport: TimeoutTransport(*viewTimeout),
	}

	log.Printf("Connecting to couchbase bucket %v at %v",
		*couchbaseBucket, *couchbaseServer)
	rv, err := cb.GetBucket(*couchbaseServer, "default", *couchbaseBucket)
	if err != nil {
		return nil, err
	}

	return rv, couchbaseutil.UpdateView(rv, "cbfs",
		ddocKey, designDoc, ddocVersion)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os/exec"
	"strings"

	"github.com/streadway/amqp"
)

type RadiodanCommand struct {
	Action        string
	CorrelationId string
}

var dryRun bool

func main() {
	host, port := parseArgs()
	listenForCommand(host, port)
}

func parseArgs() (host string, port int) {
	flag.StringVar(&host, "host", "localhost", "Hostname for RabbitMQ")
	flag.IntVar(&port, "port", 5672, "Port for RabbitMQ")
	flag.BoolVar(&dryRun, "dry-run", false, "Dry Run (do not execute command)")

	flag.Parse()

	return
}

func listenForCommand(host string, port int) {
	amqpUri := fmt.Sprintf("amqp://%s:%d", host, port)
	exchangeName := "radiodan"
	routingKey := "command.device.shutdown"

	conn, err := amqp.Dial(amqpUri)
	failOnError(err, "Cannot connect")
	defer conn.Close()

	log.Printf("[*] Connected to %s", amqpUri)

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()

	err = ch.ExchangeDeclare(
		exchangeName, // name
		"topic",      // type
		true,         // durable
		false,        // auto-deleted
		false,        // internal
		false,        // no-wait
		nil,          // arguments
	)
	failOnError(err, "Failed to declare an exchange")

	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,     // queue name
		routingKey, // routing key
		"radiodan", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	log.Println("[*] Consuming", q.Name)

	forever := make(chan bool)

	go func() {
		for m := range msgs {
			processMessage(m)
		}
	}()

	log.Printf("[*] Waiting for commands")
	<-forever
}

func processMessage(msg amqp.Delivery) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("[!] Msg processing failed:", r)
		}
	}()

	cmd := RadiodanCommand{}

	err := json.Unmarshal(msg.Body, &cmd)
	failOnError(err, "Malformed Radiodan Command")

	log.Printf("[x] Received action: %s", cmd.Action)

	execCmd(cmd)
}

func execCmd(cmd RadiodanCommand) {
	var shutdownFlag, path string
	var args []string

	switch cmd.Action {
	case "restart":
		shutdownFlag = "-r"
	case "shutdown":
		shutdownFlag = "-h"
	default:
		panic("Action " + cmd.Action + " is neither restart nor shutdown")
	}

	if dryRun {
		path = "/bin/echo"
		args = []string{"shutdown", path, shutdownFlag, "now"}
	} else {
		path = "/sbin/shutdown"
		args = []string{path, shutdownFlag, "now"}
	}

	shutdown := exec.Cmd{
		Path: path,
		Args: args,
	}

	output, err := shutdown.CombinedOutput()
	outputStr := strings.TrimRight(string(output), "\n")

	failOnError(err, "Could not exec shutdown")
	log.Println("[x] exec:", outputStr)
}

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}
<commit_msg>Retry AMQP connection after 3 seconds if unsuccessful<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

type RadiodanCommand struct {
	Action        string
	CorrelationId string
}

var dryRun bool

func main() {
	host, port := parseArgs()
	listenForCommand(host, port)
}

func parseArgs() (host string, port int) {
	flag.StringVar(&host, "host", "localhost", "Hostname for RabbitMQ")
	flag.IntVar(&port, "port", 5672, "Port for RabbitMQ")
	flag.BoolVar(&dryRun, "dry-run", false, "Dry Run (do not execute command)")

	flag.Parse()

	return
}

func listenForCommand(host string, port int) {
	amqpUri := fmt.Sprintf("amqp://%s:%d", host, port)
	exchangeName := "radiodan"
	routingKey := "command.device.shutdown"
	connected := false

	var conn *amqp.Connection

	for connected != true {
		tryConn, err := amqp.Dial(amqpUri)
		if err != nil {
			log.Printf("[!] Cannot connect", err)
			log.Printf("[*] Retry in 3 seconds")
			time.Sleep(3 * time.Second)
		} else {
			connected = true
			conn = tryConn
			defer conn.Close()
		}
	}

	log.Printf("[*] Connected to %s", amqpUri)

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()

	err = ch.ExchangeDeclare(
		exchangeName, // name
		"topic",      // type
		true,         // durable
		false,        // auto-deleted
		false,        // internal
		false,        // no-wait
		nil,          // arguments
	)
	failOnError(err, "Failed to declare an exchange")

	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,     // queue name
		routingKey, // routing key
		"radiodan", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	log.Println("[*] Consuming", q.Name)

	forever := make(chan bool)

	go func() {
		for m := range msgs {
			processMessage(m)
		}
	}()

	log.Printf("[*] Waiting for commands")
	<-forever
}

func processMessage(msg amqp.Delivery) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("[!] Msg processing failed:", r)
		}
	}()

	cmd := RadiodanCommand{}

	err := json.Unmarshal(msg.Body, &cmd)
	failOnError(err, "Malformed Radiodan Command")

	log.Printf("[x] Received action: %s", cmd.Action)

	execCmd(cmd)
}

func execCmd(cmd RadiodanCommand) {
	var shutdownFlag, path string
	var args []string

	switch cmd.Action {
	case "restart":
		shutdownFlag = "-r"
	case "shutdown":
		shutdownFlag = "-h"
	default:
		panic("Action " + cmd.Action + " is neither restart nor shutdown")
	}

	if dryRun {
		path = "/bin/echo"
		args = []string{"shutdown", path, shutdownFlag, "now"}
	} else {
		path = "/sbin/shutdown"
		args = []string{path, shutdownFlag, "now"}
	}

	shutdown := exec.Cmd{
		Path: path,
		Args: args,
	}

	output, err := shutdown.CombinedOutput()
	outputStr := strings.TrimRight(string(output), "\n")

	failOnError(err, "Could not exec shutdown")
	log.Println("[x] exec:", outputStr)
}

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}
<|endoftext|>


<commit_before>package db

import (
	"errors"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var config *MongoConfig
var instances []*mgo.Session
var instanceOnce sync.Once
var instancesIndex uint32

const mgoMaxSessions = 8

type M bson.M

func (m M) Update(qs ...M) M {
	for _, q := range qs {
		for k, v := range q {
			m[k] = v
		}
	}
	return m
}

var ErrOperaBeforeInit = errors.New("please set db.SetOnFinishInit when needed operating db in init()")

// non-multhreads
var afterEvents []func()
var indexEvents []func()

func EnsureAllIndex() {
	for _, f := range indexEvents {
		f()
	}
}

func SetOnEnsureIndex(f func()) {
	indexEvents = append(indexEvents, f)
}

func SetOnFinishInit(f func()) {
	if IsFinishInit() {
		f()
		return
	}
	afterEvents = append(afterEvents, f)
}

func IsFinishInit() bool {
	return instances != nil
}

func Setup(c *MongoConfig) {
	config = c
}

func ShareSession() *mgo.Session {
	doInit := false
	instanceOnce.Do(func() {
		instances = MustNewMgoSessions(config)
	})

	if doInit {
		for _, f := range afterEvents {
			f()
		}
	}

	i := atomic.AddUint32(&instancesIndex, 1)
	i = i % uint32(len(instances))
	return instances[int(i)].Clone()
}

func MustNewMgoSessions(config *MongoConfig) []*mgo.Session {
	sessions := make([]*mgo.Session, mgoMaxSessions)
	for i := 0; i < mgoMaxSessions; i++ {
		if config == nil {
			panic(ErrOperaBeforeInit)
		}
		session, err := mgo.Dial(config.MongoDB)
		if err != nil {
			panic(err)
		}
		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)
		if err := session.Ping(); err != nil {
			panic(err)
		}

		poolLimit := config.PoolLimit
		if poolLimit <= 0 {
			poolLimit = 16
		}

		session.SetPoolLimit(poolLimit)
		sessions[i] = session

		// Refresh session in case of network error.
		go func(s *mgo.Session) {
			for {
				if err := s.Ping(); err != nil {
					s.Refresh()
				}
				time.Sleep(time.Second)
			}
		}(session)
	}

	return sessions
}

func InID(ids []string) (ret M) {
	return M{"_id": M{"$in": ObjectIds(ids)}}
}

func In(ids []string) M {
	return M{"$in": ObjectIds(ids)}
}

func ObjectIds(ids []string) (ret []bson.ObjectId) {
	ret = make([]bson.ObjectId, 0, len(ids))
	for _, id := range ids {
		id = strings.TrimSpace(id)
		if bson.IsObjectIdHex(id) {
			ret = append(ret, bson.ObjectIdHex(id))
		}
	}
	return
}

func NewSession() (session *mgo.Session) {
	return ShareSession()
}

func NewCollection(session *mgo.Session, dbName, name string) *mgo.Collection {
	if dbName == "" {
		return session.DB(config.DBName).C(name)
	}
	return session.DB(dbName).C(name)
}

func GetCol(dbName, col string) (session *mgo.Session, collection *mgo.Collection) {
	session = NewSession()
	collection = NewCollection(session, dbName, col)
	return
}

func NewObjectId() bson.ObjectId {
	return bson.NewObjectId()
}

func IsMgoNotFound(err error) bool {
	return err == mgo.ErrNotFound
}

func IsMgoDup(err error) bool {
	return mgo.IsDup(err)
}
<commit_msg>当session被Refresh后，被clone将导致重复验证的情况 (#101)<commit_after>package db

import (
	"errors"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var config *MongoConfig
var instances []*mgo.Session
var instanceOnce sync.Once
var instancesIndex uint32

const mgoMaxSessions = 8

type M bson.M

func (m M) Update(qs ...M) M {
	for _, q := range qs {
		for k, v := range q {
			m[k] = v
		}
	}
	return m
}

var ErrOperaBeforeInit = errors.New("please set db.SetOnFinishInit when needed operating db in init()")

// non-multhreads
var afterEvents []func()
var indexEvents []func()

func EnsureAllIndex() {
	for _, f := range indexEvents {
		f()
	}
}

func SetOnEnsureIndex(f func()) {
	indexEvents = append(indexEvents, f)
}

func SetOnFinishInit(f func()) {
	if IsFinishInit() {
		f()
		return
	}
	afterEvents = append(afterEvents, f)
}

func IsFinishInit() bool {
	return instances != nil
}

func Setup(c *MongoConfig) {
	config = c
}

func ShareSession() *mgo.Session {
	doInit := false
	instanceOnce.Do(func() {
		instances = MustNewMgoSessions(config)
	})

	if doInit {
		for _, f := range afterEvents {
			f()
		}
	}

	i := atomic.AddUint32(&instancesIndex, 1)
	i = i % uint32(len(instances))
	return instances[int(i)].Clone()
}

func MustNewMgoSessions(config *MongoConfig) []*mgo.Session {
	sessions := make([]*mgo.Session, mgoMaxSessions)
	for i := 0; i < mgoMaxSessions; i++ {
		if config == nil {
			panic(ErrOperaBeforeInit)
		}
		session, err := mgo.Dial(config.MongoDB)
		if err != nil {
			panic(err)
		}
		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)
		if err := session.Ping(); err != nil {
			panic(err)
		}

		poolLimit := config.PoolLimit
		if poolLimit <= 0 {
			poolLimit = 16
		}

		session.SetPoolLimit(poolLimit)
		sessions[i] = session

		// Refresh session in case of network error.
		go func(s *mgo.Session) {
			for {
				if err := s.Ping(); err != nil {
					s.Refresh()
					s.Ping()
				}
				time.Sleep(time.Second)
			}
		}(session)
	}

	return sessions
}

func InID(ids []string) (ret M) {
	return M{"_id": M{"$in": ObjectIds(ids)}}
}

func In(ids []string) M {
	return M{"$in": ObjectIds(ids)}
}

func ObjectIds(ids []string) (ret []bson.ObjectId) {
	ret = make([]bson.ObjectId, 0, len(ids))
	for _, id := range ids {
		id = strings.TrimSpace(id)
		if bson.IsObjectIdHex(id) {
			ret = append(ret, bson.ObjectIdHex(id))
		}
	}
	return
}

func NewSession() (session *mgo.Session) {
	return ShareSession()
}

func NewCollection(session *mgo.Session, dbName, name string) *mgo.Collection {
	if dbName == "" {
		return session.DB(config.DBName).C(name)
	}
	return session.DB(dbName).C(name)
}

func GetCol(dbName, col string) (session *mgo.Session, collection *mgo.Collection) {
	session = NewSession()
	collection = NewCollection(session, dbName, col)
	return
}

func NewObjectId() bson.ObjectId {
	return bson.NewObjectId()
}

func IsMgoNotFound(err error) bool {
	return err == mgo.ErrNotFound
}

func IsMgoDup(err error) bool {
	return mgo.IsDup(err)
}
<|endoftext|>


<commit_before>package properties

import (
	"fmt"
	"sync"

	"github.com/cloudfoundry-incubator/garden"
)

type Manager struct {
	propMutex sync.RWMutex
	prop      map[string]map[string]string
}

func NewManager() *Manager {
	return &Manager{
		prop: make(map[string]map[string]string),
	}
}

func (m *Manager) CreateKeySpace(handle string) error {
	if _, exists := m.prop[handle]; !exists {
		m.prop[handle] = make(map[string]string)
	}
	return nil
}

func (m *Manager) DestroyKeySpace(handle string) error {
	if _, exists := m.prop[handle]; !exists {
		return NoSuchKeySpaceError{
			Message: fmt.Sprintf("No such key space: %s", handle),
		}
	}

	delete(m.prop, handle)

	return nil
}

func (m *Manager) Set(handle string, name string, value string) error {
	m.propMutex.Lock()
	defer m.propMutex.Unlock()

	m.prop[handle][name] = value
	return nil
}

func (m *Manager) All(handle string) (garden.Properties, error) {
	m.propMutex.RLock()
	defer m.propMutex.RUnlock()

	return m.prop[handle], nil
}

func (m *Manager) Get(handle string, name string) (string, error) {
	var (
		prop   string
		exists bool
	)

	m.propMutex.RLock()
	defer m.propMutex.RUnlock()

	if prop, exists = m.prop[handle][name]; !exists {
		return "", NoSuchPropertyError{
			Message: fmt.Sprintf("No such property: %s", name),
		}
	}

	return prop, nil
}

func (m *Manager) Remove(handle string, name string) error {
	if _, exists := m.prop[handle][name]; !exists {
		return NoSuchPropertyError{
			Message: fmt.Sprintf("No such property: %s", name),
		}
	}

	delete(m.prop[handle], name)

	return nil
}

type NoSuchPropertyError struct {
	Message string
}

func (e NoSuchPropertyError) Error() string {
	return e.Message
}

type NoSuchKeySpaceError struct {
	Message string
}

func (e NoSuchKeySpaceError) Error() string {
	return e.Message
}
<commit_msg>Make propertymanager thread safe<commit_after>package properties

import (
	"fmt"
	"sync"

	"github.com/cloudfoundry-incubator/garden"
)

type Manager struct {
	propMutex sync.RWMutex
	prop      map[string]map[string]string
}

func NewManager() *Manager {
	return &Manager{
		prop: make(map[string]map[string]string),
	}
}

func (m *Manager) CreateKeySpace(handle string) error {
	m.propMutex.Lock()
	defer m.propMutex.Unlock()

	if _, exists := m.prop[handle]; !exists {
		m.prop[handle] = make(map[string]string)
	}

	return nil
}

func (m *Manager) DestroyKeySpace(handle string) error {
	m.propMutex.Lock()
	defer m.propMutex.Unlock()

	if _, exists := m.prop[handle]; !exists {
		return NoSuchKeySpaceError{
			Message: fmt.Sprintf("No such key space: %s", handle),
		}
	}

	delete(m.prop, handle)

	return nil
}

func (m *Manager) Set(handle string, name string, value string) error {
	m.propMutex.Lock()
	defer m.propMutex.Unlock()

	m.prop[handle][name] = value
	return nil
}

func (m *Manager) All(handle string) (garden.Properties, error) {
	m.propMutex.RLock()
	defer m.propMutex.RUnlock()

	return m.prop[handle], nil
}

func (m *Manager) Get(handle string, name string) (string, error) {
	var (
		prop   string
		exists bool
	)

	m.propMutex.RLock()
	defer m.propMutex.RUnlock()

	if prop, exists = m.prop[handle][name]; !exists {
		return "", NoSuchPropertyError{
			Message: fmt.Sprintf("No such property: %s", name),
		}
	}

	return prop, nil
}

func (m *Manager) Remove(handle string, name string) error {
	m.propMutex.Lock()
	defer m.propMutex.Unlock()

	if _, exists := m.prop[handle][name]; !exists {
		return NoSuchPropertyError{
			Message: fmt.Sprintf("No such property: %s", name),
		}
	}

	delete(m.prop[handle], name)

	return nil
}

type NoSuchPropertyError struct {
	Message string
}

func (e NoSuchPropertyError) Error() string {
	return e.Message
}

type NoSuchKeySpaceError struct {
	Message string
}

func (e NoSuchKeySpaceError) Error() string {
	return e.Message
}
<|endoftext|>


<commit_before>// Copyright 2014 Sergii Bogomolov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package dbhelper helps to interact with sql.DB by generating, preparing and
// executing queries. It marshals Go structs to and from databases and uses
// database/sql.
//
// Source code and project home:
// https://github.com/biggunsv/dbhelper
//
package dbhelper

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"time"
)

var (
	paramRegexp *regexp.Regexp
	errorNil    = errors.New("dbhelper: cannot use nil to define type")
)

func init() {
	paramRegexp = regexp.MustCompile(`:[^,\s)]*`)
}

func typeOf(i interface{}) (reflect.Type, error) {
	if i == nil {
		return nil, errorNil
	}

	t := reflect.TypeOf(i)
	if t.Kind() != reflect.Ptr {
		return t, nil
	}

	return t.Elem(), nil
}

func wrapError(err error) error {
	return errors.New(fmt.Sprintf("dbhelper: %v", err))
}

func checkFieldType(t reflect.Type) bool {
	kind := t.Kind()
	return kind == reflect.String ||
		kind == reflect.Int ||
		kind == reflect.Int8 ||
		kind == reflect.Int16 ||
		kind == reflect.Int32 ||
		kind == reflect.Int64 ||
		kind == reflect.Float32 ||
		kind == reflect.Float64 ||
		kind == reflect.Bool
}

// DbHelper contains all data about database and tables.
type DbHelper struct {
	// Pointer to underlying sql.DB.
	Db *sql.DB

	sqlDialect SqlDialect
	tables     map[reflect.Type]*dbTable
}

// New returns new DbHelper.
func New(db *sql.DB, sqlDialect SqlDialect) *DbHelper {
	return &DbHelper{
		Db:         db,
		sqlDialect: sqlDialect,
		tables:     make(map[reflect.Type]*dbTable),
	}
}

// AddTable adds a connection between type of i and table name.
// There is no difference what to use, type or pointer to type.
func (dbh *DbHelper) AddTable(i interface{}, name string) error {
	t, err := typeOf(i)
	if err != nil {
		return err
	}

	tbl, ok := dbh.tables[t]
	if ok {
		return errors.New(fmt.Sprintf("dbhelper: type '%v' already has assigned table name '%s'", t, tbl.name))
	}

	if name == "" {
		return errors.New("dbhelper: table name cannot be an empty string")
	}

	tbl, err = dbh.newDbTable(t, name)
	if err != nil {
		return err
	}

	dbh.tables[t] = tbl

	return nil
}

// RemoveTable removes a connection between type of i and table name assigned to it.
// Returns true if connection was removed and false if there were no connection or if i is nil.
func (dbh *DbHelper) RemoveTable(i interface{}) bool {
	if i == nil {
		return false
	}

	t, err := typeOf(i)
	if err != nil {
		return false
	}

	_, ok := dbh.tables[t]
	if ok {
		delete(dbh.tables, t)
		return true
	}

	return false
}

func (dbh *DbHelper) getTable(t reflect.Type) (*dbTable, error) {
	tbl, ok := dbh.tables[t]
	if !ok {
		return nil, errors.New(fmt.Sprintf("dbhelper: type '%v' has no assigned table", t))
	}

	return tbl, nil
}

func (dbh *DbHelper) getPlaceholders(n int) []string {
	a := make([]string, n, n)
	ph := dbh.sqlDialect.placeholder()
	for i := 1; i < n; i++ {
		a[i] = ph.next()
	}

	return a
}

// Prepares SQL query. Prepared query can be executed with different parameter values.
func (dbh *DbHelper) Prepare(query string) (*Pstmt, error) {
	ph := dbh.sqlDialect.placeholder()
	params := paramRegexp.FindAllString(query, -1)
	for i, p := range params {
		if len(p) < 2 {
			return nil, errors.New(fmt.Sprintf("dbhelper: wrong parameter placeholder: '%s'", p))
		}

		// replaced named parameter with placeholder
		query = strings.Replace(query, p, ph.next(), 1)

		// store named parameter
		params[i] = p[1:]
	}

	// prepare query
	stmt, err := dbh.Db.Prepare(query)
	if err != nil {
		return nil, wrapError(err)
	}

	pstmp := &Pstmt{
		dbHelper: dbh,
		params:   params,
		stmt:     stmt,
	}

	return pstmp, nil
}

// Prepares standard select SQL query by value of one column.
// Prepared query can be executed with different parameter values.
func (dbh *DbHelper) PrepareSelect(i interface{}, column string) (*Pstmt, error) {
	// get type
	t, err := typeOf(i)
	if err != nil {
		return nil, err
	}

	// get table
	tbl, err := dbh.getTable(t)
	if err != nil {
		return nil, err
	}

	// check column name
	_, ok := tbl.fields[column]
	if !ok {
		return nil, errors.New(fmt.Sprintf("dbhelper: structure type '%v' has no field assigned to column '%s' of table '%s'",
			t, column, tbl.name))
	}

	// select query
	query := fmt.Sprintf("SELECT * FORM %s WHERE %s = :%s", tbl.name, column, column)

	// prepare query
	return dbh.Prepare(query)
}

// Prepares parameters for standard query.
func (dbh *DbHelper) prepareParams(i interface{}) (tbl *dbTable, params map[string]interface{}, v reflect.Value, err error) {
	// get structure type
	t, err := typeOf(i)
	if err != nil {
		return
	}

	// get table
	tbl, err = dbh.getTable(t)
	if err != nil {
		return
	}

	// get value of structure to insert
	v = reflect.ValueOf(i)
	if v.Type().Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// get parameter values
	l := len(tbl.insertQuery.params)
	params = make(map[string]interface{}, l)
	for _, f := range tbl.fields {
		params[f.column] = v.FieldByIndex(f.index).Interface()
	}

	return
}

// Inserts new record to databse. Field with option 'id' is automatically updated.
func (dbh *DbHelper) Insert(i interface{}) error {
	// get current timestamp
	time := time.Now().UTC().Unix()

	// prepare parameters
	tbl, params, v, err := dbh.prepareParams(i)
	if err != nil {
		return err
	}

	// set created time
	if tbl.createdField != nil {
		params[tbl.createdField.column] = time
	}

	// set modified time
	if tbl.modifiedField != nil {
		params[tbl.modifiedField.column] = time
	}

	var id int64
	if sqld, ok := dbh.sqlDialect.(hasCustomInsert); ok {
		// custom insert
		id, err = sqld.insert(tbl, params)
		if err != nil {
			return err
		}
	} else {
		// standart insert
		res, err := tbl.insertQuery.exec(params)
		if err != nil {
			return err
		}

		// get last inserted id
		id, err = res.LastInsertId()
		if err != nil {
			return nil
		}
	}

	// udpate id field in structure
	v.FieldByIndex(tbl.idField.index).SetInt(id)

	// update created field in structure
	if tbl.createdField != nil {
		v.FieldByIndex(tbl.createdField.index).SetInt(time)
	}

	// update modified field in structure
	if tbl.modifiedField != nil {
		v.FieldByIndex(tbl.modifiedField.index).SetInt(time)
	}

	return nil
}

// Updates record(s) in database and returns number of affected rows.
// Field with option 'id' is used to define the record in database.
// This means that field with option 'id' cannot be updated.
func (dbh *DbHelper) Update(i interface{}) (int64, error) {
	// get current timestamp
	time := time.Now().UTC().Unix()

	// prepare parameters
	tbl, params, v, err := dbh.prepareParams(i)
	if err != nil {
		return 0, err
	}

	// set modified time
	if tbl.modifiedField != nil {
		params[tbl.modifiedField.column] = time
	}

	// standart update
	num, err := tbl.updateQuery.Exec(params)
	if err != nil {
		return 0, err
	}

	// update modified field in structure
	if tbl.modifiedField != nil {
		v.FieldByIndex(tbl.modifiedField.index).SetInt(time)
	}

	return num, nil
}

// Deletes record(s) in database and returns number of affected rows.
// Field with option 'id' is used to define the record in database.
func (dbh *DbHelper) Delete(i interface{}) (int64, error) {
	// prepare parameters
	tbl, params, _, err := dbh.prepareParams(i)
	if err != nil {
		return 0, err
	}

	// standart update
	num, err := tbl.deleteQuery.Exec(params)
	if err != nil {
		return 0, err
	}

	return num, nil
}
<commit_msg>Fixed error in PrepareSelect() in SQL query<commit_after>// Copyright 2014 Sergii Bogomolov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package dbhelper helps to interact with sql.DB by generating, preparing and
// executing queries. It marshals Go structs to and from databases and uses
// database/sql.
//
// Source code and project home:
// https://github.com/biggunsv/dbhelper
//
package dbhelper

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"time"
)

var (
	paramRegexp *regexp.Regexp
	errorNil    = errors.New("dbhelper: cannot use nil to define type")
)

func init() {
	paramRegexp = regexp.MustCompile(`:[^,\s)]*`)
}

func typeOf(i interface{}) (reflect.Type, error) {
	if i == nil {
		return nil, errorNil
	}

	t := reflect.TypeOf(i)
	if t.Kind() != reflect.Ptr {
		return t, nil
	}

	return t.Elem(), nil
}

func wrapError(err error) error {
	return errors.New(fmt.Sprintf("dbhelper: %v", err))
}

func checkFieldType(t reflect.Type) bool {
	kind := t.Kind()
	return kind == reflect.String ||
		kind == reflect.Int ||
		kind == reflect.Int8 ||
		kind == reflect.Int16 ||
		kind == reflect.Int32 ||
		kind == reflect.Int64 ||
		kind == reflect.Float32 ||
		kind == reflect.Float64 ||
		kind == reflect.Bool
}

// DbHelper contains all data about database and tables.
type DbHelper struct {
	// Pointer to underlying sql.DB.
	Db *sql.DB

	sqlDialect SqlDialect
	tables     map[reflect.Type]*dbTable
}

// New returns new DbHelper.
func New(db *sql.DB, sqlDialect SqlDialect) *DbHelper {
	return &DbHelper{
		Db:         db,
		sqlDialect: sqlDialect,
		tables:     make(map[reflect.Type]*dbTable),
	}
}

// AddTable adds a connection between type of i and table name.
// There is no difference what to use, type or pointer to type.
func (dbh *DbHelper) AddTable(i interface{}, name string) error {
	t, err := typeOf(i)
	if err != nil {
		return err
	}

	tbl, ok := dbh.tables[t]
	if ok {
		return errors.New(fmt.Sprintf("dbhelper: type '%v' already has assigned table name '%s'", t, tbl.name))
	}

	if name == "" {
		return errors.New("dbhelper: table name cannot be an empty string")
	}

	tbl, err = dbh.newDbTable(t, name)
	if err != nil {
		return err
	}

	dbh.tables[t] = tbl

	return nil
}

// RemoveTable removes a connection between type of i and table name assigned to it.
// Returns true if connection was removed and false if there were no connection or if i is nil.
func (dbh *DbHelper) RemoveTable(i interface{}) bool {
	if i == nil {
		return false
	}

	t, err := typeOf(i)
	if err != nil {
		return false
	}

	_, ok := dbh.tables[t]
	if ok {
		delete(dbh.tables, t)
		return true
	}

	return false
}

func (dbh *DbHelper) getTable(t reflect.Type) (*dbTable, error) {
	tbl, ok := dbh.tables[t]
	if !ok {
		return nil, errors.New(fmt.Sprintf("dbhelper: type '%v' has no assigned table", t))
	}

	return tbl, nil
}

func (dbh *DbHelper) getPlaceholders(n int) []string {
	a := make([]string, n, n)
	ph := dbh.sqlDialect.placeholder()
	for i := 1; i < n; i++ {
		a[i] = ph.next()
	}

	return a
}

// Prepares SQL query. Prepared query can be executed with different parameter values.
func (dbh *DbHelper) Prepare(query string) (*Pstmt, error) {
	ph := dbh.sqlDialect.placeholder()
	params := paramRegexp.FindAllString(query, -1)
	for i, p := range params {
		if len(p) < 2 {
			return nil, errors.New(fmt.Sprintf("dbhelper: wrong parameter placeholder: '%s'", p))
		}

		// replaced named parameter with placeholder
		query = strings.Replace(query, p, ph.next(), 1)

		// store named parameter
		params[i] = p[1:]
	}

	// prepare query
	stmt, err := dbh.Db.Prepare(query)
	if err != nil {
		return nil, wrapError(err)
	}

	pstmp := &Pstmt{
		dbHelper: dbh,
		params:   params,
		stmt:     stmt,
	}

	return pstmp, nil
}

// Prepares standard select SQL query by value of one column.
// Prepared query can be executed with different parameter values.
func (dbh *DbHelper) PrepareSelect(i interface{}, column string) (*Pstmt, error) {
	// get type
	t, err := typeOf(i)
	if err != nil {
		return nil, err
	}

	// get table
	tbl, err := dbh.getTable(t)
	if err != nil {
		return nil, err
	}

	// check column name
	_, ok := tbl.fields[column]
	if !ok {
		return nil, errors.New(fmt.Sprintf("dbhelper: structure type '%v' has no field assigned to column '%s' of table '%s'",
			t, column, tbl.name))
	}

	// select query
	query := fmt.Sprintf("SELECT * FROM %s WHERE %s = :%s", tbl.name, column, column)

	// prepare query
	return dbh.Prepare(query)
}

// Prepares parameters for standard query.
func (dbh *DbHelper) prepareParams(i interface{}) (tbl *dbTable, params map[string]interface{}, v reflect.Value, err error) {
	// get structure type
	t, err := typeOf(i)
	if err != nil {
		return
	}

	// get table
	tbl, err = dbh.getTable(t)
	if err != nil {
		return
	}

	// get value of structure to insert
	v = reflect.ValueOf(i)
	if v.Type().Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// get parameter values
	l := len(tbl.insertQuery.params)
	params = make(map[string]interface{}, l)
	for _, f := range tbl.fields {
		params[f.column] = v.FieldByIndex(f.index).Interface()
	}

	return
}

// Inserts new record to databse. Field with option 'id' is automatically updated.
func (dbh *DbHelper) Insert(i interface{}) error {
	// get current timestamp
	time := time.Now().UTC().Unix()

	// prepare parameters
	tbl, params, v, err := dbh.prepareParams(i)
	if err != nil {
		return err
	}

	// set created time
	if tbl.createdField != nil {
		params[tbl.createdField.column] = time
	}

	// set modified time
	if tbl.modifiedField != nil {
		params[tbl.modifiedField.column] = time
	}

	var id int64
	if sqld, ok := dbh.sqlDialect.(hasCustomInsert); ok {
		// custom insert
		id, err = sqld.insert(tbl, params)
		if err != nil {
			return err
		}
	} else {
		// standart insert
		res, err := tbl.insertQuery.exec(params)
		if err != nil {
			return err
		}

		// get last inserted id
		id, err = res.LastInsertId()
		if err != nil {
			return nil
		}
	}

	// udpate id field in structure
	v.FieldByIndex(tbl.idField.index).SetInt(id)

	// update created field in structure
	if tbl.createdField != nil {
		v.FieldByIndex(tbl.createdField.index).SetInt(time)
	}

	// update modified field in structure
	if tbl.modifiedField != nil {
		v.FieldByIndex(tbl.modifiedField.index).SetInt(time)
	}

	return nil
}

// Updates record(s) in database and returns number of affected rows.
// Field with option 'id' is used to define the record in database.
// This means that field with option 'id' cannot be updated.
func (dbh *DbHelper) Update(i interface{}) (int64, error) {
	// get current timestamp
	time := time.Now().UTC().Unix()

	// prepare parameters
	tbl, params, v, err := dbh.prepareParams(i)
	if err != nil {
		return 0, err
	}

	// set modified time
	if tbl.modifiedField != nil {
		params[tbl.modifiedField.column] = time
	}

	// standart update
	num, err := tbl.updateQuery.Exec(params)
	if err != nil {
		return 0, err
	}

	// update modified field in structure
	if tbl.modifiedField != nil {
		v.FieldByIndex(tbl.modifiedField.index).SetInt(time)
	}

	return num, nil
}

// Deletes record(s) in database and returns number of affected rows.
// Field with option 'id' is used to define the record in database.
func (dbh *DbHelper) Delete(i interface{}) (int64, error) {
	// prepare parameters
	tbl, params, _, err := dbh.prepareParams(i)
	if err != nil {
		return 0, err
	}

	// standart update
	num, err := tbl.deleteQuery.Exec(params)
	if err != nil {
		return 0, err
	}

	return num, nil
}
<|endoftext|>


<commit_before>package jsok

import (
	"errors"
	"os/exec"
        "path"
        "path/filepath"
        "runtime"
)

// Lint the source file.
func JsLint(p string) error {
	out, err := exec.Command("jsl", "-nologo", "-nofilelisting", "-nosummary", "-output-format", "__FILE__:__LINE__:__COL__: __ERROR__", "-process", p).Output()
	if err != nil {
		return errors.New(string(out))
	}
	return nil
}

func JsExec(p string) error {
        _, filename, _, _ := runtime.Caller(0)
        thisDir := path.Dir(filename)

	out, err := exec.Command("node", filepath.Join(thisDir, "yoink-adapter.js"), p).Output()
	if err != nil {
		return errors.New(string(out))
	}
	return nil
}
<commit_msg>When test fails, include test's stderr in error message.<commit_after>package jsok

import (
	"errors"
	"os/exec"
        "path"
        "path/filepath"
        "runtime"
)

// Lint the source file.
func JsLint(p string) error {
	out, err := exec.Command("jsl", "-nologo", "-nofilelisting", "-nosummary", "-output-format", "__FILE__:__LINE__:__COL__: __ERROR__", "-process", p).Output()
	if err != nil {
		return errors.New(string(out))
	}
	return nil
}

func JsExec(p string) error {
        _, filename, _, _ := runtime.Caller(0)
        thisDir := path.Dir(filename)

	out, err := exec.Command("node", filepath.Join(thisDir, "yoink-adapter.js"), p).CombinedOutput()
	if err != nil {
		return errors.New(string(out))
	}
	return nil
}
<|endoftext|>