<commit_before>package hcl2template

import (
	"fmt"
	"strconv"
	"time"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/gohcl"
	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	hcl2shim "github.com/hashicorp/packer/hcl2template/shim"
	"github.com/zclconf/go-cty/cty"
)

// OnlyExcept is a struct that is meant to be embedded that contains the
// logic required for "only" and "except" meta-parameters.
type OnlyExcept struct {
	Only   []string `json:"only,omitempty"`
	Except []string `json:"except,omitempty"`
}

// Skip says whether or not to skip the build with the given name.
func (o *OnlyExcept) Skip(n string) bool {
	if len(o.Only) > 0 {
		for _, v := range o.Only {
			if v == n {
				return false
			}
		}

		return true
	}

	if len(o.Except) > 0 {
		for _, v := range o.Except {
			if v == n {
				return true
			}
		}

		return false
	}

	return false
}

// Validate validates that the OnlyExcept settings are correct for a thing.
func (o *OnlyExcept) Validate() hcl.Diagnostics {
	var diags hcl.Diagnostics

	if len(o.Only) > 0 && len(o.Except) > 0 {
		diags = diags.Append(&hcl.Diagnostic{
			Summary:  "only one of 'only' or 'except' may be specified",
			Severity: hcl.DiagError,
		})
	}

	return diags
}

// ProvisionerBlock references a detected but unparsed provisioner
type ProvisionerBlock struct {
	PType       string
	PName       string
	PauseBefore time.Duration
	MaxRetries  int
	Timeout     time.Duration
	Override    map[string]interface{}
	OnlyExcept  OnlyExcept
	HCL2Ref
}

func (p *ProvisionerBlock) String() string {
	return fmt.Sprintf(buildProvisionerLabel+"-block %q %q", p.PType, p.PName)
}

func (p *Parser) decodeProvisioner(block *hcl.Block, cfg *PackerConfig) (*ProvisionerBlock, hcl.Diagnostics) {
	var b struct {
		Name        string    `hcl:"name,optional"`
		PauseBefore string    `hcl:"pause_before,optional"`
		MaxRetries  int       `hcl:"max_retries,optional"`
		Timeout     string    `hcl:"timeout,optional"`
		Only        []string  `hcl:"only,optional"`
		Except      []string  `hcl:"except,optional"`
		Override    cty.Value `hcl:"override,optional"`
		Rest        hcl.Body  `hcl:",remain"`
	}
	diags := gohcl.DecodeBody(block.Body, cfg.EvalContext(BuildContext, nil), &b)
	if diags.HasErrors() {
		return nil, diags
	}

	provisioner := &ProvisionerBlock{
		PType:      block.Labels[0],
		PName:      b.Name,
		MaxRetries: b.MaxRetries,
		OnlyExcept: OnlyExcept{Only: b.Only, Except: b.Except},
		HCL2Ref:    newHCL2Ref(block, b.Rest),
	}

	diags = diags.Extend(provisioner.OnlyExcept.Validate())
	if diags.HasErrors() {
		return nil, diags
	}

	if !b.Override.IsNull() {
		override := make(map[string]interface{})
		for buildName, overrides := range b.Override.AsValueMap() {
			buildOverrides := make(map[string]interface{})
			for option, value := range overrides.AsValueMap() {
				buildOverrides[option] = hcl2shim.ConfigValueFromHCL2(value)
			}
			override[buildName] = buildOverrides
		}
		provisioner.Override = override
	}

	if b.PauseBefore != "" {
		pauseBefore, err := time.ParseDuration(b.PauseBefore)
		if err != nil {
			return nil, append(diags, &hcl.Diagnostic{
				Summary: "Failed to parse pause_before duration",
				Detail:  err.Error(),
			})
		}
		provisioner.PauseBefore = pauseBefore
	}

	if b.Timeout != "" {
		timeout, err := time.ParseDuration(b.Timeout)
		if err != nil {
			return nil, append(diags, &hcl.Diagnostic{
				Summary: "Failed to parse timeout duration",
				Detail:  err.Error(),
			})
		}
		provisioner.Timeout = timeout
	}

	return provisioner, diags
}

func (cfg *PackerConfig) startProvisioner(source SourceUseBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext) (packersdk.Provisioner, hcl.Diagnostics) {
	var diags hcl.Diagnostics

	provisioner, err := cfg.parser.PluginConfig.Provisioners.Start(pb.PType)
	if err != nil {
		diags = append(diags, &hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  fmt.Sprintf("failed loading %s", pb.PType),
			Subject:  pb.HCL2Ref.LabelsRanges[0].Ptr(),
			Detail:   err.Error(),
		})
		return nil, diags
	}

	builderVars := source.builderVariables()
	builderVars["packer_debug"] = strconv.FormatBool(cfg.debug)
	builderVars["packer_force"] = strconv.FormatBool(cfg.force)
	builderVars["packer_on_error"] = cfg.onError

	hclProvisioner := &HCL2Provisioner{
		Provisioner:      provisioner,
		provisionerBlock: pb,
		evalContext:      ectx,
		builderVariables: builderVars,
	}

	if pb.Override != nil {
		if override, ok := pb.Override[source.name()]; ok {
			hclProvisioner.override = override.(map[string]interface{})
		}
	}

	err = hclProvisioner.HCL2Prepare(nil)
	if err != nil {
		diags = append(diags, &hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  fmt.Sprintf("Failed preparing %s", pb),
			Detail:   err.Error(),
			Subject:  pb.HCL2Ref.DefRange.Ptr(),
		})
		return nil, diags
	}
	return hclProvisioner, diags
}
<commit_msg>Update types.build.provisioners.go<commit_after>package hcl2template

import (
	"fmt"
	"strconv"
	"time"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/gohcl"
	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	hcl2shim "github.com/hashicorp/packer/hcl2template/shim"
	"github.com/zclconf/go-cty/cty"
)

// OnlyExcept is a struct that is meant to be embedded that contains the
// logic required for "only" and "except" meta-parameters.
type OnlyExcept struct {
	Only   []string `json:"only,omitempty"`
	Except []string `json:"except,omitempty"`
}

// Skip says whether or not to skip the build with the given name.
func (o *OnlyExcept) Skip(n string) bool {
	if len(o.Only) > 0 {
		for _, v := range o.Only {
			if v == n {
				return false
			}
		}

		return true
	}

	if len(o.Except) > 0 {
		for _, v := range o.Except {
			if v == n {
				return true
			}
		}

		return false
	}

	return false
}

// Validate validates that the OnlyExcept settings are correct for a thing.
func (o *OnlyExcept) Validate() hcl.Diagnostics {
	var diags hcl.Diagnostics

	if len(o.Only) > 0 && len(o.Except) > 0 {
		diags = diags.Append(&hcl.Diagnostic{
			Summary:  "only one of 'only' or 'except' may be specified",
			Severity: hcl.DiagError,
		})
	}

	return diags
}

// ProvisionerBlock references a detected but unparsed provisioner
type ProvisionerBlock struct {
	PType       string
	PName       string
	PauseBefore time.Duration
	MaxRetries  int
	Timeout     time.Duration
	Override    map[string]interface{}
	OnlyExcept  OnlyExcept
	HCL2Ref
}

func (p *ProvisionerBlock) String() string {
	return fmt.Sprintf(buildProvisionerLabel+"-block %q %q", p.PType, p.PName)
}

func (p *Parser) decodeProvisioner(block *hcl.Block, cfg *PackerConfig) (*ProvisionerBlock, hcl.Diagnostics) {
	var b struct {
		Name        string    `hcl:"name,optional"`
		PauseBefore string    `hcl:"pause_before,optional"`
		MaxRetries  int       `hcl:"max_retries,optional"`
		Timeout     string    `hcl:"timeout,optional"`
		Only        []string  `hcl:"only,optional"`
		Except      []string  `hcl:"except,optional"`
		Override    cty.Value `hcl:"override,optional"`
		Rest        hcl.Body  `hcl:",remain"`
	}
	diags := gohcl.DecodeBody(block.Body, cfg.EvalContext(BuildContext, nil), &b)
	if diags.HasErrors() {
		return nil, diags
	}

	provisioner := &ProvisionerBlock{
		PType:      block.Labels[0],
		PName:      b.Name,
		MaxRetries: b.MaxRetries,
		OnlyExcept: OnlyExcept{Only: b.Only, Except: b.Except},
		HCL2Ref:    newHCL2Ref(block, b.Rest),
	}

	diags = diags.Extend(provisioner.OnlyExcept.Validate())
	if diags.HasErrors() {
		return nil, diags
	}

	if !b.Override.IsNull() {
		override := make(map[string]interface{})
		for buildName, overrides := range b.Override.AsValueMap() {
			buildOverrides := make(map[string]interface{})
			for option, value := range overrides.AsValueMap() {
				buildOverrides[option] = hcl2shim.ConfigValueFromHCL2(value)
			}
			override[buildName] = buildOverrides
		}
		provisioner.Override = override
	}

	if b.PauseBefore != "" {
		pauseBefore, err := time.ParseDuration(b.PauseBefore)
		if err != nil {
			return nil, append(diags, &hcl.Diagnostic{
				Summary:  "Failed to parse pause_before duration",
				Severity: hcl.DiagError,
				Detail:   err.Error(),
			})
		}
		provisioner.PauseBefore = pauseBefore
	}

	if b.Timeout != "" {
		timeout, err := time.ParseDuration(b.Timeout)
		if err != nil {
			return nil, append(diags, &hcl.Diagnostic{
				Summary: "Failed to parse timeout duration",
				Detail:  err.Error(),
			})
		}
		provisioner.Timeout = timeout
	}

	return provisioner, diags
}

func (cfg *PackerConfig) startProvisioner(source SourceUseBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext) (packersdk.Provisioner, hcl.Diagnostics) {
	var diags hcl.Diagnostics

	provisioner, err := cfg.parser.PluginConfig.Provisioners.Start(pb.PType)
	if err != nil {
		diags = append(diags, &hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  fmt.Sprintf("failed loading %s", pb.PType),
			Subject:  pb.HCL2Ref.LabelsRanges[0].Ptr(),
			Detail:   err.Error(),
		})
		return nil, diags
	}

	builderVars := source.builderVariables()
	builderVars["packer_debug"] = strconv.FormatBool(cfg.debug)
	builderVars["packer_force"] = strconv.FormatBool(cfg.force)
	builderVars["packer_on_error"] = cfg.onError

	hclProvisioner := &HCL2Provisioner{
		Provisioner:      provisioner,
		provisionerBlock: pb,
		evalContext:      ectx,
		builderVariables: builderVars,
	}

	if pb.Override != nil {
		if override, ok := pb.Override[source.name()]; ok {
			hclProvisioner.override = override.(map[string]interface{})
		}
	}

	err = hclProvisioner.HCL2Prepare(nil)
	if err != nil {
		diags = append(diags, &hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  fmt.Sprintf("Failed preparing %s", pb),
			Detail:   err.Error(),
			Subject:  pb.HCL2Ref.DefRange.Ptr(),
		})
		return nil, diags
	}
	return hclProvisioner, diags
}
<|endoftext|>


<commit_before>/*
	Copyright (c) 2016, Percona LLC and/or its affiliates. All rights reserved.

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

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

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

package pmm

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"time"

	"gopkg.in/mgo.v2"
)

// DetectMongoDB verifies MongoDB connection.
func (a *Admin) DetectMongoDB(uri string) (mgo.BuildInfo, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	args := []string{
		"--test",
	}
	// Add additional args passed to pmm-admin
	args = append(args, a.Args...)
	cmd := exec.CommandContext(
		ctx,
		fmt.Sprintf("%s/mongodb_exporter", PMMBaseDir),
		args...,
	)
	cmd.Env = append(os.Environ(), fmt.Sprintf("MONGODB_URI=%s", uri))

	b, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("cannot verify MongoDB connection: %s: %s", err, string(b))
		return mgo.BuildInfo{}, err
	}
	buildInfo := mgo.BuildInfo{}
	err = json.Unmarshal(b, &buildInfo)
	if err != nil {
		err = fmt.Errorf("cannot read BuildInfo from output: %s: %s", err, string(b))
		return mgo.BuildInfo{}, err
	}

	return buildInfo, nil
}
<commit_msg>PMM-1950: Display also path and params.<commit_after>/*
	Copyright (c) 2016, Percona LLC and/or its affiliates. All rights reserved.

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

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

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

package pmm

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"

	"gopkg.in/mgo.v2"
)

// DetectMongoDB verifies MongoDB connection.
func (a *Admin) DetectMongoDB(uri string) (mgo.BuildInfo, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	path := fmt.Sprintf("%s/mongodb_exporter", PMMBaseDir)
	args := []string{
		"--test",
	}
	// Add additional args passed to pmm-admin
	args = append(args, a.Args...)
	cmd := exec.CommandContext(
		ctx,
		path,
		args...,
	)
	cmd.Env = append(os.Environ(), fmt.Sprintf("MONGODB_URI=%s", uri))

	b, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("cannot verify MongoDB connection with `%s %s`: %s: %s", path, strings.Join(args, " "), err, string(b))
		return mgo.BuildInfo{}, err
	}
	buildInfo := mgo.BuildInfo{}
	err = json.Unmarshal(b, &buildInfo)
	if err != nil {
		err = fmt.Errorf("cannot read BuildInfo from output of `%s %s`: %s: %s", path, strings.Join(args, " "), err, string(b))
		return mgo.BuildInfo{}, err
	}

	return buildInfo, nil
}
<|endoftext|>


<commit_before>// Package core implements Chain Core and its API.
package core

import (
	"context"
	"expvar"
	"fmt"
	"net/http"
	"net/http/pprof"
	"sync"
	"time"

	"chain/core/accesstoken"
	"chain/core/account"
	"chain/core/asset"
	"chain/core/leader"
	"chain/core/mockhsm"
	"chain/core/query"
	"chain/core/rpc"
	"chain/core/txbuilder"
	"chain/core/txdb"
	"chain/database/pg"
	"chain/encoding/json"
	"chain/errors"
	"chain/generated/dashboard"
	"chain/generated/docs"
	"chain/net/http/gzip"
	"chain/net/http/httpjson"
	"chain/net/http/limit"
	"chain/net/http/reqid"
	"chain/net/http/static"
	"chain/protocol"
	"chain/protocol/bc"
)

const (
	defGenericPageSize = 100
)

// TODO(kr): change this to "network" or something.
const networkRPCPrefix = "/rpc/"

var (
	errNotFound       = errors.New("not found")
	errRateLimited    = errors.New("request limit exceeded")
	errLeaderElection = errors.New("no leader; pending election")
)

// Handler serves the Chain HTTP API
type Handler struct {
	Chain         *protocol.Chain
	Store         *txdb.Store
	Assets        *asset.Registry
	Accounts      *account.Manager
	HSM           *mockhsm.HSM
	Indexer       *query.Indexer
	AccessTokens  *accesstoken.CredentialStore
	Config        *Config
	DB            pg.DB
	Addr          string
	AltAuth       func(*http.Request) bool
	Signer        func(context.Context, *bc.Block) ([]byte, error)
	RequestLimits []RequestLimit

	once           sync.Once
	handler        http.Handler
	actionDecoders map[string]func(data []byte) (txbuilder.Action, error)

	healthMu     sync.Mutex
	healthErrors map[string]interface{}
}

type RequestLimit struct {
	Key       func(*http.Request) string
	Burst     int
	PerSecond int
}

func maxBytes(h http.Handler) http.Handler {
	const maxReqSize = 1e5 // 100kB
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		// A block can easily be bigger than maxReqSize, but everything
		// else should be pretty small.
		if req.URL.Path != networkRPCPrefix+"signer/sign-block" {
			req.Body = http.MaxBytesReader(w, req.Body, maxReqSize)
		}
		h.ServeHTTP(w, req)
	})
}

func (h *Handler) init() {
	// Setup the available transact actions.
	h.actionDecoders = map[string]func(data []byte) (txbuilder.Action, error){
		"control_account":                h.Accounts.DecodeControlAction,
		"control_program":                txbuilder.DecodeControlProgramAction,
		"issue":                          h.Assets.DecodeIssueAction,
		"spend_account":                  h.Accounts.DecodeSpendAction,
		"spend_account_unspent_output":   h.Accounts.DecodeSpendUTXOAction,
		"set_transaction_reference_data": txbuilder.DecodeSetTxRefDataAction,
	}

	// Setup the muxer.
	needConfig := jsonHandler
	if h.Config == nil {
		needConfig = func(f interface{}) http.Handler {
			return alwaysError(errUnconfigured)
		}
	}

	m := http.NewServeMux()
	m.Handle("/", alwaysError(errNotFound))
	m.Handle("/health", jsonHandler(h.health))

	m.Handle("/create-account", needConfig(h.createAccount))
	m.Handle("/create-asset", needConfig(h.createAsset))
	m.Handle("/build-transaction", needConfig(h.build))
	m.Handle("/submit-transaction", needConfig(h.submit))
	m.Handle("/create-control-program", needConfig(h.createControlProgram))
	m.Handle("/create-transaction-feed", needConfig(h.createTxFeed))
	m.Handle("/get-transaction-feed", needConfig(h.getTxFeed))
	m.Handle("/update-transaction-feed", needConfig(h.updateTxFeed))
	m.Handle("/delete-transaction-feed", needConfig(h.deleteTxFeed))
	m.Handle("/mockhsm/create-key", needConfig(h.mockhsmCreateKey))
	m.Handle("/mockhsm/list-keys", needConfig(h.mockhsmListKeys))
	m.Handle("/mockhsm/delkey", needConfig(h.mockhsmDelKey))
	m.Handle("/mockhsm/sign-transaction", needConfig(h.mockhsmSignTemplates))
	m.Handle("/list-accounts", needConfig(h.listAccounts))
	m.Handle("/list-assets", needConfig(h.listAssets))
	m.Handle("/list-transaction-feeds", needConfig(h.listTxFeeds))
	m.Handle("/list-transactions", needConfig(h.listTransactions))
	m.Handle("/list-balances", needConfig(h.listBalances))
	m.Handle("/list-unspent-outputs", needConfig(h.listUnspentOutputs))
	m.Handle("/reset", needConfig(h.reset))

	m.Handle(networkRPCPrefix+"submit", needConfig(h.Chain.AddTx))
	m.Handle(networkRPCPrefix+"get-blocks", needConfig(h.getBlocksRPC)) // DEPRECATED: use get-block instead
	m.Handle(networkRPCPrefix+"get-block", needConfig(h.getBlockRPC))
	m.Handle(networkRPCPrefix+"get-snapshot-info", needConfig(h.getSnapshotInfoRPC))
	m.Handle(networkRPCPrefix+"get-snapshot", http.HandlerFunc(h.getSnapshotRPC))
	m.Handle(networkRPCPrefix+"signer/sign-block", needConfig(h.leaderSignHandler(h.Signer)))
	m.Handle(networkRPCPrefix+"block-height", needConfig(func(ctx context.Context) map[string]uint64 {
		h := h.Chain.Height()
		return map[string]uint64{
			"block_height": h,
		}
	}))

	m.Handle("/create-access-token", jsonHandler(h.createAccessToken))
	m.Handle("/list-access-tokens", jsonHandler(h.listAccessTokens))
	m.Handle("/delete-access-token", jsonHandler(h.deleteAccessToken))
	m.Handle("/configure", jsonHandler(h.configure))
	m.Handle("/info", jsonHandler(h.info))

	m.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
	m.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	m.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	m.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	m.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

	latencyHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if l := latency(m, req); l != nil {
			defer l.RecordSince(time.Now())
		}
		m.ServeHTTP(w, req)
	})

	var handler = (&apiAuthn{
		tokens:   h.AccessTokens,
		tokenMap: make(map[string]tokenResult),
		alt:      h.AltAuth,
	}).handler(latencyHandler)
	handler = maxBytes(handler)
	handler = webAssetsHandler(handler)
	for _, l := range h.RequestLimits {
		handler = limit.Handler(handler, alwaysError(errRateLimited), l.PerSecond, l.Burst, l.Key)
	}
	handler = gzip.Handler{Handler: handler}
	handler = dbContextHandler(handler, h.DB)
	handler = coreCounter(handler)
	handler = reqid.Handler(handler)
	handler = timeoutContextHandler(handler)
	h.handler = handler
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.once.Do(h.init)

	h.handler.ServeHTTP(w, r)
}

// Config encapsulates Core-level, persistent configuration options.
type Config struct {
	ID                   string  `json:"id"`
	IsSigner             bool    `json:"is_signer"`
	IsGenerator          bool    `json:"is_generator"`
	BlockchainID         bc.Hash `json:"blockchain_id"`
	GeneratorURL         string  `json:"generator_url"`
	GeneratorAccessToken string  `json:"generator_access_token"`
	ConfiguredAt         time.Time
	BlockPub             string         `json:"block_pub"`
	Signers              []ConfigSigner `json:"block_signer_urls"`
	Quorum               int
	MaxIssuanceWindow    time.Duration
}

type ConfigSigner struct {
	AccessToken string        `json:"access_token"`
	Pubkey      json.HexBytes `json:"pubkey"`
	URL         string        `json:"url"`
}

// Used as a request object for api queries
type requestQuery struct {
	Filter       string        `json:"filter,omitempty"`
	FilterParams []interface{} `json:"filter_params,omitempty"`
	SumBy        []string      `json:"sum_by,omitempty"`
	PageSize     int           `json:"page_size"`

	// AscLongPoll and Timeout are used by /list-transactions
	// to facilitate notifications.
	AscLongPoll bool          `json:"ascending_with_long_poll,omitempty"`
	Timeout     json.Duration `json:"timeout"`

	// After is a completely opaque cursor, indicating that only
	// items in the result set after the one identified by `After`
	// should be included. It has no relationship to time.
	After string `json:"after"`

	// These two are used for time-range queries like /list-transactions
	StartTimeMS uint64 `json:"start_time,omitempty"`
	EndTimeMS   uint64 `json:"end_time,omitempty"`

	// This is used for point-in-time queries like /list-balances
	// TODO(bobg): Different request structs for endpoints with different needs
	TimestampMS uint64 `json:"timestamp,omitempty"`

	// This is used for filtering results from /list-access-tokens
	// Value must be "client" or "network"
	Type string `json:"type"`

	// Aliases is used to filter results from /mockshm/list-keys
	Aliases []string `json:"aliases,omitempty"`
}

// Used as a response object for api queries
type page struct {
	Items    interface{}  `json:"items"`
	Next     requestQuery `json:"next"`
	LastPage bool         `json:"last_page"`
}

// timeoutContextHandler propagates the timeout, if any, provided as a header
// in the http request.
func timeoutContextHandler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		timeout, err := time.ParseDuration(req.Header.Get(rpc.HeaderTimeout))
		if err != nil {
			handler.ServeHTTP(w, req) // unmodified
			return
		}

		ctx := req.Context()
		ctx, cancel := context.WithTimeout(ctx, timeout)
		defer cancel()
		handler.ServeHTTP(w, req.WithContext(ctx))
	})
}

func dbContextHandler(handler http.Handler, db pg.DB) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		ctx = pg.NewContext(ctx, db)
		handler.ServeHTTP(w, req.WithContext(ctx))
	})
}

func webAssetsHandler(next http.Handler) http.Handler {
	mux := http.NewServeMux()
	mux.Handle("/dashboard/", http.StripPrefix("/dashboard/", static.Handler{
		Assets:  dashboard.Files,
		Default: "index.html",
	}))
	mux.Handle("/docs/", http.StripPrefix("/docs/", static.Handler{
		Assets: docs.Files,
		Index:  "index.html",
	}))
	mux.Handle("/", next)

	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if req.URL.Path == "/" {
			http.Redirect(w, req, "/dashboard/", http.StatusFound)
			return
		}

		mux.ServeHTTP(w, req)
	})
}

func (h *Handler) leaderSignHandler(f func(context.Context, *bc.Block) ([]byte, error)) func(context.Context, *bc.Block) ([]byte, error) {
	return func(ctx context.Context, b *bc.Block) ([]byte, error) {
		if f == nil {
			return nil, errNotFound // TODO(kr): is this really the right error here?
		}
		if leader.IsLeading() {
			return f(ctx, b)
		}
		var resp []byte
		err := h.forwardToLeader(ctx, "/rpc/signer/sign-block", b, &resp)
		return resp, err
	}
}

// forwardToLeader forwards the current request to the core's leader
// process. It propagates the same credentials used in the current
// request. For that reason, it cannot be used outside of a request-
// handling context.
func (h *Handler) forwardToLeader(ctx context.Context, path string, body interface{}, resp interface{}) error {
	addr, err := leader.Address(ctx)
	if err != nil {
		return errors.Wrap(err)
	}

	// Don't infinite loop if the leader's address is our own address.
	// This is possible if we just became the leader. The client should
	// just retry.
	if addr == h.Addr {
		return errLeaderElection
	}

	// TODO(jackson): If using TLS, use https:// here.
	l := &rpc.Client{
		BaseURL: "http://" + addr,
	}

	// Forward the request credentials if we have them.
	// TODO(jackson): Don't use the incoming request's credentials and
	// have an alternative authentication scheme between processes of the
	// same Core. For now, we only call the leader for the purpose of
	// forwarding a request, so this is OK.
	req := httpjson.Request(ctx)
	user, pass, ok := req.BasicAuth()
	if ok {
		l.AccessToken = fmt.Sprintf("%s:%s", user, pass)
	}

	return l.Call(ctx, path, body, &resp)
}

// expvarHandler is copied from the expvar package.
// TODO(jackson): In Go 1.8, use expvar.Handler.
// https://go-review.googlesource.com/#/c/24722/
func expvarHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	fmt.Fprintf(w, "{\n")
	first := true
	expvar.Do(func(kv expvar.KeyValue) {
		if !first {
			fmt.Fprintf(w, ",\n")
		}
		first = false
		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
	})
	fmt.Fprintf(w, "\n}\n")
}
<commit_msg>core: remove errors from /health response<commit_after>// Package core implements Chain Core and its API.
package core

import (
	"context"
	"expvar"
	"fmt"
	"net/http"
	"net/http/pprof"
	"sync"
	"time"

	"chain/core/accesstoken"
	"chain/core/account"
	"chain/core/asset"
	"chain/core/leader"
	"chain/core/mockhsm"
	"chain/core/query"
	"chain/core/rpc"
	"chain/core/txbuilder"
	"chain/core/txdb"
	"chain/database/pg"
	"chain/encoding/json"
	"chain/errors"
	"chain/generated/dashboard"
	"chain/generated/docs"
	"chain/net/http/gzip"
	"chain/net/http/httpjson"
	"chain/net/http/limit"
	"chain/net/http/reqid"
	"chain/net/http/static"
	"chain/protocol"
	"chain/protocol/bc"
)

const (
	defGenericPageSize = 100
)

// TODO(kr): change this to "network" or something.
const networkRPCPrefix = "/rpc/"

var (
	errNotFound       = errors.New("not found")
	errRateLimited    = errors.New("request limit exceeded")
	errLeaderElection = errors.New("no leader; pending election")
)

// Handler serves the Chain HTTP API
type Handler struct {
	Chain         *protocol.Chain
	Store         *txdb.Store
	Assets        *asset.Registry
	Accounts      *account.Manager
	HSM           *mockhsm.HSM
	Indexer       *query.Indexer
	AccessTokens  *accesstoken.CredentialStore
	Config        *Config
	DB            pg.DB
	Addr          string
	AltAuth       func(*http.Request) bool
	Signer        func(context.Context, *bc.Block) ([]byte, error)
	RequestLimits []RequestLimit

	once           sync.Once
	handler        http.Handler
	actionDecoders map[string]func(data []byte) (txbuilder.Action, error)

	healthMu     sync.Mutex
	healthErrors map[string]interface{}
}

type RequestLimit struct {
	Key       func(*http.Request) string
	Burst     int
	PerSecond int
}

func maxBytes(h http.Handler) http.Handler {
	const maxReqSize = 1e5 // 100kB
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		// A block can easily be bigger than maxReqSize, but everything
		// else should be pretty small.
		if req.URL.Path != networkRPCPrefix+"signer/sign-block" {
			req.Body = http.MaxBytesReader(w, req.Body, maxReqSize)
		}
		h.ServeHTTP(w, req)
	})
}

func (h *Handler) init() {
	// Setup the available transact actions.
	h.actionDecoders = map[string]func(data []byte) (txbuilder.Action, error){
		"control_account":                h.Accounts.DecodeControlAction,
		"control_program":                txbuilder.DecodeControlProgramAction,
		"issue":                          h.Assets.DecodeIssueAction,
		"spend_account":                  h.Accounts.DecodeSpendAction,
		"spend_account_unspent_output":   h.Accounts.DecodeSpendUTXOAction,
		"set_transaction_reference_data": txbuilder.DecodeSetTxRefDataAction,
	}

	// Setup the muxer.
	needConfig := jsonHandler
	if h.Config == nil {
		needConfig = func(f interface{}) http.Handler {
			return alwaysError(errUnconfigured)
		}
	}

	m := http.NewServeMux()
	m.Handle("/", alwaysError(errNotFound))
	m.Handle("/health", jsonHandler(func() {}))

	m.Handle("/create-account", needConfig(h.createAccount))
	m.Handle("/create-asset", needConfig(h.createAsset))
	m.Handle("/build-transaction", needConfig(h.build))
	m.Handle("/submit-transaction", needConfig(h.submit))
	m.Handle("/create-control-program", needConfig(h.createControlProgram))
	m.Handle("/create-transaction-feed", needConfig(h.createTxFeed))
	m.Handle("/get-transaction-feed", needConfig(h.getTxFeed))
	m.Handle("/update-transaction-feed", needConfig(h.updateTxFeed))
	m.Handle("/delete-transaction-feed", needConfig(h.deleteTxFeed))
	m.Handle("/mockhsm/create-key", needConfig(h.mockhsmCreateKey))
	m.Handle("/mockhsm/list-keys", needConfig(h.mockhsmListKeys))
	m.Handle("/mockhsm/delkey", needConfig(h.mockhsmDelKey))
	m.Handle("/mockhsm/sign-transaction", needConfig(h.mockhsmSignTemplates))
	m.Handle("/list-accounts", needConfig(h.listAccounts))
	m.Handle("/list-assets", needConfig(h.listAssets))
	m.Handle("/list-transaction-feeds", needConfig(h.listTxFeeds))
	m.Handle("/list-transactions", needConfig(h.listTransactions))
	m.Handle("/list-balances", needConfig(h.listBalances))
	m.Handle("/list-unspent-outputs", needConfig(h.listUnspentOutputs))
	m.Handle("/reset", needConfig(h.reset))

	m.Handle(networkRPCPrefix+"submit", needConfig(h.Chain.AddTx))
	m.Handle(networkRPCPrefix+"get-blocks", needConfig(h.getBlocksRPC)) // DEPRECATED: use get-block instead
	m.Handle(networkRPCPrefix+"get-block", needConfig(h.getBlockRPC))
	m.Handle(networkRPCPrefix+"get-snapshot-info", needConfig(h.getSnapshotInfoRPC))
	m.Handle(networkRPCPrefix+"get-snapshot", http.HandlerFunc(h.getSnapshotRPC))
	m.Handle(networkRPCPrefix+"signer/sign-block", needConfig(h.leaderSignHandler(h.Signer)))
	m.Handle(networkRPCPrefix+"block-height", needConfig(func(ctx context.Context) map[string]uint64 {
		h := h.Chain.Height()
		return map[string]uint64{
			"block_height": h,
		}
	}))

	m.Handle("/create-access-token", jsonHandler(h.createAccessToken))
	m.Handle("/list-access-tokens", jsonHandler(h.listAccessTokens))
	m.Handle("/delete-access-token", jsonHandler(h.deleteAccessToken))
	m.Handle("/configure", jsonHandler(h.configure))
	m.Handle("/info", jsonHandler(h.info))

	m.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
	m.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	m.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	m.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	m.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

	latencyHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if l := latency(m, req); l != nil {
			defer l.RecordSince(time.Now())
		}
		m.ServeHTTP(w, req)
	})

	var handler = (&apiAuthn{
		tokens:   h.AccessTokens,
		tokenMap: make(map[string]tokenResult),
		alt:      h.AltAuth,
	}).handler(latencyHandler)
	handler = maxBytes(handler)
	handler = webAssetsHandler(handler)
	for _, l := range h.RequestLimits {
		handler = limit.Handler(handler, alwaysError(errRateLimited), l.PerSecond, l.Burst, l.Key)
	}
	handler = gzip.Handler{Handler: handler}
	handler = dbContextHandler(handler, h.DB)
	handler = coreCounter(handler)
	handler = reqid.Handler(handler)
	handler = timeoutContextHandler(handler)
	h.handler = handler
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.once.Do(h.init)

	h.handler.ServeHTTP(w, r)
}

// Config encapsulates Core-level, persistent configuration options.
type Config struct {
	ID                   string  `json:"id"`
	IsSigner             bool    `json:"is_signer"`
	IsGenerator          bool    `json:"is_generator"`
	BlockchainID         bc.Hash `json:"blockchain_id"`
	GeneratorURL         string  `json:"generator_url"`
	GeneratorAccessToken string  `json:"generator_access_token"`
	ConfiguredAt         time.Time
	BlockPub             string         `json:"block_pub"`
	Signers              []ConfigSigner `json:"block_signer_urls"`
	Quorum               int
	MaxIssuanceWindow    time.Duration
}

type ConfigSigner struct {
	AccessToken string        `json:"access_token"`
	Pubkey      json.HexBytes `json:"pubkey"`
	URL         string        `json:"url"`
}

// Used as a request object for api queries
type requestQuery struct {
	Filter       string        `json:"filter,omitempty"`
	FilterParams []interface{} `json:"filter_params,omitempty"`
	SumBy        []string      `json:"sum_by,omitempty"`
	PageSize     int           `json:"page_size"`

	// AscLongPoll and Timeout are used by /list-transactions
	// to facilitate notifications.
	AscLongPoll bool          `json:"ascending_with_long_poll,omitempty"`
	Timeout     json.Duration `json:"timeout"`

	// After is a completely opaque cursor, indicating that only
	// items in the result set after the one identified by `After`
	// should be included. It has no relationship to time.
	After string `json:"after"`

	// These two are used for time-range queries like /list-transactions
	StartTimeMS uint64 `json:"start_time,omitempty"`
	EndTimeMS   uint64 `json:"end_time,omitempty"`

	// This is used for point-in-time queries like /list-balances
	// TODO(bobg): Different request structs for endpoints with different needs
	TimestampMS uint64 `json:"timestamp,omitempty"`

	// This is used for filtering results from /list-access-tokens
	// Value must be "client" or "network"
	Type string `json:"type"`

	// Aliases is used to filter results from /mockshm/list-keys
	Aliases []string `json:"aliases,omitempty"`
}

// Used as a response object for api queries
type page struct {
	Items    interface{}  `json:"items"`
	Next     requestQuery `json:"next"`
	LastPage bool         `json:"last_page"`
}

// timeoutContextHandler propagates the timeout, if any, provided as a header
// in the http request.
func timeoutContextHandler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		timeout, err := time.ParseDuration(req.Header.Get(rpc.HeaderTimeout))
		if err != nil {
			handler.ServeHTTP(w, req) // unmodified
			return
		}

		ctx := req.Context()
		ctx, cancel := context.WithTimeout(ctx, timeout)
		defer cancel()
		handler.ServeHTTP(w, req.WithContext(ctx))
	})
}

func dbContextHandler(handler http.Handler, db pg.DB) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		ctx = pg.NewContext(ctx, db)
		handler.ServeHTTP(w, req.WithContext(ctx))
	})
}

func webAssetsHandler(next http.Handler) http.Handler {
	mux := http.NewServeMux()
	mux.Handle("/dashboard/", http.StripPrefix("/dashboard/", static.Handler{
		Assets:  dashboard.Files,
		Default: "index.html",
	}))
	mux.Handle("/docs/", http.StripPrefix("/docs/", static.Handler{
		Assets: docs.Files,
		Index:  "index.html",
	}))
	mux.Handle("/", next)

	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if req.URL.Path == "/" {
			http.Redirect(w, req, "/dashboard/", http.StatusFound)
			return
		}

		mux.ServeHTTP(w, req)
	})
}

func (h *Handler) leaderSignHandler(f func(context.Context, *bc.Block) ([]byte, error)) func(context.Context, *bc.Block) ([]byte, error) {
	return func(ctx context.Context, b *bc.Block) ([]byte, error) {
		if f == nil {
			return nil, errNotFound // TODO(kr): is this really the right error here?
		}
		if leader.IsLeading() {
			return f(ctx, b)
		}
		var resp []byte
		err := h.forwardToLeader(ctx, "/rpc/signer/sign-block", b, &resp)
		return resp, err
	}
}

// forwardToLeader forwards the current request to the core's leader
// process. It propagates the same credentials used in the current
// request. For that reason, it cannot be used outside of a request-
// handling context.
func (h *Handler) forwardToLeader(ctx context.Context, path string, body interface{}, resp interface{}) error {
	addr, err := leader.Address(ctx)
	if err != nil {
		return errors.Wrap(err)
	}

	// Don't infinite loop if the leader's address is our own address.
	// This is possible if we just became the leader. The client should
	// just retry.
	if addr == h.Addr {
		return errLeaderElection
	}

	// TODO(jackson): If using TLS, use https:// here.
	l := &rpc.Client{
		BaseURL: "http://" + addr,
	}

	// Forward the request credentials if we have them.
	// TODO(jackson): Don't use the incoming request's credentials and
	// have an alternative authentication scheme between processes of the
	// same Core. For now, we only call the leader for the purpose of
	// forwarding a request, so this is OK.
	req := httpjson.Request(ctx)
	user, pass, ok := req.BasicAuth()
	if ok {
		l.AccessToken = fmt.Sprintf("%s:%s", user, pass)
	}

	return l.Call(ctx, path, body, &resp)
}

// expvarHandler is copied from the expvar package.
// TODO(jackson): In Go 1.8, use expvar.Handler.
// https://go-review.googlesource.com/#/c/24722/
func expvarHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	fmt.Fprintf(w, "{\n")
	first := true
	expvar.Do(func(kv expvar.KeyValue) {
		if !first {
			fmt.Fprintf(w, ",\n")
		}
		first = false
		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
	})
	fmt.Fprintf(w, "\n}\n")
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"

	e "github.com/techjanitor/pram-post/errors"
	"github.com/techjanitor/pram-post/models"
	u "github.com/techjanitor/pram-post/utils"
)

// DeletePostController will delete a tag
func DeletePostController(c *gin.Context) {

	// Get parameters from validate middleware
	params := c.MustGet("params").([]uint)

	// get userdata from session middleware
	userdata := c.MustGet("userdata").(u.User)

	// Initialize model struct
	m := &models.DeletePostModel{
		Thread: params[0],
		Id:     params[1],
	}

	// Check the record id and get further info
	err := m.Status()
	if err == e.ErrNotFound {
		c.JSON(e.ErrorMessage(e.ErrNotFound))
		c.Error(err)
		return
	} else if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Delete data
	err = m.Delete()
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Initialize cache handle
	cache := u.RedisCache

	// Delete redis stuff
	index_key := fmt.Sprintf("%s:%d", "index", m.Ib)
	directory_key := fmt.Sprintf("%s:%d", "directory", m.Ib)
	thread_key := fmt.Sprintf("%s:%d:%d", "thread", m.Ib, m.Id)
	post_key := fmt.Sprintf("%s:%d:%d", "post", m.Ib, m.Id)
	tags_key := fmt.Sprintf("%s:%d", "tags", m.Ib)
	image_key := fmt.Sprintf("%s:%d", "image", m.Ib)

	err = cache.Delete(index_key, directory_key, thread_key, post_key, tags_key, image_key)
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// response message
	c.JSON(http.StatusOK, gin.H{"success_message": u.AuditDeletePost})

	// audit log
	audit := u.Audit{
		User:   userdata.Id,
		Ib:     m.Ib,
		Ip:     c.ClientIP(),
		Action: u.AuditDeletePost,
		Info:   fmt.Sprintf("%s/%d", m.Name, m.Id),
	}

	err = audit.Submit()
	if err != nil {
		c.Error(err)
	}

	return

}
<commit_msg>add delete post<commit_after>package controllers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"

	e "github.com/techjanitor/pram-post/errors"
	"github.com/techjanitor/pram-post/models"
	u "github.com/techjanitor/pram-post/utils"
)

// DeletePostController will delete a tag
func DeletePostController(c *gin.Context) {

	// Get parameters from validate middleware
	params := c.MustGet("params").([]uint)

	// get userdata from session middleware
	userdata := c.MustGet("userdata").(u.User)

	// Initialize model struct
	m := &models.DeletePostModel{
		Thread: params[0],
		Id:     params[1],
	}

	// Check the record id and get further info
	err := m.Status()
	if err == e.ErrNotFound {
		c.JSON(e.ErrorMessage(e.ErrNotFound))
		c.Error(err)
		return
	} else if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Delete data
	err = m.Delete()
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Initialize cache handle
	cache := u.RedisCache

	// Delete redis stuff
	index_key := fmt.Sprintf("%s:%d", "index", m.Ib)
	directory_key := fmt.Sprintf("%s:%d", "directory", m.Ib)
	thread_key := fmt.Sprintf("%s:%d:%d", "thread", m.Ib, m.Thread)
	post_key := fmt.Sprintf("%s:%d:%d", "post", m.Ib, m.Thread)
	tags_key := fmt.Sprintf("%s:%d", "tags", m.Ib)
	image_key := fmt.Sprintf("%s:%d", "image", m.Ib)

	err = cache.Delete(index_key, directory_key, thread_key, post_key, tags_key, image_key)
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// response message
	c.JSON(http.StatusOK, gin.H{"success_message": u.AuditDeletePost})

	// audit log
	audit := u.Audit{
		User:   userdata.Id,
		Ib:     m.Ib,
		Ip:     c.ClientIP(),
		Action: u.AuditDeletePost,
		Info:   fmt.Sprintf("%s/%d", m.Name, m.Id),
	}

	err = audit.Submit()
	if err != nil {
		c.Error(err)
	}

	return

}
<|endoftext|>


<commit_before>package pollers

import (
	"github.com/freeformz/shh/mm"
	"github.com/freeformz/shh/utils"
	"sort"
	"strings"
	"time"
)

const (
	DEVICE_FILE     = "/proc/net/dev"
	DEFAULT_DEVICES = "lo,eth0"
)

var (
	devices = utils.GetEnvWithDefaultStrings("SHH_NIF_DEVICES", DEFAULT_DEVICES)
)

type NifReceiveValues struct {
	Bytes      float64
	Packets    float64
	Errors     float64
	Dropped    float64
	Fifo       float64
	Frame      float64
	Compressed float64
	Multicast  float64
}

type NifTransmitValues struct {
	Bytes      float64
	Packets    float64
	Errors     float64
	Dropped    float64
	Fifo       float64
	Collisions float64
	Carrier    float64
	Compressed float64
}

type NifValues struct {
	Receive  NifReceiveValues
	Transmit NifTransmitValues
}

func (nv NifValues) CalcDifference(last NifValues) NifValues {
	return NifValues{
		Receive: NifReceiveValues{
			Bytes:      nv.Receive.Bytes - last.Receive.Bytes,
			Packets:    nv.Receive.Packets - last.Receive.Packets,
			Errors:     nv.Receive.Errors - last.Receive.Errors,
			Dropped:    nv.Receive.Dropped - last.Receive.Dropped,
			Fifo:       nv.Receive.Fifo - last.Receive.Fifo,
			Frame:      nv.Receive.Frame - last.Receive.Frame,
			Compressed: nv.Receive.Compressed - last.Receive.Compressed,
			Multicast:  nv.Receive.Multicast - last.Receive.Multicast,
		},
		Transmit: NifTransmitValues{
			Bytes:      nv.Transmit.Bytes - last.Transmit.Bytes,
			Packets:    nv.Transmit.Packets - last.Transmit.Packets,
			Errors:     nv.Transmit.Errors - last.Transmit.Errors,
			Dropped:    nv.Transmit.Dropped - last.Transmit.Dropped,
			Fifo:       nv.Transmit.Fifo - last.Transmit.Fifo,
			Collisions: nv.Transmit.Collisions - last.Transmit.Collisions,
			Carrier:    nv.Transmit.Carrier - last.Transmit.Carrier,
			Compressed: nv.Transmit.Compressed - last.Transmit.Compressed,
		},
	}
}

type NetworkInterface struct {
	measurements chan<- *mm.Measurement
	last         map[string]NifValues
}

func NewNetworkInterfacePoller(measurements chan<- *mm.Measurement) NetworkInterface {
	return NetworkInterface{measurements: measurements, last: make(map[string]NifValues)}
}

// http://www.kernel.org/doc/Documentation/filesystems/proc.txt (section 1.4)
func (poller NetworkInterface) Poll(tick time.Time) {

	for line := range utils.FileLineChannel(DEVICE_FILE) {
		fields := strings.Fields(line)
		if strings.HasSuffix(fields[0], ":") {
			device := fields[0]
			nakedDevice := device[:len(device)-1]
			idx := sort.SearchStrings(devices, nakedDevice)
			if idx < len(devices) && fields[idx] == device {
				// It's a device we want to gather metrics for

				current := NifValues{
					Receive: NifReceiveValues{
						Bytes:      utils.Atofloat64(fields[1]),
						Packets:    utils.Atofloat64(fields[2]),
						Errors:     utils.Atofloat64(fields[3]),
						Dropped:    utils.Atofloat64(fields[4]),
						Fifo:       utils.Atofloat64(fields[5]),
						Frame:      utils.Atofloat64(fields[6]),
						Compressed: utils.Atofloat64(fields[7]),
						Multicast:  utils.Atofloat64(fields[8]),
					},
					Transmit: NifTransmitValues{
						Bytes:      utils.Atofloat64(fields[9]),
						Packets:    utils.Atofloat64(fields[10]),
						Errors:     utils.Atofloat64(fields[11]),
						Dropped:    utils.Atofloat64(fields[12]),
						Fifo:       utils.Atofloat64(fields[13]),
						Collisions: utils.Atofloat64(fields[14]),
						Carrier:    utils.Atofloat64(fields[15]),
						Compressed: utils.Atofloat64(fields[16]),
					},
				}

				last, exists := poller.last[device]

				if exists {
					difference := current.CalcDifference(last)

					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "bytes"}, difference.Receive.Bytes}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "packets"}, difference.Receive.Packets}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "errors"}, difference.Receive.Errors}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "dropped"}, difference.Receive.Dropped}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "errors", "fifo"}, difference.Receive.Fifo}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "errors", "frame"}, difference.Receive.Frame}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "compressed"}, difference.Receive.Compressed}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "multicast"}, difference.Receive.Multicast}

					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "bytes"}, difference.Transmit.Bytes}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "packets"}, difference.Transmit.Packets}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors"}, difference.Transmit.Errors}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "dropped"}, difference.Transmit.Dropped}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors", "fifo"}, difference.Transmit.Fifo}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors", "collisions"}, difference.Transmit.Collisions}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors", "carrier"}, difference.Transmit.Carrier}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "compressed"}, difference.Transmit.Compressed}
				}

				poller.last[device] = current
			}
		}
	}
}

func (poller NetworkInterface) Name() string {
	return "nif"
}
<commit_msg>Sort it<commit_after>package pollers

import (
	"github.com/freeformz/shh/mm"
	"github.com/freeformz/shh/utils"
	"sort"
	"strings"
	"time"
)

const (
	DEVICE_FILE     = "/proc/net/dev"
	DEFAULT_DEVICES = "eth0,lo"
)

var (
	devices = utils.GetEnvWithDefaultStrings("SHH_NIF_DEVICES", DEFAULT_DEVICES)
)

type NifReceiveValues struct {
	Bytes      float64
	Packets    float64
	Errors     float64
	Dropped    float64
	Fifo       float64
	Frame      float64
	Compressed float64
	Multicast  float64
}

type NifTransmitValues struct {
	Bytes      float64
	Packets    float64
	Errors     float64
	Dropped    float64
	Fifo       float64
	Collisions float64
	Carrier    float64
	Compressed float64
}

type NifValues struct {
	Receive  NifReceiveValues
	Transmit NifTransmitValues
}

func (nv NifValues) CalcDifference(last NifValues) NifValues {
	return NifValues{
		Receive: NifReceiveValues{
			Bytes:      nv.Receive.Bytes - last.Receive.Bytes,
			Packets:    nv.Receive.Packets - last.Receive.Packets,
			Errors:     nv.Receive.Errors - last.Receive.Errors,
			Dropped:    nv.Receive.Dropped - last.Receive.Dropped,
			Fifo:       nv.Receive.Fifo - last.Receive.Fifo,
			Frame:      nv.Receive.Frame - last.Receive.Frame,
			Compressed: nv.Receive.Compressed - last.Receive.Compressed,
			Multicast:  nv.Receive.Multicast - last.Receive.Multicast,
		},
		Transmit: NifTransmitValues{
			Bytes:      nv.Transmit.Bytes - last.Transmit.Bytes,
			Packets:    nv.Transmit.Packets - last.Transmit.Packets,
			Errors:     nv.Transmit.Errors - last.Transmit.Errors,
			Dropped:    nv.Transmit.Dropped - last.Transmit.Dropped,
			Fifo:       nv.Transmit.Fifo - last.Transmit.Fifo,
			Collisions: nv.Transmit.Collisions - last.Transmit.Collisions,
			Carrier:    nv.Transmit.Carrier - last.Transmit.Carrier,
			Compressed: nv.Transmit.Compressed - last.Transmit.Compressed,
		},
	}
}

type NetworkInterface struct {
	measurements chan<- *mm.Measurement
	last         map[string]NifValues
}

func NewNetworkInterfacePoller(measurements chan<- *mm.Measurement) NetworkInterface {
	return NetworkInterface{measurements: measurements, last: make(map[string]NifValues)}
}

// http://www.kernel.org/doc/Documentation/filesystems/proc.txt (section 1.4)
func (poller NetworkInterface) Poll(tick time.Time) {

	for line := range utils.FileLineChannel(DEVICE_FILE) {
		fields := strings.Fields(line)
		if strings.HasSuffix(fields[0], ":") {
			device := fields[0]
			nakedDevice := device[:len(device)-1]
			idx := sort.SearchStrings(devices, nakedDevice)
			if idx < len(devices) && fields[idx] == device {
				// It's a device we want to gather metrics for

				current := NifValues{
					Receive: NifReceiveValues{
						Bytes:      utils.Atofloat64(fields[1]),
						Packets:    utils.Atofloat64(fields[2]),
						Errors:     utils.Atofloat64(fields[3]),
						Dropped:    utils.Atofloat64(fields[4]),
						Fifo:       utils.Atofloat64(fields[5]),
						Frame:      utils.Atofloat64(fields[6]),
						Compressed: utils.Atofloat64(fields[7]),
						Multicast:  utils.Atofloat64(fields[8]),
					},
					Transmit: NifTransmitValues{
						Bytes:      utils.Atofloat64(fields[9]),
						Packets:    utils.Atofloat64(fields[10]),
						Errors:     utils.Atofloat64(fields[11]),
						Dropped:    utils.Atofloat64(fields[12]),
						Fifo:       utils.Atofloat64(fields[13]),
						Collisions: utils.Atofloat64(fields[14]),
						Carrier:    utils.Atofloat64(fields[15]),
						Compressed: utils.Atofloat64(fields[16]),
					},
				}

				last, exists := poller.last[device]

				if exists {
					difference := current.CalcDifference(last)

					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "bytes"}, difference.Receive.Bytes}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "packets"}, difference.Receive.Packets}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "errors"}, difference.Receive.Errors}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "dropped"}, difference.Receive.Dropped}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "errors", "fifo"}, difference.Receive.Fifo}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "errors", "frame"}, difference.Receive.Frame}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "compressed"}, difference.Receive.Compressed}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "receive", "multicast"}, difference.Receive.Multicast}

					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "bytes"}, difference.Transmit.Bytes}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "packets"}, difference.Transmit.Packets}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors"}, difference.Transmit.Errors}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "dropped"}, difference.Transmit.Dropped}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors", "fifo"}, difference.Transmit.Fifo}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors", "collisions"}, difference.Transmit.Collisions}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "errors", "carrier"}, difference.Transmit.Carrier}
					poller.measurements <- &mm.Measurement{tick, poller.Name(), []string{nakedDevice, "transmit", "compressed"}, difference.Transmit.Compressed}
				}

				poller.last[device] = current
			}
		}
	}
}

func (poller NetworkInterface) Name() string {
	return "nif"
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"strconv"
	"time"

	"github.com/andrey-yantsen/teko-astra-go"
	"github.com/contactless/wbgo"
)

type AstraDetector struct {
	wbgo.DeviceBase
	sensorInfo        astra_l.SensorInfo
	astraAddress      uint16
	fieldsInitialized bool
	d                 *AstraDevice
}

func (a *AstraDetector) IsVirtual() bool {
	return false
}

func (a *AstraDetector) AcceptValue(name, value string) {
}

func (a *AstraDetector) AcceptOnValue(name, value string) bool {
	switch name {
	case "delete":
		if value == "1" {
			a.remove()
		}
	}
	return false
}

func (a *AstraDetector) remove() {
	a.d.device.DeleteLevel2Device(a.sensorInfo.Id)
	a.d.modelObserver.RemoveDevice(a)
}

func (a *AstraDetector) handleEvent(e interface{}) {
	wbgo.Debug.Printf("Inspecting %T %+v\n", e, e)
	a.Observer.OnValue(a, "Last event time", time.Now().Format(time.UnixDate))
	v := reflect.ValueOf(e)
	for i := 0; i < v.NumField(); i++ {
		f := v.Field(i)
		if !f.CanSet() {
			continue
		}
		fieldName := v.Type().Field(i).Name
		switch fi := f.Interface().(type) {
		case astra_l.EventSStateOtherBase, astra_l.EventSStateBase, astra_l.EventNoLink:
			a.handleEvent(f.Interface())
		case astra_l.EParameterCode:
			if !a.fieldsInitialized {
				a.Observer.OnNewControl(a, wbgo.Control{
					Name:        fieldName,
					Type:        "alarm",
					Writability: wbgo.ForceReadOnly,
				})
				a.Observer.OnNewControl(a, wbgo.Control{
					Name:        fieldName + "_confirmed",
					Type:        "alarm",
					Writability: wbgo.ForceReadOnly,
				})
			}
			switch f.Interface().(astra_l.EParameterCode) {
			case astra_l.PcNorm:
				a.Observer.OnValue(a, fieldName, "0")
			case astra_l.PcFault:
				a.Observer.OnValue(a, fieldName, "1")
			case astra_l.PcNormConfirmed:
				a.Observer.OnValue(a, fieldName+"_confirmed", "0")
			case astra_l.PcFaultConfirmed:
				a.Observer.OnValue(a, fieldName+"_confirmed", "1")
			}
		case bool:
			if !a.fieldsInitialized {
				a.Observer.OnNewControl(a, wbgo.Control{
					Name:        fieldName,
					Type:        "alarm",
					Value:       "0",
					Writability: wbgo.ForceReadOnly,
				})
			}
			if f.Interface().(bool) {
				a.Observer.OnValue(a, fieldName, "1")
			} else {
				a.Observer.OnValue(a, fieldName, "0")
			}
		case int:
			if !a.fieldsInitialized {
				control := wbgo.Control{
					Name:        fieldName,
					Value:       "0",
					Writability: wbgo.ForceReadOnly,
				}
				if fieldName == "Temperature" {
					control.Type = "temperature"
				}
				a.Observer.OnNewControl(a, control)
			}
			a.Observer.OnValue(a, fieldName, strconv.Itoa(f.Interface().(int)))
		case uint8:
			if !a.fieldsInitialized {
				control := wbgo.Control{
					Name:        fieldName,
					Value:       "0",
					Writability: wbgo.ForceReadOnly,
				}
				if fieldName == "Power" || fieldName == "Smoke" {
					control.Units = "%"
				}
				a.Observer.OnNewControl(a, control)
			}
			a.Observer.OnValue(a, fieldName, strconv.Itoa(int(f.Interface().(uint8))))
		case astra_l.SensorInfo:
			// do nothing
		default:
			wbgo.Error.Printf("Received unexpected field type %T %+v\n", fi, f)
		}
	}
}

func (a *AstraDetector) Publish() {
	a.Observer.OnNewControl(a, wbgo.Control{
		Name:  "delete",
		Title: "Delete sensor",
		Type:  "switch",
		Value: "0",
	})
	a.Observer.OnNewControl(a, wbgo.Control{
		Name:        "sensor id",
		Title:       "Sensor Id",
		Value:       strconv.Itoa(int(a.sensorInfo.Id)),
		Writability: wbgo.ForceReadOnly,
	})
}
<commit_msg>fix panicing on unexported events` fields, for real this time<commit_after>package main

import (
	"reflect"
	"strconv"
	"time"

	"github.com/andrey-yantsen/teko-astra-go"
	"github.com/contactless/wbgo"
)

type AstraDetector struct {
	wbgo.DeviceBase
	sensorInfo        astra_l.SensorInfo
	astraAddress      uint16
	fieldsInitialized bool
	d                 *AstraDevice
}

func (a *AstraDetector) IsVirtual() bool {
	return false
}

func (a *AstraDetector) AcceptValue(name, value string) {
}

func (a *AstraDetector) AcceptOnValue(name, value string) bool {
	switch name {
	case "delete":
		if value == "1" {
			a.remove()
		}
	}
	return false
}

func (a *AstraDetector) remove() {
	a.d.device.DeleteLevel2Device(a.sensorInfo.Id)
	a.d.modelObserver.RemoveDevice(a)
}

func (a *AstraDetector) handleEvent(e interface{}) {
	wbgo.Debug.Printf("Inspecting %T %+v\n", e, e)
	a.Observer.OnValue(a, "Last event time", time.Now().Format(time.UnixDate))
	v := reflect.ValueOf(e)
	for i := 0; i < v.NumField(); i++ {
		f := v.Field(i)
		if !f.CanInterface() {
			continue
		}
		fieldName := v.Type().Field(i).Name
		switch fi := f.Interface().(type) {
		case astra_l.EventSStateOtherBase, astra_l.EventSStateBase, astra_l.EventNoLink:
			a.handleEvent(f.Interface())
		case astra_l.EParameterCode:
			if !a.fieldsInitialized {
				a.Observer.OnNewControl(a, wbgo.Control{
					Name:        fieldName,
					Type:        "alarm",
					Writability: wbgo.ForceReadOnly,
				})
				a.Observer.OnNewControl(a, wbgo.Control{
					Name:        fieldName + "_confirmed",
					Type:        "alarm",
					Writability: wbgo.ForceReadOnly,
				})
			}
			switch f.Interface().(astra_l.EParameterCode) {
			case astra_l.PcNorm:
				a.Observer.OnValue(a, fieldName, "0")
			case astra_l.PcFault:
				a.Observer.OnValue(a, fieldName, "1")
			case astra_l.PcNormConfirmed:
				a.Observer.OnValue(a, fieldName+"_confirmed", "0")
			case astra_l.PcFaultConfirmed:
				a.Observer.OnValue(a, fieldName+"_confirmed", "1")
			}
		case bool:
			if !a.fieldsInitialized {
				a.Observer.OnNewControl(a, wbgo.Control{
					Name:        fieldName,
					Type:        "alarm",
					Value:       "0",
					Writability: wbgo.ForceReadOnly,
				})
			}
			if f.Interface().(bool) {
				a.Observer.OnValue(a, fieldName, "1")
			} else {
				a.Observer.OnValue(a, fieldName, "0")
			}
		case int:
			if !a.fieldsInitialized {
				control := wbgo.Control{
					Name:        fieldName,
					Value:       "0",
					Writability: wbgo.ForceReadOnly,
				}
				if fieldName == "Temperature" {
					control.Type = "temperature"
				}
				a.Observer.OnNewControl(a, control)
			}
			a.Observer.OnValue(a, fieldName, strconv.Itoa(f.Interface().(int)))
		case uint8:
			if !a.fieldsInitialized {
				control := wbgo.Control{
					Name:        fieldName,
					Value:       "0",
					Writability: wbgo.ForceReadOnly,
				}
				if fieldName == "Power" || fieldName == "Smoke" {
					control.Units = "%"
				}
				a.Observer.OnNewControl(a, control)
			}
			a.Observer.OnValue(a, fieldName, strconv.Itoa(int(f.Interface().(uint8))))
		case astra_l.SensorInfo:
			// do nothing
		default:
			wbgo.Error.Printf("Received unexpected field type %T %+v\n", fi, f)
		}
	}
}

func (a *AstraDetector) Publish() {
	a.Observer.OnNewControl(a, wbgo.Control{
		Name:  "delete",
		Title: "Delete sensor",
		Type:  "switch",
		Value: "0",
	})
	a.Observer.OnNewControl(a, wbgo.Control{
		Name:        "sensor id",
		Title:       "Sensor Id",
		Value:       strconv.Itoa(int(a.sensorInfo.Id)),
		Writability: wbgo.ForceReadOnly,
	})
}
<|endoftext|>


<commit_before>package docker

import (
	"encoding/json"
	"net/http"
	"reflect"
	"testing"

	"github.com/docker/docker/api/types/registry"
)

func TestInspectDistribution(t *testing.T) {
	t.Parallel()
	jsonDistribution := `{
   "Descriptor": {
    "MediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "Digest": "sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96",
    "Size": 3987495,
    "URLs": [
      ""
    ]
  },
  "Platforms": [
    {
      "Architecture": "amd64",
      "OS": "linux",
      "OSVersion": "",
      "OSFeatures": [
        ""
      ],
      "Variant": "",
      "Features": [
        ""
      ]
    }
  ]
}`

	var expected registry.DistributionInspect
	err := json.Unmarshal([]byte(jsonDistribution), &expected)
	if err != nil {
		t.Fatal(err)
	}
	fakeRT := &FakeRoundTripper{message: jsonDistribution, status: http.StatusOK}
	client := newTestClient(fakeRT)
	// image name/tag is not present in the reply, so it can be omitted for testing purposes
	distributionInspect, err := client.InspectDistribution("")
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(*distributionInspect, expected) {
		t.Errorf("InspectDistribution(%q): Expected %#v. Got %#v.", "", expected, distributionInspect)
	}
}
<commit_msg>Add missing copyright banner<commit_after>// Copyright 2017 go-dockerclient 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 docker

import (
	"encoding/json"
	"net/http"
	"reflect"
	"testing"

	"github.com/docker/docker/api/types/registry"
)

func TestInspectDistribution(t *testing.T) {
	t.Parallel()
	jsonDistribution := `{
   "Descriptor": {
    "MediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "Digest": "sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96",
    "Size": 3987495,
    "URLs": [
      ""
    ]
  },
  "Platforms": [
    {
      "Architecture": "amd64",
      "OS": "linux",
      "OSVersion": "",
      "OSFeatures": [
        ""
      ],
      "Variant": "",
      "Features": [
        ""
      ]
    }
  ]
}`

	var expected registry.DistributionInspect
	err := json.Unmarshal([]byte(jsonDistribution), &expected)
	if err != nil {
		t.Fatal(err)
	}
	fakeRT := &FakeRoundTripper{message: jsonDistribution, status: http.StatusOK}
	client := newTestClient(fakeRT)
	// image name/tag is not present in the reply, so it can be omitted for testing purposes
	distributionInspect, err := client.InspectDistribution("")
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(*distributionInspect, expected) {
		t.Errorf("InspectDistribution(%q): Expected %#v. Got %#v.", "", expected, distributionInspect)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

func logHandler(next http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%v: %v %v", r.Method, r.URL.Path, r.PostFormValue("project"))
		next.ServeHTTP(w, r)
	}
}

func logHandlerFunc(next http.HandlerFunc) http.HandlerFunc {
	return logHandler(next)
}

type Project struct {
	Name, Path string
}
type Configuration struct {
	Projects []Project
}

type Payload struct {
	Repository struct {
		Name string
	}
}

var configuration = &Configuration{}
var port = flag.Int("port", 3000, "listen on port")

func main() {
	log.Println("Oompa Loompa warming up...")
	flag.Parse()
	file, _ := os.Open("conf.json")
	decoder := json.NewDecoder(file)
	decoder.Decode(&configuration)

	http.Handle("/deploy", logHandlerFunc(deploy))
	http.Handle("/", logHandlerFunc(home))

	portString := strconv.Itoa(*port)
	log.Println("Listening on port " + portString + "...")
	http.ListenAndServe(":"+portString, nil)
}

func home(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Oompa Loompa reporting for duty!"))
}

func projectIndex(t string, vs []Project) int {
	for i, v := range vs {
		if v.Name == t {
			return i
		}
	}
	return -1
}

func deploy(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		log.Println("Payload received.")

		payload := &Payload{}
		var decoder = json.NewDecoder(strings.NewReader(r.PostFormValue("payload")))
		decoder.Decode(&payload)

		index := projectIndex(payload.Repository.Name, configuration.Projects)
		if index < 0 {
			log.Println("Invalid payload.")
			return
		}

		log.Println("Deploying '" + configuration.Projects[index].Name + "'...")
		err := os.Chdir(configuration.Projects[index].Path)
		if err != nil {
			log.Println(err.Error())
			return
		}

		out, err := exec.Command("git", "pull").Output()
		if err != nil {
			log.Println(err.Error())
			return
		}

		log.Println(string(out[:]))
	}
}
<commit_msg>Check CLI flags before warm up message.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

func logHandler(next http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%v: %v %v", r.Method, r.URL.Path, r.PostFormValue("project"))
		next.ServeHTTP(w, r)
	}
}

func logHandlerFunc(next http.HandlerFunc) http.HandlerFunc {
	return logHandler(next)
}

type Project struct {
	Name, Path string
}
type Configuration struct {
	Projects []Project
}

type Payload struct {
	Repository struct {
		Name string
	}
}

var configuration = &Configuration{}
var port = flag.Int("port", 3000, "listen on port")

func main() {
	flag.Parse()
	log.Println("Oompa Loompa warming up...")
	file, _ := os.Open("conf.json")
	decoder := json.NewDecoder(file)
	decoder.Decode(&configuration)

	http.Handle("/deploy", logHandlerFunc(deploy))
	http.Handle("/", logHandlerFunc(home))

	portString := strconv.Itoa(*port)
	log.Println("Listening on port " + portString + "...")
	http.ListenAndServe(":"+portString, nil)
}

func home(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Oompa Loompa reporting for duty!"))
}

func projectIndex(t string, vs []Project) int {
	for i, v := range vs {
		if v.Name == t {
			return i
		}
	}
	return -1
}

func deploy(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		log.Println("Payload received.")

		payload := &Payload{}
		var decoder = json.NewDecoder(strings.NewReader(r.PostFormValue("payload")))
		decoder.Decode(&payload)

		index := projectIndex(payload.Repository.Name, configuration.Projects)

		if index < 0 {
			log.Println("Invalid payload.")
			return
		}

		log.Println("Deploying '" + configuration.Projects[index].Name + "'...")
		err := os.Chdir(configuration.Projects[index].Path)
		if err != nil {
			log.Println(err.Error())
			return
		}

		out, err := exec.Command("git", "pull").Output()
		if err != nil {
			log.Println(err.Error())
			return
		}

		log.Println(string(out[:]))
	}
}
<|endoftext|>


<commit_before>package countmin

import (
	"errors"
	"hash/fnv"
	"math"
)

// Max int 64 size
const MAXINT64 = 1<<63 - 1

// CountMin holds count table for calculating
// frequencies from a given input (usually a stream of data)
type CountMin struct {
	depth      int
	width      int
	size       int64
	eps        float64
	confidence float64
	table      [][]int64
}

// New CountMin given a depth and width of the frequency
// table to use. Returns the newly created CountMin
func New(depth, width int) *CountMin {
	cm := &CountMin{
		depth:      depth,
		width:      width,
		eps:        2.0 / float64(width),
		confidence: 1.0 - 1.0/math.Pow(2, float64(depth)),
	}
	cm.initTable()
	return cm
}

// NewWithEpsCount initializes a CountMin given a confidence
// to ensure between 0 < 1.0 which effects number of hashes used
// and an epsilon between 0 and 1 with a smaller value for
// higher precision as it affects the width of the table
func NewWithEpsCount(confidence, eps float64) *CountMin {
	if confidence >= 1.0 {
		confidence = 0.99999
	}
	cm := &CountMin{
		eps:        eps,
		confidence: confidence,
		width:      int(math.Ceil(float64(2.0) / eps)),
		depth:      int(math.Ceil(-math.Log(1-confidence) / math.Log(2))),
	}
	cm.initTable()
	return cm
}

func (cm *CountMin) initTable() {
	cm.table = make([][]int64, cm.depth)
	for i := range cm.table {
		cm.table[i] = make([]int64, cm.width)
	}
}

// RelativeError returns epsilon of CountMin
func (cm *CountMin) RelativeError() float64 {
	return cm.eps
}

// Confidence returns confidence of CountMin
func (cm *CountMin) Confidence() float64 {
	return cm.confidence
}

// Size returns total size of CountMin
func (cm *CountMin) Size() int64 {
	return cm.size
}

// Add inserts an item in bytes and a count associated
// which will also increment size of CountMin
func (cm *CountMin) Add(item []byte, count int64) {
	if count < 0 {
		return
	}
	hashed := cm.hasher(item)
	for i := 0; i < cm.depth; i++ {
		cm.table[i][hashed[i]] += count
	}
	cm.size += count
}

// Count gets an associated total count for an item
// in the CountMin
func (cm *CountMin) Count(item []byte) int64 {
	var answer int64 = MAXINT64
	var val int64
	hashed := cm.hasher(item)
	for i := 0; i < cm.depth; i++ {
		val = cm.table[i][hashed[i]]
		if val < answer {
			answer = val
		}
	}
	return answer
}

// Merge two CountMin tables and return a new table of their union
func Merge(cm1, cm2 *CountMin) (*CountMin, error) {
	if cm1.depth != cm2.depth {
		return nil, errors.New("Depth does not match for merging")
	}
	if cm1.width != cm2.width {
		return nil, errors.New("Width does not match for merging")
	}
	newCm := New(cm1.depth, cm2.width)
	var val int64
	for i := 0; i < newCm.depth; i++ {
		for j := 0; j < newCm.width; j++ {
			val = cm1.table[i][j] + cm2.table[i][j]
			newCm.table[i][j] = val
		}
	}
	newCm.size = cm1.size + cm2.size
	return newCm, nil
}

func (cm *CountMin) hasher(item []byte) []int64 {
	total := cm.depth
	max := int64(cm.width)
	result := make([]int64, total)
	hash := fnv.New32a()
	hash.Write(item)
	sum := int64(hash.Sum32())
	for i := 0; i < total; i++ {
		result[i] = int64(math.Abs(float64((sum * int64(i)) % max)))
	}
	return result
}
<commit_msg>Fix golint issue with constant comment<commit_after>package countmin

import (
	"errors"
	"hash/fnv"
	"math"
)

// MAXINT64 is max 64 bit integer size
const MAXINT64 = 1<<63 - 1

// CountMin holds count table for calculating
// frequencies from a given input (usually a stream of data)
type CountMin struct {
	depth      int
	width      int
	size       int64
	eps        float64
	confidence float64
	table      [][]int64
}

// New CountMin given a depth and width of the frequency
// table to use. Returns the newly created CountMin
func New(depth, width int) *CountMin {
	cm := &CountMin{
		depth:      depth,
		width:      width,
		eps:        2.0 / float64(width),
		confidence: 1.0 - 1.0/math.Pow(2, float64(depth)),
	}
	cm.initTable()
	return cm
}

// NewWithEpsCount initializes a CountMin given a confidence
// to ensure between 0 < 1.0 which effects number of hashes used
// and an epsilon between 0 and 1 with a smaller value for
// higher precision as it affects the width of the table
func NewWithEpsCount(confidence, eps float64) *CountMin {
	if confidence >= 1.0 {
		confidence = 0.99999
	}
	cm := &CountMin{
		eps:        eps,
		confidence: confidence,
		width:      int(math.Ceil(float64(2.0) / eps)),
		depth:      int(math.Ceil(-math.Log(1-confidence) / math.Log(2))),
	}
	cm.initTable()
	return cm
}

func (cm *CountMin) initTable() {
	cm.table = make([][]int64, cm.depth)
	for i := range cm.table {
		cm.table[i] = make([]int64, cm.width)
	}
}

// RelativeError returns epsilon of CountMin
func (cm *CountMin) RelativeError() float64 {
	return cm.eps
}

// Confidence returns confidence of CountMin
func (cm *CountMin) Confidence() float64 {
	return cm.confidence
}

// Size returns total size of CountMin
func (cm *CountMin) Size() int64 {
	return cm.size
}

// Add inserts an item in bytes and a count associated
// which will also increment size of CountMin
func (cm *CountMin) Add(item []byte, count int64) {
	if count < 0 {
		return
	}
	hashed := cm.hasher(item)
	for i := 0; i < cm.depth; i++ {
		cm.table[i][hashed[i]] += count
	}
	cm.size += count
}

// Count gets an associated total count for an item
// in the CountMin
func (cm *CountMin) Count(item []byte) int64 {
	var answer int64 = MAXINT64
	var val int64
	hashed := cm.hasher(item)
	for i := 0; i < cm.depth; i++ {
		val = cm.table[i][hashed[i]]
		if val < answer {
			answer = val
		}
	}
	return answer
}

// Merge two CountMin tables and return a new table of their union
func Merge(cm1, cm2 *CountMin) (*CountMin, error) {
	if cm1.depth != cm2.depth {
		return nil, errors.New("Depth does not match for merging")
	}
	if cm1.width != cm2.width {
		return nil, errors.New("Width does not match for merging")
	}
	newCm := New(cm1.depth, cm2.width)
	var val int64
	for i := 0; i < newCm.depth; i++ {
		for j := 0; j < newCm.width; j++ {
			val = cm1.table[i][j] + cm2.table[i][j]
			newCm.table[i][j] = val
		}
	}
	newCm.size = cm1.size + cm2.size
	return newCm, nil
}

func (cm *CountMin) hasher(item []byte) []int64 {
	total := cm.depth
	max := int64(cm.width)
	result := make([]int64, total)
	hash := fnv.New32a()
	hash.Write(item)
	sum := int64(hash.Sum32())
	for i := 0; i < total; i++ {
		result[i] = int64(math.Abs(float64((sum * int64(i)) % max)))
	}
	return result
}
<|endoftext|>


<commit_before>package astrolabe

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/go-martini/martini"
)

// This function acts as a setup for other tests.
func setup() *httptest.ResponseRecorder {
	m := martini.Classic()
	m.Use(ExposeEndpoint(m.Router))

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/martini/routes", nil)

	m.ServeHTTP(res, req)

	return res
}

// Test that /martini/routes endpoint is accessible and the content-type is set to text/html.
func TestExposeEndpoint(t *testing.T) {
	res := setup()

	if res.Code != 200 {
		t.Error("Response is not 200.")
	}

	if res.HeaderMap.Get("Content-Type") != "text/html" {
		t.Error("Expecting the Content-Type to be text/html.")
	}
}

// This function is used as a setup but with a route defined.
func setupWithRoute(method string, handler martini.Handler) *httptest.ResponseRecorder {
	m := martini.Classic()

	switch method {
	case "GET":
		m.Get("/posts", handler)
	case "POST":
		m.Post("/posts", handler)
	case "PUT":
		m.Put("/posts/:id", handler)
	case "PATCH":
		m.Patch("/posts/:id", handler)
	case "OPTIONS":
		m.Options("/posts", handler)
	case "HEAD":
		m.Head("/posts", handler)
	case "DELETE":
		m.Delete("/posts/:id", handler)
	}

	m.Use(ExposeEndpoint(m.Router))

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/martini/routes", nil)

	m.ServeHTTP(res, req)

	return res
}

// This checks the endpoint is not exposed when the MARTINI.ENV is anything other than development.
func TestNotExposedIfNotInDevelopment(t *testing.T) {
	res := setup()

	// Check that we are not in development.
	if martini.Env != martini.Dev {
		if res.Code != http.StatusNotFound {
			t.Error("/martini/routes endpoint should not be exposed when environment is not development.")
		}
	}
}

// Test GET routes are displayed.
func TestGetRoute(t *testing.T) {
	res := setupWithRoute("GET", func(w http.ResponseWriter, r *http.Request) string {
		return "a GET route"
	})

	if !strings.Contains(res.Body.String(), "GET") {
		t.Error("The GET route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test POST routes are displayed.
func TestPostRoute(t *testing.T) {
	res := setupWithRoute("POST", func(w http.ResponseWriter, r *http.Request) string {
		return "a POST route"
	})

	if !strings.Contains(res.Body.String(), "POST") {
		t.Error("The POST route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test PUT routes are displayed.
func TestPutRoute(t *testing.T) {
	res := setupWithRoute("PUT", func(w http.ResponseWriter, r *http.Request) string {
		return "a PUT route"
	})

	if !strings.Contains(res.Body.String(), "PUT") {
		t.Error("The PUT route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts/:id") {
		t.Error("The route path should be displayed.")
	}
}

// Test PATCH routes are displayed.
func TestPatchRoute(t *testing.T) {
	res := setupWithRoute("PATCH", func(w http.ResponseWriter, r *http.Request) string {
		return "a PATCH route"
	})

	if !strings.Contains(res.Body.String(), "PATCH") {
		t.Error("The PATCH route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts/:id") {
		t.Error("The route path should be displayed.")
	}
}

// Test OPTIONS routes are displayed.
func TestOptionsRoute(t *testing.T) {
	res := setupWithRoute("OPTIONS", func(w http.ResponseWriter, r *http.Request) string {
		return "an OPTIONS route"
	})

	if !strings.Contains(res.Body.String(), "OPTIONS") {
		t.Error("The OPTIONS route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test HEAD routes are displayed.
func TestHeadRoute(t *testing.T) {
	res := setupWithRoute("HEAD", func(w http.ResponseWriter, r *http.Request) string {
		return "a HEAD route"
	})

	if !strings.Contains(res.Body.String(), "HEAD") {
		t.Error("The HEAD route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}
<commit_msg>Test DELETE routes are displayed<commit_after>package astrolabe

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/go-martini/martini"
)

// This function acts as a setup for other tests.
func setup() *httptest.ResponseRecorder {
	m := martini.Classic()
	m.Use(ExposeEndpoint(m.Router))

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/martini/routes", nil)

	m.ServeHTTP(res, req)

	return res
}

// Test that /martini/routes endpoint is accessible and the content-type is set to text/html.
func TestExposeEndpoint(t *testing.T) {
	res := setup()

	if res.Code != 200 {
		t.Error("Response is not 200.")
	}

	if res.HeaderMap.Get("Content-Type") != "text/html" {
		t.Error("Expecting the Content-Type to be text/html.")
	}
}

// This function is used as a setup but with a route defined.
func setupWithRoute(method string, handler martini.Handler) *httptest.ResponseRecorder {
	m := martini.Classic()

	switch method {
	case "GET":
		m.Get("/posts", handler)
	case "POST":
		m.Post("/posts", handler)
	case "PUT":
		m.Put("/posts/:id", handler)
	case "PATCH":
		m.Patch("/posts/:id", handler)
	case "OPTIONS":
		m.Options("/posts", handler)
	case "HEAD":
		m.Head("/posts", handler)
	case "DELETE":
		m.Delete("/posts/:id", handler)
	}

	m.Use(ExposeEndpoint(m.Router))

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/martini/routes", nil)

	m.ServeHTTP(res, req)

	return res
}

// This checks the endpoint is not exposed when the MARTINI.ENV is anything other than development.
func TestNotExposedIfNotInDevelopment(t *testing.T) {
	res := setup()

	// Check that we are not in development.
	if martini.Env != martini.Dev {
		if res.Code != http.StatusNotFound {
			t.Error("/martini/routes endpoint should not be exposed when environment is not development.")
		}
	}
}

// Test GET routes are displayed.
func TestGetRoute(t *testing.T) {
	res := setupWithRoute("GET", func(w http.ResponseWriter, r *http.Request) string {
		return "a GET route"
	})

	if !strings.Contains(res.Body.String(), "GET") {
		t.Error("The GET route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test POST routes are displayed.
func TestPostRoute(t *testing.T) {
	res := setupWithRoute("POST", func(w http.ResponseWriter, r *http.Request) string {
		return "a POST route"
	})

	if !strings.Contains(res.Body.String(), "POST") {
		t.Error("The POST route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test PUT routes are displayed.
func TestPutRoute(t *testing.T) {
	res := setupWithRoute("PUT", func(w http.ResponseWriter, r *http.Request) string {
		return "a PUT route"
	})

	if !strings.Contains(res.Body.String(), "PUT") {
		t.Error("The PUT route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts/:id") {
		t.Error("The route path should be displayed.")
	}
}

// Test PATCH routes are displayed.
func TestPatchRoute(t *testing.T) {
	res := setupWithRoute("PATCH", func(w http.ResponseWriter, r *http.Request) string {
		return "a PATCH route"
	})

	if !strings.Contains(res.Body.String(), "PATCH") {
		t.Error("The PATCH route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts/:id") {
		t.Error("The route path should be displayed.")
	}
}

// Test OPTIONS routes are displayed.
func TestOptionsRoute(t *testing.T) {
	res := setupWithRoute("OPTIONS", func(w http.ResponseWriter, r *http.Request) string {
		return "an OPTIONS route"
	})

	if !strings.Contains(res.Body.String(), "OPTIONS") {
		t.Error("The OPTIONS route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test HEAD routes are displayed.
func TestHeadRoute(t *testing.T) {
	res := setupWithRoute("HEAD", func(w http.ResponseWriter, r *http.Request) string {
		return "a HEAD route"
	})

	if !strings.Contains(res.Body.String(), "HEAD") {
		t.Error("The HEAD route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}

// Test DELETE routes are displayed.
func TestDeleteRoute(t *testing.T) {
	res := setupWithRoute("DELETE", func(w http.ResponseWriter, r *http.Request) string {
		return "a DELETE route"
	})

	if !strings.Contains(res.Body.String(), "DELETE") {
		t.Error("The DELETE route should be displayed.")
	}

	if !strings.Contains(res.Body.String(), "/posts") {
		t.Error("The route path should be displayed.")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"
)

type courseData struct {
	CourseTitle string
	HostAndPort string
	CourseCode  string
}

func arbitraryChatPageHandler(w http.ResponseWriter, r *http.Request) {
	// Get the segments out of the URL path
	// e.g. www.example.com/one/two --> we want "one", "two"
	// But I think Go gives us, as a URL, /one/two
	// which means that we actually get "", "one", "two": we get the empty string
	// So let's assert the length is three, not two
	// Because we want www.example.com/course/COURSECODE
	urlPathSegments := strings.Split(r.URL.Path, "/")
	if len(urlPathSegments) != 3 {
		// If they are at /course/coursecode/x, then we don't know what they want, so give a 404
		http.Error(w, http.StatusText(404), 404)
		return
	}
	courseCode := urlPathSegments[2]
	tmpl := template.Must(template.ParseFiles("templates/course_page.html"))

	cData := courseData{CourseTitle: "Databases", HostAndPort: r.Host, CourseCode: courseCode}
	tmpl.Execute(w, cData)

}

func indexPageHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "We are on index page")
}
<commit_msg>Remove old index page<commit_after>package main

import (
	"html/template"
	"net/http"
	"strings"
)

type courseData struct {
	CourseTitle string
	HostAndPort string
	CourseCode  string
}

func arbitraryChatPageHandler(w http.ResponseWriter, r *http.Request) {
	// Get the segments out of the URL path
	// e.g. www.example.com/one/two --> we want "one", "two"
	// But I think Go gives us, as a URL, /one/two
	// which means that we actually get "", "one", "two": we get the empty string
	// So let's assert the length is three, not two
	// Because we want www.example.com/course/COURSECODE
	urlPathSegments := strings.Split(r.URL.Path, "/")
	if len(urlPathSegments) != 3 {
		// If they are at /course/coursecode/x, then we don't know what they want, so give a 404
		http.Error(w, http.StatusText(404), 404)
		return
	}
	courseCode := urlPathSegments[2]
	tmpl := template.Must(template.ParseFiles("templates/course_page.html"))

	cData := courseData{CourseTitle: "Databases", HostAndPort: r.Host, CourseCode: courseCode}
	tmpl.Execute(w, cData)

}
<|endoftext|>


<commit_before>package main

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * cqlstore.go: a quick & dirty Cassandra CQL backend for Gorilla sessions
 *
 * This implementation is specific to this application.
 *
 */

import (
	"errors"
	"github.com/gocql/gocql"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"log"
	"net/http"
	"time"
)

type CQLStore struct {
	Cass    *gocql.Session       // connected gocql cassandra session
	Codecs  []securecookie.Codec // session codecs
	Options *sessions.Options    // default configuration
}

func NewCQLStore(cass *gocql.Session, keyPairs ...[]byte) *CQLStore {
	return &CQLStore{
		Cass:   cass,
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
	}
}

func (cs *CQLStore) Get(r *http.Request, name string) (*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(cs, name)
}

func (cs *CQLStore) New(r *http.Request, name string) (sess *sessions.Session, err error) {
	sess = sessions.NewSession(cs, name)
	sess.IsNew = true
	opts := *cs.Options // make a copy
	sess.Options = &opts
	sess.Values["email"] = "" // important: this must always be a string or panics ensue

	// load the session ID from the cookie (if it exists)
	c, err := r.Cookie(name)
	if err == nil {
		err = securecookie.DecodeMulti(name, c.Value, &sess.ID, cs.Codecs...)
		if err != nil {
			log.Printf("cqlstore: Cookie decode failed: %s\n", err)
			return
		}

		if cs.load(sess) == nil {
			log.Printf("Got a valid session ID from cookie: '%s'\n", sess.ID)
			sess.IsNew = false // existing session OK
		} else {
			log.Printf("Invalid session ID from cookie: '%s'\n", sess.ID)
			sess.ID = "" // invalid session ID, clear it
		}
	} else {
		log.Printf("No cookie found with name '%s'.\n", name)
	}

	// no cookie or ID found, generate an ID for a new session
	if sess.ID == "" {
		var uuid gocql.UUID
		uuid, err = gocql.RandomUUID()
		if err != nil {
			log.Printf("cqlstore: failed to generate a new UUID: %s\n", err)
			return
		}
		sess.ID = uuid.String()
	}

	return
}

func (cs *CQLStore) Save(r *http.Request, w http.ResponseWriter, sess *sessions.Session) (err error) {
	err = cs.save(sess)
	if err != nil {
		log.Printf("cqlstore: Failed to save session to Cassandra: %s\n", err)
		return err
	}

	blob, err := securecookie.EncodeMulti(sess.Name(), sess.ID, cs.Codecs...)
	if err != nil {
		log.Printf("cqlstore: Failed to encode session: %s\n", err)
		return err
	}
	http.SetCookie(w, sessions.NewCookie(sess.Name(), blob, sess.Options))

	return nil
}

func (cs *CQLStore) Delete(r *http.Request, w http.ResponseWriter, sess *sessions.Session) (err error) {
	// overwrite the cookie with a negative max age so the browser expires it immediately
	opts := *sess.Options
	opts.MaxAge = -1
	http.SetCookie(w, sessions.NewCookie(sess.Name(), "", &opts))

	// delete the session from the DB
	err = cs.Cass.Query(`DELETE FROM sessions WHERE id=?`, sess.ID).Exec()
	return
}

// load session data from Cassandra
func (cs *CQLStore) load(sess *sessions.Session) (err error) {
	var email string
	var created, modified time.Time
	query := `SELECT email, created, modified FROM sessions WHERE id=?`
	iq := cs.Cass.Query(query, sess.ID).Iter()
	ok := iq.Scan(&email, &created, &modified)
	if ok {
		// expose the created/modified times through the session values
		sess.Values["created"] = created
		sess.Values["modified"] = modified
		sess.Values["email"] = email
		sess.IsNew = false
		return
	} else {
		log.Printf("cqlstore: CQL query for session ID '%s' failed.\n", sess.ID)
		return errors.New("CQL query failed.")
	}
	return
}

func (cs *CQLStore) save(sess *sessions.Session) (err error) {
	now := time.Now()
	email := sess.Values["email"].(string)

	if sess.IsNew {
		query := `INSERT INTO sessions (id, email, created, modified) VALUES (?, ?, ?, ?)`
		err = cs.Cass.Query(query, sess.ID, email, now, now).Exec()
	} else {
		query := `UPDATE sessions SET email=?, modified=? WHERE id=?`
		err = cs.Cass.Query(query, email, now, sess.ID).Exec()
	}
	return
}
<commit_msg>quiet down<commit_after>package main

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * cqlstore.go: a quick & dirty Cassandra CQL backend for Gorilla sessions
 *
 * This implementation is specific to this application.
 *
 */

import (
	"errors"
	"github.com/gocql/gocql"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"log"
	"net/http"
	"time"
)

type CQLStore struct {
	Cass    *gocql.Session       // connected gocql cassandra session
	Codecs  []securecookie.Codec // session codecs
	Options *sessions.Options    // default configuration
}

func NewCQLStore(cass *gocql.Session, keyPairs ...[]byte) *CQLStore {
	return &CQLStore{
		Cass:   cass,
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
	}
}

func (cs *CQLStore) Get(r *http.Request, name string) (*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(cs, name)
}

func (cs *CQLStore) New(r *http.Request, name string) (sess *sessions.Session, err error) {
	sess = sessions.NewSession(cs, name)
	sess.IsNew = true
	opts := *cs.Options // make a copy
	sess.Options = &opts
	sess.Values["email"] = "" // important: this must always be a string or panics ensue

	// load the session ID from the cookie (if it exists)
	c, err := r.Cookie(name)
	if err == nil {
		err = securecookie.DecodeMulti(name, c.Value, &sess.ID, cs.Codecs...)
		if err != nil {
			log.Printf("cqlstore: Cookie decode failed: %s\n", err)
			return
		}

		if cs.load(sess) == nil {
			//log.Printf("Got a valid session ID from cookie: '%s'\n", sess.ID)
			sess.IsNew = false // existing session OK
		} else {
			log.Printf("Invalid session ID from cookie: '%s'\n", sess.ID)
			sess.ID = "" // invalid session ID, clear it
		}
	} else {
		log.Printf("No cookie found with name '%s'.\n", name)
	}

	// no cookie or ID found, generate an ID for a new session
	if sess.ID == "" {
		var uuid gocql.UUID
		uuid, err = gocql.RandomUUID()
		if err != nil {
			log.Printf("cqlstore: failed to generate a new UUID: %s\n", err)
			return
		}
		sess.ID = uuid.String()
	}

	return
}

func (cs *CQLStore) Save(r *http.Request, w http.ResponseWriter, sess *sessions.Session) (err error) {
	err = cs.save(sess)
	if err != nil {
		log.Printf("cqlstore: Failed to save session to Cassandra: %s\n", err)
		return err
	}

	blob, err := securecookie.EncodeMulti(sess.Name(), sess.ID, cs.Codecs...)
	if err != nil {
		log.Printf("cqlstore: Failed to encode session: %s\n", err)
		return err
	}
	http.SetCookie(w, sessions.NewCookie(sess.Name(), blob, sess.Options))

	return nil
}

func (cs *CQLStore) Delete(r *http.Request, w http.ResponseWriter, sess *sessions.Session) (err error) {
	// overwrite the cookie with a negative max age so the browser expires it immediately
	opts := *sess.Options
	opts.MaxAge = -1
	http.SetCookie(w, sessions.NewCookie(sess.Name(), "", &opts))

	// delete the session from the DB
	err = cs.Cass.Query(`DELETE FROM sessions WHERE id=?`, sess.ID).Exec()
	return
}

// load session data from Cassandra
func (cs *CQLStore) load(sess *sessions.Session) (err error) {
	var email string
	var created, modified time.Time
	query := `SELECT email, created, modified FROM sessions WHERE id=?`
	iq := cs.Cass.Query(query, sess.ID).Iter()
	ok := iq.Scan(&email, &created, &modified)
	if ok {
		// expose the created/modified times through the session values
		sess.Values["created"] = created
		sess.Values["modified"] = modified
		sess.Values["email"] = email
		sess.IsNew = false
		return
	} else {
		log.Printf("cqlstore: CQL query for session ID '%s' failed.\n", sess.ID)
		return errors.New("CQL query failed.")
	}
	return
}

func (cs *CQLStore) save(sess *sessions.Session) (err error) {
	now := time.Now()
	email := sess.Values["email"].(string)

	if sess.IsNew {
		query := `INSERT INTO sessions (id, email, created, modified) VALUES (?, ?, ?, ?)`
		err = cs.Cass.Query(query, sess.ID, email, now, now).Exec()
	} else {
		query := `UPDATE sessions SET email=?, modified=? WHERE id=?`
		err = cs.Cass.Query(query, email, now, sess.ID).Exec()
	}
	return
}
<|endoftext|>