<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"

	version "github.com/hashicorp/go-version"
)

// Plugin defines the Helm plugin parameters.
type Plugin struct {
	Debug        bool     `envconfig:"DEBUG"`
	ShowEnv      bool     `envconfig:"SHOW_ENV"`
	Wait         bool     `envconfig:"WAIT"`
	Recreate     bool     `envconfig:"RECREATE_PODS" default:"false"`
	WaitTimeout  uint32   `envconfig:"WAIT_TIMEOUT" default:"300"`
	Actions      []string `envconfig:"ACTIONS" required:"true"`
	AuthKey      string   `envconfig:"AUTH_KEY"`
	KeyPath      string   `envconfig:"KEY_PATH"`
	Zone         string   `envconfig:"ZONE"`
	Region       string   `envconfig:"REGION"`
	Cluster      string   `envconfig:"CLUSTER"`
	Project      string   `envconfig:"PROJECT"`
	Namespace    string   `envconfig:"NAMESPACE"`
	ChartRepo    string   `envconfig:"CHART_REPO"`
	Bucket       string   `envconfig:"BUCKET"`
	ChartPath    string   `envconfig:"CHART_PATH" required:"true"`
	ChartVersion string   `envconfig:"CHART_VERSION"`
	Release      string   `envconfig:"RELEASE"`
	Package      string   `envconfig:"PACKAGE"`
	Values       []string `envconfig:"VALUES"`
	ValueFiles   []string `envconfig:"VALUE_FILES"`
}

const (
	gcloudBin  = "gcloud"
	gsutilBin  = "gsutil"
	kubectlBin = "kubectl"
	helmBin    = "helm"

	lintPkg   = "lint"
	createPkg = "create"
	pushPkg   = "push"
	pullPkg   = "pull"
	deployPkg = "deploy"
	testPkg   = "test"

	updateWaitTime = 10 * time.Second
	updateRetries  = 10
)

// Exec executes the plugin step.
func (p Plugin) Exec() error {
	// only setup project when needed args are provided
	if p.Project != "" && p.Cluster != "" && (p.Zone != "" || p.Region != "") {
		if err := setupProject(p.Project, p.Cluster, p.Zone, p.Region, p.Debug); err != nil {
			return err
		}
		if err := helmInit(p.Debug); err != nil {
			return err
		}
	}

	for _, a := range p.Actions {
		switch a {
		case lintPkg:
			if err := p.lintPackage(); err != nil {
				return err
			}
		case createPkg:
			if err := p.createPackage(); err != nil {
				return err
			}
		case pushPkg:
			if err := p.pushPackage(); err != nil {
				return err
			}
		case pullPkg:
			if err := p.pullPackage(); err != nil {
				return err
			}
		case deployPkg:
			if err := p.deployPackage(); err != nil {
				return err
			}
		case testPkg:
			if err := p.testPackage(); err != nil {
				return err
			}
		default:
			return errors.New("unknown action")
		}
	}

	return nil
}

// setupProject setups gcloud project.
func setupProject(project, cluster, zone, region string, debug bool) error {
	// project configuration
	cmd := exec.Command(gcloudBin, "config", "set", "project", project)
	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not the configure the project with glcoud: %v", err)
	}

	// cluster configuration
	cmd = exec.Command(gcloudBin, "container", "clusters", "get-credentials", cluster, "--zone", zone)
	if region != "" {
		// override zone when region is set
		cmd = exec.Command(gcloudBin, "container", "clusters", "get-credentials", cluster, "--region", region)
	}

	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not configure the cluster with glcoud: %v", err)
	}

	return nil
}

// setupAuth configures gcloud to use the given authFile
func setupAuth(authFile string, debug bool) error {
	if err := os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", authFile); err != nil {
		return fmt.Errorf("could not set GOOGLE_APPLICATION_CREDENTIALS env variable: %v", err)
	}

	// authorization
	cmd := exec.Command(gcloudBin, "auth", "activate-service-account", fmt.Sprintf("--key-file=%s", authFile))
	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not authorize with glcoud: %v", err)
	}
	return nil
}

// createPackage creates Helm package for Kubernetes.
// helm package --version $PLUGIN_CHART_VERSION $PLUGIN_CHART_PATH
func (p Plugin) createPackage() error {
	return run(exec.Command(helmBin, "package", "--version", p.ChartVersion, p.ChartPath), p.Debug)
}

// cpPackage copies a file from SOURCE to DEST
// gsutil cp SOURCE DEST
func (p Plugin) cpPackage(source string, dest string) error {
	return run(exec.Command(gsutilBin, "cp", source, dest), p.Debug)
}

// cpPackage pulls helm chart from Google Storage to local
// gsutil cp $PACKAGE-$PLUGIN_CHART_VERSION.tgz gs://$PLUGIN_BUCKET
func (p Plugin) pullPackage() error {
	return p.cpPackage(
		fmt.Sprintf("gs://%s/%s-%s.tgz", p.Bucket, p.Package, p.ChartVersion),
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
	)
}

// pushPackage pushes Helm package to the Google Storage.
// gsutil cp $PACKAGE-$PLUGIN_CHART_VERSION.tgz gs://$PLUGIN_BUCKET
func (p Plugin) pushPackage() error {
	return p.cpPackage(
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
		fmt.Sprintf("gs://%s", p.Bucket),
	)
}

// helm lint $CHARTPATH -i
func (p Plugin) lintPackage() error {
	return run(exec.Command(helmBin, "lint", p.ChartPath), p.Debug)
}

// helm upgrade $PACKAGE $PACKAGE-$PLUGIN_CHART_VERSION.tgz -i
func (p Plugin) deployPackage() error {
	args := []string{
		helmBin,
		"upgrade",
		p.Release,
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
	}
	if len(p.ValueFiles) > 0 {
		for _, f := range p.ValueFiles {
			args = append(args, "-f", f)
		}
	}
	if len(p.Values) > 0 {
		args = append(args, "--set", strings.Join(p.Values, ","))
	}
	if p.Recreate {
		args = append(args, "--recreate-pods")
	}
	args = append(args, "--install")
	args = append(args, "--namespace", p.Namespace)

	if p.Wait {
		args = append(args, "--wait", "--timeout", strconv.Itoa(int(p.WaitTimeout)))
	}
	return run(exec.Command("/bin/sh", "-c", strings.Join(args, " ")), p.Debug)
}

// helm test $PACKAGE
func (p Plugin) testPackage() error {
	args := []string{helmBin, "test", p.Release, "--cleanup", "--timeout", strconv.Itoa(int(p.WaitTimeout))}
	return run(exec.Command("/bin/sh", "-c", strings.Join(args, " ")), p.Debug)
}

type semVer struct {
	Version string `json:"version"`
}
type helmVersions struct {
	Client semVer `json:"client"`
	Server semVer `json:"server"`
}

// fetchHelmVersions queries the helm and tiller versions
func fetchHelmVersions(debug bool) (*helmVersions, error) {
	// prepare the template for the `helm version --template` cmd line call.
	template, err := json.Marshal(&helmVersions{
		Client: semVer{Version: "{{ .Client.SemVer }}"},
		Server: semVer{Version: "{{ .Server.SemVer }}"},
	})
	if err != nil {
		return nil, fmt.Errorf("could not marshal version template: %v", err)
	}

	cmd := exec.Command(helmBin, "version", "--template", string(template))
	if debug {
		log.Printf("running: %s", strings.Join(cmd.Args, " "))
	}
	out, err := cmd.Output()
	if debug {
		log.Printf("%s", out)
	}
	if err != nil {
		return nil, fmt.Errorf("could not run command: %v", err)
	}

	var versions helmVersions
	if err := json.Unmarshal(out, &versions); err != nil {
		return nil, fmt.Errorf("could not parse client version: %v", err)
	}

	return &versions, nil
}

// helmInit inits Triller on Kubernetes cluster.
func helmInit(debug bool) error {
	ver, err := fetchHelmVersions(debug)
	if err != nil {
		return fmt.Errorf("could not fetch helm versions: %v", err)
	}

	clientVersion, err := version.NewVersion(ver.Client.Version)
	if err != nil {
		return fmt.Errorf("could not convert client version to semver: %v", err)
	}
	serverVersion, err := version.NewVersion(ver.Server.Version)
	if err != nil {
		return fmt.Errorf("could not convert server version to semver: %v", err)
	}

	var option string
	var wait bool
	switch clientVersion.Compare(serverVersion) {
	case -1: // client is older than tiller
		return fmt.Errorf("helm client is out of date")
	case 1: // client is newer than tiller
		option = "--upgrade"
		wait = true
	default: // client and tiller are at the same version
		option = "--client-only"
	}

	cmd := exec.Command(helmBin, "init", option)
	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not run command '%s': %v", strings.Join(cmd.Args, " "), err)
	}

	if wait {
		var err error
		for i := 0; i < updateRetries; i++ {
			time.Sleep(updateWaitTime)
			err = run(exec.Command(helmBin, "version", "--server"), debug)
			if err == nil {
				break
			}
		}
		if err != nil {
			return fmt.Errorf("could not wait for tiller: max retries exceeded: %v", err)
		}
	}

	return nil
}

func (p Plugin) movePkg() error {
	if err := os.Mkdir(p.Bucket, os.ModeDir); err != nil {
		return err
	}
	return cp(
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
		fmt.Sprintf("%s/%s-%s.tgz", p.Bucket, p.Package, p.ChartVersion),
	)
}

// cp copies file
func cp(src, dst string) error {
	s, err := os.Open(src)
	if err != nil {
		return err
	}
	// no need to check errors on read only file, we already got everything
	// we need from the filesystem, so nothing can go wrong now.
	defer s.Close()
	d, err := os.Create(dst)
	if err != nil {
		return err
	}
	if _, err := io.Copy(d, s); err != nil {
		d.Close()
		return err
	}
	return d.Close()
}

// scanNamed maps named regex groups to a golang map
func scanNamed(str string, rg *regexp.Regexp) (map[string]string, error) {
	result := make(map[string]string)
	for _, match := range rg.FindAllStringSubmatch(str, -1) {
		for i, name := range rg.SubexpNames() {
			if i != 0 && match[i] != "" && name != "" {
				result[name] = match[i]
			}
		}
	}

	if len(result) == 0 {
		return nil, errors.New("emtpy resultset")
	}

	return result, nil
}

func run(cmd *exec.Cmd, debug bool) error {
	if debug {
		log.Printf("running: %s", strings.Join(cmd.Args, " "))
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}
	return cmd.Run()
}
<commit_msg>remove init command, not needed for helm 3<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"

	version "github.com/hashicorp/go-version"
)

// Plugin defines the Helm plugin parameters.
type Plugin struct {
	Debug        bool     `envconfig:"DEBUG"`
	ShowEnv      bool     `envconfig:"SHOW_ENV"`
	Wait         bool     `envconfig:"WAIT"`
	Recreate     bool     `envconfig:"RECREATE_PODS" default:"false"`
	WaitTimeout  uint32   `envconfig:"WAIT_TIMEOUT" default:"300"`
	Actions      []string `envconfig:"ACTIONS" required:"true"`
	AuthKey      string   `envconfig:"AUTH_KEY"`
	KeyPath      string   `envconfig:"KEY_PATH"`
	Zone         string   `envconfig:"ZONE"`
	Region       string   `envconfig:"REGION"`
	Cluster      string   `envconfig:"CLUSTER"`
	Project      string   `envconfig:"PROJECT"`
	Namespace    string   `envconfig:"NAMESPACE"`
	ChartRepo    string   `envconfig:"CHART_REPO"`
	Bucket       string   `envconfig:"BUCKET"`
	ChartPath    string   `envconfig:"CHART_PATH" required:"true"`
	ChartVersion string   `envconfig:"CHART_VERSION"`
	Release      string   `envconfig:"RELEASE"`
	Package      string   `envconfig:"PACKAGE"`
	Values       []string `envconfig:"VALUES"`
	ValueFiles   []string `envconfig:"VALUE_FILES"`
}

const (
	gcloudBin  = "gcloud"
	gsutilBin  = "gsutil"
	kubectlBin = "kubectl"
	helmBin    = "helm"

	lintPkg   = "lint"
	createPkg = "create"
	pushPkg   = "push"
	pullPkg   = "pull"
	deployPkg = "deploy"
	testPkg   = "test"

	updateWaitTime = 10 * time.Second
	updateRetries  = 10
)

// Exec executes the plugin step.
func (p Plugin) Exec() error {
	// only setup project when needed args are provided
	if p.Project != "" && p.Cluster != "" && (p.Zone != "" || p.Region != "") {
		if err := setupProject(p.Project, p.Cluster, p.Zone, p.Region, p.Debug); err != nil {
			return err
		}
	}

	for _, a := range p.Actions {
		switch a {
		case lintPkg:
			if err := p.lintPackage(); err != nil {
				return err
			}
		case createPkg:
			if err := p.createPackage(); err != nil {
				return err
			}
		case pushPkg:
			if err := p.pushPackage(); err != nil {
				return err
			}
		case pullPkg:
			if err := p.pullPackage(); err != nil {
				return err
			}
		case deployPkg:
			if err := p.deployPackage(); err != nil {
				return err
			}
		case testPkg:
			if err := p.testPackage(); err != nil {
				return err
			}
		default:
			return errors.New("unknown action")
		}
	}

	return nil
}

// setupProject setups gcloud project.
func setupProject(project, cluster, zone, region string, debug bool) error {
	// project configuration
	cmd := exec.Command(gcloudBin, "config", "set", "project", project)
	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not the configure the project with glcoud: %v", err)
	}

	// cluster configuration
	cmd = exec.Command(gcloudBin, "container", "clusters", "get-credentials", cluster, "--zone", zone)
	if region != "" {
		// override zone when region is set
		cmd = exec.Command(gcloudBin, "container", "clusters", "get-credentials", cluster, "--region", region)
	}

	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not configure the cluster with glcoud: %v", err)
	}

	return nil
}

// setupAuth configures gcloud to use the given authFile
func setupAuth(authFile string, debug bool) error {
	if err := os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", authFile); err != nil {
		return fmt.Errorf("could not set GOOGLE_APPLICATION_CREDENTIALS env variable: %v", err)
	}

	// authorization
	cmd := exec.Command(gcloudBin, "auth", "activate-service-account", fmt.Sprintf("--key-file=%s", authFile))
	if err := run(cmd, debug); err != nil {
		return fmt.Errorf("could not authorize with glcoud: %v", err)
	}
	return nil
}

// createPackage creates Helm package for Kubernetes.
// helm package --version $PLUGIN_CHART_VERSION $PLUGIN_CHART_PATH
func (p Plugin) createPackage() error {
	return run(exec.Command(helmBin, "package", "--version", p.ChartVersion, p.ChartPath), p.Debug)
}

// cpPackage copies a file from SOURCE to DEST
// gsutil cp SOURCE DEST
func (p Plugin) cpPackage(source string, dest string) error {
	return run(exec.Command(gsutilBin, "cp", source, dest), p.Debug)
}

// cpPackage pulls helm chart from Google Storage to local
// gsutil cp $PACKAGE-$PLUGIN_CHART_VERSION.tgz gs://$PLUGIN_BUCKET
func (p Plugin) pullPackage() error {
	return p.cpPackage(
		fmt.Sprintf("gs://%s/%s-%s.tgz", p.Bucket, p.Package, p.ChartVersion),
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
	)
}

// pushPackage pushes Helm package to the Google Storage.
// gsutil cp $PACKAGE-$PLUGIN_CHART_VERSION.tgz gs://$PLUGIN_BUCKET
func (p Plugin) pushPackage() error {
	return p.cpPackage(
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
		fmt.Sprintf("gs://%s", p.Bucket),
	)
}

// helm lint $CHARTPATH -i
func (p Plugin) lintPackage() error {
	return run(exec.Command(helmBin, "lint", p.ChartPath), p.Debug)
}

// helm upgrade $PACKAGE $PACKAGE-$PLUGIN_CHART_VERSION.tgz -i
func (p Plugin) deployPackage() error {
	args := []string{
		helmBin,
		"upgrade",
		p.Release,
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
	}
	if len(p.ValueFiles) > 0 {
		for _, f := range p.ValueFiles {
			args = append(args, "-f", f)
		}
	}
	if len(p.Values) > 0 {
		args = append(args, "--set", strings.Join(p.Values, ","))
	}
	if p.Recreate {
		args = append(args, "--recreate-pods")
	}
	args = append(args, "--install")
	args = append(args, "--namespace", p.Namespace)

	if p.Wait {
		args = append(args, "--wait", "--timeout", strconv.Itoa(int(p.WaitTimeout)))
	}
	return run(exec.Command("/bin/sh", "-c", strings.Join(args, " ")), p.Debug)
}

// helm test $PACKAGE
func (p Plugin) testPackage() error {
	args := []string{helmBin, "test", p.Release, "--cleanup", "--timeout", strconv.Itoa(int(p.WaitTimeout))}
	return run(exec.Command("/bin/sh", "-c", strings.Join(args, " ")), p.Debug)
}

type semVer struct {
	Version string `json:"version"`
}
type helmVersions struct {
	Client semVer `json:"client"`
	Server semVer `json:"server"`
}

func (p Plugin) movePkg() error {
	if err := os.Mkdir(p.Bucket, os.ModeDir); err != nil {
		return err
	}
	return cp(
		fmt.Sprintf("%s-%s.tgz", p.Package, p.ChartVersion),
		fmt.Sprintf("%s/%s-%s.tgz", p.Bucket, p.Package, p.ChartVersion),
	)
}

// cp copies file
func cp(src, dst string) error {
	s, err := os.Open(src)
	if err != nil {
		return err
	}
	// no need to check errors on read only file, we already got everything
	// we need from the filesystem, so nothing can go wrong now.
	defer s.Close()
	d, err := os.Create(dst)
	if err != nil {
		return err
	}
	if _, err := io.Copy(d, s); err != nil {
		d.Close()
		return err
	}
	return d.Close()
}

// scanNamed maps named regex groups to a golang map
func scanNamed(str string, rg *regexp.Regexp) (map[string]string, error) {
	result := make(map[string]string)
	for _, match := range rg.FindAllStringSubmatch(str, -1) {
		for i, name := range rg.SubexpNames() {
			if i != 0 && match[i] != "" && name != "" {
				result[name] = match[i]
			}
		}
	}

	if len(result) == 0 {
		return nil, errors.New("emtpy resultset")
	}

	return result, nil
}

func run(cmd *exec.Cmd, debug bool) error {
	if debug {
		log.Printf("running: %s", strings.Join(cmd.Args, " "))
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}
	return cmd.Run()
}
<|endoftext|>


<commit_before>package rss

import (
	"sync"
	"testing"
	"time"
)

var feeds = []string{
	"http://cre.fm/feed/m4a",
	"http://www.konscience.de/feed/",
	//"http://minkorrekt.de/feed/m4a/",
	"http://modellansatz.de/rss/?psb",
	"http://forschergeist.de/feed/m4a/",
	"http://www.radiomono.net/feed/m4a/",
	"http://www.zeitsprung.fm/feed/mp4/",
	"http://podcast.firtz.org/firtz/mp3",
	"http://www.psycho-talk.de/feed/mp3/",
	"http://www.exponiert.berlin/feed/m4a/",
	"http://resonator-podcast.de/feed/m4a/",
	"http://feeds.metaebene.me/raumzeit/m4a",
	"http://www.openscienceradio.de/feed/mp4/",
	//"http://www.hoaxilla.de/podcast/hoaxilla.xml",
	"http://omegataupodcast.net/category/podcast/feed/",
	"http://www.uibk.ac.at/downloads/c115/zeit/zeit_mp4.xml",
}

func initTimeSeq() func() int {
	t := time.Now().Unix()
	return func() int {
		return int(time.Now().Unix() - t)
	}
}

func Test_Read(t *testing.T) {
	var feedsContent = make(map[string]*Main)
	var wg sync.WaitGroup

	timeSince := initTimeSeq()

	for _, url := range feeds {
		wg.Add(1)
		go func(url string) {
			defer wg.Done()
			feedContent, err := Read(url)
			t.Logf("%v is ready (%v) ... \n", url, timeSince())
			if err == nil {
				feedsContent[url] = feedContent
			} else {
				t.Fatalf("rss.Read Test failed: %v\nFeed: %v\n\n", err, url)
			}
		}(url)
	}

	wg.Wait()

	for url, feedContent := range feedsContent {
		t.Logf("URL: %v\tTitle: %v\n", url, feedContent.Title)
		if feedContent.Title == "" {
			t.Fatalf("rss.Read Test failed: No Title detected\nFeed: %v\n\n", url)
		}
		if feedContent.Len() < 3 {
			t.Fatalf("rss.Read Test failed: I don't think that there are only %v Episodes\nFeed: %v | %v\n\n", feedContent.Len(), url, feedContent.Title)
		}

		for _, item := range feedContent.Items {
			t.Logf("Title: %v\tTime: %v\n", item.Title, item.Time())
			if item.Time().Unix() < 921456000 && url != "http://modellansatz.de/rss/?psb" {
				t.Fatalf("rss.Read Test failed: The episode publication date is before the release date of the first RSS draft\nFeed: %v | %v \nTime: %v\nTitle: %v\n\n", url, feedContent.Title, item.Time(), item.Title)
			}
		}
	}
}

func Test_Read2(t *testing.T) {
	_, err := Read("http://localhost/feed.xml")
	if err == nil {
		t.Fatal("rss.Read2 Test failed: I expect an error but got nil\n")
	}
}

func Test_Main_Time(t *testing.T) {
	feedContent, _ := Read("http://cre.fm/feed/m4a")
	if feedContent.Time().Unix() < 921456000 {
		t.Fatal("rss.Main.Time Test failed: The specified last build date is before the release date of the first RSS draft\n")
	}
}
<commit_msg>Remove podcast.firtz.org (Fehler beim Aufbau einer Datenbankverbindung) from tests<commit_after>package rss

import (
	"sync"
	"testing"
	"time"
)

var feeds = []string{
	"http://cre.fm/feed/m4a",
	"http://www.konscience.de/feed/",
	//"http://minkorrekt.de/feed/m4a/",
	"http://modellansatz.de/rss/?psb",
	"http://forschergeist.de/feed/m4a/",
	"http://www.radiomono.net/feed/m4a/",
	"http://www.zeitsprung.fm/feed/mp4/",
	//"http://podcast.firtz.org/firtz/mp3",
	"http://www.psycho-talk.de/feed/mp3/",
	"http://www.exponiert.berlin/feed/m4a/",
	"http://resonator-podcast.de/feed/m4a/",
	"http://feeds.metaebene.me/raumzeit/m4a",
	"http://www.openscienceradio.de/feed/mp4/",
	//"http://www.hoaxilla.de/podcast/hoaxilla.xml",
	"http://omegataupodcast.net/category/podcast/feed/",
	"http://www.uibk.ac.at/downloads/c115/zeit/zeit_mp4.xml",
}

func initTimeSeq() func() int {
	t := time.Now().Unix()
	return func() int {
		return int(time.Now().Unix() - t)
	}
}

func Test_Read(t *testing.T) {
	var feedsContent = make(map[string]*Main)
	var wg sync.WaitGroup

	timeSince := initTimeSeq()

	for _, url := range feeds {
		wg.Add(1)
		go func(url string) {
			defer wg.Done()
			feedContent, err := Read(url)
			t.Logf("%v is ready (%v) ... \n", url, timeSince())
			if err == nil {
				feedsContent[url] = feedContent
			} else {
				t.Fatalf("rss.Read Test failed: %v\nFeed: %v\n\n", err, url)
			}
		}(url)
	}

	wg.Wait()

	for url, feedContent := range feedsContent {
		t.Logf("URL: %v\tTitle: %v\n", url, feedContent.Title)
		if feedContent.Title == "" {
			t.Fatalf("rss.Read Test failed: No Title detected\nFeed: %v\n\n", url)
		}
		if feedContent.Len() < 3 {
			t.Fatalf("rss.Read Test failed: I don't think that there are only %v Episodes\nFeed: %v | %v\n\n", feedContent.Len(), url, feedContent.Title)
		}

		for _, item := range feedContent.Items {
			t.Logf("Title: %v\tTime: %v\n", item.Title, item.Time())
			if item.Time().Unix() < 921456000 && url != "http://modellansatz.de/rss/?psb" {
				t.Fatalf("rss.Read Test failed: The episode publication date is before the release date of the first RSS draft\nFeed: %v | %v \nTime: %v\nTitle: %v\n\n", url, feedContent.Title, item.Time(), item.Title)
			}
		}
	}
}

func Test_Read2(t *testing.T) {
	_, err := Read("http://localhost/feed.xml")
	if err == nil {
		t.Fatal("rss.Read2 Test failed: I expect an error but got nil\n")
	}
}

func Test_Main_Time(t *testing.T) {
	feedContent, _ := Read("http://cre.fm/feed/m4a")
	if feedContent.Time().Unix() < 921456000 {
		t.Fatal("rss.Main.Time Test failed: The specified last build date is before the release date of the first RSS draft\n")
	}
}
<|endoftext|>


<commit_before>package daemon

import (
	"bufio"
	"io"
	"log"
	"os"
	"os/exec"
	"time"
)

// ServiceManager is the default implementation of the Service interface.
type ServiceManager struct {
	Command             string
	processes           map[int]*exec.Cmd
	Args                []string
	Env                 []string
	commandCompleteChan chan *exec.Cmd
	commandCreatedChan  chan *exec.Cmd
}

// Setup the Management services.
func (s *ServiceManager) Setup() {
	log.Println("[DEBUG] setting up a service manager")
	s.commandCreatedChan = make(chan *exec.Cmd)
	s.commandCompleteChan = make(chan *exec.Cmd)
	s.processes = make(map[int]*exec.Cmd)

	// Listen for service create/kill
	go s.addServiceMonitor()
	go s.removeServiceMonitor()
}

// addServiceMonitor watches a channel to add services into operation.
func (s *ServiceManager) addServiceMonitor() {
	log.Println("[DEBUG] starting service creation monitor")
	for {
		select {
		case p := <-s.commandCreatedChan:
			if p != nil && p.Process != nil {
				s.processes[p.Process.Pid] = p
			}
		}
	}
}

// removeServiceMonitor watches a channel to remove services from operation.
func (s *ServiceManager) removeServiceMonitor() {
	log.Println("[DEBUG] starting service removal monitor")
	var p *exec.Cmd
	for {
		select {
		case p = <-s.commandCompleteChan:
			if p != nil && p.Process != nil {
				p.Process.Signal(os.Interrupt)
				delete(s.processes, p.Process.Pid)
			}
		}
	}
}

// Stop a Service and returns the exit status.
// Stop a Service and returns the exit status.
func (s *ServiceManager) Stop(pid int) (bool, error) {
	log.Println("[DEBUG] stopping service with pid", pid)
	cmd := s.processes[pid]

	// Remove service from registry
	go func() {
		s.commandCompleteChan <- cmd
	}()
	var err error
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()

	select {
	case <-time.After(3 * time.Second):
		if err = cmd.Process.Kill(); err != nil {
			log.Println("failed to kill: ", err)
			return false, err
		}
		log.Println("process killed as timeout reached")
	case err = <-done:
		if err != nil {
			log.Printf("process done with error = %v", err)

		} else {
			log.Print("process done gracefully without error")
		}
	}

	return cmd.ProcessState.Success(), nil
}

// List all Service PIDs.
func (s *ServiceManager) List() map[int]*exec.Cmd {
	log.Println("[DEBUG] listing services")
	return s.processes
}

// Run runs a service synchronously and log its output to the given Pipe.
func (s *ServiceManager) Run(w io.Writer) (*exec.Cmd, error) {
	log.Println("[DEBUG] starting service")
	cmd := exec.Command(s.Command, s.Args...)
	cmd.Env = s.Env
	cmd.Stdout = w
	cmd.Stderr = w
	err := cmd.Run()

	return cmd, err
}

// Start a Service and log its output.
func (s *ServiceManager) Start() *exec.Cmd {
	log.Println("[DEBUG] starting service")
	cmd := exec.Command(s.Command, s.Args...)
	cmd.Env = s.Env

	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create output pipe for cmd: %s\n", err.Error())
		os.Exit(1)
	}

	cmdReaderErr, err := cmd.StderrPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create error pipe for cmd: %s\n", err.Error())
		os.Exit(1)
	}

	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			log.Printf("[ERROR] %s\n", scanner.Text())
		}
	}()

	scanner2 := bufio.NewScanner(cmdReaderErr)
	go func() {
		for scanner2.Scan() {
			log.Printf("[INFO] service: %s\n", scanner2.Text())
		}
	}()

	err = cmd.Start()
	if err != nil {
		log.Println("[ERROR] service", err.Error())
		os.Exit(1)
	}

	// Add service to registry
	s.commandCreatedChan <- cmd

	return cmd
}
<commit_msg>fix(windows): cleanup logging for windows service manager<commit_after>package daemon

import (
	"bufio"
	"io"
	"log"
	"os"
	"os/exec"
	"time"
)

// ServiceManager is the default implementation of the Service interface.
type ServiceManager struct {
	Command             string
	processes           map[int]*exec.Cmd
	Args                []string
	Env                 []string
	commandCompleteChan chan *exec.Cmd
	commandCreatedChan  chan *exec.Cmd
}

// Setup the Management services.
func (s *ServiceManager) Setup() {
	log.Println("[DEBUG] setting up a service manager")
	s.commandCreatedChan = make(chan *exec.Cmd)
	s.commandCompleteChan = make(chan *exec.Cmd)
	s.processes = make(map[int]*exec.Cmd)

	// Listen for service create/kill
	go s.addServiceMonitor()
	go s.removeServiceMonitor()
}

// addServiceMonitor watches a channel to add services into operation.
func (s *ServiceManager) addServiceMonitor() {
	log.Println("[DEBUG] starting service creation monitor")
	for {
		select {
		case p := <-s.commandCreatedChan:
			if p != nil && p.Process != nil {
				s.processes[p.Process.Pid] = p
			}
		}
	}
}

// removeServiceMonitor watches a channel to remove services from operation.
func (s *ServiceManager) removeServiceMonitor() {
	log.Println("[DEBUG] starting service removal monitor")
	var p *exec.Cmd
	for {
		select {
		case p = <-s.commandCompleteChan:
			if p != nil && p.Process != nil {
				p.Process.Signal(os.Interrupt)
				delete(s.processes, p.Process.Pid)
			}
		}
	}
}

// Stop a Service and returns the exit status.
// Stop a Service and returns the exit status.
func (s *ServiceManager) Stop(pid int) (bool, error) {
	log.Println("[DEBUG] stopping service with pid", pid)
	cmd := s.processes[pid]

	// Remove service from registry
	go func() {
		s.commandCompleteChan <- cmd
	}()

	// Wait for error, kill if it takes too long
	var err error
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()

	select {
	case <-time.After(3 * time.Second):
		if err = cmd.Process.Kill(); err != nil {
			log.Println("[ERROR] timeout reached, killing pid", pid)

			return false, err
		}
	case err = <-done:
		if err != nil {
			log.Println("[ERROR] error waiting for process to complete", err)
			return false, err
		}
	}

	return true, nil
}

// List all Service PIDs.
func (s *ServiceManager) List() map[int]*exec.Cmd {
	log.Println("[DEBUG] listing services")
	return s.processes
}

// Run runs a service synchronously and log its output to the given Pipe.
func (s *ServiceManager) Run(w io.Writer) (*exec.Cmd, error) {
	log.Println("[DEBUG] starting service")
	cmd := exec.Command(s.Command, s.Args...)
	cmd.Env = s.Env
	cmd.Stdout = w
	cmd.Stderr = w
	err := cmd.Run()

	return cmd, err
}

// Start a Service and log its output.
func (s *ServiceManager) Start() *exec.Cmd {
	log.Println("[DEBUG] starting service")
	cmd := exec.Command(s.Command, s.Args...)
	cmd.Env = s.Env

	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create output pipe for cmd: %s\n", err.Error())
		os.Exit(1)
	}

	cmdReaderErr, err := cmd.StderrPipe()
	if err != nil {
		log.Printf("[ERROR] unable to create error pipe for cmd: %s\n", err.Error())
		os.Exit(1)
	}

	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			log.Printf("[ERROR] %s\n", scanner.Text())
		}
	}()

	scanner2 := bufio.NewScanner(cmdReaderErr)
	go func() {
		for scanner2.Scan() {
			log.Printf("[INFO] service: %s\n", scanner2.Text())
		}
	}()

	err = cmd.Start()
	if err != nil {
		log.Println("[ERROR] service", err.Error())
		os.Exit(1)
	}

	// Add service to registry
	s.commandCreatedChan <- cmd

	return cmd
}
<|endoftext|>


<commit_before>package ui

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"runtime"
	"time"

	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/getlantern/waitforserver"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("flashlight.ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	externalUrl = "https://www.facebook.com/manototv/" // this string is going to be changed by Makefile
	r           = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		// Panicking here because this shouldn't happen at runtime unless the
		// resources were incorrectly embedded.
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return uiaddr + p
}

func Start(addr string) error {
	var err error
	l, err = net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("Unable to listen at %v: %v", addr, l)
	}

	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler:  r,
		ErrorLog: log.AsStdLogger(),
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser. It will wait for the UI addr come up for at most 3 seconds
func Show() {
	go func() {
		addr, _ := url.Parse(uiaddr)
		if err := waitforserver.WaitForServer("tcp", addr.Host, 3*time.Second); err != nil {
			log.Error(err)
			return
		}
		open.Run(uiaddr)
		if externalUrl != "NO"+"_URL" {
			time.Sleep(4 * time.Second)
			open.Run(externalUrl)
		}
	}()
}
<commit_msg>only open Manoto page once<commit_after>package ui

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"runtime"
	"time"

	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/getlantern/waitforserver"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("flashlight.ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	externalUrl    = "https://www.facebook.com/manototv/" // this string is going to be changed by Makefile
	openedExternal = false
	r              = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		// Panicking here because this shouldn't happen at runtime unless the
		// resources were incorrectly embedded.
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return uiaddr + p
}

func Start(addr string) error {
	var err error
	l, err = net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("Unable to listen at %v: %v", addr, l)
	}

	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler:  r,
		ErrorLog: log.AsStdLogger(),
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser. It will wait for the UI addr come up for at most 3 seconds
func Show() {
	go func() {
		addr, _ := url.Parse(uiaddr)
		if err := waitforserver.WaitForServer("tcp", addr.Host, 3*time.Second); err != nil {
			log.Error(err)
			return
		}
		open.Run(uiaddr)
		if externalUrl != "NO"+"_URL" && !openedExternal {
			time.Sleep(4 * time.Second)
			open.Run(externalUrl)
			openedExternal = true
		}
	}()
}
<|endoftext|>


<commit_before>package stathat

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// Kind indicates the type of stat posting
type Kind int

// Kinds
const (
	KindValue Kind = iota + 1
	KindCounter
)

// ErrKindMissing means the `Kind` was missing.
var ErrKindMissing = errors.New("kind missing")

// PostEZ posts the value to the stat using the EZ API.
// If you supply a non-nil time, it'll use that as the time value, otherwise it will not send a time value.
// This is probably what you want to do if posting stats.
func (s StatHat) PostEZ(name string, kind Kind, v float64, t *time.Time) error {
	u, _ := url.Parse(s.ezPrefix())
	q := u.Query()

	if len(s.ezkey) == 0 {
		return ErrMissingEZKey
	}
	q.Add("ezkey", s.ezkey)
	q.Add("stat", name)

	if t != nil && !t.IsZero() {
		q.Add("t", strconv.FormatInt(t.Unix(), 10))
	}

	if kind == KindValue {
		q.Add("value", strconv.FormatFloat(v, 'g', -1, 64))
	} else if kind == KindCounter {
		q.Add("count", strconv.FormatFloat(v, 'g', -1, 64))
	} else {
		return ErrKindMissing
	}

	u.RawQuery = q.Encode()
	req, err := http.NewRequest(http.MethodPost, u.String(), nil)
	if err != nil {
		return err
	}
	resp, err := httpDo(req)
	if err != nil {
		return err
	}
	var respJSON struct {
		// {"msg":"stat deleted."}
		Msg string
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, &respJSON)
	if respJSON.Msg != "ok" {
		err = errors.New(respJSON.Msg)
	}
	return err
}
<commit_msg>PostEZ no longer returns a blank non-nil error when HTTP 204 is received<commit_after>package stathat

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// Kind indicates the type of stat posting
type Kind int

// Kinds
const (
	KindValue Kind = iota + 1
	KindCounter
)

// ErrKindMissing means the `Kind` was missing.
var ErrKindMissing = errors.New("kind missing")

// PostEZ posts the value to the stat using the EZ API.
// If you supply a non-nil time, it'll use that as the time value, otherwise it will not send a time value.
// This is probably what you want to do if posting stats.
func (s StatHat) PostEZ(name string, kind Kind, v float64, t *time.Time) error {
	u, _ := url.Parse(s.ezPrefix())
	q := u.Query()

	if len(s.ezkey) == 0 {
		return ErrMissingEZKey
	}
	q.Add("ezkey", s.ezkey)
	q.Add("stat", name)

	if t != nil && !t.IsZero() {
		q.Add("t", strconv.FormatInt(t.Unix(), 10))
	}

	if kind == KindValue {
		q.Add("value", strconv.FormatFloat(v, 'g', -1, 64))
	} else if kind == KindCounter {
		q.Add("count", strconv.FormatFloat(v, 'g', -1, 64))
	} else {
		return ErrKindMissing
	}

	u.RawQuery = q.Encode()
	req, err := http.NewRequest(http.MethodPost, u.String(), nil)
	if err != nil {
		return err
	}
	resp, err := httpDo(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// StatHat may return HTTP Status Code 204 to indicate success.
	// See: https://blog.stathat.com/2017/05/05/bandwidth.html
	if resp.StatusCode == http.StatusNoContent {
		return nil
	}

	var respJSON struct {
		// {"msg":"stat deleted."}
		Msg string
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, &respJSON)
	if respJSON.Msg != "ok" {
		err = errors.New(respJSON.Msg)
	}
	return err
}
<|endoftext|>


<commit_before>package poker

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

type Poker struct {
	WebRoot string
	Addr    string
	OnAuth  func(conn *Conn, mechanism, text string) (*Occupant, error)
	OnExit  func(o *Occupant)
}

func (p *Poker) ListenAndServe() error {
	http.HandleFunc("/ws", p.pokerHandler)
	http.Handle("/", http.FileServer(http.Dir(p.WebRoot)))
	return http.ListenAndServe(p.Addr, nil)
}

func (p *Poker) pokerHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer ws.Close()

	ws.SetReadLimit(maxMessageSize)
	ws.SetPongHandler(
		func(string) error {
			ws.SetReadDeadline(time.Now().Add(pongWait))
			return nil
		})
	conn := NewConn(ws, 128)
	defer conn.Close()

	ver := &Version{}
	if err := conn.ReadJSONTimeout(ver, readWait); err != nil {
		return
	}
	if err := conn.WriteJSON(ver); err != nil {
		return
	}

	auth := &Auth{}
	if err := conn.ReadJSONTimeout(auth, readWait); err != nil {
		return
	}

	var o *Occupant
	if p.OnAuth != nil {
		o, err = p.OnAuth(conn, auth.Mechanism, auth.Text)
		if err != nil {
			log.Println(err)
			//conn.WriteJSON(err)
			//return
			o = NewOccupant(strconv.FormatInt(time.Now().Unix(), 10), conn)
			o.Name = auth.Text
		}
		o.Chips = 10000
	}

	if err := conn.WriteJSON(o); err != nil {
		return
	}

	for {
		message, _ := o.GetMessage(0)
		if message == nil {
			break
		}

		switch message.Type {
		case MsgIQ:
			go handleIQ(o, message)
		case MsgPresence:
			go handlePresence(o, message)
		case MsgMessage:
		}
	}

	o.Leave()

	if p.OnExit != nil {
		p.OnExit(o)
	}
	log.Println(o.Name, "disconnected.")
}
<commit_msg>add gracehttp feature<commit_after>package poker

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

type Poker struct {
	WebRoot string
	Addr    string
	OnAuth  func(conn *Conn, mechanism, text string) (*Occupant, error)
	OnExit  func(o *Occupant)
}

func (p *Poker) ListenAndServe() error {
	http.HandleFunc("/ws", p.pokerHandler)
	http.Handle("/", http.FileServer(http.Dir(p.WebRoot)))
	//return http.ListenAndServe(p.Addr, nil)
	return gracehttp.Serve(&http.Server{Addr: p.Addr})
}

func (p *Poker) pokerHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer ws.Close()

	ws.SetReadLimit(maxMessageSize)
	ws.SetPongHandler(
		func(string) error {
			ws.SetReadDeadline(time.Now().Add(pongWait))
			return nil
		})
	conn := NewConn(ws, 128)
	defer conn.Close()

	ver := &Version{}
	if err := conn.ReadJSONTimeout(ver, readWait); err != nil {
		return
	}
	if err := conn.WriteJSON(ver); err != nil {
		return
	}

	auth := &Auth{}
	if err := conn.ReadJSONTimeout(auth, readWait); err != nil {
		return
	}

	var o *Occupant
	if p.OnAuth != nil {
		o, err = p.OnAuth(conn, auth.Mechanism, auth.Text)
		if err != nil {
			log.Println(err)
			//conn.WriteJSON(err)
			//return
			o = NewOccupant(strconv.FormatInt(time.Now().Unix(), 10), conn)
			o.Name = auth.Text
		}
		o.Chips = 10000
	}

	if err := conn.WriteJSON(o); err != nil {
		return
	}

	for {
		message, _ := o.GetMessage(0)
		if message == nil {
			break
		}

		switch message.Type {
		case MsgIQ:
			go handleIQ(o, message)
		case MsgPresence:
			go handlePresence(o, message)
		case MsgMessage:
		}
	}

	o.Leave()

	if p.OnExit != nil {
		p.OnExit(o)
	}
	log.Println(o.Name, "disconnected.")
}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sort"
	"strconv"

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
)

type userRequest struct {
	ID         uint64            `json:"id,string"`
	Name       string            `json:"name"`
	Provider   string            `json:"provider"`
	Scheme     string            `json:"scheme"`
	SuperAdmin bool              `json:"superAdmin"`
	Roles      []chronograf.Role `json:"roles"`
}

func (r *userRequest) ValidCreate() error {
	if r.Name == "" {
		return fmt.Errorf("Name required on Chronograf User request body")
	}
	if r.Provider == "" {
		return fmt.Errorf("Provider required on Chronograf User request body")
	}
	if r.Scheme == "" {
		return fmt.Errorf("Scheme required on Chronograf User request body")
	}

	// TODO: This Scheme value is hard-coded temporarily since we only currently
	// support OAuth2. This hard-coding should be removed whenever we add
	// support for other authentication schemes.
	r.Scheme = "oauth2"
	return r.ValidRoles()
}

func (r *userRequest) ValidUpdate() error {
	if r.Name != "" {
		return fmt.Errorf("Cannot update Name")
	}
	if r.Provider != "" {
		return fmt.Errorf("Cannot update Provider")
	}
	if r.Scheme != "" {
		return fmt.Errorf("Cannot update Scheme")
	}
	if r.Roles == nil {
		return fmt.Errorf("No Roles to update")
	}
	return r.ValidRoles()
}

func (r *userRequest) ValidRoles() error {
	if len(r.Roles) > 0 {
		for _, r := range r.Roles {
			switch r.Name {
			case MemberRoleName, ViewerRoleName, EditorRoleName, AdminRoleName:
				continue
			default:
				return fmt.Errorf("Unknown role %s. Valid roles are 'viewer', 'editor', 'admin', and 'superadmin'", r.Name)
			}
		}
	}
	return nil
}

type userResponse struct {
	Links      selfLinks         `json:"links"`
	ID         uint64            `json:"id,string"`
	Name       string            `json:"name"`
	Provider   string            `json:"provider"`
	Scheme     string            `json:"scheme"`
	SuperAdmin bool              `json:"superAdmin"`
	Roles      []chronograf.Role `json:"roles"`
}

func newUserResponse(u *chronograf.User) *userResponse {
	// This ensures that any user response with no roles returns an empty array instead of
	// null when marshaled into JSON. That way, JavaScript doesn't need any guard on the
	// key existing and it can simply be iterated over.
	if u.Roles == nil {
		u.Roles = []chronograf.Role{}
	}
	return &userResponse{
		ID:       u.ID,
		Name:     u.Name,
		Provider: u.Provider,
		Scheme:   u.Scheme,
		Roles:    u.Roles,
		Links: selfLinks{
			Self: fmt.Sprintf("/chronograf/v1/users/%d", u.ID),
		},
	}
}

type usersResponse struct {
	Links selfLinks       `json:"links"`
	Users []*userResponse `json:"users"`
}

func newUsersResponse(users []chronograf.User) *usersResponse {
	usersResp := make([]*userResponse, len(users))
	for i, user := range users {
		usersResp[i] = newUserResponse(&user)
	}
	sort.Slice(usersResp, func(i, j int) bool {
		return usersResp[i].ID < usersResp[j].ID
	})
	return &usersResponse{
		Users: usersResp,
		Links: selfLinks{
			Self: "/chronograf/v1/users",
		},
	}
}

// Chronograf User Roles
const (
	MemberRoleName     = "member"
	ViewerRoleName     = "viewer"
	EditorRoleName     = "editor"
	AdminRoleName      = "admin"
	SuperAdminRoleName = "superadmin"
)

var (
	// MemberRole is the role for a user who can only perform No operations.
	MemberRole = chronograf.Role{
		Name: MemberRoleName,
	}

	// ViewerRole is the role for a user who can only perform READ operations on Dashboards, Rules, and Sources
	ViewerRole = chronograf.Role{
		Name: ViewerRoleName,
	}

	// EditorRole is the role for a user who can perform READ and WRITE operations on Dashboards, Rules, and Sources
	EditorRole = chronograf.Role{
		Name: EditorRoleName,
	}

	// AdminRole is the role for a user who can perform READ and WRITE operations on Dashboards, Rules, Sources, and Users
	AdminRole = chronograf.Role{
		Name: AdminRoleName,
	}
)

// UserID retrieves a Chronograf user with ID from store
func (s *Service) UserID(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	idStr := httprouter.GetParamFromContext(ctx, "id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		Error(w, http.StatusBadRequest, fmt.Sprintf("invalid user id: %s", err.Error()), s.Logger)
		return
	}
	user, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{ID: &id})
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	res := newUserResponse(user)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// NewUser adds a new Chronograf user to store
func (s *Service) NewUser(w http.ResponseWriter, r *http.Request) {
	var req userRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	if err := req.ValidCreate(); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	ctx := r.Context()
	user := &chronograf.User{
		Name:     req.Name,
		Provider: req.Provider,
		Scheme:   req.Scheme,
		Roles:    req.Roles,
	}

	// If req.SuperAdmin has been set, verify that it was done with the superadmin context.
	// Even though req.SuperAdmin == true is logically equivalent to req.SuperAdmin it is
	// more clear that this code should only be ran in the case that a user is trying to
	// set the SuperAdmin field.
	if req.SuperAdmin == true {
		// Only allow users to set SuperAdmin if they have the superadmin context
		if isSuperAdmin := hasSuperAdminContext(ctx); !isSuperAdmin {
			Error(w, http.StatusBadRequest, "Cannot set SuperAdmin", s.Logger)
			return
		}
		user.SuperAdmin = true
	}

	res, err := s.Store.Users(ctx).Add(ctx, user)
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	cu := newUserResponse(res)
	location(w, cu.Links.Self)
	encodeJSON(w, http.StatusCreated, cu, s.Logger)
}

// RemoveUser deletes a Chronograf user from store
func (s *Service) RemoveUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idStr := httprouter.GetParamFromContext(ctx, "id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		Error(w, http.StatusBadRequest, fmt.Sprintf("invalid user id: %s", err.Error()), s.Logger)
		return
	}

	u, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{ID: &id})
	if err != nil {
		Error(w, http.StatusNotFound, err.Error(), s.Logger)
		return
	}
	if err := s.Store.Users(ctx).Delete(ctx, u); err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// UpdateUser updates a Chronograf user in store
func (s *Service) UpdateUser(w http.ResponseWriter, r *http.Request) {
	var req userRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	if err := req.ValidUpdate(); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	ctx := r.Context()
	idStr := httprouter.GetParamFromContext(ctx, "id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		Error(w, http.StatusBadRequest, fmt.Sprintf("invalid user id: %s", err.Error()), s.Logger)
		return
	}

	u, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{ID: &id})
	if err != nil {
		Error(w, http.StatusNotFound, err.Error(), s.Logger)
		return
	}

	// ValidUpdate should ensure that req.Roles is not nil
	u.Roles = req.Roles

	// If req.SuperAdmin has been set, verify that it was done with the superadmin context.
	// Even though req.SuperAdmin == true is logically equivalent to req.SuperAdmin it is
	// more clear that this code should only be ran in the case that a user is trying to
	// set the SuperAdmin field.
	if req.SuperAdmin == true {
		// Only allow users to set SuperAdmin if they have the superadmin context
		if isSuperAdmin := hasSuperAdminContext(ctx); !isSuperAdmin {
			Error(w, http.StatusBadRequest, "Cannot set SuperAdmin", s.Logger)
			return
		}
		u.SuperAdmin = true
	}

	err = s.Store.Users(ctx).Update(ctx, u)
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	cu := newUserResponse(u)
	location(w, cu.Links.Self)
	encodeJSON(w, http.StatusOK, cu, s.Logger)
}

// Users retrieves all Chronograf users from store
func (s *Service) Users(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	users, err := s.Store.Users(ctx).All(ctx)
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	res := newUsersResponse(users)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
<commit_msg>Change nil check to len == 0 check for userRequest<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sort"
	"strconv"

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
)

type userRequest struct {
	ID         uint64            `json:"id,string"`
	Name       string            `json:"name"`
	Provider   string            `json:"provider"`
	Scheme     string            `json:"scheme"`
	SuperAdmin bool              `json:"superAdmin"`
	Roles      []chronograf.Role `json:"roles"`
}

func (r *userRequest) ValidCreate() error {
	if r.Name == "" {
		return fmt.Errorf("Name required on Chronograf User request body")
	}
	if r.Provider == "" {
		return fmt.Errorf("Provider required on Chronograf User request body")
	}
	if r.Scheme == "" {
		return fmt.Errorf("Scheme required on Chronograf User request body")
	}

	// TODO: This Scheme value is hard-coded temporarily since we only currently
	// support OAuth2. This hard-coding should be removed whenever we add
	// support for other authentication schemes.
	r.Scheme = "oauth2"
	return r.ValidRoles()
}

func (r *userRequest) ValidUpdate() error {
	if r.Name != "" {
		return fmt.Errorf("Cannot update Name")
	}
	if r.Provider != "" {
		return fmt.Errorf("Cannot update Provider")
	}
	if r.Scheme != "" {
		return fmt.Errorf("Cannot update Scheme")
	}
	if len(r.Roles) == 0 {
		return fmt.Errorf("No Roles to update")
	}
	return r.ValidRoles()
}

func (r *userRequest) ValidRoles() error {
	if len(r.Roles) > 0 {
		for _, r := range r.Roles {
			switch r.Name {
			case MemberRoleName, ViewerRoleName, EditorRoleName, AdminRoleName:
				continue
			default:
				return fmt.Errorf("Unknown role %s. Valid roles are 'viewer', 'editor', 'admin', and 'superadmin'", r.Name)
			}
		}
	}
	return nil
}

type userResponse struct {
	Links      selfLinks         `json:"links"`
	ID         uint64            `json:"id,string"`
	Name       string            `json:"name"`
	Provider   string            `json:"provider"`
	Scheme     string            `json:"scheme"`
	SuperAdmin bool              `json:"superAdmin"`
	Roles      []chronograf.Role `json:"roles"`
}

func newUserResponse(u *chronograf.User) *userResponse {
	// This ensures that any user response with no roles returns an empty array instead of
	// null when marshaled into JSON. That way, JavaScript doesn't need any guard on the
	// key existing and it can simply be iterated over.
	if u.Roles == nil {
		u.Roles = []chronograf.Role{}
	}
	return &userResponse{
		ID:       u.ID,
		Name:     u.Name,
		Provider: u.Provider,
		Scheme:   u.Scheme,
		Roles:    u.Roles,
		Links: selfLinks{
			Self: fmt.Sprintf("/chronograf/v1/users/%d", u.ID),
		},
	}
}

type usersResponse struct {
	Links selfLinks       `json:"links"`
	Users []*userResponse `json:"users"`
}

func newUsersResponse(users []chronograf.User) *usersResponse {
	usersResp := make([]*userResponse, len(users))
	for i, user := range users {
		usersResp[i] = newUserResponse(&user)
	}
	sort.Slice(usersResp, func(i, j int) bool {
		return usersResp[i].ID < usersResp[j].ID
	})
	return &usersResponse{
		Users: usersResp,
		Links: selfLinks{
			Self: "/chronograf/v1/users",
		},
	}
}

// Chronograf User Roles
const (
	MemberRoleName     = "member"
	ViewerRoleName     = "viewer"
	EditorRoleName     = "editor"
	AdminRoleName      = "admin"
	SuperAdminRoleName = "superadmin"
)

var (
	// MemberRole is the role for a user who can only perform No operations.
	MemberRole = chronograf.Role{
		Name: MemberRoleName,
	}

	// ViewerRole is the role for a user who can only perform READ operations on Dashboards, Rules, and Sources
	ViewerRole = chronograf.Role{
		Name: ViewerRoleName,
	}

	// EditorRole is the role for a user who can perform READ and WRITE operations on Dashboards, Rules, and Sources
	EditorRole = chronograf.Role{
		Name: EditorRoleName,
	}

	// AdminRole is the role for a user who can perform READ and WRITE operations on Dashboards, Rules, Sources, and Users
	AdminRole = chronograf.Role{
		Name: AdminRoleName,
	}
)

// UserID retrieves a Chronograf user with ID from store
func (s *Service) UserID(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	idStr := httprouter.GetParamFromContext(ctx, "id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		Error(w, http.StatusBadRequest, fmt.Sprintf("invalid user id: %s", err.Error()), s.Logger)
		return
	}
	user, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{ID: &id})
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	res := newUserResponse(user)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// NewUser adds a new Chronograf user to store
func (s *Service) NewUser(w http.ResponseWriter, r *http.Request) {
	var req userRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	if err := req.ValidCreate(); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	ctx := r.Context()
	user := &chronograf.User{
		Name:     req.Name,
		Provider: req.Provider,
		Scheme:   req.Scheme,
		Roles:    req.Roles,
	}

	// If req.SuperAdmin has been set, verify that it was done with the superadmin context.
	// Even though req.SuperAdmin == true is logically equivalent to req.SuperAdmin it is
	// more clear that this code should only be ran in the case that a user is trying to
	// set the SuperAdmin field.
	if req.SuperAdmin == true {
		// Only allow users to set SuperAdmin if they have the superadmin context
		if isSuperAdmin := hasSuperAdminContext(ctx); !isSuperAdmin {
			Error(w, http.StatusBadRequest, "Cannot set SuperAdmin", s.Logger)
			return
		}
		user.SuperAdmin = true
	}

	res, err := s.Store.Users(ctx).Add(ctx, user)
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	cu := newUserResponse(res)
	location(w, cu.Links.Self)
	encodeJSON(w, http.StatusCreated, cu, s.Logger)
}

// RemoveUser deletes a Chronograf user from store
func (s *Service) RemoveUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idStr := httprouter.GetParamFromContext(ctx, "id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		Error(w, http.StatusBadRequest, fmt.Sprintf("invalid user id: %s", err.Error()), s.Logger)
		return
	}

	u, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{ID: &id})
	if err != nil {
		Error(w, http.StatusNotFound, err.Error(), s.Logger)
		return
	}
	if err := s.Store.Users(ctx).Delete(ctx, u); err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// UpdateUser updates a Chronograf user in store
func (s *Service) UpdateUser(w http.ResponseWriter, r *http.Request) {
	var req userRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	if err := req.ValidUpdate(); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	ctx := r.Context()
	idStr := httprouter.GetParamFromContext(ctx, "id")
	id, err := strconv.ParseUint(idStr, 10, 64)
	if err != nil {
		Error(w, http.StatusBadRequest, fmt.Sprintf("invalid user id: %s", err.Error()), s.Logger)
		return
	}

	u, err := s.Store.Users(ctx).Get(ctx, chronograf.UserQuery{ID: &id})
	if err != nil {
		Error(w, http.StatusNotFound, err.Error(), s.Logger)
		return
	}

	// ValidUpdate should ensure that req.Roles is not nil
	u.Roles = req.Roles

	// If req.SuperAdmin has been set, verify that it was done with the superadmin context.
	// Even though req.SuperAdmin == true is logically equivalent to req.SuperAdmin it is
	// more clear that this code should only be ran in the case that a user is trying to
	// set the SuperAdmin field.
	if req.SuperAdmin == true {
		// Only allow users to set SuperAdmin if they have the superadmin context
		if isSuperAdmin := hasSuperAdminContext(ctx); !isSuperAdmin {
			Error(w, http.StatusBadRequest, "Cannot set SuperAdmin", s.Logger)
			return
		}
		u.SuperAdmin = true
	}

	err = s.Store.Users(ctx).Update(ctx, u)
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	cu := newUserResponse(u)
	location(w, cu.Links.Self)
	encodeJSON(w, http.StatusOK, cu, s.Logger)
}

// Users retrieves all Chronograf users from store
func (s *Service) Users(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	users, err := s.Store.Users(ctx).All(ctx)
	if err != nil {
		Error(w, http.StatusBadRequest, err.Error(), s.Logger)
		return
	}

	res := newUsersResponse(users)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
<|endoftext|>


<commit_before>package ls

import (
	"fmt"

	"github.com/vmware/govmomi"

	"github.com/lymingtonprecision/quorra/cli"
	"github.com/lymingtonprecision/quorra/config"
	"github.com/lymingtonprecision/quorra/vsphere/vm"
)

type ls struct{}

func (cmd *ls) Summary() string {
	return "Lists all current nodes"
}

func (cmd *ls) Description() string {
	return cmd.Summary()
}

func (cmd *ls) Run(cl *govmomi.Client, c *config.Config, args []string) error {
	vms, err := vm.FindAll(cl, c)
	if err != nil {
		return err
	}

	if len(vms) > 0 {
		for _, vm := range vms {
			fmt.Printf("%v\n", vm.Object)
		}
	} else {
		fmt.Printf("* * *\nNo Managed VMs found\n* * *\n")
	}

	return nil
}

func init() {
	cli.RegisterCommand([]string{"node", "ls"}, &ls{})
}
<commit_msg>Change 'node ls' package to 'node', as the directory will contain other commands<commit_after>package node

import (
	"fmt"

	"github.com/vmware/govmomi"

	"github.com/lymingtonprecision/quorra/cli"
	"github.com/lymingtonprecision/quorra/config"
	"github.com/lymingtonprecision/quorra/vsphere/vm"
)

type ls struct{}

func (cmd *ls) Summary() string {
	return "Lists all current nodes"
}

func (cmd *ls) Description() string {
	return cmd.Summary()
}

func (cmd *ls) Run(cl *govmomi.Client, c *config.Config, args []string) error {
	vms, err := vm.FindAll(cl, c)
	if err != nil {
		return err
	}

	if len(vms) > 0 {
		for _, vm := range vms {
			fmt.Printf("%v\n", vm.Object)
		}
	} else {
		fmt.Printf("* * *\nNo Managed VMs found\n* * *\n")
	}

	return nil
}

func init() {
	cli.RegisterCommand([]string{"node", "ls"}, &ls{})
}
<|endoftext|>


<commit_before>package scene

import (
	"image/color"

	"golang.org/x/mobile/asset"

	"github.com/pankona/gomo-simra/simra"
	"github.com/pankona/phantomize/scene/config"
)

// result represents a scene object for result
type result struct {
	text         simra.Sprite
	currentStage int
	again        simra.Sprite
	next         simra.Sprite
	nextScene    simra.Driver
	bgm          simra.Audioer
}

// Initialize initializes result scene
// This is called from simra.
// simra.GetInstance().SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (r *result) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.ScreenWidth, config.ScreenHeight)

	// initialize sprites
	r.initialize()

	simra.LogDebug("[OUT]")
}

func (r *result) initialize() {
	initTextSprite(&r.text, "result",
		config.ScreenWidth, 80, config.ScreenWidth/2, config.ScreenHeight*4/6,
		60, color.RGBA{255, 0, 0, 255})
	initTextSprite(&r.again, "try again",
		config.ScreenWidth, 80, config.ScreenWidth/2, config.ScreenHeight*2/6,
		60, color.RGBA{255, 0, 0, 255})
	initTextSprite(&r.next, "go to next stage",
		config.ScreenWidth, 80, config.ScreenWidth/2, config.ScreenHeight*1/6,
		60, color.RGBA{255, 0, 0, 255})
	//simra.GetInstance().AddTouchListener(menu)
	r.again.AddTouchListener(&again{result: r})
	r.next.AddTouchListener(&next{result: r})

	r.bgm = simra.NewAudio()
	resource, err := asset.Open("bgm3.mp3")
	if err != nil {
		panic(err.Error())
	}
	r.bgm.Play(resource, true, func() {})
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (r *result) Drive() {
	// nop
	if r.nextScene != nil {
		simra.GetInstance().SetScene(r.nextScene)
	}
}

// OnTouchBegin is called when result scene is Touched.
func (r *result) OnTouchBegin(x, y float32) {
	// nop
}

// OnTouchMove is called when result scene is Touched and moved.
func (r *result) OnTouchMove(x, y float32) {
	// nop
}

// OnTouchEnd is called when result scene is Touched and it is released.
func (r *result) OnTouchEnd(x, y float32) {
	// nop
}

type again struct {
	*result
}

func (a *again) OnTouchEnd(x, y float32) {
	a.result.nextScene = &game{currentStage: a.result.currentStage}
}

type next struct {
	*result
}

func (n *next) OnTouchEnd(x, y float32) {
	n.result.nextScene = &briefing{currentStage: n.result.currentStage + 1}
}
<commit_msg>update result screen to show thank you for playing<commit_after>package scene

import (
	"image/color"

	"golang.org/x/mobile/asset"

	"github.com/pankona/gomo-simra/simra"
	"github.com/pankona/phantomize/scene/config"
)

// result represents a scene object for result
type result struct {
	text         simra.Sprite
	currentStage int
	again        simra.Sprite
	nextScene    simra.Driver
	bgm          simra.Audioer
}

// Initialize initializes result scene
// This is called from simra.
// simra.GetInstance().SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (r *result) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.ScreenWidth, config.ScreenHeight)

	// initialize sprites
	r.initialize()

	simra.LogDebug("[OUT]")
}

func (r *result) initialize() {
	initTextSprite(&r.text, "Thank you for playing!",
		config.ScreenWidth, 80, config.ScreenWidth/2, config.ScreenHeight*4/6,
		60, color.RGBA{255, 0, 0, 255})
	initTextSprite(&r.again, "try again?",
		config.ScreenWidth, 80, config.ScreenWidth/2, config.ScreenHeight*2/6,
		60, color.RGBA{255, 0, 0, 255})

	//simra.GetInstance().AddTouchListener(menu)
	r.again.AddTouchListener(&again{result: r})

	r.bgm = simra.NewAudio()
	resource, err := asset.Open("bgm3.mp3")
	if err != nil {
		panic(err.Error())
	}
	r.bgm.Play(resource, true, func() {})
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (r *result) Drive() {
	// nop
	if r.nextScene != nil {
		r.bgm.Stop()
		simra.GetInstance().SetScene(r.nextScene)
	}
}

// OnTouchBegin is called when result scene is Touched.
func (r *result) OnTouchBegin(x, y float32) {
	// nop
}

// OnTouchMove is called when result scene is Touched and moved.
func (r *result) OnTouchMove(x, y float32) {
	// nop
}

// OnTouchEnd is called when result scene is Touched and it is released.
func (r *result) OnTouchEnd(x, y float32) {
	// nop
}

type again struct {
	*result
}

func (a *again) OnTouchEnd(x, y float32) {
	a.result.nextScene = &game{currentStage: a.result.currentStage}
}

type next struct {
	*result
}

func (n *next) OnTouchEnd(x, y float32) {
	n.result.nextScene = &briefing{currentStage: n.result.currentStage + 1}
}
<|endoftext|>


<commit_before>package common

import (
	"crypto/sha1"
	"encoding/hex"
	"log"
	"sync"
)

type LocalNode struct {
	Node

	config *Config
	state  *State

	mutex     sync.Mutex
	waitGroup sync.WaitGroup

	services []Service
}

func NewLocalNode(cfg *Config) *LocalNode {
	n := new(LocalNode)
	n.config = cfg
	n.state = &State{}
	n.services = append(n.services, &STUNService{})
	n.services = append(n.services, &DiscoveryDHT{})
	n.services = append(n.services, &UPnPService{})
	return n
}

func (n *LocalNode) Config() Config {
	return *n.config
}

func (n *LocalNode) State() State {
	return *n.state
}

func (n *LocalNode) Start() error {
	serviceCounter := 0
	for _, service := range n.services {
		err := service.Init(n)
		if err != nil {
			log.Printf("[%s] init error: %s", service.Name(), err)
			continue
		}
		serviceCounter++
	}
	n.waitGroup.Add(serviceCounter)
	for _, service := range n.services {
		go func() {
			defer n.waitGroup.Done()
			err := service.Run()
			if err != nil {
				log.Printf("service [%s] error: %s")
			}
		}()
	}
	return nil
}

func (n *LocalNode) Stop() error {
	for _, service := range n.services {
		service.Stop()
	}
	n.waitGroup.Wait()
	return nil
}

func hashSecretKey(key string) string {
	hashBytes := sha1.Sum([]byte(key))
	return hex.EncodeToString(hashBytes[:])
}
<commit_msg>cli join changes<commit_after>package common

import (
	"crypto/sha1"
	"encoding/hex"
	"log"
	"sync"
)

type LocalNode struct {
	Node

	config *Config
	state  *State

	mutex     sync.Mutex
	waitGroup sync.WaitGroup

	services []Service
}

func NewLocalNode(cfg *Config) *LocalNode {
	n := new(LocalNode)
	n.config = cfg
	n.state = &State{}
	n.services = append(n.services, &DiscoveryDHT{})
	//n.services = append(n.services, &STUNService{})
	//n.services = append(n.services, &UPnPService{})
	return n
}

func (n *LocalNode) Config() Config {
	return *n.config
}

func (n *LocalNode) State() State {
	return *n.state
}

func (n *LocalNode) Start() error {
	serviceCounter := 0
	for _, service := range n.services {
		log.Printf("[%s] service init")
		err := service.Init(n)
		if err != nil {
			log.Printf("[%s] init error: %s", service.Name(), err)
			continue
		}
		serviceCounter++
	}
	n.waitGroup.Add(serviceCounter)
	for _, service := range n.services {
		go func() {
			defer n.waitGroup.Done()
			log.Printf("[%s] service run")
			err := service.Run()
			if err != nil {
				log.Printf("service [%s] error: %s")
			}
		}()
	}
	return nil
}

func (n *LocalNode) Stop() error {
	for _, service := range n.services {
		service.Stop()
	}
	n.waitGroup.Wait()
	return nil
}

func hashSecretKey(key string) string {
	hashBytes := sha1.Sum([]byte(key))
	return hex.EncodeToString(hashBytes[:])
}
<|endoftext|>


<commit_before>package psh

import (
	"os"
	"os/exec"
)

func Sh(cmd string) sh {
	var cmdt commandTemplate
	cmdt.cmd = cmd
	return enclose(&cmdt)
}

type sh func(args ...interface{}) sh

// private type, used exactly once to create a const nobody else can create so we can use it as a flag to trigger private behavior
type expose_t bool

const expose expose_t = true

type exposer struct{ cmdt *commandTemplate }

func closure(cmdt commandTemplate, args ...interface{}) sh {
	if len(args) == 0 {
		// an empty call is a trigger for actually starting execution.
		bareCmd := exec.Command(cmdt.cmd, cmdt.args...)
		// set up direct stdin by hack for now
		bareCmd.Stdin = os.Stdin
		bareCmd.Stdout = os.Stdout
		bareCmd.Stderr = os.Stderr
		cmd := NewRunningCommand(bareCmd)
		cmd.Start()
		cmd.Wait()
		return nil
	} else if args[0] == expose {
		// produce a function that when called with an exposer, exposes its cmdt.
		return func(x ...interface{}) sh {
			t := x[0].(*exposer)
			t.cmdt = &cmdt
			return nil
		}
	} else {
		// examine each of the arguments, modify our (already forked) cmdt, and
		//  return a new callable sh closure with the newly baked command template.
		for _, rarg := range args {
			switch arg := rarg.(type) {
			case string:
				cmdt.bakeArgs(arg)
			default:
				panic(IncomprehensibleCommandModifier{wat: &rarg})
			}
		}
		return enclose(&cmdt)
	}
}

func (f sh) expose() commandTemplate {
	var t exposer
	f(expose)(&t)
	return *t.cmdt
}

func enclose(cmdt *commandTemplate) sh {
	return func(x ...interface{}) sh {
		return closure(*cmdt, x...)
	}
}

func (f sh) BakeArgs(args ...string) sh {
	cmdt := f.expose()
	cmdt.bakeArgs(args...)
	return enclose(&cmdt)
}

func (cmdt *commandTemplate) bakeArgs(args ...string) {
	cmdt.args = append(cmdt.args, args...)
}
<commit_msg>implement sh.Start(), which spawns a RunningCommand from the pattern you've set up and returns a reference to it.<commit_after>package psh

import (
	"os"
	"os/exec"
)

func Sh(cmd string) sh {
	var cmdt commandTemplate
	cmdt.cmd = cmd
	return enclose(&cmdt)
}

type sh func(args ...interface{}) sh

// private type, used exactly once to create a const nobody else can create so we can use it as a flag to trigger private behavior
type expose_t bool

const expose expose_t = true

type exposer struct{ cmdt *commandTemplate }

func closure(cmdt commandTemplate, args ...interface{}) sh {
	if len(args) == 0 {
		// an empty call is a trigger for actually starting execution.
		bareCmd := exec.Command(cmdt.cmd, cmdt.args...)
		// set up direct stdin by hack for now
		bareCmd.Stdin = os.Stdin
		bareCmd.Stdout = os.Stdout
		bareCmd.Stderr = os.Stderr
		cmd := NewRunningCommand(bareCmd)
		cmd.Start()
		cmd.Wait()
		return nil
	} else if args[0] == expose {
		// produce a function that when called with an exposer, exposes its cmdt.
		return func(x ...interface{}) sh {
			t := x[0].(*exposer)
			t.cmdt = &cmdt
			return nil
		}
	} else {
		// examine each of the arguments, modify our (already forked) cmdt, and
		//  return a new callable sh closure with the newly baked command template.
		for _, rarg := range args {
			switch arg := rarg.(type) {
			case string:
				cmdt.bakeArgs(arg)
			default:
				panic(IncomprehensibleCommandModifier{wat: &rarg})
			}
		}
		return enclose(&cmdt)
	}
}

func (f sh) expose() commandTemplate {
	var t exposer
	f(expose)(&t)
	return *t.cmdt
}

func enclose(cmdt *commandTemplate) sh {
	return func(x ...interface{}) sh {
		return closure(*cmdt, x...)
	}
}

func (f sh) BakeArgs(args ...string) sh {
	cmdt := f.expose()
	cmdt.bakeArgs(args...)
	return enclose(&cmdt)
}

func (cmdt *commandTemplate) bakeArgs(args ...string) {
	cmdt.args = append(cmdt.args, args...)
}

/**
 * Starts execution of the command.  Returns a reference to a RunningCommand,
 * which can be used to track execution of the command, configure exit listeners,
 * etc.
 */
func (f sh) Start() *RunningCommand {
	cmdt := f.expose()
	rcmd := exec.Command(cmdt.cmd, cmdt.args...)
	cmd := NewRunningCommand(rcmd)
	cmd.Start()
	return cmd
}
<|endoftext|>


<commit_before>package putio

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

const (
	defaultUserAgent = "go-putio"
	defaultMediaType = "application/json"
	defaultBaseURL   = "https://api.put.io"
	defaultUploadURL = "https://upload.put.io"
)

// Client manages communication with Put.io v2 API.
type Client struct {
	// HTTP client used to communicate with Put.io API
	client *http.Client

	// Base URL for API requests
	BaseURL *url.URL

	// base url for upload requests
	uploadURL *url.URL

	// User agent for client
	UserAgent string

	// ExtraHeaders are passed to the API server on every request.
	ExtraHeaders http.Header

	// Services used for communicating with the API
	Account   *AccountService
	Files     *FilesService
	Transfers *TransfersService
	Zips      *ZipsService
	Friends   *FriendsService
	Events    *EventsService
}

// NewClient returns a new Put.io API client, using the htttpClient, which must
// be a new Oauth2 enabled http.Client. If httpClient is not defined, default
// HTTP client is used.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	baseURL, _ := url.Parse(defaultBaseURL)
	uploadURL, _ := url.Parse(defaultUploadURL)
	c := &Client{
		client:       httpClient,
		BaseURL:      baseURL,
		uploadURL:    uploadURL,
		UserAgent:    defaultUserAgent,
		ExtraHeaders: make(http.Header),
	}

	c.Account = &AccountService{client: c}
	c.Files = &FilesService{client: c}
	c.Transfers = &TransfersService{client: c}
	c.Zips = &ZipsService{client: c}
	c.Friends = &FriendsService{client: c}
	c.Events = &EventsService{client: c}

	return c
}

func (c *Client) ValidateToken(ctx context.Context) (ok bool, err error) {
	req, err := c.NewRequest(ctx, "GET", "/v2/oauth2/validate", nil)
	if err != nil {
		return
	}
	var r struct {
		Result bool `json:"result"`
	}
	_, err = c.Do(req, &r)
	return r.Result, err
}

// NewRequest creates an API request. A relative URL can be provided via
// relURL, which will be resolved to the BaseURL of the Client.
func (c *Client) NewRequest(ctx context.Context, method, relURL string, body io.Reader) (*http.Request, error) {
	rel, err := url.Parse(relURL)
	if err != nil {
		return nil, err
	}

	var u *url.URL
	// XXX: workaroud for upload endpoint. upload method has a different base url,
	// so we've a special case for testing purposes.
	if relURL == "/v2/files/upload" {
		u = c.uploadURL.ResolveReference(rel)
	} else {
		u = c.BaseURL.ResolveReference(rel)
	}

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req = req.WithContext(ctx)
	req.Header.Set("Accept", defaultMediaType)
	req.Header.Set("User-Agent", c.UserAgent)

	// merge headers with extra headers
	for header, values := range c.ExtraHeaders {
		for _, value := range values {
			req.Header.Add(header, value)
		}
	}

	return req, nil
}

// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. Response body is closed at all cases except
// v is nil. If v is nil, response body is not closed and the body can be used
// for streaming.
func (c *Client) Do(r *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(r)
	if err != nil {
		return nil, err
	}

	err = checkResponse(resp)
	if err != nil {
		// close the body at all times if there is an http error
		resp.Body.Close()
		return resp, err
	}

	if v == nil {
		return resp, nil
	}

	// close the body for all cases from here
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(v)
	if err != nil {
		return resp, err
	}

	return resp, nil
}

// checkResponse is the entrypoint to reading the API response. If the response
// status code is not in success range, it will try to return a structured
// error.
func checkResponse(r *http.Response) error {
	status := r.StatusCode
	switch {
	case status >= 200 && status <= 399:
		return nil
	case status >= 400 && status <= 599:
		// server returns json
	default:
		return fmt.Errorf("unexpected status code: %d", status)
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return fmt.Errorf("body read error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
	}
	if len(data) > 0 {
		err = json.Unmarshal(data, errorResponse)
		if err != nil {
			return fmt.Errorf("json decod error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
		}
	}
	return errorResponse
}
<commit_msg>validate token method returns user id<commit_after>package putio

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

const (
	defaultUserAgent = "go-putio"
	defaultMediaType = "application/json"
	defaultBaseURL   = "https://api.put.io"
	defaultUploadURL = "https://upload.put.io"
)

// Client manages communication with Put.io v2 API.
type Client struct {
	// HTTP client used to communicate with Put.io API
	client *http.Client

	// Base URL for API requests
	BaseURL *url.URL

	// base url for upload requests
	uploadURL *url.URL

	// User agent for client
	UserAgent string

	// ExtraHeaders are passed to the API server on every request.
	ExtraHeaders http.Header

	// Services used for communicating with the API
	Account   *AccountService
	Files     *FilesService
	Transfers *TransfersService
	Zips      *ZipsService
	Friends   *FriendsService
	Events    *EventsService
}

// NewClient returns a new Put.io API client, using the htttpClient, which must
// be a new Oauth2 enabled http.Client. If httpClient is not defined, default
// HTTP client is used.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	baseURL, _ := url.Parse(defaultBaseURL)
	uploadURL, _ := url.Parse(defaultUploadURL)
	c := &Client{
		client:       httpClient,
		BaseURL:      baseURL,
		uploadURL:    uploadURL,
		UserAgent:    defaultUserAgent,
		ExtraHeaders: make(http.Header),
	}

	c.Account = &AccountService{client: c}
	c.Files = &FilesService{client: c}
	c.Transfers = &TransfersService{client: c}
	c.Zips = &ZipsService{client: c}
	c.Friends = &FriendsService{client: c}
	c.Events = &EventsService{client: c}

	return c
}

func (c *Client) ValidateToken(ctx context.Context) (userID *int64, err error) {
	req, err := c.NewRequest(ctx, "GET", "/v2/oauth2/validate", nil)
	if err != nil {
		return
	}
	var r struct {
		UserID *int64 `json:"user_id"`
	}
	_, err = c.Do(req, &r)
	return r.UserID, err
}

// NewRequest creates an API request. A relative URL can be provided via
// relURL, which will be resolved to the BaseURL of the Client.
func (c *Client) NewRequest(ctx context.Context, method, relURL string, body io.Reader) (*http.Request, error) {
	rel, err := url.Parse(relURL)
	if err != nil {
		return nil, err
	}

	var u *url.URL
	// XXX: workaroud for upload endpoint. upload method has a different base url,
	// so we've a special case for testing purposes.
	if relURL == "/v2/files/upload" {
		u = c.uploadURL.ResolveReference(rel)
	} else {
		u = c.BaseURL.ResolveReference(rel)
	}

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req = req.WithContext(ctx)
	req.Header.Set("Accept", defaultMediaType)
	req.Header.Set("User-Agent", c.UserAgent)

	// merge headers with extra headers
	for header, values := range c.ExtraHeaders {
		for _, value := range values {
			req.Header.Add(header, value)
		}
	}

	return req, nil
}

// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. Response body is closed at all cases except
// v is nil. If v is nil, response body is not closed and the body can be used
// for streaming.
func (c *Client) Do(r *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(r)
	if err != nil {
		return nil, err
	}

	err = checkResponse(resp)
	if err != nil {
		// close the body at all times if there is an http error
		resp.Body.Close()
		return resp, err
	}

	if v == nil {
		return resp, nil
	}

	// close the body for all cases from here
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(v)
	if err != nil {
		return resp, err
	}

	return resp, nil
}

// checkResponse is the entrypoint to reading the API response. If the response
// status code is not in success range, it will try to return a structured
// error.
func checkResponse(r *http.Response) error {
	status := r.StatusCode
	switch {
	case status >= 200 && status <= 399:
		return nil
	case status >= 400 && status <= 599:
		// server returns json
	default:
		return fmt.Errorf("unexpected status code: %d", status)
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return fmt.Errorf("body read error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
	}
	if len(data) > 0 {
		err = json.Unmarshal(data, errorResponse)
		if err != nil {
			return fmt.Errorf("json decod error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
		}
	}
	return errorResponse
}
<|endoftext|>


<commit_before><commit_msg>init functionality beginnings<commit_after><|endoftext|>


<commit_before>package QesyDb

import (
	"database/sql"
	"fmt"
	"github.com/Qesy/QesyGo"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var Db *sql.DB
var OpenLog int = 0

type Model struct {
	Cond    interface{}
	Insert  map[string]string
	Update  map[string]string
	Field   string
	Table   string
	Index   string
	Limit   interface{}
	Sort    string
	GroupBy string
	IsDeug  int
	Tx      *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string) {
	sqlDb, err := sql.Open("mysql", connStr)
	//defer sqlDb.Close()
	sqlDb.SetConnMaxLifetime(1800)
	sqlDb.SetMaxIdleConns(0)
	sqlDb.SetMaxOpenConns(600)
	if err != nil {
		log.Fatal("mysql connect error")
	}
	err = sqlDb.Ping()
	if err != nil {
		log.Fatal("mysql ping error")
	}
	fmt.Println("mysql connect sueccss")
	Db = sqlDb
}

func Begin() (*sql.Tx, error) {
	return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
	return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
	return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
	resultsSlice, _ := m.execSelect()
	retArr := map[string]map[string]string{}
	for _, v := range resultsSlice {
		if v[m.Index] == "" {
			continue
		}
		retArr[v[m.Index]] = v
	}
	m.Clean()
	return retArr, nil
}

func (m *Model) ExecSelect() ([]map[string]string, error) {
	ret, err := m.execSelect()
	m.Clean()
	return ret, err
}

// ExecSelect is a method with a sql.
func (m *Model) execSelect() ([]map[string]string, error) {
	cond := m.getSQLCond()
	field := m.getSQLField()
	sort := m.getSort()
	groupby := m.getGroupBy()
	limit := m.getSQLLimite()
	sqlStr := "SELECT " + field + " FROM " + m.Table + cond + groupby + sort + limit + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	resultsSlice := []map[string]string{}
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	}
	//defer stmt.Close()

	rows, err := stmt.Query()
	defer rows.Close()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}
	fields, err := rows.Columns()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}

	for rows.Next() {
		result := make(map[string]string)
		var scanResultContainers []interface{}
		for i := 0; i < len(fields); i++ {
			var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
		}
		if err := rows.Scan(scanResultContainers...); err != nil {
			return resultsSlice, err
		}
		for k, v := range fields {
			rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
			if rawValue.Interface() == nil {
				continue
			}
			rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
			var str string
			switch rawType.Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				str = strconv.FormatInt(rawVal.Int(), 10)
				result[v] = str
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				str = strconv.FormatUint(rawVal.Uint(), 10)
				result[v] = str
			case reflect.Float32, reflect.Float64:
				str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
				result[v] = str
			case reflect.Slice:
				if rawType.Elem().Kind() == reflect.Uint8 {
					result[v] = string(rawVal.Interface().([]byte))
					break
				}
			case reflect.String:
				str = rawVal.String()
				result[v] = str
			case reflect.Struct:
				str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
				result[v] = str
			case reflect.Bool:
				if rawVal.Bool() {
					result[v] = "1"
				} else {
					result[v] = "0"
				}
			}
		}
		resultsSlice = append(resultsSlice, result)
	}
	return resultsSlice, nil
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
	m.SetLimit([2]int{0, 1})
	resultsSlice, err := m.ExecSelect()
	if len(resultsSlice) == 0 {
		return map[string]string{}, err
	}
	return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error) {
	updateStr := m.getSQLUpdate()
	condStr := m.getSQLCond()
	sqlStr := "UPDATE " + m.Table + " SET " + updateStr + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "REPLACE INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
	condStr := m.getSQLCond()
	sqlStr := "DELETE FROM " + m.Table + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) Exec(sqlStr string) (sql.Result, error) {
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func GetLastInsertId(result sql.Result) (int64, error) {
	return result.LastInsertId()
}

func GetRowsAffected(result sql.Result) (int64, error) {
	return result.RowsAffected()
}

func (m *Model) getSQLCond() string {
	if str, ok := m.Cond.(string); ok {
		return str
	}
	var strArr []string
	if arr, ok := m.Cond.(map[string]string); ok {
		var strArr []string
		for k, v := range arr {
			strArr = append(strArr, k+"='"+v+"'")
		}
		if len(strArr) == 0 {
			return ""
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	if arr, ok := m.Cond.(map[string]interface{}); ok {
		for k, v := range arr {
			if isStr, ok := v.(string); ok {
				strArr = append(strArr, k+"='"+isStr+"'")
			}
			if isStrArrTmp, ok := v.([]string); ok {
				isStrArr := make([]string, len(isStrArrTmp))
				copy(isStrArr, isStrArrTmp)
				for k, v := range isStrArr {
					isStrArr[k] = "'" + v + "'"
				}
				if len(isStrArr) == 0 {
					continue
				}
				strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
			}
		}
		if len(strArr) == 0 {
			return ""
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	return ""
}

func (m *Model) getSQLField() string {
	if m.Field != "" {
		return m.Field
	}
	return "*"
}

func (m *Model) getSort() string {
	if m.Sort != "" {
		return " ORDER BY " + m.Sort + " "
	}
	return ""
}

func (m *Model) getGroupBy() string {
	if m.GroupBy != "" {
		return " GROUP BY " + m.GroupBy + " "
	}
	return ""
}

func (m *Model) getSQLUpdate() string {
	var strArr []string
	for k, v := range m.Update {
		strArr = append(strArr, k+"='"+v+"'")
	}
	return strings.Join(strArr, ",")
}

func (m *Model) getSQLInsert() string {
	var fieldArr, valueArr []string
	for k, v := range m.Insert {
		fieldArr = append(fieldArr, k)
		valueArr = append(valueArr, "'"+v+"'")
	}
	return "(" + strings.Join(fieldArr, ",") + ") values (" + strings.Join(valueArr, ",") + ")"
}

func (m *Model) getSQLLimite() string {
	if strArr, ok := m.Limit.([2]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	if strArr, ok := m.Limit.([]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	return ""
}

func (m *Model) Clean() {
	m.Cond = nil
	m.Insert = nil
	m.Update = nil
	m.Field = ""
	m.Table = ""
	m.Index = ""
	m.Limit = nil
	m.Sort = ""
	m.GroupBy = ""
	m.IsDeug = 0
}

func (m *Model) Debug(sql string) {
	if m.IsDeug == 1 {
		fmt.Println(sql)
	}
}

func logRecord(str string) {
	if OpenLog == 0 {
		return
	}
	QesyGo.Log(str, "error")
}
<commit_msg>fix bug<commit_after>package QesyDb

import (
	"database/sql"
	"fmt"
	"github.com/Qesy/QesyGo"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var Db *sql.DB
var OpenLog int = 0

type Model struct {
	Cond    interface{}
	Insert  map[string]string
	Update  map[string]string
	Field   string
	Table   string
	Index   string
	Limit   interface{}
	Sort    string
	GroupBy string
	IsDeug  int
	Tx      *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string) {
	sqlDb, err := sql.Open("mysql", connStr)
	//defer sqlDb.Close()
	sqlDb.SetConnMaxLifetime(1800)
	sqlDb.SetMaxIdleConns(0)
	sqlDb.SetMaxOpenConns(600)
	if err != nil {
		log.Fatal("mysql connect error")
	}
	err = sqlDb.Ping()
	if err != nil {
		log.Fatal("mysql ping error")
	}
	QesyGo.Println("mysql connect sueccss")
	Db = sqlDb
}

func Begin() (*sql.Tx, error) {
	return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
	return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
	return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
	resultsSlice, _ := m.execSelect()
	retArr := map[string]map[string]string{}
	for _, v := range resultsSlice {
		if v[m.Index] == "" {
			continue
		}
		retArr[v[m.Index]] = v
	}
	m.Clean()
	return retArr, nil
}

func (m *Model) ExecSelect() ([]map[string]string, error) {
	ret, err := m.execSelect()
	m.Clean()
	return ret, err
}

// ExecSelect is a method with a sql.
func (m *Model) execSelect() ([]map[string]string, error) {
	cond := m.getSQLCond()
	field := m.getSQLField()
	sort := m.getSort()
	groupby := m.getGroupBy()
	limit := m.getSQLLimite()
	sqlStr := "SELECT " + field + " FROM " + m.Table + cond + groupby + sort + limit + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	resultsSlice := []map[string]string{}
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	}
	//defer stmt.Close()

	rows, err := stmt.Query()
	defer rows.Close()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}
	fields, err := rows.Columns()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}

	for rows.Next() {
		result := make(map[string]string)
		var scanResultContainers []interface{}
		for i := 0; i < len(fields); i++ {
			var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
		}
		if err := rows.Scan(scanResultContainers...); err != nil {
			return resultsSlice, err
		}
		for k, v := range fields {
			rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
			if rawValue.Interface() == nil {
				continue
			}
			rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
			var str string
			switch rawType.Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				str = strconv.FormatInt(rawVal.Int(), 10)
				result[v] = str
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				str = strconv.FormatUint(rawVal.Uint(), 10)
				result[v] = str
			case reflect.Float32, reflect.Float64:
				str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
				result[v] = str
			case reflect.Slice:
				if rawType.Elem().Kind() == reflect.Uint8 {
					result[v] = string(rawVal.Interface().([]byte))
					break
				}
			case reflect.String:
				str = rawVal.String()
				result[v] = str
			case reflect.Struct:
				str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
				result[v] = str
			case reflect.Bool:
				if rawVal.Bool() {
					result[v] = "1"
				} else {
					result[v] = "0"
				}
			}
		}
		resultsSlice = append(resultsSlice, result)
	}
	return resultsSlice, nil
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
	m.SetLimit([2]int{0, 1})
	resultsSlice, err := m.ExecSelect()
	if len(resultsSlice) == 0 {
		return map[string]string{}, err
	}
	return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error) {
	updateStr := m.getSQLUpdate()
	condStr := m.getSQLCond()
	sqlStr := "UPDATE " + m.Table + " SET " + updateStr + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "REPLACE INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
	condStr := m.getSQLCond()
	sqlStr := "DELETE FROM " + m.Table + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) Exec(sqlStr string) (sql.Result, error) {
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func GetLastInsertId(result sql.Result) (int64, error) {
	return result.LastInsertId()
}

func GetRowsAffected(result sql.Result) (int64, error) {
	return result.RowsAffected()
}

func (m *Model) getSQLCond() string {
	if str, ok := m.Cond.(string); ok {
		return str
	}
	var strArr []string
	if arr, ok := m.Cond.(map[string]string); ok {
		var strArr []string
		for k, v := range arr {
			strArr = append(strArr, k+"='"+v+"'")
		}
		if len(strArr) == 0 {
			return ""
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	if arr, ok := m.Cond.(map[string]interface{}); ok {
		for k, v := range arr {
			if isStr, ok := v.(string); ok {
				strArr = append(strArr, k+"='"+isStr+"'")
			}
			if isStrArrTmp, ok := v.([]string); ok {
				isStrArr := make([]string, len(isStrArrTmp))
				copy(isStrArr, isStrArrTmp)
				for k, v := range isStrArr {
					isStrArr[k] = "'" + v + "'"
				}
				if len(isStrArr) == 0 {
					continue
				}
				strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
			}
		}
		if len(strArr) == 0 {
			return ""
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	return ""
}

func (m *Model) getSQLField() string {
	if m.Field != "" {
		return m.Field
	}
	return "*"
}

func (m *Model) getSort() string {
	if m.Sort != "" {
		return " ORDER BY " + m.Sort + " "
	}
	return ""
}

func (m *Model) getGroupBy() string {
	if m.GroupBy != "" {
		return " GROUP BY " + m.GroupBy + " "
	}
	return ""
}

func (m *Model) getSQLUpdate() string {
	var strArr []string
	for k, v := range m.Update {
		strArr = append(strArr, k+"='"+v+"'")
	}
	return strings.Join(strArr, ",")
}

func (m *Model) getSQLInsert() string {
	var fieldArr, valueArr []string
	for k, v := range m.Insert {
		fieldArr = append(fieldArr, k)
		valueArr = append(valueArr, "'"+v+"'")
	}
	return "(" + strings.Join(fieldArr, ",") + ") values (" + strings.Join(valueArr, ",") + ")"
}

func (m *Model) getSQLLimite() string {
	if strArr, ok := m.Limit.([2]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	if strArr, ok := m.Limit.([]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	return ""
}

func (m *Model) Clean() {
	m.Cond = nil
	m.Insert = nil
	m.Update = nil
	m.Field = ""
	m.Table = ""
	m.Index = ""
	m.Limit = nil
	m.Sort = ""
	m.GroupBy = ""
	m.IsDeug = 0
}

func (m *Model) Debug(sql string) {
	if m.IsDeug == 1 {
		fmt.Println(sql)
	}
}

func logRecord(str string) {
	if OpenLog == 0 {
		return
	}
	QesyGo.Log(str, "error")
}
<|endoftext|>