<commit_before>package startCmd

import (
	// Stdlib
	"fmt"
	"os"

	// Internal
	"github.com/salsaflow/salsaflow/action"
	"github.com/salsaflow/salsaflow/app"
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules"
	"github.com/salsaflow/salsaflow/version"

	// Vendor
	"gopkg.in/tchap/gocli.v2"
)

var Command = &gocli.Command{
	UsageLine: `
  start [-no_fetch] [-next_trunk_version=VERSION]`,
	Short: "start a new release",
	Long: `
  Start a new release, i.e. create the release branch,
  bump the next version number into the trunk branch
  and make the relevant changes in the issue tracker.

  The release branch is always created on top of the trunk branch,
  the issue tracker actions carried out depend on the plugin being used.

  Considering version numbers, the new release branch inherits
  the version that was on the trunk branch. Then a new version is bumped
  into the trunk branch. By default the new version is taken from
  the previous one by auto-incrementing the minor version.
  However, -next_trunk_version can be used to overwrite this behaviour.
	`,
	Action: run,
}

var (
	flagNextTrunk version.Version
	flagNoFetch   bool
)

func init() {
	Command.Flags.Var(&flagNextTrunk, "next_trunk_version", "the next trunk version string")
	Command.Flags.BoolVar(&flagNoFetch, "no_fetch", flagNoFetch, "do not fetch the remote")
}

func run(cmd *gocli.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		os.Exit(2)
	}

	app.InitOrDie()

	if err := runMain(); err != nil {
		errs.Fatal(err)
	}
}

func runMain() (err error) {
	// Load repo config.
	gitConfig, err := git.LoadConfig()
	if err != nil {
		return err
	}
	var (
		remote        = gitConfig.RemoteName()
		trunkBranch   = gitConfig.TrunkBranchName()
		releaseBranch = gitConfig.ReleaseBranchName()
	)

	// Fetch the remote repository.
	if !flagNoFetch {
		task := "Fetch the remote repository"
		log.Run(task)
		if err := git.UpdateRemotes(remote); err != nil {
			return errs.NewError(task, err, nil)
		}
	}

	// Make sure that the trunk branch is up to date.
	task := fmt.Sprintf("Make sure that branch '%v' is up to date", trunkBranch)
	if err := git.EnsureBranchSynchronized(trunkBranch, remote); err != nil {
		return errs.NewError(task, err, nil)
	}

	// Make sure that the release branch does not exist.
	task = fmt.Sprintf("Make sure that branch '%v' does not exist", releaseBranch)
	if err := git.EnsureBranchNotExist(releaseBranch, remote); err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the current trunk version string.
	task = "Get the current trunk version string"
	trunkVersion, err := version.GetByBranch(trunkBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the next trunk version (the future release version).
	var nextTrunkVersion *version.Version
	if !flagNextTrunk.Zero() {
		// Make sure the new version is actually incrementing the current one.
		var (
			current = trunkVersion
			next    = flagNextTrunk
		)
		if current.GE(next.Version) {
			return fmt.Errorf("future version string not an increment: %v <= %v", next, current)
		}

		nextTrunkVersion = &flagNextTrunk
	} else {
		nextTrunkVersion = trunkVersion.IncrementMinor()
	}

	// Fetch the stories from the issue tracker.
	tracker, err := modules.GetIssueTracker()
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	release, err := tracker.NextRelease(trunkVersion, nextTrunkVersion)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Prompt the user to confirm the release.
	fmt.Printf(`
You are about to start a new release branch.
The relevant version strings are:

  current release (current trunk version): %v
  future release (next trunk version):     %v

`, trunkVersion, nextTrunkVersion)
	ok, err := release.PromptUserToConfirmStart()
	if err != nil {
		return err
	}
	if !ok {
		fmt.Println("\nYour wish is my command, exiting now!")
		return nil
	}
	fmt.Println()

	// Create the release branch on top of the trunk branch.
	task = fmt.Sprintf("Create branch '%v' on top of branch '%v'", releaseBranch, trunkBranch)
	log.Run(task)
	if err := git.Branch(releaseBranch, trunkBranch); err != nil {
		return errs.NewError(task, err, nil)
	}
	defer action.RollbackTaskOnError(&err, task, action.ActionFunc(func() error {
		task := "Delete the release branch"
		if err := git.Branch("-d", releaseBranch); err != nil {
			errs.NewError(task, err, nil)
		}
		return nil
	}))

	// Commit the next version string into the trunk branch.
	task = fmt.Sprintf(
		"Bump version for the future release (branch '%v' -> %v)", trunkBranch, nextTrunkVersion)
	act, err := version.SetForBranch(nextTrunkVersion, trunkBranch)
	if err != nil {
		return err
	}
	defer action.RollbackTaskOnError(&err, task, act)

	// Initialise the next release in the code review tool.
	codeReviewTool, err := modules.GetCodeReviewTool()
	if err != nil {
		return err
	}
	act, err = codeReviewTool.InitialiseRelease(nextTrunkVersion)
	if err != nil {
		return err
	}
	defer action.RollbackTaskOnError(&err, task, act)

	// Start the release in the issue tracker.
	act, err = release.Start()
	if err != nil {
		return err
	}
	defer action.RollbackTaskOnError(&err, task, act)

	// Push the modified branches.
	task = "Push the affected git branches"
	log.Run(task)
	err = git.Push(remote, trunkBranch+":"+trunkBranch, releaseBranch+":"+releaseBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	return nil
}
<commit_msg>release start: Update the release workflow<commit_after>package startCmd

import (
	// Stdlib
	"fmt"
	"os"

	// Internal
	"github.com/salsaflow/salsaflow/action"
	"github.com/salsaflow/salsaflow/app"
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules"
	"github.com/salsaflow/salsaflow/version"

	// Vendor
	"gopkg.in/tchap/gocli.v2"
)

var Command = &gocli.Command{
	UsageLine: `
  start [-no_fetch] [-next_trunk_version=VERSION]`,
	Short: "start a new release",
	Long: `
  Start a new release, i.e. create the release branch,
  bump the next version number into the trunk branch
  and make the relevant changes in the issue tracker.

  The release branch is always created on top of the trunk branch,
  the issue tracker actions carried out depend on the plugin being used.

  Considering version numbers, the new release branch inherits
  the version that was on the trunk branch. Then a new version is bumped
  into the trunk branch. By default the new version is taken from
  the previous one by auto-incrementing the minor version.
  However, -next_trunk_version can be used to overwrite this behaviour.
	`,
	Action: run,
}

var (
	flagNextTrunk version.Version
	flagNoFetch   bool
)

func init() {
	Command.Flags.Var(&flagNextTrunk, "next_trunk_version", "the next trunk version string")
	Command.Flags.BoolVar(&flagNoFetch, "no_fetch", flagNoFetch, "do not fetch the remote")
}

func run(cmd *gocli.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		os.Exit(2)
	}

	app.InitOrDie()

	if err := runMain(); err != nil {
		errs.Fatal(err)
	}
}

func runMain() (err error) {
	// Load repo config.
	gitConfig, err := git.LoadConfig()
	if err != nil {
		return err
	}
	var (
		remote        = gitConfig.RemoteName()
		trunkBranch   = gitConfig.TrunkBranchName()
		releaseBranch = gitConfig.ReleaseBranchName()
	)

	// Fetch the remote repository.
	if !flagNoFetch {
		task := "Fetch the remote repository"
		log.Run(task)
		if err := git.UpdateRemotes(remote); err != nil {
			return errs.NewError(task, err, nil)
		}
	}

	// Make sure that the trunk branch is up to date.
	task := fmt.Sprintf("Make sure that branch '%v' is up to date", trunkBranch)
	if err := git.EnsureBranchSynchronized(trunkBranch, remote); err != nil {
		return errs.NewError(task, err, nil)
	}

	// Make sure that the release branch does not exist.
	task = fmt.Sprintf("Make sure that branch '%v' does not exist", releaseBranch)
	if err := git.EnsureBranchNotExist(releaseBranch, remote); err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the current trunk version string.
	task = "Get the current trunk version string"
	trunkVersion, err := version.GetByBranch(trunkBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the next trunk version (the future release version).
	var nextTrunkVersion *version.Version
	if !flagNextTrunk.Zero() {
		// Make sure it's only major, minor and patch that are set.
		// Make sure the new version is actually incrementing the current one.
		var (
			current = trunkVersion
			next    = flagNextTrunk
		)

		var part string
		switch {
		case len(next.Pre) != 0:
			part = "Pre"
		case len(next.Build) != 0:
			part = "Build"
		}
		if part != "" {
			return fmt.Errorf("invalid future version string: %v version part cannot be set", part)
		}

		if current.GE(next.Version) {
			return fmt.Errorf("future version string not an increment: %v <= %v", next, current)
		}

		nextTrunkVersion = &flagNextTrunk
	} else {
		nextTrunkVersion = trunkVersion.IncrementMinor()
	}

	// Make sure the next trunk version has the right format.
	nextTrunkVersion, err = nextTrunkVersion.ToTrunkVersion()
	if err != nil {
		return err
	}

	// Fetch the stories from the issue tracker.
	tracker, err := modules.GetIssueTracker()
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	release, err := tracker.NextRelease(trunkVersion, nextTrunkVersion)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Prompt the user to confirm the release.
	fmt.Printf(`
You are about to start a new release branch.
The relevant version strings are:

  current release (current trunk version): %v
  future release (next trunk version):     %v

`, trunkVersion, nextTrunkVersion)
	ok, err := release.PromptUserToConfirmStart()
	if err != nil {
		return err
	}
	if !ok {
		fmt.Println("\nYour wish is my command, exiting now!")
		return nil
	}
	fmt.Println()

	// Create the release branch on top of the trunk branch.
	task = fmt.Sprintf("Create branch '%v' on top of branch '%v'", releaseBranch, trunkBranch)
	log.Run(task)
	if err := git.Branch(releaseBranch, trunkBranch); err != nil {
		return errs.NewError(task, err, nil)
	}
	defer action.RollbackTaskOnError(&err, task, action.ActionFunc(func() error {
		task := "Delete the release branch"
		if err := git.Branch("-d", releaseBranch); err != nil {
			errs.NewError(task, err, nil)
		}
		return nil
	}))

	// Bump the release branch version.
	testingVersion, err := trunkVersion.ToTestingVersion()
	if err != nil {
		return err
	}

	task = fmt.Sprintf("Bump version (branch '%v' -> %v)", releaseBranch, testingVersion)
	log.Run(task)
	_, err = version.SetForBranch(testingVersion, releaseBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	// No need for a rollback function here, git branch -d specified as a rollback
	// for the previous step will take care of deleting this change as well.

	// Bump the trunk branch version.
	task = fmt.Sprintf("Bump version (branch '%v' -> %v)", trunkBranch, nextTrunkVersion)
	log.Run(task)
	act, err := version.SetForBranch(nextTrunkVersion, trunkBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	defer action.RollbackTaskOnError(&err, task, act)

	// Initialise the next release in the code review tool.
	codeReviewTool, err := modules.GetCodeReviewTool()
	if err != nil {
		return err
	}
	act, err = codeReviewTool.InitialiseRelease(nextTrunkVersion)
	if err != nil {
		return err
	}
	defer action.RollbackTaskOnError(&err, task, act)

	// Start the release in the issue tracker.
	act, err = release.Start()
	if err != nil {
		return err
	}
	defer action.RollbackTaskOnError(&err, task, act)

	// Push the modified branches.
	task = "Push changes to the remote repository"
	log.Run(task)
	err = git.Push(remote, trunkBranch+":"+trunkBranch, releaseBranch+":"+releaseBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	return nil
}
<|endoftext|>


<commit_before>package ping

import (
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/loadimpact/speedboat/client"
	"github.com/loadimpact/speedboat/comm"
	"github.com/loadimpact/speedboat/util"
	"time"
)

func init() {
	client.RegisterCommand(cli.Command{
		Name:   "ping",
		Usage:  "Tests master connectivity",
		Action: actionPing,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "worker",
				Usage: "Pings a worker instead of the master",
			},
			cli.BoolFlag{
				Name:  "local",
				Usage: "Allow pinging an inproc master/worker",
			},
			util.MasterHostFlag,
			util.MasterPortFlag,
		},
	})
}

// Parses commandline arguments.
//
// topic - The topic (master or worker) to ping
func Parse(c *cli.Context) (topic string, err error) {
	topic = comm.MasterTopic
	if c.Bool("worker") {
		topic = comm.WorkerTopic
	}

	return topic, nil
}

// Runs the command.
func Run(in <-chan comm.Message, topic string) <-chan comm.Message {
	out := make(chan comm.Message)

	go func() {
		defer close(out)

		// Send a ping
		out <- comm.To(topic, "ping.ping").With(PingMessage{
			Time: time.Now(),
		})

		// Wait for a reply
		for msg := range in {
			switch msg.Type {
			case "ping.pong":
				data := PingMessage{}
				if err := msg.Take(&data); err != nil {
					log.WithError(err).Error("Couldn't decode pong")
					break
				}
				log.WithField("time", data.Time).Info("Pong!")
				return
			}
		}
	}()

	return out
}

// Pings a master or specified workers.
func actionPing(c *cli.Context) {
	topic, err := Parse(c)
	if err != nil {
		log.WithError(err).Fatal("Couldn't parse arguments")
	}

	ct, local := util.MustGetClient(c)
	if local && !c.Bool("local") {
		log.Fatal("You're about to ping an in-process system, which doesn't make a lot of sense. You probably want to specify --master=..., or use --local if this is actually what you want.")
	}

	in, out := ct.Connector.Run()
	for res := range Run(in, topic) {
		out <- res
	}
}
<commit_msg>Parse local there too<commit_after>package ping

import (
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/loadimpact/speedboat/client"
	"github.com/loadimpact/speedboat/comm"
	"github.com/loadimpact/speedboat/util"
	"time"
)

func init() {
	client.RegisterCommand(cli.Command{
		Name:   "ping",
		Usage:  "Tests master connectivity",
		Action: actionPing,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "worker",
				Usage: "Pings a worker instead of the master",
			},
			cli.BoolFlag{
				Name:  "local",
				Usage: "Allow pinging an inproc master/worker",
			},
			util.MasterHostFlag,
			util.MasterPortFlag,
		},
	})
}

// Parses commandline arguments.
//
// topic - The topic (master or worker) to ping
func Parse(c *cli.Context) (topic string, local bool, err error) {
	topic = comm.MasterTopic
	if c.Bool("worker") {
		topic = comm.WorkerTopic
	}

	local = c.Bool("local")

	return topic, local, nil
}

// Runs the command.
func Run(in <-chan comm.Message, topic string) <-chan comm.Message {
	out := make(chan comm.Message)

	go func() {
		defer close(out)

		// Send a ping
		out <- comm.To(topic, "ping.ping").With(PingMessage{
			Time: time.Now(),
		})

		// Wait for a reply
		for msg := range in {
			switch msg.Type {
			case "ping.pong":
				data := PingMessage{}
				if err := msg.Take(&data); err != nil {
					log.WithError(err).Error("Couldn't decode pong")
					break
				}
				log.WithField("time", data.Time).Info("Pong!")
				return
			}
		}
	}()

	return out
}

// Pings a master or specified workers.
func actionPing(c *cli.Context) {
	topic, local, err := Parse(c)
	if err != nil {
		log.WithError(err).Fatal("Couldn't parse arguments")
	}

	ct, isLocal := util.MustGetClient(c)
	if isLocal && !local {
		log.Fatal("You're about to ping an in-process system, which doesn't make a lot of sense. You probably want to specify --master=..., or use --local if this is actually what you want.")
	}

	in, out := ct.Connector.Run()
	for res := range Run(in, topic) {
		out <- res
	}
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */

package thrift

import (
	"log"
	"runtime/debug"
	"sync"
)

// Simple, non-concurrent server for testing.
type TSimpleServer struct {
	quit chan struct{}

	processorFactory       TProcessorFactory
	serverTransport        TServerTransport
	inputTransportFactory  TTransportFactory
	outputTransportFactory TTransportFactory
	inputProtocolFactory   TProtocolFactory
	outputProtocolFactory  TProtocolFactory
}

func NewTSimpleServer2(processor TProcessor, serverTransport TServerTransport) *TSimpleServer {
	return NewTSimpleServerFactory2(NewTProcessorFactory(processor), serverTransport)
}

func NewTSimpleServer4(processor TProcessor, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TSimpleServer {
	return NewTSimpleServerFactory4(NewTProcessorFactory(processor),
		serverTransport,
		transportFactory,
		protocolFactory,
	)
}

func NewTSimpleServer6(processor TProcessor, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
	return NewTSimpleServerFactory6(NewTProcessorFactory(processor),
		serverTransport,
		inputTransportFactory,
		outputTransportFactory,
		inputProtocolFactory,
		outputProtocolFactory,
	)
}

func NewTSimpleServerFactory2(processorFactory TProcessorFactory, serverTransport TServerTransport) *TSimpleServer {
	return NewTSimpleServerFactory6(processorFactory,
		serverTransport,
		NewTTransportFactory(),
		NewTTransportFactory(),
		NewTBinaryProtocolFactoryDefault(),
		NewTBinaryProtocolFactoryDefault(),
	)
}

func NewTSimpleServerFactory4(processorFactory TProcessorFactory, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TSimpleServer {
	return NewTSimpleServerFactory6(processorFactory,
		serverTransport,
		transportFactory,
		transportFactory,
		protocolFactory,
		protocolFactory,
	)
}

func NewTSimpleServerFactory6(processorFactory TProcessorFactory, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
	return &TSimpleServer{
		processorFactory:       processorFactory,
		serverTransport:        serverTransport,
		inputTransportFactory:  inputTransportFactory,
		outputTransportFactory: outputTransportFactory,
		inputProtocolFactory:   inputProtocolFactory,
		outputProtocolFactory:  outputProtocolFactory,
		quit: make(chan struct{}, 1),
	}
}

func (p *TSimpleServer) ProcessorFactory() TProcessorFactory {
	return p.processorFactory
}

func (p *TSimpleServer) ServerTransport() TServerTransport {
	return p.serverTransport
}

func (p *TSimpleServer) InputTransportFactory() TTransportFactory {
	return p.inputTransportFactory
}

func (p *TSimpleServer) OutputTransportFactory() TTransportFactory {
	return p.outputTransportFactory
}

func (p *TSimpleServer) InputProtocolFactory() TProtocolFactory {
	return p.inputProtocolFactory
}

func (p *TSimpleServer) OutputProtocolFactory() TProtocolFactory {
	return p.outputProtocolFactory
}

func (p *TSimpleServer) Listen() error {
	return p.serverTransport.Listen()
}

func (p *TSimpleServer) AcceptLoop() error {
	for {
		client, err := p.serverTransport.Accept()
		if err != nil {
			select {
			case <-p.quit:
				return nil
			default:
			}
			return err
		}
		if client != nil {
			go func() {
				if err := p.processRequests(client); err != nil {
					log.Println("error processing request:", err)
				}
			}()
		}
	}
}

func (p *TSimpleServer) Serve() error {
	err := p.Listen()
	if err != nil {
		return err
	}
	p.AcceptLoop()
	return nil
}

var once sync.Once

func (p *TSimpleServer) Stop() error {
	q := func() {
		p.quit <- struct{}{}
		p.serverTransport.Interrupt()
	}
	once.Do(q)
	return nil
}

func (p *TSimpleServer) processRequests(client TTransport) error {
	processor := p.processorFactory.GetProcessor(client)
	inputTransport := p.inputTransportFactory.GetTransport(client)
	outputTransport := p.outputTransportFactory.GetTransport(client)
	inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
	outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
	defer func() {
		if e := recover(); e != nil {
			log.Printf("panic in processor: %s: %s", e, debug.Stack())
		}
	}()
	if inputTransport != nil {
		defer inputTransport.Close()
	}
	if outputTransport != nil {
		defer outputTransport.Close()
	}
	for {
		ok, err := processor.Process(inputProtocol, outputProtocol)
		if err, ok := err.(TTransportException); ok && err.TypeId() == END_OF_FILE {
			return nil
		} else if err != nil {
			log.Printf("error processing request: %s", err)
			return err
		}
		if err, ok := err.(TApplicationException); ok && err.TypeId() == UNKNOWN_METHOD {
			continue
		}
 		if !ok {
			break
		}
	}
	return nil
}
<commit_msg>THRIFT-3959: document that the go simple server is not simple Client: go Patch: JodeZer <jeffery1993@hotmail.com><commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */

package thrift

import (
	"log"
	"runtime/debug"
	"sync"
)

/*
 * This is not a typical TSimpleServer as it is not blocked after accept a socket.
 * It is more like a TThreadedServer that can handle different connections in different goroutines.
 * This will work if golang user implements a conn-pool like thing in client side.
 */
type TSimpleServer struct {
	quit chan struct{}

	processorFactory       TProcessorFactory
	serverTransport        TServerTransport
	inputTransportFactory  TTransportFactory
	outputTransportFactory TTransportFactory
	inputProtocolFactory   TProtocolFactory
	outputProtocolFactory  TProtocolFactory
}

func NewTSimpleServer2(processor TProcessor, serverTransport TServerTransport) *TSimpleServer {
	return NewTSimpleServerFactory2(NewTProcessorFactory(processor), serverTransport)
}

func NewTSimpleServer4(processor TProcessor, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TSimpleServer {
	return NewTSimpleServerFactory4(NewTProcessorFactory(processor),
		serverTransport,
		transportFactory,
		protocolFactory,
	)
}

func NewTSimpleServer6(processor TProcessor, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
	return NewTSimpleServerFactory6(NewTProcessorFactory(processor),
		serverTransport,
		inputTransportFactory,
		outputTransportFactory,
		inputProtocolFactory,
		outputProtocolFactory,
	)
}

func NewTSimpleServerFactory2(processorFactory TProcessorFactory, serverTransport TServerTransport) *TSimpleServer {
	return NewTSimpleServerFactory6(processorFactory,
		serverTransport,
		NewTTransportFactory(),
		NewTTransportFactory(),
		NewTBinaryProtocolFactoryDefault(),
		NewTBinaryProtocolFactoryDefault(),
	)
}

func NewTSimpleServerFactory4(processorFactory TProcessorFactory, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TSimpleServer {
	return NewTSimpleServerFactory6(processorFactory,
		serverTransport,
		transportFactory,
		transportFactory,
		protocolFactory,
		protocolFactory,
	)
}

func NewTSimpleServerFactory6(processorFactory TProcessorFactory, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
	return &TSimpleServer{
		processorFactory:       processorFactory,
		serverTransport:        serverTransport,
		inputTransportFactory:  inputTransportFactory,
		outputTransportFactory: outputTransportFactory,
		inputProtocolFactory:   inputProtocolFactory,
		outputProtocolFactory:  outputProtocolFactory,
		quit: make(chan struct{}, 1),
	}
}

func (p *TSimpleServer) ProcessorFactory() TProcessorFactory {
	return p.processorFactory
}

func (p *TSimpleServer) ServerTransport() TServerTransport {
	return p.serverTransport
}

func (p *TSimpleServer) InputTransportFactory() TTransportFactory {
	return p.inputTransportFactory
}

func (p *TSimpleServer) OutputTransportFactory() TTransportFactory {
	return p.outputTransportFactory
}

func (p *TSimpleServer) InputProtocolFactory() TProtocolFactory {
	return p.inputProtocolFactory
}

func (p *TSimpleServer) OutputProtocolFactory() TProtocolFactory {
	return p.outputProtocolFactory
}

func (p *TSimpleServer) Listen() error {
	return p.serverTransport.Listen()
}

func (p *TSimpleServer) AcceptLoop() error {
	for {
		client, err := p.serverTransport.Accept()
		if err != nil {
			select {
			case <-p.quit:
				return nil
			default:
			}
			return err
		}
		if client != nil {
			go func() {
				if err := p.processRequests(client); err != nil {
					log.Println("error processing request:", err)
				}
			}()
		}
	}
}

func (p *TSimpleServer) Serve() error {
	err := p.Listen()
	if err != nil {
		return err
	}
	p.AcceptLoop()
	return nil
}

var once sync.Once

func (p *TSimpleServer) Stop() error {
	q := func() {
		p.quit <- struct{}{}
		p.serverTransport.Interrupt()
	}
	once.Do(q)
	return nil
}

func (p *TSimpleServer) processRequests(client TTransport) error {
	processor := p.processorFactory.GetProcessor(client)
	inputTransport := p.inputTransportFactory.GetTransport(client)
	outputTransport := p.outputTransportFactory.GetTransport(client)
	inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
	outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
	defer func() {
		if e := recover(); e != nil {
			log.Printf("panic in processor: %s: %s", e, debug.Stack())
		}
	}()
	if inputTransport != nil {
		defer inputTransport.Close()
	}
	if outputTransport != nil {
		defer outputTransport.Close()
	}
	for {
		ok, err := processor.Process(inputProtocol, outputProtocol)
		if err, ok := err.(TTransportException); ok && err.TypeId() == END_OF_FILE {
			return nil
		} else if err != nil {
			log.Printf("error processing request: %s", err)
			return err
		}
		if err, ok := err.(TApplicationException); ok && err.TypeId() == UNKNOWN_METHOD {
			continue
		}
 		if !ok {
			break
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
 */

package topology

import (
	"encoding/json"
	"net/http"
	"os"
	"strconv"
	"text/template"

	"github.com/gorilla/mux"

	"github.com/redhat-cip/skydive/config"
	"github.com/redhat-cip/skydive/logging"
	"github.com/redhat-cip/skydive/rpc"
	"github.com/redhat-cip/skydive/statics"
	"github.com/redhat-cip/skydive/topology/graph"
)

type Server struct {
	Graph  *graph.Graph
	Router *mux.Router
	Addr   string
	Port   int
}

func (s *Server) serveIndex(w http.ResponseWriter, r *http.Request) {
	html, err := statics.Asset("statics/topology.html")
	if err != nil {
		logging.GetLogger().Panic("Unable to find the topology asset")
	}

	t := template.New("topology template")

	t, err = t.Parse(string(html))
	if err != nil {
		panic(err)
	}

	host, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	var data = &struct {
		Hostname string
		Port     int
	}{
		Hostname: host,
		Port:     s.Port,
	}

	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	t.Execute(w, data)
}

func (s *Server) TopologyIndex(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)

	if err := json.NewEncoder(w).Encode(s.Graph); err != nil {
		panic(err)
	}
}

func (s *Server) TopologyShow(w http.ResponseWriter, r *http.Request) {
	/*vars := mux.Vars(r)
	host := vars["host"]

	if topo, ok := s.MultiNodeTopology.Get(host); ok {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(http.StatusOK)
		if err := json.NewEncoder(w).Encode(topo); err != nil {
			panic(err)
		}
	} else {
		w.WriteHeader(http.StatusNotFound)
	}*/
}

func (s *Server) RegisterStaticEndpoints() {

	// static routes
	s.Router.HandleFunc("/static/topology", s.serveIndex)
}

func (s *Server) RegisterRpcEndpoints() {
	routes := []rpc.Route{
		{
			"TopologiesIndex",
			"GET",
			"/rpc/topology",
			s.TopologyIndex,
		},
		{
			"TopologyShow",
			"GET",
			"/rpc/topology/{host}",
			s.TopologyShow,
		},
	}

	for _, route := range routes {
		s.Router.
			Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(route.HandlerFunc)
	}
}

func (s *Server) ListenAndServe() {
	http.ListenAndServe(s.Addr+":"+strconv.FormatInt(int64(s.Port), 10), s.Router)
}

func NewServer(g *graph.Graph, a string, p int, router *mux.Router) *Server {
	return &Server{
		Graph:  g,
		Router: router,
		Addr:   a,
		Port:   p,
	}
}

func NewServerFromConfig(s string, g *graph.Graph, router *mux.Router) *Server {
	addr, port, err := config.GetHostPortAttributes(s, "listen")
	if err != nil {
		logging.GetLogger().Error("Configuration error: %s", err.Error())
		return nil
	}

	return NewServer(g, addr, port, router)
}
<commit_msg>Remove dead code<commit_after>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
 */

package topology

import (
	"encoding/json"
	"net/http"
	"os"
	"strconv"
	"text/template"

	"github.com/gorilla/mux"

	"github.com/redhat-cip/skydive/config"
	"github.com/redhat-cip/skydive/logging"
	"github.com/redhat-cip/skydive/rpc"
	"github.com/redhat-cip/skydive/statics"
	"github.com/redhat-cip/skydive/topology/graph"
)

type Server struct {
	Graph  *graph.Graph
	Router *mux.Router
	Addr   string
	Port   int
}

func (s *Server) serveIndex(w http.ResponseWriter, r *http.Request) {
	html, err := statics.Asset("statics/topology.html")
	if err != nil {
		logging.GetLogger().Panic("Unable to find the topology asset")
	}

	t := template.New("topology template")

	t, err = t.Parse(string(html))
	if err != nil {
		panic(err)
	}

	host, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	var data = &struct {
		Hostname string
		Port     int
	}{
		Hostname: host,
		Port:     s.Port,
	}

	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	t.Execute(w, data)
}

func (s *Server) TopologyIndex(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)

	if err := json.NewEncoder(w).Encode(s.Graph); err != nil {
		panic(err)
	}
}

func (s *Server) RegisterStaticEndpoints() {
	s.Router.HandleFunc("/static/topology", s.serveIndex)
}

func (s *Server) RegisterRpcEndpoints() {
	routes := []rpc.Route{
		{
			"TopologiesIndex",
			"GET",
			"/rpc/topology",
			s.TopologyIndex,
		},
	}

	for _, route := range routes {
		s.Router.
			Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(route.HandlerFunc)
	}
}

func (s *Server) ListenAndServe() {
	http.ListenAndServe(s.Addr+":"+strconv.FormatInt(int64(s.Port), 10), s.Router)
}

func NewServer(g *graph.Graph, a string, p int, router *mux.Router) *Server {
	return &Server{
		Graph:  g,
		Router: router,
		Addr:   a,
		Port:   p,
	}
}

func NewServerFromConfig(s string, g *graph.Graph, router *mux.Router) *Server {
	addr, port, err := config.GetHostPortAttributes(s, "listen")
	if err != nil {
		logging.GetLogger().Error("Configuration error: %s", err.Error())
		return nil
	}

	return NewServer(g, addr, port, router)
}
<|endoftext|>


<commit_before>package main

import (
	"net"
	"log"
	"fmt"
	"flag"
	"bytes"
)

type handler struct {
	s string
	f func(net.Conn, []byte)
}

var responses = map[string] handler {
	"EHLO": {"250-Pleased to meet you!\r\n250-PIPELINING\r\n250 CHUNKING\r\n", nil},
	"HELO": {"250 Pleased to meet you!\r\n", nil},
	"MAIL": {"250 OK\r\n", nil},
	"RCPT": {"250 OK\r\n", nil},
	"DATA": {"354 End data with <CR><LF>.<CR><LF>\r\n", handleData}, // Need to read data until \r\n.\r\n is received.
	"BDAT": {"250 OK\r\n", handleBdat}, // Should be sent once the data has been reveived
	"RSET": {"250 OK\r\n", nil},
	"QUIT": {"221 Goodbye\r\n", nil} }

func handleConnection(c net.Conn) {
	// Print banner
	c.Write([]byte("220 Welcome to Blackhole SMTP!\r\n"))
	readBuf := make([]byte, 1024)
	for {
		_, e := c.Read(readBuf)
		if e != nil {
			_ = c.Close()
			return
		}
		h, ok := responses[string(readBuf[0:4])]
		if ok {
			c.Write([]byte(h.s))
			if h.f != nil {
				h.f(c, readBuf)
			}
		}
	}
}

func handleData(c net.Conn, b[]byte) {
	for {
		l, e := c.Read(b)
		if e != nil || l == 0 {
			break;
		}
		if bytes.Contains(b, []byte("\r\n.\r\n")) {
			c.Write([]byte("250 OK\r\n"))
			break;
		}
	}
}

func handleBdat(c net.Conn, b[]byte) {
}

func main() {
	var port int

	flag.IntVar(&port, "port", 25, "TCP port")

	flag.Parse()

	// Get address:port
	a, e := net.ResolveTCPAddr("tcp4", fmt.Sprintf(":%d", port))
	if e != nil {
		// Error!
		log.Panic(e)
		return;
	}

	// Start listening for incoming connections
	l, e := net.ListenTCP("tcp", a)
	if e != nil {
		// Error!
		log.Panic(e)
		return;
	}

	// Accept connections then handle each one in a dedicated goroutine
	for {
		c, e := l.Accept()
		if e != nil {
			continue
		}
		go handleConnection(c)
	}
}
<commit_msg>Add a configurable -latency parameter<commit_after>package main

import (
	"net"
	"log"
	"fmt"
	"flag"
	"bytes"
	"time"
)

type handler struct {
	s string
	f func(net.Conn, []byte, time.Duration)
}

var responses = map[string] handler {
	"EHLO": {"250-Pleased to meet you!\r\n250-PIPELINING\r\n250 CHUNKING\r\n", nil},
	"HELO": {"250 Pleased to meet you!\r\n", nil},
	"MAIL": {"250 OK\r\n", nil},
	"RCPT": {"250 OK\r\n", nil},
	"DATA": {"354 End data with <CR><LF>.<CR><LF>\r\n", handleData}, // Need to read data until \r\n.\r\n is received.
	"BDAT": {"250 OK\r\n", handleBdat}, // Should be sent once the data has been reveived
	"RSET": {"250 OK\r\n", nil},
	"QUIT": {"221 Goodbye\r\n", nil} }

func handleConnection(c net.Conn, latency time.Duration) {
	// Print banner
	c.Write([]byte("220 Welcome to Blackhole SMTP!\r\n"))
	readBuf := make([]byte, 1024)
	for {
		_, e := c.Read(readBuf)
		if e != nil {
			_ = c.Close()
			return
		}
		time.Sleep(latency * time.Millisecond)
		h, ok := responses[string(readBuf[0:4])]
		if ok {
			c.Write([]byte(h.s))
			if h.f != nil {
				h.f(c, readBuf, latency)
			}
		} else {
			c.Write([]byte("500 Command unrecognized\r\n"))
		}
	}
}

func handleData(c net.Conn, b[]byte, latency time.Duration) {
	for {
		l, e := c.Read(b)
		if e != nil || l == 0 {
			break;
		}
		if bytes.Contains(b, []byte("\r\n.\r\n")) {
			time.Sleep(latency * time.Millisecond)
			c.Write([]byte("250 OK\r\n"))
			break;
		}
	}
}

func handleBdat(c net.Conn, b[]byte, latency time.Duration) {
}

func main() {
	var port int
	var latency int

	flag.IntVar(&port, "port", 25, "TCP port")
	flag.IntVar(&latency, "latency", 0, "Latency in milliseconds")

	flag.Parse()

	// Get address:port
	a, e := net.ResolveTCPAddr("tcp4", fmt.Sprintf(":%d", port))
	if e != nil {
		// Error!
		log.Panic(e)
		return;
	}

	// Start listening for incoming connections
	l, e := net.ListenTCP("tcp", a)
	if e != nil {
		// Error!
		log.Panic(e)
		return;
	}

	// Accept connections then handle each one in a dedicated goroutine
	for {
		c, e := l.Accept()
		if e != nil {
			continue
		}
		go handleConnection(c, time.Duration(latency))
	}
}
<|endoftext|>


<commit_before>// +build unit

// Copyright 2016 Mesosphere, Inc.
//
// 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.

package collector

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

	"github.com/dcos/dcos-metrics/producers"
	. "github.com/smartystreets/goconvey/convey"
)

func TestNewAgent(t *testing.T) {
	Convey("When establishing a new agentPoller", t, func() {
		Convey("Should return an error when given an improper IP address", func() {
			_, err := NewAgent("", 10000, 60, make(chan<- producers.MetricsMessage))
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an error when given an improper port", func() {
			_, err := NewAgent("1.2.3.4", 1023, 60, make(chan<- producers.MetricsMessage))
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an error when given an improper pollPeriod", func() {
			_, err := NewAgent("1.2.3.4", 1024, 0, make(chan<- producers.MetricsMessage))
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an Agent when given proper inputs", func() {
			a, err := NewAgent("1.2.3.4", 10000, 60, make(chan<- producers.MetricsMessage))
			So(a, ShouldHaveSameTypeAs, Agent{})
			So(err, ShouldBeNil)
		})
	})
}

func TestGetContainerMetrics(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		td := []byte(`
		[
			{
				"container_id": "e4faacb2-f69f-4ea1-9d96-eb06fea75eef",
				"executor_id": "foo.adf2b6f4-a171-11e6-9182-080027fb5b88",
				"executor_name": "Command Executor (Task: foo.adf2b6f4-a171-11e6-9182-080027fb5b88) (Command: sh -c 'sleep 900')",
				"framework_id": "5349f49b-68b3-4638-aab2-fc4ec845f993-0000",
				"source": "foo.adf2b6f4-a171-11e6-9182-080027fb5b88",
				"statistics": {
					"cpus_limit": 1.1,
					"cpus_system_time_secs": 0.31,
					"cpus_user_time_secs": 0.22,
					"mem_limit_bytes": 167772160,
					"mem_total_bytes": 4476928
				}
			}
		]`)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(td)
	}))
	defer ts.Close()

	Convey("When fetching container metrics", t, func() {
		port, err := extractPortFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		a, _ := NewAgent("/bin/true", port, 60, make(chan<- producers.MetricsMessage))
		a.AgentIP = "127.0.0.1"
		result, err := a.getContainerMetrics()

		Convey("Should return an array of 'agentContainer' without error", func() {
			// Ensure that we're
			//   a) unmarshaling the data correctly, and
			//   b) that we're getting valid types for the data (string, float, int)
			So(result[0].ContainerID, ShouldEqual, "e4faacb2-f69f-4ea1-9d96-eb06fea75eef")
			So(result[0].Statistics.CpusLimit, ShouldEqual, 1.1)
			So(result[0].Statistics.MemTotalBytes, ShouldEqual, 4476928)
			So(err, ShouldBeNil)
		})
	})
}

func TestGetAgentMetrics(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		td := []byte(`
		{
			"system\/cpus_total": 2,
			"system\/load_1min": 0.1,
			"system\/load_5min": 0.11,
			"system\/load_15min": 0.08,
			"system\/mem_total_bytes": 4145348608,
			"system\/mem_free_bytes": 3349942272
		}`)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(td)
	}))
	defer ts.Close()

	Convey("When fetching agent metrics", t, func() {
		port, err := extractPortFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		Convey("Should return an 'agentMetricsSnapshot' without error", func() {
			a, _ := NewAgent("/bin/true", port, 60, make(chan<- producers.MetricsMessage))
			a.AgentIP = "127.0.0.1"
			result, err := a.getAgentMetrics()

			So(result.CPUsTotal, ShouldEqual, 2)
			So(result.SystemLoad5Min, ShouldEqual, 0.11)
			So(result.MemFreeBytes, ShouldEqual, 3349942272)
			So(err, ShouldBeNil)
		})
	})
}

func TestGetAgentState(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		td := []byte(`
		{
			"frameworks": [
				{
					"id": "5349f49b-68b3-4638-aab2-fc4ec845f993-0000",
					"name": "marathon",
					"role": "*",
					"executors": [
						{
							"id": "foo.124b1048-a17a-11e6-9182-080027fb5b88",
							"name": "Command Executor (Task: foo.124b1048-a17a-11e6-9182-080027fb5b88) (Command: sh -c 'sleep 900')",
							"container": "e4c2f9f6-47aa-481d-a183-a21e8435bc06",
							"labels": [
								{
									"key": "somekey",
									"value": "someval"
								}
							],
							"tasks": [
								{
									"id": "foo.124b1048-a17a-11e6-9182-080027fb5b88",
									"name": "foo",
									"framework_id": "5349f49b-68b3-4638-aab2-fc4ec845f993-0000",
									"executor_id": "",
									"slave_id": "34b46033-69c0-4663-887c-f64b526e47a6-S0",
									"labels": [
										{
											"key": "somekey",
											"value": "someval"
										}
									]
								}
							]
						}
					]
				}
			]
		}`)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(td)
	}))
	defer ts.Close()

	Convey("When fetching the agent state", t, func() {
		port, err := extractPortFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		Convey("Should return an 'agentState' without error", func() {
			a, _ := NewAgent("/bin/true", port, 60, make(chan<- producers.MetricsMessage))
			a.AgentIP = "127.0.0.1"
			result, err := a.getAgentState()

			// getAgentState() returns a lot of metadata required for dcos-metrics
			// to be useful to operators. Let's ensure that we're unmarshaling
			// and able to return *everything* we care about.
			So(len(result.Frameworks), ShouldEqual, 1)
			So(len(result.Frameworks[0].Executors), ShouldEqual, 1)
			So(result.Frameworks[0].ID, ShouldEqual, "5349f49b-68b3-4638-aab2-fc4ec845f993-0000")
			So(result.Frameworks[0].Name, ShouldEqual, "marathon")
			So(result.Frameworks[0].Role, ShouldEqual, "*")
			So(result.Frameworks[0].Executors[0].ID, ShouldEqual, "foo.124b1048-a17a-11e6-9182-080027fb5b88")
			So(result.Frameworks[0].Executors[0].Name, ShouldEqual, "Command Executor (Task: foo.124b1048-a17a-11e6-9182-080027fb5b88) (Command: sh -c 'sleep 900')")
			So(result.Frameworks[0].Executors[0].Container, ShouldEqual, "e4c2f9f6-47aa-481d-a183-a21e8435bc06")
			So(result.Frameworks[0].Executors[0].Labels[0].Key, ShouldEqual, "somekey")
			So(result.Frameworks[0].Executors[0].Labels[0].Value, ShouldEqual, "someval")
			So(err, ShouldBeNil)
		})
	})
}

func TestGetIP(t *testing.T) {
	Convey("When getting the agent IP address using the ip_detect script", t, func() {
		Convey("Should return the IP address without error", nil)
	})
}

func TestTransform(t *testing.T) {
	Convey("When transforming agent metrics to fit producers.MetricsMessage", t, func() {
		Convey("Should return a []producers.MetricsMessage without errors", nil)
	})
}

func TestGetFrameworkNameByFrameworkID(t *testing.T) {
	Convey("When getting a framework's name, given its ID", t, func() {
		fi := []frameworkInfo{
			frameworkInfo{
				Name: "fooframework",
				ID:   "7",
			},
		}

		Convey("Should return the framework name without errors", func() {
			result := getFrameworkNameByFrameworkID("7", fi)
			So(result, ShouldEqual, "fooframework")
		})

		Convey("Should return an empty string if no match was found", func() {
			result := getFrameworkNameByFrameworkID("42", fi)
			So(result, ShouldEqual, "")
		})
	})
}

func TestGetLabelsByContainerID(t *testing.T) {
	Convey("When getting the labels for a container, given its ID", t, func() {
		fi := []frameworkInfo{
			frameworkInfo{
				Name: "fooframework",
				ID:   "7",
				Executors: []executorInfo{
					executorInfo{
						Container: "someContainerID",
						Labels: []executorLabels{
							executorLabels{
								Key:   "somekey",
								Value: "someval",
							},
						},
					},
				},
			},
		}

		Convey("Should return a map of key/value pairs", func() {
			result := getLabelsByContainerID("someContainerID", fi)
			So(result, ShouldResemble, map[string]string{"somekey": "someval"})
		})

		Convey("Should return an empty map if no labels were present", func() {
			result := getLabelsByContainerID("someOtherContainerID", fi)
			So(result, ShouldResemble, map[string]string{})
		})
	})
}

func extractPortFromURL(u string) (int, error) {
	parsed, err := url.Parse(u)
	if err != nil {
		return 0, err
	}
	port, err := strconv.Atoi(strings.Split(parsed.Host, ":")[1])
	if err != nil {
		return 0, err
	}
	return port, nil
}
<commit_msg>make mocks reusable<commit_after>// +build unit

// Copyright 2016 Mesosphere, Inc.
//
// 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.

package collector

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

	"github.com/dcos/dcos-metrics/producers"
	. "github.com/smartystreets/goconvey/convey"
)

var (
	mockAgentMetrics = []byte(`
		{
			"system\/cpus_total": 2,
			"system\/load_1min": 0.1,
			"system\/load_5min": 0.11,
			"system\/load_15min": 0.08,
			"system\/mem_total_bytes": 4145348608,
			"system\/mem_free_bytes": 3349942272
		}`)

	mockAgentState = []byte(`
		{
			"frameworks": [
				{
					"id": "5349f49b-68b3-4638-aab2-fc4ec845f993-0000",
					"name": "marathon",
					"role": "*",
					"executors": [
						{
							"id": "foo.124b1048-a17a-11e6-9182-080027fb5b88",
							"name": "Command Executor (Task: foo.124b1048-a17a-11e6-9182-080027fb5b88) (Command: sh -c 'sleep 900')",
							"container": "e4c2f9f6-47aa-481d-a183-a21e8435bc06",
							"labels": [
								{
									"key": "somekey",
									"value": "someval"
								}
							],
							"tasks": [
								{
									"id": "foo.124b1048-a17a-11e6-9182-080027fb5b88",
									"name": "foo",
									"framework_id": "5349f49b-68b3-4638-aab2-fc4ec845f993-0000",
									"executor_id": "",
									"slave_id": "34b46033-69c0-4663-887c-f64b526e47a6-S0",
									"labels": [
										{
											"key": "somekey",
											"value": "someval"
										}
									]
								}
							]
						}
					]
				}
			]
		}`)

	mockContainerMetrics = []byte(`
		[
			{
				"container_id": "e4faacb2-f69f-4ea1-9d96-eb06fea75eef",
				"executor_id": "foo.adf2b6f4-a171-11e6-9182-080027fb5b88",
				"executor_name": "Command Executor (Task: foo.adf2b6f4-a171-11e6-9182-080027fb5b88) (Command: sh -c 'sleep 900')",
				"framework_id": "5349f49b-68b3-4638-aab2-fc4ec845f993-0000",
				"source": "foo.adf2b6f4-a171-11e6-9182-080027fb5b88",
				"statistics": {
					"cpus_limit": 1.1,
					"cpus_system_time_secs": 0.31,
					"cpus_user_time_secs": 0.22,
					"mem_limit_bytes": 167772160,
					"mem_total_bytes": 4476928
				}
			}
		]`)
)

func TestNewAgent(t *testing.T) {
	Convey("When establishing a new agentPoller", t, func() {
		Convey("Should return an error when given an improper IP address", func() {
			_, err := NewAgent("", 10000, 60, make(chan<- producers.MetricsMessage))
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an error when given an improper port", func() {
			_, err := NewAgent("1.2.3.4", 1023, 60, make(chan<- producers.MetricsMessage))
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an error when given an improper pollPeriod", func() {
			_, err := NewAgent("1.2.3.4", 1024, 0, make(chan<- producers.MetricsMessage))
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an Agent when given proper inputs", func() {
			a, err := NewAgent("1.2.3.4", 10000, 60, make(chan<- producers.MetricsMessage))
			So(a, ShouldHaveSameTypeAs, Agent{})
			So(err, ShouldBeNil)
		})
	})
}

func TestGetContainerMetrics(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(mockContainerMetrics)
	}))
	defer ts.Close()

	Convey("When fetching container metrics", t, func() {
		port, err := extractPortFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		a, _ := NewAgent("/bin/true", port, 60, make(chan<- producers.MetricsMessage))
		a.AgentIP = "127.0.0.1"
		result, err := a.getContainerMetrics()

		Convey("Should return an array of 'agentContainer' without error", func() {
			// Ensure that we're
			//   a) unmarshaling the data correctly, and
			//   b) that we're getting valid types for the data (string, float, int)
			So(result[0].ContainerID, ShouldEqual, "e4faacb2-f69f-4ea1-9d96-eb06fea75eef")
			So(result[0].Statistics.CpusLimit, ShouldEqual, 1.1)
			So(result[0].Statistics.MemTotalBytes, ShouldEqual, 4476928)
			So(err, ShouldBeNil)
		})
	})
}

func TestGetAgentMetrics(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(mockAgentMetrics)
	}))
	defer ts.Close()

	Convey("When fetching agent metrics", t, func() {
		port, err := extractPortFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		Convey("Should return an 'agentMetricsSnapshot' without error", func() {
			a, _ := NewAgent("/bin/true", port, 60, make(chan<- producers.MetricsMessage))
			a.AgentIP = "127.0.0.1"
			result, err := a.getAgentMetrics()

			So(result.CPUsTotal, ShouldEqual, 2)
			So(result.SystemLoad5Min, ShouldEqual, 0.11)
			So(result.MemFreeBytes, ShouldEqual, 3349942272)
			So(err, ShouldBeNil)
		})
	})
}

func TestGetAgentState(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		w.Write(mockAgentState)
	}))
	defer ts.Close()

	Convey("When fetching the agent state", t, func() {
		port, err := extractPortFromURL(ts.URL)
		if err != nil {
			panic(err)
		}

		Convey("Should return an 'agentState' without error", func() {
			a, _ := NewAgent("/bin/true", port, 60, make(chan<- producers.MetricsMessage))
			a.AgentIP = "127.0.0.1"
			result, err := a.getAgentState()

			// getAgentState() returns a lot of metadata required for dcos-metrics
			// to be useful to operators. Let's ensure that we're unmarshaling
			// and able to return *everything* we care about.
			So(len(result.Frameworks), ShouldEqual, 1)
			So(len(result.Frameworks[0].Executors), ShouldEqual, 1)
			So(result.Frameworks[0].ID, ShouldEqual, "5349f49b-68b3-4638-aab2-fc4ec845f993-0000")
			So(result.Frameworks[0].Name, ShouldEqual, "marathon")
			So(result.Frameworks[0].Role, ShouldEqual, "*")
			So(result.Frameworks[0].Executors[0].ID, ShouldEqual, "foo.124b1048-a17a-11e6-9182-080027fb5b88")
			So(result.Frameworks[0].Executors[0].Name, ShouldEqual, "Command Executor (Task: foo.124b1048-a17a-11e6-9182-080027fb5b88) (Command: sh -c 'sleep 900')")
			So(result.Frameworks[0].Executors[0].Container, ShouldEqual, "e4c2f9f6-47aa-481d-a183-a21e8435bc06")
			So(result.Frameworks[0].Executors[0].Labels[0].Key, ShouldEqual, "somekey")
			So(result.Frameworks[0].Executors[0].Labels[0].Value, ShouldEqual, "someval")
			So(err, ShouldBeNil)
		})
	})
}

func TestGetIP(t *testing.T) {
	Convey("When getting the agent IP address using the ip_detect script", t, func() {
		Convey("Should return the IP address without error", nil)
	})
}

func TestTransform(t *testing.T) {
	Convey("When transforming agent metrics to fit producers.MetricsMessage", t, func() {
		Convey("Should return a []producers.MetricsMessage without errors", nil)
	})
}

func TestGetFrameworkNameByFrameworkID(t *testing.T) {
	Convey("When getting a framework's name, given its ID", t, func() {
		fi := []frameworkInfo{
			frameworkInfo{
				Name: "fooframework",
				ID:   "7",
			},
		}

		Convey("Should return the framework name without errors", func() {
			result := getFrameworkNameByFrameworkID("7", fi)
			So(result, ShouldEqual, "fooframework")
		})

		Convey("Should return an empty string if no match was found", func() {
			result := getFrameworkNameByFrameworkID("42", fi)
			So(result, ShouldEqual, "")
		})
	})
}

func TestGetLabelsByContainerID(t *testing.T) {
	Convey("When getting the labels for a container, given its ID", t, func() {
		fi := []frameworkInfo{
			frameworkInfo{
				Name: "fooframework",
				ID:   "7",
				Executors: []executorInfo{
					executorInfo{
						Container: "someContainerID",
						Labels: []executorLabels{
							executorLabels{
								Key:   "somekey",
								Value: "someval",
							},
						},
					},
				},
			},
		}

		Convey("Should return a map of key/value pairs", func() {
			result := getLabelsByContainerID("someContainerID", fi)
			So(result, ShouldResemble, map[string]string{"somekey": "someval"})
		})

		Convey("Should return an empty map if no labels were present", func() {
			result := getLabelsByContainerID("someOtherContainerID", fi)
			So(result, ShouldResemble, map[string]string{})
		})
	})
}

func extractPortFromURL(u string) (int, error) {
	parsed, err := url.Parse(u)
	if err != nil {
		return 0, err
	}
	port, err := strconv.Atoi(strings.Split(parsed.Host, ":")[1])
	if err != nil {
		return 0, err
	}
	return port, nil
}
<|endoftext|>


<commit_before>package proctl

// #include "proctl_darwin.h"
import "C"
import (
	"debug/gosym"
	"debug/macho"
	"fmt"
	"os"
	"sync"
	"unsafe"

	"github.com/derekparker/delve/dwarf/frame"
	sys "golang.org/x/sys/unix"
)

type OSProcessDetails struct {
	task          C.mach_port_name_t
	exceptionPort C.mach_port_t
}

func (dbp *DebuggedProcess) Halt() (err error) {
	for _, th := range dbp.Threads {
		err := th.Halt()
		if err != nil {
			return err
		}
	}
	return nil
}

// Finds the executable and then uses it
// to parse the following information:
// * Dwarf .debug_frame section
// * Dwarf .debug_line section
// * Go symbol table.
func (dbp *DebuggedProcess) LoadInformation() error {
	var (
		wg  sync.WaitGroup
		exe *macho.File
		err error
	)

	if ret := C.acquire_mach_task(C.int(dbp.Pid), &dbp.os.task, &dbp.os.exceptionPort); ret != C.KERN_SUCCESS {
		return fmt.Errorf("could not acquire mach task %d", ret)
	}
	exe, err = dbp.findExecutable()
	if err != nil {
		return err
	}
	data, err := exe.DWARF()
	if err != nil {
		return err
	}
	dbp.Dwarf = data

	wg.Add(2)
	go dbp.parseDebugFrame(exe, &wg)
	go dbp.obtainGoSymbols(exe, &wg)
	wg.Wait()

	return nil
}

func (dbp *DebuggedProcess) updateThreadList() error {
	var (
		err   error
		kret  C.kern_return_t
		count = C.thread_count(C.task_t(dbp.os.task))
	)
	if count == -1 {
		return fmt.Errorf("could not get thread count")
	}
	list := make([]uint32, count)

	// TODO(dp) might be better to malloc mem in C and then free it here
	// instead of getting count above and passing in a slice
	kret = C.get_threads(C.task_t(dbp.os.task), unsafe.Pointer(&list[0]))
	if kret != C.KERN_SUCCESS {
		return fmt.Errorf("could not get thread list")
	}
	if count < 0 {
		return fmt.Errorf("could not get thread list")
	}

	for _, port := range list {
		if _, ok := dbp.Threads[int(port)]; !ok {
			_, err = dbp.addThread(int(port), false)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (dbp *DebuggedProcess) addThread(port int, attach bool) (*ThreadContext, error) {
	if thread, ok := dbp.Threads[port]; ok {
		return thread, nil
	}
	fmt.Println("new thread spawned", port)
	thread := &ThreadContext{
		Id:      port,
		Process: dbp,
		os:      new(OSSpecificDetails),
	}
	dbp.Threads[port] = thread
	thread.os.thread_act = C.thread_act_t(port)
	if dbp.CurrentThread == nil {
		dbp.CurrentThread = thread
	}
	return thread, nil
}

func (dbp *DebuggedProcess) parseDebugFrame(exe *macho.File, wg *sync.WaitGroup) {
	defer wg.Done()

	if sec := exe.Section("__debug_frame"); sec != nil {
		debugFrame, err := exe.Section("__debug_frame").Data()
		if err != nil {
			fmt.Println("could not get __debug_frame section", err)
			os.Exit(1)
		}
		dbp.FrameEntries = frame.Parse(debugFrame)
	} else {
		fmt.Println("could not find __debug_frame section in binary")
		os.Exit(1)
	}
}

func (dbp *DebuggedProcess) obtainGoSymbols(exe *macho.File, wg *sync.WaitGroup) {
	defer wg.Done()

	var (
		symdat  []byte
		pclndat []byte
		err     error
	)

	if sec := exe.Section("__gosymtab"); sec != nil {
		symdat, err = sec.Data()
		if err != nil {
			fmt.Println("could not get .gosymtab section", err)
			os.Exit(1)
		}
	}

	if sec := exe.Section("__gopclntab"); sec != nil {
		pclndat, err = sec.Data()
		if err != nil {
			fmt.Println("could not get .gopclntab section", err)
			os.Exit(1)
		}
	}

	pcln := gosym.NewLineTable(pclndat, exe.Section("__text").Addr)
	tab, err := gosym.NewTable(symdat, pcln)
	if err != nil {
		fmt.Println("could not get initialize line table", err)
		os.Exit(1)
	}

	dbp.GoSymTable = tab
}

func (dbp *DebuggedProcess) findExecutable() (*macho.File, error) {
	pathptr, err := C.find_executable(C.int(dbp.Pid))
	if err != nil {
		return nil, err
	}
	return macho.Open(C.GoString(pathptr))
}

func trapWait(dbp *DebuggedProcess, pid int) (int, error) {
	port := C.mach_port_wait(dbp.os.exceptionPort)
	if port == 0 {
		return -1, ProcessExitedError{Pid: dbp.Pid}
	}

	dbp.updateThreadList()
	return int(port), nil
}

func wait(pid, options int) (int, *sys.WaitStatus, error) {
	var status sys.WaitStatus
	wpid, err := sys.Wait4(pid, &status, options, nil)
	return wpid, &status, err
}
<commit_msg>Reap child process for status (OS X)<commit_after>package proctl

// #include "proctl_darwin.h"
import "C"
import (
	"debug/gosym"
	"debug/macho"
	"fmt"
	"os"
	"sync"
	"unsafe"

	"github.com/derekparker/delve/dwarf/frame"
	sys "golang.org/x/sys/unix"
)

type OSProcessDetails struct {
	task          C.mach_port_name_t
	exceptionPort C.mach_port_t
}

func (dbp *DebuggedProcess) Halt() (err error) {
	for _, th := range dbp.Threads {
		err := th.Halt()
		if err != nil {
			return err
		}
	}
	return nil
}

// Finds the executable and then uses it
// to parse the following information:
// * Dwarf .debug_frame section
// * Dwarf .debug_line section
// * Go symbol table.
func (dbp *DebuggedProcess) LoadInformation() error {
	var (
		wg  sync.WaitGroup
		exe *macho.File
		err error
	)

	if ret := C.acquire_mach_task(C.int(dbp.Pid), &dbp.os.task, &dbp.os.exceptionPort); ret != C.KERN_SUCCESS {
		return fmt.Errorf("could not acquire mach task %d", ret)
	}
	exe, err = dbp.findExecutable()
	if err != nil {
		return err
	}
	data, err := exe.DWARF()
	if err != nil {
		return err
	}
	dbp.Dwarf = data

	wg.Add(2)
	go dbp.parseDebugFrame(exe, &wg)
	go dbp.obtainGoSymbols(exe, &wg)
	wg.Wait()

	return nil
}

func (dbp *DebuggedProcess) updateThreadList() error {
	var (
		err   error
		kret  C.kern_return_t
		count = C.thread_count(C.task_t(dbp.os.task))
	)
	if count == -1 {
		return fmt.Errorf("could not get thread count")
	}
	list := make([]uint32, count)

	// TODO(dp) might be better to malloc mem in C and then free it here
	// instead of getting count above and passing in a slice
	kret = C.get_threads(C.task_t(dbp.os.task), unsafe.Pointer(&list[0]))
	if kret != C.KERN_SUCCESS {
		return fmt.Errorf("could not get thread list")
	}
	if count < 0 {
		return fmt.Errorf("could not get thread list")
	}

	for _, port := range list {
		if _, ok := dbp.Threads[int(port)]; !ok {
			_, err = dbp.addThread(int(port), false)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (dbp *DebuggedProcess) addThread(port int, attach bool) (*ThreadContext, error) {
	if thread, ok := dbp.Threads[port]; ok {
		return thread, nil
	}
	fmt.Println("new thread spawned", port)
	thread := &ThreadContext{
		Id:      port,
		Process: dbp,
		os:      new(OSSpecificDetails),
	}
	dbp.Threads[port] = thread
	thread.os.thread_act = C.thread_act_t(port)
	if dbp.CurrentThread == nil {
		dbp.CurrentThread = thread
	}
	return thread, nil
}

func (dbp *DebuggedProcess) parseDebugFrame(exe *macho.File, wg *sync.WaitGroup) {
	defer wg.Done()

	if sec := exe.Section("__debug_frame"); sec != nil {
		debugFrame, err := exe.Section("__debug_frame").Data()
		if err != nil {
			fmt.Println("could not get __debug_frame section", err)
			os.Exit(1)
		}
		dbp.FrameEntries = frame.Parse(debugFrame)
	} else {
		fmt.Println("could not find __debug_frame section in binary")
		os.Exit(1)
	}
}

func (dbp *DebuggedProcess) obtainGoSymbols(exe *macho.File, wg *sync.WaitGroup) {
	defer wg.Done()

	var (
		symdat  []byte
		pclndat []byte
		err     error
	)

	if sec := exe.Section("__gosymtab"); sec != nil {
		symdat, err = sec.Data()
		if err != nil {
			fmt.Println("could not get .gosymtab section", err)
			os.Exit(1)
		}
	}

	if sec := exe.Section("__gopclntab"); sec != nil {
		pclndat, err = sec.Data()
		if err != nil {
			fmt.Println("could not get .gopclntab section", err)
			os.Exit(1)
		}
	}

	pcln := gosym.NewLineTable(pclndat, exe.Section("__text").Addr)
	tab, err := gosym.NewTable(symdat, pcln)
	if err != nil {
		fmt.Println("could not get initialize line table", err)
		os.Exit(1)
	}

	dbp.GoSymTable = tab
}

func (dbp *DebuggedProcess) findExecutable() (*macho.File, error) {
	pathptr, err := C.find_executable(C.int(dbp.Pid))
	if err != nil {
		return nil, err
	}
	return macho.Open(C.GoString(pathptr))
}

func trapWait(dbp *DebuggedProcess, pid int) (int, error) {
	port := C.mach_port_wait(dbp.os.exceptionPort)
	if port == 0 {
		_, status, err := wait(dbp.Pid, 0)
		if err != nil {
			return -1, err
		}
		return -1, ProcessExitedError{Pid: dbp.Pid, Status: status.ExitStatus()}
	}

	dbp.updateThreadList()
	return int(port), nil
}

func wait(pid, options int) (int, *sys.WaitStatus, error) {
	var status sys.WaitStatus
	wpid, err := sys.Wait4(pid, &status, options, nil)
	return wpid, &status, err
}
<|endoftext|>


<commit_before>package models

type Advisory struct {
	Id uint64 `orm:"auto;pk"`

	Prefix     string
	AdvisoryId uint64

	Creator     *User     `orm:"rel(fk)"`
	Description string    `orm:"type(text)"`
	Issued      time.Time `orm:"auto_now_add"`
	Updated     time.Time `orm:"auto_now"`

	Updates []*BuildList `orm:"reverse(many)"`
}
<commit_msg>advisory stuff<commit_after>package models

import (
	"github.com/astaxie/beego/orm"
	"time"
)

type Advisory struct {
	Id uint64 `orm:"auto;pk"`

	Prefix     string
	AdvisoryId uint64

	Creator     *User     `orm:"rel(fk)"`
	Description string    `orm:"type(text)"`
	Issued      time.Time `orm:"auto_now_add"`
	Updated     time.Time `orm:"auto_now"`

	Updates []*BuildList `orm:"reverse(many)"`
}

func NextAdvisoryId(prefix string) uint64 {
	o := orm.NewOrm()

	var adv Advisory
	err := o.QueryTable(new(Advisory)).Filter("Prefix", prefix).OrderBy("-AdvisoryId").Limit(1).One(&adv)
	if err == orm.ErrNoRows {
		return 1
	} else if err != nil {
		panic(err)
	}

	return adv.AdvisoryId + 1
}
<|endoftext|>


<commit_before>package turnservicecli

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sync"
	"time"
)

const (
	requestTimeoutSeconds = 30
)

// A TURNCredentialsHandler is a function handler which can be registered to
// get called when the cached TURN credentials change.
type TURNCredentialsHandler func(*CachedCredentialsData, error)

// A TURNService provides the TURN service remote API.
type TURNService struct {
	sync.RWMutex

	uri                  string
	tlsConfig            *tls.Config
	expirationPercentile uint

	session     string
	accessToken string
	clientID    string

	credentials *CachedCredentialsData
	err         error
	autorefresh bool

	handlers []TURNCredentialsHandler
	refresh  chan bool
	quit     chan bool
}

// NewTURNService creates a TURNService.
func NewTURNService(uri string, expirationPercentile uint, tlsConfig *tls.Config) *TURNService {
	if expirationPercentile == 0 {
		expirationPercentile = 80
	}
	if tlsConfig == nil {
		tlsConfig = &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(0),
			InsecureSkipVerify: false,
		}
	}

	service := &TURNService{
		uri:                  uri,
		tlsConfig:            tlsConfig,
		expirationPercentile: expirationPercentile,
		quit:                 make(chan bool),
		refresh:              make(chan bool, 1),
	}
	go func() {
		// Check for refresh every minute.
		ticker := time.NewTicker(1 * time.Minute)
		autorefresh := false
		for {
			select {
			case <-service.quit:
				ticker.Stop()
				return
			case <-service.refresh:
			case <-ticker.C:
			}

			service.RLock()
			autorefresh = service.autorefresh
			service.RUnlock()
			if autorefresh {
				service.Credentials(true)
			}
		}
	}()

	return service
}

// Open sets the data to use for requests to the TURNService.
func (service *TURNService) Open(accessToken, clientID, session string) {
	service.Lock()
	defer service.Unlock()
	service.accessToken = accessToken
	service.clientID = clientID
	service.session = session
}

// Close expires all data and resets the data to use with the TURNService.
func (service *TURNService) Close() {
	service.Lock()
	defer service.Unlock()
	close(service.quit)
	if service.credentials != nil {
		service.credentials.Close()
	}
	service.accessToken = ""
	service.clientID = ""
	service.session = ""
}

// Autorefresh enables or disables automatic refresh of TURNService credentials.
func (service *TURNService) Autorefresh(autorefresh bool) {
	service.Lock()
	defer service.Unlock()
	if autorefresh == service.autorefresh {
		return
	}
	service.autorefresh = autorefresh
	if autorefresh {
		// Trigger instant refresh, do not care if already pending.
		select {
		case service.refresh <- true:
		default:
		}
	}
}

// BindOnCredentials triggeres whenever new TURN credentials become available.
func (service *TURNService) BindOnCredentials(h TURNCredentialsHandler) {
	service.Lock()
	defer service.Unlock()
	service.handlers = append(service.handlers, h)
}

// Credentials implements the credentials API call to the TURNService returning
// cached credential data when those are not yet expired.
func (service *TURNService) Credentials(fetch bool) *CachedCredentialsData {
	service.RLock()
	credentials := service.credentials
	accessToken := service.accessToken
	clientID := service.clientID
	session := service.session
	service.RUnlock()

	var err error
	var fetched bool
	var response *CredentialsResponse

	if credentials == nil {
		// No credentials.
		if !fetch {
			return nil
		}

		service.Lock()
		defer service.Unlock()
		if service.credentials == nil {
			response, err = service.fetchCredentials(accessToken, clientID, session)
			if err != nil {
				service.err = err
			}
			fetched = true
		} else {
			credentials = service.credentials
		}
	} else {
		if credentials.Expired() {
			// Expired credentials.
			if fetch {
				service.Lock()
				defer service.Unlock()
				if service.credentials == nil || service.credentials.Expired() {
					response, err = service.fetchCredentials(accessToken, clientID, session)
					service.err = err
				} else {
					credentials = service.credentials
				}
				fetched = true
			} else {
				credentials = nil
			}
		}
	}

	if response != nil && err == nil {
		credentials = NewCachedCredentialsData(response.Turn, service.expirationPercentile)
		// Already locked from above if response is not nil.
		service.credentials = credentials
		service.session = response.Session
	}

	if fetched {
		// Trigger registered handlers.
		for _, h := range service.handlers {
			go h(credentials, err)
		}
	}

	return credentials
}

// LastError returns the last occured Error if any.
func (service *TURNService) LastError() error {
	service.RLock()
	defer service.RUnlock()
	return service.err
}

// FetchCredentials fetches new TURN credentials via the remote service.
func (service *TURNService) FetchCredentials() (*CredentialsResponse, error) {
	service.RLock()
	accessToken := service.accessToken
	clientID := service.clientID
	session := service.session
	service.RUnlock()

	return service.fetchCredentials(accessToken, clientID, session)
}

func (service *TURNService) fetchCredentials(accessToken, clientID, session string) (*CredentialsResponse, error) {
	if accessToken == "" && clientID == "" {
		return nil, fmt.Errorf("missign one of accessToken/clientId")
	}

	var body *bytes.Buffer
	nonce, err := makeNonce()
	if err != nil {
		return nil, fmt.Errorf("failed to make nonce: %s", err.Error())
	}

	data := url.Values{}
	data.Set("nonce", nonce)
	data.Set("client_id", clientID)
	auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", accessToken, session)))
	body = bytes.NewBufferString(data.Encode())

	request, err := http.NewRequest("POST", fmt.Sprintf("%s/api/v1/turn/credentials", service.uri), body)
	if err != nil {
		return nil, err
	}

	request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", auth))
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	transport := &http.Transport{
		Proxy:               http.ProxyFromEnvironment,
		TLSClientConfig:     service.tlsConfig,
		TLSHandshakeTimeout: time.Second * requestTimeoutSeconds,
	}

	client := &http.Client{
		Transport: transport,
	}

	result, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	defer result.Body.Close()

	switch result.StatusCode {
	case http.StatusOK:
		// Success.
	case http.StatusForbidden:
		content, _ := ioutil.ReadAll(result.Body)
		return nil, fmt.Errorf("forbidden: %s", content)
	default:
		return nil, fmt.Errorf("credentials return wrong status: %d", result.StatusCode)
	}

	var response CredentialsResponse
	err = json.NewDecoder(result.Body).Decode(&response)
	if err != nil {
		return nil, err
	}

	if !response.Success {
		return &response, fmt.Errorf("credentials response unsuccessfull")
	}

	if response.Nonce != nonce {
		return &response, fmt.Errorf("nonce mismatch")
	}

	return &response, nil
}
<commit_msg>Still return credentials that are about to expire.<commit_after>package turnservicecli

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sync"
	"time"
)

const (
	requestTimeoutSeconds = 30

	// Still return "expired" credentials if they are valid for at least this
	// many seconds (but trigger refresh).
	minCredentialsTTL = 10
)

// A TURNCredentialsHandler is a function handler which can be registered to
// get called when the cached TURN credentials change.
type TURNCredentialsHandler func(*CachedCredentialsData, error)

// A TURNService provides the TURN service remote API.
type TURNService struct {
	sync.RWMutex

	uri                  string
	tlsConfig            *tls.Config
	expirationPercentile uint

	session     string
	accessToken string
	clientID    string

	credentials *CachedCredentialsData
	err         error
	autorefresh bool

	handlers []TURNCredentialsHandler
	refresh  chan bool
	quit     chan bool
}

// NewTURNService creates a TURNService.
func NewTURNService(uri string, expirationPercentile uint, tlsConfig *tls.Config) *TURNService {
	if expirationPercentile == 0 {
		expirationPercentile = 80
	}
	if tlsConfig == nil {
		tlsConfig = &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(0),
			InsecureSkipVerify: false,
		}
	}

	service := &TURNService{
		uri:                  uri,
		tlsConfig:            tlsConfig,
		expirationPercentile: expirationPercentile,
		quit:                 make(chan bool),
		refresh:              make(chan bool, 1),
	}
	go func() {
		// Check for refresh every minute.
		ticker := time.NewTicker(1 * time.Minute)
		autorefresh := false
		for {
			select {
			case <-service.quit:
				ticker.Stop()
				return
			case <-service.refresh:
			case <-ticker.C:
			}

			service.RLock()
			autorefresh = service.autorefresh
			service.RUnlock()
			if autorefresh {
				service.Credentials(true)
			}
		}
	}()

	return service
}

// Open sets the data to use for requests to the TURNService.
func (service *TURNService) Open(accessToken, clientID, session string) {
	service.Lock()
	defer service.Unlock()
	service.accessToken = accessToken
	service.clientID = clientID
	service.session = session
}

// Close expires all data and resets the data to use with the TURNService.
func (service *TURNService) Close() {
	service.Lock()
	defer service.Unlock()
	close(service.quit)
	if service.credentials != nil {
		service.credentials.Close()
	}
	service.accessToken = ""
	service.clientID = ""
	service.session = ""
}

func (service *TURNService) scheduleRefresh() {
	select {
	case service.refresh <- true:
	default:
	}
}

// Autorefresh enables or disables automatic refresh of TURNService credentials.
func (service *TURNService) Autorefresh(autorefresh bool) {
	service.Lock()
	defer service.Unlock()
	if autorefresh == service.autorefresh {
		return
	}
	service.autorefresh = autorefresh
	if autorefresh {
		// Trigger instant refresh, do not care if already pending.
		service.scheduleRefresh()
	}
}

// BindOnCredentials triggeres whenever new TURN credentials become available.
func (service *TURNService) BindOnCredentials(h TURNCredentialsHandler) {
	service.Lock()
	defer service.Unlock()
	service.handlers = append(service.handlers, h)
}

// Credentials implements the credentials API call to the TURNService returning
// cached credential data when those are not yet expired.
func (service *TURNService) Credentials(fetch bool) *CachedCredentialsData {
	service.RLock()
	credentials := service.credentials
	accessToken := service.accessToken
	clientID := service.clientID
	session := service.session
	service.RUnlock()

	var err error
	var fetched bool
	var response *CredentialsResponse

	if credentials == nil {
		// No credentials.
		if !fetch {
			return nil
		}

		service.Lock()
		defer service.Unlock()
		if service.credentials == nil {
			response, err = service.fetchCredentials(accessToken, clientID, session)
			if err != nil {
				service.err = err
			}
			fetched = true
		} else {
			credentials = service.credentials
		}
	} else {
		if credentials.Expired() {
			// Expired credentials.
			if fetch {
				service.Lock()
				defer service.Unlock()
				if service.credentials == nil || service.credentials.Expired() {
					response, err = service.fetchCredentials(accessToken, clientID, session)
					service.err = err
				} else {
					credentials = service.credentials
				}
				fetched = true
			} else if credentials.TTL() >= minCredentialsTTL {
				// Credentials are about to expire, schedule refresh
				service.scheduleRefresh()
			} else {
				credentials = nil
			}
		}
	}

	if response != nil && err == nil {
		credentials = NewCachedCredentialsData(response.Turn, service.expirationPercentile)
		// Already locked from above if response is not nil.
		service.credentials = credentials
		service.session = response.Session
	}

	if fetched {
		// Trigger registered handlers.
		for _, h := range service.handlers {
			go h(credentials, err)
		}
	}

	return credentials
}

// LastError returns the last occured Error if any.
func (service *TURNService) LastError() error {
	service.RLock()
	defer service.RUnlock()
	return service.err
}

// FetchCredentials fetches new TURN credentials via the remote service.
func (service *TURNService) FetchCredentials() (*CredentialsResponse, error) {
	service.RLock()
	accessToken := service.accessToken
	clientID := service.clientID
	session := service.session
	service.RUnlock()

	return service.fetchCredentials(accessToken, clientID, session)
}

func (service *TURNService) fetchCredentials(accessToken, clientID, session string) (*CredentialsResponse, error) {
	if accessToken == "" && clientID == "" {
		return nil, fmt.Errorf("missign one of accessToken/clientId")
	}

	var body *bytes.Buffer
	nonce, err := makeNonce()
	if err != nil {
		return nil, fmt.Errorf("failed to make nonce: %s", err.Error())
	}

	data := url.Values{}
	data.Set("nonce", nonce)
	data.Set("client_id", clientID)
	auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", accessToken, session)))
	body = bytes.NewBufferString(data.Encode())

	request, err := http.NewRequest("POST", fmt.Sprintf("%s/api/v1/turn/credentials", service.uri), body)
	if err != nil {
		return nil, err
	}

	request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", auth))
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	transport := &http.Transport{
		Proxy:               http.ProxyFromEnvironment,
		TLSClientConfig:     service.tlsConfig,
		TLSHandshakeTimeout: time.Second * requestTimeoutSeconds,
	}

	client := &http.Client{
		Transport: transport,
	}

	result, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	defer result.Body.Close()

	switch result.StatusCode {
	case http.StatusOK:
		// Success.
	case http.StatusForbidden:
		content, _ := ioutil.ReadAll(result.Body)
		return nil, fmt.Errorf("forbidden: %s", content)
	default:
		return nil, fmt.Errorf("credentials return wrong status: %d", result.StatusCode)
	}

	var response CredentialsResponse
	err = json.NewDecoder(result.Body).Decode(&response)
	if err != nil {
		return nil, err
	}

	if !response.Success {
		return &response, fmt.Errorf("credentials response unsuccessfull")
	}

	if response.Nonce != nonce {
		return &response, fmt.Errorf("nonce mismatch")
	}

	return &response, nil
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"time"
)

const (
	apiPurchasesByUsername = "purchases/by_user/%s?limit=%d"
	apiPurchasesByProduct  = "purchases/by_product/%d?limit=%d"
)

// Purchases models contains information about
// multiple orders of a product / products.
type Purchases []Purchase

// purchasesData is a type that's used for representation of
// Purchases by the third party API.
type purchasesData struct {
	Data Purchases `json:"purchases"`
}

// Purchase type represents information a single order.
type Purchase struct {
	ID        int       `json:"id,omitempty"`
	ProductID int       `json:"product_id"`
	Username  string    `json:"username"`
	Date      time.Time `json:"date,omitempty"`
}

// PurchasesByUsername gets a username and a limit number as input
// arguments and returns a list of purchases that belong to the
// related user.
// NB: According to the gdocs the API must return the most recent purchases
// (i.e. they are sorted by the date).
// Service "daw-purchases" by-default returns a random unsorted data instead.
func PurchasesByUsername(username string, limit uint) (Purchases, error) {
	// Get the user's recent purchases.
	var d purchasesData
	err := objectFromURN(fmt.Sprintf(apiPurchasesByUsername, username, limit), &d)
	if err != nil {
		return nil, err
	}
	return d.Data, nil
}

// PurchasesByProductID gets an ID of a product and a limit number as
// input arguments and returns a list of all purchases of the product.
func PurchasesByProductID(id int, limit uint) (Purchases, error) {
	var d purchasesData
	err := objectFromURN(fmt.Sprintf(apiPurchasesByProduct, id, limit), &d)
	if err != nil {
		return nil, err
	}
	return d.Data, nil
}

// CustomerUsernames returns a slice of usernames the purchases' customers.
// Every username is unique, there are no repetitions.
func (m Purchases) CustomerUsernames() (us []string) {
	check := map[string]bool{}
	for i := range m {
		// Ignore the username we have already added to the list.
		if check[m[i].Username] {
			continue
		}
		us = append(us, m[i].Username)
		check[m[i].Username] = true
	}
	return
}

// Popular allocates and returns a new PopularPurchase.
// NB: This function is not atomic.
func (m Purchase) Popular(limit uint) (*PopularPurchase, error) {
	// Try to get product info.
	p, err := ProductByID(m.ProductID)
	if err != nil {
		return nil, err
	}
	// Try to get buyers of the product (aka customers).
	cs, err := PurchasesByProductID(m.ProductID, limit)
	if err != nil {
		return nil, err
	}
	return &PopularPurchase{
		ID:      m.ID,
		Product: p,
		Recent:  cs.CustomerUsernames(),
	}, nil
}

// Popular allocates and returns new PopularPurchases.
// NB: This function is not atomic.
func (m Purchases) Popular(limit uint) (ps PopularPurchases, err error) {
	for i := range m {
		p, err := m[i].Popular(limit)
		if err != nil {
			return nil, err
		}
		ps = append(ps, *p)
	}
	return
}
<commit_msg>Remote API uses 'productId' key not 'product_id'<commit_after>package models

import (
	"fmt"
	"time"
)

const (
	apiPurchasesByUsername = "purchases/by_user/%s?limit=%d"
	apiPurchasesByProduct  = "purchases/by_product/%d?limit=%d"
)

// Purchases models contains information about
// multiple orders of a product / products.
type Purchases []Purchase

// purchasesData is a type that's used for representation of
// Purchases by the third party API.
type purchasesData struct {
	Data Purchases `json:"purchases"`
}

// Purchase type represents information a single order.
type Purchase struct {
	ID        int       `json:"id,omitempty"`
	ProductID int       `json:"productId"`
	Username  string    `json:"username"`
	Date      time.Time `json:"date,omitempty"`
}

// PurchasesByUsername gets a username and a limit number as input
// arguments and returns a list of purchases that belong to the
// related user.
// NB: According to the gdocs the API must return the most recent purchases
// (i.e. they are sorted by the date).
// Service "daw-purchases" by-default returns a random unsorted data instead.
func PurchasesByUsername(username string, limit uint) (Purchases, error) {
	// Get the user's recent purchases.
	var d purchasesData
	err := objectFromURN(fmt.Sprintf(apiPurchasesByUsername, username, limit), &d)
	if err != nil {
		return nil, err
	}
	return d.Data, nil
}

// PurchasesByProductID gets an ID of a product and a limit number as
// input arguments and returns a list of all purchases of the product.
func PurchasesByProductID(id int, limit uint) (Purchases, error) {
	var d purchasesData
	err := objectFromURN(fmt.Sprintf(apiPurchasesByProduct, id, limit), &d)
	if err != nil {
		return nil, err
	}
	return d.Data, nil
}

// CustomerUsernames returns a slice of usernames the purchases' customers.
// Every username is unique, there are no repetitions.
func (m Purchases) CustomerUsernames() (us []string) {
	check := map[string]bool{}
	for i := range m {
		// Ignore the username we have already added to the list.
		if check[m[i].Username] {
			continue
		}
		us = append(us, m[i].Username)
		check[m[i].Username] = true
	}
	return
}

// Popular allocates and returns a new PopularPurchase.
// NB: This function is not atomic.
func (m Purchase) Popular(limit uint) (*PopularPurchase, error) {
	// Try to get product info.
	p, err := ProductByID(m.ProductID)
	if err != nil {
		return nil, err
	}
	// Try to get buyers of the product (aka customers).
	cs, err := PurchasesByProductID(m.ProductID, limit)
	if err != nil {
		return nil, err
	}
	return &PopularPurchase{
		ID:      m.ID,
		Product: p,
		Recent:  cs.CustomerUsernames(),
	}, nil
}

// Popular allocates and returns new PopularPurchases.
// NB: This function is not atomic.
func (m Purchases) Popular(limit uint) (ps PopularPurchases, err error) {
	for i := range m {
		p, err := m[i].Popular(limit)
		if err != nil {
			return nil, err
		}
		ps = append(ps, *p)
	}
	return
}
<|endoftext|>


<commit_before>package trivial

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/goyaml"
	"os"
)

// WriteYaml marshals obj as yaml and then writes it to a file, atomically,
// by first writing a sibling with the suffix ".preparing" and then moving
// the sibling to the real path.
func WriteYaml(path string, obj interface{}) error {
	data, err := goyaml.Marshal(obj)
	if err != nil {
		return err
	}
	prep := path + ".preparing"
	f, err := os.OpenFile(prep, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	if _, err = f.Write(data); err != nil {
		return err
	}
	return os.Rename(prep, path)
}

// ReadYaml unmarshals the yaml contained in the file at path into obj. See
// goyaml.Unmarshal.
func ReadYaml(path string, obj interface{}) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	return goyaml.Unmarshal(data, obj)
}

// ErrorContextf prefixes any error stored in err with text formatted
// according to the format specifier. If err does not contain an error,
// ErrorContextf does nothing.
func ErrorContextf(err *error, format string, args ...interface{}) {
	if *err != nil {
		*err = errors.New(fmt.Sprintf(format, args...) + ": " + (*err).Error())
	}
}
<commit_msg>trivial: add ShQuote<commit_after>package trivial

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/goyaml"
	"os"
	"strings"
)

// WriteYaml marshals obj as yaml and then writes it to a file, atomically,
// by first writing a sibling with the suffix ".preparing" and then moving
// the sibling to the real path.
func WriteYaml(path string, obj interface{}) error {
	data, err := goyaml.Marshal(obj)
	if err != nil {
		return err
	}
	prep := path + ".preparing"
	f, err := os.OpenFile(prep, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	if _, err = f.Write(data); err != nil {
		return err
	}
	return os.Rename(prep, path)
}

// ReadYaml unmarshals the yaml contained in the file at path into obj. See
// goyaml.Unmarshal.
func ReadYaml(path string, obj interface{}) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	return goyaml.Unmarshal(data, obj)
}

// ErrorContextf prefixes any error stored in err with text formatted
// according to the format specifier. If err does not contain an error,
// ErrorContextf does nothing.
func ErrorContextf(err *error, format string, args ...interface{}) {
	if *err != nil {
		*err = errors.New(fmt.Sprintf(format, args...) + ": " + (*err).Error())
	}
}

// ShQuote quotes s so that when read by bash, no metacharacters
// within s will be interpreted as such.
func ShQuote(s string) string {
	// single-quote becomes single-quote, double-quote, single-quote, double-quote, single-quote
	return `'` + strings.Replace(s, `'`, `'"'"'`, -1) + `'`
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-martini/martini"
	"log"
	"net/http"
)

func main() {
	m := martini.Classic()
	//中间件处理器是工作于请求和路由之间的. 本质上来说和Martini其他的处理器没有分别.
	/*
		你可以通过Handlers函数对中间件堆有完全的控制. 它将会替换掉之前的任何设置过的处理器
		m.Handlers(
		  Middleware1,
		  Middleware2,
		  Middleware3,
		)
		中间件处理器可以非常好处理一些功能，像logging(日志), authorization(授权), authentication(认证), sessions(会话), error pages(错误页面),
		以及任何其他的操作需要在http请求发生之前或者之后的:
	*/
	// 验证api密匙
	// m.Use(func(res http.ResponseWriter, req *http.Request) {
	// 	if req.Header.Get("X-API-KEY") != "secret123" {
	// 		res.WriteHeader(http.StatusUnauthorized)
	// 	}
	// })

	//Context.Next()是一个可选的函数用于中间件处理器暂时放弃执行直到其他的处理器都执行完毕. 这样就可以很好的处理在http请求完成后需要做的操作.
	// log 记录请求完成前后  (*译者注: 很巧妙，掌声鼓励.)
	m.Use(func(c martini.Context, log *log.Logger) {
		log.Println("before a request")

		c.Next()

		log.Println("after a request")
	})

	//路由匹配的顺序是按照他们被定义的顺序执行的. 最先被定义的路由将会首先被用户请求匹配并调用
	m.Get("/", func() (int, string) {
		return 418, "I'm a teaport" //状态码418
	})

	m.Patch("/", func() {
		// 更新
	})

	m.Post("/", func() {
		// 创建
	})

	m.Put("/", func() {
		// 替换
	})

	m.Delete("/", func() {
		// 删除
	})

	m.Options("/", func() {
		// http 选项
	})

	m.NotFound(func() {
		// 处理 404
	})

	//路由模型可能包含参数列表, 可以通过martini.Params服务来获取
	m.Get("/hello/:name", func(params martini.Params) string {
		return "Hello " + params["name"]
	})

	//路由匹配可以通过正则表达式或者glob的形式
	m.Get("/hello2/**", func(params martini.Params) string {
		log.Println("hello2")
		return "Hello " + params["_1"]
	})

	//martini整合到现有服务当中
	http.Handle("/", m)
	//m.Run()
	//修改端口
	http.ListenAndServe(":8080", m)
}
<commit_msg>martini的auth<commit_after>package main

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/auth"
	"log"
	"net/http"
)

func main() {
	m := martini.Classic()
	//中间件处理器是工作于请求和路由之间的. 本质上来说和Martini其他的处理器没有分别.
	/*
		你可以通过Handlers函数对中间件堆有完全的控制. 它将会替换掉之前的任何设置过的处理器
		m.Handlers(
		  Middleware1,
		  Middleware2,
		  Middleware3,
		)
		中间件处理器可以非常好处理一些功能，像logging(日志), authorization(授权), authentication(认证), sessions(会话), error pages(错误页面),
		以及任何其他的操作需要在http请求发生之前或者之后的:
	*/
	// 验证api密匙
	// m.Use(func(res http.ResponseWriter, req *http.Request) {
	// 	if req.Header.Get("X-API-KEY") != "secret123" {
	// 		res.WriteHeader(http.StatusUnauthorized)
	// 	}
	// })

	//Context.Next()是一个可选的函数用于中间件处理器暂时放弃执行直到其他的处理器都执行完毕. 这样就可以很好的处理在http请求完成后需要做的操作.
	// log 记录请求完成前后  (*译者注: 很巧妙，掌声鼓励.)
	m.Use(func(c martini.Context, log *log.Logger) {
		log.Println("before a request")

		c.Next()

		log.Println("after a request")
	})

	m.Use(auth.Basic("test", "123"))

	//路由匹配的顺序是按照他们被定义的顺序执行的. 最先被定义的路由将会首先被用户请求匹配并调用
	m.Get("/", func() (int, string) {
		return 418, "I'm a teaport" //状态码418
	})

	m.Patch("/", func() {
		// 更新
	})

	m.Post("/", func() {
		// 创建
	})

	m.Put("/", func() {
		// 替换
	})

	m.Delete("/", func() {
		// 删除
	})

	m.Options("/", func() {
		// http 选项
	})

	m.NotFound(func() {
		// 处理 404
	})

	//路由模型可能包含参数列表, 可以通过martini.Params服务来获取
	m.Get("/hello/:name", func(params martini.Params) string {
		return "Hello " + params["name"]
	})

	//路由匹配可以通过正则表达式或者glob的形式
	m.Get("/hello2/**", func(params martini.Params) string {
		log.Println("hello2")
		return "Hello " + params["_1"]
	})

	//martini整合到现有服务当中
	http.Handle("/", m)
	//m.Run()
	//修改端口
	http.ListenAndServe(":8080", m)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"hge"
)

var h *hge.HGE

func FrameFunc() int {
	if h.Input_GetKeyState(hge.K_ESCAPE) {
		return 1
	}

	return 0
}

func main() {
	h = hge.Create(hge.VERSION)
	defer h.Release()

	h.System_SetState(hge.FRAMEFUNC, FrameFunc)
	h.System_SetState(hge.TITLE, "HGE Tutorial 01 - Minimal HGE application")
	h.System_SetState(hge.WINDOWED, true)
	h.System_SetState(hge.USESOUND, false)

	h.System_Log("Test")
	h.System_Log("Test vararg: %s %d", "test", 15)

	if h.System_Initiate() {
		defer h.System_Shutdown()
		h.System_Log("Test")
		h.System_Log("Test vararg: %s %d", "test", 15)
		h.System_Start()
	} else {
		fmt.Println("Error: ", h.System_GetErrorMessage())
	}

	h.System_Log("Test")
}
<commit_msg>Add a logfile for tutorial01<commit_after>package main

import (
	"fmt"
	"hge"
)

var h *hge.HGE

func FrameFunc() int {
	if h.Input_GetKeyState(hge.K_ESCAPE) {
		return 1
	}

	return 0
}

func main() {
	h = hge.Create(hge.VERSION)
	defer h.Release()

	h.System_SetState(hge.LOGFILE, "tutorial01.log")
	h.System_SetState(hge.FRAMEFUNC, FrameFunc)
	h.System_SetState(hge.TITLE, "HGE Tutorial 01 - Minimal HGE application")
	h.System_SetState(hge.WINDOWED, true)
	h.System_SetState(hge.USESOUND, false)

	h.System_Log("Test")
	h.System_Log("Test vararg: %s %d", "test", 15)

	if h.System_Initiate() {
		defer h.System_Shutdown()
		h.System_Log("Test")
		h.System_Log("Test vararg: %s %d", "test", 15)
		h.System_Start()
	} else {
		fmt.Println("Error: ", h.System_GetErrorMessage())
	}

	h.System_Log("Test")
}
<|endoftext|>