<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"path/filepath"
	"strings"

	realio "io/ioutil"
	realos "os"

	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/configuration/confighelpers"
	"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
	"github.com/cloudfoundry/cli/plugin"
)

type TargetsPlugin struct {
	configPath  string
	targetsPath string
	currentPath string
	suffix      string
	status      TargetStatus
}

type TargetStatus struct {
	currentHasName     bool
	currentName        string
	currentNeedsSaving bool
	currentNeedsUpdate bool
}

type RealOS struct{}
type OS interface {
	Exit(int)
	Mkdir(string, realos.FileMode)
	Remove(string)
	Symlink(string, string) error
	ReadDir(string) ([]realos.FileInfo, error)
	ReadFile(string) ([]byte, error)
	WriteFile(string, []byte, realos.FileMode) error
}

func (*RealOS) Exit(code int)                                  { realos.Exit(code) }
func (*RealOS) Mkdir(path string, mode realos.FileMode)        { realos.Mkdir(path, mode) }
func (*RealOS) Remove(path string)                             { realos.Remove(path) }
func (*RealOS) Symlink(target string, source string) error     { return realos.Symlink(target, source) }
func (*RealOS) ReadDir(path string) ([]realos.FileInfo, error) { return realio.ReadDir(path) }
func (*RealOS) ReadFile(path string) ([]byte, error)           { return realio.ReadFile(path) }
func (*RealOS) WriteFile(path string, content []byte, mode realos.FileMode) error {
	return realio.WriteFile(path, content, mode)
}

var os OS

func newTargetsPlugin() *TargetsPlugin {
	configPath, _ := confighelpers.DefaultFilePath()
	targetsPath := filepath.Join(filepath.Dir(configPath), "targets")
	os.Mkdir(targetsPath, 0700)
	return &TargetsPlugin{
		configPath:  configPath,
		targetsPath: targetsPath,
		currentPath: filepath.Join(targetsPath, "current"),
		suffix:      "." + filepath.Base(configPath),
	}
}

func (c *TargetsPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "cf-targets",
		Version: plugin.VersionType{
			Major: 1,
			Minor: 0,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "targets",
				HelpText: "List available targets",
				UsageDetails: plugin.Usage{
					Usage: "cf targets",
				},
			},
			{
				Name:     "set-target",
				HelpText: "Set current target",
				UsageDetails: plugin.Usage{
					Usage: "cf set-target [-f] NAME",
					Options: map[string]string{
						"f": "replace the current target even if it has not been saved",
					},
				},
			},
			{
				Name:     "save-target",
				HelpText: "Save current target",
				UsageDetails: plugin.Usage{
					Usage: "cf save-target [-f] [NAME]",
					Options: map[string]string{
						"f": "save the target even if the specified name already exists",
					},
				},
			},
			{
				Name:     "delete-target",
				HelpText: "Delete a saved target",
				UsageDetails: plugin.Usage{
					Usage: "cf delete-target NAME",
				},
			},
		},
	}
}

func main() {
	os = &RealOS{}
	plugin.Start(newTargetsPlugin())
}

func (c *TargetsPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	defer func() {
		reason := recover()
		if code, ok := reason.(int); ok {
			os.Exit(code)
		} else if reason != nil {
			panic(reason)
		}
	}()

	c.checkStatus()
	if args[0] == "targets" {
		c.TargetsCommand(args)
	} else if args[0] == "set-target" {
		c.SetTargetCommand(args)
	} else if args[0] == "save-target" {
		c.SaveTargetCommand(args)
	} else if args[0] == "delete-target" {
		c.DeleteTargetCommand(args)
	}
}

func (c *TargetsPlugin) TargetsCommand(args []string) {
	if len(args) != 1 {
		c.exitWithUsage("targets")
	}
	targets := c.getTargets()
	if len(targets) < 1 {
		fmt.Println("No targets have been saved yet. To save the current target, use:")
		fmt.Println("   cf save-target NAME")
	} else {
		for _, target := range targets {
			var qualifier string
			if c.isCurrent(target) {
				qualifier = "(current"
				if c.status.currentNeedsSaving {
					qualifier += ", modified"
				} else if c.status.currentNeedsUpdate {
					qualifier += "*"
				}
				qualifier += ")"
			}
			fmt.Println(target, qualifier)
		}
	}
}

func (c *TargetsPlugin) SetTargetCommand(args []string) {
	flagSet := flag.NewFlagSet("set-target", flag.ContinueOnError)
	force := flagSet.Bool("f", false, "force")
	err := flagSet.Parse(args[1:])
	if err != nil || len(flagSet.Args()) != 1 {
		c.exitWithUsage("set-target")
	}
	targetName := flagSet.Arg(0)
	targetPath := c.targetPath(targetName)
	if !c.targetExists(targetPath) {
		fmt.Println("Target", targetName, "does not exist.")
		panic(1)
	}
	if *force || !c.status.currentNeedsSaving {
		c.copyContents(targetPath, c.configPath)
		c.linkCurrent(targetPath)
	} else {
		fmt.Println("Your current target has not been saved. Use save-target first, or use -f to discard your changes.")
		panic(1)
	}
	fmt.Println("Set target to", targetName)
}

func (c *TargetsPlugin) SaveTargetCommand(args []string) {
	flagSet := flag.NewFlagSet("save-target", flag.ContinueOnError)
	force := flagSet.Bool("f", false, "force")
	err := flagSet.Parse(args[1:])
	if err != nil || len(flagSet.Args()) > 1 {
		c.exitWithUsage("save-target")
	}
	if len(flagSet.Args()) < 1 {
		c.SaveCurrentTargetCommand(*force)
	} else {
		c.SaveNamedTargetCommand(flagSet.Arg(0), *force)
	}
}

func (c *TargetsPlugin) SaveNamedTargetCommand(targetName string, force bool) {
	targetPath := c.targetPath(targetName)
	if force || !c.targetExists(targetPath) {
		c.copyContents(c.configPath, targetPath)
		c.linkCurrent(targetPath)
	} else {
		fmt.Println("Target", targetName, "already exists. Use -f to overwrite it.")
		panic(1)
	}
	fmt.Println("Saved current target as", targetName)
}

func (c *TargetsPlugin) SaveCurrentTargetCommand(force bool) {
	if !c.status.currentHasName {
		fmt.Println("Current target has not been previously saved. Please provide a name.")
		panic(1)
	}
	targetName := c.status.currentName
	targetPath := c.targetPath(targetName)
	if c.status.currentNeedsSaving && !force {
		fmt.Println("You've made substantial changes to the current target.")
		fmt.Println("Use -f if you intend to overwrite the target named", targetName, "or provide an alternate name")
		panic(1)
	}
	c.copyContents(c.configPath, targetPath)
	fmt.Println("Saved current target as", targetName)
}

func (c *TargetsPlugin) DeleteTargetCommand(args []string) {
	if len(args) != 2 {
		c.exitWithUsage("delete-target")
	}
	targetName := args[1]
	targetPath := c.targetPath(targetName)
	if !c.targetExists(targetPath) {
		fmt.Println("Target", targetName, "does not exist")
		panic(1)
	}
	os.Remove(targetPath)
	if c.isCurrent(targetName) {
		os.Remove(c.currentPath)
	}
	fmt.Println("Deleted target", targetName)
}

func (c *TargetsPlugin) getTargets() []string {
	var targets []string
	files, _ := os.ReadDir(c.targetsPath)
	for _, file := range files {
		filename := file.Name()
		if strings.HasSuffix(filename, c.suffix) {
			targets = append(targets, strings.TrimSuffix(filename, c.suffix))
		}
	}
	return targets
}

func (c *TargetsPlugin) targetExists(targetPath string) bool {
	target := configuration.NewDiskPersistor(targetPath)
	return target.Exists()
}

func (c *TargetsPlugin) checkStatus() {
	currentConfig := configuration.NewDiskPersistor(c.configPath)
	currentTarget := configuration.NewDiskPersistor(c.currentPath)
	if !currentTarget.Exists() {
		os.Remove(c.currentPath)
		c.status = TargetStatus{false, "", true, false}
		return
	}

	name := c.getCurrent()

	configData := coreconfig.NewData()
	targetData := coreconfig.NewData()

	err := currentConfig.Load(configData)
	c.checkError(err)
	err = currentTarget.Load(targetData)
	c.checkError(err)

	// Ignore the access-token field, as it changes frequently
	needsUpdate := targetData.AccessToken != configData.AccessToken
	targetData.AccessToken = configData.AccessToken

	currentContent, err := configData.JSONMarshalV3()
	c.checkError(err)
	savedContent, err := targetData.JSONMarshalV3()
	c.checkError(err)
	c.status = TargetStatus{true, name, !bytes.Equal(currentContent, savedContent), needsUpdate}
}

func (c *TargetsPlugin) copyContents(sourcePath, targetPath string) {
	content, err := os.ReadFile(sourcePath)
	c.checkError(err)
	err = os.WriteFile(targetPath, content, 0600)
	c.checkError(err)
}

func (c *TargetsPlugin) linkCurrent(targetPath string) {
	os.Remove(c.currentPath)
	err := os.Symlink(targetPath, c.currentPath)
	c.checkError(err)
}

func (c *TargetsPlugin) targetPath(targetName string) string {
	return filepath.Join(c.targetsPath, targetName+c.suffix)
}

func (c *TargetsPlugin) checkError(err error) {
	if err != nil {
		fmt.Println("Error:", err)
		panic(1)
	}
}

func (c *TargetsPlugin) exitWithUsage(command string) {
	metadata := c.GetMetadata()
	for _, candidate := range metadata.Commands {
		if candidate.Name == command {
			fmt.Println("Usage: " + candidate.UsageDetails.Usage)
			panic(1)
		}
	}
}

func (c *TargetsPlugin) getCurrent() string {
	targetPath, err := filepath.EvalSymlinks(c.currentPath)
	c.checkError(err)
	return strings.TrimSuffix(filepath.Base(targetPath), c.suffix)
}

func (c *TargetsPlugin) isCurrent(target string) bool {
	return c.status.currentHasName && c.status.currentName == target
}
<commit_msg>Build version 1.2.0<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"path/filepath"
	"strings"

	realio "io/ioutil"
	realos "os"

	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/configuration/confighelpers"
	"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
	"github.com/cloudfoundry/cli/plugin"
)

type TargetsPlugin struct {
	configPath  string
	targetsPath string
	currentPath string
	suffix      string
	status      TargetStatus
}

type TargetStatus struct {
	currentHasName     bool
	currentName        string
	currentNeedsSaving bool
	currentNeedsUpdate bool
}

type RealOS struct{}
type OS interface {
	Exit(int)
	Mkdir(string, realos.FileMode)
	Remove(string)
	Symlink(string, string) error
	ReadDir(string) ([]realos.FileInfo, error)
	ReadFile(string) ([]byte, error)
	WriteFile(string, []byte, realos.FileMode) error
}

func (*RealOS) Exit(code int)                                  { realos.Exit(code) }
func (*RealOS) Mkdir(path string, mode realos.FileMode)        { realos.Mkdir(path, mode) }
func (*RealOS) Remove(path string)                             { realos.Remove(path) }
func (*RealOS) Symlink(target string, source string) error     { return realos.Symlink(target, source) }
func (*RealOS) ReadDir(path string) ([]realos.FileInfo, error) { return realio.ReadDir(path) }
func (*RealOS) ReadFile(path string) ([]byte, error)           { return realio.ReadFile(path) }
func (*RealOS) WriteFile(path string, content []byte, mode realos.FileMode) error {
	return realio.WriteFile(path, content, mode)
}

var os OS

func newTargetsPlugin() *TargetsPlugin {
	configPath, _ := confighelpers.DefaultFilePath()
	targetsPath := filepath.Join(filepath.Dir(configPath), "targets")
	os.Mkdir(targetsPath, 0700)
	return &TargetsPlugin{
		configPath:  configPath,
		targetsPath: targetsPath,
		currentPath: filepath.Join(targetsPath, "current"),
		suffix:      "." + filepath.Base(configPath),
	}
}

func (c *TargetsPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "cf-targets",
		Version: plugin.VersionType{
			Major: 1,
			Minor: 2,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "targets",
				HelpText: "List available targets",
				UsageDetails: plugin.Usage{
					Usage: "cf targets",
				},
			},
			{
				Name:     "set-target",
				HelpText: "Set current target",
				UsageDetails: plugin.Usage{
					Usage: "cf set-target [-f] NAME",
					Options: map[string]string{
						"f": "replace the current target even if it has not been saved",
					},
				},
			},
			{
				Name:     "save-target",
				HelpText: "Save current target",
				UsageDetails: plugin.Usage{
					Usage: "cf save-target [-f] [NAME]",
					Options: map[string]string{
						"f": "save the target even if the specified name already exists",
					},
				},
			},
			{
				Name:     "delete-target",
				HelpText: "Delete a saved target",
				UsageDetails: plugin.Usage{
					Usage: "cf delete-target NAME",
				},
			},
		},
	}
}

func main() {
	os = &RealOS{}
	plugin.Start(newTargetsPlugin())
}

func (c *TargetsPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	defer func() {
		reason := recover()
		if code, ok := reason.(int); ok {
			os.Exit(code)
		} else if reason != nil {
			panic(reason)
		}
	}()

	c.checkStatus()
	if args[0] == "targets" {
		c.TargetsCommand(args)
	} else if args[0] == "set-target" {
		c.SetTargetCommand(args)
	} else if args[0] == "save-target" {
		c.SaveTargetCommand(args)
	} else if args[0] == "delete-target" {
		c.DeleteTargetCommand(args)
	}
}

func (c *TargetsPlugin) TargetsCommand(args []string) {
	if len(args) != 1 {
		c.exitWithUsage("targets")
	}
	targets := c.getTargets()
	if len(targets) < 1 {
		fmt.Println("No targets have been saved yet. To save the current target, use:")
		fmt.Println("   cf save-target NAME")
	} else {
		for _, target := range targets {
			var qualifier string
			if c.isCurrent(target) {
				qualifier = "(current"
				if c.status.currentNeedsSaving {
					qualifier += ", modified"
				} else if c.status.currentNeedsUpdate {
					qualifier += "*"
				}
				qualifier += ")"
			}
			fmt.Println(target, qualifier)
		}
	}
}

func (c *TargetsPlugin) SetTargetCommand(args []string) {
	flagSet := flag.NewFlagSet("set-target", flag.ContinueOnError)
	force := flagSet.Bool("f", false, "force")
	err := flagSet.Parse(args[1:])
	if err != nil || len(flagSet.Args()) != 1 {
		c.exitWithUsage("set-target")
	}
	targetName := flagSet.Arg(0)
	targetPath := c.targetPath(targetName)
	if !c.targetExists(targetPath) {
		fmt.Println("Target", targetName, "does not exist.")
		panic(1)
	}
	if *force || !c.status.currentNeedsSaving {
		c.copyContents(targetPath, c.configPath)
		c.linkCurrent(targetPath)
	} else {
		fmt.Println("Your current target has not been saved. Use save-target first, or use -f to discard your changes.")
		panic(1)
	}
	fmt.Println("Set target to", targetName)
}

func (c *TargetsPlugin) SaveTargetCommand(args []string) {
	flagSet := flag.NewFlagSet("save-target", flag.ContinueOnError)
	force := flagSet.Bool("f", false, "force")
	err := flagSet.Parse(args[1:])
	if err != nil || len(flagSet.Args()) > 1 {
		c.exitWithUsage("save-target")
	}
	if len(flagSet.Args()) < 1 {
		c.SaveCurrentTargetCommand(*force)
	} else {
		c.SaveNamedTargetCommand(flagSet.Arg(0), *force)
	}
}

func (c *TargetsPlugin) SaveNamedTargetCommand(targetName string, force bool) {
	targetPath := c.targetPath(targetName)
	if force || !c.targetExists(targetPath) {
		c.copyContents(c.configPath, targetPath)
		c.linkCurrent(targetPath)
	} else {
		fmt.Println("Target", targetName, "already exists. Use -f to overwrite it.")
		panic(1)
	}
	fmt.Println("Saved current target as", targetName)
}

func (c *TargetsPlugin) SaveCurrentTargetCommand(force bool) {
	if !c.status.currentHasName {
		fmt.Println("Current target has not been previously saved. Please provide a name.")
		panic(1)
	}
	targetName := c.status.currentName
	targetPath := c.targetPath(targetName)
	if c.status.currentNeedsSaving && !force {
		fmt.Println("You've made substantial changes to the current target.")
		fmt.Println("Use -f if you intend to overwrite the target named", targetName, "or provide an alternate name")
		panic(1)
	}
	c.copyContents(c.configPath, targetPath)
	fmt.Println("Saved current target as", targetName)
}

func (c *TargetsPlugin) DeleteTargetCommand(args []string) {
	if len(args) != 2 {
		c.exitWithUsage("delete-target")
	}
	targetName := args[1]
	targetPath := c.targetPath(targetName)
	if !c.targetExists(targetPath) {
		fmt.Println("Target", targetName, "does not exist")
		panic(1)
	}
	os.Remove(targetPath)
	if c.isCurrent(targetName) {
		os.Remove(c.currentPath)
	}
	fmt.Println("Deleted target", targetName)
}

func (c *TargetsPlugin) getTargets() []string {
	var targets []string
	files, _ := os.ReadDir(c.targetsPath)
	for _, file := range files {
		filename := file.Name()
		if strings.HasSuffix(filename, c.suffix) {
			targets = append(targets, strings.TrimSuffix(filename, c.suffix))
		}
	}
	return targets
}

func (c *TargetsPlugin) targetExists(targetPath string) bool {
	target := configuration.NewDiskPersistor(targetPath)
	return target.Exists()
}

func (c *TargetsPlugin) checkStatus() {
	currentConfig := configuration.NewDiskPersistor(c.configPath)
	currentTarget := configuration.NewDiskPersistor(c.currentPath)
	if !currentTarget.Exists() {
		os.Remove(c.currentPath)
		c.status = TargetStatus{false, "", true, false}
		return
	}

	name := c.getCurrent()

	configData := coreconfig.NewData()
	targetData := coreconfig.NewData()

	err := currentConfig.Load(configData)
	c.checkError(err)
	err = currentTarget.Load(targetData)
	c.checkError(err)

	// Ignore the access-token field, as it changes frequently
	needsUpdate := targetData.AccessToken != configData.AccessToken
	targetData.AccessToken = configData.AccessToken

	currentContent, err := configData.JSONMarshalV3()
	c.checkError(err)
	savedContent, err := targetData.JSONMarshalV3()
	c.checkError(err)
	c.status = TargetStatus{true, name, !bytes.Equal(currentContent, savedContent), needsUpdate}
}

func (c *TargetsPlugin) copyContents(sourcePath, targetPath string) {
	content, err := os.ReadFile(sourcePath)
	c.checkError(err)
	err = os.WriteFile(targetPath, content, 0600)
	c.checkError(err)
}

func (c *TargetsPlugin) linkCurrent(targetPath string) {
	os.Remove(c.currentPath)
	err := os.Symlink(targetPath, c.currentPath)
	c.checkError(err)
}

func (c *TargetsPlugin) targetPath(targetName string) string {
	return filepath.Join(c.targetsPath, targetName+c.suffix)
}

func (c *TargetsPlugin) checkError(err error) {
	if err != nil {
		fmt.Println("Error:", err)
		panic(1)
	}
}

func (c *TargetsPlugin) exitWithUsage(command string) {
	metadata := c.GetMetadata()
	for _, candidate := range metadata.Commands {
		if candidate.Name == command {
			fmt.Println("Usage: " + candidate.UsageDetails.Usage)
			panic(1)
		}
	}
}

func (c *TargetsPlugin) getCurrent() string {
	targetPath, err := filepath.EvalSymlinks(c.currentPath)
	c.checkError(err)
	return strings.TrimSuffix(filepath.Base(targetPath), c.suffix)
}

func (c *TargetsPlugin) isCurrent(target string) bool {
	return c.status.currentHasName && c.status.currentName == target
}
<|endoftext|>


<commit_before>package event

import (
	"encoding/json"
	"os"
	"sync"
	"time"

	"github.com/grafana/grafana/pkg/log"
)

type Event interface {
	Type() string
	Timestamp() time.Time
	Body() ([]byte, error)
}

type RawEvent struct {
	Type      string          `json:"type"`
	Timestamp time.Time       `json:"timestamp"`
	Body      json.RawMessage `json:"payload"`
	Source    string
	Attempts  int `json:"attempts"`
}

type Handlers struct {
	sync.Mutex
	Listeners map[string][]chan<- RawEvent
}

func (h *Handlers) Add(key string, ch chan<- RawEvent) {
	h.Lock()
	if l, ok := h.Listeners[key]; !ok {
		l = make([]chan<- RawEvent, 0)
		h.Listeners[key] = l
	}
	h.Listeners[key] = append(h.Listeners[key], ch)
	h.Unlock()
}

func (h *Handlers) GetListeners(key string) []chan<- RawEvent {
	listeners := make([]chan<- RawEvent, 0)
	h.Lock()
	for rk, l := range h.Listeners {
		if rk == "*" || rk == key {
			listeners = append(listeners, l...)
		}
	}
	h.Unlock()
	return listeners
}

var (
	handlers *Handlers
	pubChan  chan Message
	subChan  chan Message
)

func Init(rabbitmqUrl, exchange string) error {
	handlers = &Handlers{
		Listeners: make(map[string][]chan<- RawEvent),
	}
	pubChan = make(chan Message, 100)
	subChan = make(chan Message, 10)
	go Run(rabbitmqUrl, exchange, pubChan, subChan)
	go handleMessages(subChan)
	return nil
}

func Subscribe(t string, channel chan<- RawEvent) {
	handlers.Add(t, channel)
}

func Publish(e Event, attempts int) error {
	payload, err := e.Body()
	if err != nil {
		return err
	}
	hostname, _ := os.Hostname()
	raw := &RawEvent{
		Type:      e.Type(),
		Timestamp: e.Timestamp(),
		Source:    hostname,
		Body:      payload,
	}
	body, err := json.Marshal(raw)
	if err != nil {
		return err
	}
	msg := Message{
		RoutingKey: e.Type(),
		Payload:    body,
	}
	pubChan <- msg
	return nil
}

func handleMessages(c chan Message) {
	for msg := range c {
		go func() {
			e := RawEvent{}
			err := json.Unmarshal(msg.Payload, &e)
			if err != nil {
				log.Error(3, "unable to unmarshal event Message. %s", err)
				return
			}
			//broadcast the event to listeners.
			for _, ch := range handlers.GetListeners(e.Type) {
				ch <- e
			}
		}()
	}
}
<commit_msg>fix range variable msg captured by func literal<commit_after>package event

import (
	"encoding/json"
	"os"
	"sync"
	"time"

	"github.com/grafana/grafana/pkg/log"
)

type Event interface {
	Type() string
	Timestamp() time.Time
	Body() ([]byte, error)
}

type RawEvent struct {
	Type      string          `json:"type"`
	Timestamp time.Time       `json:"timestamp"`
	Body      json.RawMessage `json:"payload"`
	Source    string
	Attempts  int `json:"attempts"`
}

type Handlers struct {
	sync.Mutex
	Listeners map[string][]chan<- RawEvent
}

func (h *Handlers) Add(key string, ch chan<- RawEvent) {
	h.Lock()
	if l, ok := h.Listeners[key]; !ok {
		l = make([]chan<- RawEvent, 0)
		h.Listeners[key] = l
	}
	h.Listeners[key] = append(h.Listeners[key], ch)
	h.Unlock()
}

func (h *Handlers) GetListeners(key string) []chan<- RawEvent {
	listeners := make([]chan<- RawEvent, 0)
	h.Lock()
	for rk, l := range h.Listeners {
		if rk == "*" || rk == key {
			listeners = append(listeners, l...)
		}
	}
	h.Unlock()
	return listeners
}

var (
	handlers *Handlers
	pubChan  chan Message
	subChan  chan Message
)

func Init(rabbitmqUrl, exchange string) error {
	handlers = &Handlers{
		Listeners: make(map[string][]chan<- RawEvent),
	}
	pubChan = make(chan Message, 100)
	subChan = make(chan Message, 10)
	go Run(rabbitmqUrl, exchange, pubChan, subChan)
	go handleMessages(subChan)
	return nil
}

func Subscribe(t string, channel chan<- RawEvent) {
	handlers.Add(t, channel)
}

func Publish(e Event, attempts int) error {
	payload, err := e.Body()
	if err != nil {
		return err
	}
	hostname, _ := os.Hostname()
	raw := &RawEvent{
		Type:      e.Type(),
		Timestamp: e.Timestamp(),
		Source:    hostname,
		Body:      payload,
	}
	body, err := json.Marshal(raw)
	if err != nil {
		return err
	}
	msg := Message{
		RoutingKey: e.Type(),
		Payload:    body,
	}
	pubChan <- msg
	return nil
}

func handleMessages(c chan Message) {
	for m := range c {
		go func(msg Message) {
			e := RawEvent{}
			err := json.Unmarshal(msg.Payload, &e)
			if err != nil {
				log.Error(3, "unable to unmarshal event Message. %s", err)
				return
			}
			//broadcast the event to listeners.
			for _, ch := range handlers.GetListeners(e.Type) {
				ch <- e
			}
		}(m)
	}
}
<|endoftext|>


<commit_before>package geojson

import (
	"encoding/json"

	"github.com/go-spatial/geom"
	"github.com/go-spatial/geom/encoding"
)

type GeoJSONType string

const (
	PointType              GeoJSONType = "Point"
	MultiPointType         GeoJSONType = "MultiPoint"
	LineStringType         GeoJSONType = "LineString"
	MultiLineStringType    GeoJSONType = "MultiLineString"
	PolygonType            GeoJSONType = "Polygon"
	MultiPolygonType       GeoJSONType = "MultiPolygon"
	GeometryCollectionType GeoJSONType = "GeometryCollection"
	FeatureType            GeoJSONType = "Feature"
	FeatureCollectionType  GeoJSONType = "FeatureCollection"
)

type Geometry struct {
	geom.Geometry
}

func (geo Geometry) MarshalJSON() ([]byte, error) {
	type coordinates struct {
		Type   GeoJSONType `json:"type"`
		Coords interface{} `json:"coordinates,omitempty"`
	}
	type collection struct {
		Type       GeoJSONType `json:"type"`
		Geometries []Geometry  `json:"geometries,omitempty"`
	}

	switch g := geo.Geometry.(type) {
	case geom.Pointer:
		return json.Marshal(coordinates{
			Type:   PointType,
			Coords: g.XY(),
		})

	case geom.MultiPointer:
		return json.Marshal(coordinates{
			Type:   MultiPointType,
			Coords: g.Points(),
		})

	case geom.LineStringer:
		return json.Marshal(coordinates{
			Type:   LineStringType,
			Coords: g.Vertices(),
		})

	case geom.MultiLineStringer:
		return json.Marshal(coordinates{
			Type:   MultiLineStringType,
			Coords: g.LineStrings(),
		})

	case geom.Polygoner:
		ps := g.LinearRings()
		closePolygon(ps)

		return json.Marshal(coordinates{
			Type: PolygonType,
			// make sure our rings are closed
			Coords: ps,
		})

	case geom.MultiPolygoner:
		ps := g.Polygons()

		// iterate through the polygons making sure they're closed
		for i := range ps {
			closePolygon(geom.Polygon(ps[i]))
		}

		return json.Marshal(coordinates{
			Type:   MultiPolygonType,
			Coords: ps,
		})

	case geom.Collectioner:
		gs := g.Geometries()

		var geos = make([]Geometry, 0, len(gs))
		for _, gg := range gs {
			geos = append(geos, Geometry{gg})
		}

		return json.Marshal(collection{
			Type:       GeometryCollectionType,
			Geometries: geos,
		})

	default:
		return nil, geom.ErrUnknownGeometry{g}
	}
}

// featureType allows the GeoJSON type for Feature to be automatically set during json Marshalling
// which avoids the user from accidentally setting the incorrect GeoJSON type.
type featureType struct{}

func (_ featureType) MarshalJSON() ([]byte, error) {
	return []byte(`"` + FeatureType + `"`), nil
}
func (fc *featureType) UnmarshalJSON(b []byte) error { return nil }

type Feature struct {
	Type featureType `json:"type"`
	ID   *uint64     `json:"id,omitempty"`
	// can be null
	Geometry Geometry `json:"geometry"`
	// can be null
	Properties map[string]interface{} `json:"properties"`
}

// featureCollectionType allows the GeoJSON type for Feature to be automatically set during json Marshalling
// which avoids the user from accidentally setting the incorrect GeoJSON type.
type featureCollectionType struct{}

func (_ featureCollectionType) MarshalJSON() ([]byte, error) {
	return []byte(`"` + FeatureCollectionType + `"`), nil
}
func (fc *featureCollectionType) UnmarshalJSON(b []byte) error { return nil }

type FeatureCollection struct {
	Type     featureCollectionType `json:"type"`
	Features []Feature             `json:"features"`
}

func closePolygon(p geom.Polygon) {
	for i := range p {
		if len(p[i]) == 0 {
			continue
		}

		// check if the first point and the last point are the same
		// if they're not, make a copy of the first point and add it as the last position
		if p[i][0] != p[i][len(p[i])-1] {
			p[i] = append(p[i], p[i][0])
		}
	}
}

func (geo *Geometry) UnmarshalJSON(b []byte) error {
	var geojsonMap map[string]*json.RawMessage
	if err := json.Unmarshal(b, &geojsonMap); err != nil {
		return err
	}

	var geomType GeoJSONType
	if err := json.Unmarshal(*geojsonMap["type"], &geomType); err != nil {
		return err
	}
	switch geomType {
	case PointType:
		var pt geom.Point
		if err := json.Unmarshal(*geojsonMap["coordinates"], &pt); err != nil {
			return err
		}
		geo.Geometry = pt
		return nil
	case PolygonType:
		var poly geom.Polygon
		if err := json.Unmarshal(*geojsonMap["coordinates"], &poly); err != nil {
			return err
		}
		geo.Geometry = poly
		return nil
	case LineStringType:
		var ls geom.LineString
		if err := json.Unmarshal(*geojsonMap["coordinates"], &ls); err != nil {
			return err
		}
		geo.Geometry = ls
		return nil
	case MultiPointType:
		var mp geom.MultiPoint
		if err := json.Unmarshal(*geojsonMap["coordinates"], &mp); err != nil {
			return err
		}
		geo.Geometry = mp
		return nil
	case MultiLineStringType:
		var ml geom.MultiLineString
		if err := json.Unmarshal(*geojsonMap["coordinates"], &ml); err != nil {
			return err
		}
		geo.Geometry = ml
		return nil
	case MultiPolygonType:
		var mp geom.MultiPolygon
		if err := json.Unmarshal(*geojsonMap["coordinates"], &mp); err != nil {
			return err
		}
		geo.Geometry = mp
		return nil
	case GeometryCollectionType:
		gc := geom.Collection{}
		var rawMessageForGeometries []*json.RawMessage
		if err := json.Unmarshal(*geojsonMap["geometries"], &rawMessageForGeometries); err != nil {
			return err
		}
		geoms := make([]geom.Geometry, len(rawMessageForGeometries))
		for i, v := range rawMessageForGeometries {
			var g Geometry
			if err := json.Unmarshal(*v, &g); err != nil {
				return err
			}
			geoms[i] = g.Geometry
		}
		gc.SetGeometries(geoms)
		geo.Geometry = gc
		return nil
	case FeatureType:
		f := Feature{}
		if err := json.Unmarshal(b, &f); err != nil {
			return err
		}
		geo.Geometry = f
		return nil
	case FeatureCollectionType:
		fc := FeatureCollection{}
		if err := json.Unmarshal(b, &fc); err != nil {
			return err
		}
		geo.Geometry = fc
		return nil
	default:
		return encoding.ErrInvalidGeoJSON{b}
	}
	return nil
}
<commit_msg>Started to document out the geojson package.<commit_after>// Package geojson implements encoding and decoding of GeoJSON as
// defined in [RFC 7946](https://tools.ietf.org/html/rfc7946). The
// mapping between JSON and geom Geometry values are described in
// the documentation for the Marshal and Unmarshal functions.
//
// At current this pacakge only supports 2D Geometries unless stated
// otherwise by the documentation of the Marshal and Unmarshal functions
package geojson
import (
	"encoding/json"

	"github.com/go-spatial/geom"
	"github.com/go-spatial/geom/encoding"
)

type GeoJSONType string

const (
	PointType              GeoJSONType = "Point"
	MultiPointType         GeoJSONType = "MultiPoint"
	LineStringType         GeoJSONType = "LineString"
	MultiLineStringType    GeoJSONType = "MultiLineString"
	PolygonType            GeoJSONType = "Polygon"
	MultiPolygonType       GeoJSONType = "MultiPolygon"
	GeometryCollectionType GeoJSONType = "GeometryCollection"
	FeatureType            GeoJSONType = "Feature"
	FeatureCollectionType  GeoJSONType = "FeatureCollection"
)

// Geometry wraps a geom Geometry so that it can be encoded as a GeoJSON
// feature
type Geometry struct {
	geom.Geometry
}

func (geo Geometry) MarshalJSON() ([]byte, error) {
	type coordinates struct {
		Type   GeoJSONType `json:"type"`
		Coords interface{} `json:"coordinates,omitempty"`
	}
	type collection struct {
		Type       GeoJSONType `json:"type"`
		Geometries []Geometry  `json:"geometries,omitempty"`
	}

	switch g := geo.Geometry.(type) {
	case geom.Pointer:
		return json.Marshal(coordinates{
			Type:   PointType,
			Coords: g.XY(),
		})

	case geom.MultiPointer:
		return json.Marshal(coordinates{
			Type:   MultiPointType,
			Coords: g.Points(),
		})

	case geom.LineStringer:
		return json.Marshal(coordinates{
			Type:   LineStringType,
			Coords: g.Vertices(),
		})

	case geom.MultiLineStringer:
		return json.Marshal(coordinates{
			Type:   MultiLineStringType,
			Coords: g.LineStrings(),
		})

	case geom.Polygoner:
		ps := g.LinearRings()
		closePolygon(ps)

		return json.Marshal(coordinates{
			Type: PolygonType,
			Coords: ps,
		})

	case geom.MultiPolygoner:
		ps := g.Polygons()

		// iterate through the polygons making sure they're closed
		for i := range ps {
			closePolygon(geom.Polygon(ps[i]))
		}

		return json.Marshal(coordinates{
			Type:   MultiPolygonType,
			Coords: ps,
		})

	case geom.Collectioner:
		gs := g.Geometries()

		var geos = make([]Geometry, 0, len(gs))
		for _, gg := range gs {
			geos = append(geos, Geometry{gg})
		}

		return json.Marshal(collection{
			Type:       GeometryCollectionType,
			Geometries: geos,
		})

	default:
		return nil, geom.ErrUnknownGeometry{g}
	}
}

// featureType allows the GeoJSON type for Feature to be automatically set during json Marshalling
// which avoids the user from accidentally setting the incorrect GeoJSON type.
type featureType struct{}

func (_ featureType) MarshalJSON() ([]byte, error) {
	return []byte(`"` + FeatureType + `"`), nil
}
func (fc *featureType) UnmarshalJSON(b []byte) error { return nil }

// Feature represents as geojson feature
type Feature struct {
	Type featureType `json:"type"`
	ID   *uint64     `json:"id,omitempty"`
	// Geometry can be null
	Geometry Geometry `json:"geometry"`
	// Properties can be null
	Properties map[string]interface{} `json:"properties"`
}

// featureCollectionType allows the GeoJSON type for Feature to be automatically set during json Marshalling
// which avoids the user from accidentally setting the incorrect GeoJSON type.
type featureCollectionType struct{}

func (_ featureCollectionType) MarshalJSON() ([]byte, error) {
	return []byte(`"` + FeatureCollectionType + `"`), nil
}
func (fc *featureCollectionType) UnmarshalJSON(b []byte) error { return nil }

// FeatureCollection describes a geoJSON collection feature
type FeatureCollection struct {
	Type     featureCollectionType `json:"type"`
	Features []Feature             `json:"features"`
}

// closePolygon will ensure that the last point of a polygon is the same as the first
// point of the polygon. geom Polygon rings are not "closed", however geoJSON polygon
// ring are.
func closePolygon(p geom.Polygon) {
	for i := range p {
		if len(p[i]) == 0 {
			continue
		}

		// check if the first point and the last point are the same
		// if they're not, make a copy of the first point and add it as the last position
		if p[i][0] != p[i][len(p[i])-1] {
			p[i] = append(p[i], p[i][0])
		}
	}
}

// UnmarshalJSON will attempt to unmarshal the given bytes into a GeoJSON object.
// It can produce a varity of json Marshaling errors or
// encoding.InvalidGeometry if the geometry type in unsupported
func (geo *Geometry) UnmarshalJSON(b []byte) error {
	var geojsonMap map[string]*json.RawMessage
	if err := json.Unmarshal(b, &geojsonMap); err != nil {
		return err
	}

	var geomType GeoJSONType
	if err := json.Unmarshal(*geojsonMap["type"], &geomType); err != nil {
		return err
	}
	switch geomType {
	case PointType:
		var pt geom.Point
		if err := json.Unmarshal(*geojsonMap["coordinates"], &pt); err != nil {
			return err
		}
		geo.Geometry = pt
		return nil
	case PolygonType:
		var poly geom.Polygon
		if err := json.Unmarshal(*geojsonMap["coordinates"], &poly); err != nil {
			return err
		}
		geo.Geometry = poly
		return nil
	case LineStringType:
		var ls geom.LineString
		if err := json.Unmarshal(*geojsonMap["coordinates"], &ls); err != nil {
			return err
		}
		geo.Geometry = ls
		return nil
	case MultiPointType:
		var mp geom.MultiPoint
		if err := json.Unmarshal(*geojsonMap["coordinates"], &mp); err != nil {
			return err
		}
		geo.Geometry = mp
		return nil
	case MultiLineStringType:
		var ml geom.MultiLineString
		if err := json.Unmarshal(*geojsonMap["coordinates"], &ml); err != nil {
			return err
		}
		geo.Geometry = ml
		return nil
	case MultiPolygonType:
		var mp geom.MultiPolygon
		if err := json.Unmarshal(*geojsonMap["coordinates"], &mp); err != nil {
			return err
		}
		geo.Geometry = mp
		return nil
	case GeometryCollectionType:
		gc := geom.Collection{}
		var rawMessageForGeometries []*json.RawMessage
		if err := json.Unmarshal(*geojsonMap["geometries"], &rawMessageForGeometries); err != nil {
			return err
		}
		geoms := make([]geom.Geometry, len(rawMessageForGeometries))
		for i, v := range rawMessageForGeometries {
			var g Geometry
			if err := json.Unmarshal(*v, &g); err != nil {
				return err
			}
			geoms[i] = g.Geometry
		}
		gc.SetGeometries(geoms)
		geo.Geometry = gc
		return nil
	case FeatureType:
		f := Feature{}
		if err := json.Unmarshal(b, &f); err != nil {
			return err
		}
		geo.Geometry = f
		return nil
	case FeatureCollectionType:
		fc := FeatureCollection{}
		if err := json.Unmarshal(b, &fc); err != nil {
			return err
		}
		geo.Geometry = fc
		return nil
	default:
		return encoding.ErrInvalidGeoJSON{b}
	}
	return nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"

	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsIamRolePolicy() *schema.Resource {
	return &schema.Resource{
		// PutRolePolicy API is idempotent, so these can be the same.
		Create: resourceAwsIamRolePolicyPut,
		Update: resourceAwsIamRolePolicyPut,

		Read:   resourceAwsIamRolePolicyRead,
		Delete: resourceAwsIamRolePolicyDelete,

		Schema: map[string]*schema.Schema{
			"policy": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"role": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsIamRolePolicyPut(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	request := &iam.PutRolePolicyInput{
		RoleName:       aws.String(d.Get("role").(string)),
		PolicyName:     aws.String(d.Get("name").(string)),
		PolicyDocument: aws.String(d.Get("policy").(string)),
	}

	if _, err := iamconn.PutRolePolicy(request); err != nil {
		return fmt.Errorf("Error putting IAM role policy %s: %s", *request.PolicyName, err)
	}

	d.SetId(fmt.Sprintf("%s:%s", *request.RoleName, *request.PolicyName))
	return nil
}

func resourceAwsIamRolePolicyRead(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	role, name := resourceAwsIamRolePolicyParseId(d.Id())

	request := &iam.GetRolePolicyInput{
		PolicyName: aws.String(name),
		RoleName:   aws.String(role),
	}

	var err error
	getResp, err := iamconn.GetRolePolicy(request)
	if err != nil {
		if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { // XXX test me
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading IAM policy %s from role %s: %s", name, role, err)
	}

	if getResp.PolicyDocument == nil {
		return fmt.Errorf("GetRolePolicy returned a nil policy document")
	}

	policy, err := url.QueryUnescape(*getResp.PolicyDocument)
	if err != nil {
		return err
	}
	return d.Set("policy", policy)
}

func resourceAwsIamRolePolicyDelete(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	role, name := resourceAwsIamRolePolicyParseId(d.Id())

	request := &iam.DeleteRolePolicyInput{
		PolicyName: aws.String(name),
		RoleName:   aws.String(role),
	}

	if _, err := iamconn.DeleteRolePolicy(request); err != nil {
		return fmt.Errorf("Error deleting IAM role policy %s: %s", d.Id(), err)
	}
	return nil
}

func resourceAwsIamRolePolicyParseId(id string) (roleName, policyName string) {
	parts := strings.SplitN(id, ":", 2)
	roleName = parts[0]
	policyName = parts[1]
	return
}
<commit_msg>provider/aws: Add validation for aws_iam_role_policy.name<commit_after>package aws

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"

	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsIamRolePolicy() *schema.Resource {
	return &schema.Resource{
		// PutRolePolicy API is idempotent, so these can be the same.
		Create: resourceAwsIamRolePolicyPut,
		Update: resourceAwsIamRolePolicyPut,

		Read:   resourceAwsIamRolePolicyRead,
		Delete: resourceAwsIamRolePolicyDelete,

		Schema: map[string]*schema.Schema{
			"policy": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					// https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296
					value := v.(string)
					if len(value) > 128 {
						errors = append(errors, fmt.Errorf(
							"%q cannot be longer than 128 characters", k))
					}
					if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) {
						errors = append(errors, fmt.Errorf(
							"%q must match [\\w+=,.@-]", k))
					}
					return
				},
			},
			"role": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsIamRolePolicyPut(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	request := &iam.PutRolePolicyInput{
		RoleName:       aws.String(d.Get("role").(string)),
		PolicyName:     aws.String(d.Get("name").(string)),
		PolicyDocument: aws.String(d.Get("policy").(string)),
	}

	if _, err := iamconn.PutRolePolicy(request); err != nil {
		return fmt.Errorf("Error putting IAM role policy %s: %s", *request.PolicyName, err)
	}

	d.SetId(fmt.Sprintf("%s:%s", *request.RoleName, *request.PolicyName))
	return nil
}

func resourceAwsIamRolePolicyRead(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	role, name := resourceAwsIamRolePolicyParseId(d.Id())

	request := &iam.GetRolePolicyInput{
		PolicyName: aws.String(name),
		RoleName:   aws.String(role),
	}

	var err error
	getResp, err := iamconn.GetRolePolicy(request)
	if err != nil {
		if iamerr, ok := err.(awserr.Error); ok && iamerr.Code() == "NoSuchEntity" { // XXX test me
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading IAM policy %s from role %s: %s", name, role, err)
	}

	if getResp.PolicyDocument == nil {
		return fmt.Errorf("GetRolePolicy returned a nil policy document")
	}

	policy, err := url.QueryUnescape(*getResp.PolicyDocument)
	if err != nil {
		return err
	}
	return d.Set("policy", policy)
}

func resourceAwsIamRolePolicyDelete(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	role, name := resourceAwsIamRolePolicyParseId(d.Id())

	request := &iam.DeleteRolePolicyInput{
		PolicyName: aws.String(name),
		RoleName:   aws.String(role),
	}

	if _, err := iamconn.DeleteRolePolicy(request); err != nil {
		return fmt.Errorf("Error deleting IAM role policy %s: %s", d.Id(), err)
	}
	return nil
}

func resourceAwsIamRolePolicyParseId(id string) (roleName, policyName string) {
	parts := strings.SplitN(id, ":", 2)
	roleName = parts[0]
	policyName = parts[1]
	return
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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.

// This is a simple command line tool for Cloud Pub/Sub
// Cloud Pub/Sub docs: https://cloud.google.com/pubsub/docs
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/go.net/context"

	"github.com/golang/oauth2"
	"github.com/golang/oauth2/google"
	"google.golang.org/cloud"
	"google.golang.org/cloud/pubsub"
)

var (
	jsonFile  = flag.String("j", "", "Secrets json file of your service account, not needed if you run it on Compute Engine instances")
	reportMPS = flag.Bool("report_mps", false, "Whether or not to report msgs per seconds")
)

const (
	usage = `Available arguments are:
    list_topics
    create_topic TOPIC
    delete_topic TOPIC
    list_subscriptions
    create_subscription SUBSCRIPTION LINKED_TOPIC
    delete_subscription SUBSCRIPTION
    publish TOPIC MESSAGE
    pull_messages SUBSCRIPTION workers
    publish_messages TOPIC workers
`
	tick               = 1 * time.Second
	googOAuth2Endpoint = "https://accounts.google.com/o/oauth2/token"
	metadataServer     = "metadata" // host name of the GCE metadata server
	projectIDPath      = "/computeMetadata/v1/project/project-id"
)

func usageAndExit(msg string) {
	fmt.Fprintln(os.Stderr, msg)
	fmt.Println("Flags:")
	flag.PrintDefaults()
	fmt.Fprint(os.Stderr, usage)
	os.Exit(2)
}

// Check the length of the arguments.
func checkArgs(argv []string, min int) {
	if len(argv) < min {
		usageAndExit("Missing arguments")
	}
}

// jwtConfig is for JWT json file parsing.
type jwtConfig struct {
	Type         string `json:"type"`
	Scope        string `json:"scope"`
	ProjectId    string `json:"project_id"`
	PrivateKeyId string `json:"private_key_id"`
	PrivateKey   string `json:"private_key" binding:"required"`
	ClientEmail  string `json:"client_email" binding:"required"`
	ClientId     string `json:"client_id" binding:"required"`
}

// clientAndId creates http.Client and determines project id to use,
// with a jwt service account when jsonFile flag is specified,
// otherwise by obtaining the GCE service account's access token and
// project ID from the metadata server.
func clientAndId(jsonFile string) (*http.Client, string) {
	if jsonFile != "" {
		file, err := ioutil.ReadFile(jsonFile)
		if err != nil {
			log.Fatalf("Can not read file %s", jsonFile)
		}
		var config jwtConfig
		if err := json.Unmarshal(file, &config); err != nil {
			log.Fatalf("Can not parse the json file: %s, %v", jsonFile, err)
		}
		projectID := strings.SplitN(config.ClientId, "-", 2)[0]
		options := &oauth2.JWTOptions{
			Email:      config.ClientEmail,
			PrivateKey: []byte(config.PrivateKey),
			Scopes:     []string{pubsub.ScopePubSub},
		}
		conf, err := oauth2.NewJWTConfig(options, googOAuth2Endpoint)
		if err != nil {
			log.Fatalf("NewJWTConfig failed, %v", err)
		}
		client := &http.Client{Transport: conf.NewTransport()}
		return client, projectID
	} else {
		gceConfig := google.NewComputeEngineConfig("")
		client := &http.Client{Transport: gceConfig.NewTransport()}
		projectID, err := getProjectID()
		if err != nil {
			log.Fatalf("Failed to get the project id: %v", err)
		}
		return client, projectID
	}
}

// getProjectID fetches the project id from GCE metadata server.
func getProjectID() (string, error) {
	projectIDURL := &url.URL{
		Scheme: "http",
		Host:   metadataServer,
		Path:   projectIDPath,
	}
	req, err := http.NewRequest("GET", projectIDURL.String(), nil)
	if err != nil {
		return "", err
	}
	req.Header.Add("Metadata-Flavor", "Google")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func listTopics(ctx context.Context, argv []string) {
	panic("listTopics not implemented yet")
}

func createTopic(ctx context.Context, argv []string) {
	checkArgs(argv, 2)
	topic := argv[1]
	err := pubsub.CreateTopic(ctx, topic)
	if err != nil {
		log.Fatalf("CreateTopic failed, %v", err)
	}
	fmt.Printf("Topic %s was created.\n", topic)
}

func deleteTopic(ctx context.Context, argv []string) {
	checkArgs(argv, 2)
	topic := argv[1]
	err := pubsub.DeleteTopic(ctx, topic)
	if err != nil {
		log.Fatalf("DeleteTopic failed, %v", err)
	}
	fmt.Printf("Topic %s was deleted.\n", topic)
}

func listSubscriptions(ctx context.Context, argv []string) {
	panic("listSubscriptions not implemented yet")
}

func createSubscription(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	sub := argv[1]
	topic := argv[2]
	err := pubsub.CreateSub(ctx, sub, topic, 60*time.Second, "")
	if err != nil {
		log.Fatalf("CreateSub failed, %v", err)
	}
	fmt.Printf("Subscription %s was created.\n", sub)
}

func deleteSubscription(ctx context.Context, argv []string) {
	checkArgs(argv, 2)
	sub := argv[1]
	err := pubsub.DeleteSub(ctx, sub)
	if err != nil {
		log.Fatalf("DeleteSub failed, %v", err)
	}
	fmt.Printf("Subscription %s was deleted.\n", sub)
}

func publish(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	topic := argv[1]
	message := argv[2]
	err := pubsub.Publish(ctx, topic, []byte(message), nil)
	if err != nil {
		log.Fatalf("Publish failed, %v", err)
	}
	fmt.Printf("Message '%s' published to a topic %s\n", message, topic)
}

type puller struct {
	lastC  uint64
	c      uint64
	ctx    context.Context
	sub    string
	result chan struct{}
}

func (p *puller) pullLoop() {
	for {
		msg, err := pubsub.PullWait(p.ctx, p.sub)
		if err != nil {
			log.Printf("PullWait failed, %v\n", err)
			time.Sleep(5 * time.Second)
			continue
		}
		if *reportMPS {
			p.result <- struct{}{}
		} else {
			fmt.Printf("Got a message: %s\n", msg.Data)
		}
	}
}

func (p *puller) ack(ackID string) {
	err := pubsub.Ack(p.ctx, p.sub, ackID)
	if err != nil {
		log.Printf("Ack failed, %v\n", err)
	}
}

func (p *puller) report() {
	ticker := time.NewTicker(tick)
	defer func() {
		ticker.Stop()
	}()
	for {
		select {
		case <-ticker.C:
			n := p.c - p.lastC
			p.lastC = p.c
			mps := n / uint64(tick/time.Second)
			log.Printf("Received ~%d msgs/s, total: %d", mps, p.c)
		case <-p.result:
			p.c += 1
		}
	}
}

func pullMessages(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	sub := argv[1]
	workers, err := strconv.Atoi(argv[2])
	if err != nil {
		log.Fatalf("Atoi failed, %v", err)
	}
	p := puller{
		ctx:    ctx,
		sub:    sub,
		result: make(chan struct{}, 1024),
	}
	for i := 0; i < int(workers); i++ {
		go p.pullLoop()
	}
	if *reportMPS {
		p.report()
	} else {
		select {}
	}
}

type publisher struct {
	lastC  uint64
	c      uint64
	ctx    context.Context
	topic  string
	result chan struct{}
}

func (p *publisher) publishLoop(workerid int) {
	var i uint64
	for {
		message := fmt.Sprintf("Worker: %d, Message: %d", workerid, i)
		err := pubsub.Publish(p.ctx, p.topic, []byte(message), nil)
		if err != nil {
			log.Printf("Publish failed, %v\n", err)
		} else {
			i++
			if *reportMPS {
				p.result <- struct{}{}
			}
		}
	}
}

func (p *publisher) report() {
	ticker := time.NewTicker(tick)
	defer func() {
		ticker.Stop()
	}()
	for {
		select {
		case <-ticker.C:
			n := p.c - p.lastC
			p.lastC = p.c
			mps := n / uint64(tick/time.Second)
			log.Printf("Sent ~%d msg/s, total: %d", mps, p.c)
		case <-p.result:
			p.c += 1
		}
	}
}

func publishMessages(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	topic := argv[1]
	workers, err := strconv.Atoi(argv[2])
	if err != nil {
		log.Fatalf("Atoi failed, %v", err)
	}
	p := publisher{
		ctx:    ctx,
		topic:  topic,
		result: make(chan struct{}, 1024),
	}
	for i := 0; i < int(workers); i++ {
		go p.publishLoop(i)
	}
	if *reportMPS {
		p.report()
	} else {
		select {}
	}
}

// This example demonstrates calling the Cloud Pub/Sub API. As of 22
// Oct 2014, the Cloud Pub/Sub API is only available if you're
// whitelisted. If you're interested in using it, please apply for the
// Limited Preview program at the following form:
// http://goo.gl/Wql9HL
//
// Also, before running this example, be sure to enable Cloud Pub/Sub
// service on your project in Developer Console at:
// https://console.developers.google.com/
//
// Unless you run this sample on Compute Engine instance, please
// create a new service account and download a json file for it at the
// developer console at: https://console.developers.google.com/
//
// It has the following subcommands:
//
// create_topic TOPIC
// delete_topic TOPIC
// create_subscription SUBSCRIPTION LINKED_TOPIC
// delete_subscription SUBSCRIPTION
// publish TOPIC MESSAGE
// pull_messages SUBSCRIPTION workers
// publish_messages TOPIC workers
//
// You can choose any names for TOPIC and SUBSCRIPTION as long as they
// follow the naming rule described at:
// https://cloud.google.com/pubsub/overview#names
//
// You can create/delete topics/subscriptions by self-explanatory
// subcommands.
//
// The "publish" subcommand is for publishing a single message to a
// specified Cloud Pub/Sub topic.
//
// The "pull_messages" subcommand is for continuously pulling messages
// from a specified Cloud Pub/Sub subscription with specified number
// of workers.
//
// The "publish_messages" subcommand is for continuously publishing
// messages to a specified Cloud Pub/Sub topic with specified number
// of workers.
func main() {
	flag.Parse()
	argv := flag.Args()
	checkArgs(argv, 1)
	client, projectID := clientAndId(*jsonFile)
	ctx := cloud.NewContext(projectID, client)
	m := map[string]func(ctx context.Context, argv []string){
		"create_topic":        createTopic,
		"delete_topic":        deleteTopic,
		"create_subscription": createSubscription,
		"delete_subscription": deleteSubscription,
		"publish":             publish,
		"pull_messages":       pullMessages,
		"publish_messages":    publishMessages,
	}
	subcommand := argv[0]
	f, ok := m[subcommand]
	if !ok {
		usageAndExit(fmt.Sprintf("Function not found for %s", subcommand))
	}
	f(ctx, argv)
}
<commit_msg>A little fix for usage.<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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.

// This is a simple command line tool for Cloud Pub/Sub
// Cloud Pub/Sub docs: https://cloud.google.com/pubsub/docs
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/go.net/context"

	"github.com/golang/oauth2"
	"github.com/golang/oauth2/google"
	"google.golang.org/cloud"
	"google.golang.org/cloud/pubsub"
)

var (
	jsonFile  = flag.String("j", "", "Secrets json file of your service account, not needed if you run it on Compute Engine instances")
	reportMPS = flag.Bool("report_mps", false, "Whether or not to report msgs per seconds")
)

const (
	usage = `Available arguments are:
    create_topic TOPIC
    delete_topic TOPIC
    create_subscription SUBSCRIPTION LINKED_TOPIC
    delete_subscription SUBSCRIPTION
    publish TOPIC MESSAGE
    pull_messages SUBSCRIPTION numworkers
    publish_messages TOPIC numworkers
`
	tick               = 1 * time.Second
	googOAuth2Endpoint = "https://accounts.google.com/o/oauth2/token"
	metadataServer     = "metadata" // host name of the GCE metadata server
	projectIDPath      = "/computeMetadata/v1/project/project-id"
)

func usageAndExit(msg string) {
	fmt.Fprintln(os.Stderr, msg)
	fmt.Println("Flags:")
	flag.PrintDefaults()
	fmt.Fprint(os.Stderr, usage)
	os.Exit(2)
}

// Check the length of the arguments.
func checkArgs(argv []string, min int) {
	if len(argv) < min {
		usageAndExit("Missing arguments")
	}
}

// jwtConfig is for JWT json file parsing.
type jwtConfig struct {
	Type         string `json:"type"`
	Scope        string `json:"scope"`
	ProjectId    string `json:"project_id"`
	PrivateKeyId string `json:"private_key_id"`
	PrivateKey   string `json:"private_key" binding:"required"`
	ClientEmail  string `json:"client_email" binding:"required"`
	ClientId     string `json:"client_id" binding:"required"`
}

// clientAndId creates http.Client and determines project id to use,
// with a jwt service account when jsonFile flag is specified,
// otherwise by obtaining the GCE service account's access token and
// project ID from the metadata server.
func clientAndId(jsonFile string) (*http.Client, string) {
	if jsonFile != "" {
		file, err := ioutil.ReadFile(jsonFile)
		if err != nil {
			log.Fatalf("Can not read file %s", jsonFile)
		}
		var config jwtConfig
		if err := json.Unmarshal(file, &config); err != nil {
			log.Fatalf("Can not parse the json file: %s, %v", jsonFile, err)
		}
		projectID := strings.SplitN(config.ClientId, "-", 2)[0]
		options := &oauth2.JWTOptions{
			Email:      config.ClientEmail,
			PrivateKey: []byte(config.PrivateKey),
			Scopes:     []string{pubsub.ScopePubSub},
		}
		conf, err := oauth2.NewJWTConfig(options, googOAuth2Endpoint)
		if err != nil {
			log.Fatalf("NewJWTConfig failed, %v", err)
		}
		client := &http.Client{Transport: conf.NewTransport()}
		return client, projectID
	} else {
		gceConfig := google.NewComputeEngineConfig("")
		client := &http.Client{Transport: gceConfig.NewTransport()}
		projectID, err := getProjectID()
		if err != nil {
			log.Fatalf("Failed to get the project id: %v", err)
		}
		return client, projectID
	}
}

// getProjectID fetches the project id from GCE metadata server.
func getProjectID() (string, error) {
	projectIDURL := &url.URL{
		Scheme: "http",
		Host:   metadataServer,
		Path:   projectIDPath,
	}
	req, err := http.NewRequest("GET", projectIDURL.String(), nil)
	if err != nil {
		return "", err
	}
	req.Header.Add("Metadata-Flavor", "Google")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func listTopics(ctx context.Context, argv []string) {
	panic("listTopics not implemented yet")
}

func createTopic(ctx context.Context, argv []string) {
	checkArgs(argv, 2)
	topic := argv[1]
	err := pubsub.CreateTopic(ctx, topic)
	if err != nil {
		log.Fatalf("CreateTopic failed, %v", err)
	}
	fmt.Printf("Topic %s was created.\n", topic)
}

func deleteTopic(ctx context.Context, argv []string) {
	checkArgs(argv, 2)
	topic := argv[1]
	err := pubsub.DeleteTopic(ctx, topic)
	if err != nil {
		log.Fatalf("DeleteTopic failed, %v", err)
	}
	fmt.Printf("Topic %s was deleted.\n", topic)
}

func listSubscriptions(ctx context.Context, argv []string) {
	panic("listSubscriptions not implemented yet")
}

func createSubscription(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	sub := argv[1]
	topic := argv[2]
	err := pubsub.CreateSub(ctx, sub, topic, 60*time.Second, "")
	if err != nil {
		log.Fatalf("CreateSub failed, %v", err)
	}
	fmt.Printf("Subscription %s was created.\n", sub)
}

func deleteSubscription(ctx context.Context, argv []string) {
	checkArgs(argv, 2)
	sub := argv[1]
	err := pubsub.DeleteSub(ctx, sub)
	if err != nil {
		log.Fatalf("DeleteSub failed, %v", err)
	}
	fmt.Printf("Subscription %s was deleted.\n", sub)
}

func publish(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	topic := argv[1]
	message := argv[2]
	err := pubsub.Publish(ctx, topic, []byte(message), nil)
	if err != nil {
		log.Fatalf("Publish failed, %v", err)
	}
	fmt.Printf("Message '%s' published to a topic %s\n", message, topic)
}

type puller struct {
	lastC  uint64
	c      uint64
	ctx    context.Context
	sub    string
	result chan struct{}
}

func (p *puller) pullLoop() {
	for {
		msg, err := pubsub.PullWait(p.ctx, p.sub)
		if err != nil {
			log.Printf("PullWait failed, %v\n", err)
			time.Sleep(5 * time.Second)
			continue
		}
		if *reportMPS {
			p.result <- struct{}{}
		} else {
			fmt.Printf("Got a message: %s\n", msg.Data)
		}
	}
}

func (p *puller) ack(ackID string) {
	err := pubsub.Ack(p.ctx, p.sub, ackID)
	if err != nil {
		log.Printf("Ack failed, %v\n", err)
	}
}

func (p *puller) report() {
	ticker := time.NewTicker(tick)
	defer func() {
		ticker.Stop()
	}()
	for {
		select {
		case <-ticker.C:
			n := p.c - p.lastC
			p.lastC = p.c
			mps := n / uint64(tick/time.Second)
			log.Printf("Received ~%d msgs/s, total: %d", mps, p.c)
		case <-p.result:
			p.c += 1
		}
	}
}

func pullMessages(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	sub := argv[1]
	workers, err := strconv.Atoi(argv[2])
	if err != nil {
		log.Fatalf("Atoi failed, %v", err)
	}
	p := puller{
		ctx:    ctx,
		sub:    sub,
		result: make(chan struct{}, 1024),
	}
	for i := 0; i < int(workers); i++ {
		go p.pullLoop()
	}
	if *reportMPS {
		p.report()
	} else {
		select {}
	}
}

type publisher struct {
	lastC  uint64
	c      uint64
	ctx    context.Context
	topic  string
	result chan struct{}
}

func (p *publisher) publishLoop(workerid int) {
	var i uint64
	for {
		message := fmt.Sprintf("Worker: %d, Message: %d", workerid, i)
		err := pubsub.Publish(p.ctx, p.topic, []byte(message), nil)
		if err != nil {
			log.Printf("Publish failed, %v\n", err)
		} else {
			i++
			if *reportMPS {
				p.result <- struct{}{}
			}
		}
	}
}

func (p *publisher) report() {
	ticker := time.NewTicker(tick)
	defer func() {
		ticker.Stop()
	}()
	for {
		select {
		case <-ticker.C:
			n := p.c - p.lastC
			p.lastC = p.c
			mps := n / uint64(tick/time.Second)
			log.Printf("Sent ~%d msg/s, total: %d", mps, p.c)
		case <-p.result:
			p.c += 1
		}
	}
}

func publishMessages(ctx context.Context, argv []string) {
	checkArgs(argv, 3)
	topic := argv[1]
	workers, err := strconv.Atoi(argv[2])
	if err != nil {
		log.Fatalf("Atoi failed, %v", err)
	}
	p := publisher{
		ctx:    ctx,
		topic:  topic,
		result: make(chan struct{}, 1024),
	}
	for i := 0; i < int(workers); i++ {
		go p.publishLoop(i)
	}
	if *reportMPS {
		p.report()
	} else {
		select {}
	}
}

// This example demonstrates calling the Cloud Pub/Sub API. As of 22
// Oct 2014, the Cloud Pub/Sub API is only available if you're
// whitelisted. If you're interested in using it, please apply for the
// Limited Preview program at the following form:
// http://goo.gl/Wql9HL
//
// Also, before running this example, be sure to enable Cloud Pub/Sub
// service on your project in Developer Console at:
// https://console.developers.google.com/
//
// Unless you run this sample on Compute Engine instance, please
// create a new service account and download a json file for it at the
// developer console at: https://console.developers.google.com/
//
// It has the following subcommands:
//
// create_topic TOPIC
// delete_topic TOPIC
// create_subscription SUBSCRIPTION LINKED_TOPIC
// delete_subscription SUBSCRIPTION
// publish TOPIC MESSAGE
// pull_messages SUBSCRIPTION workers
// publish_messages TOPIC workers
//
// You can choose any names for TOPIC and SUBSCRIPTION as long as they
// follow the naming rule described at:
// https://cloud.google.com/pubsub/overview#names
//
// You can create/delete topics/subscriptions by self-explanatory
// subcommands.
//
// The "publish" subcommand is for publishing a single message to a
// specified Cloud Pub/Sub topic.
//
// The "pull_messages" subcommand is for continuously pulling messages
// from a specified Cloud Pub/Sub subscription with specified number
// of workers.
//
// The "publish_messages" subcommand is for continuously publishing
// messages to a specified Cloud Pub/Sub topic with specified number
// of workers.
func main() {
	flag.Parse()
	argv := flag.Args()
	checkArgs(argv, 1)
	client, projectID := clientAndId(*jsonFile)
	ctx := cloud.NewContext(projectID, client)
	m := map[string]func(ctx context.Context, argv []string){
		"create_topic":        createTopic,
		"delete_topic":        deleteTopic,
		"create_subscription": createSubscription,
		"delete_subscription": deleteSubscription,
		"publish":             publish,
		"pull_messages":       pullMessages,
		"publish_messages":    publishMessages,
	}
	subcommand := argv[0]
	f, ok := m[subcommand]
	if !ok {
		usageAndExit(fmt.Sprintf("Function not found for %s", subcommand))
	}
	f(ctx, argv)
}
<|endoftext|>


<commit_before>package main

import (
	log "github.com/golang/glog"
	"github.com/micro/go-micro/cmd"
	"github.com/micro/go-micro/examples/server/handler"
	"github.com/micro/go-micro/examples/server/subscriber"
	"github.com/micro/go-micro/server"
	"golang.org/x/net/context"
)

func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		log.Infof("[Log Wrapper] Before serving request method: %v", req.Method())
		err := fn(ctx, req, rsp)
		log.Infof("[Log Wrapper] After serving request")
		return err
	}
}

func logSubWrapper(fn server.SubscriberFunc) server.SubscriberFunc {
	return func(ctx context.Context, req server.Publication) error {
		log.Infof("[Log Sub Wrapper] Before serving publication topic: %v", req.Topic())
		err := fn(ctx, req)
		log.Infof("[Log Sub Wrapper] After serving publication")
		return err
	}
}

func main() {
	// optionally setup command line usage
	cmd.Init()

	md := server.DefaultOptions().Metadata
	md["datacenter"] = "local"

	server.DefaultServer = server.NewServer(
		server.WrapHandler(logWrapper),
		server.WrapSubscriber(logSubWrapper),
		server.Metadata(md),
	)

	// Initialise Server
	server.Init(
		server.Name("go.micro.srv.example"),
	)

	// Register Handlers
	server.Handle(
		server.NewHandler(
			new(handler.Example),
		),
	)

	// Register Subscribers
	if err := server.Subscribe(
		server.NewSubscriber(
			"topic.go.micro.srv.example",
			new(subscriber.Example),
		),
	); err != nil {
		log.Fatal(err)
	}

	if err := server.Subscribe(
		server.NewSubscriber(
			"topic.go.micro.srv.example",
			subscriber.Handler,
		),
	); err != nil {
		log.Fatal(err)
	}

	// Run server
	if err := server.Run(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Remove glog from example too<commit_after>package main

import (
	"log"

	"github.com/micro/go-micro/cmd"
	"github.com/micro/go-micro/examples/server/handler"
	"github.com/micro/go-micro/examples/server/subscriber"
	"github.com/micro/go-micro/server"
	"golang.org/x/net/context"
)

func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		log.Printf("[Log Wrapper] Before serving request method: %v", req.Method())
		err := fn(ctx, req, rsp)
		log.Printf("[Log Wrapper] After serving request")
		return err
	}
}

func logSubWrapper(fn server.SubscriberFunc) server.SubscriberFunc {
	return func(ctx context.Context, req server.Publication) error {
		log.Printf("[Log Sub Wrapper] Before serving publication topic: %v", req.Topic())
		err := fn(ctx, req)
		log.Printf("[Log Sub Wrapper] After serving publication")
		return err
	}
}

func main() {
	// optionally setup command line usage
	cmd.Init()

	md := server.DefaultOptions().Metadata
	md["datacenter"] = "local"

	server.DefaultServer = server.NewServer(
		server.WrapHandler(logWrapper),
		server.WrapSubscriber(logSubWrapper),
		server.Metadata(md),
	)

	// Initialise Server
	server.Init(
		server.Name("go.micro.srv.example"),
	)

	// Register Handlers
	server.Handle(
		server.NewHandler(
			new(handler.Example),
		),
	)

	// Register Subscribers
	if err := server.Subscribe(
		server.NewSubscriber(
			"topic.go.micro.srv.example",
			new(subscriber.Example),
		),
	); err != nil {
		log.Fatal(err)
	}

	if err := server.Subscribe(
		server.NewSubscriber(
			"topic.go.micro.srv.example",
			subscriber.Handler,
		),
	); err != nil {
		log.Fatal(err)
	}

	// Run server
	if err := server.Run(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package bitswap

import (
	"context"
	"sync"
	"time"

	engine "github.com/ipfs/go-ipfs/exchange/bitswap/decision"
	bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"

	metrics "gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
	peer "gx/ipfs/QmZoWKhxUmZ2seW4BzX6fJkNR8hh9PsGModr7q171yq2SS/go-libp2p-peer"
	cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
)

type WantManager struct {
	// sync channels for Run loop
	incoming     chan *wantSet
	connectEvent chan peerStatus     // notification channel for peers connecting/disconnecting
	peerReqs     chan chan []peer.ID // channel to request connected peers on

	// synchronized by Run loop, only touch inside there
	peers map[peer.ID]*msgQueue
	wl    *wantlist.ThreadSafe
	bcwl  *wantlist.ThreadSafe

	network bsnet.BitSwapNetwork
	ctx     context.Context
	cancel  func()

	wantlistGauge metrics.Gauge
	sentHistogram metrics.Histogram
}

type peerStatus struct {
	connect bool
	peer    peer.ID
}

func NewWantManager(ctx context.Context, network bsnet.BitSwapNetwork) *WantManager {
	ctx, cancel := context.WithCancel(ctx)
	wantlistGauge := metrics.NewCtx(ctx, "wantlist_total",
		"Number of items in wantlist.").Gauge()
	sentHistogram := metrics.NewCtx(ctx, "sent_all_blocks_bytes", "Histogram of blocks sent by"+
		" this bitswap").Histogram(metricsBuckets)
	return &WantManager{
		incoming:      make(chan *wantSet, 10),
		connectEvent:  make(chan peerStatus, 10),
		peerReqs:      make(chan chan []peer.ID),
		peers:         make(map[peer.ID]*msgQueue),
		wl:            wantlist.NewThreadSafe(),
		bcwl:          wantlist.NewThreadSafe(),
		network:       network,
		ctx:           ctx,
		cancel:        cancel,
		wantlistGauge: wantlistGauge,
		sentHistogram: sentHistogram,
	}
}

type msgQueue struct {
	p peer.ID

	outlk   sync.Mutex
	out     bsmsg.BitSwapMessage
	network bsnet.BitSwapNetwork
	wl      *wantlist.ThreadSafe

	sender bsnet.MessageSender

	refcnt int

	work chan struct{}
	done chan struct{}
}

// WantBlocks adds the given cids to the wantlist, tracked by the given session
func (pm *WantManager) WantBlocks(ctx context.Context, ks []*cid.Cid, peers []peer.ID, ses uint64) {
	log.Infof("want blocks: %s", ks)
	pm.addEntries(ctx, ks, peers, false, ses)
}

// CancelWants removes the given cids from the wantlist, tracked by the given session
func (pm *WantManager) CancelWants(ctx context.Context, ks []*cid.Cid, peers []peer.ID, ses uint64) {
	pm.addEntries(context.Background(), ks, peers, true, ses)
}

type wantSet struct {
	entries []*bsmsg.Entry
	targets []peer.ID
	from    uint64
}

func (pm *WantManager) addEntries(ctx context.Context, ks []*cid.Cid, targets []peer.ID, cancel bool, ses uint64) {
	entries := make([]*bsmsg.Entry, 0, len(ks))
	for i, k := range ks {
		entries = append(entries, &bsmsg.Entry{
			Cancel: cancel,
			Entry:  wantlist.NewRefEntry(k, kMaxPriority-i),
		})
	}
	select {
	case pm.incoming <- &wantSet{entries: entries, targets: targets, from: ses}:
	case <-pm.ctx.Done():
	case <-ctx.Done():
	}
}

func (pm *WantManager) ConnectedPeers() []peer.ID {
	resp := make(chan []peer.ID)
	pm.peerReqs <- resp
	return <-resp
}

func (pm *WantManager) SendBlock(ctx context.Context, env *engine.Envelope) {
	// Blocks need to be sent synchronously to maintain proper backpressure
	// throughout the network stack
	defer env.Sent()

	pm.sentHistogram.Observe(float64(len(env.Block.RawData())))

	msg := bsmsg.New(false)
	msg.AddBlock(env.Block)
	log.Infof("Sending block %s to %s", env.Block, env.Peer)
	err := pm.network.SendMessage(ctx, env.Peer, msg)
	if err != nil {
		log.Infof("sendblock error: %s", err)
	}
}

func (pm *WantManager) startPeerHandler(p peer.ID) *msgQueue {
	mq, ok := pm.peers[p]
	if ok {
		mq.refcnt++
		return nil
	}

	mq = pm.newMsgQueue(p)

	// new peer, we will want to give them our full wantlist
	fullwantlist := bsmsg.New(true)
	for _, e := range pm.bcwl.Entries() {
		for k := range e.SesTrk {
			mq.wl.AddEntry(e, k)
		}
		fullwantlist.AddEntry(e.Cid, e.Priority)
	}
	mq.out = fullwantlist
	mq.work <- struct{}{}

	pm.peers[p] = mq
	go mq.runQueue(pm.ctx)
	return mq
}

func (pm *WantManager) stopPeerHandler(p peer.ID) {
	pq, ok := pm.peers[p]
	if !ok {
		// TODO: log error?
		return
	}

	pq.refcnt--
	if pq.refcnt > 0 {
		return
	}

	close(pq.done)
	delete(pm.peers, p)
}

func (mq *msgQueue) runQueue(ctx context.Context) {
	for {
		select {
		case <-mq.work: // there is work to be done
			mq.doWork(ctx)
		case <-mq.done:
			if mq.sender != nil {
				mq.sender.Close()
			}
			return
		case <-ctx.Done():
			if mq.sender != nil {
				mq.sender.Reset()
			}
			return
		}
	}
}

func (mq *msgQueue) doWork(ctx context.Context) {
	// grab outgoing message
	mq.outlk.Lock()
	wlm := mq.out
	if wlm == nil || wlm.Empty() {
		mq.outlk.Unlock()
		return
	}
	mq.out = nil
	mq.outlk.Unlock()

	// NB: only open a stream if we actually have data to send
	if mq.sender == nil {
		err := mq.openSender(ctx)
		if err != nil {
			log.Infof("cant open message sender to peer %s: %s", mq.p, err)
			// TODO: cant connect, what now?
			return
		}
	}

	// send wantlist updates
	for { // try to send this message until we fail.
		err := mq.sender.SendMsg(ctx, wlm)
		if err == nil {
			return
		}

		log.Infof("bitswap send error: %s", err)
		mq.sender.Reset()
		mq.sender = nil

		select {
		case <-mq.done:
			return
		case <-ctx.Done():
			return
		case <-time.After(time.Millisecond * 100):
			// wait 100ms in case disconnect notifications are still propogating
			log.Warning("SendMsg errored but neither 'done' nor context.Done() were set")
		}

		err = mq.openSender(ctx)
		if err != nil {
			log.Infof("couldnt open sender again after SendMsg(%s) failed: %s", mq.p, err)
			// TODO(why): what do we do now?
			// I think the *right* answer is to probably put the message we're
			// trying to send back, and then return to waiting for new work or
			// a disconnect.
			return
		}

		// TODO: Is this the same instance for the remote peer?
		// If its not, we should resend our entire wantlist to them
		/*
			if mq.sender.InstanceID() != mq.lastSeenInstanceID {
				wlm = mq.getFullWantlistMessage()
			}
		*/
	}
}

func (mq *msgQueue) openSender(ctx context.Context) error {
	// allow ten minutes for connections this includes looking them up in the
	// dht dialing them, and handshaking
	conctx, cancel := context.WithTimeout(ctx, time.Minute*10)
	defer cancel()

	err := mq.network.ConnectTo(conctx, mq.p)
	if err != nil {
		return err
	}

	nsender, err := mq.network.NewMessageSender(ctx, mq.p)
	if err != nil {
		return err
	}

	mq.sender = nsender
	return nil
}

func (pm *WantManager) Connected(p peer.ID) {
	select {
	case pm.connectEvent <- peerStatus{peer: p, connect: true}:
	case <-pm.ctx.Done():
	}
}

func (pm *WantManager) Disconnected(p peer.ID) {
	select {
	case pm.connectEvent <- peerStatus{peer: p, connect: false}:
	case <-pm.ctx.Done():
	}
}

// TODO: use goprocess here once i trust it
func (pm *WantManager) Run() {
	// NOTE: Do not open any streams or connections from anywhere in this
	// event loop. Really, just don't do anything likely to block.
	for {
		select {
		case ws := <-pm.incoming:

			// is this a broadcast or not?
			brdc := len(ws.targets) == 0

			// add changes to our wantlist
			for _, e := range ws.entries {
				if e.Cancel {
					if brdc {
						pm.bcwl.Remove(e.Cid, ws.from)
					}

					if pm.wl.Remove(e.Cid, ws.from) {
						pm.wantlistGauge.Dec()
					}
				} else {
					if brdc {
						pm.bcwl.AddEntry(e.Entry, ws.from)
					}
					if pm.wl.AddEntry(e.Entry, ws.from) {
						pm.wantlistGauge.Inc()
					}
				}
			}

			// broadcast those wantlist changes
			if len(ws.targets) == 0 {
				for _, p := range pm.peers {
					p.addMessage(ws.entries, ws.from)
				}
			} else {
				for _, t := range ws.targets {
					p, ok := pm.peers[t]
					if !ok {
						// No longer connected.
						continue
					}
					p.addMessage(ws.entries, ws.from)
				}
			}

		case p := <-pm.connectEvent:
			if p.connect {
				pm.startPeerHandler(p.peer)
			} else {
				pm.stopPeerHandler(p.peer)
			}
		case req := <-pm.peerReqs:
			peers := make([]peer.ID, 0, len(pm.peers))
			for p := range pm.peers {
				peers = append(peers, p)
			}
			req <- peers
		case <-pm.ctx.Done():
			return
		}
	}
}

func (wm *WantManager) newMsgQueue(p peer.ID) *msgQueue {
	return &msgQueue{
		done:    make(chan struct{}),
		work:    make(chan struct{}, 1),
		wl:      wantlist.NewThreadSafe(),
		network: wm.network,
		p:       p,
		refcnt:  1,
	}
}

func (mq *msgQueue) addMessage(entries []*bsmsg.Entry, ses uint64) {
	var work bool
	mq.outlk.Lock()
	defer func() {
		mq.outlk.Unlock()
		if !work {
			return
		}
		select {
		case mq.work <- struct{}{}:
		default:
		}
	}()

	// if we have no message held allocate a new one
	if mq.out == nil {
		mq.out = bsmsg.New(false)
	}

	// TODO: add a msg.Combine(...) method
	// otherwise, combine the one we are holding with the
	// one passed in
	for _, e := range entries {
		if e.Cancel {
			if mq.wl.Remove(e.Cid, ses) {
				work = true
				mq.out.Cancel(e.Cid)
			}
		} else {
			if mq.wl.Add(e.Cid, e.Priority, ses) {
				work = true
				mq.out.AddEntry(e.Cid, e.Priority)
			}
		}
	}
}
<commit_msg>exchange: reintroduce info on wantlist update to no connected peer<commit_after>package bitswap

import (
	"context"
	"sync"
	"time"

	engine "github.com/ipfs/go-ipfs/exchange/bitswap/decision"
	bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"

	metrics "gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
	peer "gx/ipfs/QmZoWKhxUmZ2seW4BzX6fJkNR8hh9PsGModr7q171yq2SS/go-libp2p-peer"
	cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
)

type WantManager struct {
	// sync channels for Run loop
	incoming     chan *wantSet
	connectEvent chan peerStatus     // notification channel for peers connecting/disconnecting
	peerReqs     chan chan []peer.ID // channel to request connected peers on

	// synchronized by Run loop, only touch inside there
	peers map[peer.ID]*msgQueue
	wl    *wantlist.ThreadSafe
	bcwl  *wantlist.ThreadSafe

	network bsnet.BitSwapNetwork
	ctx     context.Context
	cancel  func()

	wantlistGauge metrics.Gauge
	sentHistogram metrics.Histogram
}

type peerStatus struct {
	connect bool
	peer    peer.ID
}

func NewWantManager(ctx context.Context, network bsnet.BitSwapNetwork) *WantManager {
	ctx, cancel := context.WithCancel(ctx)
	wantlistGauge := metrics.NewCtx(ctx, "wantlist_total",
		"Number of items in wantlist.").Gauge()
	sentHistogram := metrics.NewCtx(ctx, "sent_all_blocks_bytes", "Histogram of blocks sent by"+
		" this bitswap").Histogram(metricsBuckets)
	return &WantManager{
		incoming:      make(chan *wantSet, 10),
		connectEvent:  make(chan peerStatus, 10),
		peerReqs:      make(chan chan []peer.ID),
		peers:         make(map[peer.ID]*msgQueue),
		wl:            wantlist.NewThreadSafe(),
		bcwl:          wantlist.NewThreadSafe(),
		network:       network,
		ctx:           ctx,
		cancel:        cancel,
		wantlistGauge: wantlistGauge,
		sentHistogram: sentHistogram,
	}
}

type msgQueue struct {
	p peer.ID

	outlk   sync.Mutex
	out     bsmsg.BitSwapMessage
	network bsnet.BitSwapNetwork
	wl      *wantlist.ThreadSafe

	sender bsnet.MessageSender

	refcnt int

	work chan struct{}
	done chan struct{}
}

// WantBlocks adds the given cids to the wantlist, tracked by the given session
func (pm *WantManager) WantBlocks(ctx context.Context, ks []*cid.Cid, peers []peer.ID, ses uint64) {
	log.Infof("want blocks: %s", ks)
	pm.addEntries(ctx, ks, peers, false, ses)
}

// CancelWants removes the given cids from the wantlist, tracked by the given session
func (pm *WantManager) CancelWants(ctx context.Context, ks []*cid.Cid, peers []peer.ID, ses uint64) {
	pm.addEntries(context.Background(), ks, peers, true, ses)
}

type wantSet struct {
	entries []*bsmsg.Entry
	targets []peer.ID
	from    uint64
}

func (pm *WantManager) addEntries(ctx context.Context, ks []*cid.Cid, targets []peer.ID, cancel bool, ses uint64) {
	entries := make([]*bsmsg.Entry, 0, len(ks))
	for i, k := range ks {
		entries = append(entries, &bsmsg.Entry{
			Cancel: cancel,
			Entry:  wantlist.NewRefEntry(k, kMaxPriority-i),
		})
	}
	select {
	case pm.incoming <- &wantSet{entries: entries, targets: targets, from: ses}:
	case <-pm.ctx.Done():
	case <-ctx.Done():
	}
}

func (pm *WantManager) ConnectedPeers() []peer.ID {
	resp := make(chan []peer.ID)
	pm.peerReqs <- resp
	return <-resp
}

func (pm *WantManager) SendBlock(ctx context.Context, env *engine.Envelope) {
	// Blocks need to be sent synchronously to maintain proper backpressure
	// throughout the network stack
	defer env.Sent()

	pm.sentHistogram.Observe(float64(len(env.Block.RawData())))

	msg := bsmsg.New(false)
	msg.AddBlock(env.Block)
	log.Infof("Sending block %s to %s", env.Block, env.Peer)
	err := pm.network.SendMessage(ctx, env.Peer, msg)
	if err != nil {
		log.Infof("sendblock error: %s", err)
	}
}

func (pm *WantManager) startPeerHandler(p peer.ID) *msgQueue {
	mq, ok := pm.peers[p]
	if ok {
		mq.refcnt++
		return nil
	}

	mq = pm.newMsgQueue(p)

	// new peer, we will want to give them our full wantlist
	fullwantlist := bsmsg.New(true)
	for _, e := range pm.bcwl.Entries() {
		for k := range e.SesTrk {
			mq.wl.AddEntry(e, k)
		}
		fullwantlist.AddEntry(e.Cid, e.Priority)
	}
	mq.out = fullwantlist
	mq.work <- struct{}{}

	pm.peers[p] = mq
	go mq.runQueue(pm.ctx)
	return mq
}

func (pm *WantManager) stopPeerHandler(p peer.ID) {
	pq, ok := pm.peers[p]
	if !ok {
		// TODO: log error?
		return
	}

	pq.refcnt--
	if pq.refcnt > 0 {
		return
	}

	close(pq.done)
	delete(pm.peers, p)
}

func (mq *msgQueue) runQueue(ctx context.Context) {
	for {
		select {
		case <-mq.work: // there is work to be done
			mq.doWork(ctx)
		case <-mq.done:
			if mq.sender != nil {
				mq.sender.Close()
			}
			return
		case <-ctx.Done():
			if mq.sender != nil {
				mq.sender.Reset()
			}
			return
		}
	}
}

func (mq *msgQueue) doWork(ctx context.Context) {
	// grab outgoing message
	mq.outlk.Lock()
	wlm := mq.out
	if wlm == nil || wlm.Empty() {
		mq.outlk.Unlock()
		return
	}
	mq.out = nil
	mq.outlk.Unlock()

	// NB: only open a stream if we actually have data to send
	if mq.sender == nil {
		err := mq.openSender(ctx)
		if err != nil {
			log.Infof("cant open message sender to peer %s: %s", mq.p, err)
			// TODO: cant connect, what now?
			return
		}
	}

	// send wantlist updates
	for { // try to send this message until we fail.
		err := mq.sender.SendMsg(ctx, wlm)
		if err == nil {
			return
		}

		log.Infof("bitswap send error: %s", err)
		mq.sender.Reset()
		mq.sender = nil

		select {
		case <-mq.done:
			return
		case <-ctx.Done():
			return
		case <-time.After(time.Millisecond * 100):
			// wait 100ms in case disconnect notifications are still propogating
			log.Warning("SendMsg errored but neither 'done' nor context.Done() were set")
		}

		err = mq.openSender(ctx)
		if err != nil {
			log.Infof("couldnt open sender again after SendMsg(%s) failed: %s", mq.p, err)
			// TODO(why): what do we do now?
			// I think the *right* answer is to probably put the message we're
			// trying to send back, and then return to waiting for new work or
			// a disconnect.
			return
		}

		// TODO: Is this the same instance for the remote peer?
		// If its not, we should resend our entire wantlist to them
		/*
			if mq.sender.InstanceID() != mq.lastSeenInstanceID {
				wlm = mq.getFullWantlistMessage()
			}
		*/
	}
}

func (mq *msgQueue) openSender(ctx context.Context) error {
	// allow ten minutes for connections this includes looking them up in the
	// dht dialing them, and handshaking
	conctx, cancel := context.WithTimeout(ctx, time.Minute*10)
	defer cancel()

	err := mq.network.ConnectTo(conctx, mq.p)
	if err != nil {
		return err
	}

	nsender, err := mq.network.NewMessageSender(ctx, mq.p)
	if err != nil {
		return err
	}

	mq.sender = nsender
	return nil
}

func (pm *WantManager) Connected(p peer.ID) {
	select {
	case pm.connectEvent <- peerStatus{peer: p, connect: true}:
	case <-pm.ctx.Done():
	}
}

func (pm *WantManager) Disconnected(p peer.ID) {
	select {
	case pm.connectEvent <- peerStatus{peer: p, connect: false}:
	case <-pm.ctx.Done():
	}
}

// TODO: use goprocess here once i trust it
func (pm *WantManager) Run() {
	// NOTE: Do not open any streams or connections from anywhere in this
	// event loop. Really, just don't do anything likely to block.
	for {
		select {
		case ws := <-pm.incoming:

			// is this a broadcast or not?
			brdc := len(ws.targets) == 0

			// add changes to our wantlist
			for _, e := range ws.entries {
				if e.Cancel {
					if brdc {
						pm.bcwl.Remove(e.Cid, ws.from)
					}

					if pm.wl.Remove(e.Cid, ws.from) {
						pm.wantlistGauge.Dec()
					}
				} else {
					if brdc {
						pm.bcwl.AddEntry(e.Entry, ws.from)
					}
					if pm.wl.AddEntry(e.Entry, ws.from) {
						pm.wantlistGauge.Inc()
					}
				}
			}

			// broadcast those wantlist changes
			if len(ws.targets) == 0 {
				for _, p := range pm.peers {
					p.addMessage(ws.entries, ws.from)
				}
			} else {
				for _, t := range ws.targets {
					p, ok := pm.peers[t]
					if !ok {
						log.Infof("tried sending wantlist change to non-partner peer: %s", t)
						continue
					}
					p.addMessage(ws.entries, ws.from)
				}
			}

		case p := <-pm.connectEvent:
			if p.connect {
				pm.startPeerHandler(p.peer)
			} else {
				pm.stopPeerHandler(p.peer)
			}
		case req := <-pm.peerReqs:
			peers := make([]peer.ID, 0, len(pm.peers))
			for p := range pm.peers {
				peers = append(peers, p)
			}
			req <- peers
		case <-pm.ctx.Done():
			return
		}
	}
}

func (wm *WantManager) newMsgQueue(p peer.ID) *msgQueue {
	return &msgQueue{
		done:    make(chan struct{}),
		work:    make(chan struct{}, 1),
		wl:      wantlist.NewThreadSafe(),
		network: wm.network,
		p:       p,
		refcnt:  1,
	}
}

func (mq *msgQueue) addMessage(entries []*bsmsg.Entry, ses uint64) {
	var work bool
	mq.outlk.Lock()
	defer func() {
		mq.outlk.Unlock()
		if !work {
			return
		}
		select {
		case mq.work <- struct{}{}:
		default:
		}
	}()

	// if we have no message held allocate a new one
	if mq.out == nil {
		mq.out = bsmsg.New(false)
	}

	// TODO: add a msg.Combine(...) method
	// otherwise, combine the one we are holding with the
	// one passed in
	for _, e := range entries {
		if e.Cancel {
			if mq.wl.Remove(e.Cid, ses) {
				work = true
				mq.out.Cancel(e.Cid)
			}
		} else {
			if mq.wl.Add(e.Cid, e.Priority, ses) {
				work = true
				mq.out.AddEntry(e.Cid, e.Priority)
			}
		}
	}
}
<|endoftext|>