<commit_before>package gotop

import (
	// "errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

/*
#include <unistd.h>
unsigned int get_pagesize(void) {
  return sysconf(_SC_PAGESIZE);
}
*/
import "C"

var (
	procDirectory   = "/proc"
	processStatFile = "/proc/%d/stat"
	processMemFile  = "/proc/%d/statm"
	processStates   = map[string]string{"R": "Running", "S": "Sleeping", "D": "Sleeping-uninterruptable", "Z": "Zombie", "T": "Traced/Stopped"}
)

type ProcessInfo struct {
	Pid    int
	Name   string
	State  string
	CPU    float64
	Memory int
}

type pstat struct {
	pid       int
	name      string
	state     string
	utime     int
	stime     int
	startTime int
	// rss       int
}

func processIds() ([]int, error) {
	file, err := os.Open(procDirectory)
	if err != nil {
		return make([]int, 0), err
	}
	fi, _ := file.Readdir(-1)
	pids := make([]int, len(fi))
	var index int
	for _, i := range fi {
		val, err := strconv.Atoi(i.Name())
		if err != nil {
			continue
		}
		pids[index] = val
		index = index + 1
	}
	return pids[:index], nil
}

func readStatFile(pid int) ([]string, error) {
	path := fmt.Sprintf(processStatFile, pid)
	file, err := readFile(path)
	if err != nil {
		return make([]string, 0), err
	}
	return strings.Split(file, " "), nil
}

func processStat(pid int) (pstat, error) {
	pfile, err := readStatFile(pid)
	if err != nil {
		return pstat{}, err
	}
	name := pfile[1]
	name = name[1 : len(name)-1] // Removes parentheses
	state := processStates[pfile[2]]
	utime, _ := strconv.Atoi(pfile[13])
	stime, _ := strconv.Atoi(pfile[14])
	starttime, _ := strconv.Atoi(pfile[21])
	// rss, _ := strconv.Atoi(pfile[23])
	return pstat{pid, name, state, utime, stime, starttime}, nil
}

func calcCPU(prevps, curps pstat, prevtime, curtime int64) float64 {
	// Time is in nanoseconds. Needs to be converted to jiffies.
	timedelta := float64(curtime-prevtime) / 10000000
	usercpu := float64(curps.utime-prevps.utime) / timedelta
	systemcpu := float64(curps.stime-prevps.stime) / timedelta
	usage := (usercpu + systemcpu) * 100
	// Return value is truncated to 2 places after decimal
	return float64(int(usage*100)) / 100
}

func processStats(done <-chan struct{}, delay time.Duration) (<-chan map[int]ProcessInfo, <-chan error) {
	resultChan := make(chan map[int]ProcessInfo, 1)
	errc := make(chan error, 1)
	var err error
	cleanup := func() {
		errc <- err
		close(errc)
		close(resultChan)
	}
	go func() {
		defer cleanup()
		pids, err := processIds()
		if err != nil {
			return
		}
		var result map[int]ProcessInfo
		prev := make(map[int]pstat)
		var ps pstat
		var cpu float64
		var curtime, prevtime int64
		for {
			prevtime = curtime
			time.Sleep(delay)
			curtime = time.Now().UnixNano()
			if err != nil {
				return
			}
			result = make(map[int]ProcessInfo)
			for _, pid := range pids {
				ps, err = processStat(pid)
				if err != nil {
					return
				}
				if psprev, ok := prev[pid]; ok {
					cpu = calcCPU(psprev, ps, prevtime, curtime)
				} else {
					cpu = 0
				}
				result[pid] = ProcessInfo{ps.pid, ps.name, ps.state, cpu, 0}
				prev[pid] = ps
			}

			select {
			case resultChan <- result:
			case <-done:
				return
			}
		}
	}()
	return resultChan, errc
}

func processMem(pid int) (int, error) {
	memfile := fmt.Sprintf(processMemFile, pid)
	val, err := readFile(memfile)
	if err != nil {
		return 0, err
	}
	vals := stringtointslice(val)
	return vals[1], nil
}

func processMems(done <-chan struct{}, delay time.Duration) (<-chan map[int]int, <-chan error) {
	resultChan := make(chan map[int]int, 1)
	errc := make(chan error)
	var err error
	cleanup := func() {
		errc <- err
		close(errc)
		close(resultChan)
	}
	go func() {
		defer cleanup()
		pids, err := processIds()
		if err != nil {
			return
		}
		var result map[int]int
		var mem int
		psize := pagesize()
		for {
			result = make(map[int]int)
			for _, pid := range pids {
				mem, err = processMem(pid)
				if err != nil {
					return
				}
				result[pid] = mem
			}
			for key, val := range result {
				result[key] = val * psize
			}
			select {
			case resultChan <- result:
			case <-done:
				return
			}
		}
	}()
	return resultChan, errc
}

func pagesize() int{
	return int(C.get_pagesize())
}

func merge(pInfo map[int]ProcessInfo, pMem map[int]int) map[int]ProcessInfo {
	for pid, val := range pInfo {
		val.Memory = pMem[pid]
		pInfo[pid] = val
	}
	return pInfo
}

func GetProcessInfo(done <-chan struct{}, delay time.Duration) (<-chan map[int]ProcessInfo, <-chan error) {
	resultChan := make(chan map[int]ProcessInfo, 1)
	errc := make(chan error)
	pInfoChan, errsc := processStats(done, delay)
	pMemChan, errmc := processMems(done, delay)
	var err error
	cleanup := func() {
		errc <- err
		close(errc)
		close(resultChan)
	}
	go func() {
		defer cleanup()
		var pMem map[int]int
		var pInfo map[int]ProcessInfo
		for {
			select {
			case pInfo = <-pInfoChan:
				pMem = <-pMemChan
				pInfo = merge(pInfo, pMem)
				resultChan <- pInfo
			case pMem = <-pMemChan:
				pInfo = <-pInfoChan
				pInfo = merge(pInfo, pMem)
				resultChan <- pInfo
			case err = <-errsc:
				return
			case err = <-errmc:
				return
			case <-done:
				return
			}
		}
	}()
	return resultChan, errc
}
<commit_msg>Move exported functions to the top of the file<commit_after>package gotop

import (
	// "errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

/*
#include <unistd.h>
unsigned int get_pagesize(void) {
  return sysconf(_SC_PAGESIZE);
}
*/
import "C"

var (
	procDirectory   = "/proc"
	processStatFile = "/proc/%d/stat"
	processMemFile  = "/proc/%d/statm"
	processStates   = map[string]string{"R": "Running", "S": "Sleeping", "D": "Sleeping-uninterruptable", "Z": "Zombie", "T": "Traced/Stopped"}
)

type ProcessInfo struct {
	Pid    int
	Name   string
	State  string
	CPU    float64
	Memory int
}

func GetProcessInfo(done <-chan struct{}, delay time.Duration) (<-chan map[int]ProcessInfo, <-chan error) {
	resultChan := make(chan map[int]ProcessInfo, 1)
	errc := make(chan error)
	pInfoChan, errsc := processStats(done, delay)
	pMemChan, errmc := processMems(done, delay)
	var err error
	cleanup := func() {
		errc <- err
		close(errc)
		close(resultChan)
	}
	go func() {
		defer cleanup()
		var pMem map[int]int
		var pInfo map[int]ProcessInfo
		for {
			select {
			case pInfo = <-pInfoChan:
				pMem = <-pMemChan
				pInfo = merge(pInfo, pMem)
				resultChan <- pInfo
			case pMem = <-pMemChan:
				pInfo = <-pInfoChan
				pInfo = merge(pInfo, pMem)
				resultChan <- pInfo
			case err = <-errsc:
				return
			case err = <-errmc:
				return
			case <-done:
				return
			}
		}
	}()
	return resultChan, errc
}

func processMems(done <-chan struct{}, delay time.Duration) (<-chan map[int]int, <-chan error) {
	resultChan := make(chan map[int]int, 1)
	errc := make(chan error)
	var err error
	cleanup := func() {
		errc <- err
		close(errc)
		close(resultChan)
	}
	go func() {
		defer cleanup()
		pids, err := processIds()
		if err != nil {
			return
		}
		var result map[int]int
		var mem int
		psize := pagesize()
		for {
			result = make(map[int]int)
			for _, pid := range pids {
				mem, err = processMem(pid)
				if err != nil {
					return
				}
				result[pid] = mem
			}
			for key, val := range result {
				result[key] = val * psize
			}
			select {
			case resultChan <- result:
			case <-done:
				return
			}
		}
	}()
	return resultChan, errc
}

func processStats(done <-chan struct{}, delay time.Duration) (<-chan map[int]ProcessInfo, <-chan error) {
	resultChan := make(chan map[int]ProcessInfo, 1)
	errc := make(chan error, 1)
	var err error
	cleanup := func() {
		errc <- err
		close(errc)
		close(resultChan)
	}
	go func() {
		defer cleanup()
		pids, err := processIds()
		if err != nil {
			return
		}
		var result map[int]ProcessInfo
		prev := make(map[int]pstat)
		var ps pstat
		var cpu float64
		var curtime, prevtime int64
		for {
			prevtime = curtime
			time.Sleep(delay)
			curtime = time.Now().UnixNano()
			if err != nil {
				return
			}
			result = make(map[int]ProcessInfo)
			for _, pid := range pids {
				ps, err = processStat(pid)
				if err != nil {
					return
				}
				if psprev, ok := prev[pid]; ok {
					cpu = calcCPU(psprev, ps, prevtime, curtime)
				} else {
					cpu = 0
				}
				result[pid] = ProcessInfo{ps.pid, ps.name, ps.state, cpu, 0}
				prev[pid] = ps
			}

			select {
			case resultChan <- result:
			case <-done:
				return
			}
		}
	}()
	return resultChan, errc
}

func processIds() ([]int, error) {
	file, err := os.Open(procDirectory)
	if err != nil {
		return make([]int, 0), err
	}
	fi, _ := file.Readdir(-1)
	pids := make([]int, len(fi))
	var index int
	for _, i := range fi {
		val, err := strconv.Atoi(i.Name())
		if err != nil {
			continue
		}
		pids[index] = val
		index = index + 1
	}
	return pids[:index], nil
}

func readStatFile(pid int) ([]string, error) {
	path := fmt.Sprintf(processStatFile, pid)
	file, err := readFile(path)
	if err != nil {
		return make([]string, 0), err
	}
	return strings.Split(file, " "), nil
}

type pstat struct {
	pid       int
	name      string
	state     string
	utime     int
	stime     int
	startTime int
}

func processStat(pid int) (pstat, error) {
	pfile, err := readStatFile(pid)
	if err != nil {
		return pstat{}, err
	}
	name := pfile[1]
	name = name[1 : len(name)-1] // Removes parentheses
	state := processStates[pfile[2]]
	utime, _ := strconv.Atoi(pfile[13])
	stime, _ := strconv.Atoi(pfile[14])
	starttime, _ := strconv.Atoi(pfile[21])
	// rss, _ := strconv.Atoi(pfile[23])
	return pstat{pid, name, state, utime, stime, starttime}, nil
}

func calcCPU(prevps, curps pstat, prevtime, curtime int64) float64 {
	// Time is in nanoseconds. Needs to be converted to jiffies.
	timedelta := float64(curtime-prevtime) / 10000000
	usercpu := float64(curps.utime-prevps.utime) / timedelta
	systemcpu := float64(curps.stime-prevps.stime) / timedelta
	usage := (usercpu + systemcpu) * 100
	// Return value is truncated to 2 places after decimal
	return float64(int(usage*100)) / 100
}

func processMem(pid int) (int, error) {
	memfile := fmt.Sprintf(processMemFile, pid)
	val, err := readFile(memfile)
	if err != nil {
		return 0, err
	}
	vals := stringtointslice(val)
	return vals[1], nil
}

func pagesize() int{
	return int(C.get_pagesize())
}

func merge(pInfo map[int]ProcessInfo, pMem map[int]int) map[int]ProcessInfo {
	for pid, val := range pInfo {
		val.Memory = pMem[pid]
		pInfo[pid] = val
	}
	return pInfo
}
<|endoftext|>


<commit_before>// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile

import (
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
)

type profile struct {
	// Quiet suppresses informational messages during profiling.
	Quiet bool

	// CPUProfile controls if cpu profiling will be enabled.
	CPUProfile bool

	// MemProfile controls if memory profiling will be enabled.
	MemProfile bool

	// BlockProfile controls if block (contention) profiling will
	// be enabled.
	// It defaults to false.
	BlockProfile bool

	// ProfilePath controls the base path where various profiling
	// files are written. If blank, the base path will be generated
	// by ioutil.TempDir.
	ProfilePath string

	// NoShutdownHook controls whether the profiling package should
	// hook SIGINT to write profiles cleanly.
	NoShutdownHook bool

	// MemProfileRate sent the rate for the memory profile
	memProfileRate int

	closers []func()
}

// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *profile) { p.NoShutdownHook = true }

// Quiet suppresses informational messages during profiling.
func Quiet(p *profile) { p.Quiet = true }

func (p *profile) NoProfiles() {
	p.CPUProfile = false
	p.MemProfile = false
	p.BlockProfile = false
}

// CPUProfile controls if cpu profiling will be enabled. It disables any previous profiling settings.
func CPUProfile(p *profile) {
	p.NoProfiles()
	p.CPUProfile = true
}

// MemProfile controls if memory profiling will be enabled. It disables any previous profiling settings.
func MemProfile(p *profile) {
	p.NoProfiles()
	p.MemProfile = true
}

// BlockProfile controls if block (contention) profiling will be enabled. It disables any previous profiling settings.
func BlockProfile(p *profile) {
	p.NoProfiles()
	p.BlockProfile = true
}

// resolvePath resolves the profile's path or outputs to a temporarry directory
func resolvePath(path string) (resolvedPath string, err error) {
	if path != "" {
		return path, os.MkdirAll(path, 0777)
	}

	return ioutil.TempDir("", "profile")
}

func (p *profile) Stop() {
	for _, c := range p.closers {
		c()
	}
}

func newProfile() *profile {
	prof := &profile{memProfileRate: 4096}
	CPUProfile(prof)
	return prof
}

// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*profile)) interface {
	Stop()
} {
	prof := newProfile()
	for _, option := range options {
		option(prof)
	}

	path, err := resolvePath(prof.ProfilePath)
	if err != nil {
		log.Fatalf("profile: could not create initial output directory: %v", err)
	}

	prof.ProfilePath = path
	if prof.Quiet {
		log.SetOutput(ioutil.Discard)
	}

	switch {
	case prof.CPUProfile:
		fn := filepath.Join(prof.ProfilePath, "cpu.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
		}

		log.Printf("profile: cpu profiling enabled, %s", fn)
		pprof.StartCPUProfile(f)
		prof.closers = append(prof.closers, func() {
			pprof.StopCPUProfile()
			f.Close()
		})

	case prof.MemProfile:
		fn := filepath.Join(prof.ProfilePath, "mem.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
		}
		old := runtime.MemProfileRate
		runtime.MemProfileRate = prof.memProfileRate

		log.Printf("profile: memory profiling enabled, %s", fn)
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("heap").WriteTo(f, 0)
			f.Close()
			runtime.MemProfileRate = old
		})

	case prof.BlockProfile:
		fn := filepath.Join(prof.ProfilePath, "block.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create block profile %q: %v", fn, err)
		}
		runtime.SetBlockProfileRate(1)

		log.Printf("profile: block profiling enabled, %s", fn)
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("block").WriteTo(f, 0)
			f.Close()
			runtime.SetBlockProfileRate(0)
		})
	}

	if !prof.NoShutdownHook {
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, os.Interrupt)
			<-c

			log.Println("profile: caught interrupt, stopping profiles")
			prof.Stop()

			os.Exit(0)
		}()
	}

	return prof
}
<commit_msg>remove empty lines<commit_after>// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile

import (
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
)

type profile struct {
	// Quiet suppresses informational messages during profiling.
	Quiet bool

	// CPUProfile controls if cpu profiling will be enabled.
	CPUProfile bool

	// MemProfile controls if memory profiling will be enabled.
	MemProfile bool

	// BlockProfile controls if block (contention) profiling will
	// be enabled.
	// It defaults to false.
	BlockProfile bool

	// ProfilePath controls the base path where various profiling
	// files are written. If blank, the base path will be generated
	// by ioutil.TempDir.
	ProfilePath string

	// NoShutdownHook controls whether the profiling package should
	// hook SIGINT to write profiles cleanly.
	NoShutdownHook bool

	// MemProfileRate sent the rate for the memory profile
	memProfileRate int

	closers []func()
}

// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *profile) { p.NoShutdownHook = true }

// Quiet suppresses informational messages during profiling.
func Quiet(p *profile) { p.Quiet = true }

func (p *profile) NoProfiles() {
	p.CPUProfile = false
	p.MemProfile = false
	p.BlockProfile = false
}

// CPUProfile controls if cpu profiling will be enabled. It disables any previous profiling settings.
func CPUProfile(p *profile) {
	p.NoProfiles()
	p.CPUProfile = true
}

// MemProfile controls if memory profiling will be enabled. It disables any previous profiling settings.
func MemProfile(p *profile) {
	p.NoProfiles()
	p.MemProfile = true
}

// BlockProfile controls if block (contention) profiling will be enabled. It disables any previous profiling settings.
func BlockProfile(p *profile) {
	p.NoProfiles()
	p.BlockProfile = true
}

// resolvePath resolves the profile's path or outputs to a temporarry directory
func resolvePath(path string) (resolvedPath string, err error) {
	if path != "" {
		return path, os.MkdirAll(path, 0777)
	}

	return ioutil.TempDir("", "profile")
}

func (p *profile) Stop() {
	for _, c := range p.closers {
		c()
	}
}

func newProfile() *profile {
	prof := &profile{memProfileRate: 4096}
	CPUProfile(prof)
	return prof
}

// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*profile)) interface {
	Stop()
} {
	prof := newProfile()
	for _, option := range options {
		option(prof)
	}

	path, err := resolvePath(prof.ProfilePath)
	if err != nil {
		log.Fatalf("profile: could not create initial output directory: %v", err)
	}

	prof.ProfilePath = path
	if prof.Quiet {
		log.SetOutput(ioutil.Discard)
	}

	switch {
	case prof.CPUProfile:
		fn := filepath.Join(prof.ProfilePath, "cpu.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
		}
		log.Printf("profile: cpu profiling enabled, %s", fn)
		pprof.StartCPUProfile(f)
		prof.closers = append(prof.closers, func() {
			pprof.StopCPUProfile()
			f.Close()
		})

	case prof.MemProfile:
		fn := filepath.Join(prof.ProfilePath, "mem.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
		}
		old := runtime.MemProfileRate
		runtime.MemProfileRate = prof.memProfileRate
		log.Printf("profile: memory profiling enabled, %s", fn)
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("heap").WriteTo(f, 0)
			f.Close()
			runtime.MemProfileRate = old
		})

	case prof.BlockProfile:
		fn := filepath.Join(prof.ProfilePath, "block.pprof")
		f, err := os.Create(fn)
		if err != nil {
			log.Fatalf("profile: could not create block profile %q: %v", fn, err)
		}
		runtime.SetBlockProfileRate(1)
		log.Printf("profile: block profiling enabled, %s", fn)
		prof.closers = append(prof.closers, func() {
			pprof.Lookup("block").WriteTo(f, 0)
			f.Close()
			runtime.SetBlockProfileRate(0)
		})
	}

	if !prof.NoShutdownHook {
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, os.Interrupt)
			<-c

			log.Println("profile: caught interrupt, stopping profiles")
			prof.Stop()

			os.Exit(0)
		}()
	}

	return prof
}
<|endoftext|>


<commit_before>package jira

import (
	"fmt"

	"github.com/google/go-querystring/query"
)

// ProjectService handles projects for the JIRA instance / API.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project
type ProjectService struct {
	client *Client
}

// ProjectList represent a list of Projects
type ProjectList []struct {
	Expand          string          `json:"expand" structs:"expand"`
	Self            string          `json:"self" structs:"self"`
	ID              string          `json:"id" structs:"id"`
	Key             string          `json:"key" structs:"key"`
	Name            string          `json:"name" structs:"name"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls" structs:"avatarUrls"`
	ProjectTypeKey  string          `json:"projectTypeKey" structs:"projectTypeKey"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty" structs:"projectsCategory,omitempty"`
}

// ProjectCategory represents a single project category
type ProjectCategory struct {
	Self        string `json:"self" structs:"self,omitempty"`
	ID          string `json:"id" structs:"id,omitempty"`
	Name        string `json:"name" structs:"name,omitempty"`
	Description string `json:"description" structs:"description,omitempty"`
}

// Project represents a JIRA Project.
type Project struct {
	Expand       string             `json:"expand,omitempty" structs:"expand,omitempty"`
	Self         string             `json:"self,omitempty" structs:"self,omitempty"`
	ID           string             `json:"id,omitempty" structs:"id,omitempty"`
	Key          string             `json:"key,omitempty" structs:"key,omitempty"`
	Description  string             `json:"description,omitempty" structs:"description,omitempty"`
	Lead         User               `json:"lead,omitempty" structs:"lead,omitempty"`
	Components   []ProjectComponent `json:"components,omitempty" structs:"components,omitempty"`
	IssueTypes   []IssueType        `json:"issueTypes,omitempty" structs:"issueTypes,omitempty"`
	URL          string             `json:"url,omitempty" structs:"url,omitempty"`
	Email        string             `json:"email,omitempty" structs:"email,omitempty"`
	AssigneeType string             `json:"assigneeType,omitempty" structs:"assigneeType,omitempty"`
	Versions     []Version          `json:"versions,omitempty" structs:"versions,omitempty"`
	Name         string             `json:"name,omitempty" structs:"name,omitempty"`
	Roles        struct {
		Developers string `json:"Developers,omitempty" structs:"Developers,omitempty"`
	} `json:"roles,omitempty" structs:"roles,omitempty"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls,omitempty" structs:"avatarUrls,omitempty"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty" structs:"projectCategory,omitempty"`
}

// ProjectComponent represents a single component of a project
type ProjectComponent struct {
	Self                string `json:"self" structs:"self,omitempty"`
	ID                  string `json:"id" structs:"id,omitempty"`
	Name                string `json:"name" structs:"name,omitempty"`
	Description         string `json:"description" structs:"description,omitempty"`
	Lead                User   `json:"lead,omitempty" structs:"lead,omitempty"`
	AssigneeType        string `json:"assigneeType" structs:"assigneeType,omitempty"`
	Assignee            User   `json:"assignee" structs:"assignee,omitempty"`
	RealAssigneeType    string `json:"realAssigneeType" structs:"realAssigneeType,omitempty"`
	RealAssignee        User   `json:"realAssignee" structs:"realAssignee,omitempty"`
	IsAssigneeTypeValid bool   `json:"isAssigneeTypeValid" structs:"isAssigneeTypeValid,omitempty"`
	Project             string `json:"project" structs:"project,omitempty"`
	ProjectID           int    `json:"projectId" structs:"projectId,omitempty"`
}

// GetList gets all projects form JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
	return s.ListWithOptions(&GetQueryOptions{})
}

// GetList gets all projects form JIRA with optional query params, like &GetQueryOptions{Expand: "issueTypes"} to get
// a list of all projects and their supported issuetypes
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) ListWithOptions(options *GetQueryOptions) (*ProjectList, *Response, error) {
	apiEndpoint := "rest/api/2/project"
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	if options != nil {
		q, err := query.Values(options)
		if err != nil {
			return nil, nil, err
		}
		req.URL.RawQuery = q.Encode()
	}

	projectList := new(ProjectList)
	resp, err := s.client.Do(req, projectList)
	if err != nil {
		jerr := NewJiraError(resp, err)
		return nil, resp, jerr
	}

	return projectList, resp, nil
}

// Get returns a full representation of the project for the given issue key.
// JIRA will attempt to identify the project by the projectIdOrKey path parameter.
// This can be an project id, or an project key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
	apiEndpoint := fmt.Sprintf("rest/api/2/project/%s", projectID)
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	project := new(Project)
	resp, err := s.client.Do(req, project)
	if err != nil {
		jerr := NewJiraError(resp, err)
		return nil, resp, jerr
	}

	return project, resp, nil
}
<commit_msg>add IssueTypes field to ProjectList<commit_after>package jira

import (
	"fmt"

	"github.com/google/go-querystring/query"
)

// ProjectService handles projects for the JIRA instance / API.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project
type ProjectService struct {
	client *Client
}

// ProjectList represent a list of Projects
type ProjectList []struct {
	Expand          string          `json:"expand" structs:"expand"`
	Self            string          `json:"self" structs:"self"`
	ID              string          `json:"id" structs:"id"`
	Key             string          `json:"key" structs:"key"`
	Name            string          `json:"name" structs:"name"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls" structs:"avatarUrls"`
	ProjectTypeKey  string          `json:"projectTypeKey" structs:"projectTypeKey"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty" structs:"projectsCategory,omitempty"`
	IssueTypes      []IssueType     `json:"issueTypes,omitempty" structs:"issueTypes,omitempty"`
}

// ProjectCategory represents a single project category
type ProjectCategory struct {
	Self        string `json:"self" structs:"self,omitempty"`
	ID          string `json:"id" structs:"id,omitempty"`
	Name        string `json:"name" structs:"name,omitempty"`
	Description string `json:"description" structs:"description,omitempty"`
}

// Project represents a JIRA Project.
type Project struct {
	Expand       string             `json:"expand,omitempty" structs:"expand,omitempty"`
	Self         string             `json:"self,omitempty" structs:"self,omitempty"`
	ID           string             `json:"id,omitempty" structs:"id,omitempty"`
	Key          string             `json:"key,omitempty" structs:"key,omitempty"`
	Description  string             `json:"description,omitempty" structs:"description,omitempty"`
	Lead         User               `json:"lead,omitempty" structs:"lead,omitempty"`
	Components   []ProjectComponent `json:"components,omitempty" structs:"components,omitempty"`
	IssueTypes   []IssueType        `json:"issueTypes,omitempty" structs:"issueTypes,omitempty"`
	URL          string             `json:"url,omitempty" structs:"url,omitempty"`
	Email        string             `json:"email,omitempty" structs:"email,omitempty"`
	AssigneeType string             `json:"assigneeType,omitempty" structs:"assigneeType,omitempty"`
	Versions     []Version          `json:"versions,omitempty" structs:"versions,omitempty"`
	Name         string             `json:"name,omitempty" structs:"name,omitempty"`
	Roles        struct {
		Developers string `json:"Developers,omitempty" structs:"Developers,omitempty"`
	} `json:"roles,omitempty" structs:"roles,omitempty"`
	AvatarUrls      AvatarUrls      `json:"avatarUrls,omitempty" structs:"avatarUrls,omitempty"`
	ProjectCategory ProjectCategory `json:"projectCategory,omitempty" structs:"projectCategory,omitempty"`
}

// ProjectComponent represents a single component of a project
type ProjectComponent struct {
	Self                string `json:"self" structs:"self,omitempty"`
	ID                  string `json:"id" structs:"id,omitempty"`
	Name                string `json:"name" structs:"name,omitempty"`
	Description         string `json:"description" structs:"description,omitempty"`
	Lead                User   `json:"lead,omitempty" structs:"lead,omitempty"`
	AssigneeType        string `json:"assigneeType" structs:"assigneeType,omitempty"`
	Assignee            User   `json:"assignee" structs:"assignee,omitempty"`
	RealAssigneeType    string `json:"realAssigneeType" structs:"realAssigneeType,omitempty"`
	RealAssignee        User   `json:"realAssignee" structs:"realAssignee,omitempty"`
	IsAssigneeTypeValid bool   `json:"isAssigneeTypeValid" structs:"isAssigneeTypeValid,omitempty"`
	Project             string `json:"project" structs:"project,omitempty"`
	ProjectID           int    `json:"projectId" structs:"projectId,omitempty"`
}

// GetList gets all projects form JIRA
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) GetList() (*ProjectList, *Response, error) {
	return s.ListWithOptions(&GetQueryOptions{})
}

// GetList gets all projects form JIRA with optional query params, like &GetQueryOptions{Expand: "issueTypes"} to get
// a list of all projects and their supported issuetypes
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getAllProjects
func (s *ProjectService) ListWithOptions(options *GetQueryOptions) (*ProjectList, *Response, error) {
	apiEndpoint := "rest/api/2/project"
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	if options != nil {
		q, err := query.Values(options)
		if err != nil {
			return nil, nil, err
		}
		req.URL.RawQuery = q.Encode()
	}

	projectList := new(ProjectList)
	resp, err := s.client.Do(req, projectList)
	if err != nil {
		jerr := NewJiraError(resp, err)
		return nil, resp, jerr
	}

	return projectList, resp, nil
}

// Get returns a full representation of the project for the given issue key.
// JIRA will attempt to identify the project by the projectIdOrKey path parameter.
// This can be an project id, or an project key.
//
// JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/project-getProject
func (s *ProjectService) Get(projectID string) (*Project, *Response, error) {
	apiEndpoint := fmt.Sprintf("rest/api/2/project/%s", projectID)
	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	project := new(Project)
	resp, err := s.client.Do(req, project)
	if err != nil {
		jerr := NewJiraError(resp, err)
		return nil, resp, jerr
	}

	return project, resp, nil
}
<|endoftext|>


<commit_before>package twitch

import (
	"testing"
)

func assertStringsEqual(t *testing.T, expected, actual string) {
	if expected != actual {
		t.Errorf("failed asserting that \"%s\" is expected \"%s\"", actual, expected)
	}
}

func assertIntsEqual(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Errorf("failed asserting that \"%d\" is expected \"%d\"", actual, expected)
	}
}

func assertInt32sEqual(t *testing.T, expected, actual int32) {
	if expected != actual {
		t.Errorf("failed asserting that \"%d\" is expected \"%d\"", actual, expected)
	}
}

func assertTrue(t *testing.T, actual bool, errorMessage string) {
	if !actual {
		t.Error(errorMessage)
	}
}

func assertFalse(t *testing.T, actual bool, errorMessage string) {
	if actual {
		t.Error(errorMessage)
	}
}

func assertStringSlicesEqual(t *testing.T, expected, actual []string) {
	if actual == nil {
		t.Errorf("actual slice was nil")
	}

	if len(actual) != len(expected) {
		t.Errorf("actual slice was not the same length as expected slice")
	}

	for i, v := range actual {
		if v != expected[i] {
			t.Errorf("actual slice value \"%s\" was not equal to expected value \"%s\" at index \"%d\"", v, expected[i], i)
		}
	}
}

func assertStringMapsEqual(t *testing.T, expected, actual map[string]string) {
	if actual == nil {
		t.Errorf("actual map was nil")
	}

	if len(expected) != len(actual) {
		t.Errorf("actual map was not the same length as the expected map")
	}

	for key, want := range expected {
		got, ok := actual[key]
		if !ok {
			t.Errorf("actual map doesn't contain key \"%s\"", key)
			continue
		}

		if want != got {
			t.Errorf("actual map value \"%s\" was not equal to expected value \"%s\" in key \"%s\"", got, want, key)
			continue
		}
	}
}

func assertStringIntMapsEqual(t *testing.T, expected, actual map[string]int) {
	if actual == nil {
		t.Errorf("actual map was nil")
	}

	if len(expected) != len(actual) {
		t.Errorf("actual map was not the same length as the expected map")
	}

	for k, v := range expected {
		got, ok := actual[k]
		if !ok {
			t.Errorf("actual map doesn't contain key \"%s\"", k)
			continue
		}

		if v != got {
			t.Errorf("actual map value \"%d\" was not equal to expected value \"%d\" in key \"%s\"", got, v, k)
			continue
		}
	}
}

func assertErrorsEqual(t *testing.T, expected, actual error) {
	if expected != actual {
		t.Errorf("failed asserting that error \"%s\" is expected \"%s\"", actual, expected)
	}
}

// formats a ping-signature (i.e. go-twitch-irc) into a full-fledged pong response (i.e. ":tmi.twitch.tv PONG tmi.twitch.tv :go-twitch-irc")
func formatPong(signature string) string {
	return ":tmi.twitch.tv PONG tmi.twitch.tv :" + signature
}
<commit_msg>Update StringSlices and StringMaps<commit_after>package twitch

import (
	"testing"
)

func assertStringsEqual(t *testing.T, expected, actual string) {
	if expected != actual {
		t.Errorf("failed asserting that \"%s\" is expected \"%s\"", actual, expected)
	}
}

func assertIntsEqual(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Errorf("failed asserting that \"%d\" is expected \"%d\"", actual, expected)
	}
}

func assertInt32sEqual(t *testing.T, expected, actual int32) {
	if expected != actual {
		t.Errorf("failed asserting that \"%d\" is expected \"%d\"", actual, expected)
	}
}

func assertTrue(t *testing.T, actual bool, errorMessage string) {
	if !actual {
		t.Error(errorMessage)
	}
}

func assertFalse(t *testing.T, actual bool, errorMessage string) {
	if actual {
		t.Error(errorMessage)
	}
}

func assertStringSlicesEqual(t *testing.T, expected, actual []string) {
	if actual == nil {
		if expected == nil {
			return
		}

		t.Errorf("actual slice was nil")
	}

	if len(actual) != len(expected) {
		t.Errorf("actual slice was not the same length as expected slice")
	}

	for i, v := range actual {
		if v != expected[i] {
			t.Errorf("actual slice value \"%s\" was not equal to expected value \"%s\" at index \"%d\"", v, expected[i], i)
		}
	}
}

func assertStringMapsEqual(t *testing.T, expected, actual map[string]string) {
	if actual == nil {
		if expected == nil {
			return
		}

		t.Errorf("actual map was nil")
	}

	if len(expected) != len(actual) {
		t.Errorf("actual map was not the same length as the expected map")
	}

	for key, want := range expected {
		got, ok := actual[key]
		if !ok {
			t.Errorf("actual map doesn't contain key \"%s\"", key)
			continue
		}

		if want != got {
			t.Errorf("actual map value \"%s\" was not equal to expected value \"%s\" in key \"%s\"", got, want, key)
			continue
		}
	}
}

func assertStringIntMapsEqual(t *testing.T, expected, actual map[string]int) {
	if actual == nil {
		t.Errorf("actual map was nil")
	}

	if len(expected) != len(actual) {
		t.Errorf("actual map was not the same length as the expected map")
	}

	for k, v := range expected {
		got, ok := actual[k]
		if !ok {
			t.Errorf("actual map doesn't contain key \"%s\"", k)
			continue
		}

		if v != got {
			t.Errorf("actual map value \"%d\" was not equal to expected value \"%d\" in key \"%s\"", got, v, k)
			continue
		}
	}
}

func assertErrorsEqual(t *testing.T, expected, actual error) {
	if expected != actual {
		t.Errorf("failed asserting that error \"%s\" is expected \"%s\"", actual, expected)
	}
}

// formats a ping-signature (i.e. go-twitch-irc) into a full-fledged pong response (i.e. ":tmi.twitch.tv PONG tmi.twitch.tv :go-twitch-irc")
func formatPong(signature string) string {
	return ":tmi.twitch.tv PONG tmi.twitch.tv :" + signature
}
<|endoftext|>


<commit_before>package heroku

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type Build struct {
	Id         string      `json:"id"`
	SourceBlob *SourceBlob `json:"source_blob"`
	Status     string      `json:"status"`
}

type SourceBlob struct {
	Checksum string `json:"checksum,omitempty"`
	Url      string `json:"url"`
	Version  string `json:"url"`
}

func (c *Client) BuildCreate(appId string, sourceBlob *SourceBlob) (*Build, *http.Response, error) {
	body, err := json.Marshal(map[string]interface{}{
		"source_blob": sourceBlob,
	})
	if err != nil {
		return nil, nil, err
	}

	url := c.BaseUrl() + fmt.Sprintf("/apps/%v/builds", appId)
	resp, err := c.MakeRequest("POST", url, &body)
	if err != nil {
		return nil, resp, err
	}

	var build Build
	err = c.readResponseInto(resp, &build)
	if err != nil {
		return nil, resp, err
	}

	return &build, resp, nil
}

func (c *Client) BuildInfo(appId string, id string) (*Build, *http.Response, error) {
	url := c.BaseUrl() + fmt.Sprintf("/apps/%v/builds/%v", appId, id)
	resp, err := c.MakeRequest("GET", url, nil)
	if err != nil {
		return nil, resp, err
	}

	var build Build
	err = c.readResponseInto(resp, &build)
	if err != nil {
		return nil, resp, err
	}

	return &build, resp, nil
}

func (c *Client) readResponse(resp *http.Response) ([]byte, error) {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 && c.Debug {
		fmt.Printf("[Heroku] Error: code=%v %v", resp.StatusCode, string(body))
	}

	return body, nil
}

func (c *Client) readResponseInto(resp *http.Response, val interface{}) error {
	body, err := c.readResponse(resp)
	if err != nil {
		return err
	}

	err = json.Unmarshal(body, val)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Log body of build creation Heroku request<commit_after>package heroku

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type Build struct {
	Id         string      `json:"id"`
	SourceBlob *SourceBlob `json:"source_blob"`
	Status     string      `json:"status"`
}

type SourceBlob struct {
	Checksum string `json:"checksum,omitempty"`
	Url      string `json:"url"`
	Version  string `json:"url"`
}

func (c *Client) BuildCreate(appId string, sourceBlob *SourceBlob) (*Build, *http.Response, error) {
	body, err := json.Marshal(map[string]interface{}{
		"source_blob": sourceBlob,
	})
	fmt.Printf("BuildCreate body: %v\n", string(body))
	if err != nil {
		return nil, nil, err
	}

	url := c.BaseUrl() + fmt.Sprintf("/apps/%v/builds", appId)
	resp, err := c.MakeRequest("POST", url, &body)
	if err != nil {
		return nil, resp, err
	}

	var build Build
	err = c.readResponseInto(resp, &build)
	if err != nil {
		return nil, resp, err
	}

	return &build, resp, nil
}

func (c *Client) BuildInfo(appId string, id string) (*Build, *http.Response, error) {
	url := c.BaseUrl() + fmt.Sprintf("/apps/%v/builds/%v", appId, id)
	resp, err := c.MakeRequest("GET", url, nil)
	if err != nil {
		return nil, resp, err
	}

	var build Build
	err = c.readResponseInto(resp, &build)
	if err != nil {
		return nil, resp, err
	}

	return &build, resp, nil
}

func (c *Client) readResponse(resp *http.Response) ([]byte, error) {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 && c.Debug {
		fmt.Printf("[Heroku] Error: code=%v %v", resp.StatusCode, string(body))
	}

	return body, nil
}

func (c *Client) readResponseInto(resp *http.Response, val interface{}) error {
	body, err := c.readResponse(resp)
	if err != nil {
		return err
	}

	err = json.Unmarshal(body, val)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

/*
	The rpc package provides access to the public methods of an object across a
	network or other I/O connection.  A server registers an object, making it visible
	as a service with the name of the type of the object.  After registration, public
	methods of the object will be accessible remotely.  A server may register multiple
	objects (services) of different types but it is an error to register multiple
	objects of the same type.

	Only methods that satisfy these criteria will be made available for remote access;
	other methods will be ignored:

		- the method name is publicly visible, that is, begins with an upper case letter.
		- the method has two arguments, both pointers to publicly visible structs.
		- the method has return type os.Error.

	The method's first argument represents the arguments provided by the caller; the
	second argument represents the result parameters to be returned to the caller.
	The method's return value, if non-nil, is passed back as a string that the client
	sees as an os.ErrorString.

	The server may handle requests on a single connection by calling ServeConn.  More
	typically it will create a network listener and call Accept or, for an HTTP
	listener, HandleHTTP and http.Serve.

	A client wishing to use the service establishes a connection and then invokes
	NewClient on the connection.  The convenience function Dial (DialHTTP) performs
	both steps for a raw network connection (an HTTP connection).  The resulting
	Client object has two methods, Call and Go, that specify the service and method to
	call, a structure containing the arguments, and a structure to receive the result
	parameters.

	Call waits for the remote call to complete; Go launches the call asynchronously
	and returns a channel that will signal completion.

	Package "gob" is used to transport the data.

	Here is a simple example.  A server wishes to export an object of type Arith:

		package server

		type Args struct {
			A, B int
		}

		type Reply struct {
			C int
		}

		type Arith int

		func (t *Arith) Multiply(args *Args, reply *Reply) os.Error {
			reply.C = args.A * args.B;
			return nil
		}

		func (t *Arith) Divide(args *Args, reply *Reply) os.Error {
			if args.B == 0 {
				return os.ErrorString("divide by zero");
			}
			reply.C = args.A / args.B;
			return nil
		}

	The server calls (for HTTP service):

		arith := new(Arith);
		rpc.Register(arith);
		rpc.HandleHTTP();
		l, e := net.Listen("tcp", ":1234");
		if e != nil {
			log.Exit("listen error:", e);
		}
		go http.Serve(l, nil);

	At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
	"Arith.Divide".  To invoke one, a client first dials the server:

		client, err := rpc.DialHTTP("tcp", serverAddress + ":1234");
		if err != nil {
			log.Exit("dialing:", err);
		}

	Then it can make a remote call:

		// Synchronous call
		args := &server.Args{7,8};
		reply := new(server.Reply);
		err = client.Call("Arith.Multiply", args, reply);
		if err != nil {
			log.Exit("arith error:", err);
		}
		fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply.C);

	or

		// Asynchronous call
		divCall := client.Go("Arith.Divide", args, reply, nil);
		replyCall := <-divCall.Done;	// will be equal to divCall
		// check errors, print, etc.

	A server implementation will often provide a simple, type-safe wrapper for the
	client.
*/
package rpc

import (
	"gob"
	"http"
	"log"
	"io"
	"net"
	"os"
	"reflect"
	"strings"
	"sync"
	"unicode"
	"utf8"
)

// Precompute the reflect type for os.Error.  Can't use os.Error directly
// because Typeof takes an empty interface value.  This is annoying.
var unusedError *os.Error
var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem()

type methodType struct {
	sync.Mutex // protects counters
	method     reflect.Method
	argType    *reflect.PtrType
	replyType  *reflect.PtrType
	numCalls   uint
}

type service struct {
	name   string                 // name of service
	rcvr   reflect.Value          // receiver of methods for the service
	typ    reflect.Type           // type of the receiver
	method map[string]*methodType // registered methods
}

// Request is a header written before every RPC call.  It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
type Request struct {
	ServiceMethod string // format: "Service.Method"
	Seq           uint64 // sequence number chosen by client
}

// Response is a header written before every RPC return.  It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
type Response struct {
	ServiceMethod string // echoes that of the Request
	Seq           uint64 // echoes that of the request
	Error         string // error, if any.
}

type serverType struct {
	sync.Mutex // protects the serviceMap
	serviceMap map[string]*service
}

// This variable is a global whose "public" methods are really private methods
// called from the global functions of this package: rpc.Register, rpc.ServeConn, etc.
// For example, rpc.Register() calls server.add().
var server = &serverType{serviceMap: make(map[string]*service)}

// Is this a publicly visible - upper case - name?
func isPublic(name string) bool {
	rune, _ := utf8.DecodeRuneInString(name)
	return unicode.IsUpper(rune)
}

func (server *serverType) register(rcvr interface{}) os.Error {
	server.Lock()
	defer server.Unlock()
	if server.serviceMap == nil {
		server.serviceMap = make(map[string]*service)
	}
	s := new(service)
	s.typ = reflect.Typeof(rcvr)
	s.rcvr = reflect.NewValue(rcvr)
	sname := reflect.Indirect(s.rcvr).Type().Name()
	if sname == "" {
		log.Exit("rpc: no service name for type", s.typ.String())
	}
	if !isPublic(sname) {
		s := "rpc Register: type " + sname + " is not public"
		log.Stderr(s)
		return os.ErrorString(s)
	}
	if _, present := server.serviceMap[sname]; present {
		return os.ErrorString("rpc: service already defined: " + sname)
	}
	s.name = sname
	s.method = make(map[string]*methodType)

	// Install the methods
	for m := 0; m < s.typ.NumMethod(); m++ {
		method := s.typ.Method(m)
		mtype := method.Type
		mname := method.Name
		if !isPublic(mname) {
			continue
		}
		// Method needs three ins: receiver, *args, *reply.
		// The args and reply must be structs until gobs are more general.
		if mtype.NumIn() != 3 {
			log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn())
			continue
		}
		argType, ok := mtype.In(1).(*reflect.PtrType)
		if !ok {
			log.Stderr(mname, "arg type not a pointer:", mtype.In(1))
			continue
		}
		if _, ok := argType.Elem().(*reflect.StructType); !ok {
			log.Stderr(mname, "arg type not a pointer to a struct:", argType)
			continue
		}
		replyType, ok := mtype.In(2).(*reflect.PtrType)
		if !ok {
			log.Stderr(mname, "reply type not a pointer:", mtype.In(2))
			continue
		}
		if _, ok := replyType.Elem().(*reflect.StructType); !ok {
			log.Stderr(mname, "reply type not a pointer to a struct:", replyType)
			continue
		}
		if !isPublic(argType.Elem().Name()) {
			log.Stderr(mname, "argument type not public:", argType)
			continue
		}
		if !isPublic(replyType.Elem().Name()) {
			log.Stderr(mname, "reply type not public:", replyType)
			continue
		}
		// Method needs one out: os.Error.
		if mtype.NumOut() != 1 {
			log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut())
			continue
		}
		if returnType := mtype.Out(0); returnType != typeOfOsError {
			log.Stderr("method", mname, "returns", returnType.String(), "not os.Error")
			continue
		}
		s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType}
	}

	if len(s.method) == 0 {
		s := "rpc Register: type " + sname + " has no public methods of suitable type"
		log.Stderr(s)
		return os.ErrorString(s)
	}
	server.serviceMap[s.name] = s
	return nil
}

// A value sent as a placeholder for the response when the server receives an invalid request.
type InvalidRequest struct {
	marker int
}

var invalidRequest = InvalidRequest{1}

func _new(t *reflect.PtrType) *reflect.PtrValue {
	v := reflect.MakeZero(t).(*reflect.PtrValue)
	v.PointTo(reflect.MakeZero(t.Elem()))
	return v
}

func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, enc *gob.Encoder, errmsg string) {
	resp := new(Response)
	// Encode the response header
	resp.ServiceMethod = req.ServiceMethod
	if errmsg != "" {
		resp.Error = errmsg
	}
	resp.Seq = req.Seq
	sending.Lock()
	enc.Encode(resp)
	// Encode the reply value.
	enc.Encode(reply)
	sending.Unlock()
}

func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, enc *gob.Encoder) {
	mtype.Lock()
	mtype.numCalls++
	mtype.Unlock()
	function := mtype.method.Func
	// Invoke the method, providing a new value for the reply.
	returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
	// The return value for the method is an os.Error.
	errInter := returnValues[0].Interface()
	errmsg := ""
	if errInter != nil {
		errmsg = errInter.(os.Error).String()
	}
	sendResponse(sending, req, replyv.Interface(), enc, errmsg)
}

func (server *serverType) input(conn io.ReadWriteCloser) {
	dec := gob.NewDecoder(conn)
	enc := gob.NewEncoder(conn)
	sending := new(sync.Mutex)
	for {
		// Grab the request header.
		req := new(Request)
		err := dec.Decode(req)
		if err != nil {
			if err == os.EOF || err == io.ErrUnexpectedEOF {
				log.Stderr("rpc: ", err)
				break
			}
			s := "rpc: server cannot decode request: " + err.String()
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		serviceMethod := strings.Split(req.ServiceMethod, ".", 0)
		if len(serviceMethod) != 2 {
			s := "rpc: service/method request ill:formed: " + req.ServiceMethod
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		// Look up the request.
		server.Lock()
		service, ok := server.serviceMap[serviceMethod[0]]
		server.Unlock()
		if !ok {
			s := "rpc: can't find service " + req.ServiceMethod
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		mtype, ok := service.method[serviceMethod[1]]
		if !ok {
			s := "rpc: can't find method " + req.ServiceMethod
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		// Decode the argument value.
		argv := _new(mtype.argType)
		replyv := _new(mtype.replyType)
		err = dec.Decode(argv.Interface())
		if err != nil {
			log.Stderr("rpc: tearing down", serviceMethod[0], "connection:", err)
			sendResponse(sending, req, replyv.Interface(), enc, err.String())
			continue
		}
		go service.call(sending, mtype, req, argv, replyv, enc)
	}
	conn.Close()
}

func (server *serverType) accept(lis net.Listener) {
	for {
		conn, err := lis.Accept()
		if err != nil {
			log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
		}
		go server.input(conn)
	}
}

// Register publishes in the server the set of methods of the
// receiver value that satisfy the following conditions:
//	- public method
//	- two arguments, both pointers to public structs
//	- one return value of type os.Error
// It returns an error if the receiver is not public or has no
// suitable methods.
func Register(rcvr interface{}) os.Error { return server.register(rcvr) }

// ServeConn runs the server on a single connection.  When the connection
// completes, service terminates.  ServeConn blocks; the caller typically
// invokes it in a go statement.
func ServeConn(conn io.ReadWriteCloser) { go server.input(conn) }

// Accept accepts connections on the listener and serves requests
// for each incoming connection.  Accept blocks; the caller typically
// invokes it in a go statement.
func Accept(lis net.Listener) { server.accept(lis) }

// Can connect to RPC service using HTTP CONNECT to rpcPath.
var rpcPath string = "/_goRPC_"
var debugPath string = "/debug/rpc"
var connected = "200 Connected to Go RPC"

func serveHTTP(c *http.Conn, req *http.Request) {
	if req.Method != "CONNECT" {
		c.SetHeader("Content-Type", "text/plain; charset=utf-8")
		c.WriteHeader(http.StatusMethodNotAllowed)
		io.WriteString(c, "405 must CONNECT to "+rpcPath+"\n")
		return
	}
	conn, _, err := c.Hijack()
	if err != nil {
		log.Stderr("rpc hijacking ", c.RemoteAddr, ": ", err.String())
		return
	}
	io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
	server.input(conn)
}

// HandleHTTP registers an HTTP handler for RPC messages.
// It is still necessary to invoke http.Serve(), typically in a go statement.
func HandleHTTP() {
	http.Handle(rpcPath, http.HandlerFunc(serveHTTP))
	http.Handle(debugPath, http.HandlerFunc(debugHTTP))
}
<commit_msg>rpc documentation cleanup: remove ;'s from code in documentation<commit_after>// Copyright 2009 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.

/*
	The rpc package provides access to the public methods of an object across a
	network or other I/O connection.  A server registers an object, making it visible
	as a service with the name of the type of the object.  After registration, public
	methods of the object will be accessible remotely.  A server may register multiple
	objects (services) of different types but it is an error to register multiple
	objects of the same type.

	Only methods that satisfy these criteria will be made available for remote access;
	other methods will be ignored:

		- the method name is publicly visible, that is, begins with an upper case letter.
		- the method has two arguments, both pointers to publicly visible structs.
		- the method has return type os.Error.

	The method's first argument represents the arguments provided by the caller; the
	second argument represents the result parameters to be returned to the caller.
	The method's return value, if non-nil, is passed back as a string that the client
	sees as an os.ErrorString.

	The server may handle requests on a single connection by calling ServeConn.  More
	typically it will create a network listener and call Accept or, for an HTTP
	listener, HandleHTTP and http.Serve.

	A client wishing to use the service establishes a connection and then invokes
	NewClient on the connection.  The convenience function Dial (DialHTTP) performs
	both steps for a raw network connection (an HTTP connection).  The resulting
	Client object has two methods, Call and Go, that specify the service and method to
	call, a structure containing the arguments, and a structure to receive the result
	parameters.

	Call waits for the remote call to complete; Go launches the call asynchronously
	and returns a channel that will signal completion.

	Package "gob" is used to transport the data.

	Here is a simple example.  A server wishes to export an object of type Arith:

		package server

		type Args struct {
			A, B int
		}

		type Reply struct {
			C int
		}

		type Arith int

		func (t *Arith) Multiply(args *Args, reply *Reply) os.Error {
			reply.C = args.A * args.B
			return nil
		}

		func (t *Arith) Divide(args *Args, reply *Reply) os.Error {
			if args.B == 0 {
				return os.ErrorString("divide by zero")
			}
			reply.C = args.A / args.B
			return nil
		}

	The server calls (for HTTP service):

		arith := new(Arith)
		rpc.Register(arith)
		rpc.HandleHTTP()
		l, e := net.Listen("tcp", ":1234")
		if e != nil {
			log.Exit("listen error:", e)
		}
		go http.Serve(l, nil)

	At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
	"Arith.Divide".  To invoke one, a client first dials the server:

		client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
		if err != nil {
			log.Exit("dialing:", err)
		}

	Then it can make a remote call:

		// Synchronous call
		args := &server.Args{7,8}
		reply := new(server.Reply)
		err = client.Call("Arith.Multiply", args, reply)
		if err != nil {
			log.Exit("arith error:", err)
		}
		fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply.C)

	or

		// Asynchronous call
		divCall := client.Go("Arith.Divide", args, reply, nil)
		replyCall := <-divCall.Done	// will be equal to divCall
		// check errors, print, etc.

	A server implementation will often provide a simple, type-safe wrapper for the
	client.
*/
package rpc

import (
	"gob"
	"http"
	"log"
	"io"
	"net"
	"os"
	"reflect"
	"strings"
	"sync"
	"unicode"
	"utf8"
)

// Precompute the reflect type for os.Error.  Can't use os.Error directly
// because Typeof takes an empty interface value.  This is annoying.
var unusedError *os.Error
var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem()

type methodType struct {
	sync.Mutex // protects counters
	method     reflect.Method
	argType    *reflect.PtrType
	replyType  *reflect.PtrType
	numCalls   uint
}

type service struct {
	name   string                 // name of service
	rcvr   reflect.Value          // receiver of methods for the service
	typ    reflect.Type           // type of the receiver
	method map[string]*methodType // registered methods
}

// Request is a header written before every RPC call.  It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
type Request struct {
	ServiceMethod string // format: "Service.Method"
	Seq           uint64 // sequence number chosen by client
}

// Response is a header written before every RPC return.  It is used internally
// but documented here as an aid to debugging, such as when analyzing
// network traffic.
type Response struct {
	ServiceMethod string // echoes that of the Request
	Seq           uint64 // echoes that of the request
	Error         string // error, if any.
}

type serverType struct {
	sync.Mutex // protects the serviceMap
	serviceMap map[string]*service
}

// This variable is a global whose "public" methods are really private methods
// called from the global functions of this package: rpc.Register, rpc.ServeConn, etc.
// For example, rpc.Register() calls server.add().
var server = &serverType{serviceMap: make(map[string]*service)}

// Is this a publicly visible - upper case - name?
func isPublic(name string) bool {
	rune, _ := utf8.DecodeRuneInString(name)
	return unicode.IsUpper(rune)
}

func (server *serverType) register(rcvr interface{}) os.Error {
	server.Lock()
	defer server.Unlock()
	if server.serviceMap == nil {
		server.serviceMap = make(map[string]*service)
	}
	s := new(service)
	s.typ = reflect.Typeof(rcvr)
	s.rcvr = reflect.NewValue(rcvr)
	sname := reflect.Indirect(s.rcvr).Type().Name()
	if sname == "" {
		log.Exit("rpc: no service name for type", s.typ.String())
	}
	if !isPublic(sname) {
		s := "rpc Register: type " + sname + " is not public"
		log.Stderr(s)
		return os.ErrorString(s)
	}
	if _, present := server.serviceMap[sname]; present {
		return os.ErrorString("rpc: service already defined: " + sname)
	}
	s.name = sname
	s.method = make(map[string]*methodType)

	// Install the methods
	for m := 0; m < s.typ.NumMethod(); m++ {
		method := s.typ.Method(m)
		mtype := method.Type
		mname := method.Name
		if !isPublic(mname) {
			continue
		}
		// Method needs three ins: receiver, *args, *reply.
		// The args and reply must be structs until gobs are more general.
		if mtype.NumIn() != 3 {
			log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn())
			continue
		}
		argType, ok := mtype.In(1).(*reflect.PtrType)
		if !ok {
			log.Stderr(mname, "arg type not a pointer:", mtype.In(1))
			continue
		}
		if _, ok := argType.Elem().(*reflect.StructType); !ok {
			log.Stderr(mname, "arg type not a pointer to a struct:", argType)
			continue
		}
		replyType, ok := mtype.In(2).(*reflect.PtrType)
		if !ok {
			log.Stderr(mname, "reply type not a pointer:", mtype.In(2))
			continue
		}
		if _, ok := replyType.Elem().(*reflect.StructType); !ok {
			log.Stderr(mname, "reply type not a pointer to a struct:", replyType)
			continue
		}
		if !isPublic(argType.Elem().Name()) {
			log.Stderr(mname, "argument type not public:", argType)
			continue
		}
		if !isPublic(replyType.Elem().Name()) {
			log.Stderr(mname, "reply type not public:", replyType)
			continue
		}
		// Method needs one out: os.Error.
		if mtype.NumOut() != 1 {
			log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut())
			continue
		}
		if returnType := mtype.Out(0); returnType != typeOfOsError {
			log.Stderr("method", mname, "returns", returnType.String(), "not os.Error")
			continue
		}
		s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType}
	}

	if len(s.method) == 0 {
		s := "rpc Register: type " + sname + " has no public methods of suitable type"
		log.Stderr(s)
		return os.ErrorString(s)
	}
	server.serviceMap[s.name] = s
	return nil
}

// A value sent as a placeholder for the response when the server receives an invalid request.
type InvalidRequest struct {
	marker int
}

var invalidRequest = InvalidRequest{1}

func _new(t *reflect.PtrType) *reflect.PtrValue {
	v := reflect.MakeZero(t).(*reflect.PtrValue)
	v.PointTo(reflect.MakeZero(t.Elem()))
	return v
}

func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, enc *gob.Encoder, errmsg string) {
	resp := new(Response)
	// Encode the response header
	resp.ServiceMethod = req.ServiceMethod
	if errmsg != "" {
		resp.Error = errmsg
	}
	resp.Seq = req.Seq
	sending.Lock()
	enc.Encode(resp)
	// Encode the reply value.
	enc.Encode(reply)
	sending.Unlock()
}

func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, enc *gob.Encoder) {
	mtype.Lock()
	mtype.numCalls++
	mtype.Unlock()
	function := mtype.method.Func
	// Invoke the method, providing a new value for the reply.
	returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
	// The return value for the method is an os.Error.
	errInter := returnValues[0].Interface()
	errmsg := ""
	if errInter != nil {
		errmsg = errInter.(os.Error).String()
	}
	sendResponse(sending, req, replyv.Interface(), enc, errmsg)
}

func (server *serverType) input(conn io.ReadWriteCloser) {
	dec := gob.NewDecoder(conn)
	enc := gob.NewEncoder(conn)
	sending := new(sync.Mutex)
	for {
		// Grab the request header.
		req := new(Request)
		err := dec.Decode(req)
		if err != nil {
			if err == os.EOF || err == io.ErrUnexpectedEOF {
				log.Stderr("rpc: ", err)
				break
			}
			s := "rpc: server cannot decode request: " + err.String()
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		serviceMethod := strings.Split(req.ServiceMethod, ".", 0)
		if len(serviceMethod) != 2 {
			s := "rpc: service/method request ill:formed: " + req.ServiceMethod
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		// Look up the request.
		server.Lock()
		service, ok := server.serviceMap[serviceMethod[0]]
		server.Unlock()
		if !ok {
			s := "rpc: can't find service " + req.ServiceMethod
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		mtype, ok := service.method[serviceMethod[1]]
		if !ok {
			s := "rpc: can't find method " + req.ServiceMethod
			sendResponse(sending, req, invalidRequest, enc, s)
			continue
		}
		// Decode the argument value.
		argv := _new(mtype.argType)
		replyv := _new(mtype.replyType)
		err = dec.Decode(argv.Interface())
		if err != nil {
			log.Stderr("rpc: tearing down", serviceMethod[0], "connection:", err)
			sendResponse(sending, req, replyv.Interface(), enc, err.String())
			continue
		}
		go service.call(sending, mtype, req, argv, replyv, enc)
	}
	conn.Close()
}

func (server *serverType) accept(lis net.Listener) {
	for {
		conn, err := lis.Accept()
		if err != nil {
			log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
		}
		go server.input(conn)
	}
}

// Register publishes in the server the set of methods of the
// receiver value that satisfy the following conditions:
//	- public method
//	- two arguments, both pointers to public structs
//	- one return value of type os.Error
// It returns an error if the receiver is not public or has no
// suitable methods.
func Register(rcvr interface{}) os.Error { return server.register(rcvr) }

// ServeConn runs the server on a single connection.  When the connection
// completes, service terminates.  ServeConn blocks; the caller typically
// invokes it in a go statement.
func ServeConn(conn io.ReadWriteCloser) { go server.input(conn) }

// Accept accepts connections on the listener and serves requests
// for each incoming connection.  Accept blocks; the caller typically
// invokes it in a go statement.
func Accept(lis net.Listener) { server.accept(lis) }

// Can connect to RPC service using HTTP CONNECT to rpcPath.
var rpcPath string = "/_goRPC_"
var debugPath string = "/debug/rpc"
var connected = "200 Connected to Go RPC"

func serveHTTP(c *http.Conn, req *http.Request) {
	if req.Method != "CONNECT" {
		c.SetHeader("Content-Type", "text/plain; charset=utf-8")
		c.WriteHeader(http.StatusMethodNotAllowed)
		io.WriteString(c, "405 must CONNECT to "+rpcPath+"\n")
		return
	}
	conn, _, err := c.Hijack()
	if err != nil {
		log.Stderr("rpc hijacking ", c.RemoteAddr, ": ", err.String())
		return
	}
	io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
	server.input(conn)
}

// HandleHTTP registers an HTTP handler for RPC messages.
// It is still necessary to invoke http.Serve(), typically in a go statement.
func HandleHTTP() {
	http.Handle(rpcPath, http.HandlerFunc(serveHTTP))
	http.Handle(debugPath, http.HandlerFunc(debugHTTP))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"time"
)

var (
	bindAddr string
)

func init() {
	flag.StringVar(&bindAddr, "bind", ":65000", "UDP local listen address")
}

func main() {
	flag.Parse()

	addr, err := net.ResolveUDPAddr("udp", bindAddr)
	if err != nil {
		fmt.Printf("Couldn't resolve bind address: %s\n", err.Error())
		os.Exit(1)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Printf("Listen error: %s", err.Error())
		os.Exit(1)
	}
	log.Printf("Listening on %s...", conn.LocalAddr().String())
	buf := [1024]byte{}
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt, os.Kill)
	for {
		select {
		case <-sigchan:
			goto exit
		default:
			// Timeout forces us to poll on sigchan regularly; otherwise receive blocks
			conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
			n, addr, err := conn.ReadFromUDP(buf[0:])
			if err != nil {
				if neterr, ok := err.(net.Error); ok {
					if neterr.Timeout() {
						continue
					}
				}
				log.Fatal(err)
			}
			log.Printf("From %s: %q", addr.String(), buf[0:n])
		}
	}
exit:
	conn.Close()
	log.Println("Exited normally.")
}
<commit_msg>Added program expiration time.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"time"
)

var (
	bindAddr string
	timeout time.Duration
	sigchan chan os.Signal
	tchan <-chan time.Time
)

func init() {
	flag.StringVar(&bindAddr, "bind", ":65000", "UDP local listen address")
	flag.DurationVar(&timeout, "t", 0, "Time to run (or forever if <0)")
}

func main() {
	flag.Parse()

	addr, err := net.ResolveUDPAddr("udp", bindAddr)
	if err != nil {
		fmt.Printf("Couldn't resolve bind address: %s\n", err.Error())
		os.Exit(1)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Printf("Listen error: %s", err.Error())
		os.Exit(1)
	}
	log.Printf("Listening on %s...", conn.LocalAddr().String())
	buf := [1024]byte{}
	sigchan = make(chan os.Signal, 1)
	var readT time.Duration
	if timeout > 0 {
		tchan = time.After(timeout)
		readT = timeout
	} else {
		readT = 100 * time.Millisecond
	}
	signal.Notify(sigchan, os.Interrupt, os.Kill)
	for {
		select {
		case <-sigchan:
			goto exit
		case <-tchan:
			goto exit
		default:
			// Timeout forces us to poll on sigchan regularly; otherwise receive blocks
			conn.SetReadDeadline(time.Now().Add(readT))
			n, addr, err := conn.ReadFromUDP(buf[0:])
			if err != nil {
				if neterr, ok := err.(net.Error); ok {
					if neterr.Timeout() {
						continue
					}
				}
				log.Fatal(err)
			}
			log.Printf("From %s: %q", addr.String(), buf[0:n])
		}
	}
exit:
	conn.Close()
	log.Println("Exited normally.")
}
<|endoftext|>


<commit_before>package arn

// Analytics ...
type Analytics struct {
	UserID  string           `json:"userId"`
	General GeneralAnalytics `json:"general"`
	Screen  ScreenAnalytics  `json:"screen"`
	System  SystemAnalytics  `json:"system"`
}

// GeneralAnalytics ...
type GeneralAnalytics struct {
	TimezoneOffset int `json:"timezoneOffset"`
}

// ScreenAnalytics ...
type ScreenAnalytics struct {
	Width           int     `json:"width"`
	Height          int     `json:"height"`
	AvailableWidth  int     `json:"availableWidth"`
	AvailableHeight int     `json:"availableHeight"`
	PixelRatio      float64 `json:"pixelRatio"`
}

// SystemAnalytics ...
type SystemAnalytics struct {
	CPUCount int    `json:"cpuCount"`
	Platform string `json:"platform"`
}
<commit_msg>AllAnalytics<commit_after>package arn

// Analytics ...
type Analytics struct {
	UserID  string           `json:"userId"`
	General GeneralAnalytics `json:"general"`
	Screen  ScreenAnalytics  `json:"screen"`
	System  SystemAnalytics  `json:"system"`
}

// GeneralAnalytics ...
type GeneralAnalytics struct {
	TimezoneOffset int `json:"timezoneOffset"`
}

// ScreenAnalytics ...
type ScreenAnalytics struct {
	Width           int     `json:"width"`
	Height          int     `json:"height"`
	AvailableWidth  int     `json:"availableWidth"`
	AvailableHeight int     `json:"availableHeight"`
	PixelRatio      float64 `json:"pixelRatio"`
}

// SystemAnalytics ...
type SystemAnalytics struct {
	CPUCount int    `json:"cpuCount"`
	Platform string `json:"platform"`
}

// StreamAnalytics returns a stream of all analytics.
func StreamAnalytics() (chan *Analytics, error) {
	objects, err := DB.All("Analytics")
	return objects.(chan *Analytics), err
}

// MustStreamAnalytics returns a stream of all analytics.
func MustStreamAnalytics() chan *Analytics {
	stream, err := StreamAnalytics()
	PanicOnError(err)
	return stream
}

// AllAnalytics returns a slice of all analytics.
func AllAnalytics() ([]*Analytics, error) {
	var all []*Analytics

	stream, err := StreamAnalytics()

	if err != nil {
		return nil, err
	}

	for obj := range stream {
		all = append(all, obj)
	}

	return all, nil
}
<|endoftext|>


<commit_before>package rmq

import (
	"errors"
	"strings"
	"sync"
	"time"
)

// TestRedisClient is a mock for redis
type TestRedisClient struct {
	store sync.Map
	ttl   sync.Map
	mx    sync.Mutex
}

// NewTestRedisClient returns a NewTestRedisClient

func NewTestRedisClient() *TestRedisClient {
	return &TestRedisClient{}
}

// Set sets key to hold the string value.
// If key already holds a value, it is overwritten, regardless of its type.
// Any previous time to live associated with the key is discarded on successful SET operation.
func (client *TestRedisClient) Set(key string, value string, expiration time.Duration) error {

	client.mx.Lock()
	defer client.mx.Unlock()

	client.store.Store(key, value)
	// Delete any previous time to live associated with the key
	client.ttl.Delete(key)

	// 0.0 expiration means that the value won't expire
	if expiration.Seconds() != 0.0 {
		// Store the unix time at which we should delete this
		client.ttl.Store(key, time.Now().Add(expiration).Unix())
	}

	return nil
}

// Get the value of key.
// If the key does not exist or isn't a string
// the special value nil is returned.
func (client *TestRedisClient) Get(key string) (string, error) {

	value, found := client.store.Load(key)

	if found {
		if stringValue, casted := value.(string); casted {
			return stringValue, nil
		}
	}

	return "nil", nil
}

// Del removes the specified key. A key is ignored if it does not exist.
func (client *TestRedisClient) Del(key string) (affected int64, err error) {

	_, found := client.store.Load(key)
	client.store.Delete(key)
	client.ttl.Delete(key)

	if found {
		return 1, nil
	}
	return 0, nil

}

// TTL returns the remaining time to live of a key that has a timeout.
// This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset.
// In Redis 2.6 or older the command returns -1 if the key does not exist or if the key exist but has no associated expire.
// Starting with Redis 2.8 the return value in case of error changed:
// The command returns -2 if the key does not exist.
// The command returns -1 if the key exists but has no associated expire.
func (client *TestRedisClient) TTL(key string) (ttl time.Duration, err error) {

	// Lookup the expiration map
	expiration, found := client.ttl.Load(key)

	// Found an expiration time
	if found {

		// It was there, but it expired; removing it now
		if expiration.(int64) < time.Now().Unix() {
			client.ttl.Delete(key)
			return -2, nil
		}

		ttl = time.Duration(expiration.(int64) - time.Now().Unix())
		return ttl, nil
	}

	// Lookup the store in case this key exists but don't have an expiration
	// date
	_, found = client.store.Load(key)

	// The key was in store but didn't have an expiration associated
	// to it.
	if found {
		return -1, nil
	}

	return -2, nil
}

// LPush inserts the specified value at the head of the list stored at key.
// If key does not exist, it is created as empty list before performing the push operations.
// When key holds a value that is not a list, an error is returned.
// It is possible to push multiple elements using a single command call just specifying multiple arguments
// at the end of the command. Elements are inserted one after the other to the head of the list,
// from the leftmost element to the rightmost element.
func (client *TestRedisClient) LPush(key string, values ...string) (total int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)

	if err != nil {
		return 0, nil
	}

	newList := append(values, list...)
	client.storeList(key, newList)
	return int64(len(newList)), nil
}

// RPop removes and returns one value from the tail of the list stored at key.
// When key holds a value that is not a list, an error is returned.
func (client *TestRedisClient) RPop(key string) (value string, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)
	// not a list
	if err != nil {
		return "", ErrorNotFound
	}
	// list is empty
	if len(list) == 0 {
		return "", ErrorNotFound
	}

	// Remove the last element of source (tail)
	client.storeList(key, list[0:len(list)-1])

	return list[len(list)-1], nil
}

// LLen returns the length of the list stored at key.
// If key does not exist, it is interpreted as an empty list and 0 is returned.
// An error is returned when the value stored at key is not a list.
func (client *TestRedisClient) LLen(key string) (affected int64, err error) {
	list, err := client.findList(key)

	if err != nil {
		return 0, nil
	}
	return int64(len(list)), nil
}

// LRem removes the first count occurrences of elements equal to
// value from the list stored at key. The count argument influences
// the operation in the following ways:
// count > 0: Remove elements equal to value moving from head to tail.
// count < 0: Remove elements equal to value moving from tail to head.
// count = 0: Remove all elements equal to value. For example,
// LREM list -2 "hello" will remove the last two occurrences of "hello" in
// the list stored at list. Note that non-existing keys are treated like empty
// lists, so when key does not exist, the command will always return 0.
func (client *TestRedisClient) LRem(key string, count int64, value string) (affected int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)

	// Wasn't a list, or is empty
	if err != nil || len(list) == 0 {
		return 0, nil
	}

	// Create a list that have the capacity to store
	// the old one
	// This will be much more performant in case of
	// very long list
	newList := make([]string, 0, len(list))

	if err != nil {
		return 0, nil
	}

	// left to right removal of count elements
	if count >= 0 {

		// All the elements are to be removed.
		// Set count to max possible elements
		if count == 0 {
			count = int64(len(list))
		}
		// left to right traversal
		for index := 0; index < len(list); index++ {

			// isn't what we look for or we found enough element already
			if strings.Compare(list[index], value) != 0 || affected > count {
				newList = append(newList, list[index])
			} else {
				affected++
			}
		}
		// right to left removal of count elements
	} else if count < 0 {

		// right to left traversal
		for index := len(list) - 1; index >= 0; index-- {

			// isn't what we look for or we found enough element already
			if strings.Compare(list[index], value) != 0 || affected > count {
				// prepend instead of append to keep the order
				newList = append([]string{list[index]}, newList...)
			} else {
				affected++
			}
		}
	}

	// store the updated list
	client.storeList(key, newList)

	return affected, nil
}

// LTrim trims an existing list so that it will contain only the specified range of elements specified.
// Both start and stop are zero-based indexes, where 0 is the first element of the list (the head),
// 1 the next element and so on. For example: LTRIM foobar 0 2 will modify the list stored
// at foobar so that only the first three elements of the list will remain.
// start and end can also be negative numbers indicating offsets from the end of the list,
// where -1 is the last element of the list, -2 the penultimate element and so on.
// Out of range indexes will not produce an error: if start is larger than the end of the list,
// or start > end, the result will be an empty list (which causes key to be removed).
// If end is larger than the end of the list, Redis will treat it like the last element of the list
func (client *TestRedisClient) LTrim(key string, start, stop int64) error {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)

	// Wasn't a list, or is empty
	if err != nil || len(list) == 0 {
		return nil
	}

	if start < 0 {
		start += int64(len(list))
	}
	if stop < 0 {
		stop += int64(len(list))
	}

	// invalid values cause the remove of the key
	if start > stop {
		client.store.Delete(key)
		return nil
	}

	client.storeList(key, list[start:stop])
	return nil
}

// RPopLPush atomically returns and removes the last element (tail) of the list stored at source,
// and pushes the element at the first element (head) of the list stored at destination.
// For example: consider source holding the list a,b,c, and destination holding the list x,y,z.
// Executing RPOPLPUSH results in source holding a,b and destination holding c,x,y,z.
// If source does not exist, the value nil is returned and no operation is performed.
// If source and destination are the same, the operation is equivalent to removing the
// last element from the list and pushing it as first element of the list,
// so it can be considered as a list rotation command.
func (client *TestRedisClient) RPopLPush(source, destination string) (value string, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	sourceList, sourceErr := client.findList(source)
	destList, destErr := client.findList(destination)

	// One of the two isn't a list
	if sourceErr != nil || destErr != nil {
		return "", ErrorNotFound
	}
	// we have nothing to move
	if len(sourceList) == 0 {
		return "", ErrorNotFound
	}

	// Remove the last element of source (tail)
	client.storeList(source, sourceList[0:len(sourceList)-1])
	// Put the last element of source (tail) and prepend it to dest
	client.storeList(destination, append([]string{sourceList[len(sourceList)-1]}, destList...))

	return sourceList[len(sourceList)-1], nil
}

// SAdd adds the specified members to the set stored at key.
// Specified members that are already a member of this set are ignored.
// If key does not exist, a new set is created before adding the specified members.
// An error is returned when the value stored at key is not a set.
func (client *TestRedisClient) SAdd(key, value string) (total int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	set, err := client.findSet(key)
	if err != nil {
		return 0, err
	}

	set[value] = struct{}{}
	client.storeSet(key, set)
	return int64(len(set)), nil
}

// SMembers returns all the members of the set value stored at key.
// This has the same effect as running SINTER with one argument key.
func (client *TestRedisClient) SMembers(key string) (members []string, err error) {
	set, err := client.findSet(key)
	if err != nil {
		return members, nil
	}

	members = make([]string, 0, len(set))
	for k := range set {
		members = append(members, k)
	}

	return members, nil
}

// SRem removes the specified members from the set stored at key.
// Specified members that are not a member of this set are ignored.
// If key does not exist, it is treated as an empty set and this command returns 0.
// An error is returned when the value stored at key is not a set.
func (client *TestRedisClient) SRem(key, value string) (affected int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	set, err := client.findSet(key)
	if err != nil || len(set) == 0 {
		return 0, nil
	}

	if _, found := set[value]; found != false {
		delete(set, value)
		return 1, nil
	}

	return 0, nil
}

// FlushDb delete all the keys of the currently selected DB. This command never fails.
func (client *TestRedisClient) FlushDb() error {
	client.store = *new(sync.Map)
	client.ttl = *new(sync.Map)
	return nil
}

// storeSet stores a set
func (client *TestRedisClient) storeSet(key string, set map[string]struct{}) {
	client.store.Store(key, set)
}

// findSet finds a set
func (client *TestRedisClient) findSet(key string) (map[string]struct{}, error) {
	// Lookup the store for the list
	storedValue, found := client.store.Load(key)
	if found {
		// list are stored as pointer to []string
		set, casted := storedValue.(map[string]struct{})

		if casted {
			return set, nil
		}

		return nil, errors.New("Stored value wasn't a set")
	}

	// return an empty set if not found
	return make(map[string]struct{}), nil
}

// storeList is an helper function so others don't have to deal with pointers
func (client *TestRedisClient) storeList(key string, list []string) {
	client.store.Store(key, &list)
}

// findList returns the list stored at key.
// if key doesn't exist, an empty list is returned
// an error is returned when the value at key isn't a list
func (client *TestRedisClient) findList(key string) ([]string, error) {
	// Lookup the store for the list
	storedValue, found := client.store.Load(key)
	if found {

		// list are stored as pointer to []string
		list, casted := storedValue.(*[]string)

		// Successful cass from interface{} to *[]string
		// Preprend the new key
		if casted {

			// This mock use sync.Map to be thread safe.
			// sync.Map only accepts interface{} as values and
			// in order to store an array as interface{}, you need
			// to use a pointer to it.
			// We could return the pointer instead of the value
			// and gain some performances here. Returning the pointer,
			// however, will open us up to race conditions.
			return *list, nil
		}

		return nil, errors.New("Stored value wasn't a list")
	}

	// return an empty list if not found
	return []string{}, nil
}
<commit_msg>use redis nil in rpop<commit_after>package rmq

import (
	"errors"
	"strings"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
)

// TestRedisClient is a mock for redis
type TestRedisClient struct {
	store sync.Map
	ttl   sync.Map
	mx    sync.Mutex
}

// NewTestRedisClient returns a NewTestRedisClient

func NewTestRedisClient() *TestRedisClient {
	return &TestRedisClient{}
}

// Set sets key to hold the string value.
// If key already holds a value, it is overwritten, regardless of its type.
// Any previous time to live associated with the key is discarded on successful SET operation.
func (client *TestRedisClient) Set(key string, value string, expiration time.Duration) error {

	client.mx.Lock()
	defer client.mx.Unlock()

	client.store.Store(key, value)
	// Delete any previous time to live associated with the key
	client.ttl.Delete(key)

	// 0.0 expiration means that the value won't expire
	if expiration.Seconds() != 0.0 {
		// Store the unix time at which we should delete this
		client.ttl.Store(key, time.Now().Add(expiration).Unix())
	}

	return nil
}

// Get the value of key.
// If the key does not exist or isn't a string
// the special value nil is returned.
func (client *TestRedisClient) Get(key string) (string, error) {

	value, found := client.store.Load(key)

	if found {
		if stringValue, casted := value.(string); casted {
			return stringValue, nil
		}
	}

	return "nil", nil
}

// Del removes the specified key. A key is ignored if it does not exist.
func (client *TestRedisClient) Del(key string) (affected int64, err error) {

	_, found := client.store.Load(key)
	client.store.Delete(key)
	client.ttl.Delete(key)

	if found {
		return 1, nil
	}
	return 0, nil

}

// TTL returns the remaining time to live of a key that has a timeout.
// This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset.
// In Redis 2.6 or older the command returns -1 if the key does not exist or if the key exist but has no associated expire.
// Starting with Redis 2.8 the return value in case of error changed:
// The command returns -2 if the key does not exist.
// The command returns -1 if the key exists but has no associated expire.
func (client *TestRedisClient) TTL(key string) (ttl time.Duration, err error) {

	// Lookup the expiration map
	expiration, found := client.ttl.Load(key)

	// Found an expiration time
	if found {

		// It was there, but it expired; removing it now
		if expiration.(int64) < time.Now().Unix() {
			client.ttl.Delete(key)
			return -2, nil
		}

		ttl = time.Duration(expiration.(int64) - time.Now().Unix())
		return ttl, nil
	}

	// Lookup the store in case this key exists but don't have an expiration
	// date
	_, found = client.store.Load(key)

	// The key was in store but didn't have an expiration associated
	// to it.
	if found {
		return -1, nil
	}

	return -2, nil
}

// LPush inserts the specified value at the head of the list stored at key.
// If key does not exist, it is created as empty list before performing the push operations.
// When key holds a value that is not a list, an error is returned.
// It is possible to push multiple elements using a single command call just specifying multiple arguments
// at the end of the command. Elements are inserted one after the other to the head of the list,
// from the leftmost element to the rightmost element.
func (client *TestRedisClient) LPush(key string, values ...string) (total int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)

	if err != nil {
		return 0, nil
	}

	newList := append(values, list...)
	client.storeList(key, newList)
	return int64(len(newList)), nil
}

// RPop removes and returns one value from the tail of the list stored at key.
// When key holds a value that is not a list, an error is returned.
func (client *TestRedisClient) RPop(key string) (value string, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)
	// not a list
	if err != nil {
		return "", err
	}
	// list is empty
	if len(list) == 0 {
		return "", redis.Nil
	}

	// Remove the last element of source (tail)
	client.storeList(key, list[0:len(list)-1])

	return list[len(list)-1], nil
}

// LLen returns the length of the list stored at key.
// If key does not exist, it is interpreted as an empty list and 0 is returned.
// An error is returned when the value stored at key is not a list.
func (client *TestRedisClient) LLen(key string) (affected int64, err error) {
	list, err := client.findList(key)

	if err != nil {
		return 0, nil
	}
	return int64(len(list)), nil
}

// LRem removes the first count occurrences of elements equal to
// value from the list stored at key. The count argument influences
// the operation in the following ways:
// count > 0: Remove elements equal to value moving from head to tail.
// count < 0: Remove elements equal to value moving from tail to head.
// count = 0: Remove all elements equal to value. For example,
// LREM list -2 "hello" will remove the last two occurrences of "hello" in
// the list stored at list. Note that non-existing keys are treated like empty
// lists, so when key does not exist, the command will always return 0.
func (client *TestRedisClient) LRem(key string, count int64, value string) (affected int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)

	// Wasn't a list, or is empty
	if err != nil || len(list) == 0 {
		return 0, nil
	}

	// Create a list that have the capacity to store
	// the old one
	// This will be much more performant in case of
	// very long list
	newList := make([]string, 0, len(list))

	if err != nil {
		return 0, nil
	}

	// left to right removal of count elements
	if count >= 0 {

		// All the elements are to be removed.
		// Set count to max possible elements
		if count == 0 {
			count = int64(len(list))
		}
		// left to right traversal
		for index := 0; index < len(list); index++ {

			// isn't what we look for or we found enough element already
			if strings.Compare(list[index], value) != 0 || affected > count {
				newList = append(newList, list[index])
			} else {
				affected++
			}
		}
		// right to left removal of count elements
	} else if count < 0 {

		// right to left traversal
		for index := len(list) - 1; index >= 0; index-- {

			// isn't what we look for or we found enough element already
			if strings.Compare(list[index], value) != 0 || affected > count {
				// prepend instead of append to keep the order
				newList = append([]string{list[index]}, newList...)
			} else {
				affected++
			}
		}
	}

	// store the updated list
	client.storeList(key, newList)

	return affected, nil
}

// LTrim trims an existing list so that it will contain only the specified range of elements specified.
// Both start and stop are zero-based indexes, where 0 is the first element of the list (the head),
// 1 the next element and so on. For example: LTRIM foobar 0 2 will modify the list stored
// at foobar so that only the first three elements of the list will remain.
// start and end can also be negative numbers indicating offsets from the end of the list,
// where -1 is the last element of the list, -2 the penultimate element and so on.
// Out of range indexes will not produce an error: if start is larger than the end of the list,
// or start > end, the result will be an empty list (which causes key to be removed).
// If end is larger than the end of the list, Redis will treat it like the last element of the list
func (client *TestRedisClient) LTrim(key string, start, stop int64) error {

	client.mx.Lock()
	defer client.mx.Unlock()

	list, err := client.findList(key)

	// Wasn't a list, or is empty
	if err != nil || len(list) == 0 {
		return nil
	}

	if start < 0 {
		start += int64(len(list))
	}
	if stop < 0 {
		stop += int64(len(list))
	}

	// invalid values cause the remove of the key
	if start > stop {
		client.store.Delete(key)
		return nil
	}

	client.storeList(key, list[start:stop])
	return nil
}

// RPopLPush atomically returns and removes the last element (tail) of the list stored at source,
// and pushes the element at the first element (head) of the list stored at destination.
// For example: consider source holding the list a,b,c, and destination holding the list x,y,z.
// Executing RPOPLPUSH results in source holding a,b and destination holding c,x,y,z.
// If source does not exist, the value nil is returned and no operation is performed.
// If source and destination are the same, the operation is equivalent to removing the
// last element from the list and pushing it as first element of the list,
// so it can be considered as a list rotation command.
func (client *TestRedisClient) RPopLPush(source, destination string) (value string, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	sourceList, sourceErr := client.findList(source)
	destList, destErr := client.findList(destination)

	// One of the two isn't a list
	if sourceErr != nil || destErr != nil {
		return "", ErrorNotFound
	}
	// we have nothing to move
	if len(sourceList) == 0 {
		return "", ErrorNotFound
	}

	// Remove the last element of source (tail)
	client.storeList(source, sourceList[0:len(sourceList)-1])
	// Put the last element of source (tail) and prepend it to dest
	client.storeList(destination, append([]string{sourceList[len(sourceList)-1]}, destList...))

	return sourceList[len(sourceList)-1], nil
}

// SAdd adds the specified members to the set stored at key.
// Specified members that are already a member of this set are ignored.
// If key does not exist, a new set is created before adding the specified members.
// An error is returned when the value stored at key is not a set.
func (client *TestRedisClient) SAdd(key, value string) (total int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	set, err := client.findSet(key)
	if err != nil {
		return 0, err
	}

	set[value] = struct{}{}
	client.storeSet(key, set)
	return int64(len(set)), nil
}

// SMembers returns all the members of the set value stored at key.
// This has the same effect as running SINTER with one argument key.
func (client *TestRedisClient) SMembers(key string) (members []string, err error) {
	set, err := client.findSet(key)
	if err != nil {
		return members, nil
	}

	members = make([]string, 0, len(set))
	for k := range set {
		members = append(members, k)
	}

	return members, nil
}

// SRem removes the specified members from the set stored at key.
// Specified members that are not a member of this set are ignored.
// If key does not exist, it is treated as an empty set and this command returns 0.
// An error is returned when the value stored at key is not a set.
func (client *TestRedisClient) SRem(key, value string) (affected int64, err error) {

	client.mx.Lock()
	defer client.mx.Unlock()

	set, err := client.findSet(key)
	if err != nil || len(set) == 0 {
		return 0, nil
	}

	if _, found := set[value]; found != false {
		delete(set, value)
		return 1, nil
	}

	return 0, nil
}

// FlushDb delete all the keys of the currently selected DB. This command never fails.
func (client *TestRedisClient) FlushDb() error {
	client.store = *new(sync.Map)
	client.ttl = *new(sync.Map)
	return nil
}

// storeSet stores a set
func (client *TestRedisClient) storeSet(key string, set map[string]struct{}) {
	client.store.Store(key, set)
}

// findSet finds a set
func (client *TestRedisClient) findSet(key string) (map[string]struct{}, error) {
	// Lookup the store for the list
	storedValue, found := client.store.Load(key)
	if found {
		// list are stored as pointer to []string
		set, casted := storedValue.(map[string]struct{})

		if casted {
			return set, nil
		}

		return nil, errors.New("Stored value wasn't a set")
	}

	// return an empty set if not found
	return make(map[string]struct{}), nil
}

// storeList is an helper function so others don't have to deal with pointers
func (client *TestRedisClient) storeList(key string, list []string) {
	client.store.Store(key, &list)
}

// findList returns the list stored at key.
// if key doesn't exist, an empty list is returned
// an error is returned when the value at key isn't a list
func (client *TestRedisClient) findList(key string) ([]string, error) {
	// Lookup the store for the list
	storedValue, found := client.store.Load(key)
	if found {

		// list are stored as pointer to []string
		list, casted := storedValue.(*[]string)

		// Successful cass from interface{} to *[]string
		// Preprend the new key
		if casted {

			// This mock use sync.Map to be thread safe.
			// sync.Map only accepts interface{} as values and
			// in order to store an array as interface{}, you need
			// to use a pointer to it.
			// We could return the pointer instead of the value
			// and gain some performances here. Returning the pointer,
			// however, will open us up to race conditions.
			return *list, nil
		}

		return nil, errors.New("Stored value wasn't a list")
	}

	// return an empty list if not found
	return []string{}, nil
}
<|endoftext|>