<commit_before>package cmd

import (
	"strings"

	"github.com/rancher/go-rancher/v2"

	"github.com/urfave/cli"
)

/*
  -a, --attach=[]                 Attach to STDIN, STDOUT or STDERR
  --add-host=[]                   Add a custom host-to-IP mapping (host:ip)
  --blkio-weight                  Block IO (relative weight), between 10 and 1000
  --blkio-weight-device=[]        Block IO weight (relative device weight)
  --cgroup-parent                 Optional parent cgroup for the container
  --cidfile                       Write the container ID to the file
  --cpu-period                    Limit CPU CFS (Completely Fair Scheduler) period
  --cpu-quota                     Limit CPU CFS (Completely Fair Scheduler) quota
  --cpuset-cpus                   CPUs in which to allow execution (0-3, 0,1)
  --cpuset-mems                   MEMs in which to allow execution (0-3, 0,1)
  -d, --detach                    Run container in background and print container ID
  --detach-keys                   Override the key sequence for detaching a container
  --device-read-bps=[]            Limit read rate (bytes per second) from a device
  --device-read-iops=[]           Limit read rate (IO per second) from a device
  --device-write-bps=[]           Limit write rate (bytes per second) to a device
  --device-write-iops=[]          Limit write rate (IO per second) to a device
  --disable-content-trust=true    Skip image verification
  --dns-opt=[]                    Set DNS options
  -e, --env=[]                    Set environment variables
  --env-file=[]                   Read in a file of environment variables
  --group-add=[]                  Add additional groups to join
  --help                          Print usage
  --ip                            Container IPv4 address (e.g. 172.30.100.104)
  --ip6                           Container IPv6 address (e.g. 2001:db8::33)
  --ipc                           IPC namespace to use
  --isolation                     Container isolation level
  --kernel-memory                 Kernel memory limit
  -l, --label=[]                  Set meta data on a container
  --label-file=[]                 Read in a line delimited file of labels
  --link=[]                       Add link to another container
  --log-driver                    Logging driver for container
  --log-opt=[]                    Log driver options
  --mac-address                   Container MAC address (e.g. 92:d0:c6:0a:29:33)
  --memory-reservation            Memory soft limit
  --memory-swappiness=-1          Tune container memory swappiness (0 to 100)
  --net=default                   Connect a container to a network
  --net-alias=[]                  Add network-scoped alias for the container
  --oom-kill-disable              Disable OOM Killer
  --oom-score-adj                 Tune host's OOM preferences (-1000 to 1000)
  --restart=no                    Restart policy to apply when a container exits
  --rm                            Automatically remove the container when it exits
  --shm-size                      Size of /dev/shm, default value is 64MB
  --sig-proxy=true                Proxy received signals to the process
  --stop-signal=SIGTERM           Signal to stop a container, SIGTERM by default
  --tmpfs=[]                      Mount a tmpfs directory
  --ulimit=[]                     Ulimit options
  --uts                           UTS namespace to use
  -v, --volume=[]                 Bind mount a volume
  --volumes-from=[]               Mount volumes from the specified container(s)
*/

func RunCommand() cli.Command {
	return cli.Command{
		Name:   "run",
		Usage:  "Run services",
		Action: serviceRun,
		Flags: []cli.Flag{
			cli.Int64Flag{
				Name:  "cpu-shares",
				Usage: "CPU shares (relative weight)",
			},
			cli.StringSliceFlag{
				Name:  "cap-add",
				Usage: "Add Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "cap-drop",
				Usage: "Drop Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "device",
				Usage: "Add a host device to the container",
			},
			cli.StringSliceFlag{
				Name:  "dns",
				Usage: "Set custom DNS servers",
			},
			cli.StringSliceFlag{
				Name:  "dns-search",
				Usage: "Set custom DNS search domains",
			},
			cli.StringSliceFlag{
				Name:  "entrypoint",
				Usage: "Overwrite the default ENTRYPOINT of the image",
			},
			cli.StringSliceFlag{
				Name:  "expose",
				Usage: "Expose a port or a range of ports",
			},
			cli.StringFlag{
				Name:  "hostname",
				Usage: "Container host name",
			},
			cli.BoolFlag{
				Name:  "interactive, i",
				Usage: "Keep STDIN open even if not attached",
			},
			cli.Int64Flag{
				Name:  "memory, m",
				Usage: "Memory limit",
			},
			cli.Int64Flag{
				Name:  "memory-swap",
				Usage: "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
			},
			cli.StringFlag{
				Name:  "name",
				Usage: "Assign a name to the container",
			},
			cli.BoolFlag{
				Name:  "publish-all",
				Usage: "Publish all exposed ports to random ports",
			},
			cli.StringSliceFlag{
				Name:  "publish, p",
				Usage: "Publish a container's `port`(s) to the host",
			},
			cli.StringFlag{
				Name:  "pid",
				Usage: "PID namespace to use",
			},
			cli.BoolFlag{
				Name:  "privileged",
				Usage: "Give extended privileges to this container",
			},
			cli.BoolFlag{
				Name:  "read-only",
				Usage: "Mount the container's root filesystem as read only",
			},
			cli.StringSliceFlag{
				Name:  "security-opt",
				Usage: "Security Options",
			},
			cli.BoolFlag{
				Name:  "tty, t",
				Usage: "Allocate a pseudo-TTY",
			},
			cli.StringFlag{
				Name:  "user, u",
				Usage: "Username or UID (format: <name|uid>[:<group|gid>])",
			},
			cli.StringFlag{
				Name:  "volume-driver",
				Usage: "Optional volume driver for the container",
			},
			cli.StringFlag{
				Name:  "workdir, w",
				Usage: "Working directory inside the container",
			},
			cli.StringFlag{
				Name:  "log-driver",
				Usage: "Logging driver for container",
			},
			cli.StringSliceFlag{
				Name:  "log-opt",
				Usage: "Log driver options",
			},
			cli.StringSliceFlag{
				Name:  "volume, v",
				Usage: "Bind mount a volume",
			},
			cli.StringFlag{
				Name:  "net",
				Usage: "Connect a container to a network: host, none, bridge, managed",
				Value: "managed",
			},
			cli.IntFlag{
				Name:  "scale",
				Usage: "Number of containers to run",
				Value: 1,
			},
			cli.BoolFlag{
				Name:  "schedule-global",
				Usage: "Run 1 container per host",
			},
			cli.StringSliceFlag{
				Name:  "label,l",
				Usage: "Add label in the form of key=value",
			},
			cli.BoolFlag{
				Name:  "pull",
				Usage: "Always pull image on container start",
			},
		},
	}
}

func ParseName(c *client.RancherClient, name string) (*client.Stack, string, error) {
	stackName := ""
	serviceName := name

	parts := strings.SplitN(name, "/", 2)
	if len(parts) == 2 {
		stackName = parts[0]
		serviceName = parts[1]
	}

	stack, err := GetOrCreateDefaultStack(c, stackName)
	if err != nil {
		return stack, "", err
	}

	if serviceName == "" {
		serviceName = RandomName()
	}

	return stack, serviceName, nil
}

func serviceRun(ctx *cli.Context) error {
	c, err := GetClient(ctx)
	if ctx.NArg() < 1 {
		return cli.NewExitError("Image name is required as the first argument", 1)
	}

	if err != nil {
		return err
	}

	launchConfig := &client.LaunchConfig{
		//BlkioDeviceOptions:
		CapAdd:  ctx.StringSlice("cap-add"),
		CapDrop: ctx.StringSlice("cap-drop"),
		//CpuSet: ctx.String(""),
		CpuShares:  ctx.Int64("cpu-shares"),
		Devices:    ctx.StringSlice("device"),
		Dns:        ctx.StringSlice("dns"),
		DnsSearch:  ctx.StringSlice("dns-search"),
		EntryPoint: ctx.StringSlice("entrypoint"),
		Expose:     ctx.StringSlice("expose"),
		Hostname:   ctx.String("hostname"),
		ImageUuid:  "docker:" + ctx.Args()[0],
		Labels:     map[string]interface{}{},
		//LogConfig:
		Memory:     ctx.Int64("memory"),
		MemorySwap: ctx.Int64("memory-swap"),
		//NetworkIds: ctx.StringSlice("networkids"),
		NetworkMode:     ctx.String("net"),
		PidMode:         ctx.String("pid"),
		Ports:           ctx.StringSlice("publish"),
		Privileged:      ctx.Bool("privileged"),
		PublishAllPorts: ctx.Bool("publish-all"),
		ReadOnly:        ctx.Bool("read-only"),
		SecurityOpt:     ctx.StringSlice("security-opt"),
		StdinOpen:       ctx.Bool("interactive"),
		Tty:             ctx.Bool("tty"),
		User:            ctx.String("user"),
		VolumeDriver:    ctx.String("volume-driver"),
		WorkingDir:      ctx.String("workdir"),
		DataVolumes:     ctx.StringSlice("volume"),
	}

	if ctx.String("log-driver") != "" || len(ctx.StringSlice("log-opt")) > 0 {
		launchConfig.LogConfig = &client.LogConfig{
			Driver: ctx.String("log-driver"),
			Config: map[string]interface{}{},
		}
		for _, opt := range ctx.StringSlice("log-opt") {
			parts := strings.SplitN(opt, "=", 2)
			if len(parts) > 1 {
				launchConfig.LogConfig.Config[parts[0]] = parts[1]
			} else {
				launchConfig.LogConfig.Config[parts[0]] = ""
			}
		}
	}

	for _, label := range ctx.StringSlice("label") {
		parts := strings.SplitN(label, "=", 1)
		value := ""
		if len(parts) > 1 {
			value = parts[1]
		}
		launchConfig.Labels[parts[0]] = value
	}

	if ctx.Bool("schedule-global") {
		launchConfig.Labels["io.rancher.scheduler.global"] = "true"
	}

	if ctx.Bool("pull") {
		launchConfig.Labels["io.rancher.container.pull_image"] = "always"
	}

	args := ctx.Args()[1:]

	if len(args) > 0 {
		launchConfig.Command = args
	}

	stack, name, err := ParseName(c, ctx.String("name"))
	if err != nil {
		return err
	}

	service := &client.Service{
		Name:          name,
		StackId:       stack.Id,
		LaunchConfig:  launchConfig,
		StartOnCreate: true,
		Scale:         int64(ctx.Int("scale")),
	}

	service, err = c.Service.Create(service)
	if err != nil {
		return err
	}

	return WaitFor(ctx, service.Id)
}
<commit_msg>Fix labels in run<commit_after>package cmd

import (
	"strings"

	"github.com/rancher/go-rancher/v2"

	"github.com/urfave/cli"
)

/*
  -a, --attach=[]                 Attach to STDIN, STDOUT or STDERR
  --add-host=[]                   Add a custom host-to-IP mapping (host:ip)
  --blkio-weight                  Block IO (relative weight), between 10 and 1000
  --blkio-weight-device=[]        Block IO weight (relative device weight)
  --cgroup-parent                 Optional parent cgroup for the container
  --cidfile                       Write the container ID to the file
  --cpu-period                    Limit CPU CFS (Completely Fair Scheduler) period
  --cpu-quota                     Limit CPU CFS (Completely Fair Scheduler) quota
  --cpuset-cpus                   CPUs in which to allow execution (0-3, 0,1)
  --cpuset-mems                   MEMs in which to allow execution (0-3, 0,1)
  -d, --detach                    Run container in background and print container ID
  --detach-keys                   Override the key sequence for detaching a container
  --device-read-bps=[]            Limit read rate (bytes per second) from a device
  --device-read-iops=[]           Limit read rate (IO per second) from a device
  --device-write-bps=[]           Limit write rate (bytes per second) to a device
  --device-write-iops=[]          Limit write rate (IO per second) to a device
  --disable-content-trust=true    Skip image verification
  --dns-opt=[]                    Set DNS options
  -e, --env=[]                    Set environment variables
  --env-file=[]                   Read in a file of environment variables
  --group-add=[]                  Add additional groups to join
  --help                          Print usage
  --ip                            Container IPv4 address (e.g. 172.30.100.104)
  --ip6                           Container IPv6 address (e.g. 2001:db8::33)
  --ipc                           IPC namespace to use
  --isolation                     Container isolation level
  --kernel-memory                 Kernel memory limit
  -l, --label=[]                  Set meta data on a container
  --label-file=[]                 Read in a line delimited file of labels
  --link=[]                       Add link to another container
  --log-driver                    Logging driver for container
  --log-opt=[]                    Log driver options
  --mac-address                   Container MAC address (e.g. 92:d0:c6:0a:29:33)
  --memory-reservation            Memory soft limit
  --memory-swappiness=-1          Tune container memory swappiness (0 to 100)
  --net=default                   Connect a container to a network
  --net-alias=[]                  Add network-scoped alias for the container
  --oom-kill-disable              Disable OOM Killer
  --oom-score-adj                 Tune host's OOM preferences (-1000 to 1000)
  --restart=no                    Restart policy to apply when a container exits
  --rm                            Automatically remove the container when it exits
  --shm-size                      Size of /dev/shm, default value is 64MB
  --sig-proxy=true                Proxy received signals to the process
  --stop-signal=SIGTERM           Signal to stop a container, SIGTERM by default
  --tmpfs=[]                      Mount a tmpfs directory
  --ulimit=[]                     Ulimit options
  --uts                           UTS namespace to use
  -v, --volume=[]                 Bind mount a volume
  --volumes-from=[]               Mount volumes from the specified container(s)
*/

func RunCommand() cli.Command {
	return cli.Command{
		Name:   "run",
		Usage:  "Run services",
		Action: serviceRun,
		Flags: []cli.Flag{
			cli.Int64Flag{
				Name:  "cpu-shares",
				Usage: "CPU shares (relative weight)",
			},
			cli.StringSliceFlag{
				Name:  "cap-add",
				Usage: "Add Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "cap-drop",
				Usage: "Drop Linux capabilities",
			},
			cli.StringSliceFlag{
				Name:  "device",
				Usage: "Add a host device to the container",
			},
			cli.StringSliceFlag{
				Name:  "dns",
				Usage: "Set custom DNS servers",
			},
			cli.StringSliceFlag{
				Name:  "dns-search",
				Usage: "Set custom DNS search domains",
			},
			cli.StringSliceFlag{
				Name:  "entrypoint",
				Usage: "Overwrite the default ENTRYPOINT of the image",
			},
			cli.StringSliceFlag{
				Name:  "expose",
				Usage: "Expose a port or a range of ports",
			},
			cli.StringFlag{
				Name:  "hostname",
				Usage: "Container host name",
			},
			cli.BoolFlag{
				Name:  "interactive, i",
				Usage: "Keep STDIN open even if not attached",
			},
			cli.Int64Flag{
				Name:  "memory, m",
				Usage: "Memory limit",
			},
			cli.Int64Flag{
				Name:  "memory-swap",
				Usage: "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
			},
			cli.StringFlag{
				Name:  "name",
				Usage: "Assign a name to the container",
			},
			cli.BoolFlag{
				Name:  "publish-all",
				Usage: "Publish all exposed ports to random ports",
			},
			cli.StringSliceFlag{
				Name:  "publish, p",
				Usage: "Publish a container's `port`(s) to the host",
			},
			cli.StringFlag{
				Name:  "pid",
				Usage: "PID namespace to use",
			},
			cli.BoolFlag{
				Name:  "privileged",
				Usage: "Give extended privileges to this container",
			},
			cli.BoolFlag{
				Name:  "read-only",
				Usage: "Mount the container's root filesystem as read only",
			},
			cli.StringSliceFlag{
				Name:  "security-opt",
				Usage: "Security Options",
			},
			cli.BoolFlag{
				Name:  "tty, t",
				Usage: "Allocate a pseudo-TTY",
			},
			cli.StringFlag{
				Name:  "user, u",
				Usage: "Username or UID (format: <name|uid>[:<group|gid>])",
			},
			cli.StringFlag{
				Name:  "volume-driver",
				Usage: "Optional volume driver for the container",
			},
			cli.StringFlag{
				Name:  "workdir, w",
				Usage: "Working directory inside the container",
			},
			cli.StringFlag{
				Name:  "log-driver",
				Usage: "Logging driver for container",
			},
			cli.StringSliceFlag{
				Name:  "log-opt",
				Usage: "Log driver options",
			},
			cli.StringSliceFlag{
				Name:  "volume, v",
				Usage: "Bind mount a volume",
			},
			cli.StringFlag{
				Name:  "net",
				Usage: "Connect a container to a network: host, none, bridge, managed",
				Value: "managed",
			},
			cli.IntFlag{
				Name:  "scale",
				Usage: "Number of containers to run",
				Value: 1,
			},
			cli.BoolFlag{
				Name:  "schedule-global",
				Usage: "Run 1 container per host",
			},
			cli.StringSliceFlag{
				Name:  "label,l",
				Usage: "Add label in the form of key=value",
			},
			cli.BoolFlag{
				Name:  "pull",
				Usage: "Always pull image on container start",
			},
		},
	}
}

func ParseName(c *client.RancherClient, name string) (*client.Stack, string, error) {
	stackName := ""
	serviceName := name

	parts := strings.SplitN(name, "/", 2)
	if len(parts) == 2 {
		stackName = parts[0]
		serviceName = parts[1]
	}

	stack, err := GetOrCreateDefaultStack(c, stackName)
	if err != nil {
		return stack, "", err
	}

	if serviceName == "" {
		serviceName = RandomName()
	}

	return stack, serviceName, nil
}

func serviceRun(ctx *cli.Context) error {
	c, err := GetClient(ctx)
	if ctx.NArg() < 1 {
		return cli.NewExitError("Image name is required as the first argument", 1)
	}

	if err != nil {
		return err
	}

	launchConfig := &client.LaunchConfig{
		//BlkioDeviceOptions:
		CapAdd:  ctx.StringSlice("cap-add"),
		CapDrop: ctx.StringSlice("cap-drop"),
		//CpuSet: ctx.String(""),
		CpuShares:  ctx.Int64("cpu-shares"),
		Devices:    ctx.StringSlice("device"),
		Dns:        ctx.StringSlice("dns"),
		DnsSearch:  ctx.StringSlice("dns-search"),
		EntryPoint: ctx.StringSlice("entrypoint"),
		Expose:     ctx.StringSlice("expose"),
		Hostname:   ctx.String("hostname"),
		ImageUuid:  "docker:" + ctx.Args()[0],
		Labels:     map[string]interface{}{},
		//LogConfig:
		Memory:     ctx.Int64("memory"),
		MemorySwap: ctx.Int64("memory-swap"),
		//NetworkIds: ctx.StringSlice("networkids"),
		NetworkMode:     ctx.String("net"),
		PidMode:         ctx.String("pid"),
		Ports:           ctx.StringSlice("publish"),
		Privileged:      ctx.Bool("privileged"),
		PublishAllPorts: ctx.Bool("publish-all"),
		ReadOnly:        ctx.Bool("read-only"),
		SecurityOpt:     ctx.StringSlice("security-opt"),
		StdinOpen:       ctx.Bool("interactive"),
		Tty:             ctx.Bool("tty"),
		User:            ctx.String("user"),
		VolumeDriver:    ctx.String("volume-driver"),
		WorkingDir:      ctx.String("workdir"),
		DataVolumes:     ctx.StringSlice("volume"),
	}

	if ctx.String("log-driver") != "" || len(ctx.StringSlice("log-opt")) > 0 {
		launchConfig.LogConfig = &client.LogConfig{
			Driver: ctx.String("log-driver"),
			Config: map[string]interface{}{},
		}
		for _, opt := range ctx.StringSlice("log-opt") {
			parts := strings.SplitN(opt, "=", 2)
			if len(parts) > 1 {
				launchConfig.LogConfig.Config[parts[0]] = parts[1]
			} else {
				launchConfig.LogConfig.Config[parts[0]] = ""
			}
		}
	}

	for _, label := range ctx.StringSlice("label") {
		parts := strings.SplitN(label, "=", 2)
		value := ""
		if len(parts) > 1 {
			value = parts[1]
		}
		launchConfig.Labels[parts[0]] = value
	}

	if ctx.Bool("schedule-global") {
		launchConfig.Labels["io.rancher.scheduler.global"] = "true"
	}

	if ctx.Bool("pull") {
		launchConfig.Labels["io.rancher.container.pull_image"] = "always"
	}

	args := ctx.Args()[1:]

	if len(args) > 0 {
		launchConfig.Command = args
	}

	stack, name, err := ParseName(c, ctx.String("name"))
	if err != nil {
		return err
	}

	service := &client.Service{
		Name:          name,
		StackId:       stack.Id,
		LaunchConfig:  launchConfig,
		StartOnCreate: true,
		Scale:         int64(ctx.Int("scale")),
	}

	service, err = c.Service.Create(service)
	if err != nil {
		return err
	}

	return WaitFor(ctx, service.Id)
}
<|endoftext|>


<commit_before>package	gearman	// import "github.com/nathanaelle/gearman"

import	(
	"fmt"
)

type	(
	Command	uint64
)

const	(
	CAN_DO			Command = 0x0052455100000001	// 1	REQ    Worker
	CANT_DO			Command = 0x0052455100000002	// 2	REQ    Worker
	RESET_ABILITIES		Command = 0x0052455100000003	// 3	REQ    Worker
	PRE_SLEEP		Command = 0x0052455100000004	// 4	REQ    Worker
	NOOP			Command = 0x0052455300000006	// 6	RES    Worker
	SUBMIT_JOB		Command = 0x0052455100000007	// 7	REQ    Client
	JOB_CREATED		Command = 0x0052455300000008	// 8	RES    Client
	GRAB_JOB		Command = 0x0052455100000009	// 9	REQ    Worker
	NO_JOB			Command = 0x005245530000000a	// 10	RES    Worker
	JOB_ASSIGN		Command = 0x005245530000000b	// 11	RES    Worker
	WORK_STATUS_WRK		Command = 0x005245510000000c	// 12	REQ    Worker
	WORK_STATUS		Command = 0x005245530000000c	// 12	RES    Client
	WORK_COMPLETE_WRK	Command = 0x005245510000000d	// 13	REQ    Worker
	WORK_COMPLETE		Command = 0x005245530000000d	// 13	RES    Client
	WORK_FAIL_WRK		Command = 0x005245510000000e	// 14	REQ    Worker
	WORK_FAIL		Command = 0x005245530000000e	// 14	RES    Client
	GET_STATUS		Command = 0x005245510000000f	// 15	REQ    Client
	ECHO_REQ		Command = 0x0052455100000010	// 16	REQ    Client/Worker
	ECHO_RES		Command = 0x0052455300000011	// 17	RES    Client/Worker
	SUBMIT_JOB_BG		Command = 0x0052455100000012	// 18	REQ    Client
	ERROR			Command = 0x0052455300000013	// 19	RES    Client/Worker
	STATUS_RES		Command = 0x0052455300000014	// 20	RES    Client
	SUBMIT_JOB_HIGH		Command = 0x0052455100000015	// 21	REQ    Client
	SET_CLIENT_ID		Command = 0x0052455100000016	// 22	REQ    Worker
	CAN_DO_TIMEOUT		Command = 0x0052455100000017	// 23	REQ    Worker
	ALL_YOURS		Command = 0x0052455100000018	// 24	REQ    Worker
	WORK_EXCEPTION_WRK	Command = 0x0052455100000019	// 25	REQ    Worker
	WORK_EXCEPTION		Command = 0x0052455300000019	// 25	RES    Client
	OPTION_REQ		Command = 0x005245510000001a	// 26	REQ    Client/Worker
	OPTION_RES		Command = 0x005245530000001b	// 27	RES    Client/Worker
	WORK_DATA_WRK		Command = 0x005245510000001c	// 28	REQ    Worker
	WORK_DATA		Command = 0x005245530000001c	// 28	RES    Client
	WORK_WARNING_WRK	Command = 0x005245510000001d	// 29	REQ    Worker
	WORK_WARNING		Command = 0x005245530000001d	// 29	RES    Client
	GRAB_JOB_UNIQ		Command = 0x005245510000001e	// 30	REQ    Worker
	JOB_ASSIGN_UNIQ		Command = 0x005245530000001f	// 31	RES    Worker
	SUBMIT_JOB_HIGH_BG	Command = 0x0052455100000020	// 32	REQ    Client
	SUBMIT_JOB_LOW		Command = 0x0052455100000021	// 33	REQ    Client
	SUBMIT_JOB_LOW_BG	Command = 0x0052455100000022	// 34	REQ    Client
	SUBMIT_JOB_SCHED	Command = 0x0052455100000023	// 35	REQ    Client
	SUBMIT_JOB_EPOCH	Command = 0x0052455100000024	// 36	REQ    Client

	OK			Command = 0x0052455300000040
	ADMIN_WORKERS		Command = 0x0052455100000041
	ADMIN_STATUS		Command = 0x0052455100000042
	ADMIN_MAX_QUEUE		Command = 0x0052455100000043
	ADMIN_SHUTDOWN		Command = 0x0052455100000044
	ADMIN_VERSION		Command = 0x0052455100000045
	ADMIN_WORKERS_LIST	Command = 0x0052455300000046
	ADMIN_STATUS_LIST	Command = 0x0052455300000047
)

func (c Command)String() string {
	switch	c {
	case	CAN_DO:			return	"CAN_DO"
	case	CANT_DO:		return	"CANT_DO"
	case	RESET_ABILITIES:	return	"RESET_ABILITIES"
	case	PRE_SLEEP:		return	"PRE_SLEEP"
	case	NOOP:			return	"NOOP"
	case	SUBMIT_JOB:		return	"SUBMIT_JOB"
	case	JOB_CREATED:		return	"JOB_CREATED"
	case	GRAB_JOB:		return	"GRAB_JOB"
	case	NO_JOB:			return	"NO_JOB"
	case	JOB_ASSIGN:		return	"JOB_ASSIGN"
	case	WORK_STATUS_WRK:	return	"WORK_STATUS_WRK"
	case	WORK_STATUS:		return	"WORK_STATUS"
	case	WORK_COMPLETE_WRK:	return	"WORK_COMPLETE_WRK"
	case	WORK_COMPLETE:		return	"WORK_COMPLETE"
	case	WORK_FAIL_WRK:		return	"WORK_FAIL_WRK"
	case	WORK_FAIL:		return	"WORK_FAIL"
	case	GET_STATUS:		return	"GET_STATUS"
	case	ECHO_REQ:		return	"ECHO_REQ"
	case	ECHO_RES:		return	"ECHO_RES"
	case	SUBMIT_JOB_BG:		return	"SUBMIT_JOB_BG"
	case	ERROR:			return	"ERROR"
	case	STATUS_RES:		return	"STATUS_RES"
	case	SUBMIT_JOB_HIGH:	return	"SUBMIT_JOB_HIGH"
	case	SET_CLIENT_ID:		return	"SET_CLIENT_ID"
	case	CAN_DO_TIMEOUT:		return	"CAN_DO_TIMEOUT"
	case	ALL_YOURS:		return	"ALL_YOURS"
	case	WORK_EXCEPTION_WRK:	return	"WORK_EXCEPTION_WRK"
	case	WORK_EXCEPTION:		return	"WORK_EXCEPTION"
	case	OPTION_REQ:		return	"OPTION_REQ"
	case	OPTION_RES:		return	"OPTION_RES"
	case	WORK_DATA_WRK:		return	"WORK_DATA_WRK"
	case	WORK_DATA:		return	"WORK_DATA"
	case	WORK_WARNING_WRK:	return	"WORK_WARNING_WRK"
	case	WORK_WARNING:		return	"WORK_WARNING"
	case	GRAB_JOB_UNIQ:		return	"GRAB_JOB_UNIQ"
	case	JOB_ASSIGN_UNIQ:	return	"JOB_ASSIGN_UNIQ"
	case	SUBMIT_JOB_HIGH_BG:	return	"SUBMIT_JOB_HIGH_BG"
	case	SUBMIT_JOB_LOW:		return	"SUBMIT_JOB_LOW"
	case	SUBMIT_JOB_LOW_BG:	return	"SUBMIT_JOB_LOW_BG"
	case	SUBMIT_JOB_SCHED:	return	"SUBMIT_JOB_SCHED"
	case	SUBMIT_JOB_EPOCH:	return	"SUBMIT_JOB_EPOCH"
	case	OK:			return	"OK"
	case	ADMIN_WORKERS:		return	"ADMIN_WORKERS"
	case	ADMIN_STATUS:		return	"ADMIN_STATUS"
	case	ADMIN_MAX_QUEUE:	return	"ADMIN_MAX_QUEUE"
	case	ADMIN_SHUTDOWN:		return	"ADMIN_SHUTDOWN"
	case	ADMIN_VERSION:		return	"ADMIN_VERSION"
	case	ADMIN_WORKERS_LIST:	return	"ADMIN_WORKERS_LIST"
	case	ADMIN_STATUS_LIST:	return	"ADMIN_STATUS_LIST"

	default:			return	fmt.Sprintf("HELLO[%08x] CMD[%08x]", uint32(c>>32), uint32(c))
	}
}

func (cmd Command)Unmarshal(payload []byte) (Packet,error) {
	switch	cmd {
	case	RESET_ABILITIES,PRE_SLEEP,NOOP,GRAB_JOB,NO_JOB,ALL_YOURS,GRAB_JOB_UNIQ,ADMIN_WORKERS,ADMIN_STATUS,ADMIN_VERSION:
		return	newPkt0size(cmd, len(payload) )

	case	JOB_CREATED,CAN_DO,CANT_DO,GET_STATUS,SET_CLIENT_ID,OK,ADMIN_SHUTDOWN,
		WORK_FAIL_WRK,WORK_FAIL,
		ECHO_REQ,ECHO_RES,
		OPTION_REQ,OPTION_RES:
		return	newPkt1len(cmd, payload)

	case	ERROR,CAN_DO_TIMEOUT,ADMIN_MAX_QUEUE,
		WORK_COMPLETE_WRK,WORK_COMPLETE,
		WORK_EXCEPTION_WRK,WORK_EXCEPTION,
		WORK_DATA_WRK,WORK_DATA,
		WORK_WARNING_WRK,WORK_WARNING:
		return	newPktnlen(cmd, payload, 2)

	case	SUBMIT_JOB,JOB_ASSIGN,
		WORK_STATUS_WRK,WORK_STATUS,
		SUBMIT_JOB_HIGH,SUBMIT_JOB_LOW,
		SUBMIT_JOB_BG,SUBMIT_JOB_HIGH_BG,SUBMIT_JOB_LOW_BG:
		return	newPktnlen(cmd, payload, 3)

	case	JOB_ASSIGN_UNIQ,SUBMIT_JOB_EPOCH:
		return	newPktnlen(cmd, payload, 4)

	case	STATUS_RES:
		return	newPktnlen(cmd, payload, 5)

	case	SUBMIT_JOB_SCHED:
		return	newPktnlen(cmd, payload, 8)

	case	ADMIN_WORKERS_LIST,ADMIN_STATUS_LIST:
		return	newPktnlen(cmd, payload, -1)
	}

	return	nil, &UndefinedPacketError{ cmd }
}
<commit_msg>add official undocumented command<commit_after>package	gearman	// import "github.com/nathanaelle/gearman"

import	(
	"fmt"
)

type	(
	Command	uint64
)

const	(
	CAN_DO			Command = 0x0052455100000001	// 1	REQ    Worker
	CANT_DO			Command = 0x0052455100000002	// 2	REQ    Worker
	RESET_ABILITIES		Command = 0x0052455100000003	// 3	REQ    Worker
	PRE_SLEEP		Command = 0x0052455100000004	// 4	REQ    Worker
	NOOP			Command = 0x0052455300000006	// 6	RES    Worker
	SUBMIT_JOB		Command = 0x0052455100000007	// 7	REQ    Client
	JOB_CREATED		Command = 0x0052455300000008	// 8	RES    Client
	GRAB_JOB		Command = 0x0052455100000009	// 9	REQ    Worker
	NO_JOB			Command = 0x005245530000000a	// 10	RES    Worker
	JOB_ASSIGN		Command = 0x005245530000000b	// 11	RES    Worker
	WORK_STATUS_WRK		Command = 0x005245510000000c	// 12	REQ    Worker
	WORK_STATUS		Command = 0x005245530000000c	// 12	RES    Client
	WORK_COMPLETE_WRK	Command = 0x005245510000000d	// 13	REQ    Worker
	WORK_COMPLETE		Command = 0x005245530000000d	// 13	RES    Client
	WORK_FAIL_WRK		Command = 0x005245510000000e	// 14	REQ    Worker
	WORK_FAIL		Command = 0x005245530000000e	// 14	RES    Client
	GET_STATUS		Command = 0x005245510000000f	// 15	REQ    Client
	ECHO_REQ		Command = 0x0052455100000010	// 16	REQ    Client/Worker
	ECHO_RES		Command = 0x0052455300000011	// 17	RES    Client/Worker
	SUBMIT_JOB_BG		Command = 0x0052455100000012	// 18	REQ    Client
	ERROR			Command = 0x0052455300000013	// 19	RES    Client/Worker
	STATUS_RES		Command = 0x0052455300000014	// 20	RES    Client
	SUBMIT_JOB_HIGH		Command = 0x0052455100000015	// 21	REQ    Client
	SET_CLIENT_ID		Command = 0x0052455100000016	// 22	REQ    Worker
	CAN_DO_TIMEOUT		Command = 0x0052455100000017	// 23	REQ    Worker
	ALL_YOURS		Command = 0x0052455100000018	// 24	REQ    Worker
	WORK_EXCEPTION_WRK	Command = 0x0052455100000019	// 25	REQ    Worker
	WORK_EXCEPTION		Command = 0x0052455300000019	// 25	RES    Client
	OPTION_REQ		Command = 0x005245510000001a	// 26	REQ    Client/Worker
	OPTION_RES		Command = 0x005245530000001b	// 27	RES    Client/Worker
	WORK_DATA_WRK		Command = 0x005245510000001c	// 28	REQ    Worker
	WORK_DATA		Command = 0x005245530000001c	// 28	RES    Client
	WORK_WARNING_WRK	Command = 0x005245510000001d	// 29	REQ    Worker
	WORK_WARNING		Command = 0x005245530000001d	// 29	RES    Client
	GRAB_JOB_UNIQ		Command = 0x005245510000001e	// 30	REQ    Worker
	JOB_ASSIGN_UNIQ		Command = 0x005245530000001f	// 31	RES    Worker
	SUBMIT_JOB_HIGH_BG	Command = 0x0052455100000020	// 32	REQ    Client
	SUBMIT_JOB_LOW		Command = 0x0052455100000021	// 33	REQ    Client
	SUBMIT_JOB_LOW_BG	Command = 0x0052455100000022	// 34	REQ    Client
	SUBMIT_JOB_SCHED	Command = 0x0052455100000023	// 35	REQ    Client
	SUBMIT_JOB_EPOCH	Command = 0x0052455100000024	// 36	REQ    Client
	SUBMIT_REDUCE_JOB	Command = 0x0052455100000025	// 37	REQ    Client
	SUBMIT_REDUCE_JOB_BG	Command = 0x0052455100000026	// 38	REQ    Client
	GRAB_JOB_ALL		Command = 0x0052455100000027	// 39	REQ    Worker
	JOB_ASSIGN_ALL		Command = 0x0052455300000028	// 40	RES    Worker
	GET_STATUS_UNIQ		Command = 0x0052455100000029	// 41	REQ    Client
	STATUS_RES_UNIQ		Command = 0x005245530000002a	// 42	RES    Client

	OK			Command = 0x0052455300000050
	ADMIN_WORKERS		Command = 0x0052455100000051
	ADMIN_STATUS		Command = 0x0052455100000052
	ADMIN_MAX_QUEUE		Command = 0x0052455100000053
	ADMIN_SHUTDOWN		Command = 0x0052455100000054
	ADMIN_VERSION		Command = 0x0052455100000055
	ADMIN_WORKERS_LIST	Command = 0x0052455300000056
	ADMIN_STATUS_LIST	Command = 0x0052455300000057
	CAPABILITY		Command = 0x0052455100000058
	CAPABILITY_LIST		Command = 0x0052455300000059
)

func (c Command)String() string {
	switch	c {
	case	CAN_DO:			return	"CAN_DO"
	case	CANT_DO:		return	"CANT_DO"
	case	RESET_ABILITIES:	return	"RESET_ABILITIES"
	case	PRE_SLEEP:		return	"PRE_SLEEP"
	case	NOOP:			return	"NOOP"
	case	SUBMIT_JOB:		return	"SUBMIT_JOB"
	case	JOB_CREATED:		return	"JOB_CREATED"
	case	GRAB_JOB:		return	"GRAB_JOB"
	case	NO_JOB:			return	"NO_JOB"
	case	JOB_ASSIGN:		return	"JOB_ASSIGN"
	case	WORK_STATUS_WRK:	return	"WORK_STATUS_WRK"
	case	WORK_STATUS:		return	"WORK_STATUS"
	case	WORK_COMPLETE_WRK:	return	"WORK_COMPLETE_WRK"
	case	WORK_COMPLETE:		return	"WORK_COMPLETE"
	case	WORK_FAIL_WRK:		return	"WORK_FAIL_WRK"
	case	WORK_FAIL:		return	"WORK_FAIL"
	case	GET_STATUS:		return	"GET_STATUS"
	case	ECHO_REQ:		return	"ECHO_REQ"
	case	ECHO_RES:		return	"ECHO_RES"
	case	SUBMIT_JOB_BG:		return	"SUBMIT_JOB_BG"
	case	ERROR:			return	"ERROR"
	case	STATUS_RES:		return	"STATUS_RES"
	case	SUBMIT_JOB_HIGH:	return	"SUBMIT_JOB_HIGH"
	case	SET_CLIENT_ID:		return	"SET_CLIENT_ID"
	case	CAN_DO_TIMEOUT:		return	"CAN_DO_TIMEOUT"
	case	ALL_YOURS:		return	"ALL_YOURS"
	case	WORK_EXCEPTION_WRK:	return	"WORK_EXCEPTION_WRK"
	case	WORK_EXCEPTION:		return	"WORK_EXCEPTION"
	case	OPTION_REQ:		return	"OPTION_REQ"
	case	OPTION_RES:		return	"OPTION_RES"
	case	WORK_DATA_WRK:		return	"WORK_DATA_WRK"
	case	WORK_DATA:		return	"WORK_DATA"
	case	WORK_WARNING_WRK:	return	"WORK_WARNING_WRK"
	case	WORK_WARNING:		return	"WORK_WARNING"
	case	GRAB_JOB_UNIQ:		return	"GRAB_JOB_UNIQ"
	case	JOB_ASSIGN_UNIQ:	return	"JOB_ASSIGN_UNIQ"
	case	SUBMIT_JOB_HIGH_BG:	return	"SUBMIT_JOB_HIGH_BG"
	case	SUBMIT_JOB_LOW:		return	"SUBMIT_JOB_LOW"
	case	SUBMIT_JOB_LOW_BG:	return	"SUBMIT_JOB_LOW_BG"
	case	SUBMIT_JOB_SCHED:	return	"SUBMIT_JOB_SCHED"
	case	SUBMIT_JOB_EPOCH:	return	"SUBMIT_JOB_EPOCH"
	case	SUBMIT_REDUCE_JOB:	return	"SUBMIT_REDUCE_JOB"
	case	SUBMIT_REDUCE_JOB_BG:	return	"SUBMIT_REDUCE_JOB_BG"
	case	GRAB_JOB_ALL:		return	"GRAB_JOB_ALL"
	case	JOB_ASSIGN_ALL:		return	"JOB_ASSIGN_ALL"
	case	GET_STATUS_UNIQ:	return	"GET_STATUS_UNIQ"
	case	STATUS_RES_UNIQ:	return	"STATUS_RES_UNIQ"

	case	OK:			return	"OK"
	case	ADMIN_WORKERS:		return	"ADMIN_WORKERS"
	case	ADMIN_STATUS:		return	"ADMIN_STATUS"
	case	ADMIN_MAX_QUEUE:	return	"ADMIN_MAX_QUEUE"
	case	ADMIN_SHUTDOWN:		return	"ADMIN_SHUTDOWN"
	case	ADMIN_VERSION:		return	"ADMIN_VERSION"
	case	ADMIN_WORKERS_LIST:	return	"ADMIN_WORKERS_LIST"
	case	ADMIN_STATUS_LIST:	return	"ADMIN_STATUS_LIST"

	default:			return	fmt.Sprintf("HELLO[%08x] CMD[%08x]", uint32(c>>32), uint32(c))
	}
}

func (cmd Command)Unmarshal(payload []byte) (Packet,error) {
	switch	cmd {
	case	RESET_ABILITIES,PRE_SLEEP,NOOP,ALL_YOURS,
		GRAB_JOB,NO_JOB,GRAB_JOB_UNIQ,GRAB_JOB_ALL,
		ADMIN_WORKERS,ADMIN_STATUS,ADMIN_VERSION:
		return	newPkt0size(cmd, len(payload))

	case	JOB_CREATED,CAN_DO,CANT_DO,SET_CLIENT_ID,OK,ADMIN_SHUTDOWN,
		WORK_FAIL_WRK,WORK_FAIL,
		ECHO_REQ,ECHO_RES,
		OPTION_REQ,OPTION_RES,
		GET_STATUS,GET_STATUS_UNIQ:
		return	newPkt1len(cmd, payload)

	case	ERROR,CAN_DO_TIMEOUT,ADMIN_MAX_QUEUE,
		WORK_COMPLETE_WRK,WORK_COMPLETE,
		WORK_EXCEPTION_WRK,WORK_EXCEPTION,
		WORK_DATA_WRK,WORK_DATA,
		WORK_WARNING_WRK,WORK_WARNING:
		return	newPktnlen(cmd, payload, 2)

	case	SUBMIT_JOB,JOB_ASSIGN,
		WORK_STATUS_WRK,WORK_STATUS,
		SUBMIT_JOB_HIGH,SUBMIT_JOB_LOW,
		SUBMIT_JOB_BG,SUBMIT_JOB_HIGH_BG,SUBMIT_JOB_LOW_BG:
		return	newPktnlen(cmd, payload, 3)

	case	JOB_ASSIGN_UNIQ,SUBMIT_JOB_EPOCH,SUBMIT_REDUCE_JOB,SUBMIT_REDUCE_JOB_BG:
		return	newPktnlen(cmd, payload, 4)

	case	STATUS_RES,JOB_ASSIGN_ALL:
		return	newPktnlen(cmd, payload, 5)

	case	STATUS_RES_UNIQ:
		return	newPktnlen(cmd, payload, 6)

	case	SUBMIT_JOB_SCHED:
		return	newPktnlen(cmd, payload, 8)

	case	ADMIN_WORKERS_LIST,ADMIN_STATUS_LIST:
		return	newPktnlen(cmd, payload, -1)
	}

	return	nil, &UndefinedPacketError{ cmd }
}
<|endoftext|>


<commit_before>// UNREVIEWED
// Copyright 2013 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.

// This file implements printing of types.

package types2

import (
	"bytes"
	"fmt"
	"unicode/utf8"
)

// A Qualifier controls how named package-level objects are printed in
// calls to TypeString, ObjectString, and SelectionString.
//
// These three formatting routines call the Qualifier for each
// package-level object O, and if the Qualifier returns a non-empty
// string p, the object is printed in the form p.O.
// If it returns an empty string, only the object name O is printed.
//
// Using a nil Qualifier is equivalent to using (*Package).Path: the
// object is qualified by the import path, e.g., "encoding/json.Marshal".
//
type Qualifier func(*Package) string

// RelativeTo returns a Qualifier that fully qualifies members of
// all packages other than pkg.
func RelativeTo(pkg *Package) Qualifier {
	if pkg == nil {
		return nil
	}
	return func(other *Package) string {
		if pkg == other {
			return "" // same package; unqualified
		}
		return other.Path()
	}
}

// If gcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
//	- byte and rune lose their alias name and simply stand for
//	  uint8 and int32 respectively
//	- embedded interfaces get flattened (the embedding info is lost,
//	  and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data.
//
// This flag is exported in the x/tools/go/types package. We don't
// need it at the moment in the std repo and so we don't export it
// anymore. We should eventually try to remove it altogether.
// TODO(gri) remove this
var gcCompatibilityMode bool

// TypeString returns the string representation of typ.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
	var buf bytes.Buffer
	WriteType(&buf, typ, qf)
	return buf.String()
}

// WriteType writes the string representation of typ to buf.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
	writeType(buf, typ, qf, make([]Type, 0, 8))
}

// instanceMarker is the prefix for an instantiated type
// in "non-evaluated" instance form.
const instanceMarker = '#'

func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
	// Theoretically, this is a quadratic lookup algorithm, but in
	// practice deeply nested composite types with unnamed component
	// types are uncommon. This code is likely more efficient than
	// using a map.
	for _, t := range visited {
		if t == typ {
			fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
			return
		}
	}
	visited = append(visited, typ)

	switch t := typ.(type) {
	case nil:
		buf.WriteString("<nil>")

	case *Basic:
		if t.kind == UnsafePointer {
			buf.WriteString("unsafe.")
		}
		if gcCompatibilityMode {
			// forget the alias names
			switch t.kind {
			case Byte:
				t = Typ[Uint8]
			case Rune:
				t = Typ[Int32]
			}
		}
		buf.WriteString(t.name)

	case *Array:
		fmt.Fprintf(buf, "[%d]", t.len)
		writeType(buf, t.elem, qf, visited)

	case *Slice:
		buf.WriteString("[]")
		writeType(buf, t.elem, qf, visited)

	case *Struct:
		buf.WriteString("struct{")
		for i, f := range t.fields {
			if i > 0 {
				buf.WriteString("; ")
			}
			buf.WriteString(f.name)
			if f.embedded {
				// emphasize that the embedded field's name
				// doesn't match the field's type name
				if f.name != embeddedFieldName(f.typ) {
					buf.WriteString(" /* = ")
					writeType(buf, f.typ, qf, visited)
					buf.WriteString(" */")
				}
			} else {
				buf.WriteByte(' ')
				writeType(buf, f.typ, qf, visited)
			}
			if tag := t.Tag(i); tag != "" {
				fmt.Fprintf(buf, " %q", tag)
			}
		}
		buf.WriteByte('}')

	case *Pointer:
		buf.WriteByte('*')
		writeType(buf, t.base, qf, visited)

	case *Tuple:
		writeTuple(buf, t, false, qf, visited)

	case *Signature:
		buf.WriteString("func")
		writeSignature(buf, t, qf, visited)

	case *Sum:
		for i, t := range t.types {
			if i > 0 {
				buf.WriteString(", ")
			}
			writeType(buf, t, qf, visited)
		}

	case *Interface:
		// We write the source-level methods and embedded types rather
		// than the actual method set since resolved method signatures
		// may have non-printable cycles if parameters have embedded
		// interface types that (directly or indirectly) embed the
		// current interface. For instance, consider the result type
		// of m:
		//
		//     type T interface{
		//         m() interface{ T }
		//     }
		//
		buf.WriteString("interface{")
		empty := true
		if gcCompatibilityMode {
			// print flattened interface
			// (useful to compare against gc-generated interfaces)
			for i, m := range t.allMethods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.allTypes != nil {
				buf.WriteString("; ")
			}
			if t.allTypes != nil {
				buf.WriteString("type ")
				writeType(buf, t.allTypes, qf, visited)
			}
		} else {
			// print explicit interface methods and embedded types
			for i, m := range t.methods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.types != nil {
				buf.WriteString("; ")
			}
			if t.types != nil {
				buf.WriteString("type ")
				writeType(buf, t.types, qf, visited)
				empty = false
			}
			if !empty && len(t.embeddeds) > 0 {
				buf.WriteString("; ")
			}
			for i, typ := range t.embeddeds {
				if i > 0 {
					buf.WriteString("; ")
				}
				writeType(buf, typ, qf, visited)
				empty = false
			}
		}
		if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
			if !empty {
				buf.WriteByte(' ')
			}
			buf.WriteString("/* incomplete */")
		}
		buf.WriteByte('}')

	case *Map:
		buf.WriteString("map[")
		writeType(buf, t.key, qf, visited)
		buf.WriteByte(']')
		writeType(buf, t.elem, qf, visited)

	case *Chan:
		var s string
		var parens bool
		switch t.dir {
		case SendRecv:
			s = "chan "
			// chan (<-chan T) requires parentheses
			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
				parens = true
			}
		case SendOnly:
			s = "chan<- "
		case RecvOnly:
			s = "<-chan "
		default:
			panic("unreachable")
		}
		buf.WriteString(s)
		if parens {
			buf.WriteByte('(')
		}
		writeType(buf, t.elem, qf, visited)
		if parens {
			buf.WriteByte(')')
		}

	case *Named:
		writeTypeName(buf, t.obj, qf)
		if t.targs != nil {
			// instantiated type
			buf.WriteByte('[')
			writeTypeList(buf, t.targs, qf, visited)
			buf.WriteByte(']')
		} else if t.tparams != nil {
			// parameterized type
			writeTParamList(buf, t.tparams, qf, visited)
		}

	case *TypeParam:
		s := "?"
		if t.obj != nil {
			s = t.obj.name
		}
		buf.WriteString(s + subscript(t.id))

	case *instance:
		buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
		writeTypeName(buf, t.base.obj, qf)
		buf.WriteByte('[')
		writeTypeList(buf, t.targs, qf, visited)
		buf.WriteByte(']')

	case *bottom:
		buf.WriteString("⊥")

	case *top:
		buf.WriteString("⊤")

	default:
		// For externally defined implementations of Type.
		buf.WriteString(t.String())
	}
}

func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
	for i, typ := range list {
		if i > 0 {
			buf.WriteString(", ")
		}
		writeType(buf, typ, qf, visited)
	}
}

func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
	// bound returns the type bound for tname. The result is never nil.
	bound := func(tname *TypeName) Type {
		// be careful to avoid crashes in case of inconsistencies
		if t, _ := tname.typ.(*TypeParam); t != nil && t.bound != nil {
			return t.bound
		}
		return &emptyInterface
	}

	// If a single type bound is not the empty interface, we have to write them all.
	var writeBounds bool
	for _, p := range list {
		// bound(p) should be an interface but be careful (it may be invalid)
		b := asInterface(bound(p))
		if b != nil && !b.Empty() {
			writeBounds = true
			break
		}
	}
	writeBounds = true // always write the bounds for new type parameter list syntax

	buf.WriteString("[")
	var prev Type
	for i, p := range list {
		b := bound(p)
		if i > 0 {
			if writeBounds && b != prev {
				// type bound changed - write previous one before advancing
				buf.WriteByte(' ')
				writeType(buf, prev, qf, visited)
			}
			buf.WriteString(", ")
		}
		prev = b

		if t, _ := p.typ.(*TypeParam); t != nil {
			writeType(buf, t, qf, visited)
		} else {
			buf.WriteString(p.name)
		}
	}
	if writeBounds && prev != nil {
		buf.WriteByte(' ')
		writeType(buf, prev, qf, visited)
	}
	buf.WriteByte(']')
}

func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
	s := "<Named w/o object>"
	if obj != nil {
		if obj.pkg != nil {
			writePackage(buf, obj.pkg, qf)
		}
		// TODO(gri): function-local named types should be displayed
		// differently from named types at package level to avoid
		// ambiguity.
		s = obj.name
	}
	buf.WriteString(s)
}

func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
	buf.WriteByte('(')
	if tup != nil {
		for i, v := range tup.vars {
			if i > 0 {
				buf.WriteString(", ")
			}
			if v.name != "" {
				buf.WriteString(v.name)
				buf.WriteByte(' ')
			}
			typ := v.typ
			if variadic && i == len(tup.vars)-1 {
				if s, ok := typ.(*Slice); ok {
					buf.WriteString("...")
					typ = s.elem
				} else {
					// special case:
					// append(s, "foo"...) leads to signature func([]byte, string...)
					if t := asBasic(typ); t == nil || t.kind != String {
						panic("internal error: string type expected")
					}
					writeType(buf, typ, qf, visited)
					buf.WriteString("...")
					continue
				}
			}
			writeType(buf, typ, qf, visited)
		}
	}
	buf.WriteByte(')')
}

// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
	writeSignature(buf, sig, qf, make([]Type, 0, 8))
}

func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
	if sig.tparams != nil {
		writeTParamList(buf, sig.tparams, qf, visited)
	}

	writeTuple(buf, sig.params, sig.variadic, qf, visited)

	n := sig.results.Len()
	if n == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if n == 1 && sig.results.vars[0].name == "" {
		// single unnamed result
		writeType(buf, sig.results.vars[0].typ, qf, visited)
		return
	}

	// multiple or named result(s)
	writeTuple(buf, sig.results, false, qf, visited)
}

// embeddedFieldName returns an embedded field's name given its type.
// The result is "" if the type doesn't have an embedded field name.
func embeddedFieldName(typ Type) string {
	switch t := typ.(type) {
	case *Basic:
		return t.name
	case *Named:
		return t.obj.name
	case *Pointer:
		// *T is ok, but **T is not
		if _, ok := t.base.(*Pointer); !ok {
			return embeddedFieldName(t.base)
		}
	case *instance:
		return t.base.obj.name
	}
	return "" // not a (pointer to) a defined type
}

// subscript returns the decimal (utf8) representation of x using subscript digits.
func subscript(x uint64) string {
	const w = len("₀") // all digits 0...9 have the same utf8 width
	var buf [32 * w]byte
	i := len(buf)
	for {
		i -= w
		utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
		x /= 10
		if x == 0 {
			break
		}
	}
	return string(buf[i:])
}
<commit_msg>[dev.typeparams] cmd/compile/internal/types: review of typestring.go<commit_after>// Copyright 2013 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.

// This file implements printing of types.

package types2

import (
	"bytes"
	"fmt"
	"unicode/utf8"
)

// A Qualifier controls how named package-level objects are printed in
// calls to TypeString, ObjectString, and SelectionString.
//
// These three formatting routines call the Qualifier for each
// package-level object O, and if the Qualifier returns a non-empty
// string p, the object is printed in the form p.O.
// If it returns an empty string, only the object name O is printed.
//
// Using a nil Qualifier is equivalent to using (*Package).Path: the
// object is qualified by the import path, e.g., "encoding/json.Marshal".
//
type Qualifier func(*Package) string

// RelativeTo returns a Qualifier that fully qualifies members of
// all packages other than pkg.
func RelativeTo(pkg *Package) Qualifier {
	if pkg == nil {
		return nil
	}
	return func(other *Package) string {
		if pkg == other {
			return "" // same package; unqualified
		}
		return other.Path()
	}
}

// If gcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
//	- byte and rune lose their alias name and simply stand for
//	  uint8 and int32 respectively
//	- embedded interfaces get flattened (the embedding info is lost,
//	  and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data.
//
// This flag is exported in the x/tools/go/types package. We don't
// need it at the moment in the std repo and so we don't export it
// anymore. We should eventually try to remove it altogether.
// TODO(gri) remove this
var gcCompatibilityMode bool

// TypeString returns the string representation of typ.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
	var buf bytes.Buffer
	WriteType(&buf, typ, qf)
	return buf.String()
}

// WriteType writes the string representation of typ to buf.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
	writeType(buf, typ, qf, make([]Type, 0, 8))
}

// instanceMarker is the prefix for an instantiated type
// in "non-evaluated" instance form.
const instanceMarker = '#'

func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
	// Theoretically, this is a quadratic lookup algorithm, but in
	// practice deeply nested composite types with unnamed component
	// types are uncommon. This code is likely more efficient than
	// using a map.
	for _, t := range visited {
		if t == typ {
			fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
			return
		}
	}
	visited = append(visited, typ)

	switch t := typ.(type) {
	case nil:
		buf.WriteString("<nil>")

	case *Basic:
		if t.kind == UnsafePointer {
			buf.WriteString("unsafe.")
		}
		if gcCompatibilityMode {
			// forget the alias names
			switch t.kind {
			case Byte:
				t = Typ[Uint8]
			case Rune:
				t = Typ[Int32]
			}
		}
		buf.WriteString(t.name)

	case *Array:
		fmt.Fprintf(buf, "[%d]", t.len)
		writeType(buf, t.elem, qf, visited)

	case *Slice:
		buf.WriteString("[]")
		writeType(buf, t.elem, qf, visited)

	case *Struct:
		buf.WriteString("struct{")
		for i, f := range t.fields {
			if i > 0 {
				buf.WriteString("; ")
			}
			buf.WriteString(f.name)
			if f.embedded {
				// emphasize that the embedded field's name
				// doesn't match the field's type name
				if f.name != embeddedFieldName(f.typ) {
					buf.WriteString(" /* = ")
					writeType(buf, f.typ, qf, visited)
					buf.WriteString(" */")
				}
			} else {
				buf.WriteByte(' ')
				writeType(buf, f.typ, qf, visited)
			}
			if tag := t.Tag(i); tag != "" {
				fmt.Fprintf(buf, " %q", tag)
			}
		}
		buf.WriteByte('}')

	case *Pointer:
		buf.WriteByte('*')
		writeType(buf, t.base, qf, visited)

	case *Tuple:
		writeTuple(buf, t, false, qf, visited)

	case *Signature:
		buf.WriteString("func")
		writeSignature(buf, t, qf, visited)

	case *Sum:
		for i, t := range t.types {
			if i > 0 {
				buf.WriteString(", ")
			}
			writeType(buf, t, qf, visited)
		}

	case *Interface:
		// We write the source-level methods and embedded types rather
		// than the actual method set since resolved method signatures
		// may have non-printable cycles if parameters have embedded
		// interface types that (directly or indirectly) embed the
		// current interface. For instance, consider the result type
		// of m:
		//
		//     type T interface{
		//         m() interface{ T }
		//     }
		//
		buf.WriteString("interface{")
		empty := true
		if gcCompatibilityMode {
			// print flattened interface
			// (useful to compare against gc-generated interfaces)
			for i, m := range t.allMethods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.allTypes != nil {
				buf.WriteString("; ")
			}
			if t.allTypes != nil {
				buf.WriteString("type ")
				writeType(buf, t.allTypes, qf, visited)
			}
		} else {
			// print explicit interface methods and embedded types
			for i, m := range t.methods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.types != nil {
				buf.WriteString("; ")
			}
			if t.types != nil {
				buf.WriteString("type ")
				writeType(buf, t.types, qf, visited)
				empty = false
			}
			if !empty && len(t.embeddeds) > 0 {
				buf.WriteString("; ")
			}
			for i, typ := range t.embeddeds {
				if i > 0 {
					buf.WriteString("; ")
				}
				writeType(buf, typ, qf, visited)
				empty = false
			}
		}
		if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
			if !empty {
				buf.WriteByte(' ')
			}
			buf.WriteString("/* incomplete */")
		}
		buf.WriteByte('}')

	case *Map:
		buf.WriteString("map[")
		writeType(buf, t.key, qf, visited)
		buf.WriteByte(']')
		writeType(buf, t.elem, qf, visited)

	case *Chan:
		var s string
		var parens bool
		switch t.dir {
		case SendRecv:
			s = "chan "
			// chan (<-chan T) requires parentheses
			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
				parens = true
			}
		case SendOnly:
			s = "chan<- "
		case RecvOnly:
			s = "<-chan "
		default:
			panic("unreachable")
		}
		buf.WriteString(s)
		if parens {
			buf.WriteByte('(')
		}
		writeType(buf, t.elem, qf, visited)
		if parens {
			buf.WriteByte(')')
		}

	case *Named:
		writeTypeName(buf, t.obj, qf)
		if t.targs != nil {
			// instantiated type
			buf.WriteByte('[')
			writeTypeList(buf, t.targs, qf, visited)
			buf.WriteByte(']')
		} else if t.tparams != nil {
			// parameterized type
			writeTParamList(buf, t.tparams, qf, visited)
		}

	case *TypeParam:
		s := "?"
		if t.obj != nil {
			s = t.obj.name
		}
		buf.WriteString(s + subscript(t.id))

	case *instance:
		buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
		writeTypeName(buf, t.base.obj, qf)
		buf.WriteByte('[')
		writeTypeList(buf, t.targs, qf, visited)
		buf.WriteByte(']')

	case *bottom:
		buf.WriteString("⊥")

	case *top:
		buf.WriteString("⊤")

	default:
		// For externally defined implementations of Type.
		buf.WriteString(t.String())
	}
}

func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
	for i, typ := range list {
		if i > 0 {
			buf.WriteString(", ")
		}
		writeType(buf, typ, qf, visited)
	}
}

func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
	buf.WriteString("[")
	var prev Type
	for i, p := range list {
		// TODO(gri) support 'any' sugar here.
		var b Type = &emptyInterface
		if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
			b = t.bound
		}
		if i > 0 {
			if b != prev {
				// type bound changed - write previous one before advancing
				buf.WriteByte(' ')
				writeType(buf, prev, qf, visited)
			}
			buf.WriteString(", ")
		}
		prev = b

		if t, _ := p.typ.(*TypeParam); t != nil {
			writeType(buf, t, qf, visited)
		} else {
			buf.WriteString(p.name)
		}
	}
	if prev != nil {
		buf.WriteByte(' ')
		writeType(buf, prev, qf, visited)
	}
	buf.WriteByte(']')
}

func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
	s := "<Named w/o object>"
	if obj != nil {
		if obj.pkg != nil {
			writePackage(buf, obj.pkg, qf)
		}
		// TODO(gri): function-local named types should be displayed
		// differently from named types at package level to avoid
		// ambiguity.
		s = obj.name
	}
	buf.WriteString(s)
}

func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
	buf.WriteByte('(')
	if tup != nil {
		for i, v := range tup.vars {
			if i > 0 {
				buf.WriteString(", ")
			}
			if v.name != "" {
				buf.WriteString(v.name)
				buf.WriteByte(' ')
			}
			typ := v.typ
			if variadic && i == len(tup.vars)-1 {
				if s, ok := typ.(*Slice); ok {
					buf.WriteString("...")
					typ = s.elem
				} else {
					// special case:
					// append(s, "foo"...) leads to signature func([]byte, string...)
					if t := asBasic(typ); t == nil || t.kind != String {
						panic("internal error: string type expected")
					}
					writeType(buf, typ, qf, visited)
					buf.WriteString("...")
					continue
				}
			}
			writeType(buf, typ, qf, visited)
		}
	}
	buf.WriteByte(')')
}

// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
	writeSignature(buf, sig, qf, make([]Type, 0, 8))
}

func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
	if sig.tparams != nil {
		writeTParamList(buf, sig.tparams, qf, visited)
	}

	writeTuple(buf, sig.params, sig.variadic, qf, visited)

	n := sig.results.Len()
	if n == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if n == 1 && sig.results.vars[0].name == "" {
		// single unnamed result
		writeType(buf, sig.results.vars[0].typ, qf, visited)
		return
	}

	// multiple or named result(s)
	writeTuple(buf, sig.results, false, qf, visited)
}

// embeddedFieldName returns an embedded field's name given its type.
// The result is "" if the type doesn't have an embedded field name.
func embeddedFieldName(typ Type) string {
	switch t := typ.(type) {
	case *Basic:
		return t.name
	case *Named:
		return t.obj.name
	case *Pointer:
		// *T is ok, but **T is not
		if _, ok := t.base.(*Pointer); !ok {
			return embeddedFieldName(t.base)
		}
	case *instance:
		return t.base.obj.name
	}
	return "" // not a (pointer to) a defined type
}

// subscript returns the decimal (utf8) representation of x using subscript digits.
func subscript(x uint64) string {
	const w = len("₀") // all digits 0...9 have the same utf8 width
	var buf [32 * w]byte
	i := len(buf)
	for {
		i -= w
		utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
		x /= 10
		if x == 0 {
			break
		}
	}
	return string(buf[i:])
}
<|endoftext|>


<commit_before>package resource

import (
	"errors"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

var (
	ErrProcessorRecordNotFound = errors.New("resource: record not found")
	ErrProcessorSkipLeft       = errors.New("resource: skip left")
)

type processor struct {
	Result     interface{}
	Resource   Resourcer
	Context    *qor.Context
	MetaValues *MetaValues
	SkipLeft   bool
	newRecord  bool
}

func DecodeToResource(res Resourcer, result interface{}, metaValues *MetaValues, context *qor.Context) *processor {
	scope := &gorm.Scope{Value: result}
	return &processor{Resource: res, Result: result, Context: context, MetaValues: metaValues, newRecord: scope.PrimaryKeyZero()}
}

func (processor *processor) checkSkipLeft(errs ...error) bool {
	if processor.SkipLeft {
		return true
	}

	for _, err := range errs {
		if err == ErrProcessorSkipLeft {
			processor.SkipLeft = true
			break
		}
	}
	return processor.SkipLeft
}

func (processor *processor) Initialize() error {
	err := processor.Resource.CallFindOne(processor.Result, processor.MetaValues, processor.Context)
	processor.checkSkipLeft(err)
	return err
}

func (processor *processor) Validate() error {
	var errors qor.Errors
	if processor.checkSkipLeft() {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().validators {
		if errors.AddError(fc(processor.Result, processor.MetaValues, processor.Context)); errors.HasError() {
			if processor.checkSkipLeft(errors.GetErrors()...) {
				break
			}
		}
	}
	return errors
}

func (processor *processor) decode() (errors []error) {
	if processor.checkSkipLeft() {
		return
	}

	for _, metaValue := range processor.MetaValues.Values {
		meta := metaValue.Meta
		if meta == nil {
			continue
		}

		if processor.newRecord && !meta.HasPermission(roles.Create, processor.Context) {
			continue
		} else if !meta.HasPermission(roles.Update, processor.Context) {
			continue
		}

		if metaValue.MetaValues == nil {
			if setter := meta.GetSetter(); setter != nil {
				setter(processor.Result, metaValue, processor.Context)
			}
			continue
		}

		res := metaValue.Meta.GetResource()
		if res == nil {
			continue
		}

		field := reflect.Indirect(reflect.ValueOf(processor.Result)).FieldByName(meta.GetFieldName())
		if field.Kind() == reflect.Struct {
			association := field.Addr().Interface()
			DecodeToResource(res, association, metaValue.MetaValues, processor.Context).Start()
		} else if field.Kind() == reflect.Slice {
			value := reflect.New(field.Type().Elem())
			associationProcessor := DecodeToResource(res, value.Interface(), metaValue.MetaValues, processor.Context)
			associationProcessor.Start()
			if !associationProcessor.SkipLeft {
				if !reflect.DeepEqual(reflect.Zero(field.Type().Elem()).Interface(), value.Elem().Interface()) {
					field.Set(reflect.Append(field, value.Elem()))
				}
			}
		}
	}

	return
}

func (processor *processor) Commit() error {
	var errors qor.Errors
	errors.AddError(processor.decode()...)
	if processor.checkSkipLeft(errors.GetErrors()...) {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().processors {
		if err := fc(processor.Result, processor.MetaValues, processor.Context); err != nil {
			if processor.checkSkipLeft(err) {
				break
			}
			errors.AddError(err)
		}
	}
	return errors
}

func (processor *processor) Start() error {
	var errors qor.Errors
	processor.Initialize()
	if errors.AddError(processor.Validate()); errors.HasError() {
		errors.AddError(processor.Commit())
	}
	return errors
}
<commit_msg>Fix check error when decode resource<commit_after>package resource

import (
	"errors"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

var (
	ErrProcessorRecordNotFound = errors.New("resource: record not found")
	ErrProcessorSkipLeft       = errors.New("resource: skip left")
)

type processor struct {
	Result     interface{}
	Resource   Resourcer
	Context    *qor.Context
	MetaValues *MetaValues
	SkipLeft   bool
	newRecord  bool
}

func DecodeToResource(res Resourcer, result interface{}, metaValues *MetaValues, context *qor.Context) *processor {
	scope := &gorm.Scope{Value: result}
	return &processor{Resource: res, Result: result, Context: context, MetaValues: metaValues, newRecord: scope.PrimaryKeyZero()}
}

func (processor *processor) checkSkipLeft(errs ...error) bool {
	if processor.SkipLeft {
		return true
	}

	for _, err := range errs {
		if err == ErrProcessorSkipLeft {
			processor.SkipLeft = true
			break
		}
	}
	return processor.SkipLeft
}

func (processor *processor) Initialize() error {
	err := processor.Resource.CallFindOne(processor.Result, processor.MetaValues, processor.Context)
	processor.checkSkipLeft(err)
	return err
}

func (processor *processor) Validate() error {
	var errors qor.Errors
	if processor.checkSkipLeft() {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().validators {
		if errors.AddError(fc(processor.Result, processor.MetaValues, processor.Context)); !errors.HasError() {
			if processor.checkSkipLeft(errors.GetErrors()...) {
				break
			}
		}
	}
	return errors
}

func (processor *processor) decode() (errors []error) {
	if processor.checkSkipLeft() {
		return
	}

	for _, metaValue := range processor.MetaValues.Values {
		meta := metaValue.Meta
		if meta == nil {
			continue
		}

		if processor.newRecord && !meta.HasPermission(roles.Create, processor.Context) {
			continue
		} else if !meta.HasPermission(roles.Update, processor.Context) {
			continue
		}

		if metaValue.MetaValues == nil {
			if setter := meta.GetSetter(); setter != nil {
				setter(processor.Result, metaValue, processor.Context)
			}
			continue
		}

		res := metaValue.Meta.GetResource()
		if res == nil {
			continue
		}

		field := reflect.Indirect(reflect.ValueOf(processor.Result)).FieldByName(meta.GetFieldName())
		if field.Kind() == reflect.Struct {
			association := field.Addr().Interface()
			DecodeToResource(res, association, metaValue.MetaValues, processor.Context).Start()
		} else if field.Kind() == reflect.Slice {
			value := reflect.New(field.Type().Elem())
			associationProcessor := DecodeToResource(res, value.Interface(), metaValue.MetaValues, processor.Context)
			associationProcessor.Start()
			if !associationProcessor.SkipLeft {
				if !reflect.DeepEqual(reflect.Zero(field.Type().Elem()).Interface(), value.Elem().Interface()) {
					field.Set(reflect.Append(field, value.Elem()))
				}
			}
		}
	}

	return
}

func (processor *processor) Commit() error {
	var errors qor.Errors
	errors.AddError(processor.decode()...)
	if processor.checkSkipLeft(errors.GetErrors()...) {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().processors {
		if err := fc(processor.Result, processor.MetaValues, processor.Context); err != nil {
			if processor.checkSkipLeft(err) {
				break
			}
			errors.AddError(err)
		}
	}
	return errors
}

func (processor *processor) Start() error {
	var errors qor.Errors
	processor.Initialize()
	if errors.AddError(processor.Validate()); !errors.HasError() {
		errors.AddError(processor.Commit())
	}
	return errors
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	counter := new(Counter)
	err := http.ListenAndServe("localhost:7000", counter)
	if err != nil {
		log.Fatal("Server Failed!")
	}
}

type Counter struct {
	counts       int
	notification chan *http.Request
}

func (counter *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	counter.counts++
	fmt.Fprintf(w, "counter = %d\n", counter.counts)
}
<commit_msg>Use channel to provide notification ipon receiving a request from client.<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	counter := newCounter()
	go func() {
		<-counter.notification
		fmt.Println("Received a request")
	}()

	fmt.Println("Starting server at localhost:7000")
	err := http.ListenAndServe("localhost:7000", counter)
	if err != nil {
		log.Fatal("Server Failed!")
	}
}

type Counter struct {
	counts       int
	notification chan int
}

func newCounter() *Counter {
	return &Counter{
		counts:       0,
		notification: make(chan int),
	}
}

func (counter *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	counter.notification <- 1
	counter.counts++
	fmt.Fprintf(w, "counter = %d\n", counter.counts)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/Shopify/sarama"
	"github.com/golang/glog"
)

const HTTP_FORM_ENCODING = "application/x-www-form-urlencoded"

type HTTPTransporter struct {
	Callback          *WorkerCallback
	Serializer        string
	ContentType       string
	config            *CallbackItemConfig
	transporterConfig TransporterConfig
	discardBuffer     []byte
	manager           *PartitionManager
}

type MessageBody struct {
	Topic        string `json:"Topic"`
	PartitionKey string `json:"PartitionKey"`
	TimeStamp    int64  `json:"TimeStamp"`
	Data         string `json:"Data"`
	LogId        string `json:"LogId"`
	ContentType  string `json:"ContentType"`
}

func NewHTTPTransporter() Transporter {
	return &HTTPTransporter{}
}

func (ht *HTTPTransporter) Init(config *CallbackItemConfig, transporterConfig TransporterConfig, manager *PartitionManager) error {
	ht.Callback = &WorkerCallback{
		Url:          config.Url,
		RetryTimes:   config.RetryTimes,
		Timeout:      config.Timeout,
		BypassFailed: config.BypassFailed,
		FailedSleep:  config.FailedSleep,
	}
	ht.Serializer = config.Serializer
	ht.ContentType = config.ContentType
	ht.transporterConfig = transporterConfig
	ht.discardBuffer = make([]byte, 4096)
	ht.manager = manager

	return nil
}

func (ht *HTTPTransporter) Run() error {
	arbiter := ht.manager.GetArbiter()
	messages := arbiter.MessageChannel()
	offsets := arbiter.OffsetChannel()

	for message := range messages {
		glog.V(1).Infof("Recevied message [topic:%s][partition:%d][url:%s][offset:%d]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset)

		rpcStartTime := time.Now()

		for {
			deliveryState := false
			leftRetryTimes := ht.Callback.RetryTimes

			for {
				deliveryState = ht.delivery(message, ht.Callback.RetryTimes-leftRetryTimes)

				if deliveryState {
					// success
					break
				} else if leftRetryTimes--; leftRetryTimes <= 0 {
					// failed
					break
				}
			}

			if deliveryState {
				// success
				break
			} else if ht.Callback.BypassFailed {
				// failed
				glog.Errorf(
					"Message skipped due to delivery retryTimes exceeded [topic:%s][partition:%d][url:%s][offset:%d][retryTimes:%d][bypassFailed:%t]",
					message.Topic, message.Partition, ht.Callback.Url, message.Offset, ht.Callback.RetryTimes, ht.Callback.BypassFailed)
				break
			}

			glog.Errorf(
				"Retry delivery after %s due to delivery retryTime exceeded [topic:%s][partition:%d][url:%s][offset:%d][retryTimes:%d][bypassFailed:%t][failedSleep:%.2fms]",
				ht.Callback.FailedSleep.String(), message.Topic, message.Partition, ht.Callback.Url, message.Offset, ht.Callback.RetryTimes, ht.Callback.BypassFailed,
				ht.Callback.FailedSleep.Seconds()*1000)

			// wait for FailedSleep times for another retry round
			time.Sleep(ht.Callback.FailedSleep)
		}

		rpcStopTime := time.Now()

		glog.Infof("Committed message [topic:%s][partition:%d][url:%s][offset:%d][cost:%.2fms]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset, rpcStopTime.Sub(rpcStartTime).Seconds()*1000)

		glog.V(1).Infof("HTTP Transporter commit message to arbiter [topic:%s][partition:%d][url:%s][offset:%d]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset)

		offsets <- message.Offset

		glog.V(1).Infof("HTTP Transporter processed message [topic:%s][partition:%d][url:%s][offset:%d]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset)
	}

	glog.V(1).Infof("HTTPTransporter exited [topic:%s][partition:%d][url:%s]", ht.manager.Topic, ht.manager.Partition, ht.Callback.Url)

	return nil
}

func (ht *HTTPTransporter) Close() error {
	// dummy
	return nil
}

func (ht *HTTPTransporter) delivery(message *sarama.ConsumerMessage, retryTime int) bool {
	client := &http.Client{Transport: GetServer().GetHttpTransport()}
	client.Timeout = ht.Callback.Timeout

	var messageData MessageBody

	// deserialize message
	switch ht.Serializer {
	case "", "raw":
		messageData.Data = string(message.Value)
	case "json":
		fallthrough
	default:
		json.Unmarshal(message.Value, &messageData)
		// ignore message json decode failure
	}

	// delivery Content-Type
	if "" != ht.ContentType {
		messageData.ContentType = ht.ContentType
	} else if "" == ht.ContentType {
		ht.ContentType = HTTP_FORM_ENCODING
	}

	req, _ := http.NewRequest("POST", ht.Callback.Url, ioutil.NopCloser(strings.NewReader(messageData.Data)))
	req.Header.Set("Content-Type", messageData.ContentType)
	req.Header.Set("User-Agent", "Taiji pusher consumer(go)/v"+VERSION)
	req.Header.Set("X-Retry-Times", fmt.Sprintf("%d", retryTime))
	req.Header.Set("X-Kmq-Topic", message.Topic)
	req.Header.Set("X-Kmq-Partition", fmt.Sprintf("%d", message.Partition))
	req.Header.Set("X-Kmq-Partition-Key", messageData.PartitionKey)
	req.Header.Set("X-Kmq-Offset", fmt.Sprintf("%d", message.Offset))
	req.Header.Set("X-Kmq-Logid", fmt.Sprintf("%s", messageData.LogId))
	req.Header.Set("X-Kmq-Timestamp", fmt.Sprintf("%d", messageData.TimeStamp))
	req.Header.Set("Meilishuo", "uid:0;ip:0.0.0.0;v:0;master:0")

	rpcStartTime := time.Now()
	res, err := client.Do(req)
	rpcStopTime := time.Now()

	rpcTime := rpcStopTime.Sub(rpcStartTime).Seconds() * 1000
	totalTime := float64(-1)
	if "json" == ht.Serializer {
		totalTime = float64(rpcStopTime.UnixNano()/1000000 - messageData.TimeStamp)
	}

	success := false

	if err == nil {
		defer res.Body.Close()

		if 200 == res.StatusCode {
			// success
			// discard body
			for {
				_, e := res.Body.Read(ht.discardBuffer)
				if e != nil {
					break
				}
			}

			success = true
		} else {
			// error response code, read body
			responseBody, err := ioutil.ReadAll(res.Body)
			if err != nil {
				responseBody = []byte{}
			}
			glog.Errorf(
				"Delivery failed [topic:%s][partition:%d][url:%s][offset:%d][retryTime:%d][responseCode:%d][rpcCost:%.2fms][totalCost:%.2fms][responseBody:%s']",
				message.Topic, message.Partition, ht.Callback.Url, message.Offset, retryTime, res.StatusCode, rpcTime, totalTime, responseBody)
		}
	} else {
		glog.Errorf(
			"Delivery failed [topic:%s][partition:%d][url:%s][offset:%d][retryTime:%d][rpcCost:%.2fms][totalCost:%.2fms][err:%s]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset, retryTime, rpcTime, totalTime, err.Error())
	}

	return success
}

func init() {
	RegisterTransporter("HTTP", NewHTTPTransporter)
}
<commit_msg>Optimize http_transporter.go, do json unmarshal only once<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/Shopify/sarama"
	"github.com/golang/glog"
)

const HTTP_FORM_ENCODING = "application/x-www-form-urlencoded"

type HTTPTransporter struct {
	Callback          *WorkerCallback
	Serializer        string
	ContentType       string
	config            *CallbackItemConfig
	transporterConfig TransporterConfig
	discardBuffer     []byte
	httpClient        *http.Client
	manager           *PartitionManager
}

type MessageBody struct {
	Topic        string `json:"Topic"`
	PartitionKey string `json:"PartitionKey"`
	TimeStamp    int64  `json:"TimeStamp"`
	Data         string `json:"Data"`
	LogId        string `json:"LogId"`
	ContentType  string `json:"ContentType"`
}

func NewHTTPTransporter() Transporter {
	return &HTTPTransporter{}
}

func (ht *HTTPTransporter) Init(config *CallbackItemConfig, transporterConfig TransporterConfig, manager *PartitionManager) error {
	ht.Callback = &WorkerCallback{
		Url:          config.Url,
		RetryTimes:   config.RetryTimes,
		Timeout:      config.Timeout,
		BypassFailed: config.BypassFailed,
		FailedSleep:  config.FailedSleep,
	}
	ht.Serializer = config.Serializer
	ht.ContentType = config.ContentType
	ht.transporterConfig = transporterConfig
	ht.discardBuffer = make([]byte, 4096)
	ht.manager = manager

	// build http client
	ht.httpClient = &http.Client{Transport: GetServer().GetHttpTransport()}
	ht.httpClient.Timeout = ht.Callback.Timeout

	return nil
}

func (ht *HTTPTransporter) Run() error {
	arbiter := ht.manager.GetArbiter()
	messages := arbiter.MessageChannel()
	offsets := arbiter.OffsetChannel()

	for message := range messages {
		glog.V(1).Infof("Recevied message [topic:%s][partition:%d][url:%s][offset:%d]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset)

		var messageData MessageBody

		// deserialize message
		switch ht.Serializer {
		case "", "raw":
			messageData.Data = string(message.Value)
		case "json":
			fallthrough
		default:
			json.Unmarshal(message.Value, &messageData)
			// ignore message json decode failure
		}

		// delivery Content-Type
		if "" != ht.ContentType {
			messageData.ContentType = ht.ContentType
		} else if "" == ht.ContentType {
			ht.ContentType = HTTP_FORM_ENCODING
		}

		rpcStartTime := time.Now()

		for {
			deliveryState := false

			for i := 0; i <= ht.Callback.RetryTimes; i++ {
				deliveryState = ht.delivery(&messageData, message, i)

				if deliveryState {
					// success
					break
				}
			}

			if deliveryState {
				// success
				break
			} else if ht.Callback.BypassFailed {
				// failed
				glog.Errorf(
					"Message skipped due to delivery retryTimes exceeded [topic:%s][partition:%d][url:%s][offset:%d][retryTimes:%d][bypassFailed:%t]",
					message.Topic, message.Partition, ht.Callback.Url, message.Offset, ht.Callback.RetryTimes, ht.Callback.BypassFailed)
				break
			}

			glog.Errorf(
				"Retry delivery after %s due to delivery retryTime exceeded [topic:%s][partition:%d][url:%s][offset:%d][retryTimes:%d][bypassFailed:%t][failedSleep:%.2fms]",
				ht.Callback.FailedSleep.String(), message.Topic, message.Partition, ht.Callback.Url, message.Offset, ht.Callback.RetryTimes, ht.Callback.BypassFailed,
				ht.Callback.FailedSleep.Seconds()*1000)

			// wait for FailedSleep times for another retry round
			time.Sleep(ht.Callback.FailedSleep)
		}

		rpcStopTime := time.Now()

		// total time from proxy to pusher complete sending
		totalTime := float64(-1)
		if ht.Serializer == "json" {
			totalTime = float64(rpcStopTime.UnixNano()/1000000 - messageData.TimeStamp)
		}

		glog.Infof("Committed message [topic:%s][partition:%d][url:%s][offset:%d][cost:%.2fms][totalCost:%.2fms]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset,
			rpcStopTime.Sub(rpcStartTime).Seconds()*1000,
			totalTime)

		glog.V(1).Infof("HTTP Transporter commit message to arbiter [topic:%s][partition:%d][url:%s][offset:%d]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset)

		offsets <- message.Offset

		glog.V(1).Infof("HTTP Transporter processed message [topic:%s][partition:%d][url:%s][offset:%d]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset)
	}

	glog.V(1).Infof("HTTPTransporter exited [topic:%s][partition:%d][url:%s]", ht.manager.Topic, ht.manager.Partition, ht.Callback.Url)

	return nil
}

func (ht *HTTPTransporter) Close() error {
	// dummy
	return nil
}

func (ht *HTTPTransporter) delivery(messageData *MessageBody, message *sarama.ConsumerMessage, retryTime int) bool {
	req, _ := http.NewRequest("POST", ht.Callback.Url, strings.NewReader(messageData.Data))
	req.Header.Set("Content-Type", messageData.ContentType)
	req.Header.Set("User-Agent", "Taiji pusher consumer(go)/v"+VERSION)
	req.Header.Set("X-Retry-Times", fmt.Sprintf("%d", retryTime))
	req.Header.Set("X-Kmq-Topic", message.Topic)
	req.Header.Set("X-Kmq-Partition", fmt.Sprintf("%d", message.Partition))
	req.Header.Set("X-Kmq-Partition-Key", messageData.PartitionKey)
	req.Header.Set("X-Kmq-Offset", fmt.Sprintf("%d", message.Offset))
	req.Header.Set("X-Kmq-Logid", fmt.Sprintf("%s", messageData.LogId))
	req.Header.Set("X-Kmq-Timestamp", fmt.Sprintf("%d", messageData.TimeStamp))
	req.Header.Set("Meilishuo", "uid:0;ip:0.0.0.0;v:0;master:0")

	rpcStartTime := time.Now()
	res, err := ht.httpClient.Do(req)
	rpcStopTime := time.Now()

	rpcTime := rpcStopTime.Sub(rpcStartTime).Seconds() * 1000

	success := false

	if err == nil {
		defer res.Body.Close()

		if 200 == res.StatusCode {
			// success
			success = true
			// discard body
			// better use io.Copy(ioutil.Discard, res.Body), but io.Copy/ioutil.Discard is too slow
			for {
				_, e := res.Body.Read(ht.discardBuffer)
				if e != nil {
					break
				}
			}
		} else {
			// error response code, read body
			responseBody, err := ioutil.ReadAll(res.Body)
			if err != nil {
				responseBody = []byte{}
			}
			glog.Errorf(
				"Delivery failed [topic:%s][partition:%d][url:%s][offset:%d][retryTime:%d][responseCode:%d][cost:%.2fms][responseBody:%s']",
				message.Topic, message.Partition, ht.Callback.Url, message.Offset, retryTime, res.StatusCode, rpcTime, responseBody)
		}
	} else {
		glog.Errorf(
			"Delivery failed [topic:%s][partition:%d][url:%s][offset:%d][retryTime:%d][cost:%.2fms][err:%s]",
			message.Topic, message.Partition, ht.Callback.Url, message.Offset, retryTime, rpcTime, err.Error())
	}

	return success
}

func init() {
	RegisterTransporter("HTTP", NewHTTPTransporter)
}
<|endoftext|>


<commit_before>package robots

import (
	"fmt"
	"github.com/trinchan/slackbot/robots"
	"math/rand"
	"github.com/trinchan/slackbot/robots/raffl/db"
	"log"
)

type bot struct{}

var botInitialized bool = false;

func init() {
	p := &bot{}
	robots.RegisterRobot("raffl", p)

	/*
			// Get a prize from the database by their ID.
			for _, id := range []string{"100", "101"} {
				p, err := person.GetPerson(id)
				if err != nil {
					log.Fatal(err)
				}
				fmt.Println(p)
			}

			person.ListPrefix(prize.PrizeBucketName, "20")         // ... with key prefix `20`
			person.ListRange(prize.PrizeBucketName, "101", "103")  // ... within range `101` to `103`
			*/

}

func InitDb(payload *robots.Payload) (err error) {

	if (botInitialized) {
		return nil;
	}

	log.Println("Initializing the Database")

	prize.Open()
	defer prize.Close()

	prizes := []*prize.Prize{
		{
			"100",
			"JetBrains Product License",
			"1 year subscription to any product\nLicense Key: CH3DZ-3EEVS-727UJ-2P4KK-7IHL8",
			"CH3DZ-3EEVS-727UJ-2P4KK-7IHL8",
			false,
			"",
			"https://www.jetbrains.com/products.html",
		},
		{
			"101",
			"JetBrains product license",
			"1 year subscription to any product\nLicense Key: 7WIF8-AKIWA-CX0QD-A7BY8-6A1EH",
			"7WIF8-AKIWA-CX0QD-A7BY8-6A1EH",
			false,
			"",
			"https://www.jetbrains.com/products.html",
		},
	}

	// Persist prizes in the database.
	for _, p := range prizes {
		p.Save()
	}

	prize.List(prize.PrizeBucketName)                     // each key/val in people bucket

	numberOfPrizes := prize.NumberOfPrizes(prize.PrizeBucketName)
	log.Printf("Number of prizes: %d", numberOfPrizes)

	return nil;
}

func (pb bot) Run(p *robots.Payload) (slashCommandImmediateReturn string) {

	log.Printf("[DEBUG] Payload: %s", p)
	prize.Open()
	defer prize.Close()

	status := "checking..."

	if (!botInitialized && p.Text != "init") {
		return "raffle needs to be initialized before continuing..."
	}

	switch p.Text {
	case "init":
		status = "initializing"
		go pb.InitializeDeferred(p)
		break;
	case "status":
		status = "running status"
		go pb.PrizeStatusDeferred(p, false)
		break;
	case "astatus":
		status = "running admin status"
		go pb.PrizeStatusDeferred(p, true)
		break;
	default:
		status = "checking for winner"
		go pb.CheckForPrizeWinDeferred(p)
	}

	return status
}

func (pb bot) InitializeDeferred(p *robots.Payload) {

	message := ""
	err := InitDb(p)
	if (err != nil) {
		botInitialized = false;
		message = "Initialization failed"
	} else {
		botInitialized = true;
		message = "Initialization complete"
	}
	SendResponse(p, message)
}

var SendResponse = func(p *robots.Payload, message string) {
	response := &robots.IncomingWebhook{
		Domain:      p.TeamDomain,
		Channel:     "@" + p.UserName,
		Username:    "raffl",
		Text:        message,
		IconEmoji:   ":gift:",
		UnfurlLinks: true,
		Parse:       robots.ParseStyleFull,
	}
	response.Send()
}

func (pb bot) PrizeStatusDeferred(p *robots.Payload, admin bool) {
	prize.Open()
	defer prize.Close()
	if admin {
		SendResponse(p, prize.List(prize.PrizeBucketName))
	} else {
		SendResponse(p, prize.ListUnclaimed(prize.PrizeBucketName))
	}
}

func (pb bot) CheckForPrizeWinDeferred(p *robots.Payload) {

	numberOfPrizes := prize.NumberOfPrizes(prize.PrizeBucketName)

	pick := rand.Intn(4)

	outcome := ""
	if pick > 0 && pick <= numberOfPrizes {
		prizeInfo, err := prize.SelectAndClaimPrize(pick, p.UserName)
		if err != nil {
			outcome = fmt.Sprintf("Something went wrong, our crack dev team will check this out: %v", err)
		} else {
			outcome = fmt.Sprintf("Your a winner! Here is your prize: %v", prizeInfo)
		}
	} else {
		outcome = "Sorry, better luck next time!"
	}
	message := fmt.Sprintf("Hi @%s!\n %s\n %s", p.UserName, "Let's see if you've won a prize...", outcome)
	SendResponse(p, message)
}

func (pb bot) Description() (description string) {
	return "Raffl bot!\n\tUsage: /raffl\n\tExpected Response: @user: Raffl this!"
}
<commit_msg>Implement select and claim a prize<commit_after>package robots

import (
	"fmt"
	"github.com/trinchan/slackbot/robots"
	"math/rand"
	"github.com/trinchan/slackbot/robots/raffl/db"
	"log"
)

type bot struct{}

var botInitialized bool = false;

func init() {
	p := &bot{}
	robots.RegisterRobot("raffl", p)

	/*
			// Get a prize from the database by their ID.
			for _, id := range []string{"100", "101"} {
				p, err := person.GetPerson(id)
				if err != nil {
					log.Fatal(err)
				}
				fmt.Println(p)
			}

			person.ListPrefix(prize.PrizeBucketName, "20")         // ... with key prefix `20`
			person.ListRange(prize.PrizeBucketName, "101", "103")  // ... within range `101` to `103`
			*/

}

func InitDb(payload *robots.Payload) (err error) {

	if (botInitialized) {
		return nil;
	}

	log.Println("Initializing the Database")

	prize.Open()
	defer prize.Close()

	prizes := []*prize.Prize{
		{
			"100",
			"JetBrains Product License",
			"1 year subscription to any product\nLicense Key: CH3DZ-3EEVS-727UJ-2P4KK-7IHL8",
			"CH3DZ-3EEVS-727UJ-2P4KK-7IHL8",
			false,
			"",
			"https://www.jetbrains.com/products.html",
		},
		{
			"101",
			"JetBrains product license",
			"1 year subscription to any product\nLicense Key: 7WIF8-AKIWA-CX0QD-A7BY8-6A1EH",
			"7WIF8-AKIWA-CX0QD-A7BY8-6A1EH",
			false,
			"",
			"https://www.jetbrains.com/products.html",
		},
	}

	// Persist prizes in the database.
	for _, p := range prizes {
		p.Save()
	}

	prize.List(prize.PrizeBucketName)                     // each key/val in people bucket

	numberOfPrizes := prize.NumberOfPrizes(prize.PrizeBucketName)
	log.Printf("Number of prizes: %d", numberOfPrizes)

	return nil;
}

func (pb bot) Run(p *robots.Payload) (slashCommandImmediateReturn string) {

	log.Printf("[DEBUG] Payload: %s", p)
	prize.Open()
	defer prize.Close()

	status := "checking..."

	if (!botInitialized && p.Text != "init") {
		return "raffle needs to be initialized before continuing..."
	}

	switch p.Text {
	case "init":
		status = "initializing"
		go pb.InitializeDeferred(p)
		break;
	case "status":
		status = "running status"
		go pb.PrizeStatusDeferred(p, false)
		break;
	case "astatus":
		status = "running admin status"
		go pb.PrizeStatusDeferred(p, true)
		break;
	default:
		status = "checking for winner"
		go pb.CheckForPrizeWinDeferred(p)
	}

	return status
}

func (pb bot) InitializeDeferred(p *robots.Payload) {

	message := ""
	err := InitDb(p)
	if (err != nil) {
		botInitialized = false;
		message = "Initialization failed"
	} else {
		botInitialized = true;
		message = "Initialization complete"
	}
	SendResponse(p, message)
}

var SendResponse = func(p *robots.Payload, message string) {
	response := &robots.IncomingWebhook{
		Domain:      p.TeamDomain,
		Channel:     "@" + p.UserName,
		Username:    "raffl",
		Text:        message,
		IconEmoji:   ":gift:",
		UnfurlLinks: true,
		Parse:       robots.ParseStyleFull,
	}
	response.Send()
}

func (pb bot) PrizeStatusDeferred(p *robots.Payload, admin bool) {
	prize.Open()
	defer prize.Close()
	if admin {
		SendResponse(p, prize.List(prize.PrizeBucketName))
	} else {
		SendResponse(p, prize.ListUnclaimed(prize.PrizeBucketName))
	}
}

func (pb bot) CheckForPrizeWinDeferred(p *robots.Payload) {

	numberOfPrizes := prize.NumberOfPrizes(prize.PrizeBucketName)

	pick := rand.Intn(4)
	outcome := ""

	log.Printf("Number of prizes: %v - pick %v", numberOfPrizes, pick)

	if pick > 0 && pick <= numberOfPrizes {
		prizeInfo, err := prize.SelectAndClaimPrize(pick, p.UserName)
		if err != nil {
			outcome = fmt.Sprintf("Something went wrong, our crack dev team will check this out: %v", err)
		} else {
			outcome = fmt.Sprintf("Your a winner! Here is your prize: %v", prizeInfo)
		}
	} else {
		outcome = "Sorry, better luck next time!"
	}
	message := fmt.Sprintf("Hi @%s!\n %s\n %s", p.UserName, "Let's see if you've won a prize...", outcome)
	SendResponse(p, message)
}

func (pb bot) Description() (description string) {
	return "Raffl bot!\n\tUsage: /raffl\n\tExpected Response: @user: Raffl this!"
}
<|endoftext|>


<commit_before>package router

import (
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/AsynkronIT/protoactor-go/actor"
	"github.com/stretchr/testify/mock"
)

func init() {
	// discard all logging in tests
	log.SetOutput(ioutil.Discard)
}

func spawnMockProcess(name string) (*actor.PID, *mockProcess) {
	p := &mockProcess{}
	pid, ok := actor.ProcessRegistry.Add(p, name)
	if !ok {
		panic(fmt.Errorf("did not spawn named process '%s'", name))
	}

	return pid, p
}

func removeMockProcess(pid *actor.PID) {
	actor.ProcessRegistry.Remove(pid)
}

type mockProcess struct {
	mock.Mock
}

func (m *mockProcess) SendUserMessage(pid *actor.PID, message interface{}, sender *actor.PID) {
	m.Called(pid, message, sender)
}
func (m *mockProcess) SendSystemMessage(pid *actor.PID, message actor.SystemMessage) {
	m.Called(pid, message)
}
func (m *mockProcess) Stop(pid *actor.PID) {
	m.Called(pid)
}
type mockContext struct {
	mock.Mock
}

func (m *mockContext) Watch(pid *actor.PID) {
	m.Called(pid)
}

func (m *mockContext) Unwatch(pid *actor.PID) {
	m.Called(pid)
}

func (m *mockContext) Message() interface{} {
	args := m.Called()
	return args.Get(0)
}

func (m *mockContext) SetReceiveTimeout(d time.Duration) {
	m.Called(d)
}
func (m *mockContext) ReceiveTimeout() time.Duration {
	args := m.Called()
	return args.Get(0).(time.Duration)
}

func (m *mockContext) Sender() *actor.PID {
	args := m.Called()
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Become(r actor.Receive) {
	m.Called(r)
}

func (m *mockContext) BecomeStacked(r actor.Receive) {
	m.Called(r)
}

func (m *mockContext) UnbecomeStacked() {
	m.Called()
}

func (m *mockContext) Self() *actor.PID {
	args := m.Called()
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Parent() *actor.PID {
	args := m.Called()
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Spawn(p actor.Props) *actor.PID {
	args := m.Called(p)
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) SpawnNamed(p actor.Props, name string) *actor.PID {
	args := m.Called(p, name)
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Children() []*actor.PID {
	args := m.Called()
	return args.Get(0).([]*actor.PID)
}

func (m *mockContext) Next() {
	m.Called()
}

func (m *mockContext) Receive(i interface{}) {
	m.Called(i)
}

func (m *mockContext) Stash() {
	m.Called()
}

func (m *mockContext) Respond(response interface{}) {
	m.Called(response)
}

func (m *mockContext) Actor() actor.Actor {
	args := m.Called()
	return args.Get(0).(actor.Actor)
}
<commit_msg>gofmt<commit_after>package router

import (
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/AsynkronIT/protoactor-go/actor"
	"github.com/stretchr/testify/mock"
)

func init() {
	// discard all logging in tests
	log.SetOutput(ioutil.Discard)
}

func spawnMockProcess(name string) (*actor.PID, *mockProcess) {
	p := &mockProcess{}
	pid, ok := actor.ProcessRegistry.Add(p, name)
	if !ok {
		panic(fmt.Errorf("did not spawn named process '%s'", name))
	}

	return pid, p
}

func removeMockProcess(pid *actor.PID) {
	actor.ProcessRegistry.Remove(pid)
}

type mockProcess struct {
	mock.Mock
}

func (m *mockProcess) SendUserMessage(pid *actor.PID, message interface{}, sender *actor.PID) {
	m.Called(pid, message, sender)
}
func (m *mockProcess) SendSystemMessage(pid *actor.PID, message actor.SystemMessage) {
	m.Called(pid, message)
}
func (m *mockProcess) Stop(pid *actor.PID) {
	m.Called(pid)
}

type mockContext struct {
	mock.Mock
}

func (m *mockContext) Watch(pid *actor.PID) {
	m.Called(pid)
}

func (m *mockContext) Unwatch(pid *actor.PID) {
	m.Called(pid)
}

func (m *mockContext) Message() interface{} {
	args := m.Called()
	return args.Get(0)
}

func (m *mockContext) SetReceiveTimeout(d time.Duration) {
	m.Called(d)
}
func (m *mockContext) ReceiveTimeout() time.Duration {
	args := m.Called()
	return args.Get(0).(time.Duration)
}

func (m *mockContext) Sender() *actor.PID {
	args := m.Called()
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Become(r actor.Receive) {
	m.Called(r)
}

func (m *mockContext) BecomeStacked(r actor.Receive) {
	m.Called(r)
}

func (m *mockContext) UnbecomeStacked() {
	m.Called()
}

func (m *mockContext) Self() *actor.PID {
	args := m.Called()
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Parent() *actor.PID {
	args := m.Called()
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Spawn(p actor.Props) *actor.PID {
	args := m.Called(p)
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) SpawnNamed(p actor.Props, name string) *actor.PID {
	args := m.Called(p, name)
	return args.Get(0).(*actor.PID)
}

func (m *mockContext) Children() []*actor.PID {
	args := m.Called()
	return args.Get(0).([]*actor.PID)
}

func (m *mockContext) Next() {
	m.Called()
}

func (m *mockContext) Receive(i interface{}) {
	m.Called(i)
}

func (m *mockContext) Stash() {
	m.Called()
}

func (m *mockContext) Respond(response interface{}) {
	m.Called(response)
}

func (m *mockContext) Actor() actor.Actor {
	args := m.Called()
	return args.Get(0).(actor.Actor)
}
<|endoftext|>


<commit_before>package endpoints

import (
	"fmt"
)

/*
 * Parameter / Request Validation
 */

// Check if the value is not longer than a given length
func ValidateLength(value string, maxLength int) error {
	if len(value) > maxLength {
		return fmt.Errorf("Provided param value is too long.")
	}
	return nil
}

func ValidateCharset(value string, alphabet string) error {
	for _, check := range value {
		ok := false
		for _, char := range alphabet {
			if char == check {
				ok = true
				break
			}
		}
		if !ok {
			return fmt.Errorf("Invalid character in param value")
		}
	}
	return nil
}

func ValidateLengthAndCharset(value string, maxLength int, alphabet string) (string, error) {
	// Check length
	if err := ValidateLength(value, maxLength); err != nil {
		return "", err
	}

	// Check input
	if err := ValidateCharset(value, alphabet); err != nil {
		return "", err
	}

	return value, nil
}

func ValidateProtocolParam(value string) (string, error) {
	return ValidateLengthAndCharset(value, 80, "ID_AS:.abcdef1234567890")
}

func ValidatePrefixParam(value string) (string, error) {
	return ValidateLengthAndCharset(value, 80, "1234567890abcdef.:/")
}
<commit_msg>fix: more permissive protocol alphabet<commit_after>package endpoints

import (
	"fmt"
)

/*
 * Parameter / Request Validation
 */

// Check if the value is not longer than a given length
func ValidateLength(value string, maxLength int) error {
	if len(value) > maxLength {
		return fmt.Errorf("Provided param value is too long.")
	}
	return nil
}

func ValidateCharset(value string, alphabet string) error {
	for _, check := range value {
		ok := false
		for _, char := range alphabet {
			if char == check {
				ok = true
				break
			}
		}
		if !ok {
			return fmt.Errorf("Invalid character in param value")
		}
	}
	return nil
}

func ValidateLengthAndCharset(value string, maxLength int, alphabet string) (string, error) {
	// Check length
	if err := ValidateLength(value, maxLength); err != nil {
		return "", err
	}

	// Check input
	if err := ValidateCharset(value, alphabet); err != nil {
		return "", err
	}

	return value, nil
}

func ValidateProtocolParam(value string) (string, error) {
	return ValidateLengthAndCharset(value, 80, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_:.abcdefghijklmnopqrstuvwxyz1234567890")
}

func ValidatePrefixParam(value string) (string, error) {
	return ValidateLengthAndCharset(value, 80, "1234567890abcdef.:/")
}
<|endoftext|>


<commit_before>package rpc

import "sync"

// SampleCounter is a thread-safe  decreasing counter
type SampleCounter struct {
	sync.Mutex
	Counter int
}

// NewSampleCounter initializes the counter with a value
func NewSampleCounter(value int) *SampleCounter {
	return &SampleCounter{Counter: value + 1}
}

// Dec decreases the counter by value, but doesn't go below zero (if
// value > sc.value, the counter's value will become 0). Returns the
// new value.
func (sc *SampleCounter) Dec(value int) int {
	sc.Lock()
	defer sc.Unlock()

	if sc.Counter >= value {
		sc.Counter -= value
	} else {
		value = sc.Counter
		sc.Counter = 0
	}
	return value
}
<commit_msg>fix sample counter bug<commit_after>package rpc

import "sync/atomic"

// SampleCounter is a thread-safe  decreasing counter
type SampleCounter struct {
	Counter int64
}

// NewSampleCounter initializes the counter with a value
func NewSampleCounter(value int) *SampleCounter {
	return &SampleCounter{Counter: int64(value)}
}

// Dec decreases the counter by value, but doesn't go below zero (if
// value > sc.value, the counter's value will become 0). Returns the
// actual amount decremented (so the return value is 0 if the counter
// has already been 0)
func (sc *SampleCounter) Dec(value int) int {
	difference := int64(value)
	newValue := atomic.AddInt64(&sc.Counter, -difference)

	if newValue >= 0 {
		return int(difference)
	}

	atomic.StoreInt64(&sc.Counter, 0)

	if -newValue < difference {
		return int(difference + newValue)
	} else {
		return 0
	}
}
<|endoftext|>