<commit_before>package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/client"
	"github.com/libopenstorage/openstorage/volume"
)

type VolumeSzUnits uint64

const (
	_                = iota
	KB VolumeSzUnits = 1 << (10 * iota)
	MB
	GB
	TB
	PB
)

type VolDriver struct {
	volDriver volume.VolumeDriver
	name      string
}

func processLabels(s string) (api.Labels, error) {
	m := make(map[string]string)
	labels := strings.Split(s, ",")
	for _, v := range labels {
		label := strings.Split(v, "=")
		if len(label) != 2 {
			return nil, fmt.Errorf("Malformed label: %s", v)
		}
		if _, ok := m[label[0]]; ok {
			return nil, fmt.Errorf("Duplicate label: %s", v)
		}
		m[label[0]] = label[1]
	}
	return m, nil
}

func (v *VolDriver) volumeOptions(c *cli.Context) {
	clnt, err := client.NewDriverClient(v.name)
	if err != nil {
		fmt.Printf("Failed to initialize client library: %v\n", err)
		os.Exit(1)
	}
	v.volDriver = clnt.VolumeDriver()
}

func (v *VolDriver) volumeCreate(c *cli.Context) {
	var err error
	var labels api.Labels
	var locator api.VolumeLocator
	var id api.VolumeID
	fn := "create"

	if len(c.Args()) != 1 {
		missingParameter(c, fn, "name", "Invalid number of arguments")
		return
	}

	v.volumeOptions(c)
	if l := c.String("label"); l != "" {
		if labels, err = processLabels(l); err != nil {
			cmdError(c, fn, err)
			return
		}
	}
	locator = api.VolumeLocator{
		Name:         c.Args()[0],
		VolumeLabels: labels,
	}
	spec := &api.VolumeSpec{
		Size:             uint64(VolumeSzUnits(c.Int("s")) * MB),
		Format:           api.Filesystem(c.String("fs")),
		BlockSize:        c.Int("b") * 1024,
		HALevel:          c.Int("r"),
		Cos:              api.VolumeCos(c.Int("cos")),
		SnapShotInterval: c.Int("si"),
	}
	if id, err = v.volDriver.Create(locator, nil, spec); err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{string(id)}})
}

func (v *VolDriver) volumeFormat(c *cli.Context) {
	v.volumeOptions(c)
	fn := "format"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	volumeID := c.Args()[0]

	err := v.volDriver.Format(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func (v *VolDriver) volumeAttach(c *cli.Context) {
	fn := "attach"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	v.volumeOptions(c)
	volumeID := c.Args()[0]

	devicePath, err := v.volDriver.Attach(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{Result: devicePath})
}

func (v *VolDriver) volumeDetach(c *cli.Context) {
	fn := "detach"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	volumeID := c.Args()[0]
	v.volumeOptions(c)
	err := v.volDriver.Detach(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func (v *VolDriver) volumeInspect(c *cli.Context) {

	v.volumeOptions(c)
	fn := "inspect"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}

	d := make([]api.VolumeID, len(c.Args()))
	for i, v := range c.Args() {
		d[i] = api.VolumeID(v)
	}

	volumes, err := v.volDriver.Inspect(d)
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	cmdOutput(c, volumes)
}

func (v *VolDriver) volumeEnumerate(c *cli.Context) {
	var locator api.VolumeLocator
	var err error

	fn := "enumerate"
	locator.Name = c.String("name")
	if l := c.String("label"); l != "" {
		locator.VolumeLabels, err = processLabels(l)
		if err != nil {
			cmdError(c, fn, err)
			return
		}
	}

	v.volumeOptions(c)
	volumes, err := v.volDriver.Enumerate(locator, nil)
	if err != nil {
		cmdError(c, fn, err)
		return
	}
	cmdOutput(c, volumes)
}

func (v *VolDriver) volumeDelete(c *cli.Context) {
	fn := "delete"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	volumeID := c.Args()[0]
	v.volumeOptions(c)
	err := v.volDriver.Delete(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func (v *VolDriver) snapCreate(c *cli.Context) {
}

func (v *VolDriver) snapInspect(c *cli.Context) {

	v.volumeOptions(c)
	fn := "inspect"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "snapID", "Invalid number of arguments")
		return
	}
	d := make([]api.SnapID, len(c.Args()))
	for i, v := range c.Args() {
		d[i] = api.SnapID(v)
	}

	snaps, err := v.volDriver.SnapInspect(d)
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	cmdOutput(c, snaps)
}

func (v *VolDriver) snapEnumerate(c *cli.Context) {
	var locator api.VolumeLocator
	var err error

	fn := "enumerate"
	locator.Name = c.String("name")
	if l := c.String("label"); l != "" {
		locator.VolumeLabels, err = processLabels(l)
		if err != nil {
			cmdError(c, fn, err)
			return
		}
	}

	v.volumeOptions(c)
	snaps, err := v.volDriver.Enumerate(locator, nil)
	if err != nil {
		cmdError(c, fn, err)
		return
	}
	if snaps == nil {
		cmdError(c, fn, err)
		return
	}
	cmdOutput(c, snaps)
}

func (v *VolDriver) snapDelete(c *cli.Context) {
	fn := "delete"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "snapID", "Invalid number of arguments")
		return
	}
	v.volumeOptions(c)
	snapID := c.Args()[0]
	err := v.volDriver.SnapDelete(api.SnapID(snapID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func VolumeCommands(name string) []cli.Command {

	v := &VolDriver{name: name}

	commands := []cli.Command{
		{
			Name:    "create",
			Aliases: []string{"c"},
			Usage:   "create a new volume",
			Action:  v.volumeCreate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
					Value: "",
				},
				cli.IntFlag{
					Name:  "size,s",
					Usage: "specify size in MB",
					Value: 1000,
				},
				cli.StringFlag{
					Name:  "fs",
					Usage: "filesystem to be laid out: none|xfs|ext4",
					Value: "ext4",
				},
				cli.IntFlag{
					Name:  "block_size,b",
					Usage: "block size in Kbytes",
					Value: 32,
				},
				cli.IntFlag{
					Name:  "repl,r",
					Usage: "replication factor [1..2]",
					Value: 1,
				},
				cli.IntFlag{
					Name:  "cos",
					Usage: "Class of Service [1..9]",
					Value: 1,
				},
				cli.IntFlag{
					Name:  "snap_interval,si",
					Usage: "snapshot interval in minutes, 0 disables snaps",
					Value: 0,
				},
			},
		},
		{
			Name:    "format",
			Aliases: []string{"f"},
			Usage:   "Format volume to spec in create",
			Action:  v.volumeFormat,
		},
		{
			Name:    "attach",
			Aliases: []string{"a"},
			Usage:   "Attach volume to specified path",
			Action:  v.volumeAttach,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "path,p",
					Usage: "Path on local filesystem",
				},
			},
		},
		{
			Name:    "detach",
			Aliases: []string{"d"},
			Usage:   "Detach specified volume",
			Action:  v.volumeDetach,
		},
		{
			Name:    "delete",
			Aliases: []string{"rm"},
			Usage:   "Detach specified volume",
			Action:  v.volumeDelete,
		},
		{
			Name:    "enumerate",
			Aliases: []string{"e"},
			Usage:   "Enumerate volumes",
			Action:  v.volumeEnumerate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name",
					Usage: "volume name used during creation if any",
				},
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
				},
			},
		},
		{
			Name:    "inspect",
			Aliases: []string{"i"},
			Usage:   "Inspect volume",
			Action:  v.volumeInspect,
		},
		{
			Name:    "snap",
			Aliases: []string{"sc"},
			Usage:   "create snap",
			Action:  v.snapCreate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
				},
			},
		},
		{
			Name:    "snapInspect",
			Aliases: []string{"si"},
			Usage:   "Inspect snap",
			Action:  v.snapInspect,
		},
		{
			Name:    "snapEnumerate",
			Aliases: []string{"se"},
			Usage:   "Enumerate snap",
			Action:  v.snapEnumerate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name, n",
					Usage: "snap name used during creation",
				},
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
				},
			},
		},
		{
			Name:    "snapDelete",
			Aliases: []string{"si"},
			Usage:   "Delete snap",
			Action:  v.snapDelete,
		},
	}
	return commands
}
<commit_msg>Fix SnapshotInterval field<commit_after>package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/client"
	"github.com/libopenstorage/openstorage/volume"
)

type VolumeSzUnits uint64

const (
	_                = iota
	KB VolumeSzUnits = 1 << (10 * iota)
	MB
	GB
	TB
	PB
)

type VolDriver struct {
	volDriver volume.VolumeDriver
	name      string
}

func processLabels(s string) (api.Labels, error) {
	m := make(map[string]string)
	labels := strings.Split(s, ",")
	for _, v := range labels {
		label := strings.Split(v, "=")
		if len(label) != 2 {
			return nil, fmt.Errorf("Malformed label: %s", v)
		}
		if _, ok := m[label[0]]; ok {
			return nil, fmt.Errorf("Duplicate label: %s", v)
		}
		m[label[0]] = label[1]
	}
	return m, nil
}

func (v *VolDriver) volumeOptions(c *cli.Context) {
	clnt, err := client.NewDriverClient(v.name)
	if err != nil {
		fmt.Printf("Failed to initialize client library: %v\n", err)
		os.Exit(1)
	}
	v.volDriver = clnt.VolumeDriver()
}

func (v *VolDriver) volumeCreate(c *cli.Context) {
	var err error
	var labels api.Labels
	var locator api.VolumeLocator
	var id api.VolumeID
	fn := "create"

	if len(c.Args()) != 1 {
		missingParameter(c, fn, "name", "Invalid number of arguments")
		return
	}

	v.volumeOptions(c)
	if l := c.String("label"); l != "" {
		if labels, err = processLabels(l); err != nil {
			cmdError(c, fn, err)
			return
		}
	}
	locator = api.VolumeLocator{
		Name:         c.Args()[0],
		VolumeLabels: labels,
	}
	spec := &api.VolumeSpec{
		Size:             uint64(VolumeSzUnits(c.Int("s")) * MB),
		Format:           api.Filesystem(c.String("fs")),
		BlockSize:        c.Int("b") * 1024,
		HALevel:          c.Int("r"),
		Cos:              api.VolumeCos(c.Int("cos")),
		SnapshotInterval: c.Int("si"),
	}
	if id, err = v.volDriver.Create(locator, nil, spec); err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{string(id)}})
}

func (v *VolDriver) volumeFormat(c *cli.Context) {
	v.volumeOptions(c)
	fn := "format"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	volumeID := c.Args()[0]

	err := v.volDriver.Format(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func (v *VolDriver) volumeAttach(c *cli.Context) {
	fn := "attach"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	v.volumeOptions(c)
	volumeID := c.Args()[0]

	devicePath, err := v.volDriver.Attach(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{Result: devicePath})
}

func (v *VolDriver) volumeDetach(c *cli.Context) {
	fn := "detach"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	volumeID := c.Args()[0]
	v.volumeOptions(c)
	err := v.volDriver.Detach(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func (v *VolDriver) volumeInspect(c *cli.Context) {

	v.volumeOptions(c)
	fn := "inspect"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}

	d := make([]api.VolumeID, len(c.Args()))
	for i, v := range c.Args() {
		d[i] = api.VolumeID(v)
	}

	volumes, err := v.volDriver.Inspect(d)
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	cmdOutput(c, volumes)
}

func (v *VolDriver) volumeEnumerate(c *cli.Context) {
	var locator api.VolumeLocator
	var err error

	fn := "enumerate"
	locator.Name = c.String("name")
	if l := c.String("label"); l != "" {
		locator.VolumeLabels, err = processLabels(l)
		if err != nil {
			cmdError(c, fn, err)
			return
		}
	}

	v.volumeOptions(c)
	volumes, err := v.volDriver.Enumerate(locator, nil)
	if err != nil {
		cmdError(c, fn, err)
		return
	}
	cmdOutput(c, volumes)
}

func (v *VolDriver) volumeDelete(c *cli.Context) {
	fn := "delete"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "volumeID", "Invalid number of arguments")
		return
	}
	volumeID := c.Args()[0]
	v.volumeOptions(c)
	err := v.volDriver.Delete(api.VolumeID(volumeID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func (v *VolDriver) snapCreate(c *cli.Context) {
}

func (v *VolDriver) snapInspect(c *cli.Context) {

	v.volumeOptions(c)
	fn := "inspect"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "snapID", "Invalid number of arguments")
		return
	}
	d := make([]api.SnapID, len(c.Args()))
	for i, v := range c.Args() {
		d[i] = api.SnapID(v)
	}

	snaps, err := v.volDriver.SnapInspect(d)
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	cmdOutput(c, snaps)
}

func (v *VolDriver) snapEnumerate(c *cli.Context) {
	var locator api.VolumeLocator
	var err error

	fn := "enumerate"
	locator.Name = c.String("name")
	if l := c.String("label"); l != "" {
		locator.VolumeLabels, err = processLabels(l)
		if err != nil {
			cmdError(c, fn, err)
			return
		}
	}

	v.volumeOptions(c)
	snaps, err := v.volDriver.Enumerate(locator, nil)
	if err != nil {
		cmdError(c, fn, err)
		return
	}
	if snaps == nil {
		cmdError(c, fn, err)
		return
	}
	cmdOutput(c, snaps)
}

func (v *VolDriver) snapDelete(c *cli.Context) {
	fn := "delete"
	if len(c.Args()) < 1 {
		missingParameter(c, fn, "snapID", "Invalid number of arguments")
		return
	}
	v.volumeOptions(c)
	snapID := c.Args()[0]
	err := v.volDriver.SnapDelete(api.SnapID(snapID))
	if err != nil {
		cmdError(c, fn, err)
		return
	}

	fmtOutput(c, &Format{UUID: []string{c.Args()[0]}})
}

func VolumeCommands(name string) []cli.Command {

	v := &VolDriver{name: name}

	commands := []cli.Command{
		{
			Name:    "create",
			Aliases: []string{"c"},
			Usage:   "create a new volume",
			Action:  v.volumeCreate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
					Value: "",
				},
				cli.IntFlag{
					Name:  "size,s",
					Usage: "specify size in MB",
					Value: 1000,
				},
				cli.StringFlag{
					Name:  "fs",
					Usage: "filesystem to be laid out: none|xfs|ext4",
					Value: "ext4",
				},
				cli.IntFlag{
					Name:  "block_size,b",
					Usage: "block size in Kbytes",
					Value: 32,
				},
				cli.IntFlag{
					Name:  "repl,r",
					Usage: "replication factor [1..2]",
					Value: 1,
				},
				cli.IntFlag{
					Name:  "cos",
					Usage: "Class of Service [1..9]",
					Value: 1,
				},
				cli.IntFlag{
					Name:  "snap_interval,si",
					Usage: "snapshot interval in minutes, 0 disables snaps",
					Value: 0,
				},
			},
		},
		{
			Name:    "format",
			Aliases: []string{"f"},
			Usage:   "Format volume to spec in create",
			Action:  v.volumeFormat,
		},
		{
			Name:    "attach",
			Aliases: []string{"a"},
			Usage:   "Attach volume to specified path",
			Action:  v.volumeAttach,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "path,p",
					Usage: "Path on local filesystem",
				},
			},
		},
		{
			Name:    "detach",
			Aliases: []string{"d"},
			Usage:   "Detach specified volume",
			Action:  v.volumeDetach,
		},
		{
			Name:    "delete",
			Aliases: []string{"rm"},
			Usage:   "Detach specified volume",
			Action:  v.volumeDelete,
		},
		{
			Name:    "enumerate",
			Aliases: []string{"e"},
			Usage:   "Enumerate volumes",
			Action:  v.volumeEnumerate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name",
					Usage: "volume name used during creation if any",
				},
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
				},
			},
		},
		{
			Name:    "inspect",
			Aliases: []string{"i"},
			Usage:   "Inspect volume",
			Action:  v.volumeInspect,
		},
		{
			Name:    "snap",
			Aliases: []string{"sc"},
			Usage:   "create snap",
			Action:  v.snapCreate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
				},
			},
		},
		{
			Name:    "snapInspect",
			Aliases: []string{"si"},
			Usage:   "Inspect snap",
			Action:  v.snapInspect,
		},
		{
			Name:    "snapEnumerate",
			Aliases: []string{"se"},
			Usage:   "Enumerate snap",
			Action:  v.snapEnumerate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name, n",
					Usage: "snap name used during creation",
				},
				cli.StringFlag{
					Name:  "label,l",
					Usage: "Comma separated name=value pairs, e.g name=sqlvolume,type=production",
				},
			},
		},
		{
			Name:    "snapDelete",
			Aliases: []string{"si"},
			Usage:   "Delete snap",
			Action:  v.snapDelete,
		},
	}
	return commands
}
<|endoftext|>


<commit_before>package messenger

import (
	"fmt"
	"net/http"
	"regexp"

	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/julienschmidt/httprouter"
	"github.com/liam-lai/ptt-alertor/command"
	"github.com/liam-lai/ptt-alertor/myutil"
)

const (
	SendAPIURL = "https://graph.facebook.com/v2.6/me/messages?access_token="
	ProfileURL = "https://graph.facebook.com/v2.6/me/messenger_profile?access_token="
)

type Messenger struct {
	VerifyToken string
	AccessToken string
}

var config map[string]string

func init() {
	config = myutil.Config("messenger")
}

func New() Messenger {
	return Messenger{
		VerifyToken: config["verifyToken"],
		AccessToken: config["accessToken"],
	}
}

func (m *Messenger) Verify(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	if r.FormValue("hub.mode") == "subscribe" && r.FormValue("hub.verify_token") == m.VerifyToken {
		log.Info("Validating webhook")
		resStr := r.FormValue("hub.challenge")
		fmt.Fprintln(w, resStr)
	} else {
		log.Info("Failed validation. Make sure the validation tokens match.")
		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
	}
}

func (m *Messenger) Received(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	data := Webhook{}
	json.NewDecoder(r.Body).Decode(&data)
	if data.Object == "page" {
		for _, entry := range data.Entry {
			for _, messaging := range entry.Messaging {
				id := messaging.Sender.ID
				if messaging.Message != nil {
					text := messaging.Message.Text
					if text != "" {
						if match, _ := regexp.MatchString("^(刪除|刪除作者)+\\s.*\\*+", text); match {
							m.SendConfirmation(id, text)
							return
						}
						responseText := command.HandleCommand(text, id)
						m.SendTextMessage(id, responseText)
					}
				} else if messaging.Postback != nil {
					payload := messaging.Postback.Payload
					log.WithField("payload", payload).Info("Messenger Postback")
					m.handlePostback(id, payload)
				}
			}
		}
	}
}

func (m *Messenger) handlePostback(id string, payload string) {
	var responseText string
	switch payload {
	case "GET_STARTED_PAYLOAD":
		err := command.HandleMessengerFollow(id)
		if err != nil {
			log.WithError(err).Error("Messenger Follow Error")
		}
		responseText = "歡迎使用 PTT Alertor\n輸入「指令」查看相關功能。\n\n觀看Demo:\nhttps://media.giphy.com/media/3ohzdF6vidM6I49lQs/giphy.gif"
	case "COMMANDS_PAYLOAD":
		// responseText = command.HandleCommand("指令", id)
		var str string
		commands := make(map[string]string)
		for cat, cmds := range command.Commands {
			for cmd, doc := range cmds {
				str += cmd + "：" + doc + "\n"
			}
			commands[cat] = str
			str = ""
		}
		m.SendListMessage(id, commands)
	case "SUBSCRIPTIONS_PAYLOAD":
		responseText = command.HandleCommand("清單", id)
	case "CANCEL":
		responseText = "取消"
	default:
		responseText = command.HandleCommand(payload, id)
	}
	m.SendTextMessage(id, responseText)
}

func (m *Messenger) SendTextMessage(id string, message string) {
	body := Request{
		Recipient{id},
		Message{Text: message},
	}
	log.WithField("ID", id).Info("Messenger Sent")
	m.callSendAPI(body)
}

func (m *Messenger) SendConfirmation(id string, cmd string) {
	attachment := Attachment{
		Type: "template",
		Payload: ButtonPayload{
			TemplateType: "button",
			Text:         "確認" + cmd,
			Buttons: Buttons{
				Button{"postback", "是", cmd},
				Button{"postback", "否", "CANCEL"},
			},
		},
	}
	body := Request{}
	body.Recipient.ID = id
	body.Message.Attachment = &attachment
	m.callSendAPI(body)
}

func (m *Messenger) SendQuickReplies(id string, payload string) {
	qrs := QuickReplies{
		QuickReply{"text", "是", payload},
		QuickReply{"text", "否", "CANCEL"},
	}
	body := Request{
		Recipient{id},
		Message{Text: "確定" + payload, QuickReplies: &qrs},
	}
	log.WithField("ID", id).Info("Messenger Confirmation Sent")
	m.callSendAPI(body)
}

func (m *Messenger) SendListMessage(id string, StringMap map[string]string) {
	elements := []Element{}
	for key, str := range StringMap {
		elements = append(elements, Element{
			Title:    key,
			Subtitle: str,
		})
	}
	attachment := Attachment{
		Type: "template",
		Payload: ListPayload{
			TemplateType:    "list",
			TopElementStyle: "compact",
			Elements:        elements,
		},
	}
	body := Request{}
	body.Recipient.ID = id
	body.Message.Attachment = &attachment
	m.callSendAPI(body)
}

func (m *Messenger) callSendAPI(body Request) {
	url := SendAPIURL + m.AccessToken
	err := callAPI(url, body)
	if err != nil {
		log.WithError(err).Error("Call Send API Error")
	}
}
<commit_msg>remove log<commit_after>package messenger

import (
	"fmt"
	"net/http"
	"regexp"

	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/julienschmidt/httprouter"
	"github.com/liam-lai/ptt-alertor/command"
	"github.com/liam-lai/ptt-alertor/myutil"
)

const (
	SendAPIURL = "https://graph.facebook.com/v2.6/me/messages?access_token="
	ProfileURL = "https://graph.facebook.com/v2.6/me/messenger_profile?access_token="
)

type Messenger struct {
	VerifyToken string
	AccessToken string
}

var config map[string]string

func init() {
	config = myutil.Config("messenger")
}

func New() Messenger {
	return Messenger{
		VerifyToken: config["verifyToken"],
		AccessToken: config["accessToken"],
	}
}

func (m *Messenger) Verify(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	if r.FormValue("hub.mode") == "subscribe" && r.FormValue("hub.verify_token") == m.VerifyToken {
		log.Info("Validating webhook")
		resStr := r.FormValue("hub.challenge")
		fmt.Fprintln(w, resStr)
	} else {
		log.Info("Failed validation. Make sure the validation tokens match.")
		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
	}
}

func (m *Messenger) Received(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	data := Webhook{}
	json.NewDecoder(r.Body).Decode(&data)
	if data.Object == "page" {
		for _, entry := range data.Entry {
			for _, messaging := range entry.Messaging {
				id := messaging.Sender.ID
				if messaging.Message != nil {
					text := messaging.Message.Text
					if text != "" {
						if match, _ := regexp.MatchString("^(刪除|刪除作者)+\\s.*\\*+", text); match {
							m.SendConfirmation(id, text)
							return
						}
						responseText := command.HandleCommand(text, id)
						m.SendTextMessage(id, responseText)
					}
				} else if messaging.Postback != nil {
					payload := messaging.Postback.Payload
					log.WithField("payload", payload).Info("Messenger Postback")
					m.handlePostback(id, payload)
				}
			}
		}
	}
}

func (m *Messenger) handlePostback(id string, payload string) {
	var responseText string
	switch payload {
	case "GET_STARTED_PAYLOAD":
		err := command.HandleMessengerFollow(id)
		if err != nil {
			log.WithError(err).Error("Messenger Follow Error")
		}
		responseText = "歡迎使用 PTT Alertor\n輸入「指令」查看相關功能。\n\n觀看Demo:\nhttps://media.giphy.com/media/3ohzdF6vidM6I49lQs/giphy.gif"
	case "COMMANDS_PAYLOAD":
		// responseText = command.HandleCommand("指令", id)
		var str string
		commands := make(map[string]string)
		for cat, cmds := range command.Commands {
			for cmd, doc := range cmds {
				str += cmd + "：" + doc + "\n"
			}
			commands[cat] = str
			str = ""
		}
		m.SendListMessage(id, commands)
	case "SUBSCRIPTIONS_PAYLOAD":
		responseText = command.HandleCommand("清單", id)
	case "CANCEL":
		responseText = "取消"
	default:
		responseText = command.HandleCommand(payload, id)
	}
	m.SendTextMessage(id, responseText)
}

func (m *Messenger) SendTextMessage(id string, message string) {
	body := Request{
		Recipient{id},
		Message{Text: message},
	}
	m.callSendAPI(body)
}

func (m *Messenger) SendConfirmation(id string, cmd string) {
	attachment := Attachment{
		Type: "template",
		Payload: ButtonPayload{
			TemplateType: "button",
			Text:         "確認" + cmd,
			Buttons: Buttons{
				Button{"postback", "是", cmd},
				Button{"postback", "否", "CANCEL"},
			},
		},
	}
	body := Request{}
	body.Recipient.ID = id
	body.Message.Attachment = &attachment
	m.callSendAPI(body)
}

func (m *Messenger) SendQuickReplies(id string, payload string) {
	qrs := QuickReplies{
		QuickReply{"text", "是", payload},
		QuickReply{"text", "否", "CANCEL"},
	}
	body := Request{
		Recipient{id},
		Message{Text: "確定" + payload, QuickReplies: &qrs},
	}
	log.WithField("ID", id).Info("Messenger Confirmation Sent")
	m.callSendAPI(body)
}

func (m *Messenger) SendListMessage(id string, StringMap map[string]string) {
	elements := []Element{}
	for key, str := range StringMap {
		elements = append(elements, Element{
			Title:    key,
			Subtitle: str,
		})
	}
	attachment := Attachment{
		Type: "template",
		Payload: ListPayload{
			TemplateType:    "list",
			TopElementStyle: "compact",
			Elements:        elements,
		},
	}
	body := Request{}
	body.Recipient.ID = id
	body.Message.Attachment = &attachment
	m.callSendAPI(body)
}

func (m *Messenger) callSendAPI(body Request) {
	url := SendAPIURL + m.AccessToken
	err := callAPI(url, body)
	if err != nil {
		log.WithError(err).Error("Call Send API Error")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os/exec"
	"runtime"

	"bitbucket.org/nstratos/mal"
)

func main() {

	//verify()
	//searchManga("naruto")
	//getAnime("Leonteus")
	//getManga("Leonteus")
	//data := mal.AnimeEntry{Status: "1", Score: 9}
	// data := mal.AnimeEntry{
	// 	Episode:            1,
	// 	Status:             "onhold",
	// 	Score:              4,
	// 	DownloadedEpisodes: 1,
	// 	StorageType:        0,
	// 	StorageValue:       0.0,
	// 	TimesRewatched:     1,
	// 	RewatchValue:       5,
	// 	DateStart:          "12252007",
	// 	DateFinish:         "12252008",
	// 	Priority:           3,
	// 	EnableDiscussion:   0,
	// 	EnableRewatching:   1,
	// 	Comments:           "good",
	// 	FansubGroup:        "horriblesubs",
	// 	Tags:               "mytag",
	// }
	//mal.UpdateAnime(9989, data)
	//mal.AddAnime(9989, data)
	//searchAnime("anohana")
	//mal.DeleteAnime(9989)
	//searchManga("anohana")
	//data := mal.MangaData{Status: "1", Score: 10}
	//mal.AddManga(35733, data)
	//mal.UpdateManga(35733, data)
	//mal.DeleteManga(35733)
	client := mal.NewClient()
	//client.SetCredentials("Leonteus", "001010100")
	// agent, err := ioutil.ReadFile("agent.txt")
	// if err != nil {
	// 	log.Fatalln("cannot read agent:", err)
	// }
	// client.SetUserAgent(string(agent))
	// _, err := client.Anime.Delete(11933)
	// if err != nil {
	// 	log.Fatalf("Anime.Delete error: %v\n", err)
	// }
	// _, err := client.Anime.Add(11933, mal.AnimeEntry{Status: "1", Score: 10})
	// if err != nil {
	// 	log.Fatalf("Anime.Add error: %v\n", err)
	// }
	result, resp, err := client.Manga.Search("anohana")
	if err != nil {
		log.Fatalf("Anime.Search error: %v, received: '%v'\n", err, string(resp.Body))
		//log.Fatalf("Anime.Search error: %v\n", err)
	}
	printMangaResult(result)
}

func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

func printAnimeList(list mal.AnimeList) {
	for _, anime := range list.Anime {
		fmt.Printf("----------------Anime-------------------\n")
		fmt.Printf("| MyID: %v\n", anime.MyID)
		fmt.Printf("| MyStartDate: %v\n", anime.MyStartDate)
		fmt.Printf("| MyFinishDate: %v\n", anime.MyFinishDate)
		fmt.Printf("| MyScore: %v\n", anime.MyScore)
		fmt.Printf("| MyStatus: %v\n", anime.MyStatus)
		fmt.Printf("| MyRewatching: %v\n", anime.MyRewatching)
		fmt.Printf("| MyRewatchingEp: %v\n", anime.MyRewatchingEp)
		fmt.Printf("| MyLastUpdated: %v\n", anime.MyLastUpdated)
		fmt.Printf("| MyTags: %v\n", anime.MyTags)
		fmt.Printf("| MyWatchedEpisodes: %v\n", anime.MyWatchedEpisodes)
		fmt.Printf("| SeriesAnimeDBID: %v\n", anime.SeriesAnimeDBID)
		fmt.Printf("| SeriesEpisodes: %v\n", anime.SeriesEpisodes)
		fmt.Printf("| SeriesTitle: %v\n", anime.SeriesTitle)
		fmt.Printf("| SeriesSynonyms: %v\n", anime.SeriesSynonyms)
		fmt.Printf("| SeriesType: %v\n", anime.SeriesType)
		fmt.Printf("| SeriesStatus: %v\n", anime.SeriesStatus)
		fmt.Printf("| SeriesStart: %v\n", anime.SeriesStart)
		fmt.Printf("| SeriesEnd: %v\n", anime.SeriesEnd)
		fmt.Printf("| SeriesImage: %v\n", anime.SeriesImage)
		fmt.Printf("\n")
	}
	fmt.Printf("----------------MyInfo------------------\n")
	fmt.Printf("| ID: %v\n", list.MyInfo.ID)
	fmt.Printf("| Name: %v\n", list.MyInfo.Name)
	fmt.Printf("| Completed: %v\n", list.MyInfo.Completed)
	fmt.Printf("| OnHold: %v\n", list.MyInfo.OnHold)
	fmt.Printf("| Dropped: %v\n", list.MyInfo.Dropped)
	fmt.Printf("| DaysSpentWatching: %v\n", list.MyInfo.DaysSpentWatching)
	fmt.Printf("| Watching: %v\n", list.MyInfo.Watching)
	fmt.Printf("| PlanToWatch: %v\n", list.MyInfo.PlanToWatch)
}

func printMangaList(list mal.MangaList) {
	for _, manga := range list.Manga {
		fmt.Printf("----------------Manga-------------------\n")
		fmt.Printf("| MyID: %v\n", manga.MyID)
		fmt.Printf("| MyStartDate: %v\n", manga.MyStartDate)
		fmt.Printf("| MyFinishDate: %v\n", manga.MyFinishDate)
		fmt.Printf("| MyScore: %v\n", manga.MyScore)
		fmt.Printf("| MyStatus: %v\n", manga.MyStatus)
		fmt.Printf("| MyRewatching: %v\n", manga.MyRewatching)
		fmt.Printf("| MyRewatchingEp: %v\n", manga.MyRewatchingEp)
		fmt.Printf("| MyLastUpdated: %v\n", manga.MyLastUpdated)
		fmt.Printf("| MyTags: %v\n", manga.MyTags)
		fmt.Printf("| MyReadChapters: %v\n", manga.MyReadChapters)
		fmt.Printf("| MyReadVolumes: %v\n", manga.MyReadVolumes)
		fmt.Printf("| SeriesMangaDBID: %v\n", manga.SeriesMangaDBID)
		fmt.Printf("| SeriesChapters: %v\n", manga.SeriesChapters)
		fmt.Printf("| SeriesVolumes: %v\n", manga.SeriesVolumes)
		fmt.Printf("| SeriesTitle: %v\n", manga.SeriesTitle)
		fmt.Printf("| SeriesSynonyms: %v\n", manga.SeriesSynonyms)
		fmt.Printf("| SeriesType: %v\n", manga.SeriesType)
		fmt.Printf("| SeriesStatus: %v\n", manga.SeriesStatus)
		fmt.Printf("| SeriesStart: %v\n", manga.SeriesStart)
		fmt.Printf("| SeriesEnd: %v\n", manga.SeriesEnd)
		fmt.Printf("| SeriesImage: %v\n", manga.SeriesImage)
		fmt.Printf("\n")
	}
	fmt.Printf("----------------MyInfo------------------\n")
	fmt.Printf("| ID: %v\n", list.MyInfo.ID)
	fmt.Printf("| Name: %v\n", list.MyInfo.Name)
	fmt.Printf("| Completed: %v\n", list.MyInfo.Completed)
	fmt.Printf("| OnHold: %v\n", list.MyInfo.OnHold)
	fmt.Printf("| Dropped: %v\n", list.MyInfo.Dropped)
	fmt.Printf("| DaysSpentWatching: %v\n", list.MyInfo.DaysSpentWatching)
	fmt.Printf("| Reading: %v\n", list.MyInfo.Reading)
	fmt.Printf("| PlanToRead: %v\n", list.MyInfo.PlanToRead)
}

func printAnimeResult(result *mal.AnimeResult) {
	for _, entry := range result.Rows {
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("| ID: %v\n", entry.ID)
		fmt.Printf("| Title: %v\n", entry.Title)
		fmt.Printf("| Episodes: %d\n", entry.Episodes)
		fmt.Printf("| Type: %v\n", entry.Type)
		fmt.Printf("| Score: %v\n", entry.Score)
		fmt.Printf("| Synopsis: %v\n", entry.Synopsis)
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("\n")
	}
}

func printMangaResult(result *mal.MangaResult) {
	for _, entry := range result.Rows {
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("| ID: %v\n", entry.ID)
		fmt.Printf("| Title: %v\n", entry.Title)
		fmt.Printf("| Chapters: %d\n", entry.Chapters)
		fmt.Printf("| Volumes: %d\n", entry.Volumes)
		fmt.Printf("| Type: %v\n", entry.Type)
		fmt.Printf("| Score: %v\n", entry.Score)
		fmt.Printf("| Synopsis: %v\n", entry.Synopsis)
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("\n")
	}
}
<commit_msg>cleanup main.go<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os/exec"
	"runtime"
	"strings"

	"bitbucket.org/nstratos/mal"
)

func main() {

	//verify()
	//searchManga("naruto")
	//getAnime("Leonteus")
	//getManga("Leonteus")
	//data := mal.AnimeEntry{Status: "1", Score: 9}
	// data := mal.AnimeEntry{
	// 	Episode:            1,
	// 	Status:             "onhold",
	// 	Score:              4,
	// 	DownloadedEpisodes: 1,
	// 	StorageType:        0,
	// 	StorageValue:       0.0,
	// 	TimesRewatched:     1,
	// 	RewatchValue:       5,
	// 	DateStart:          "12252007",
	// 	DateFinish:         "12252008",
	// 	Priority:           3,
	// 	EnableDiscussion:   0,
	// 	EnableRewatching:   1,
	// 	Comments:           "good",
	// 	FansubGroup:        "horriblesubs",
	// 	Tags:               "mytag",
	// }
	//mal.UpdateAnime(9989, data)
	//mal.AddAnime(9989, data)
	//searchAnime("anohana")
	//mal.DeleteAnime(9989)
	//searchManga("anohana")
	//data := mal.MangaData{Status: "1", Score: 10}
	//mal.AddManga(35733, data)
	//mal.UpdateManga(35733, data)
	//mal.DeleteManga(35733)
	client := mal.NewClient()
	agent, err := ioutil.ReadFile("agent.txt")
	if err != nil {
		log.Fatalln("cannot read agent:", err)
	}
	a := string(agent)
	s := strings.Split(a, "\n")
	client.SetUserAgent(s[0])
	client.SetCredentials(s[1], s[2])
	// _, err := client.Anime.Delete(11933)
	// if err != nil {
	// 	log.Fatalf("Anime.Delete error: %v\n", err)
	// }
	// _, err := client.Anime.Add(11933, mal.AnimeEntry{Status: "1", Score: 10})
	// if err != nil {
	// 	log.Fatalf("Anime.Add error: %v\n", err)
	// }
	result, resp, err := client.Manga.Search("anohana")
	if err != nil {
		log.Fatalf("Anime.Search error: %v, received: '%v'\n", err, string(resp.Body))
		//log.Fatalf("Anime.Search error: %v\n", err)
	}
	printMangaResult(result)
}

func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

func printAnimeList(list mal.AnimeList) {
	for _, anime := range list.Anime {
		fmt.Printf("----------------Anime-------------------\n")
		fmt.Printf("| MyID: %v\n", anime.MyID)
		fmt.Printf("| MyStartDate: %v\n", anime.MyStartDate)
		fmt.Printf("| MyFinishDate: %v\n", anime.MyFinishDate)
		fmt.Printf("| MyScore: %v\n", anime.MyScore)
		fmt.Printf("| MyStatus: %v\n", anime.MyStatus)
		fmt.Printf("| MyRewatching: %v\n", anime.MyRewatching)
		fmt.Printf("| MyRewatchingEp: %v\n", anime.MyRewatchingEp)
		fmt.Printf("| MyLastUpdated: %v\n", anime.MyLastUpdated)
		fmt.Printf("| MyTags: %v\n", anime.MyTags)
		fmt.Printf("| MyWatchedEpisodes: %v\n", anime.MyWatchedEpisodes)
		fmt.Printf("| SeriesAnimeDBID: %v\n", anime.SeriesAnimeDBID)
		fmt.Printf("| SeriesEpisodes: %v\n", anime.SeriesEpisodes)
		fmt.Printf("| SeriesTitle: %v\n", anime.SeriesTitle)
		fmt.Printf("| SeriesSynonyms: %v\n", anime.SeriesSynonyms)
		fmt.Printf("| SeriesType: %v\n", anime.SeriesType)
		fmt.Printf("| SeriesStatus: %v\n", anime.SeriesStatus)
		fmt.Printf("| SeriesStart: %v\n", anime.SeriesStart)
		fmt.Printf("| SeriesEnd: %v\n", anime.SeriesEnd)
		fmt.Printf("| SeriesImage: %v\n", anime.SeriesImage)
		fmt.Printf("\n")
	}
	fmt.Printf("----------------MyInfo------------------\n")
	fmt.Printf("| ID: %v\n", list.MyInfo.ID)
	fmt.Printf("| Name: %v\n", list.MyInfo.Name)
	fmt.Printf("| Completed: %v\n", list.MyInfo.Completed)
	fmt.Printf("| OnHold: %v\n", list.MyInfo.OnHold)
	fmt.Printf("| Dropped: %v\n", list.MyInfo.Dropped)
	fmt.Printf("| DaysSpentWatching: %v\n", list.MyInfo.DaysSpentWatching)
	fmt.Printf("| Watching: %v\n", list.MyInfo.Watching)
	fmt.Printf("| PlanToWatch: %v\n", list.MyInfo.PlanToWatch)
}

func printMangaList(list mal.MangaList) {
	for _, manga := range list.Manga {
		fmt.Printf("----------------Manga-------------------\n")
		fmt.Printf("| MyID: %v\n", manga.MyID)
		fmt.Printf("| MyStartDate: %v\n", manga.MyStartDate)
		fmt.Printf("| MyFinishDate: %v\n", manga.MyFinishDate)
		fmt.Printf("| MyScore: %v\n", manga.MyScore)
		fmt.Printf("| MyStatus: %v\n", manga.MyStatus)
		fmt.Printf("| MyRewatching: %v\n", manga.MyRewatching)
		fmt.Printf("| MyRewatchingEp: %v\n", manga.MyRewatchingEp)
		fmt.Printf("| MyLastUpdated: %v\n", manga.MyLastUpdated)
		fmt.Printf("| MyTags: %v\n", manga.MyTags)
		fmt.Printf("| MyReadChapters: %v\n", manga.MyReadChapters)
		fmt.Printf("| MyReadVolumes: %v\n", manga.MyReadVolumes)
		fmt.Printf("| SeriesMangaDBID: %v\n", manga.SeriesMangaDBID)
		fmt.Printf("| SeriesChapters: %v\n", manga.SeriesChapters)
		fmt.Printf("| SeriesVolumes: %v\n", manga.SeriesVolumes)
		fmt.Printf("| SeriesTitle: %v\n", manga.SeriesTitle)
		fmt.Printf("| SeriesSynonyms: %v\n", manga.SeriesSynonyms)
		fmt.Printf("| SeriesType: %v\n", manga.SeriesType)
		fmt.Printf("| SeriesStatus: %v\n", manga.SeriesStatus)
		fmt.Printf("| SeriesStart: %v\n", manga.SeriesStart)
		fmt.Printf("| SeriesEnd: %v\n", manga.SeriesEnd)
		fmt.Printf("| SeriesImage: %v\n", manga.SeriesImage)
		fmt.Printf("\n")
	}
	fmt.Printf("----------------MyInfo------------------\n")
	fmt.Printf("| ID: %v\n", list.MyInfo.ID)
	fmt.Printf("| Name: %v\n", list.MyInfo.Name)
	fmt.Printf("| Completed: %v\n", list.MyInfo.Completed)
	fmt.Printf("| OnHold: %v\n", list.MyInfo.OnHold)
	fmt.Printf("| Dropped: %v\n", list.MyInfo.Dropped)
	fmt.Printf("| DaysSpentWatching: %v\n", list.MyInfo.DaysSpentWatching)
	fmt.Printf("| Reading: %v\n", list.MyInfo.Reading)
	fmt.Printf("| PlanToRead: %v\n", list.MyInfo.PlanToRead)
}

func printAnimeResult(result *mal.AnimeResult) {
	for _, entry := range result.Rows {
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("| ID: %v\n", entry.ID)
		fmt.Printf("| Title: %v\n", entry.Title)
		fmt.Printf("| Episodes: %d\n", entry.Episodes)
		fmt.Printf("| Type: %v\n", entry.Type)
		fmt.Printf("| Score: %v\n", entry.Score)
		fmt.Printf("| Synopsis: %v\n", entry.Synopsis)
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("\n")
	}
}

func printMangaResult(result *mal.MangaResult) {
	for _, entry := range result.Rows {
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("| ID: %v\n", entry.ID)
		fmt.Printf("| Title: %v\n", entry.Title)
		fmt.Printf("| Chapters: %d\n", entry.Chapters)
		fmt.Printf("| Volumes: %d\n", entry.Volumes)
		fmt.Printf("| Type: %v\n", entry.Type)
		fmt.Printf("| Score: %v\n", entry.Score)
		fmt.Printf("| Synopsis: %v\n", entry.Synopsis)
		fmt.Printf("----------------------------------------\n")
		fmt.Printf("\n")
	}
}
<|endoftext|>


<commit_before>package client // import "github.com/docker/docker/client"

import (
	"context"
	"net/http"
	"path"

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

// Ping pings the server and returns the value of the "Docker-Experimental",
// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use
// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported
// by the daemon.
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
	var ping types.Ping

	// Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest()
	// because ping requests are used during  API version negotiation, so we want
	// to hit the non-versioned /_ping endpoint, not /v1.xx/_ping
	req, err := cli.buildRequest("HEAD", path.Join(cli.basePath, "/_ping"), nil, nil)
	if err != nil {
		return ping, err
	}
	serverResp, err := cli.doRequest(ctx, req)
	if err == nil {
		defer ensureReaderClosed(serverResp)
		switch serverResp.statusCode {
		case http.StatusOK, http.StatusInternalServerError:
			// Server handled the request, so parse the response
			return parsePingResponse(cli, serverResp)
		}
	}

	req, err = cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
	if err != nil {
		return ping, err
	}
	serverResp, err = cli.doRequest(ctx, req)
	defer ensureReaderClosed(serverResp)
	if err != nil {
		return ping, err
	}
	return parsePingResponse(cli, serverResp)
}

func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
	var ping types.Ping
	if resp.header == nil {
		err := cli.checkResponseErr(resp)
		return ping, errdefs.FromStatusCode(err, resp.statusCode)
	}
	ping.APIVersion = resp.header.Get("API-Version")
	ping.OSType = resp.header.Get("OSType")
	if resp.header.Get("Docker-Experimental") == "true" {
		ping.Experimental = true
	}
	if bv := resp.header.Get("Builder-Version"); bv != "" {
		ping.BuilderVersion = types.BuilderVersion(bv)
	}
	err := cli.checkResponseErr(resp)
	return ping, errdefs.FromStatusCode(err, resp.statusCode)
}
<commit_msg>client: do not fallback to GET if HEAD on _ping fail to connect<commit_after>package client // import "github.com/docker/docker/client"

import (
	"context"
	"net/http"
	"path"

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

// Ping pings the server and returns the value of the "Docker-Experimental",
// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use
// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported
// by the daemon.
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
	var ping types.Ping

	// Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest()
	// because ping requests are used during  API version negotiation, so we want
	// to hit the non-versioned /_ping endpoint, not /v1.xx/_ping
	req, err := cli.buildRequest("HEAD", path.Join(cli.basePath, "/_ping"), nil, nil)
	if err != nil {
		return ping, err
	}
	serverResp, err := cli.doRequest(ctx, req)
	if err == nil {
		defer ensureReaderClosed(serverResp)
		switch serverResp.statusCode {
		case http.StatusOK, http.StatusInternalServerError:
			// Server handled the request, so parse the response
			return parsePingResponse(cli, serverResp)
		}
	} else if IsErrConnectionFailed(err) {
		return ping, err
	}

	req, err = cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
	if err != nil {
		return ping, err
	}
	serverResp, err = cli.doRequest(ctx, req)
	defer ensureReaderClosed(serverResp)
	if err != nil {
		return ping, err
	}
	return parsePingResponse(cli, serverResp)
}

func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
	var ping types.Ping
	if resp.header == nil {
		err := cli.checkResponseErr(resp)
		return ping, errdefs.FromStatusCode(err, resp.statusCode)
	}
	ping.APIVersion = resp.header.Get("API-Version")
	ping.OSType = resp.header.Get("OSType")
	if resp.header.Get("Docker-Experimental") == "true" {
		ping.Experimental = true
	}
	if bv := resp.header.Get("Builder-Version"); bv != "" {
		ping.BuilderVersion = types.BuilderVersion(bv)
	}
	err := cli.checkResponseErr(resp)
	return ping, errdefs.FromStatusCode(err, resp.statusCode)
}
<|endoftext|>


<commit_before>// Copyright Istio Authors
//
// 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 sdscompare

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"time"

	envoy_admin "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
	auth "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"

	"istio.io/istio/istioctl/pkg/util/configdump"
	"istio.io/pkg/log"
)

// SecretItemDiff represents a secret that has been diffed between nodeagent and proxy
type SecretItemDiff struct {
	Agent string `json:"agent"`
	Proxy string `json:"proxy"`
	SecretItem
}

// SecretItem is an intermediate representation of secrets, used to provide a common
// format between the envoy proxy secrets and node agent output which can be diffed
type SecretItem struct {
	Name        string `json:"resource_name"`
	Data        string `json:"cert"`
	Source      string `json:"source"`
	Destination string `json:"destination"`
	State       string `json:"state"`
	SecretMeta
}

// SecretMeta holds selected fields which can be extracted from parsed x509 cert
type SecretMeta struct {
	Valid        bool   `json:"cert_valid"`
	SerialNumber string `json:"serial_number"`
	NotAfter     string `json:"not_after"`
	NotBefore    string `json:"not_before"`
	Type         string `json:"type"`
}

// NewSecretItemBuilder returns a new builder to create a secret item
func NewSecretItemBuilder() SecretItemBuilder {
	return &secretItemBuilder{}
}

// SecretItemBuilder wraps the process of setting fields for the SecretItem
// and builds the Metadata fields from the cert contents behind the scenes
type SecretItemBuilder interface {
	Name(string) SecretItemBuilder
	Data(string) SecretItemBuilder
	Source(string) SecretItemBuilder
	Destination(string) SecretItemBuilder
	State(string) SecretItemBuilder
	Build() (SecretItem, error)
}

// secretItemBuilder implements SecretItemBuilder, and acts as an intermediate before SecretItem generation
type secretItemBuilder struct {
	name   string
	data   string
	source string
	dest   string
	state  string
	SecretMeta
}

// Name sets the name field on a secretItemBuilder
func (s *secretItemBuilder) Name(name string) SecretItemBuilder {
	s.name = name
	return s
}

// Data sets the data field on a secretItemBuilder
func (s *secretItemBuilder) Data(data string) SecretItemBuilder {
	s.data = data
	return s
}

// Source sets the source field on a secretItemBuilder
func (s *secretItemBuilder) Source(source string) SecretItemBuilder {
	s.source = source
	return s
}

// Destination sets the destination field on a secretItemBuilder
func (s *secretItemBuilder) Destination(dest string) SecretItemBuilder {
	s.dest = dest
	return s
}

// State sets the state of the secret on the agent or sidecar
func (s *secretItemBuilder) State(state string) SecretItemBuilder {
	s.state = state
	return s
}

// Build takes the set fields from the builder and constructs the actual SecretItem
// including generating the SecretMeta from the supplied cert data, if present
func (s *secretItemBuilder) Build() (SecretItem, error) {
	result := SecretItem{
		Name:        s.name,
		Data:        s.data,
		Source:      s.source,
		Destination: s.dest,
		State:       s.state,
	}

	var meta SecretMeta
	var err error
	if s.data != "" {
		meta, err = secretMetaFromCert([]byte(s.data))
		if err != nil {
			log.Debugf("failed to parse secret resource %s from source %s: %v",
				s.name, s.source, err)
			result.Valid = false
			return result, nil
		}
		result.SecretMeta = meta
		result.Valid = true
		return result, nil
	}
	result.Valid = false
	return result, nil
}

// GetEnvoySecrets parses the secrets section of the config dump into []SecretItem
func GetEnvoySecrets(
	wrapper *configdump.Wrapper) ([]SecretItem, error) {
	secretConfigDump, err := wrapper.GetSecretConfigDump()
	if err != nil {
		return nil, err
	}

	proxySecretItems := make([]SecretItem, 0)
	for _, warmingSecret := range secretConfigDump.DynamicWarmingSecrets {
		secret, err := parseDynamicSecret(warmingSecret, "WARMING")
		if err != nil {
			return nil, fmt.Errorf("failed building warming secret %s: %v",
				warmingSecret.Name, err)
		}
		proxySecretItems = append(proxySecretItems, secret)
	}
	for _, activeSecret := range secretConfigDump.DynamicActiveSecrets {
		secret, err := parseDynamicSecret(activeSecret, "ACTIVE")
		if err != nil {
			return nil, fmt.Errorf("failed building warming secret %s: %v",
				activeSecret.Name, err)
		}
		proxySecretItems = append(proxySecretItems, secret)
	}
	return proxySecretItems, nil
}

func parseDynamicSecret(s *envoy_admin.SecretsConfigDump_DynamicSecret, state string) (SecretItem, error) {
	builder := NewSecretItemBuilder()
	builder.Name(s.Name).State(state)

	secretTyped := &auth.Secret{}
	err := s.GetSecret().UnmarshalTo(secretTyped)
	if err != nil {
		return SecretItem{}, err
	}

	certChainSecret := secretTyped.
		GetTlsCertificate().
		GetCertificateChain().
		GetInlineBytes()
	caDataSecret := secretTyped.
		GetValidationContext().
		GetTrustedCa().
		GetInlineBytes()

	// seems as though the most straightforward way to tell whether this is a root ca or not
	// is to check whether the inline bytes of the cert chain or the trusted ca field is zero length
	if len(certChainSecret) > 0 {
		builder.Data(string(certChainSecret))
	} else if len(caDataSecret) > 0 {
		builder.Data(string(caDataSecret))
	}

	secret, err := builder.Build()
	if err != nil {
		return SecretItem{}, fmt.Errorf("error building secret: %v", err)
	}

	return secret, nil
}

func secretMetaFromCert(rawCert []byte) (SecretMeta, error) {
	block, _ := pem.Decode(rawCert)
	if block == nil {
		return SecretMeta{}, fmt.Errorf("failed to parse certificate PEM")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return SecretMeta{}, err
	}
	var certType string
	if cert.IsCA {
		certType = "CA"
	} else {
		certType = "Cert Chain"
	}

	return SecretMeta{
		SerialNumber: fmt.Sprintf("%d", cert.SerialNumber),
		NotAfter:     cert.NotAfter.Format(time.RFC3339),
		NotBefore:    cert.NotBefore.Format(time.RFC3339),
		Type:         certType,
	}, nil
}
<commit_msg>Add UNINITIALIZED state to `istioctl proxy-config secret` (#36539)<commit_after>// Copyright Istio Authors
//
// 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 sdscompare

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"time"

	envoy_admin "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
	auth "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"

	"istio.io/istio/istioctl/pkg/util/configdump"
	"istio.io/pkg/log"
)

// SecretItemDiff represents a secret that has been diffed between nodeagent and proxy
type SecretItemDiff struct {
	Agent string `json:"agent"`
	Proxy string `json:"proxy"`
	SecretItem
}

// SecretItem is an intermediate representation of secrets, used to provide a common
// format between the envoy proxy secrets and node agent output which can be diffed
type SecretItem struct {
	Name        string `json:"resource_name"`
	Data        string `json:"cert"`
	Source      string `json:"source"`
	Destination string `json:"destination"`
	State       string `json:"state"`
	SecretMeta
}

// SecretMeta holds selected fields which can be extracted from parsed x509 cert
type SecretMeta struct {
	Valid        bool   `json:"cert_valid"`
	SerialNumber string `json:"serial_number"`
	NotAfter     string `json:"not_after"`
	NotBefore    string `json:"not_before"`
	Type         string `json:"type"`
}

// NewSecretItemBuilder returns a new builder to create a secret item
func NewSecretItemBuilder() SecretItemBuilder {
	return &secretItemBuilder{}
}

// SecretItemBuilder wraps the process of setting fields for the SecretItem
// and builds the Metadata fields from the cert contents behind the scenes
type SecretItemBuilder interface {
	Name(string) SecretItemBuilder
	Data(string) SecretItemBuilder
	Source(string) SecretItemBuilder
	Destination(string) SecretItemBuilder
	State(string) SecretItemBuilder
	Build() (SecretItem, error)
}

// secretItemBuilder implements SecretItemBuilder, and acts as an intermediate before SecretItem generation
type secretItemBuilder struct {
	name   string
	data   string
	source string
	dest   string
	state  string
	SecretMeta
}

// Name sets the name field on a secretItemBuilder
func (s *secretItemBuilder) Name(name string) SecretItemBuilder {
	s.name = name
	return s
}

// Data sets the data field on a secretItemBuilder
func (s *secretItemBuilder) Data(data string) SecretItemBuilder {
	s.data = data
	return s
}

// Source sets the source field on a secretItemBuilder
func (s *secretItemBuilder) Source(source string) SecretItemBuilder {
	s.source = source
	return s
}

// Destination sets the destination field on a secretItemBuilder
func (s *secretItemBuilder) Destination(dest string) SecretItemBuilder {
	s.dest = dest
	return s
}

// State sets the state of the secret on the agent or sidecar
func (s *secretItemBuilder) State(state string) SecretItemBuilder {
	s.state = state
	return s
}

// Build takes the set fields from the builder and constructs the actual SecretItem
// including generating the SecretMeta from the supplied cert data, if present
func (s *secretItemBuilder) Build() (SecretItem, error) {
	result := SecretItem{
		Name:        s.name,
		Data:        s.data,
		Source:      s.source,
		Destination: s.dest,
		State:       s.state,
	}

	var meta SecretMeta
	var err error
	if s.data != "" {
		meta, err = secretMetaFromCert([]byte(s.data))
		if err != nil {
			log.Debugf("failed to parse secret resource %s from source %s: %v",
				s.name, s.source, err)
			result.Valid = false
			return result, nil
		}
		result.SecretMeta = meta
		result.Valid = true
		return result, nil
	}
	result.Valid = false
	return result, nil
}

// GetEnvoySecrets parses the secrets section of the config dump into []SecretItem
func GetEnvoySecrets(
	wrapper *configdump.Wrapper) ([]SecretItem, error) {
	secretConfigDump, err := wrapper.GetSecretConfigDump()
	if err != nil {
		return nil, err
	}

	proxySecretItems := make([]SecretItem, 0)
	for _, warmingSecret := range secretConfigDump.DynamicWarmingSecrets {
		secret, err := parseDynamicSecret(warmingSecret, "WARMING")
		if err != nil {
			return nil, fmt.Errorf("failed building warming secret %s: %v",
				warmingSecret.Name, err)
		}
		proxySecretItems = append(proxySecretItems, secret)
	}
	for _, activeSecret := range secretConfigDump.DynamicActiveSecrets {
		secret, err := parseDynamicSecret(activeSecret, "ACTIVE")
		if err != nil {
			return nil, fmt.Errorf("failed building warming secret %s: %v",
				activeSecret.Name, err)
		}
		if activeSecret.VersionInfo == "uninitialized" {
			secret.State = "UNINITIALIZED"
		}
		proxySecretItems = append(proxySecretItems, secret)
	}
	return proxySecretItems, nil
}

func parseDynamicSecret(s *envoy_admin.SecretsConfigDump_DynamicSecret, state string) (SecretItem, error) {
	builder := NewSecretItemBuilder()
	builder.Name(s.Name).State(state)

	secretTyped := &auth.Secret{}
	err := s.GetSecret().UnmarshalTo(secretTyped)
	if err != nil {
		return SecretItem{}, err
	}

	certChainSecret := secretTyped.
		GetTlsCertificate().
		GetCertificateChain().
		GetInlineBytes()
	caDataSecret := secretTyped.
		GetValidationContext().
		GetTrustedCa().
		GetInlineBytes()

	// seems as though the most straightforward way to tell whether this is a root ca or not
	// is to check whether the inline bytes of the cert chain or the trusted ca field is zero length
	if len(certChainSecret) > 0 {
		builder.Data(string(certChainSecret))
	} else if len(caDataSecret) > 0 {
		builder.Data(string(caDataSecret))
	}

	secret, err := builder.Build()
	if err != nil {
		return SecretItem{}, fmt.Errorf("error building secret: %v", err)
	}

	return secret, nil
}

func secretMetaFromCert(rawCert []byte) (SecretMeta, error) {
	block, _ := pem.Decode(rawCert)
	if block == nil {
		return SecretMeta{}, fmt.Errorf("failed to parse certificate PEM")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return SecretMeta{}, err
	}
	var certType string
	if cert.IsCA {
		certType = "CA"
	} else {
		certType = "Cert Chain"
	}

	return SecretMeta{
		SerialNumber: fmt.Sprintf("%d", cert.SerialNumber),
		NotAfter:     cert.NotAfter.Format(time.RFC3339),
		NotBefore:    cert.NotBefore.Format(time.RFC3339),
		Type:         certType,
	}, nil
}
<|endoftext|>


<commit_before>package cmd

// Version is the current version of the buffalo binary
var Version = "0.7.0"
<commit_msg>version bump 0.7.1<commit_after>package cmd

// Version is the current version of the buffalo binary
var Version = "0.7.1"
<|endoftext|>


<commit_before>package statsd

import (
	"fmt"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"testing"
	"time"
)

func TestBufferedTotal(t *testing.T) {
	ln, udpAddr := newLocalListenerUDP(t)
	defer ln.Close()

	prefix := "myproject."

	client := NewStatsdClient(udpAddr.String(), prefix)
	buffered := NewStatsdBuffer(time.Millisecond*20, client)

	ch := make(chan string, 0)

	s := map[string]int64{
		"a:b:c": 5,
		"d:e:f": 2,
		"x:b:c": 5,
		"g.h.i": 1,
	}

	expected := make(map[string]int64)
	for k, v := range s {
		expected[k] = v
	}

	// also test %HOST% replacement
	s["zz.%HOST%"] = 1
	hostname, err := os.Hostname()
	expected["zz."+hostname] = 1

	go doListenUDP(t, ln, ch, len(s))

	err = buffered.CreateSocket()
	if nil != err {
		t.Fatal(err)
	}
	defer buffered.Close()

	for k, v := range s {
		buffered.Total(k, v)
	}

	actual := make(map[string]int64)

	re := regexp.MustCompile(`^(.*)\:(\d+)\|(\w).*$`)

	received := 0

	for received < len(s) {
		batch := <-ch
		for _, x := range strings.Split(batch, "\n") {
			x = strings.TrimSpace(x)
			//fmt.Println(x)
			if !strings.HasPrefix(x, prefix) {
				t.Errorf("Metric without expected prefix: expected '%s', actual '%s'", prefix, x)
				return
			}
			received++
			vv := re.FindStringSubmatch(x)
			fmt.Println(vv, x)
			if vv[3] != "t" {
				t.Errorf("Metric without expected suffix: expected 't', actual '%s'", vv[3])
			}
			v, err := strconv.ParseInt(vv[2], 10, 64)
			if err != nil {
				t.Error(err)
			}
			actual[vv[1][len(prefix):]] = v
		}
	}

	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("did not receive all metrics: Expected: %T %v, Actual: %T %v ", expected, expected, actual, actual)
	}
}
<commit_msg>buffered_client_test: there is only one UDP message<commit_after>package statsd

import (
	"fmt"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"testing"
	"time"
)

func TestBufferedTotal(t *testing.T) {
	ln, udpAddr := newLocalListenerUDP(t)
	defer ln.Close()

	prefix := "myproject."

	client := NewStatsdClient(udpAddr.String(), prefix)
	buffered := NewStatsdBuffer(time.Millisecond*20, client)

	ch := make(chan string, 0)

	s := map[string]int64{
		"a:b:c": 5,
		"d:e:f": 2,
		"x:b:c": 5,
		"g.h.i": 1,
	}

	expected := make(map[string]int64)
	for k, v := range s {
		expected[k] = v
	}

	// also test %HOST% replacement
	s["zz.%HOST%"] = 1
	hostname, err := os.Hostname()
	expected["zz."+hostname] = 1

	go doListenUDP(t, ln, ch, 1)

	err = buffered.CreateSocket()
	if nil != err {
		t.Fatal(err)
	}
	defer buffered.Close()

	for k, v := range s {
		buffered.Total(k, v)
	}

	actual := make(map[string]int64)

	re := regexp.MustCompile(`^(.*)\:(\d+)\|(\w).*$`)

	received := 0

	for received < len(s) {
		batch := <-ch
		for _, x := range strings.Split(batch, "\n") {
			x = strings.TrimSpace(x)
			//fmt.Println(x)
			if !strings.HasPrefix(x, prefix) {
				t.Errorf("Metric without expected prefix: expected '%s', actual '%s'", prefix, x)
				return
			}
			received++
			vv := re.FindStringSubmatch(x)
			fmt.Println(vv, x)
			if vv[3] != "t" {
				t.Errorf("Metric without expected suffix: expected 't', actual '%s'", vv[3])
			}
			v, err := strconv.ParseInt(vv[2], 10, 64)
			if err != nil {
				t.Error(err)
			}
			actual[vv[1][len(prefix):]] = v
		}
	}

	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("did not receive all metrics: Expected: %T %v, Actual: %T %v ", expected, expected, actual, actual)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package objabi

// For the linkers. Must match Go definitions.

const (
	STACKSYSTEM = 0
	StackSystem = STACKSYSTEM
	StackBig    = 4096
	StackSmall  = 128
)

const (
	StackPreempt = -1314 // 0xfff...fade
)

// Initialize StackGuard and StackLimit according to target system.
var StackGuard = 928*stackGuardMultiplier() + StackSystem
var StackLimit = StackGuard - StackSystem - StackSmall

// stackGuardMultiplier returns a multiplier to apply to the default
// stack guard size. Larger multipliers are used for non-optimized
// builds that have larger stack frames or for specific targets.
func stackGuardMultiplier() int {
	// On AIX, a larger stack is needed for syscalls.
	if GOOS == "aix" {
		return 2
	}
	return stackGuardMultiplierDefault
}
<commit_msg>cmd/internal/objabi: remove StackPreempt<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package objabi

// For the linkers. Must match Go definitions.

const (
	STACKSYSTEM = 0
	StackSystem = STACKSYSTEM
	StackBig    = 4096
	StackSmall  = 128
)

// Initialize StackGuard and StackLimit according to target system.
var StackGuard = 928*stackGuardMultiplier() + StackSystem
var StackLimit = StackGuard - StackSystem - StackSmall

// stackGuardMultiplier returns a multiplier to apply to the default
// stack guard size. Larger multipliers are used for non-optimized
// builds that have larger stack frames or for specific targets.
func stackGuardMultiplier() int {
	// On AIX, a larger stack is needed for syscalls.
	if GOOS == "aix" {
		return 2
	}
	return stackGuardMultiplierDefault
}
<|endoftext|>


<commit_before>package system

import (
	"testing"

	"reflect"

	"kego.io/json"
	"kego.io/kerr/assert"
	"kego.io/process/tests"
)

func TestTypeSortedFields(t *testing.T) {
	ty := &Type{
		Object: &Object{Id: NewReference("a.b/c", "d")},
		Fields: map[string]RuleInterface{
			"c": &StringRule{},
			"b": &StringRule{},
			"a": &StringRule{},
		},
	}
	f := ty.SortedFields()
	assert.Equal(t, "a", f[0].Name)
	assert.Equal(t, "b", f[1].Name)
	assert.Equal(t, "c", f[2].Name)
}

func TestNativeValueGolangType(t *testing.T) {
	test := func(expected string, in string) {
		ty := &Type{Native: NewString(in)}
		v, err := ty.NativeValueGolangType()
		assert.NoError(t, err)
		assert.Equal(t, expected, v)
	}
	test("float64", "number")
	test("string", "string")
	test("bool", "bool")
	testErr := func(in string) {
		ty := &Type{Native: NewString(in)}
		_, err := ty.NativeValueGolangType()
		assert.IsError(t, err, "TXQIDRBJRH")
	}
	testErr("map")
	testErr("object")
	testErr("array")
	testErr("null")
	testErr("")
	testErr("foo")
}

func TestIsNativeObject(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeObject(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(false, "map")
	test(true, "object")
	test(false, "array")
	test(true, "null")
	test(true, "")
	test(true, "foo")
}

func TestIsNativeArray(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeArray(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(false, "map")
	test(false, "object")
	test(true, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsNativeMap(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeMap(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(true, "map")
	test(false, "object")
	test(false, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsNativeCollection(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeCollection(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(true, "map")
	test(false, "object")
	test(true, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsNativeValue(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeValue(), in)
	}
	test(true, "number")
	test(true, "string")
	test(true, "bool")
	test(false, "map")
	test(false, "object")
	test(false, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsJsonValue(t *testing.T) {
	test := func(expected bool, in *Reference) {
		ty := &Type{Object: &Object{Id: in}}
		assert.Equal(t, expected, ty.IsJsonValue(), in)
	}
	test(false, NewReference("a.b/c", "d"))
	test(true, NewReference("kego.io/json", "a"))
}

func TestNativeJsonType(t *testing.T) {
	test := func(expected json.Type, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.NativeJsonType(), in)
	}
	test(json.J_NUMBER, "number")
	test(json.J_STRING, "string")
	test(json.J_BOOL, "bool")
	test(json.J_MAP, "map")
	test(json.J_OBJECT, "object")
	test(json.J_ARRAY, "array")
	test(json.J_NULL, "null")
	test(json.J_NULL, "")
	test(json.J_NULL, "foo")
}

func TestGetTypeFromCache(t *testing.T) {
	d := &Type{Object: &Object{Id: NewReference("a.b/c", "d")}}
	cb := tests.Context("a.b/c").Stype("d", d)
	ty, ok := GetTypeFromCache(cb.Ctx(), "a.b/c", "d")
	assert.True(t, ok)
	assert.Equal(t, d, ty)

	ty, ok = GetTypeFromCache(cb.Ctx(), "a.b/c", "e")
	assert.False(t, ok)

	ty, ok = GetTypeFromCache(cb.Ctx(), "f", "g")
	assert.False(t, ok)
}

type iFoo interface {
	foo()
}
type iBar interface {
	bar()
}
type tFoo struct{}

func (*tFoo) foo() {

}

type tFooBar struct{}

func (*tFooBar) foo() {

}
func (*tFooBar) bar() {

}

func TestGetAllTypesThatImplementInterface(t *testing.T) {

	ibar := &Type{Object: &Object{Id: NewReference("a.b/c", "ibar")}, Interface: true}
	tfoo := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoo")}}
	tfoobar := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoobar")}}

	cb := tests.
		Context("a.b/c").
		Jtype("ibar", reflect.TypeOf((*iBar)(nil)).Elem()).Stype("ibar", ibar).
		JtypeIface("tfoo", reflect.TypeOf(&tFoo{}), reflect.TypeOf((*iFoo)(nil)).Elem()).Stype("tfoo", tfoo).
		Jtype("tfoobar", reflect.TypeOf(&tFooBar{})).Stype("tfoobar", tfoobar)

	types := GetAllTypesThatImplementInterface(cb.Ctx(), ibar)
	assert.Equal(t, 1, len(types))
	assert.Equal(t, "tfoobar", types[0].Id.Name)

	types = GetAllTypesThatImplementInterface(cb.Ctx(), tfoo)
	assert.Equal(t, 2, len(types))
	assert.Equal(t, "tfoo", types[0].Id.Name)
	assert.Equal(t, "tfoobar", types[1].Id.Name)

	types = GetAllTypesThatImplementInterface(cb.Ctx(), &Type{Object: &Object{Id: NewReference("a.b/c", "d")}})
	assert.Nil(t, types)

	types = GetAllTypesThatImplementInterface(cb.Ctx(), &Type{Object: &Object{Id: NewReference("a.b/c", "d")}, Interface: true})
	assert.Nil(t, types)

}

type tInt int

func TestZeroValue(t *testing.T) {
	tfoo := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoo")}, Native: NewString("object")}
	cb := tests.
		Context("a.b/c").
		Jtype("tfoo", reflect.TypeOf(&tFoo{})).Stype("tfoo", tfoo)

	i, err := tfoo.ZeroValue(cb.Ctx())
	assert.NoError(t, err)
	tf, ok := i.(*tFoo)
	assert.True(t, ok)
	assert.Nil(t, tf)

	tint := &Type{Object: &Object{Id: NewReference("a.b/c", "tint")}, Native: NewString("int")}
	cb.Jtype("tint", reflect.TypeOf(tInt(0))).Stype("tint", tint)

	i, err = tint.ZeroValue(cb.Ctx())
	assert.NoError(t, err)
	ti, ok := i.(tInt)
	assert.True(t, ok)
	assert.Equal(t, ti, tInt(0))

	tnil := &Type{Object: &Object{Id: NewReference("a.b/c", "d")}, Native: NewString("object")}
	i, err = tnil.ZeroValue(cb.Ctx())
	assert.IsError(t, err, "RSWTEOTNBD")
}

func TestTypeImplements(t *testing.T) {
	tfoo := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoo")}}
	cb := tests.
		Context("a.b/c").
		Jtype("tfoo", reflect.TypeOf(&tFoo{})).Stype("tfoo", tfoo)

	assert.False(t, tfoo.Implements(cb.Ctx(), reflect.TypeOf((*iBar)(nil)).Elem()))
	assert.True(t, tfoo.Implements(cb.Ctx(), reflect.TypeOf((*iFoo)(nil)).Elem()))
	tnil := &Type{Object: &Object{Id: NewReference("a.b/c", "tnil")}}
	assert.False(t, tnil.Implements(cb.Ctx(), reflect.TypeOf((*iFoo)(nil)).Elem()))
}

func TestNativeGoType(t *testing.T) {
	n, err := nativeGoType("string")
	assert.NoError(t, err)
	assert.Equal(t, "string", n)

	n, err = nativeGoType("number")
	assert.NoError(t, err)
	assert.Equal(t, "float64", n)

	n, err = nativeGoType("bool")
	assert.NoError(t, err)
	assert.Equal(t, "bool", n)

	_, err = nativeGoType("a")
	assert.IsError(t, err, "TXQIDRBJRH")
}

func TestTypeIsNativeType(t *testing.T) {
	y := &Type{Native: NewString("bool")}
	n := y.IsNativeObject()
	assert.False(t, n)

	y = &Type{Native: NewString("array")}
	n = y.IsNativeObject()
	assert.False(t, n)

	y = &Type{Native: NewString("object")}
	n = y.IsNativeObject()
	assert.True(t, n)

	// Will also return true for any other value
	y = &Type{Native: NewString("a")}
	n = y.IsNativeObject()
	assert.True(t, n)
}

func TestTypeNativeValueGolangType(t *testing.T) {
	y := &Type{Native: NewString("bool")}
	n, err := y.NativeValueGolangType()
	assert.NoError(t, err)
	assert.Equal(t, "bool", n)
}

func TestTypeGoName(t *testing.T) {
	y := &Type{Object: &Object{Id: NewReference("a.b/c", "aa")}}
	n := y.GoName()
	assert.Equal(t, "Aa", n)
}
<commit_msg>Test ZeroValue<commit_after>package system

import (
	"testing"

	"reflect"

	"golang.org/x/net/context"
	"kego.io/json"
	"kego.io/kerr/assert"
	"kego.io/process/tests"
)

func TestTypeSortedFields(t *testing.T) {
	ty := &Type{
		Object: &Object{Id: NewReference("a.b/c", "d")},
		Fields: map[string]RuleInterface{
			"c": &StringRule{},
			"b": &StringRule{},
			"a": &StringRule{},
		},
	}
	f := ty.SortedFields()
	assert.Equal(t, "a", f[0].Name)
	assert.Equal(t, "b", f[1].Name)
	assert.Equal(t, "c", f[2].Name)
}

func TestNativeValueGolangType(t *testing.T) {
	test := func(expected string, in string) {
		ty := &Type{Native: NewString(in)}
		v, err := ty.NativeValueGolangType()
		assert.NoError(t, err)
		assert.Equal(t, expected, v)
	}
	test("float64", "number")
	test("string", "string")
	test("bool", "bool")
	testErr := func(in string) {
		ty := &Type{Native: NewString(in)}
		_, err := ty.NativeValueGolangType()
		assert.IsError(t, err, "TXQIDRBJRH")
	}
	testErr("map")
	testErr("object")
	testErr("array")
	testErr("null")
	testErr("")
	testErr("foo")
}

func TestIsNativeObject(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeObject(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(false, "map")
	test(true, "object")
	test(false, "array")
	test(true, "null")
	test(true, "")
	test(true, "foo")
}

func TestIsNativeArray(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeArray(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(false, "map")
	test(false, "object")
	test(true, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsNativeMap(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeMap(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(true, "map")
	test(false, "object")
	test(false, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsNativeCollection(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeCollection(), in)
	}
	test(false, "number")
	test(false, "string")
	test(false, "bool")
	test(true, "map")
	test(false, "object")
	test(true, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsNativeValue(t *testing.T) {
	test := func(expected bool, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.IsNativeValue(), in)
	}
	test(true, "number")
	test(true, "string")
	test(true, "bool")
	test(false, "map")
	test(false, "object")
	test(false, "array")
	test(false, "null")
	test(false, "")
	test(false, "foo")
}

func TestIsJsonValue(t *testing.T) {
	test := func(expected bool, in *Reference) {
		ty := &Type{Object: &Object{Id: in}}
		assert.Equal(t, expected, ty.IsJsonValue(), in)
	}
	test(false, NewReference("a.b/c", "d"))
	test(true, NewReference("kego.io/json", "a"))
}

func TestNativeJsonType(t *testing.T) {
	test := func(expected json.Type, in string) {
		ty := &Type{Native: NewString(in)}
		assert.Equal(t, expected, ty.NativeJsonType(), in)
	}
	test(json.J_NUMBER, "number")
	test(json.J_STRING, "string")
	test(json.J_BOOL, "bool")
	test(json.J_MAP, "map")
	test(json.J_OBJECT, "object")
	test(json.J_ARRAY, "array")
	test(json.J_NULL, "null")
	test(json.J_NULL, "")
	test(json.J_NULL, "foo")
}

func TestGetTypeFromCache(t *testing.T) {
	d := &Type{Object: &Object{Id: NewReference("a.b/c", "d")}}
	cb := tests.Context("a.b/c").Stype("d", d)
	ty, ok := GetTypeFromCache(cb.Ctx(), "a.b/c", "d")
	assert.True(t, ok)
	assert.Equal(t, d, ty)

	ty, ok = GetTypeFromCache(cb.Ctx(), "a.b/c", "e")
	assert.False(t, ok)

	ty, ok = GetTypeFromCache(cb.Ctx(), "f", "g")
	assert.False(t, ok)
}

type iFoo interface {
	foo()
}
type iBar interface {
	bar()
}
type tFoo struct{}

func (*tFoo) foo() {

}

type tFooBar struct{}

func (*tFooBar) foo() {

}
func (*tFooBar) bar() {

}

func TestGetAllTypesThatImplementInterface(t *testing.T) {

	ibar := &Type{Object: &Object{Id: NewReference("a.b/c", "ibar")}, Interface: true}
	tfoo := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoo")}}
	tfoobar := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoobar")}}

	cb := tests.
		Context("a.b/c").
		Jtype("ibar", reflect.TypeOf((*iBar)(nil)).Elem()).Stype("ibar", ibar).
		JtypeIface("tfoo", reflect.TypeOf(&tFoo{}), reflect.TypeOf((*iFoo)(nil)).Elem()).Stype("tfoo", tfoo).
		Jtype("tfoobar", reflect.TypeOf(&tFooBar{})).Stype("tfoobar", tfoobar)

	types := GetAllTypesThatImplementInterface(cb.Ctx(), ibar)
	assert.Equal(t, 1, len(types))
	assert.Equal(t, "tfoobar", types[0].Id.Name)

	types = GetAllTypesThatImplementInterface(cb.Ctx(), tfoo)
	assert.Equal(t, 2, len(types))
	assert.Equal(t, "tfoo", types[0].Id.Name)
	assert.Equal(t, "tfoobar", types[1].Id.Name)

	types = GetAllTypesThatImplementInterface(cb.Ctx(), &Type{Object: &Object{Id: NewReference("a.b/c", "d")}})
	assert.Nil(t, types)

	types = GetAllTypesThatImplementInterface(cb.Ctx(), &Type{Object: &Object{Id: NewReference("a.b/c", "d")}, Interface: true})
	assert.Nil(t, types)

}

type tInt int

func TestZeroValue(t *testing.T) {

	ty := &Type{Native: NewString("map")}
	_, err := ty.ZeroValue(context.Background())
	assert.IsError(t, err, "PGUHCGBJWE")

	tfoo := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoo")}, Native: NewString("object")}
	cb := tests.
		Context("a.b/c").
		Jtype("tfoo", reflect.TypeOf(&tFoo{})).Stype("tfoo", tfoo)

	i, err := tfoo.ZeroValue(cb.Ctx())
	assert.NoError(t, err)
	tf, ok := i.(*tFoo)
	assert.True(t, ok)
	assert.Nil(t, tf)

	tint := &Type{Object: &Object{Id: NewReference("a.b/c", "tint")}, Native: NewString("int")}
	cb.Jtype("tint", reflect.TypeOf(tInt(0))).Stype("tint", tint)

	i, err = tint.ZeroValue(cb.Ctx())
	assert.NoError(t, err)
	ti, ok := i.(tInt)
	assert.True(t, ok)
	assert.Equal(t, ti, tInt(0))

	tnil := &Type{Object: &Object{Id: NewReference("a.b/c", "d")}, Native: NewString("object")}
	i, err = tnil.ZeroValue(cb.Ctx())
	assert.IsError(t, err, "RSWTEOTNBD")
}

func TestTypeImplements(t *testing.T) {
	tfoo := &Type{Object: &Object{Id: NewReference("a.b/c", "tfoo")}}
	cb := tests.
		Context("a.b/c").
		Jtype("tfoo", reflect.TypeOf(&tFoo{})).Stype("tfoo", tfoo)

	assert.False(t, tfoo.Implements(cb.Ctx(), reflect.TypeOf((*iBar)(nil)).Elem()))
	assert.True(t, tfoo.Implements(cb.Ctx(), reflect.TypeOf((*iFoo)(nil)).Elem()))
	tnil := &Type{Object: &Object{Id: NewReference("a.b/c", "tnil")}}
	assert.False(t, tnil.Implements(cb.Ctx(), reflect.TypeOf((*iFoo)(nil)).Elem()))
}

func TestNativeGoType(t *testing.T) {
	n, err := nativeGoType("string")
	assert.NoError(t, err)
	assert.Equal(t, "string", n)

	n, err = nativeGoType("number")
	assert.NoError(t, err)
	assert.Equal(t, "float64", n)

	n, err = nativeGoType("bool")
	assert.NoError(t, err)
	assert.Equal(t, "bool", n)

	_, err = nativeGoType("a")
	assert.IsError(t, err, "TXQIDRBJRH")
}

func TestTypeIsNativeType(t *testing.T) {
	y := &Type{Native: NewString("bool")}
	n := y.IsNativeObject()
	assert.False(t, n)

	y = &Type{Native: NewString("array")}
	n = y.IsNativeObject()
	assert.False(t, n)

	y = &Type{Native: NewString("object")}
	n = y.IsNativeObject()
	assert.True(t, n)

	// Will also return true for any other value
	y = &Type{Native: NewString("a")}
	n = y.IsNativeObject()
	assert.True(t, n)
}

func TestTypeNativeValueGolangType(t *testing.T) {
	y := &Type{Native: NewString("bool")}
	n, err := y.NativeValueGolangType()
	assert.NoError(t, err)
	assert.Equal(t, "bool", n)
}

func TestTypeGoName(t *testing.T) {
	y := &Type{Object: &Object{Id: NewReference("a.b/c", "aa")}}
	n := y.GoName()
	assert.Equal(t, "Aa", n)
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"errors"
	"github.com/globocom/tsuru/router"
	"sync"
)

var ErrBackendNotFound = errors.New("Backend not found")

func init() {
	router.Register("fake", &FakeRouter{backends: make(map[string][]string)})
}

type FakeRouter struct {
	backends map[string][]string
	mutex    sync.Mutex
}

func (r *FakeRouter) HasBackend(name string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	_, ok := r.backends[name]
	return ok
}

func (r *FakeRouter) HasRoute(name, address string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes, ok := r.backends[name]
	if !ok {
		return false
	}
	for _, route := range routes {
		if route == address {
			return true
		}
	}
	return false
}

func (r *FakeRouter) AddBackend(name string) error {
	if r.HasBackend(name) {
		return errors.New("Backend already exists")
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[name] = nil
	return nil
}

func (r *FakeRouter) RemoveBackend(name string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	delete(r.backends, name)
	return nil
}

func (r *FakeRouter) AddRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[name]
	routes = append(routes, ip)
	r.backends[name] = routes
	return nil
}

func (r *FakeRouter) RemoveRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[name]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[name] = routes[:len(routes)-1]
	return nil
}

func (FakeRouter) AddCNAME(cname, name, address string) error {
	return nil
}

func (FakeRouter) RemoveCNAME(cname, address string) error {
	return nil
}

func (r *FakeRouter) Addr(name string) (string, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if v, ok := r.backends[name]; ok {
		return v[0], nil
	}
	return "", ErrBackendNotFound
}
<commit_msg>router/testing: make the registered router public<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"errors"
	"github.com/globocom/tsuru/router"
	"sync"
)

var Instance = FakeRouter{backends: make(map[string][]string)}

var ErrBackendNotFound = errors.New("Backend not found")

func init() {
	router.Register("fake", &Instance)
}

type FakeRouter struct {
	backends map[string][]string
	mutex    sync.Mutex
}

func (r *FakeRouter) HasBackend(name string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	_, ok := r.backends[name]
	return ok
}

func (r *FakeRouter) HasRoute(name, address string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes, ok := r.backends[name]
	if !ok {
		return false
	}
	for _, route := range routes {
		if route == address {
			return true
		}
	}
	return false
}

func (r *FakeRouter) AddBackend(name string) error {
	if r.HasBackend(name) {
		return errors.New("Backend already exists")
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[name] = nil
	return nil
}

func (r *FakeRouter) RemoveBackend(name string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	delete(r.backends, name)
	return nil
}

func (r *FakeRouter) AddRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[name]
	routes = append(routes, ip)
	r.backends[name] = routes
	return nil
}

func (r *FakeRouter) RemoveRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[name]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[name] = routes[:len(routes)-1]
	return nil
}

func (FakeRouter) AddCNAME(cname, name, address string) error {
	return nil
}

func (FakeRouter) RemoveCNAME(cname, address string) error {
	return nil
}

func (r *FakeRouter) Addr(name string) (string, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if v, ok := r.backends[name]; ok {
		return v[0], nil
	}
	return "", ErrBackendNotFound
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"errors"
	"github.com/globocom/tsuru/router"
	"sync"
)

var FakeRouter = fakeRouter{backends: make(map[string][]string)}

var ErrBackendNotFound = errors.New("Backend not found")

func init() {
	router.Register("fake", &FakeRouter)
}

type fakeRouter struct {
	backends map[string][]string
	mutex    sync.Mutex
}

func (r *fakeRouter) HasBackend(name string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	_, ok := r.backends[name]
	return ok
}

func (r *fakeRouter) HasRoute(name, address string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes, ok := r.backends[name]
	if !ok {
		return false
	}
	for _, route := range routes {
		if route == address {
			return true
		}
	}
	return false
}

func (r *fakeRouter) AddBackend(name string) error {
	if r.HasBackend(name) {
		return errors.New("Backend already exists")
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[name] = nil
	return nil
}

func (r *fakeRouter) RemoveBackend(name string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	delete(r.backends, name)
	return nil
}

func (r *fakeRouter) AddRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[name]
	routes = append(routes, ip)
	r.backends[name] = routes
	return nil
}

func (r *fakeRouter) RemoveRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[name]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[name] = routes[:len(routes)-1]
	return nil
}

func (r *fakeRouter) AddCName(cname, name string) error {
	if !r.HasBackend(name) {
		return nil
	}
	r.AddBackend(cname)
	r.backends[cname] = append(r.backends[name])
	return nil
}

func (r *fakeRouter) RemoveCName(cname, address string) error {
	return r.RemoveRoute(cname, address)
}

func (r *fakeRouter) Addr(name string) (string, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if v, ok := r.backends[name]; ok {
		return v[0], nil
	}
	return "", ErrBackendNotFound
}

func (r *fakeRouter) Reset() {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends = make(map[string][]string)
}
<commit_msg>router/testing/router.go: added mutex in AddCName method<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"errors"
	"github.com/globocom/tsuru/router"
	"sync"
)

var FakeRouter = fakeRouter{backends: make(map[string][]string)}

var ErrBackendNotFound = errors.New("Backend not found")

func init() {
	router.Register("fake", &FakeRouter)
}

type fakeRouter struct {
	backends map[string][]string
	mutex    sync.Mutex
}

func (r *fakeRouter) HasBackend(name string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	_, ok := r.backends[name]
	return ok
}

func (r *fakeRouter) HasRoute(name, address string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes, ok := r.backends[name]
	if !ok {
		return false
	}
	for _, route := range routes {
		if route == address {
			return true
		}
	}
	return false
}

func (r *fakeRouter) AddBackend(name string) error {
	if r.HasBackend(name) {
		return errors.New("Backend already exists")
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[name] = nil
	return nil
}

func (r *fakeRouter) RemoveBackend(name string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	delete(r.backends, name)
	return nil
}

func (r *fakeRouter) AddRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[name]
	routes = append(routes, ip)
	r.backends[name] = routes
	return nil
}

func (r *fakeRouter) RemoveRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[name]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[name] = routes[:len(routes)-1]
	return nil
}

func (r *fakeRouter) AddCName(cname, name string) error {
	if !r.HasBackend(name) {
		return nil
	}
	r.AddBackend(cname)
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[cname] = append(r.backends[name])
	return nil
}

func (r *fakeRouter) RemoveCName(cname, address string) error {
	return r.RemoveRoute(cname, address)
}

func (r *fakeRouter) Addr(name string) (string, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if v, ok := r.backends[name]; ok {
		return v[0], nil
	}
	return "", ErrBackendNotFound
}

func (r *fakeRouter) Reset() {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends = make(map[string][]string)
}
<|endoftext|>


<commit_before>package clog

import "github.com/thatguystone/cog/cio/eio"

const (
	defaultConfigFileOutputName = "__default_config_file__"
	defaultTermOutputName       = "__default_term__"
)

// Config specifies basic config for logging.
//
// The Config struct is meant to be embedded directly into some other struct
// that you're Unmarshaling your application's config into (typically, this is a
// struct that is being filled by json.Unmarshal, yaml.Unmarshal, etc on
// application start).
type Config struct {
	// File is the simplest way of configuring this logger. It sets up a
	// JSONFile writing to the given path, with a root logger that only accepts
	// Info and greater.
	File string

	// Identifies all of the places where log entries are written. They keys in
	// this map name the output.
	Outputs map[string]*OutputConfig

	// Identifies all modules that you want to configure. They keys in this map
	// identify the module to work on.
	//
	// If no modules are given, everything at level Info and above goes to the
	// terminal by default.
	Modules map[string]*ModuleConfig
}

// OutputConfig specifies how an output is to be built
type OutputConfig struct {
	// Which Producer to use. This value is case-insensitive.
	//
	// The full list of Producers can be found at:
	// https://godoc.org/github.com/thatguystone/cog/cio/eio
	Prod     string
	ProdArgs eio.Args // Args to pass to the Producer

	// Which Formatter to use for this output.
	Fmt     string
	FmtArgs eio.Args // Args to pass to the Fmt

	// Log level to use for this output. Use Debug to accept all. This is
	// actually an implicit (and required) Filter.
	Level Level

	// Which filters to apply to this output.
	Filters []FilterConfig
}

// ModuleConfig specifies how a module to to be treated
type ModuleConfig struct {
	// The list of outputs to write to. These values come from the keys in the
	// Outputs map in Config.
	Outputs []string

	// Log level to use for this output. Use Debug to accept all. This is
	// actually an implicit (and required) Filter.
	Level Level

	// Which filters to apply to this module
	Filters []FilterConfig

	// By default, messages are propagated until the root logger. If you want
	// messages to stop here, set this to True.
	DontPropagate bool
}

// FilterConfig is for setting up a Filter
type FilterConfig struct {
	// Which the filter to use. This value is case-insensitive.
	Which string

	// Filter arguments
	Args eio.Args
}

var asdasdcfg = Config{
	// If set, this creates a new root module (the module named "" (the empty
	// string)), and it records any message level >= Info to the named file in
	// JSON format.
	File: "/var/log/app.log",

	Outputs: map[string]*OutputConfig{
		// Only errors with level >= Error will be logged here
		"errors": {
			Prod: "file",
			ProdArgs: eio.Args{
				"path": "/var/log/app.error.json.log",
			},
			Fmt:   "json",
			Level: Error,
			Filters: []FilterConfig{
				FilterConfig{
					Which: "exampleFilter",
					Args: eio.Args{
						"exampleConfig": "someValue",
					},
				},
			},
		},

		// All messages will be accepted here
		"debug": {
			Prod: "file",
			ProdArgs: eio.Args{
				"path": "/var/log/app.log.json",
			},
			Fmt:   "human", // Or "logfmt", or any other valid formatter
			Level: Debug,
		},

		// Only errors level >= Warn will be accepted here
		"heroku": {
			Prod: "file",
			ProdArgs: eio.Args{
				"path": "/var/log/app.logfmt",
			},
			Fmt: "human",
			FmtArgs: eio.Args{
				"ShortTime": true,
			},
			Level: Warn,
		},
	},

	Modules: map[string]*ModuleConfig{
		// All messages eventually reach here, unless DontPropagate==true in a
		// module
		"": {
			Outputs: []string{"errors"},
		},

		// This logs all messages level >= Info, where the filter allows the
		// message through, to the debug log. These messages do not propagate to
		// the root.
		"http": {
			Outputs: []string{"debug"},
			Level:   Info,
			Filters: []FilterConfig{
				FilterConfig{
					Which: "exampleFilter",
					Args: eio.Args{
						"exampleConfig": "someValue",
					},
				},
			},
			DontPropagate: true,
		},

		// This logs all messages level >= Warn, to both the heroku and errors
		// outputs. These messages do not propagate to the root.
		"templates": {
			Outputs:       []string{"heroku", "errors"},
			Level:         Warn,
			DontPropagate: true,
		},

		// This logs all messages from the external library to the debug log.
		// These messages also propagate to the root, which will log any error
		// messages. So, effectively, errors from this module will be logged
		// twice.
		"external.library": {
			Outputs: []string{"debug"},
			Level:   Debug,
		},
	},
}
<commit_msg>clog: Drop debug config<commit_after>package clog

import "github.com/thatguystone/cog/cio/eio"

const (
	defaultConfigFileOutputName = "__default_config_file__"
	defaultTermOutputName       = "__default_term__"
)

// Config specifies basic config for logging.
//
// The Config struct is meant to be embedded directly into some other struct
// that you're Unmarshaling your application's config into (typically, this is a
// struct that is being filled by json.Unmarshal, yaml.Unmarshal, etc on
// application start).
type Config struct {
	// File is the simplest way of configuring this logger. It sets up a
	// JSONFile writing to the given path, with a root logger that only accepts
	// Info and greater.
	File string

	// Identifies all of the places where log entries are written. They keys in
	// this map name the output.
	Outputs map[string]*OutputConfig

	// Identifies all modules that you want to configure. They keys in this map
	// identify the module to work on.
	//
	// If no modules are given, everything at level Info and above goes to the
	// terminal by default.
	Modules map[string]*ModuleConfig
}

// OutputConfig specifies how an output is to be built
type OutputConfig struct {
	// Which Producer to use. This value is case-insensitive.
	//
	// The full list of Producers can be found at:
	// https://godoc.org/github.com/thatguystone/cog/cio/eio
	Prod     string
	ProdArgs eio.Args // Args to pass to the Producer

	// Which Formatter to use for this output.
	Fmt     string
	FmtArgs eio.Args // Args to pass to the Fmt

	// Log level to use for this output. Use Debug to accept all. This is
	// actually an implicit (and required) Filter.
	Level Level

	// Which filters to apply to this output.
	Filters []FilterConfig
}

// ModuleConfig specifies how a module to to be treated
type ModuleConfig struct {
	// The list of outputs to write to. These values come from the keys in the
	// Outputs map in Config.
	Outputs []string

	// Log level to use for this output. Use Debug to accept all. This is
	// actually an implicit (and required) Filter.
	Level Level

	// Which filters to apply to this module
	Filters []FilterConfig

	// By default, messages are propagated until the root logger. If you want
	// messages to stop here, set this to True.
	DontPropagate bool
}

// FilterConfig is for setting up a Filter
type FilterConfig struct {
	// Which the filter to use. This value is case-insensitive.
	Which string

	// Filter arguments
	Args eio.Args
}
<|endoftext|>