<commit_before>package acceptance_test

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"code.cloudfoundry.org/cf-networking-helpers/testsupport"

	pusherConfig "cf-pusher/config"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	. "github.com/onsi/ginkgo"
	ginkgoConfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const Timeout_Push = 2 * time.Minute

var (
	appsDir    string
	config     helpers.Config
	testConfig pusherConfig.Config
)

func TestAcceptance(t *testing.T) {
	RegisterFailHandler(Fail)

	BeforeSuite(func() {
		config = helpers.LoadConfig()

		configPath := helpers.ConfigPath()
		configBytes, err := ioutil.ReadFile(configPath)
		Expect(err).NotTo(HaveOccurred())

		err = json.Unmarshal(configBytes, &testConfig)
		Expect(err).NotTo(HaveOccurred())

		if testConfig.Applications <= 0 {
			Fail("Applications count needs to be greater than 0")
		}

		if testConfig.AppInstances <= 0 {
			Fail("AppInstances count needs to be greater than 0")
		}

		if testConfig.ProxyApplications <= 0 {
			Fail("ProxyApplications count needs to be greater than 0")
		}

		if testConfig.ProxyInstances <= 0 {
			Fail("ProxyInstances count needs to be greater than 0")
		}

		Expect(cf.Cf("api", "--skip-ssl-validation", config.ApiEndpoint).Wait(Timeout_Short)).To(gexec.Exit(0))
		AuthAsAdmin()

		appsDir = os.Getenv("APPS_DIR")
		Expect(appsDir).NotTo(BeEmpty())

		rand.Seed(ginkgoConfig.GinkgoConfig.RandomSeed + int64(GinkgoParallelNode()))
	})

	RunSpecs(t, "Acceptance Suite")
}

func Auth(username, password string) {
	By("authenticating as " + username)
	cmd := exec.Command("cf", "auth", username, password)
	sess, err := gexec.Start(cmd, nil, nil)
	Expect(err).NotTo(HaveOccurred())
	Eventually(sess.Wait(Timeout_Short)).Should(gexec.Exit(0))
}

func getUAABaseURL() string {
	sess := cf.Cf("curl", "/v2/info")
	Eventually(sess.Wait(Timeout_Short)).Should(gexec.Exit(0))
	var response struct {
		TokenEndpoint string `json:"token_endpoint"`
	}
	err := json.Unmarshal(sess.Out.Contents(), &response)
	Expect(err).NotTo(HaveOccurred())

	uaaBaseURL := response.TokenEndpoint
	Expect(uaaBaseURL).To(HavePrefix("https://uaa."))
	return uaaBaseURL
}

func AuthAsAdmin() {
	Auth(config.AdminUser, config.AdminPassword)
}

func appDir(appType string) string {
	return filepath.Join(appsDir, appType)
}

func pushProxy(appName string) {
	Expect(cf.Cf(
		"push", appName,
		"-p", appDir("proxy"),
		"-f", defaultManifest("proxy"),
	).Wait(Timeout_Push)).To(gexec.Exit(0))
}

func defaultManifest(appType string) string {
	return filepath.Join(appDir(appType), "manifest.yml")
}

func scaleApps(apps []string, instances int) {
	parallelRunner := &testsupport.ParallelRunner{
		NumWorkers: 16,
	}
	parallelRunner.RunOnSliceStrings(apps, func(app string) {
		scaleApp(app, instances)
	})
}

func scaleApp(appName string, instances int) {
	Expect(cf.Cf(
		"scale", appName,
		"-i", fmt.Sprintf("%d", instances),
	).Wait(Timeout_Short)).To(gexec.Exit(0))

	waitForAllInstancesToBeRunning(appName)
}

func pushAppWithInstanceCount(appName string, appCount int) {
	Expect(cf.Cf(
		"push", appName,
		"-p", appDir("proxy"),
		"-i", fmt.Sprintf("%d", appCount),
		"-f", defaultManifest("proxy"),
	).Wait(Timeout_Push)).To(gexec.Exit(0))

	waitForAllInstancesToBeRunning(appName)
}

func waitForAllInstancesToBeRunning(appName string) {
	appGuidSession := cf.Cf("app", appName, "--guid")
	Expect(appGuidSession.Wait(Timeout_Short)).To(gexec.Exit(0))

	capiURL := fmt.Sprintf("v2/apps/%s/instances", strings.TrimSpace(string(appGuidSession.Out.Contents())))

	type instanceInfo struct {
		State string `json:"state"`
	}

	instances := make(map[string]instanceInfo)

	allInstancesRunning := func() bool {
		session := cf.Cf("curl", capiURL)
		Expect(session.Wait(Timeout_Short)).To(gexec.Exit(0))

		json.Unmarshal(session.Out.Contents(), &instances)
		Expect(instances).To(Not(BeEmpty()))

		for _, instance := range instances {
			if instance.State != "RUNNING" {
				return false
			}
		}
		return true
	}

	Eventually(allInstancesRunning).Should(Equal(true), "not all instances running")

}

func restage(appName string) {
	Expect(cf.Cf(
		"restage", appName,
	).Wait(Timeout_Push)).To(gexec.Exit(0))

	waitForAllInstancesToBeRunning(appName)
}

type AppInstance struct {
	hostIdentifier string
	index          string
	internalIP     string
}

func getAppInstances(appName string, instances int) []AppInstance {
	apps := make([]AppInstance, instances)
	for i := 0; i < instances; i++ {
		session := cf.Cf("ssh", appName, "-i", fmt.Sprintf("%d", i), "-c", "env | grep CF_INSTANCE")
		Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))

		env := strings.Split(string(session.Out.Contents()), "\n")
		var app AppInstance
		for _, envVar := range env {
			kv := strings.Split(envVar, "=")
			switch kv[0] {
			case "CF_INSTANCE_IP":
				app.hostIdentifier = kv[1]
			case "CF_INSTANCE_INDEX":
				app.index = kv[1]
			case "CF_INSTANCE_INTERNAL_IP":
				app.internalIP = kv[1]
			}
		}
		apps[i] = app
	}
	return apps
}

func findTwoInstancesOnTheSameHost(apps []AppInstance) (AppInstance, AppInstance) {
	hostsToApps := map[string]AppInstance{}

	for _, app := range apps {
		foundApp, ok := hostsToApps[app.hostIdentifier]
		if ok {
			return foundApp, app
		}
		hostsToApps[app.hostIdentifier] = app
	}

	Expect(errors.New("failed to find two instances on the same host")).ToNot(HaveOccurred())
	return AppInstance{}, AppInstance{}
}

func findTwoInstancesOnDifferentHosts(apps []AppInstance) (AppInstance, AppInstance) {
	for _, app := range apps[1:] {
		if apps[0].hostIdentifier != app.hostIdentifier {
			return apps[0], app
		}
	}

	Expect(errors.New("failed to find two instances on different hosts")).ToNot(HaveOccurred())
	return AppInstance{}, AppInstance{}
}
<commit_msg>Do not wait for instances on scaling in acceptance tests<commit_after>package acceptance_test

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"code.cloudfoundry.org/cf-networking-helpers/testsupport"

	pusherConfig "cf-pusher/config"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	. "github.com/onsi/ginkgo"
	ginkgoConfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const Timeout_Push = 2 * time.Minute

var (
	appsDir    string
	config     helpers.Config
	testConfig pusherConfig.Config
)

func TestAcceptance(t *testing.T) {
	RegisterFailHandler(Fail)

	BeforeSuite(func() {
		config = helpers.LoadConfig()

		configPath := helpers.ConfigPath()
		configBytes, err := ioutil.ReadFile(configPath)
		Expect(err).NotTo(HaveOccurred())

		err = json.Unmarshal(configBytes, &testConfig)
		Expect(err).NotTo(HaveOccurred())

		if testConfig.Applications <= 0 {
			Fail("Applications count needs to be greater than 0")
		}

		if testConfig.AppInstances <= 0 {
			Fail("AppInstances count needs to be greater than 0")
		}

		if testConfig.ProxyApplications <= 0 {
			Fail("ProxyApplications count needs to be greater than 0")
		}

		if testConfig.ProxyInstances <= 0 {
			Fail("ProxyInstances count needs to be greater than 0")
		}

		Expect(cf.Cf("api", "--skip-ssl-validation", config.ApiEndpoint).Wait(Timeout_Short)).To(gexec.Exit(0))
		AuthAsAdmin()

		appsDir = os.Getenv("APPS_DIR")
		Expect(appsDir).NotTo(BeEmpty())

		rand.Seed(ginkgoConfig.GinkgoConfig.RandomSeed + int64(GinkgoParallelNode()))
	})

	RunSpecs(t, "Acceptance Suite")
}

func Auth(username, password string) {
	By("authenticating as " + username)
	cmd := exec.Command("cf", "auth", username, password)
	sess, err := gexec.Start(cmd, nil, nil)
	Expect(err).NotTo(HaveOccurred())
	Eventually(sess.Wait(Timeout_Short)).Should(gexec.Exit(0))
}

func getUAABaseURL() string {
	sess := cf.Cf("curl", "/v2/info")
	Eventually(sess.Wait(Timeout_Short)).Should(gexec.Exit(0))
	var response struct {
		TokenEndpoint string `json:"token_endpoint"`
	}
	err := json.Unmarshal(sess.Out.Contents(), &response)
	Expect(err).NotTo(HaveOccurred())

	uaaBaseURL := response.TokenEndpoint
	Expect(uaaBaseURL).To(HavePrefix("https://uaa."))
	return uaaBaseURL
}

func AuthAsAdmin() {
	Auth(config.AdminUser, config.AdminPassword)
}

func appDir(appType string) string {
	return filepath.Join(appsDir, appType)
}

func pushProxy(appName string) {
	Expect(cf.Cf(
		"push", appName,
		"-p", appDir("proxy"),
		"-f", defaultManifest("proxy"),
	).Wait(Timeout_Push)).To(gexec.Exit(0))
}

func defaultManifest(appType string) string {
	return filepath.Join(appDir(appType), "manifest.yml")
}

func scaleApps(apps []string, instances int) {
	parallelRunner := &testsupport.ParallelRunner{
		NumWorkers: 16,
	}
	parallelRunner.RunOnSliceStrings(apps, func(app string) {
		scaleApp(app, instances)
	})
}

func scaleApp(appName string, instances int) {
	Expect(cf.Cf(
		"scale", appName,
		"-i", fmt.Sprintf("%d", instances),
	).Wait(Timeout_Short)).To(gexec.Exit(0))
}

func pushAppWithInstanceCount(appName string, appCount int) {
	Expect(cf.Cf(
		"push", appName,
		"-p", appDir("proxy"),
		"-i", fmt.Sprintf("%d", appCount),
		"-f", defaultManifest("proxy"),
	).Wait(Timeout_Push)).To(gexec.Exit(0))

	waitForAllInstancesToBeRunning(appName)
}

func waitForAllInstancesToBeRunning(appName string) {
	appGuidSession := cf.Cf("app", appName, "--guid")
	Expect(appGuidSession.Wait(Timeout_Short)).To(gexec.Exit(0))

	capiURL := fmt.Sprintf("v2/apps/%s/instances", strings.TrimSpace(string(appGuidSession.Out.Contents())))

	type instanceInfo struct {
		State string `json:"state"`
	}

	instances := make(map[string]instanceInfo)

	allInstancesRunning := func() bool {
		session := cf.Cf("curl", capiURL)
		Expect(session.Wait(Timeout_Short)).To(gexec.Exit(0))

		json.Unmarshal(session.Out.Contents(), &instances)
		Expect(instances).To(Not(BeEmpty()))

		for _, instance := range instances {
			if instance.State != "RUNNING" {
				return false
			}
		}
		return true
	}

	Eventually(allInstancesRunning).Should(Equal(true), "not all instances running")
}

func restage(appName string) {
	Expect(cf.Cf(
		"restage", appName,
	).Wait(Timeout_Push)).To(gexec.Exit(0))

	waitForAllInstancesToBeRunning(appName)
}

type AppInstance struct {
	hostIdentifier string
	index          string
	internalIP     string
}

func getAppInstances(appName string, instances int) []AppInstance {
	apps := make([]AppInstance, instances)
	for i := 0; i < instances; i++ {
		session := cf.Cf("ssh", appName, "-i", fmt.Sprintf("%d", i), "-c", "env | grep CF_INSTANCE")
		Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))

		env := strings.Split(string(session.Out.Contents()), "\n")
		var app AppInstance
		for _, envVar := range env {
			kv := strings.Split(envVar, "=")
			switch kv[0] {
			case "CF_INSTANCE_IP":
				app.hostIdentifier = kv[1]
			case "CF_INSTANCE_INDEX":
				app.index = kv[1]
			case "CF_INSTANCE_INTERNAL_IP":
				app.internalIP = kv[1]
			}
		}
		apps[i] = app
	}
	return apps
}

func findTwoInstancesOnTheSameHost(apps []AppInstance) (AppInstance, AppInstance) {
	hostsToApps := map[string]AppInstance{}

	for _, app := range apps {
		foundApp, ok := hostsToApps[app.hostIdentifier]
		if ok {
			return foundApp, app
		}
		hostsToApps[app.hostIdentifier] = app
	}

	Expect(errors.New("failed to find two instances on the same host")).ToNot(HaveOccurred())
	return AppInstance{}, AppInstance{}
}

func findTwoInstancesOnDifferentHosts(apps []AppInstance) (AppInstance, AppInstance) {
	for _, app := range apps[1:] {
		if apps[0].hostIdentifier != app.hostIdentifier {
			return apps[0], app
		}
	}

	Expect(errors.New("failed to find two instances on different hosts")).ToNot(HaveOccurred())
	return AppInstance{}, AppInstance{}
}
<|endoftext|>


<commit_before>package lnwallet

// FeeEstimator provides the ability to estimate on-chain transaction fees for
// various combinations of transaction sizes and desired confirmation time
// (measured by number of blocks).
type FeeEstimator interface {
	// EstimateFeePerByte takes in a target for the number of blocks until
	// an initial confirmation and returns the estimated fee expressed in
	// satoshis/byte.
	EstimateFeePerByte(numBlocks uint32) uint64

	// EstimateFeePerWeight takes in a target for the number of blocks
	// until an initial confirmation and returns the estimated fee
	// expressed in satoshis/weight.
	EstimateFeePerWeight(numBlocks uint32) uint64
}

// StaticFeeEstimator will return a static value for all fee calculation
// requests. It is designed to be replaced by a proper fee calculation
// implementation.
type StaticFeeEstimator struct {
	// FeeRate is the static fee rate in satoshis-per-byte that will be
	// returned by this fee estimator. Queries for the fee rate in weight
	// units will be scaled accordingly.
	FeeRate uint64
}

// EstimateFeePerByte will return a static value for fee calculations.
func (e StaticFeeEstimator) EstimateFeePerByte(numBlocks uint32) uint64 {
	return e.FeeRate
}

// EstimateFeePerWeight will return a static value for fee calculations.
func (e StaticFeeEstimator) EstimateFeePerWeight(numBlocks uint32) uint64 {
	return e.FeeRate / 4
}

// A compile-time assertion to ensure that StaticFeeEstimator implements the
// FeeEstimator interface.
var _ FeeEstimator = (*StaticFeeEstimator)(nil)
<commit_msg>lnwallet: extend FeeEstimator methods to be able to return an error<commit_after>package lnwallet

import (
	"github.com/roasbeef/btcutil"
)

// FeeEstimator provides the ability to estimate on-chain transaction fees for
// various combinations of transaction sizes and desired confirmation time
// (measured by number of blocks).
type FeeEstimator interface {
	// EstimateFeePerByte takes in a target for the number of blocks until
	// an initial confirmation and returns the estimated fee expressed in
	// satoshis/byte.
	EstimateFeePerByte(numBlocks uint32) (btcutil.Amount, error)

	// EstimateFeePerWeight takes in a target for the number of blocks
	// until an initial confirmation and returns the estimated fee
	// expressed in satoshis/weight.
	EstimateFeePerWeight(numBlocks uint32) (btcutil.Amount, error)
}

// StaticFeeEstimator will return a static value for all fee calculation
// requests. It is designed to be replaced by a proper fee calculation
// implementation.
type StaticFeeEstimator struct {
	// FeeRate is the static fee rate in satoshis-per-byte that will be
	// returned by this fee estimator. Queries for the fee rate in weight
	// units will be scaled accordingly.
	FeeRate uint64
}

// EstimateFeePerByte will return a static value for fee calculations.
func (e StaticFeeEstimator) EstimateFeePerByte(numBlocks uint32) uint64 {
	return e.FeeRate
}

// EstimateFeePerWeight will return a static value for fee calculations.
func (e StaticFeeEstimator) EstimateFeePerWeight(numBlocks uint32) uint64 {
	return e.FeeRate / 4
}

// A compile-time assertion to ensure that StaticFeeEstimator implements the
// FeeEstimator interface.
var _ FeeEstimator = (*StaticFeeEstimator)(nil)
<|endoftext|>


<commit_before>package grafana

import (
	"encoding/json"
	"time"
)

type DashboardID uint64

type Dashboard struct {
	ID      DashboardID `json:"id"`
	Version uint64      `json:"version"`

	Editable     bool   `json:"editable"`
	GraphTooltip uint8  `json:"graphTooltip"`
	HideControls bool   `json:"hideControls"`
	Rows         []*Row `json:"rows"`
	Style        string `json:"style"`
	Timezone     string `json:"timezone"`
	Title        string `json:"title"`
	tags         []string
	Meta         *DashboardMeta `json:"meta,omitempty"`
}

// NewDashboard creates new Dashboard.
func NewDashboard(title string) *Dashboard {
	return &Dashboard{
		Title: title,
	}
}

func (d *Dashboard) String() string {
	return Stringify(d)
}

// Tags is a getter for Dashboard tags field
func (d *Dashboard) Tags() []string {
	return d.tags
}

// SetTags sets new tags to dashboard
func (d *Dashboard) SetTags(tags ...string) {
	newTags := []string{}
	uniqTags := make(map[string]bool)
	for _, tag := range tags {
		if _, ok := uniqTags[tag]; ok {
			continue
		}

		uniqTags[tag] = true
		newTags = append(newTags, tag)
	}

	d.tags = newTags
}

// AddTags adds given tags to dashboard. This method keeps uniqueness of tags.
func (d *Dashboard) AddTags(tags ...string) {
	tagFound := make(map[string]bool, len(d.tags))
	for _, tag := range d.tags {
		tagFound[tag] = true
	}

	for _, tag := range tags {
		if _, ok := tagFound[tag]; ok {
			continue
		}
		d.tags = append(d.tags, tag)
	}
}

// RemoveTags removes given tags from dashboard. Does nothing if tag is not found.
func (d *Dashboard) RemoveTags(tags ...string) {
	tagIndex := make(map[string]int, len(d.tags))
	for i, tag := range d.tags {
		tagIndex[tag] = i
	}

	for _, tag := range tags {
		if i, ok := tagIndex[tag]; ok {
			d.tags = append(d.tags[:i], d.tags[i+1:]...)
		}
	}
}

// UnmarshalJSON implements json.Unmarshaler interface
func (d *Dashboard) UnmarshalJSON(data []byte) error {
	type JSONDashboard Dashboard
	inDashboard := struct {
		*JSONDashboard
		Tags []string `json:"tags"`
	}{
		JSONDashboard: (*JSONDashboard)(d),
	}
	if err := json.Unmarshal(data, &inDashboard); err != nil {
		return err
	}

	d.tags = inDashboard.Tags

	return nil
}

// MarshalJSON implements json.Marshaler interface
func (d *Dashboard) MarshalJSON() ([]byte, error) {
	type JSONDashboard Dashboard
	dd := (*JSONDashboard)(d)
	dd.Meta = nil

	return json.Marshal(&struct {
		*JSONDashboard
		Tags []string `json:"tags,omitempty"`
	}{
		JSONDashboard: dd,
		Tags:          d.Tags(),
	})
}

type DashboardMeta struct {
	Slug    string `json:"slug"`
	Type    string `json:"type"`
	Version int    `json:"version"`

	CanEdit bool `json:"canEdit"`
	CanSave bool `json:"canSave"`
	CanStar bool `json:"canStar"`

	Created   time.Time `json:"created"`
	CreatedBy string    `json:"createdBy"`
	Expires   time.Time `json:"expires"`
	Updated   time.Time `json:"updated"`
	UpdatedBy string    `json:"updatedBy"`
}

func (dm *DashboardMeta) String() string {
	return Stringify(dm)
}

type Row struct {
	Collapse bool     `json:"collapse"`
	Editable bool     `json:"editable"`
	Height   string   `json:"height"`
	Title    string   `json:"title"`
	Panels   []*Panel `json:"panels"`
}

type Panel struct {
}
<commit_msg>Row draft<commit_after>package grafana

import (
	"encoding/json"
	"time"
)

type DashboardID uint64

type Dashboard struct {
	ID      DashboardID `json:"id"`
	Version uint64      `json:"version"`

	Editable     bool   `json:"editable"`
	GraphTooltip uint8  `json:"graphTooltip"`
	HideControls bool   `json:"hideControls"`
	Rows         []*Row `json:"rows"`
	Style        string `json:"style"`
	Timezone     string `json:"timezone"`
	Title        string `json:"title"`
	tags         []string
	Meta         *DashboardMeta `json:"meta,omitempty"`
}

// NewDashboard creates new Dashboard.
func NewDashboard(title string) *Dashboard {
	return &Dashboard{
		Title: title,
	}
}

func (d *Dashboard) String() string {
	return Stringify(d)
}

// Tags is a getter for Dashboard tags field
func (d *Dashboard) Tags() []string {
	return d.tags
}

// SetTags sets new tags to dashboard
func (d *Dashboard) SetTags(tags ...string) {
	newTags := []string{}
	uniqTags := make(map[string]bool)
	for _, tag := range tags {
		if _, ok := uniqTags[tag]; ok {
			continue
		}

		uniqTags[tag] = true
		newTags = append(newTags, tag)
	}

	d.tags = newTags
}

// AddTags adds given tags to dashboard. This method keeps uniqueness of tags.
func (d *Dashboard) AddTags(tags ...string) {
	tagFound := make(map[string]bool, len(d.tags))
	for _, tag := range d.tags {
		tagFound[tag] = true
	}

	for _, tag := range tags {
		if _, ok := tagFound[tag]; ok {
			continue
		}
		d.tags = append(d.tags, tag)
	}
}

// RemoveTags removes given tags from dashboard. Does nothing if tag is not found.
func (d *Dashboard) RemoveTags(tags ...string) {
	tagIndex := make(map[string]int, len(d.tags))
	for i, tag := range d.tags {
		tagIndex[tag] = i
	}

	for _, tag := range tags {
		if i, ok := tagIndex[tag]; ok {
			d.tags = append(d.tags[:i], d.tags[i+1:]...)
		}
	}
}

// UnmarshalJSON implements json.Unmarshaler interface
func (d *Dashboard) UnmarshalJSON(data []byte) error {
	type JSONDashboard Dashboard
	inDashboard := struct {
		*JSONDashboard
		Tags []string `json:"tags"`
	}{
		JSONDashboard: (*JSONDashboard)(d),
	}
	if err := json.Unmarshal(data, &inDashboard); err != nil {
		return err
	}

	d.tags = inDashboard.Tags

	return nil
}

// MarshalJSON implements json.Marshaler interface
func (d *Dashboard) MarshalJSON() ([]byte, error) {
	type JSONDashboard Dashboard
	dd := (*JSONDashboard)(d)
	dd.Meta = nil

	return json.Marshal(&struct {
		*JSONDashboard
		Tags []string `json:"tags,omitempty"`
	}{
		JSONDashboard: dd,
		Tags:          d.Tags(),
	})
}

type DashboardMeta struct {
	Slug    string `json:"slug"`
	Type    string `json:"type"`
	Version int    `json:"version"`

	CanEdit bool `json:"canEdit"`
	CanSave bool `json:"canSave"`
	CanStar bool `json:"canStar"`

	Created   time.Time `json:"created"`
	CreatedBy string    `json:"createdBy"`
	Expires   time.Time `json:"expires"`
	Updated   time.Time `json:"updated"`
	UpdatedBy string    `json:"updatedBy"`
}

func (dm *DashboardMeta) String() string {
	return Stringify(dm)
}

type Row struct {
	Collapsed bool     `json:"collapse"`
	Editable  bool     `json:"editable"`
	Height    string   `json:"height"`
	Panels    []*Panel `json:"panels"`
	ShowTitle bool     `json:"showTitle"`
	Title     string   `json:"title"`
	TitleSize string   `json:"titleSize"` // h1-h6
}

func NewRow() *Row {
	return &Row{
		Panels: []*Panel{},
	}
}

type Panel struct {
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"github.com/projectjane/jane/connectors"
	"github.com/projectjane/jane/models"
	"sort"
	"strings"
)

func Help(message models.Message, tokens map[string]string, publishMsgs chan<- models.Message, config *models.Config) {

	help := make([]string, 0)

	// pull all help from the aliases
	for _, alias := range config.Aliases {
		if !alias.HideHelp {
			if alias.Help != "" {
				help = append(help, alias.Help)
			} else {
				help = append(help, alias.Match)
			}
		}
	}

	// pull all help from the connectors
	for _, connector := range config.Connectors {
		if connector.Active {
			canRun := false
			if connector.Users == "" || connector.Users == "*" {
				canRun = true
			} else {
				users := strings.Split(connector.Users, ",")
				for _, u := range users {
					if u == message.In.User {
						canRun = true
					}
				}
			}
			if canRun {
				c := connectors.MakeConnector(connector.Type).(connectors.Connector)
				help = append(help, c.Help(connector)...)
			}
		}
	}

	// sort, filter and de-dupe help
	sort.Strings(help)
	var lasthelp = ""
	var newhelp = make([]string, 0)
	for _, h := range help {
		if (tokens["1"] != "" && strings.Contains(h, tokens["1"])) || tokens["1"] == "" {
			if h != lasthelp {
				newhelp = append(newhelp, h)
			}
			lasthelp = h
		}
	}

	fmt.Printf("%+v", tokens)

	// output help
	if len(newhelp) > 0 {
		message.Out.Text = "Help for " + config.BotName + "..."
		message.Out.Detail = strings.Join(newhelp, "\n")
		publishMsgs <- message

	}
}
<commit_msg>removing the fmt output for help<commit_after>package core

import (
	"github.com/projectjane/jane/connectors"
	"github.com/projectjane/jane/models"
	"sort"
	"strings"
)

func Help(message models.Message, tokens map[string]string, publishMsgs chan<- models.Message, config *models.Config) {

	help := make([]string, 0)

	// pull all help from the aliases
	for _, alias := range config.Aliases {
		if !alias.HideHelp {
			if alias.Help != "" {
				help = append(help, alias.Help)
			} else {
				help = append(help, alias.Match)
			}
		}
	}

	// pull all help from the connectors
	for _, connector := range config.Connectors {
		if connector.Active {
			canRun := false
			if connector.Users == "" || connector.Users == "*" {
				canRun = true
			} else {
				users := strings.Split(connector.Users, ",")
				for _, u := range users {
					if u == message.In.User {
						canRun = true
					}
				}
			}
			if canRun {
				c := connectors.MakeConnector(connector.Type).(connectors.Connector)
				help = append(help, c.Help(connector)...)
			}
		}
	}

	// sort, filter and de-dupe help
	sort.Strings(help)
	var lasthelp = ""
	var newhelp = make([]string, 0)
	for _, h := range help {
		if (tokens["1"] != "" && strings.Contains(h, tokens["1"])) || tokens["1"] == "" {
			if h != lasthelp {
				newhelp = append(newhelp, h)
			}
			lasthelp = h
		}
	}

	// output help
	if len(newhelp) > 0 {
		message.Out.Text = "Help for " + config.BotName + "..."
		message.Out.Detail = strings.Join(newhelp, "\n")
		publishMsgs <- message

	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"time"
)

type Response struct {
	Ok bool   `json:"ok"`
	Id string `json:"id"`
}

type Queue struct {
	Total_rows int        `json:"total_rows,omitempty"`
	Rows       []QueueRow `json:"rows,omitempty"`
}
type QueueRow struct {
	Lock Lock `json:"value,omitempty"`
}

type Lock struct {
	Id      string `json:"_id,omitempty"`
	Lock    string `json:"Lock"`
	Name    string `json:"Name"`
	Status  string `json:"Status,omitempty"`
	Created int    `json:"Created,omitempty"`
}

func NewLock(lock string, name string) *Lock {
	return &Lock{Lock: lock, Name: name}
}

type Config struct {
	lock     string
	name     string
	couchdb  string
	interval int
}

var config Config

func main() {
	flag.StringVar(&config.lock, "lock", "default", "Lock name - default to 'default'.")
	flag.StringVar(&config.name, "name", "", "Unique identifier for lock session.")
	flag.StringVar(&config.couchdb, "couchdb", "http://couchdb/couchlock", "Couchdb - default to 'http://couchdb/couchlock'.")
	flag.IntVar(&config.interval, "interval", 5, "Polling interval in seconds - default to 5.")

	flag.Usage = func() {
		fmt.Printf("Usage: couchlock [options] command\n\n")

		fmt.Printf("Options:\n")
		flag.PrintDefaults()
		fmt.Printf("\n")

		fmt.Printf("Commands:\n")
		fmt.Printf("\tlock\tAquire lock\n")
		fmt.Printf("\tunlock\tUnlock lock\n")
		fmt.Printf("\tqueue\tList queue for lock\n\n")

	}

	flag.Parse()
	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}

	if config.name == "" {
		fmt.Println("ERROR: Unique 'name' identifier for lock session required.")
		flag.Usage()
		os.Exit(1)
	}

	command := flag.Args()[0]
	if command == "lock" {
		verifyDesignUpdate()
		lock := createLock()
		waitForLock(lock)
		lockLock(lock)
	} else if command == "unlock" {
		fmt.Println("INFO: Not implemented.")
		os.Exit(1)
	} else if command == "queue" {
		fmt.Println("INFO: Not implemented.")
		os.Exit(1)
	} else {
		fmt.Printf("ERROR: Unknown command '%s'.\n", command)
		flag.Usage()
		os.Exit(1)
	}
}

func verifyDesignUpdate() {
	client := &http.Client{}
	design_locks_url := config.couchdb + "/_design/locks"

	resp, err := http.Get(design_locks_url)
	if err != nil {
		fmt.Printf("ERROR: %s\n", err)
		os.Exit(1)
	}
	if resp.StatusCode == 404 {
		// View document probably doesn't exist

		// Get design document
		design_document, err := Asset("data/designs/locks.json")
		if err != nil {
			panic(err)
		}

		// Create design document in couchdb
		buf := bytes.NewBuffer(design_document)
		req, err := http.NewRequest("PUT", design_locks_url, buf)
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		if resp.StatusCode != 201 {
			buf := new(bytes.Buffer)
			buf.ReadFrom(resp.Body)
			fmt.Printf("ERROR: %d %s\n", resp.StatusCode, buf.String())
			os.Exit(1)
		}
		fmt.Printf("INFO: %s\n", "Locks design created.")
	} else {
		fmt.Printf("INFO: %s\n", "Locks design exists.")
	}
}

func createLock() *Lock {
	client := &http.Client{}

	// create lock
	lock := NewLock(config.lock, config.name)

	// create lock in couchdb
	json1, _ := json.Marshal(lock)
	buf := bytes.NewBuffer(json1)
	req, err := http.NewRequest("POST", config.couchdb+"/_design/locks/_update/create/", buf)
	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	if resp.StatusCode != 201 {
		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)
		fmt.Printf("ERROR: %d %s\n", resp.StatusCode, buf.String())
		os.Exit(1)
	}
	fmt.Printf("INFO: Lock '%s' created.\n", config.lock)

	buf = new(bytes.Buffer)
	buf.ReadFrom(resp.Body)

	var res Response
	err = json.Unmarshal(buf.Bytes(), &res)
	if err != nil {
		panic(err)
	}

	// save id for couchdb lock document
	lock.Id = res.Id

	return lock
}

func lockLock(lock *Lock) {
	client := &http.Client{}

	// change status of lock in couchdb to 'locked'
	req, err := http.NewRequest("POST", config.couchdb+"/_design/locks/_update/lock/"+lock.Id, nil)
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	if resp.StatusCode != 201 {
		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)
		fmt.Printf("ERROR: %d %s\n", resp.StatusCode, buf.String())
		os.Exit(1)
	}
	fmt.Printf("INFO: Lock '%s' aquired.\n", config.lock)
}

func waitForLock(lock *Lock) bool {
	client := &http.Client{}
	req, err := http.NewRequest("GET", config.couchdb+"/_design/locks/_view/queue/?startkey=[\""+config.lock+"\"]&endkey=[\""+config.lock+"\",{}]", nil)
	if err != nil {
		panic(err)
	}

	fmt.Printf("INFO: Waiting for lock '%s' to be available.\n", config.lock)

	// wait until our lock is top of list
	for true {
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}

		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)

		var queue Queue
		err = json.Unmarshal(buf.Bytes(), &queue)
		if err != nil {
			panic(err)
		}

		if queue.Rows[0].Lock.Id == lock.Id {
			return true
		}

		time.Sleep(time.Duration(config.interval) * 1000 * time.Millisecond)
	}

	return false
}
<commit_msg>Add list-queue<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"time"
)

type Response struct {
	Ok bool   `json:"ok"`
	Id string `json:"id"`
}

type Queue struct {
	Total_rows int        `json:"total_rows,omitempty"`
	Rows       []QueueRow `json:"rows,omitempty"`
}
type QueueRow struct {
	Lock Lock `json:"value,omitempty"`
}

type Lock struct {
	Id      string `json:"_id,omitempty"`
	Lock    string `json:"Lock"`
	Name    string `json:"Name"`
	Status  string `json:"Status,omitempty"`
	Created int    `json:"Created,omitempty"`
}

func NewLock(lock string, name string) *Lock {
	return &Lock{Lock: lock, Name: name}
}

type Config struct {
	lock     string
	name     string
	couchdb  string
	interval int
}

var config Config

func main() {
	flag.StringVar(&config.lock, "lock", "default", "Lock name - default to 'default'.")
	flag.StringVar(&config.name, "name", "", "Unique identifier for lock session.")
	flag.StringVar(&config.couchdb, "couchdb", "http://couchdb/couchlock", "Couchdb - default to 'http://couchdb/couchlock'.")
	flag.IntVar(&config.interval, "interval", 5, "Polling interval in seconds - default to 5.")

	flag.Usage = func() {
		fmt.Printf("Usage: couchlock [options] command\n\n")

		fmt.Printf("Options:\n")
		flag.PrintDefaults()
		fmt.Printf("\n")

		fmt.Printf("Commands:\n")
		fmt.Printf("\tlock\tAquire lock\n")
		fmt.Printf("\tunlock\tUnlock lock\n")
		fmt.Printf("\tlist-queue\tList queue for lock\n\n")

	}

	flag.Parse()
	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}

	if config.name == "" {
		fmt.Println("ERROR: Unique 'name' identifier for lock session required.")
		flag.Usage()
		os.Exit(1)
	}

	command := flag.Args()[0]
	if command == "lock" {
		verifyDesignUpdate()
		lock := createLock()
		waitForLock(lock)
		lockLock(lock)
	} else if command == "unlock" {
		fmt.Println("INFO: Not implemented.")
		os.Exit(1)
	} else if command == "list-queue" {
		listQueue()
	} else {
		fmt.Printf("ERROR: Unknown command '%s'.\n", command)
		flag.Usage()
		os.Exit(1)
	}
}

func verifyDesignUpdate() {
	client := &http.Client{}
	design_locks_url := config.couchdb + "/_design/locks"

	resp, err := http.Get(design_locks_url)
	if err != nil {
		fmt.Printf("ERROR: %s\n", err)
		os.Exit(1)
	}
	if resp.StatusCode == 404 {
		// View document probably doesn't exist

		// Get design document
		design_document, err := Asset("data/designs/locks.json")
		if err != nil {
			panic(err)
		}

		// Create design document in couchdb
		buf := bytes.NewBuffer(design_document)
		req, err := http.NewRequest("PUT", design_locks_url, buf)
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		if resp.StatusCode != 201 {
			buf := new(bytes.Buffer)
			buf.ReadFrom(resp.Body)
			fmt.Printf("ERROR: %d %s\n", resp.StatusCode, buf.String())
			os.Exit(1)
		}
		fmt.Printf("INFO: %s\n", "Locks design created.")
	} else {
		fmt.Printf("INFO: %s\n", "Locks design exists.")
	}
}

func createLock() *Lock {
	client := &http.Client{}

	// create lock
	lock := NewLock(config.lock, config.name)

	// create lock in couchdb
	json1, _ := json.Marshal(lock)
	buf := bytes.NewBuffer(json1)
	req, err := http.NewRequest("POST", config.couchdb+"/_design/locks/_update/create/", buf)
	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	if resp.StatusCode != 201 {
		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)
		fmt.Printf("ERROR: %d %s\n", resp.StatusCode, buf.String())
		os.Exit(1)
	}
	fmt.Printf("INFO: Lock '%s' created.\n", config.lock)

	buf = new(bytes.Buffer)
	buf.ReadFrom(resp.Body)

	var res Response
	err = json.Unmarshal(buf.Bytes(), &res)
	if err != nil {
		panic(err)
	}

	// save id for couchdb lock document
	lock.Id = res.Id

	return lock
}

func lockLock(lock *Lock) {
	client := &http.Client{}

	// change status of lock in couchdb to 'locked'
	req, err := http.NewRequest("POST", config.couchdb+"/_design/locks/_update/lock/"+lock.Id, nil)
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	if resp.StatusCode != 201 {
		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)
		fmt.Printf("ERROR: %d %s\n", resp.StatusCode, buf.String())
		os.Exit(1)
	}
	fmt.Printf("INFO: Lock '%s' aquired.\n", config.lock)
}

func waitForLock(lock *Lock) bool {
	client := &http.Client{}
	req, err := http.NewRequest("GET", config.couchdb+"/_design/locks/_view/queue/?startkey=[\""+config.lock+"\"]&endkey=[\""+config.lock+"\",{}]", nil)
	if err != nil {
		panic(err)
	}

	fmt.Printf("INFO: Waiting for lock '%s' to be available.\n", config.lock)

	// wait until our lock is top of list
	for true {
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}

		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)

		var queue Queue
		err = json.Unmarshal(buf.Bytes(), &queue)
		if err != nil {
			panic(err)
		}

		if queue.Rows[0].Lock.Id == lock.Id {
			return true
		}

		time.Sleep(time.Duration(config.interval) * 1000 * time.Millisecond)
	}

	return false
}

func listQueue() {
	client := &http.Client{}
	req, err := http.NewRequest("GET", config.couchdb+"/_design/locks/_view/queue/?startkey=[\""+config.lock+"\"]&endkey=[\""+config.lock+"\",{}]", nil)
	if err != nil {
		panic(err)
	}

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}

	buf := new(bytes.Buffer)
	buf.ReadFrom(resp.Body)

	var queue Queue
	err = json.Unmarshal(buf.Bytes(), &queue)
	if err != nil {
		panic(err)
	}

	for _, row := range queue.Rows {
		fmt.Printf("%d %s %s\n",
			row.Lock.Created,
			row.Lock.Name,
			row.Lock.Status)
	}
}
<|endoftext|>


<commit_before>package bits

import (
	"testing"
	"testing/quick"
)

func testQuick(ffast, fslow func(x uint64) uint64) {
	f := func(x uint64) bool {
		return ffast(x) == fslow(x)
	}
	quick.Check(f, nil)
}

func ctzSlow(x uint64) uint64 {
	var n uint64
	for x&1 == 0 {
		n++
		x >>= 1
	}
	return n
}

func TestQuickCtz(t *testing.T) { testQuick(Ctz, ctzSlow) }

func clzSlow(x uint64) uint64 {
	var n uint64
	for x&0x8000000000000000 == 0 {
		n++
		x <<= 1
	}
	return n
}

func TestQuickClz(t *testing.T) { testQuick(Clz, clzSlow) }

func popcntSlow(x uint64) uint64 {
	var n uint64
	for x != 0 {
		if x&1 == 1 {
			n++
		}
		x >>= 1
	}
	return n
}

func TestQuickPopcnt(t *testing.T) { testQuick(Popcnt, popcntSlow) }
<commit_msg>fix quick.Check() call<commit_after>package bits

import (
	"testing"
	"testing/quick"
)

func testQuick(t *testing.T, which string, ffast, fslow func(x uint64) uint64) {
	f := func(x uint64) bool {
		return ffast(x) == fslow(x)
	}
	if err := quick.Check(f, nil); err != nil {
		t.Errorf("fast%v != slow%v: %v: ", which, which, err)
	}
}

func ctzSlow(x uint64) uint64 {
	var n uint64
	for x&1 == 0 {
		n++
		x >>= 1
	}
	return n
}

func TestQuickCtz(t *testing.T) { testQuick(t, "ctz", Ctz, ctzSlow) }

func clzSlow(x uint64) uint64 {
	var n uint64
	for x&0x8000000000000000 == 0 {
		n++
		x <<= 1
	}
	return n
}

func TestQuickClz(t *testing.T) { testQuick(t, "clz", Clz, clzSlow) }

func popcntSlow(x uint64) uint64 {
	var n uint64
	for x != 0 {
		if x&1 == 1 {
			n++
		}
		x >>= 1
	}
	return n
}

func TestQuickPopcnt(t *testing.T) { testQuick(t, "popcnt", Popcnt, popcntSlow) }
<|endoftext|>


<commit_before>// Extending for Blacklist support in Subgraph Oz
// Much refactoring on this remains to be done.
// Original copyright and license below.
//
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Package seccomp implements support for compiling and installing Seccomp-BPF policy files.
//   - http://www.chromium.org/chromium-os/developer-guide/chromium-os-sandboxing
//
// Typical usage:
//	// Check for the required kernel support for seccomp.
//	if err := seccomp.CheckSupport(); err != nil {
//		log.Fatal(err)
//	}
//
//	// Compile BPF program from a Chromium-OS policy file.
//	bpf, err := seccomp.Compile(path)
//	if err != nil {
//		log.Fatal(err)
//	}
//
//	// Install Seccomp-BPF filter program with the kernel.
//	if err := seccomp.Install(bpf); err != nil {
//		log.Fatal(err)
//	}
//
// For background and more information:
//   - http://www.tcpdump.org/papers/bpf-usenix93.pdf
//   - http://en.wikipedia.org/wiki/Seccomp
//   - http://lwn.net/Articles/475043/
//   - http://outflux.net/teach-seccomp/
//   - http://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt
//   - http://github.com/torvalds/linux/blob/master/kernel/seccomp.c
//
// TODO:
//   - Exit the program if any thread is killed because of seccomp violation.
//   - Provide a debug mode to log system calls used during normal operation.
package seccomp

import (
	"fmt"
	"io/ioutil"
	"runtime"
	"strconv"
	"strings"
	"syscall"
)

// #include <sys/prctl.h>
// #include "unistd_64.h"
// #include "seccomp.h"
import "C"

// parseLine parses the policy line for a single syscall.
func parseLineBlacklist(line string, enforce bool) (policy, error) {
	var name, expr, ret string
	var then SockFilter
	var def *SockFilter

	line = strings.TrimSpace(line)
	if match := allowRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		if enforce == true {
			def = ptr(bpfRet(retKill()))
		} else {
			def = ptr(bpfRet(retTrace()))
		}
	} else if match = returnRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		ret = match[2]
	} else if match = exprRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		expr = match[2]
	} else if match = exprReturnRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		expr = match[2]
		ret = match[3]
	} else {
		return policy{}, fmt.Errorf("invalid syntax")
	}

	if _, ok := syscallNum[name]; !ok {
		return policy{}, fmt.Errorf("unknown syscall: %s", name)
	}

	var or orExpr
	if expr != "" {
		for _, sub := range strings.Split(expr, "||") {
			var and andExpr
			for _, arg := range strings.Split(sub, "&&") {
				arg = strings.TrimSpace(arg)
				match := argRE.FindStringSubmatch(arg)
				if match == nil {
					return policy{}, fmt.Errorf("invalid expression: %s", arg)
				}
				idx, err := strconv.Atoi(match[1])
				if err != nil {
					return policy{}, fmt.Errorf("invalid arg: %s", arg)
				}
				oper := match[2]
				val, err := strconv.ParseUint(match[3], 0, 64)
				if err != nil {
					return policy{}, fmt.Errorf("invalid value: %s", arg)
				}
				and = append(and, argComp{idx, oper, val})
			}
			or = append(or, and)
		}
	}

	if enforce == true {
		then = bpfRet(retKill())
	} else {
		then = bpfRet(retTrace())
	}

	if ret != "" {
		errno, err := strconv.ParseUint(ret, 0, 16)
		if err != nil {
			return policy{}, fmt.Errorf("invalid errno: %s", ret)
		}
		def = ptr(bpfRet(retErrno(syscall.Errno(errno))))
	}

	return policy{name, or, then, def}, nil
}

// parseLines parses multiple policy lines, each one for a single syscall.
// Empty lines and lines beginning with "#" are ignored.
// Multiple policies for a syscall are detected and reported as error.
func parseLinesBlacklist(lines []string, enforce bool) ([]policy, error) {
	var ps []policy
	seen := make(map[string]int)
	for i, line := range lines {
		lineno := i + 1
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		p, err := parseLineBlacklist(line, enforce)
		if err != nil {
			return nil, fmt.Errorf("line %d: %v", lineno, err)
		}
		if seen[p.name] > 0 {
			return nil, fmt.Errorf("lines %d,%d: multiple policies for %s",
				seen[p.name], lineno, p.name)
		}
		seen[p.name] = lineno
		ps = append(ps, p)
	}
	return ps, nil
}

// parseFile reads a Chromium-OS Seccomp-BPF policy file and parses its contents.
func parseFileBlacklist(path string, enforce bool) ([]policy, error) {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return parseLinesBlacklist(strings.Split(string(file), "\n"), enforce)
}

// compile compiles a Seccomp-BPF program implementing the syscall policies.
// long specifies whether to generate 32-bit or 64-bit argument comparisons.
// def is the overall default action to take when the syscall does not match
// any policy in the filter.
func compileBlacklist(ps []policy, long bool, def SockFilter, enforce bool) ([]SockFilter, error) {
	var bpf []SockFilter
	do := func(insn SockFilter) {
		bpf = append(bpf, insn)
	}

	// ref maps a label to addresses of all the instructions that jump to it.
	ref := make(map[string][]int)
	jump := func(name string) {
		// jump to a label with unresolved address: insert a placeholder instruction.
		ref[name] = append(ref[name], len(bpf))
		do(SockFilter{})
	}
	label := func(name string) {
		// label address resolved: replace placeholder instructions with actual jumps.
		for _, i := range ref[name] {
			bpf[i] = bpfJump(len(bpf) - (i + 1))
		}
		delete(ref, name)
	}

	// Conditional jumps: jump if condition is true, fall through otherwise.
	jeq := func(val uint32, target string) {
		// if A == val { goto target }
		do(bpfJeq(val, 0, 1))
		jump(target)
	}
	jne := func(val uint32, target string) {
		// if A != val { goto target }
		do(bpfJeq(val, 1, 0))
		jump(target)
	}
	jset := func(val uint32, target string) {
		// if A&val != 0 { goto target }
		do(bpfJset(val, 0, 1))
		jump(target)
	}
	jnset := func(val uint32, target string) {
		// if A&val == 0 { goto target }
		do(bpfJset(val, 1, 0))
		jump(target)
	}

	do(bpfLoadArch())
	do(bpfJeq(auditArch, 1, 0))
	do(bpfRet(retKill()))
	do(bpfRet(retTrace()))

	do(bpfLoadNR())
	for _, p := range ps {
		nr, ok := syscallNum[p.name]
		if !ok {
			return nil, fmt.Errorf("unknown syscall: %s", p.name)
		}
		jne(uint32(nr), "nextcall")
		for _, and := range p.expr {
			for _, arg := range and {
				val := struct{ high, low uint32 }{uint32(arg.val >> 32), uint32(arg.val)}
				switch arg.oper {
				case "==":
					if long {
						do(bpfLoadArg(arg.idx, 1))
						jne(val.high, "nextor")
					}
					do(bpfLoadArg(arg.idx, 0))
					jne(val.low, "nextor")
				case "!=":
					if long {
						do(bpfLoadArg(arg.idx, 1))
						jne(val.high, "nextand")
					}
					do(bpfLoadArg(arg.idx, 0))
					jeq(val.low, "nextor")
				case "&":
					if long {
						do(bpfLoadArg(arg.idx, 1))
						jset(val.high, "nextand")
					}
					do(bpfLoadArg(arg.idx, 0))
					jnset(val.low, "nextor")
				default:
					return nil, fmt.Errorf("unknown operator: %q", arg.oper)
				}

				// Comparison was satisfied. Move on to the next comparison in &&.
				label("nextand")
			}

			// All comparisons in && were satisfied.
			do(p.then)

			// Some comparison in && was false. Move on to the next expression in ||.
			label("nextor")
		}

		// All expressions in || evaluated to false (or expr was nil).
		if p.def != nil {
			do(*p.def)
		} else {
			jump("default")
		}

		label("nextcall")
	}

	label("default")
	do(def)

	if len(ref) > 0 {
		return nil, fmt.Errorf("unresolved labels: %v\n%v", ref, bpf)
	}
	return bpf, nil
}

// Compile reads a Chromium-OS policy file and compiles a
// Seccomp-BPF filter program implementing the policies.
func CompileBlacklist(path string, enforce bool) ([]SockFilter, error) {
	ps, err := parseFileBlacklist(path, enforce)
	if err != nil {
		return nil, err
	}
	return compileBlacklist(ps, nbits > 32, bpfRet(retAllow()), enforce)
}

// Install makes the necessary system calls to install the Seccomp-BPF
// filter for the current process (all threads). Install can be called
// multiple times to install additional filters.
func InstallBlacklist(bpf []SockFilter) error {
	// prctl(set_no_new_privs, 1) must be called (from the same thread)
	// before a seccomp filter can be installed by an unprivileged user:
	// - http://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	if err := prctl(C.PR_SET_NO_NEW_PRIVS, 1); err != nil {
		return err
	}
	return Load(bpf)
}
<commit_msg>Oops..<commit_after>// Extending for Blacklist support in Subgraph Oz
// Much refactoring on this remains to be done.
// Original copyright and license below.
//
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Package seccomp implements support for compiling and installing Seccomp-BPF policy files.
//   - http://www.chromium.org/chromium-os/developer-guide/chromium-os-sandboxing
//
// Typical usage:
//	// Check for the required kernel support for seccomp.
//	if err := seccomp.CheckSupport(); err != nil {
//		log.Fatal(err)
//	}
//
//	// Compile BPF program from a Chromium-OS policy file.
//	bpf, err := seccomp.Compile(path)
//	if err != nil {
//		log.Fatal(err)
//	}
//
//	// Install Seccomp-BPF filter program with the kernel.
//	if err := seccomp.Install(bpf); err != nil {
//		log.Fatal(err)
//	}
//
// For background and more information:
//   - http://www.tcpdump.org/papers/bpf-usenix93.pdf
//   - http://en.wikipedia.org/wiki/Seccomp
//   - http://lwn.net/Articles/475043/
//   - http://outflux.net/teach-seccomp/
//   - http://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt
//   - http://github.com/torvalds/linux/blob/master/kernel/seccomp.c
//
// TODO:
//   - Exit the program if any thread is killed because of seccomp violation.
//   - Provide a debug mode to log system calls used during normal operation.
package seccomp

import (
	"fmt"
	"io/ioutil"
	"runtime"
	"strconv"
	"strings"
	"syscall"
)

// #include <sys/prctl.h>
// #include "unistd_64.h"
// #include "seccomp.h"
import "C"

// parseLine parses the policy line for a single syscall.
func parseLineBlacklist(line string, enforce bool) (policy, error) {
	var name, expr, ret string
	var then SockFilter
	var def *SockFilter

	line = strings.TrimSpace(line)
	if match := allowRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		if enforce == true {
			def = ptr(bpfRet(retKill()))
		} else {
			def = ptr(bpfRet(retTrace()))
		}
	} else if match = returnRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		ret = match[2]
	} else if match = exprRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		expr = match[2]
	} else if match = exprReturnRE.FindStringSubmatch(line); match != nil {
		name = match[1]
		expr = match[2]
		ret = match[3]
	} else {
		return policy{}, fmt.Errorf("invalid syntax")
	}

	if _, ok := syscallNum[name]; !ok {
		return policy{}, fmt.Errorf("unknown syscall: %s", name)
	}

	var or orExpr
	if expr != "" {
		for _, sub := range strings.Split(expr, "||") {
			var and andExpr
			for _, arg := range strings.Split(sub, "&&") {
				arg = strings.TrimSpace(arg)
				match := argRE.FindStringSubmatch(arg)
				if match == nil {
					return policy{}, fmt.Errorf("invalid expression: %s", arg)
				}
				idx, err := strconv.Atoi(match[1])
				if err != nil {
					return policy{}, fmt.Errorf("invalid arg: %s", arg)
				}
				oper := match[2]
				val, err := strconv.ParseUint(match[3], 0, 64)
				if err != nil {
					return policy{}, fmt.Errorf("invalid value: %s", arg)
				}
				and = append(and, argComp{idx, oper, val})
			}
			or = append(or, and)
		}
	}

	if enforce == true {
		then = bpfRet(retKill())
	} else {
		then = bpfRet(retTrace())
	}

	if ret != "" {
		errno, err := strconv.ParseUint(ret, 0, 16)
		if err != nil {
			return policy{}, fmt.Errorf("invalid errno: %s", ret)
		}
		def = ptr(bpfRet(retErrno(syscall.Errno(errno))))
	}

	return policy{name, or, then, def}, nil
}

// parseLines parses multiple policy lines, each one for a single syscall.
// Empty lines and lines beginning with "#" are ignored.
// Multiple policies for a syscall are detected and reported as error.
func parseLinesBlacklist(lines []string, enforce bool) ([]policy, error) {
	var ps []policy
	seen := make(map[string]int)
	for i, line := range lines {
		lineno := i + 1
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		p, err := parseLineBlacklist(line, enforce)
		if err != nil {
			return nil, fmt.Errorf("line %d: %v", lineno, err)
		}
		if seen[p.name] > 0 {
			return nil, fmt.Errorf("lines %d,%d: multiple policies for %s",
				seen[p.name], lineno, p.name)
		}
		seen[p.name] = lineno
		ps = append(ps, p)
	}
	return ps, nil
}

// parseFile reads a Chromium-OS Seccomp-BPF policy file and parses its contents.
func parseFileBlacklist(path string, enforce bool) ([]policy, error) {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return parseLinesBlacklist(strings.Split(string(file), "\n"), enforce)
}

// compile compiles a Seccomp-BPF program implementing the syscall policies.
// long specifies whether to generate 32-bit or 64-bit argument comparisons.
// def is the overall default action to take when the syscall does not match
// any policy in the filter.
func compileBlacklist(ps []policy, long bool, def SockFilter, enforce bool) ([]SockFilter, error) {
	var bpf []SockFilter
	do := func(insn SockFilter) {
		bpf = append(bpf, insn)
	}

	// ref maps a label to addresses of all the instructions that jump to it.
	ref := make(map[string][]int)
	jump := func(name string) {
		// jump to a label with unresolved address: insert a placeholder instruction.
		ref[name] = append(ref[name], len(bpf))
		do(SockFilter{})
	}
	label := func(name string) {
		// label address resolved: replace placeholder instructions with actual jumps.
		for _, i := range ref[name] {
			bpf[i] = bpfJump(len(bpf) - (i + 1))
		}
		delete(ref, name)
	}

	// Conditional jumps: jump if condition is true, fall through otherwise.
	jeq := func(val uint32, target string) {
		// if A == val { goto target }
		do(bpfJeq(val, 0, 1))
		jump(target)
	}
	jne := func(val uint32, target string) {
		// if A != val { goto target }
		do(bpfJeq(val, 1, 0))
		jump(target)
	}
	jset := func(val uint32, target string) {
		// if A&val != 0 { goto target }
		do(bpfJset(val, 0, 1))
		jump(target)
	}
	jnset := func(val uint32, target string) {
		// if A&val == 0 { goto target }
		do(bpfJset(val, 1, 0))
		jump(target)
	}

	do(bpfLoadArch())
	do(bpfJeq(auditArch, 1, 0))
	do(bpfRet(retKill()))

	do(bpfLoadNR())
	for _, p := range ps {
		nr, ok := syscallNum[p.name]
		if !ok {
			return nil, fmt.Errorf("unknown syscall: %s", p.name)
		}
		jne(uint32(nr), "nextcall")
		for _, and := range p.expr {
			for _, arg := range and {
				val := struct{ high, low uint32 }{uint32(arg.val >> 32), uint32(arg.val)}
				switch arg.oper {
				case "==":
					if long {
						do(bpfLoadArg(arg.idx, 1))
						jne(val.high, "nextor")
					}
					do(bpfLoadArg(arg.idx, 0))
					jne(val.low, "nextor")
				case "!=":
					if long {
						do(bpfLoadArg(arg.idx, 1))
						jne(val.high, "nextand")
					}
					do(bpfLoadArg(arg.idx, 0))
					jeq(val.low, "nextor")
				case "&":
					if long {
						do(bpfLoadArg(arg.idx, 1))
						jset(val.high, "nextand")
					}
					do(bpfLoadArg(arg.idx, 0))
					jnset(val.low, "nextor")
				default:
					return nil, fmt.Errorf("unknown operator: %q", arg.oper)
				}

				// Comparison was satisfied. Move on to the next comparison in &&.
				label("nextand")
			}

			// All comparisons in && were satisfied.
			do(p.then)

			// Some comparison in && was false. Move on to the next expression in ||.
			label("nextor")
		}

		// All expressions in || evaluated to false (or expr was nil).
		if p.def != nil {
			do(*p.def)
		} else {
			jump("default")
		}

		label("nextcall")
	}

	label("default")
	do(def)

	if len(ref) > 0 {
		return nil, fmt.Errorf("unresolved labels: %v\n%v", ref, bpf)
	}
	return bpf, nil
}

// Compile reads a Chromium-OS policy file and compiles a
// Seccomp-BPF filter program implementing the policies.
func CompileBlacklist(path string, enforce bool) ([]SockFilter, error) {
	ps, err := parseFileBlacklist(path, enforce)
	if err != nil {
		return nil, err
	}
	return compileBlacklist(ps, nbits > 32, bpfRet(retAllow()), enforce)
}

// Install makes the necessary system calls to install the Seccomp-BPF
// filter for the current process (all threads). Install can be called
// multiple times to install additional filters.
func InstallBlacklist(bpf []SockFilter) error {
	// prctl(set_no_new_privs, 1) must be called (from the same thread)
	// before a seccomp filter can be installed by an unprivileged user:
	// - http://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	if err := prctl(C.PR_SET_NO_NEW_PRIVS, 1); err != nil {
		return err
	}
	return Load(bpf)
}
<|endoftext|>


<commit_before>package blob

import (
	"crypto/sha1"
	"database/sql"
	"encoding/hex"
	"fmt"
	_ "github.com/herenow/go-crate"
	"io"
	"net/http"
	"time"
)

type Driver struct {
	url string
	db  *sql.DB
}

type Table struct {
	Name string
	drv  *Driver
	c    *http.Client
}

// DownloadError represents an error that occurs when downloading a blob.
type DownloadError struct {
	Status string
	StatusCode int
	Message string
}

// Error returns a string representation of the DownloadError.
func (e DownloadError) Error() string {
	return e.Message
}

// New creates a new connection with crate server
func New(crate_url string) (*Driver, error) {
	db, err := sql.Open("crate", crate_url)
	if err != nil {
		return nil, err
	}
	return &Driver{
		url: crate_url,
		db:  db,
	}, nil
}

// NewTable create new blob table with name and extra int to specify
// shards(the second argument) and
// replicas(by the third int argument)
func (d *Driver) NewTable(name string, shards ...int) (*Table, error) {
	sql := fmt.Sprintf(
		"create blob table %s",
		name,
	)
	if len(shards) == 1 {
		sql = fmt.Sprintf(
			"create blob table %s clustered into %d shards",
			name, shards[0],
		)
	}
	if len(shards) >= 2 {
		sql = fmt.Sprintf(
			"create blob table %s clustered into %d shards with (number_of_replicas=%d)",
			name, shards[0], shards[1],
		)
	}
	_, err := d.db.Exec(sql)
	if err != nil {
		return nil, err
	}
	return &Table{
		Name: name,
		drv:  d,
		c:    new(http.Client),
	}, nil
}

// Get an existing table from the crate server
// or error when this table does not exist
func (d *Driver) GetTable(name string) (*Table, error) {
	row := d.db.QueryRow(
		"select table_name from information_schema.tables where table_name = ? and table_schema = 'blob'",
		name,
	)
	if err := row.Scan(&name); err != nil {
		return nil, err
	}
	return &Table{
		Name: name,
		drv:  d,
		c:    new(http.Client),
	}, nil
}

func (d *Driver) Close() {
	if d.db != nil {
		return d.db.Close()
	}
	return nil
}

type Record struct {
	Digest       string
	LastModified time.Time
}

// Sha1Digest calculates the sha1 digest for the io.Reader
func Sha1Digest(r io.Reader) string {
	h := sha1.New()
	io.Copy(h, r)
	return hex.EncodeToString(h.Sum(nil))
}

func (t *Table) url(digest string) string {
	return fmt.Sprintf("%s/_blobs/%s/%s", t.drv.url, t.Name, digest)
}

// Upload upload the blob(r) with sha1 hash(digest)
func (t *Table) Upload(digest string, r io.Reader) (*Record, error) {
	req, err := http.NewRequest("PUT", t.url(digest), r)
	if err != nil {
		return nil, err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 201 {
		return nil, fmt.Errorf("Upload failed: %s", resp.Status)
	}
	return &Record{
		Digest: digest,
	}, nil
}

// UploadEx upload a io.ReadSeeker, and computes the sha1 hash automatically
func (t *Table) UploadEx(r io.ReadSeeker) (*Record, error) {
	digest := Sha1Digest(r)
	_, err := r.Seek(0, 0)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("PUT", t.url(digest), r)
	if err != nil {
		return nil, err
	}
	_, err = t.c.Do(req)
	if err != nil {
		return nil, err
	}
	return &Record{
		Digest: digest,
	}, nil
}

// List all blobs inside a blob table
func (t *Table) List() (*sql.Rows, error) {
	query := fmt.Sprintf("select digest, last_modified from blob.%s", t.Name)
	rows, err := t.drv.db.Query(query)
	if err != nil {
		return nil, err
	}
	return rows, err
}

// Is the blob specified by the digest exist in the table
func (t *Table) Has(digest string) (bool, error) {
	req, err := http.NewRequest("HEAD", t.url(digest), nil)
	if err != nil {
		return false, err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return false, err
	}
	if resp.StatusCode == http.StatusOK {
		return true, nil
	}
	return false, nil
}

// Download a blob in a blob table with the specific digest
func (t *Table) Download(digest string) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", t.url(digest), nil)
	if err != nil {
		return nil, err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return resp.Body, &DownloadError{resp.Status, resp.StatusCode, "problem downloading blob"}
	}
	return resp.Body, nil
}

// Delete a blob in a blob table with the specific digest
func (t *Table) Delete(digest string) error {
	req, err := http.NewRequest("DELETE", t.url(digest), nil)
	if err != nil {
		return err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode == http.StatusNoContent {
		return nil
	}
	return fmt.Errorf("%s", resp.Status)
}

// Drop the blob table
func (t *Table) Drop() error {
	sql := fmt.Sprintf("drop blob table %s", t.Name)
	_, err := t.drv.db.Exec(sql)
	return err
}
<commit_msg>added missing comment<commit_after>package blob

import (
	"crypto/sha1"
	"database/sql"
	"encoding/hex"
	"fmt"
	_ "github.com/herenow/go-crate"
	"io"
	"net/http"
	"time"
)

type Driver struct {
	url string
	db  *sql.DB
}

type Table struct {
	Name string
	drv  *Driver
	c    *http.Client
}

// DownloadError represents an error that occurs when downloading a blob.
type DownloadError struct {
	Status string
	StatusCode int
	Message string
}

// Error returns a string representation of the DownloadError.
func (e DownloadError) Error() string {
	return e.Message
}

// New creates a new connection with crate server
func New(crate_url string) (*Driver, error) {
	db, err := sql.Open("crate", crate_url)
	if err != nil {
		return nil, err
	}
	return &Driver{
		url: crate_url,
		db:  db,
	}, nil
}

// NewTable create new blob table with name and extra int to specify
// shards(the second argument) and
// replicas(by the third int argument)
func (d *Driver) NewTable(name string, shards ...int) (*Table, error) {
	sql := fmt.Sprintf(
		"create blob table %s",
		name,
	)
	if len(shards) == 1 {
		sql = fmt.Sprintf(
			"create blob table %s clustered into %d shards",
			name, shards[0],
		)
	}
	if len(shards) >= 2 {
		sql = fmt.Sprintf(
			"create blob table %s clustered into %d shards with (number_of_replicas=%d)",
			name, shards[0], shards[1],
		)
	}
	_, err := d.db.Exec(sql)
	if err != nil {
		return nil, err
	}
	return &Table{
		Name: name,
		drv:  d,
		c:    new(http.Client),
	}, nil
}

// Get an existing table from the crate server
// or error when this table does not exist
func (d *Driver) GetTable(name string) (*Table, error) {
	row := d.db.QueryRow(
		"select table_name from information_schema.tables where table_name = ? and table_schema = 'blob'",
		name,
	)
	if err := row.Scan(&name); err != nil {
		return nil, err
	}
	return &Table{
		Name: name,
		drv:  d,
		c:    new(http.Client),
	}, nil
}

// Close the database connection
func (d *Driver) Close() {
	if d.db != nil {
		return d.db.Close()
	}
	return nil
}

type Record struct {
	Digest       string
	LastModified time.Time
}

// Sha1Digest calculates the sha1 digest for the io.Reader
func Sha1Digest(r io.Reader) string {
	h := sha1.New()
	io.Copy(h, r)
	return hex.EncodeToString(h.Sum(nil))
}

func (t *Table) url(digest string) string {
	return fmt.Sprintf("%s/_blobs/%s/%s", t.drv.url, t.Name, digest)
}

// Upload upload the blob(r) with sha1 hash(digest)
func (t *Table) Upload(digest string, r io.Reader) (*Record, error) {
	req, err := http.NewRequest("PUT", t.url(digest), r)
	if err != nil {
		return nil, err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 201 {
		return nil, fmt.Errorf("Upload failed: %s", resp.Status)
	}
	return &Record{
		Digest: digest,
	}, nil
}

// UploadEx upload a io.ReadSeeker, and computes the sha1 hash automatically
func (t *Table) UploadEx(r io.ReadSeeker) (*Record, error) {
	digest := Sha1Digest(r)
	_, err := r.Seek(0, 0)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("PUT", t.url(digest), r)
	if err != nil {
		return nil, err
	}
	_, err = t.c.Do(req)
	if err != nil {
		return nil, err
	}
	return &Record{
		Digest: digest,
	}, nil
}

// List all blobs inside a blob table
func (t *Table) List() (*sql.Rows, error) {
	query := fmt.Sprintf("select digest, last_modified from blob.%s", t.Name)
	rows, err := t.drv.db.Query(query)
	if err != nil {
		return nil, err
	}
	return rows, err
}

// Is the blob specified by the digest exist in the table
func (t *Table) Has(digest string) (bool, error) {
	req, err := http.NewRequest("HEAD", t.url(digest), nil)
	if err != nil {
		return false, err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return false, err
	}
	if resp.StatusCode == http.StatusOK {
		return true, nil
	}
	return false, nil
}

// Download a blob in a blob table with the specific digest
func (t *Table) Download(digest string) (io.ReadCloser, error) {
	req, err := http.NewRequest("GET", t.url(digest), nil)
	if err != nil {
		return nil, err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return resp.Body, &DownloadError{resp.Status, resp.StatusCode, "problem downloading blob"}
	}
	return resp.Body, nil
}

// Delete a blob in a blob table with the specific digest
func (t *Table) Delete(digest string) error {
	req, err := http.NewRequest("DELETE", t.url(digest), nil)
	if err != nil {
		return err
	}
	resp, err := t.c.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode == http.StatusNoContent {
		return nil
	}
	return fmt.Errorf("%s", resp.Status)
}

// Drop the blob table
func (t *Table) Drop() error {
	sql := fmt.Sprintf("drop blob table %s", t.Name)
	_, err := t.drv.db.Exec(sql)
	return err
}
<|endoftext|>


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

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

	"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 MaxRecipeDescLength = 60
const RecipeDescTailIfTooLong = "..."
const RecipeCarouselAltTextTailing = "..."

type RecipeDBSearchResult struct {
	Hits struct {
		Total int `json:"total"`
		Hits  []struct {
			Source struct {
				Title    string `json:"title"`
				Desc     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, query string, config *RecipeLinebotConfig) {
	queryPhrases := strings.Fields(query)
	var reqBody bytes.Buffer
	reqBody.WriteString(`{"size": `)
	reqBody.WriteString(MaxRecipesToReply)
	reqBody.WriteString(`, "query": {"bool": {"should": [`)
	for idx, phrase := range queryPhrases {
		if idx != 0 {
			reqBody.WriteString(`, `)
		}
		reqBody.WriteString(`{"multi_match": {"query": "`)
		reqBody.WriteString(phrase)
		reqBody.WriteString(`", "type": "phrase", "fields": ["materials", "title", "description"]}}`)
	}
	reqBody.WriteString(`]}}}`)

	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.NewReader(reqBody.Bytes()))
	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.Desc
			if len(desc) > MaxRecipeDescLength {
				descEnd := MaxRecipeDescLength - len(RecipeDescTailIfTooLong)
				for !utf8.RuneStart(desc[descEnd]) {
					descEnd--
				}
				desc = desc[0:descEnd] + RecipeDescTailIfTooLong
			}
			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>:art: 受信メッセージのトークナイズを Elasticsearch に移譲する<commit_after>/**
 * Copyright (C) 2016 tech0522.tk
 */
package main

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

	"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 MaxRecipeDescLength = 60
const RecipeDescTailIfTooLong = "..."
const RecipeCarouselAltTextTailing = "..."

type RecipeDBSearchQuery struct {
	Size int `json:"size"`
	Query struct {
		MultiMatch struct {
			Query string `json:"query"`
			Type string `json:"type"`
			Fields []string `json:"fields"`
		} `json:"multi_match"`
	} `json:"query"`
}

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

func buildSearchQuery(rawQuery string) ([]byte, error) {
	var query RecipeDBSearchQuery
	query.Size = MaxRecipesToReply
	query.Query.MultiMatch.Query = rawQuery
	query.Query.MultiMatch.Type = "cross_fields"
	query.Query.MultiMatch.Fields = []string{"materials.keyword^100", "materials^5", "title", "description"}
	return json.Marshal(query)
}

func replyRecipe(bot *linebot.Client, replyToken string, rawQuery string, config *RecipeLinebotConfig) {
	query, err := buildSearchQuery(rawQuery)
	if err != nil {
		log.Fatal(err)
	}
	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.NewReader(query))
	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.Desc
			if len(desc) > MaxRecipeDescLength {
				descEnd := MaxRecipeDescLength - len(RecipeDescTailIfTooLong)
				for !utf8.RuneStart(desc[descEnd]) {
					descEnd--
				}
				desc = desc[0:descEnd] + RecipeDescTailIfTooLong
			}
			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>// Copyright (c) 2013-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"io/ioutil"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"sync"

	"github.com/btcsuite/btcwallet/chain"
	"github.com/btcsuite/btcwallet/rpc/legacyrpc"
	"github.com/btcsuite/btcwallet/wallet"
)

var (
	cfg *config
)

func main() {
	// Use all processor cores.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Work around defer not working after os.Exit.
	if err := walletMain(); err != nil {
		os.Exit(1)
	}
}

// walletMain is a work-around main function that is required since deferred
// functions (such as log flushing) are not called with calls to os.Exit.
// Instead, main runs this function and checks for a non-nil error, at which
// point any defers have already run, and if the error is non-nil, the program
// can be exited with an error exit status.
func walletMain() error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer backendLog.Flush()

	if cfg.Profile != "" {
		go func() {
			listenAddr := net.JoinHostPort("", cfg.Profile)
			log.Infof("Profile server listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			log.Errorf("%v", http.ListenAndServe(listenAddr, nil))
		}()
	}

	dbDir := networkDir(cfg.DataDir, activeNet.Params)
	loader := wallet.NewLoader(activeNet.Params, dbDir)

	// Create and start HTTP server to serve wallet client connections.
	// This will be updated with the wallet and chain server RPC client
	// created below after each is created.
	rpcs, legacyRPCServer, err := startRPCServers(loader)
	if err != nil {
		log.Errorf("Unable to create RPC servers: %v", err)
		return err
	}

	// Create and start chain RPC client so it's ready to connect to
	// the wallet when loaded later.
	if !cfg.NoInitialLoad {
		go rpcClientConnectLoop(legacyRPCServer, loader)
	}

	loader.RunAfterLoad(func(w *wallet.Wallet) {
		startWalletRPCServices(w, rpcs, legacyRPCServer)
	})

	if !cfg.NoInitialLoad {
		// Load the wallet database.  It must have been created already
		// or this will return an appropriate error.
		_, err = loader.OpenExistingWallet([]byte(cfg.WalletPass), true)
		if err != nil {
			log.Error(err)
			return err
		}
	}

	// Add interrupt handlers to shutdown the various process components
	// before exiting.  Interrupt handlers run in LIFO order, so the wallet
	// (which should be closed last) is added first.
	addInterruptHandler(func() {
		err := loader.UnloadWallet()
		if err != nil && err != wallet.ErrNotLoaded {
			log.Errorf("Failed to close wallet: %v", err)
		}
	})
	if rpcs != nil {
		addInterruptHandler(func() {
			// TODO: Does this need to wait for the grpc server to
			// finish up any requests?
			log.Warn("Stopping RPC server...")
			rpcs.Stop()
			log.Info("RPC server shutdown")
		})
	}
	if legacyRPCServer != nil {
		addInterruptHandler(func() {
			log.Warn("Stopping legacy RPC server...")
			legacyRPCServer.Stop()
			log.Info("Legacy RPC server shutdown")
		})
		go func() {
			<-legacyRPCServer.RequestProcessShutdown()
			simulateInterrupt()
		}()
	}

	<-interruptHandlersDone
	log.Info("Shutdown complete")
	return nil
}

// rpcClientConnectLoop continuously attempts a connection to the consensus RPC
// server.  When a connection is established, the client is used to sync the
// loaded wallet, either immediately or when loaded at a later time.
//
// The legacy RPC is optional.  If set, the connected RPC client will be
// associated with the server for RPC passthrough and to enable additional
// methods.
func rpcClientConnectLoop(legacyRPCServer *legacyrpc.Server, loader *wallet.Loader) {
	certs := readCAFile()

	for {
		chainClient, err := startChainRPC(certs)
		if err != nil {
			log.Errorf("Unable to open connection to consensus RPC server: %v", err)
			continue
		}

		// Rather than inlining this logic directly into the loader
		// callback, a function variable is used to avoid running any of
		// this after the client disconnects by setting it to nil.  This
		// prevents the callback from associating a wallet loaded at a
		// later time with a client that has already disconnected.  A
		// mutex is used to make this concurrent safe.
		associateRPCClient := func(w *wallet.Wallet) {
			w.SynchronizeRPC(chainClient)
			if legacyRPCServer != nil {
				legacyRPCServer.SetChainServer(chainClient)
			}
		}
		mu := new(sync.Mutex)
		loader.RunAfterLoad(func(w *wallet.Wallet) {
			mu.Lock()
			associate := associateRPCClient
			mu.Unlock()
			if associate != nil {
				associate(w)
			}
		})

		chainClient.WaitForShutdown()

		mu.Lock()
		associateRPCClient = nil
		mu.Unlock()

		loadedWallet, ok := loader.LoadedWallet()
		if ok {
			// Do not attempt a reconnect when the wallet was
			// explicitly stopped.
			if loadedWallet.ShuttingDown() {
				return
			}

			loadedWallet.SetChainSynced(false)

			// TODO: Rework the wallet so changing the RPC client
			// does not require stopping and restarting everything.
			loadedWallet.Stop()
			loadedWallet.WaitForShutdown()
			loadedWallet.Start()
		}
	}
}

func readCAFile() []byte {
	// Read certificate file if TLS is not disabled.
	var certs []byte
	if !cfg.DisableClientTLS {
		var err error
		certs, err = ioutil.ReadFile(cfg.CAFile)
		if err != nil {
			log.Warnf("Cannot open CA file: %v", err)
			// If there's an error reading the CA file, continue
			// with nil certs and without the client connection.
			certs = nil
		}
	} else {
		log.Info("Chain server RPC TLS is disabled")
	}

	return certs
}

// startChainRPC opens a RPC client connection to a btcd server for blockchain
// services.  This function uses the RPC options from the global config and
// there is no recovery in case the server is not available or if there is an
// authentication error.  Instead, all requests to the client will simply error.
func startChainRPC(certs []byte) (*chain.RPCClient, error) {
	log.Infof("Attempting RPC client connection to %v", cfg.RPCConnect)
	rpcc, err := chain.NewRPCClient(activeNet.Params, cfg.RPCConnect,
		cfg.BtcdUsername, cfg.BtcdPassword, certs, cfg.DisableClientTLS, 0)
	if err != nil {
		return nil, err
	}
	err = rpcc.Start()
	return rpcc, err
}
<commit_msg>Print version string at startup.<commit_after>// Copyright (c) 2013-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"io/ioutil"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"sync"

	"github.com/btcsuite/btcwallet/chain"
	"github.com/btcsuite/btcwallet/rpc/legacyrpc"
	"github.com/btcsuite/btcwallet/wallet"
)

var (
	cfg *config
)

func main() {
	// Use all processor cores.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Work around defer not working after os.Exit.
	if err := walletMain(); err != nil {
		os.Exit(1)
	}
}

// walletMain is a work-around main function that is required since deferred
// functions (such as log flushing) are not called with calls to os.Exit.
// Instead, main runs this function and checks for a non-nil error, at which
// point any defers have already run, and if the error is non-nil, the program
// can be exited with an error exit status.
func walletMain() error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer backendLog.Flush()

	// Show version at startup.
	log.Infof("Version %s", version())

	if cfg.Profile != "" {
		go func() {
			listenAddr := net.JoinHostPort("", cfg.Profile)
			log.Infof("Profile server listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			log.Errorf("%v", http.ListenAndServe(listenAddr, nil))
		}()
	}

	dbDir := networkDir(cfg.DataDir, activeNet.Params)
	loader := wallet.NewLoader(activeNet.Params, dbDir)

	// Create and start HTTP server to serve wallet client connections.
	// This will be updated with the wallet and chain server RPC client
	// created below after each is created.
	rpcs, legacyRPCServer, err := startRPCServers(loader)
	if err != nil {
		log.Errorf("Unable to create RPC servers: %v", err)
		return err
	}

	// Create and start chain RPC client so it's ready to connect to
	// the wallet when loaded later.
	if !cfg.NoInitialLoad {
		go rpcClientConnectLoop(legacyRPCServer, loader)
	}

	loader.RunAfterLoad(func(w *wallet.Wallet) {
		startWalletRPCServices(w, rpcs, legacyRPCServer)
	})

	if !cfg.NoInitialLoad {
		// Load the wallet database.  It must have been created already
		// or this will return an appropriate error.
		_, err = loader.OpenExistingWallet([]byte(cfg.WalletPass), true)
		if err != nil {
			log.Error(err)
			return err
		}
	}

	// Add interrupt handlers to shutdown the various process components
	// before exiting.  Interrupt handlers run in LIFO order, so the wallet
	// (which should be closed last) is added first.
	addInterruptHandler(func() {
		err := loader.UnloadWallet()
		if err != nil && err != wallet.ErrNotLoaded {
			log.Errorf("Failed to close wallet: %v", err)
		}
	})
	if rpcs != nil {
		addInterruptHandler(func() {
			// TODO: Does this need to wait for the grpc server to
			// finish up any requests?
			log.Warn("Stopping RPC server...")
			rpcs.Stop()
			log.Info("RPC server shutdown")
		})
	}
	if legacyRPCServer != nil {
		addInterruptHandler(func() {
			log.Warn("Stopping legacy RPC server...")
			legacyRPCServer.Stop()
			log.Info("Legacy RPC server shutdown")
		})
		go func() {
			<-legacyRPCServer.RequestProcessShutdown()
			simulateInterrupt()
		}()
	}

	<-interruptHandlersDone
	log.Info("Shutdown complete")
	return nil
}

// rpcClientConnectLoop continuously attempts a connection to the consensus RPC
// server.  When a connection is established, the client is used to sync the
// loaded wallet, either immediately or when loaded at a later time.
//
// The legacy RPC is optional.  If set, the connected RPC client will be
// associated with the server for RPC passthrough and to enable additional
// methods.
func rpcClientConnectLoop(legacyRPCServer *legacyrpc.Server, loader *wallet.Loader) {
	certs := readCAFile()

	for {
		chainClient, err := startChainRPC(certs)
		if err != nil {
			log.Errorf("Unable to open connection to consensus RPC server: %v", err)
			continue
		}

		// Rather than inlining this logic directly into the loader
		// callback, a function variable is used to avoid running any of
		// this after the client disconnects by setting it to nil.  This
		// prevents the callback from associating a wallet loaded at a
		// later time with a client that has already disconnected.  A
		// mutex is used to make this concurrent safe.
		associateRPCClient := func(w *wallet.Wallet) {
			w.SynchronizeRPC(chainClient)
			if legacyRPCServer != nil {
				legacyRPCServer.SetChainServer(chainClient)
			}
		}
		mu := new(sync.Mutex)
		loader.RunAfterLoad(func(w *wallet.Wallet) {
			mu.Lock()
			associate := associateRPCClient
			mu.Unlock()
			if associate != nil {
				associate(w)
			}
		})

		chainClient.WaitForShutdown()

		mu.Lock()
		associateRPCClient = nil
		mu.Unlock()

		loadedWallet, ok := loader.LoadedWallet()
		if ok {
			// Do not attempt a reconnect when the wallet was
			// explicitly stopped.
			if loadedWallet.ShuttingDown() {
				return
			}

			loadedWallet.SetChainSynced(false)

			// TODO: Rework the wallet so changing the RPC client
			// does not require stopping and restarting everything.
			loadedWallet.Stop()
			loadedWallet.WaitForShutdown()
			loadedWallet.Start()
		}
	}
}

func readCAFile() []byte {
	// Read certificate file if TLS is not disabled.
	var certs []byte
	if !cfg.DisableClientTLS {
		var err error
		certs, err = ioutil.ReadFile(cfg.CAFile)
		if err != nil {
			log.Warnf("Cannot open CA file: %v", err)
			// If there's an error reading the CA file, continue
			// with nil certs and without the client connection.
			certs = nil
		}
	} else {
		log.Info("Chain server RPC TLS is disabled")
	}

	return certs
}

// startChainRPC opens a RPC client connection to a btcd server for blockchain
// services.  This function uses the RPC options from the global config and
// there is no recovery in case the server is not available or if there is an
// authentication error.  Instead, all requests to the client will simply error.
func startChainRPC(certs []byte) (*chain.RPCClient, error) {
	log.Infof("Attempting RPC client connection to %v", cfg.RPCConnect)
	rpcc, err := chain.NewRPCClient(activeNet.Params, cfg.RPCConnect,
		cfg.BtcdUsername, cfg.BtcdPassword, certs, cfg.DisableClientTLS, 0)
	if err != nil {
		return nil, err
	}
	err = rpcc.Start()
	return rpcc, err
}
<|endoftext|>