<commit_before>package main

import (
	"os"
	"os/signal"
	"syscall"

	"github.com/libopenstorage/stork/drivers/volume"
	_ "github.com/libopenstorage/stork/drivers/volume/portworx"
	"github.com/libopenstorage/stork/pkg/extender"
	"github.com/libopenstorage/stork/pkg/monitor"
	log "github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "stork"
	app.Usage = "STorage Orchestartor Runtime for Kubernetes (STORK)"
	app.Version = "0.1"
	app.Action = run

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "Enable verbose logging",
		},
		cli.StringFlag{
			Name:  "driver,d",
			Usage: "Storage driver name",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatalf("Error starting stork: %v", err)
	}
}
func run(c *cli.Context) {
	driverName := c.String("driver")
	if len(driverName) == 0 {
		log.Fatalf("driver option is required")
		os.Exit(-1)
	}

	verbose := c.Bool("verbose")
	if verbose {
		log.SetLevel(log.DebugLevel)
	}

	d, err := volume.Get(driverName)
	if err != nil {
		log.Fatalf("Error getting Stork Driver %v: %v", driverName, err)
		os.Exit(-1)
	}

	if err = d.Init(); err != nil {
		log.Fatalf("Error initializing Stork Driver %v: %v", driverName, err)
		os.Exit(-1)
	}

	extender := &extender.Extender{
		Driver: d,
	}

	if err = extender.Start(); err != nil {
		log.Fatalf("Error starting scheduler extender: %v", err)
		os.Exit(-1)
	}

	monitor := &monitor.Monitor{
		Driver: d,
	}

	if err = monitor.Start(); err != nil {
		log.Fatalf("Error starting storage monitor: %v", err)
		os.Exit(-1)
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	for {
		select {
		case <-signalChan:
			log.Printf("Shutdown signal received, exiting...")
			if err := extender.Stop(); err != nil {
				log.Warnf("Error stopping extender: %v", err)
			}
			if err := monitor.Stop(); err != nil {
				log.Warnf("Error stopping monitor: %v", err)
			}
			os.Exit(0)
		}
	}
}
<commit_msg>Update version to 0.2<commit_after>package main

import (
	"os"
	"os/signal"
	"syscall"

	"github.com/libopenstorage/stork/drivers/volume"
	_ "github.com/libopenstorage/stork/drivers/volume/portworx"
	"github.com/libopenstorage/stork/pkg/extender"
	"github.com/libopenstorage/stork/pkg/monitor"
	log "github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "stork"
	app.Usage = "STorage Orchestartor Runtime for Kubernetes (STORK)"
	app.Version = "0.2"
	app.Action = run

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "Enable verbose logging",
		},
		cli.StringFlag{
			Name:  "driver,d",
			Usage: "Storage driver name",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatalf("Error starting stork: %v", err)
	}
}
func run(c *cli.Context) {
	driverName := c.String("driver")
	if len(driverName) == 0 {
		log.Fatalf("driver option is required")
		os.Exit(-1)
	}

	verbose := c.Bool("verbose")
	if verbose {
		log.SetLevel(log.DebugLevel)
	}

	d, err := volume.Get(driverName)
	if err != nil {
		log.Fatalf("Error getting Stork Driver %v: %v", driverName, err)
		os.Exit(-1)
	}

	if err = d.Init(); err != nil {
		log.Fatalf("Error initializing Stork Driver %v: %v", driverName, err)
		os.Exit(-1)
	}

	extender := &extender.Extender{
		Driver: d,
	}

	if err = extender.Start(); err != nil {
		log.Fatalf("Error starting scheduler extender: %v", err)
		os.Exit(-1)
	}

	monitor := &monitor.Monitor{
		Driver: d,
	}

	if err = monitor.Start(); err != nil {
		log.Fatalf("Error starting storage monitor: %v", err)
		os.Exit(-1)
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	for {
		select {
		case <-signalChan:
			log.Printf("Shutdown signal received, exiting...")
			if err := extender.Stop(); err != nil {
				log.Warnf("Error stopping extender: %v", err)
			}
			if err := monitor.Stop(); err != nil {
				log.Warnf("Error stopping monitor: %v", err)
			}
			os.Exit(0)
		}
	}
}
<|endoftext|>


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

// The worker command runs a service with the primary job of fetching modules
// from a proxy and writing them to the database.
package main

import (
	"bufio"
	"context"
	"flag"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"cloud.google.com/go/errorreporting"
	"cloud.google.com/go/profiler"
	"github.com/go-redis/redis/v7"
	"github.com/google/safehtml/template"
	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/config"
	"golang.org/x/pkgsite/internal/database"
	"golang.org/x/pkgsite/internal/dcensus"
	"golang.org/x/pkgsite/internal/index"
	"golang.org/x/pkgsite/internal/queue"
	"golang.org/x/pkgsite/internal/source"
	"golang.org/x/pkgsite/internal/worker"

	"golang.org/x/pkgsite/internal/log"
	"golang.org/x/pkgsite/internal/middleware"
	"golang.org/x/pkgsite/internal/postgres"
	"golang.org/x/pkgsite/internal/proxy"

	"contrib.go.opencensus.io/integrations/ocsql"
)

var (
	timeout   = config.GetEnv("GO_DISCOVERY_WORKER_TIMEOUT_MINUTES", "10")
	queueName = config.GetEnv("GO_DISCOVERY_WORKER_TASK_QUEUE", "")
	workers   = flag.Int("workers", 10, "number of concurrent requests to the fetch service, when running locally")
	// flag used in call to safehtml/template.TrustedSourceFromFlag
	_                  = flag.String("static", "content/static", "path to folder containing static files served")
	bypassLicenseCheck = flag.Bool("bypass_license_check", false, "insert all data into the DB, even for non-redistributable paths")
)

func main() {
	flag.Parse()

	ctx := context.Background()

	cfg, err := config.Init(ctx)
	if err != nil {
		log.Fatal(ctx, err)
	}
	cfg.Dump(os.Stderr)

	log.SetLevel(cfg.LogLevel)

	if cfg.UseProfiler {
		if err := profiler.Start(profiler.Config{}); err != nil {
			log.Fatalf(ctx, "profiler.Start: %v", err)
		}
	}

	readProxyRemoved(ctx)

	// Wrap the postgres driver with OpenCensus instrumentation.
	driverName, err := ocsql.Register("postgres", ocsql.WithAllTraceOptions())
	if err != nil {
		log.Fatalf(ctx, "unable to register the ocsql driver: %v\n", err)
	}
	ddb, err := database.Open(driverName, cfg.DBConnInfo(), cfg.InstanceID)
	if err != nil {
		log.Fatalf(ctx, "database.Open: %v", err)
	}
	var db *postgres.DB
	if *bypassLicenseCheck {
		db = postgres.NewBypassingLicenseCheck(ddb)
	} else {
		db = postgres.New(ddb)
	}
	defer db.Close()

	populateExcluded(ctx, db)

	indexClient, err := index.New(cfg.IndexURL)
	if err != nil {
		log.Fatal(ctx, err)
	}
	proxyClient, err := proxy.New(cfg.ProxyURL)
	if err != nil {
		log.Fatal(ctx, err)
	}
	sourceClient := source.NewClient(config.SourceTimeout)
	fetchQueue, err := queue.New(ctx, cfg, queueName, *workers, db,
		func(ctx context.Context, modulePath, version string) (int, error) {
			return worker.FetchAndUpdateState(ctx, modulePath, version, proxyClient, sourceClient, db, cfg.AppVersionLabel())
		})
	if err != nil {
		log.Fatalf(ctx, "queue.New: %v", err)
	}

	reportingClient := reportingClient(ctx, cfg)
	redisHAClient := getHARedis(ctx, cfg)
	redisCacheClient := getCacheRedis(ctx, cfg)
	server, err := worker.NewServer(cfg, worker.ServerConfig{
		DB:                   db,
		IndexClient:          indexClient,
		ProxyClient:          proxyClient,
		SourceClient:         sourceClient,
		RedisHAClient:        redisHAClient,
		RedisCacheClient:     redisCacheClient,
		Queue:                fetchQueue,
		ReportingClient:      reportingClient,
		TaskIDChangeInterval: config.TaskIDChangeIntervalWorker,
		StaticPath:           template.TrustedSourceFromFlag(flag.Lookup("static").Value),
	})
	if err != nil {
		log.Fatal(ctx, err)
	}
	router := dcensus.NewRouter(nil)
	server.Install(router.Handle)

	views := append(dcensus.ServerViews, worker.EnqueueResponseCount)
	if err := dcensus.Init(cfg, views...); err != nil {
		log.Fatal(ctx, err)
	}
	// We are not currently forwarding any ports on AppEngine, so serving debug
	// information is broken.
	if !cfg.OnAppEngine() {
		dcensusServer, err := dcensus.NewServer()
		if err != nil {
			log.Fatal(ctx, err)
		}
		go http.ListenAndServe(cfg.DebugAddr("localhost:8001"), dcensusServer)
	}

	handlerTimeout, err := strconv.Atoi(timeout)
	if err != nil {
		log.Fatalf(ctx, "strconv.Atoi(%q): %v", timeout, err)
	}
	requestLogger := logger(ctx, cfg)

	experimenter, err := middleware.NewExperimenter(ctx, 1*time.Minute, func(context.Context) internal.ExperimentSource { return db })
	if err != nil {
		log.Fatal(ctx, err)
	}
	mw := middleware.Chain(
		middleware.RequestLog(requestLogger),
		middleware.Timeout(time.Duration(handlerTimeout)*time.Minute),
		middleware.Experiment(experimenter),
	)
	http.Handle("/", mw(router))

	addr := cfg.HostAddr("localhost:8000")
	log.Infof(ctx, "Listening on addr %s", addr)
	log.Fatal(ctx, http.ListenAndServe(addr, nil))
}

func getHARedis(ctx context.Context, cfg *config.Config) *redis.Client {
	// We update completions with one big pipeline, so we need long write
	// timeouts. ReadTimeout is increased only to be consistent with
	// WriteTimeout.
	return getRedis(ctx, cfg.RedisHAHost, cfg.RedisHAPort, 5*time.Minute, 5*time.Minute)
}

func getCacheRedis(ctx context.Context, cfg *config.Config) *redis.Client {
	return getRedis(ctx, cfg.RedisCacheHost, cfg.RedisCachePort, 0, 0)
}

func getRedis(ctx context.Context, host, port string, writeTimeout, readTimeout time.Duration) *redis.Client {
	if host == "" {
		return nil
	}
	var dialTimeout time.Duration
	if dl, ok := ctx.Deadline(); ok {
		dialTimeout = time.Until(dl)
	}
	return redis.NewClient(&redis.Options{
		Addr:         host + ":" + port,
		DialTimeout:  dialTimeout,
		WriteTimeout: writeTimeout,
		ReadTimeout:  readTimeout,
	})
}

func reportingClient(ctx context.Context, cfg *config.Config) *errorreporting.Client {
	if !cfg.OnGCP() {
		return nil
	}
	reporter, err := errorreporting.NewClient(ctx, cfg.ProjectID, errorreporting.Config{
		ServiceName: cfg.ServiceID,
		OnError: func(err error) {
			log.Errorf(ctx, "Error reporting failed: %v", err)
		},
	})
	if err != nil {
		log.Fatal(ctx, err)
	}
	return reporter
}

func logger(ctx context.Context, cfg *config.Config) middleware.Logger {
	if cfg.OnGCP() {
		logger, err := log.UseStackdriver(ctx, cfg, "worker-log")
		if err != nil {
			log.Fatal(ctx, err)
		}
		return logger
	}
	return middleware.LocalLogger{}
}

// Read a file of module versions that we should ignore because
// the are in the index but not stored in the proxy.
// Format of the file: each line is
//     module@version
func readProxyRemoved(ctx context.Context) {
	filename := config.GetEnv("GO_DISCOVERY_PROXY_REMOVED", "")
	if filename == "" {
		return
	}
	lines, err := readFileLines(filename)
	if err != nil {
		log.Fatal(ctx, err)
	}
	for _, line := range lines {
		worker.ProxyRemoved[line] = true
	}
	log.Infof(ctx, "read %d excluded module versions from %s", len(worker.ProxyRemoved), filename)
}

// populateExcluded adds each element of excludedPrefixes to the excluded_prefixes
// table if it isn't already present.
func populateExcluded(ctx context.Context, db *postgres.DB) {
	filename := config.GetEnv("GO_DISCOVERY_EXCLUDED_FILENAME", "")
	if filename == "" {
		return
	}
	lines, err := readFileLines(filename)
	if err != nil {
		log.Fatal(ctx, err)
	}
	user := os.Getenv("USER")
	if user == "" {
		user = "worker"
	}
	for _, line := range lines {
		var prefix, reason string
		i := strings.IndexAny(line, " \t")
		if i >= 0 {
			prefix = line[:i]
			reason = strings.TrimSpace(line[i+1:])
		}
		if reason == "" {
			log.Fatalf(ctx, "missing reason in %s, line %q", filename, line)
		}
		present, err := db.IsExcluded(ctx, prefix)
		if err != nil {
			log.Fatalf(ctx, "db.IsExcluded(%q): %v", prefix, err)
		}
		if !present {
			if err := db.InsertExcludedPrefix(ctx, prefix, user, reason); err != nil {
				log.Fatalf(ctx, "db.InsertExcludedPrefix(%q, %q, %q): %v", prefix, user, reason, err)
			}
		}
	}
}

// readFileLines reads filename and returns its lines, trimmed of whitespace.
// Blank lines and lines whose first non-blank character is '#' are omitted.
func readFileLines(filename string) ([]string, error) {
	var lines []string
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	scan := bufio.NewScanner(f)
	for scan.Scan() {
		line := strings.TrimSpace(scan.Text())
		if line == "" || line[0] == '#' {
			continue
		}
		lines = append(lines, line)
	}
	if err := scan.Err(); err != nil {
		return nil, err
	}
	return lines, nil
}
<commit_msg>internal/worker: write config to stdout, not stderr<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The worker command runs a service with the primary job of fetching modules
// from a proxy and writing them to the database.
package main

import (
	"bufio"
	"context"
	"flag"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"cloud.google.com/go/errorreporting"
	"cloud.google.com/go/profiler"
	"github.com/go-redis/redis/v7"
	"github.com/google/safehtml/template"
	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/config"
	"golang.org/x/pkgsite/internal/database"
	"golang.org/x/pkgsite/internal/dcensus"
	"golang.org/x/pkgsite/internal/index"
	"golang.org/x/pkgsite/internal/queue"
	"golang.org/x/pkgsite/internal/source"
	"golang.org/x/pkgsite/internal/worker"

	"golang.org/x/pkgsite/internal/log"
	"golang.org/x/pkgsite/internal/middleware"
	"golang.org/x/pkgsite/internal/postgres"
	"golang.org/x/pkgsite/internal/proxy"

	"contrib.go.opencensus.io/integrations/ocsql"
)

var (
	timeout   = config.GetEnv("GO_DISCOVERY_WORKER_TIMEOUT_MINUTES", "10")
	queueName = config.GetEnv("GO_DISCOVERY_WORKER_TASK_QUEUE", "")
	workers   = flag.Int("workers", 10, "number of concurrent requests to the fetch service, when running locally")
	// flag used in call to safehtml/template.TrustedSourceFromFlag
	_                  = flag.String("static", "content/static", "path to folder containing static files served")
	bypassLicenseCheck = flag.Bool("bypass_license_check", false, "insert all data into the DB, even for non-redistributable paths")
)

func main() {
	flag.Parse()

	ctx := context.Background()

	cfg, err := config.Init(ctx)
	if err != nil {
		log.Fatal(ctx, err)
	}
	cfg.Dump(os.Stdout)

	log.SetLevel(cfg.LogLevel)

	if cfg.UseProfiler {
		if err := profiler.Start(profiler.Config{}); err != nil {
			log.Fatalf(ctx, "profiler.Start: %v", err)
		}
	}

	readProxyRemoved(ctx)

	// Wrap the postgres driver with OpenCensus instrumentation.
	driverName, err := ocsql.Register("postgres", ocsql.WithAllTraceOptions())
	if err != nil {
		log.Fatalf(ctx, "unable to register the ocsql driver: %v\n", err)
	}
	ddb, err := database.Open(driverName, cfg.DBConnInfo(), cfg.InstanceID)
	if err != nil {
		log.Fatalf(ctx, "database.Open: %v", err)
	}
	var db *postgres.DB
	if *bypassLicenseCheck {
		db = postgres.NewBypassingLicenseCheck(ddb)
	} else {
		db = postgres.New(ddb)
	}
	defer db.Close()

	populateExcluded(ctx, db)

	indexClient, err := index.New(cfg.IndexURL)
	if err != nil {
		log.Fatal(ctx, err)
	}
	proxyClient, err := proxy.New(cfg.ProxyURL)
	if err != nil {
		log.Fatal(ctx, err)
	}
	sourceClient := source.NewClient(config.SourceTimeout)
	fetchQueue, err := queue.New(ctx, cfg, queueName, *workers, db,
		func(ctx context.Context, modulePath, version string) (int, error) {
			return worker.FetchAndUpdateState(ctx, modulePath, version, proxyClient, sourceClient, db, cfg.AppVersionLabel())
		})
	if err != nil {
		log.Fatalf(ctx, "queue.New: %v", err)
	}

	reportingClient := reportingClient(ctx, cfg)
	redisHAClient := getHARedis(ctx, cfg)
	redisCacheClient := getCacheRedis(ctx, cfg)
	server, err := worker.NewServer(cfg, worker.ServerConfig{
		DB:                   db,
		IndexClient:          indexClient,
		ProxyClient:          proxyClient,
		SourceClient:         sourceClient,
		RedisHAClient:        redisHAClient,
		RedisCacheClient:     redisCacheClient,
		Queue:                fetchQueue,
		ReportingClient:      reportingClient,
		TaskIDChangeInterval: config.TaskIDChangeIntervalWorker,
		StaticPath:           template.TrustedSourceFromFlag(flag.Lookup("static").Value),
	})
	if err != nil {
		log.Fatal(ctx, err)
	}
	router := dcensus.NewRouter(nil)
	server.Install(router.Handle)

	views := append(dcensus.ServerViews, worker.EnqueueResponseCount)
	if err := dcensus.Init(cfg, views...); err != nil {
		log.Fatal(ctx, err)
	}
	// We are not currently forwarding any ports on AppEngine, so serving debug
	// information is broken.
	if !cfg.OnAppEngine() {
		dcensusServer, err := dcensus.NewServer()
		if err != nil {
			log.Fatal(ctx, err)
		}
		go http.ListenAndServe(cfg.DebugAddr("localhost:8001"), dcensusServer)
	}

	handlerTimeout, err := strconv.Atoi(timeout)
	if err != nil {
		log.Fatalf(ctx, "strconv.Atoi(%q): %v", timeout, err)
	}
	requestLogger := logger(ctx, cfg)

	experimenter, err := middleware.NewExperimenter(ctx, 1*time.Minute, func(context.Context) internal.ExperimentSource { return db })
	if err != nil {
		log.Fatal(ctx, err)
	}
	mw := middleware.Chain(
		middleware.RequestLog(requestLogger),
		middleware.Timeout(time.Duration(handlerTimeout)*time.Minute),
		middleware.Experiment(experimenter),
	)
	http.Handle("/", mw(router))

	addr := cfg.HostAddr("localhost:8000")
	log.Infof(ctx, "Listening on addr %s", addr)
	log.Fatal(ctx, http.ListenAndServe(addr, nil))
}

func getHARedis(ctx context.Context, cfg *config.Config) *redis.Client {
	// We update completions with one big pipeline, so we need long write
	// timeouts. ReadTimeout is increased only to be consistent with
	// WriteTimeout.
	return getRedis(ctx, cfg.RedisHAHost, cfg.RedisHAPort, 5*time.Minute, 5*time.Minute)
}

func getCacheRedis(ctx context.Context, cfg *config.Config) *redis.Client {
	return getRedis(ctx, cfg.RedisCacheHost, cfg.RedisCachePort, 0, 0)
}

func getRedis(ctx context.Context, host, port string, writeTimeout, readTimeout time.Duration) *redis.Client {
	if host == "" {
		return nil
	}
	var dialTimeout time.Duration
	if dl, ok := ctx.Deadline(); ok {
		dialTimeout = time.Until(dl)
	}
	return redis.NewClient(&redis.Options{
		Addr:         host + ":" + port,
		DialTimeout:  dialTimeout,
		WriteTimeout: writeTimeout,
		ReadTimeout:  readTimeout,
	})
}

func reportingClient(ctx context.Context, cfg *config.Config) *errorreporting.Client {
	if !cfg.OnGCP() {
		return nil
	}
	reporter, err := errorreporting.NewClient(ctx, cfg.ProjectID, errorreporting.Config{
		ServiceName: cfg.ServiceID,
		OnError: func(err error) {
			log.Errorf(ctx, "Error reporting failed: %v", err)
		},
	})
	if err != nil {
		log.Fatal(ctx, err)
	}
	return reporter
}

func logger(ctx context.Context, cfg *config.Config) middleware.Logger {
	if cfg.OnGCP() {
		logger, err := log.UseStackdriver(ctx, cfg, "worker-log")
		if err != nil {
			log.Fatal(ctx, err)
		}
		return logger
	}
	return middleware.LocalLogger{}
}

// Read a file of module versions that we should ignore because
// the are in the index but not stored in the proxy.
// Format of the file: each line is
//     module@version
func readProxyRemoved(ctx context.Context) {
	filename := config.GetEnv("GO_DISCOVERY_PROXY_REMOVED", "")
	if filename == "" {
		return
	}
	lines, err := readFileLines(filename)
	if err != nil {
		log.Fatal(ctx, err)
	}
	for _, line := range lines {
		worker.ProxyRemoved[line] = true
	}
	log.Infof(ctx, "read %d excluded module versions from %s", len(worker.ProxyRemoved), filename)
}

// populateExcluded adds each element of excludedPrefixes to the excluded_prefixes
// table if it isn't already present.
func populateExcluded(ctx context.Context, db *postgres.DB) {
	filename := config.GetEnv("GO_DISCOVERY_EXCLUDED_FILENAME", "")
	if filename == "" {
		return
	}
	lines, err := readFileLines(filename)
	if err != nil {
		log.Fatal(ctx, err)
	}
	user := os.Getenv("USER")
	if user == "" {
		user = "worker"
	}
	for _, line := range lines {
		var prefix, reason string
		i := strings.IndexAny(line, " \t")
		if i >= 0 {
			prefix = line[:i]
			reason = strings.TrimSpace(line[i+1:])
		}
		if reason == "" {
			log.Fatalf(ctx, "missing reason in %s, line %q", filename, line)
		}
		present, err := db.IsExcluded(ctx, prefix)
		if err != nil {
			log.Fatalf(ctx, "db.IsExcluded(%q): %v", prefix, err)
		}
		if !present {
			if err := db.InsertExcludedPrefix(ctx, prefix, user, reason); err != nil {
				log.Fatalf(ctx, "db.InsertExcludedPrefix(%q, %q, %q): %v", prefix, user, reason, err)
			}
		}
	}
}

// readFileLines reads filename and returns its lines, trimmed of whitespace.
// Blank lines and lines whose first non-blank character is '#' are omitted.
func readFileLines(filename string) ([]string, error) {
	var lines []string
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	scan := bufio.NewScanner(f)
	for scan.Scan() {
		line := strings.TrimSpace(scan.Text())
		if line == "" || line[0] == '#' {
			continue
		}
		lines = append(lines, line)
	}
	if err := scan.Err(); err != nil {
		return nil, err
	}
	return lines, nil
}
<|endoftext|>


<commit_before>package common

import (
	"github.com/EngoEngine/ecs"
	"github.com/EngoEngine/engo"
	"github.com/EngoEngine/gl"
	"image/color"
	"reflect"
	"sort"
	"sync"
	"unsafe"
)

const (
	// RenderSystemPriority is the priority of the RenderSystem
	RenderSystemPriority = -1000
)

type renderChangeMessage struct{}

func (renderChangeMessage) Type() string {
	return "renderChangeMessage"
}

// Drawable is that which can be rendered to OpenGL.
type Drawable interface {
	Texture() *gl.Texture
	Width() float32
	Height() float32
	View() (float32, float32, float32, float32)
	Close()
}

// TextureRepeating is the method used to repeat a texture in OpenGL.
type TextureRepeating uint8

const (
	// NoRepeat does not repeat the texture.
	NoRepeat TextureRepeating = iota
	// ClampToEdge stretches the texture to the edge of the viewport.
	ClampToEdge
	// ClampToBorder stretches the texture to the border of the viewpport.
	ClampToBorder
	// Repeat repeats the texture until the border of the viewport.
	Repeat
	// MirroredRepeat repeats a mirror image of the texture until the border of the viewport.
	MirroredRepeat
)

// ZoomFilter is a filter used when zooming in or out of a texture.
type ZoomFilter uint8

const (
	// FilterNearest is a simple nearest neighbor algorithm
	FilterNearest ZoomFilter = iota
	// FilterLinear is a bilinear interpolation algorithm
	FilterLinear
)

// RenderComponent is the component needed to render an entity.
type RenderComponent struct {
	// Hidden is used to prevent drawing by OpenGL
	Hidden bool
	// Scale is the scale at which to render, in the X and Y axis. Not defining Scale, will default to engo.Point{1, 1}
	Scale engo.Point
	// Color defines how much of the color-components of the texture get used
	Color color.Color
	// Drawable refers to the Texture that should be drawn
	Drawable Drawable
	// Repeat defines how to repeat the Texture if the SpaceComponent of the entity
	// is larger than the texture itself, after applying scale. Defaults to NoRepeat
	// which allows the texture to draw entirely without regard to th SpaceComponent
	// Do not set to anything other than NoRepeat for textures in a sprite sheet.
	// This does not yet work with sprite sheets.
	Repeat TextureRepeating
	// Buffer represents the buffer object itself
	// Avoid using it unless your are writing a custom shader
	Buffer *gl.Buffer
	// BufferContent contains the buffer data
	// Avoid using it unless your are writing a custom shader
	BufferContent []float32
	// StartZIndex defines the initial Z-Index. Z-Index defines the order which the content is drawn to the
	// screen. Higher z-indices are drawn on top of lower ones. Beware that you must use `SetZIndex` function to change
	// the Z-Index.
	StartZIndex float32

	magFilter, minFilter ZoomFilter

	shader Shader
	zIndex float32
}

// SetShader sets the shader used by the RenderComponent.
func (r *RenderComponent) SetShader(s Shader) {
	r.shader = s
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

func (r *RenderComponent) ensureShader() {
	// Setting default shader
	if r.shader == nil {
		switch r.Drawable.(type) {
		case Triangle:
			r.shader = LegacyShader
		case Circle:
			r.shader = LegacyShader
		case Rectangle:
			r.shader = LegacyShader
		case ComplexTriangles:
			r.shader = LegacyShader
		case Text:
			r.shader = TextShader
		case Blendmap:
			r.shader = BlendmapShader
		default:
			r.shader = DefaultShader
		}
	}
}

func (r *RenderComponent) Shader() Shader {
	r.ensureShader()
	return r.shader
}

// SetZIndex sets the order that the RenderComponent is drawn to the screen. Higher z-indices are drawn on top of
// lower ones if they overlap.
func (r *RenderComponent) SetZIndex(index float32) {
	r.zIndex = index
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

// SetMinFilter sets the ZoomFilter used for minimizing the RenderComponent
func (r *RenderComponent) SetMinFilter(z ZoomFilter) {
	r.minFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

// SetMagFilter sets the ZoomFilter used for magnifying the RenderComponent
func (r *RenderComponent) SetMagFilter(z ZoomFilter) {
	r.magFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

type renderEntity struct {
	*ecs.BasicEntity
	*RenderComponent
	*SpaceComponent
}

type renderEntityList []renderEntity

func (r renderEntityList) Len() int {
	return len(r)
}

func (r renderEntityList) Less(i, j int) bool {
	// Sort by shader-pointer if they have the same zIndex
	if r[i].RenderComponent.zIndex != r[j].RenderComponent.zIndex {
		return r[i].RenderComponent.zIndex < r[j].RenderComponent.zIndex
	}

	// // TODO: optimize this for performance
	p1, p2 := reflect.ValueOf(r[i].RenderComponent.shader).Pointer(), reflect.ValueOf(r[j].RenderComponent.shader).Pointer()
	if p1 != p2 {
		return p1 < p2
	}

	switch r[i].RenderComponent.Drawable.(type) {
	// Tiles can either be as a spriteSheet or as separate image
	// if we sort them by texture and they're saved as separate images,
	// sorting by texture messes up rendering.
	case *Tile:
		// NO-OP
	default:
		t1, t2 := uintptr(unsafe.Pointer(r[i].RenderComponent.Drawable.Texture())), uintptr(unsafe.Pointer(r[j].RenderComponent.Drawable.Texture()))
		if t1 != t2 {
			return t1 < t2
		}
	}

	// Sort by minFilter if they're the same magFilter
	mag1, mag2 := r[i].RenderComponent.magFilter, r[j].RenderComponent.magFilter
	if mag1 != mag2 {
		return mag1 < mag2
	}

	// Sort by position if they're the same minFilter
	min1, min2 := r[i].RenderComponent.minFilter, r[j].RenderComponent.minFilter
	if min1 != min2 {
		return min1 < min2
	}

	if r[i].Position.Y != r[j].Position.Y {
		return r[i].Position.Y < r[j].Position.Y
	}

	return r[i].Position.X < r[j].Position.X
}

func (r renderEntityList) Swap(i, j int) {
	r[i], r[j] = r[j], r[i]
}

// RenderSystem is the system that draws entities on the OpenGL surface. It requires
// a CameraSystem to work. If a CameraSystem is not in the World when you add RenderSystem
// one is automatically added to the world.
type RenderSystem struct {
	entities renderEntityList
	ids      map[uint64]struct{}
	world    *ecs.World

	sortingNeeded, newCamera bool
}

// Priority implements the ecs.Prioritizer interface.
func (*RenderSystem) Priority() int { return RenderSystemPriority }

// New initializes the RenderSystem
func (rs *RenderSystem) New(w *ecs.World) {
	rs.world = w
	rs.ids = make(map[uint64]struct{})

	engo.Mailbox.Listen("NewCameraMessage", func(engo.Message) {
		rs.newCamera = true
	})

	addCameraSystemOnce(w)

	if !engo.Headless() {
		if err := initShaders(w); err != nil {
			panic(err)
		}
		engo.Gl.Enable(engo.Gl.MULTISAMPLE)
	}

	engo.Mailbox.Listen("renderChangeMessage", func(engo.Message) {
		rs.sortingNeeded = true
	})
}

var cameraInitMutex sync.Mutex

func addCameraSystemOnce(w *ecs.World) {
	cameraInitMutex.Lock()
	defer cameraInitMutex.Unlock()

	camSystemAlreadyAdded := false
	for _, system := range w.Systems() {
		switch system.(type) {
		case *CameraSystem:
			camSystemAlreadyAdded = true
		}
	}
	if !camSystemAlreadyAdded {
		w.AddSystem(&CameraSystem{})
	}
}

// Add adds an entity to the RenderSystem. The entity needs a basic, render, and space component to be added to the system.
func (rs *RenderSystem) Add(basic *ecs.BasicEntity, render *RenderComponent, space *SpaceComponent) {
	// Do nothing if entity already exists
	if _, ok := rs.ids[basic.ID()]; ok {
		return
	}

	rs.ids[basic.ID()] = struct{}{}

	render.ensureShader()

	// This is to prevent users from using the wrong one
	if render.shader == HUDShader {
		switch render.Drawable.(type) {
		case Triangle:
			render.shader = LegacyHUDShader
		case Circle:
			render.shader = LegacyHUDShader
		case Rectangle:
			render.shader = LegacyHUDShader
		case ComplexTriangles:
			render.shader = LegacyHUDShader
		case Text:
			render.shader = TextHUDShader
		default:
			render.shader = HUDShader
		}
	}

	// If the scale is zero, set it to one.
	if render.Scale.X == 0 {
		render.Scale.X = 1
	}
	if render.Scale.Y == 0 {
		render.Scale.Y = 1
	}

	render.zIndex = render.StartZIndex

	rs.entities = append(rs.entities, renderEntity{basic, render, space})
	rs.sortingNeeded = true
}

// EntityExists looks if the entity is already into the System's entities. It will return the index >= 0 of the object into de rs.entities or -1 if it could not be found.
func (rs *RenderSystem) EntityExists(basic *ecs.BasicEntity) int {
	for index, entity := range rs.entities {
		if entity.ID() == basic.ID() {
			return index
		}
	}

	return -1
}

// AddByInterface adds any Renderable to the render system. Any Entity containing a BasicEntity,RenderComponent, and SpaceComponent anonymously does this automatically
func (rs *RenderSystem) AddByInterface(i ecs.Identifier) {
	o, _ := i.(Renderable)
	rs.Add(o.GetBasicEntity(), o.GetRenderComponent(), o.GetSpaceComponent())
}

// Remove removes an entity from the RenderSystem
func (rs *RenderSystem) Remove(basic ecs.BasicEntity) {
	var d = rs.EntityExists(&basic)
	if d >= 0 {
		rs.entities = append(rs.entities[:d], rs.entities[d+1:]...)
		rs.sortingNeeded = true
	}
	delete(rs.ids, basic.ID())
}

// Update draws the entities in the RenderSystem to the OpenGL Surface.
func (rs *RenderSystem) Update(dt float32) {
	if engo.Headless() {
		return
	}

	if rs.sortingNeeded {
		sort.Sort(rs.entities)
		rs.sortingNeeded = false
	}

	if rs.newCamera {
		newCamera(rs.world)
		rs.newCamera = false
	}

	engo.Gl.Clear(engo.Gl.COLOR_BUFFER_BIT)

	preparedCullingShaders := make(map[CullingShader]struct{})
	var cullingShader CullingShader // current culling shader
	var prevShader Shader           // shader of the previous entity
	var currentShader Shader        // currently "active" shader

	// TODO: it's linear for now, but that might very well be a bad idea
	for _, e := range rs.entities {
		if e.RenderComponent.Hidden {
			continue // with other entities
		}

		// Retrieve a shader, may be the default one -- then use it if we aren't already using it
		shader := e.RenderComponent.shader

		if !compareShaders(shader, prevShader) {
			// to increase performance avoid the type assertions when possible
			prevShader = shader
			if cs, ok := shader.(CullingShader); ok {
				cullingShader = cs
				if _, isPrepared := preparedCullingShaders[cullingShader]; !isPrepared {
					cullingShader.PrepareCulling()
					preparedCullingShaders[cullingShader] = struct{}{}
				}
			} else {
				cullingShader = nil
			}
		}

		if cullingShader != nil && !cullingShader.ShouldDraw(e.RenderComponent, e.SpaceComponent) {
			continue
		}

		// Change Shader if we have to
		if !compareShaders(shader, currentShader) {
			if currentShader != nil {
				currentShader.Post()
			}
			shader.Pre()
			currentShader = shader
		}

		// Setting default scale to 1
		if e.RenderComponent.Scale.X == 0 && e.RenderComponent.Scale.Y == 0 {
			e.RenderComponent.Scale = engo.Point{X: 1, Y: 1}
		}

		// Setting default to white
		if e.RenderComponent.Color == nil {
			e.RenderComponent.Color = color.White
		}

		currentShader.Draw(e.RenderComponent, e.SpaceComponent)
	}

	if currentShader != nil {
		currentShader.Post()
	}
}

// SetBackground sets the OpenGL ClearColor to the provided color.
func SetBackground(c color.Color) {
	if !engo.Headless() {
		r, g, b, a := c.RGBA()

		engo.Gl.ClearColor(float32(r)/0xffff, float32(g)/0xffff, float32(b)/0xffff, float32(a)/0xffff)
	}
}
<commit_msg>remove reflect and fmt<commit_after>package common

import (
	"github.com/EngoEngine/ecs"
	"github.com/EngoEngine/engo"
	"github.com/EngoEngine/gl"
	"image/color"
	"sort"
	"sync"
	"unsafe"
)

const (
	// RenderSystemPriority is the priority of the RenderSystem
	RenderSystemPriority = -1000
)

type renderChangeMessage struct{}

func (renderChangeMessage) Type() string {
	return "renderChangeMessage"
}

// Drawable is that which can be rendered to OpenGL.
type Drawable interface {
	Texture() *gl.Texture
	Width() float32
	Height() float32
	View() (float32, float32, float32, float32)
	Close()
}

// TextureRepeating is the method used to repeat a texture in OpenGL.
type TextureRepeating uint8

const (
	// NoRepeat does not repeat the texture.
	NoRepeat TextureRepeating = iota
	// ClampToEdge stretches the texture to the edge of the viewport.
	ClampToEdge
	// ClampToBorder stretches the texture to the border of the viewpport.
	ClampToBorder
	// Repeat repeats the texture until the border of the viewport.
	Repeat
	// MirroredRepeat repeats a mirror image of the texture until the border of the viewport.
	MirroredRepeat
)

// ZoomFilter is a filter used when zooming in or out of a texture.
type ZoomFilter uint8

const (
	// FilterNearest is a simple nearest neighbor algorithm
	FilterNearest ZoomFilter = iota
	// FilterLinear is a bilinear interpolation algorithm
	FilterLinear
)

// RenderComponent is the component needed to render an entity.
type RenderComponent struct {
	// Hidden is used to prevent drawing by OpenGL
	Hidden bool
	// Scale is the scale at which to render, in the X and Y axis. Not defining Scale, will default to engo.Point{1, 1}
	Scale engo.Point
	// Color defines how much of the color-components of the texture get used
	Color color.Color
	// Drawable refers to the Texture that should be drawn
	Drawable Drawable
	// Repeat defines how to repeat the Texture if the SpaceComponent of the entity
	// is larger than the texture itself, after applying scale. Defaults to NoRepeat
	// which allows the texture to draw entirely without regard to th SpaceComponent
	// Do not set to anything other than NoRepeat for textures in a sprite sheet.
	// This does not yet work with sprite sheets.
	Repeat TextureRepeating
	// Buffer represents the buffer object itself
	// Avoid using it unless your are writing a custom shader
	Buffer *gl.Buffer
	// BufferContent contains the buffer data
	// Avoid using it unless your are writing a custom shader
	BufferContent []float32
	// StartZIndex defines the initial Z-Index. Z-Index defines the order which the content is drawn to the
	// screen. Higher z-indices are drawn on top of lower ones. Beware that you must use `SetZIndex` function to change
	// the Z-Index.
	StartZIndex float32

	magFilter, minFilter ZoomFilter

	shader Shader
	zIndex float32
}

// SetShader sets the shader used by the RenderComponent.
func (r *RenderComponent) SetShader(s Shader) {
	r.shader = s
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

func (r *RenderComponent) ensureShader() {
	// Setting default shader
	if r.shader == nil {
		switch r.Drawable.(type) {
		case Triangle:
			r.shader = LegacyShader
		case Circle:
			r.shader = LegacyShader
		case Rectangle:
			r.shader = LegacyShader
		case ComplexTriangles:
			r.shader = LegacyShader
		case Text:
			r.shader = TextShader
		case Blendmap:
			r.shader = BlendmapShader
		default:
			r.shader = DefaultShader
		}
	}
}

func (r *RenderComponent) Shader() Shader {
	r.ensureShader()
	return r.shader
}

// SetZIndex sets the order that the RenderComponent is drawn to the screen. Higher z-indices are drawn on top of
// lower ones if they overlap.
func (r *RenderComponent) SetZIndex(index float32) {
	r.zIndex = index
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

// SetMinFilter sets the ZoomFilter used for minimizing the RenderComponent
func (r *RenderComponent) SetMinFilter(z ZoomFilter) {
	r.minFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

// SetMagFilter sets the ZoomFilter used for magnifying the RenderComponent
func (r *RenderComponent) SetMagFilter(z ZoomFilter) {
	r.magFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

type renderEntity struct {
	*ecs.BasicEntity
	*RenderComponent
	*SpaceComponent
}

type renderEntityList []renderEntity

func (r renderEntityList) Len() int {
	return len(r)
}

func (r renderEntityList) Less(i, j int) bool {
	// Sort by shader-pointer if they have the same zIndex
	if r[i].RenderComponent.zIndex != r[j].RenderComponent.zIndex {
		return r[i].RenderComponent.zIndex < r[j].RenderComponent.zIndex
	}

	// TODO: optimize this for performance (is it enough? maybe "cache" shader uintptr (i.e: r.shaderPtr)?)
	p1, p2 := (*[2]uintptr)(unsafe.Pointer(&r[i].RenderComponent.shader))[1], (*[2]uintptr)(unsafe.Pointer(&r[j].RenderComponent.shader))[1]
	if p1 != p2 {
		return p1 < p2
	}

	switch r[i].RenderComponent.Drawable.(type) {
	// Tiles can either be as a spriteSheet or as separate image
	// if we sort them by texture and they're saved as separate images,
	// sorting by texture messes up rendering.
	case *Tile:
		// NO-OP
	default:
		t1, t2 := uintptr(unsafe.Pointer(r[i].RenderComponent.Drawable.Texture())), uintptr(unsafe.Pointer(r[j].RenderComponent.Drawable.Texture()))
		if t1 != t2 {
			return t1 < t2
		}
	}

	// Sort by minFilter if they're the same magFilter
	mag1, mag2 := r[i].RenderComponent.magFilter, r[j].RenderComponent.magFilter
	if mag1 != mag2 {
		return mag1 < mag2
	}

	// Sort by position if they're the same minFilter
	min1, min2 := r[i].RenderComponent.minFilter, r[j].RenderComponent.minFilter
	if min1 != min2 {
		return min1 < min2
	}

	if r[i].Position.Y != r[j].Position.Y {
		return r[i].Position.Y < r[j].Position.Y
	}

	return r[i].Position.X < r[j].Position.X
}

func (r renderEntityList) Swap(i, j int) {
	r[i], r[j] = r[j], r[i]
}

// RenderSystem is the system that draws entities on the OpenGL surface. It requires
// a CameraSystem to work. If a CameraSystem is not in the World when you add RenderSystem
// one is automatically added to the world.
type RenderSystem struct {
	entities renderEntityList
	ids      map[uint64]struct{}
	world    *ecs.World

	sortingNeeded, newCamera bool
}

// Priority implements the ecs.Prioritizer interface.
func (*RenderSystem) Priority() int { return RenderSystemPriority }

// New initializes the RenderSystem
func (rs *RenderSystem) New(w *ecs.World) {
	rs.world = w
	rs.ids = make(map[uint64]struct{})

	engo.Mailbox.Listen("NewCameraMessage", func(engo.Message) {
		rs.newCamera = true
	})

	addCameraSystemOnce(w)

	if !engo.Headless() {
		if err := initShaders(w); err != nil {
			panic(err)
		}
		engo.Gl.Enable(engo.Gl.MULTISAMPLE)
	}

	engo.Mailbox.Listen("renderChangeMessage", func(engo.Message) {
		rs.sortingNeeded = true
	})
}

var cameraInitMutex sync.Mutex

func addCameraSystemOnce(w *ecs.World) {
	cameraInitMutex.Lock()
	defer cameraInitMutex.Unlock()

	camSystemAlreadyAdded := false
	for _, system := range w.Systems() {
		switch system.(type) {
		case *CameraSystem:
			camSystemAlreadyAdded = true
		}
	}
	if !camSystemAlreadyAdded {
		w.AddSystem(&CameraSystem{})
	}
}

// Add adds an entity to the RenderSystem. The entity needs a basic, render, and space component to be added to the system.
func (rs *RenderSystem) Add(basic *ecs.BasicEntity, render *RenderComponent, space *SpaceComponent) {
	// Do nothing if entity already exists
	if _, ok := rs.ids[basic.ID()]; ok {
		return
	}

	rs.ids[basic.ID()] = struct{}{}

	render.ensureShader()

	// This is to prevent users from using the wrong one
	if render.shader == HUDShader {
		switch render.Drawable.(type) {
		case Triangle:
			render.shader = LegacyHUDShader
		case Circle:
			render.shader = LegacyHUDShader
		case Rectangle:
			render.shader = LegacyHUDShader
		case ComplexTriangles:
			render.shader = LegacyHUDShader
		case Text:
			render.shader = TextHUDShader
		default:
			render.shader = HUDShader
		}
	}

	// If the scale is zero, set it to one.
	if render.Scale.X == 0 {
		render.Scale.X = 1
	}
	if render.Scale.Y == 0 {
		render.Scale.Y = 1
	}

	render.zIndex = render.StartZIndex

	rs.entities = append(rs.entities, renderEntity{basic, render, space})
	rs.sortingNeeded = true
}

// EntityExists looks if the entity is already into the System's entities. It will return the index >= 0 of the object into de rs.entities or -1 if it could not be found.
func (rs *RenderSystem) EntityExists(basic *ecs.BasicEntity) int {
	for index, entity := range rs.entities {
		if entity.ID() == basic.ID() {
			return index
		}
	}

	return -1
}

// AddByInterface adds any Renderable to the render system. Any Entity containing a BasicEntity,RenderComponent, and SpaceComponent anonymously does this automatically
func (rs *RenderSystem) AddByInterface(i ecs.Identifier) {
	o, _ := i.(Renderable)
	rs.Add(o.GetBasicEntity(), o.GetRenderComponent(), o.GetSpaceComponent())
}

// Remove removes an entity from the RenderSystem
func (rs *RenderSystem) Remove(basic ecs.BasicEntity) {
	var d = rs.EntityExists(&basic)
	if d >= 0 {
		rs.entities = append(rs.entities[:d], rs.entities[d+1:]...)
		rs.sortingNeeded = true
	}
	delete(rs.ids, basic.ID())
}

// Update draws the entities in the RenderSystem to the OpenGL Surface.
func (rs *RenderSystem) Update(dt float32) {
	if engo.Headless() {
		return
	}

	if rs.sortingNeeded {
		sort.Sort(rs.entities)
		rs.sortingNeeded = false
	}

	if rs.newCamera {
		newCamera(rs.world)
		rs.newCamera = false
	}

	engo.Gl.Clear(engo.Gl.COLOR_BUFFER_BIT)

	preparedCullingShaders := make(map[CullingShader]struct{})
	var cullingShader CullingShader // current culling shader
	var prevShader Shader           // shader of the previous entity
	var currentShader Shader        // currently "active" shader

	// TODO: it's linear for now, but that might very well be a bad idea
	for _, e := range rs.entities {
		if e.RenderComponent.Hidden {
			continue // with other entities
		}

		// Retrieve a shader, may be the default one -- then use it if we aren't already using it
		shader := e.RenderComponent.shader

		if !compareShaders(shader, prevShader) {
			// to increase performance avoid the type assertions when possible
			prevShader = shader
			if cs, ok := shader.(CullingShader); ok {
				cullingShader = cs
				if _, isPrepared := preparedCullingShaders[cullingShader]; !isPrepared {
					cullingShader.PrepareCulling()
					preparedCullingShaders[cullingShader] = struct{}{}
				}
			} else {
				cullingShader = nil
			}
		}

		if cullingShader != nil && !cullingShader.ShouldDraw(e.RenderComponent, e.SpaceComponent) {
			continue
		}

		// Change Shader if we have to
		if !compareShaders(shader, currentShader) {
			if currentShader != nil {
				currentShader.Post()
			}
			shader.Pre()
			currentShader = shader
		}

		// Setting default scale to 1
		if e.RenderComponent.Scale.X == 0 && e.RenderComponent.Scale.Y == 0 {
			e.RenderComponent.Scale = engo.Point{X: 1, Y: 1}
		}

		// Setting default to white
		if e.RenderComponent.Color == nil {
			e.RenderComponent.Color = color.White
		}

		currentShader.Draw(e.RenderComponent, e.SpaceComponent)
	}

	if currentShader != nil {
		currentShader.Post()
	}
}

// SetBackground sets the OpenGL ClearColor to the provided color.
func SetBackground(c color.Color) {
	if !engo.Headless() {
		r, g, b, a := c.RGBA()

		engo.Gl.ClearColor(float32(r)/0xffff, float32(g)/0xffff, float32(b)/0xffff, float32(a)/0xffff)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.net/publicsuffix"
	"encoding/json"
	"errors"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strconv"
	"strings"
)

//{"data":{"count":0,"wodou":650,"getWodou":50},"message":null,"success":true}
type SignJsonResultData struct {
	Count, Wodou, GetWodou int64
}

type SignJsonResult struct {
	Success bool
	Message string
	Data    SignJsonResultData
}

type MemberDayData struct {
	code int64
}

type MemberDay struct {
	Success bool
	Message string
	Data    MemberDayData
}

//{"data":{"message":{"show":"0","chance":0,"info":"7M\u6d41\u91cf"}},"message":null,"success":true}
type RedPacketDataInfo struct {
	Show   string
	Chance int64
	Info   string
}
type RedPacketData struct {
	Message RedPacketDataInfo
}
type RedPacket struct {
	Data    RedPacketData
	Message string
	Success bool
}

func login(mobile, password string, cookieJar *cookiejar.Jar) (http.Client, error) {
	loginUrl := "http://17wo.cn/Login!process.action"
	log.Println("loginUrl", loginUrl)

	postBody := url.Values{}
	postBody.Set("mobile", mobile)
	postBody.Add("password", password)
	postBody.Add("chkType", "on")
	postBody.Add("backurl", "")
	postBody.Add("backurl2", "")
	postBody.Add("chk", "")
	postBody.Add("loginType", "0")

	client := http.Client{
		Jar: cookieJar,
	}

	req, err := http.NewRequest("POST", loginUrl, strings.NewReader(postBody.Encode()))
	if err != nil {
		log.Println("some wrong :", err)
		return client, err
	}

	req.Header.Add("User-Agent", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16")
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
		return client, err
	}

	htmlStr := string(body)

	matched, _ := regexp.MatchString(`<p id="getAlert"[^>]*>(.*?)</p>|(错误信息)`, htmlStr)
	if resp.StatusCode != http.StatusOK || matched {
		return client, errors.New("登录失败,请检查你的手机号或密码是否正确")
	}

	log.Println("登录成功")

	matched, _ = regexp.MatchString(`已签到`, htmlStr)
	if matched {
		log.Println("已签到")
	}

	return client, nil
}

func requestJson(fn func([]byte), client http.Client, cookieJar *cookiejar.Jar, url string) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Println("request json failed. ", err)
		return
	}

	resp, err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err)
		return
	}

	fn(body)

	log.Println("")
}

func signin(body []byte) {
	log.Println("====  签到 开始 ====")

	var m SignJsonResult
	err := json.Unmarshal(body, &m)
	if err != nil {
		log.Fatal(err)
		return
	}

	log.Printf("%+v", m)
	log.Println("====  签到 结束 ====")
}

func memberDay(body []byte) {
	log.Println("====  会员日开红包 开始 ====")

	var m MemberDay
	err := json.Unmarshal(body, &m)
	if err != nil {
		log.Fatal(err)
		return
	}

	log.Printf("%+v", m)
	log.Println("====  会员日开红包 结束 ====")
}

func flowRedPacket(body []byte) {
	log.Println("====  流量红包 开始 ====")

	var m RedPacket
	err := json.Unmarshal(body, &m)
	if err != nil {
		log.Fatal(err)
		return
	}

	log.Printf("%+v", m)
	log.Println("====  流量红包 结束 ====")
}

func main() {
	options := cookiejar.Options{
		PublicSuffixList: publicsuffix.List,
	}

	cookieJar, err := cookiejar.New(&options)
	if err != nil {
		log.Fatal(err)
	}

	mobile := flag.Int64("mobile", 0, "手机号")
	password := flag.String("password", "", "密码")

	flag.Parse()

	if *mobile == 0 || *password == "" {
		log.Println("请使用app.go -h查看帮助")
		return
	}

	log.Println("手机: ", *mobile)
	log.Println("密码: ", *password)

	client, err := login(strconv.FormatInt(*mobile, 10), *password, cookieJar)
	if err != nil {
		log.Println(err)
		return
	}

	requestJson(signin, client, cookieJar, "http://17wo.cn/SignIn!checkin.action?checkIn=true&rnd=4151")
	requestJson(memberDay, client, cookieJar, "http://17wo.cn/MemberDay!draw.action?_=1411834905292")
	requestJson(flowRedPacket, client, cookieJar, "http://17wo.cn/FlowRedPacket!LuckDraw.action?1238")

}
<commit_msg>change some text<commit_after>package main

import (
	"code.google.com/p/go.net/publicsuffix"
	"encoding/json"
	"errors"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strconv"
	"strings"
)

//{"data":{"count":0,"wodou":650,"getWodou":50},"message":null,"success":true}
type SignJsonResultData struct {
	Count, Wodou, GetWodou int64
}

type SignJsonResult struct {
	Success bool
	Message string
	Data    SignJsonResultData
}

type MemberDayData struct {
	code int64
}

type MemberDay struct {
	Success bool
	Message string
	Data    MemberDayData
}

//{"data":{"message":{"show":"0","chance":0,"info":"7M\u6d41\u91cf"}},"message":null,"success":true}
type RedPacketDataInfo struct {
	Show   string
	Chance int64
	Info   string
}
type RedPacketData struct {
	Message RedPacketDataInfo
}
type RedPacket struct {
	Data    RedPacketData
	Message string
	Success bool
}

func login(mobile, password string, cookieJar *cookiejar.Jar) (http.Client, error) {
	loginUrl := "http://17wo.cn/Login!process.action"
	log.Println("登录网址 ", loginUrl)

	postBody := url.Values{}
	postBody.Set("mobile", mobile)
	postBody.Add("password", password)
	postBody.Add("chkType", "on")
	postBody.Add("backurl", "")
	postBody.Add("backurl2", "")
	postBody.Add("chk", "")
	postBody.Add("loginType", "0")

	client := http.Client{
		Jar: cookieJar,
	}

	req, err := http.NewRequest("POST", loginUrl, strings.NewReader(postBody.Encode()))
	if err != nil {
		log.Println("some wrong :", err)
		return client, err
	}

	req.Header.Add("User-Agent", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16")
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
		return client, err
	}

	htmlStr := string(body)

	matched, _ := regexp.MatchString(`<p id="getAlert"[^>]*>(.*?)</p>|(错误信息)`, htmlStr)
	if resp.StatusCode != http.StatusOK || matched {
		return client, errors.New("登录失败,请检查你的手机号或密码是否正确")
	}

	log.Println("登录成功")

	matched, _ = regexp.MatchString(`已签到`, htmlStr)
	if matched {
		log.Println("**已签到过了,无需再签**")
	}

	return client, nil
}

func requestJson(fn func([]byte), client http.Client, cookieJar *cookiejar.Jar, url string) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Println("request json failed. ", err)
		return
	}

	resp, err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err)
		return
	}

	fn(body)

	log.Println("")
}

func signin(body []byte) {
	log.Println("====  签到 开始 ====")

	var m SignJsonResult
	err := json.Unmarshal(body, &m)
	if err != nil {
		log.Fatal(err)
		return
	}

	log.Printf("%+v", m)
	log.Println("====  签到 结束 ====")
}

func memberDay(body []byte) {
	log.Println("====  会员日开红包 开始 ====")

	var m MemberDay
	err := json.Unmarshal(body, &m)
	if err != nil {
		log.Fatal(err)
		return
	}

	log.Printf("%+v", m)
	log.Println("====  会员日开红包 结束 ====")
}

func flowRedPacket(body []byte) {
	log.Println("====  流量红包 开始 ====")

	var m RedPacket
	err := json.Unmarshal(body, &m)
	if err != nil {
		log.Fatal(err)
		return
	}

	log.Printf("%+v", m)
	log.Println("====  流量红包 结束 ====")
}

func main() {
	options := cookiejar.Options{
		PublicSuffixList: publicsuffix.List,
	}

	cookieJar, err := cookiejar.New(&options)
	if err != nil {
		log.Fatal(err)
	}

	mobile := flag.Int64("mobile", 0, "手机号")
	password := flag.String("password", "", "密码")

	flag.Parse()

	if *mobile == 0 || *password == "" {
		log.Println("请使用 auto17wo -h 查看帮助")
		return
	}

	log.Println("手机: ", *mobile)
	log.Println("密码: ", *password)

	client, err := login(strconv.FormatInt(*mobile, 10), *password, cookieJar)
	if err != nil {
		log.Println(err)
		return
	}

	requestJson(signin, client, cookieJar, "http://17wo.cn/SignIn!checkin.action?checkIn=true&rnd=4151")
	requestJson(memberDay, client, cookieJar, "http://17wo.cn/MemberDay!draw.action?_=1411834905292")
	requestJson(flowRedPacket, client, cookieJar, "http://17wo.cn/FlowRedPacket!LuckDraw.action?1238")

}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"net/http"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	fthealth "github.com/Financial-Times/go-fthealth/v1a"
	log "github.com/Sirupsen/logrus"
	"time"
	"github.com/rcrowley/go-metrics"
	"github.com/Financial-Times/http-handlers-go"
)

const serviceName = "content-preview"
const serviceDescription = "A RESTful API for retrieving and transforming content to preview data"

var timeout = time.Duration(5 * time.Second)
var client = &http.Client{Timeout: timeout}

func main() {

	log.SetLevel(log.InfoLevel)
	log.Infof("%s service started with args %s", serviceName, os.Args)

	app := cli.App(serviceName, serviceDescription)
	appPort := app.StringOpt("app-port", "8084", "Default port for app")
	mapiAuth := app.StringOpt("mapi-auth", "default", "Basic auth for MAPI")
	mapiUri := app.StringOpt("mapi-uri", "http://methode-api-uk-p.svc.ft.com", "Host and port for MAPI")
	matHostHeader := app.StringOpt("mat-host-header", "methode-article-transformer", "Hostheader for MAT")
	matUri := app.StringOpt("mat-uri", "http://ftapp05951-lvpr-uk-int:8080", "Host and port for MAT")

	app.Action = func() {
		r := mux.NewRouter()
		handler := Handlers{*mapiAuth, *matHostHeader, *mapiUri, *matUri}
		r.HandleFunc("/content-preview/{uuid}", handler.contentPreviewHandler)
		r.HandleFunc("/build-info", handler.buildInfoHandler)
		r.HandleFunc("/__health", fthealth.Handler(serviceName, serviceDescription, handler.mapiCheck(), handler.matCheck()))
		r.HandleFunc("/__ping", pingHandler)

		err := http.ListenAndServe( ":"+*appPort,
			httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry,
				httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), r)))

		if err != nil {
			log.Fatalf("Unable to start server: %v", err)
		}

	}
	log.WithFields(log.Fields{
		"mapi-uri" : *mapiUri,
		"mat-uri"  : *matUri,
		"mapi-auth" : *mapiAuth,
		"mat-host-header" : *matHostHeader,
	}).Infof("%s service started on localhost:%s with configuration", serviceName, *appPort)
	app.Run(os.Args)

}
<commit_msg>fixed logging cmd args<commit_after>package main

import (
	"os"
	"net/http"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	fthealth "github.com/Financial-Times/go-fthealth/v1a"
	log "github.com/Sirupsen/logrus"
	"time"
	"github.com/rcrowley/go-metrics"
	"github.com/Financial-Times/http-handlers-go"
)

const serviceName = "content-preview"
const serviceDescription = "A RESTful API for retrieving and transforming content to preview data"

var timeout = time.Duration(5 * time.Second)
var client = &http.Client{Timeout: timeout}

func main() {
	log.SetLevel(log.InfoLevel)
	log.Infof("%s service started with args %s", serviceName, os.Args)

	app := cli.App(serviceName, serviceDescription)
	appPort := app.StringOpt("app-port", "8084", "Default port for app")
	mapiAuth := app.StringOpt("mapi-auth", "default", "Basic auth for MAPI")
	mapiUri := app.StringOpt("mapi-uri", "http://methode-api-uk-p.svc.ft.com", "Host and port for MAPI")
	matHostHeader := app.StringOpt("mat-host-header", "methode-article-transformer", "Hostheader for MAT")
	matUri := app.StringOpt("mat-uri", "http://ftapp05951-lvpr-uk-int:8080", "Host and port for MAT")

	app.Action = func() {
		r := mux.NewRouter()
		handler := Handlers{*mapiAuth, *matHostHeader, *mapiUri, *matUri}
		r.HandleFunc("/content-preview/{uuid}", handler.contentPreviewHandler)
		r.HandleFunc("/build-info", handler.buildInfoHandler)
		r.HandleFunc("/__health", fthealth.Handler(serviceName, serviceDescription, handler.mapiCheck(), handler.matCheck()))
		r.HandleFunc("/__ping", pingHandler)

		log.WithFields(log.Fields{
			"mapi-uri" : *mapiUri,
			"mat-uri"  : *matUri,
			"mapi-auth" : *mapiAuth,
			"mat-host-header" : *matHostHeader,
		}).Infof("%s service started on localhost:%s with configuration", serviceName, *appPort)

		err := http.ListenAndServe( ":"+*appPort,
			httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry,
				httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), r)))

		if err != nil {
			log.Fatalf("Unable to start server: %v", err)
		}

	}

	app.Run(os.Args)

}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"io"

	"github.com/subsilent/kappa/server"
)

type ColorCodes struct {
	// Foreground colors
	Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte

	// Light Foreground colors
	LightGrey, LightRed, LightGreen, LightYellow, LightBlue, LightMagenta, LightCyan, LightWhite []byte

	// Reset all attributes
	Reset []byte
}

const keyEscape = 27

// ANSI colors
var DefaultColorCodes = ColorCodes{
	Black:   []byte{keyEscape, '[', '3', '0', 'm'},
	Red:     []byte{keyEscape, '[', '3', '1', 'm'},
	Green:   []byte{keyEscape, '[', '3', '2', 'm'},
	Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
	Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
	Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
	Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
	White:   []byte{keyEscape, '[', '3', '7', 'm'},

	LightGrey:    []byte{keyEscape, '[', '9', '0', 'm'},
	LightRed:     []byte{keyEscape, '[', '9', '1', 'm'},
	LightGreen:   []byte{keyEscape, '[', '9', '2', 'm'},
	LightYellow:  []byte{keyEscape, '[', '9', '3', 'm'},
	LightBlue:    []byte{keyEscape, '[', '9', '4', 'm'},
	LightMagenta: []byte{keyEscape, '[', '9', '5', 'm'},
	LightCyan:    []byte{keyEscape, '[', '9', '6', 'm'},
	LightWhite:   []byte{keyEscape, '[', '9', '7', 'm'},
	Reset:        []byte{keyEscape, '[', '0', 'm'},
}

// ResponseWriter writes data and status codes to the client
type ResponseWriter struct {
	Colors      ColorCodes
	Writer      io.Writer
	StatusCodes map[server.StatusCode]string
}

func (r *ResponseWriter) colorCode(color []byte, code StatusCode, format string, args ...interface{}) {

	// Set color
	r.Writer.Write(color)

	// Write error name and code
	if t, ok := r.StatusCodes[code]; ok {
		r.Writer.Write([]byte(fmt.Sprintf(" %s (%d)", t, int(code))))
	} else {
		r.Writer.Write([]byte(fmt.Sprintf(" Unknown (%d)", int(code))))
	}

	// Write the error message if there is one
	if len(format) > 0 {
		r.Writer.Write([]byte(": "))
		fmt.Fprintf(r.Writer, format, args...)
	}

	// Reset terminal colors
	r.Writer.Write(r.Colors.Reset)
	r.Writer.Write([]byte("\r\n"))
}

// Fail writes the error status code to the Writer
func (r *ResponseWriter) Fail(code StatusCode, format string, args ...interface{}) {
	r.colorCode(r.Colors.LightRed, code, format, args...)
}

// Success writes the status code to the Writer
func (r *ResponseWriter) Success(code StatusCode, format string, args ...interface{}) {
	r.colorCode(r.Colors.LightGreen, code, format, args...)
}

// Write is a pass through function into the underlying Writer
func (r *ResponseWriter) Write(data []byte) (int, error) {
	return r.Writer.Write(data)
}
<commit_msg>Resolve build errors<commit_after>package common

import (
	"fmt"
	"io"
)

type ColorCodes struct {
	// Foreground colors
	Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte

	// Light Foreground colors
	LightGrey, LightRed, LightGreen, LightYellow, LightBlue, LightMagenta, LightCyan, LightWhite []byte

	// Reset all attributes
	Reset []byte
}

const keyEscape = 27

// ANSI colors
var DefaultColorCodes = ColorCodes{
	Black:   []byte{keyEscape, '[', '3', '0', 'm'},
	Red:     []byte{keyEscape, '[', '3', '1', 'm'},
	Green:   []byte{keyEscape, '[', '3', '2', 'm'},
	Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
	Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
	Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
	Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
	White:   []byte{keyEscape, '[', '3', '7', 'm'},

	LightGrey:    []byte{keyEscape, '[', '9', '0', 'm'},
	LightRed:     []byte{keyEscape, '[', '9', '1', 'm'},
	LightGreen:   []byte{keyEscape, '[', '9', '2', 'm'},
	LightYellow:  []byte{keyEscape, '[', '9', '3', 'm'},
	LightBlue:    []byte{keyEscape, '[', '9', '4', 'm'},
	LightMagenta: []byte{keyEscape, '[', '9', '5', 'm'},
	LightCyan:    []byte{keyEscape, '[', '9', '6', 'm'},
	LightWhite:   []byte{keyEscape, '[', '9', '7', 'm'},
	Reset:        []byte{keyEscape, '[', '0', 'm'},
}

// ResponseWriter writes data and status codes to the client
type ResponseWriter struct {
	Colors ColorCodes
	Writer io.Writer
}

func (r *ResponseWriter) colorCode(color []byte, code StatusCode, format string, args ...interface{}) {

	// Set color
	r.Writer.Write(color)

	// Write error name and code
	if t, ok := statusCodes[code]; ok {
		r.Writer.Write([]byte(fmt.Sprintf(" %s (%d)", t, int(code))))
	} else {
		r.Writer.Write([]byte(fmt.Sprintf(" Unknown (%d)", int(code))))
	}

	// Write the error message if there is one
	if len(format) > 0 {
		r.Writer.Write([]byte(": "))
		fmt.Fprintf(r.Writer, format, args...)
	}

	// Reset terminal colors
	r.Writer.Write(r.Colors.Reset)
	r.Writer.Write([]byte("\r\n"))
}

// Fail writes the error status code to the Writer
func (r *ResponseWriter) Fail(code StatusCode, format string, args ...interface{}) {
	r.colorCode(r.Colors.LightRed, code, format, args...)
}

// Success writes the status code to the Writer
func (r *ResponseWriter) Success(code StatusCode, format string, args ...interface{}) {
	r.colorCode(r.Colors.LightGreen, code, format, args...)
}

// Write is a pass through function into the underlying Writer
func (r *ResponseWriter) Write(data []byte) (int, error) {
	return r.Writer.Write(data)
}
<|endoftext|>


<commit_before>package gogist

import (
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

const t = `
<html>
  <head>
    <meta name="go-import" content="%s git gist.github.com/%s/%s.git" />
    <script>window.location='https://github.com/ImJasonH/go-gist/';</script>
  </head>
</html>
`

func init() {
	r := mux.NewRouter()
	r.HandleFunc("/{username}/{gistID:[0-9]+}", func(w http.ResponseWriter, r *http.Request) {
		v := mux.Vars(r)
		w.Header().Set("Content-Type", "text/html")
		w.Write([]byte(fmt.Sprintf(t, r.URL.Host+r.URL.Path, v["username"], v["gistID"])))
	}).Methods("GET")
	http.Handle("/", r)
}
<commit_msg>Redirect from / to GitHub<commit_after>package gogist

import (
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

const t = `
<html>
  <head>
    <meta name="go-import" content="%s git gist.github.com/%s/%s.git" />
    <script>window.location='https://github.com/ImJasonH/go-gist/';</script>
  </head>
</html>
`

func init() {
	r := mux.NewRouter()
	r.HandleFunc("/{username}/{gistID:[0-9]+}", func(w http.ResponseWriter, r *http.Request) {
		v := mux.Vars(r)
		w.Header().Set("Content-Type", "text/html")
		w.Write([]byte(fmt.Sprintf(t, r.URL.Host+r.URL.Path, v["username"], v["gistID"])))
	}).Methods("GET")
	r.Handle("/", http.RedirectHandler("https://github.com/ImJasonH/go-gist", http.StatusSeeOther))
	http.Handle("/", r)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"gopkg.in/unrolled/render.v1"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

var (
	renderer    = render.New(render.Options{})
	fleetClient = NewClientCLIWithPeer("http://192.168.81.101:4001")
	tempDir     = "./tmp"
)

func main() {
	r := mux.NewRouter().StrictSlash(false)

	api := r.PathPrefix("/api/v1").Subrouter()

	// machines collection
	machines := api.Path("/machines").Subrouter()
	machines.Methods("GET").HandlerFunc(machineAllHandler)

	// Units collection
	units := api.Path("/units").Subrouter()
	units.Methods("GET").HandlerFunc(statusAllHandler)
	units.Methods("POST").HandlerFunc(submitUnitHandler)

	// Units singular
	unit := api.PathPrefix("/units/{id}").Subrouter()
	unit.Methods("GET").HandlerFunc(statusHandler)
	unit.Methods("DELETE").HandlerFunc(destroyHandler)
	unit.Path("/start").Methods("POST").HandlerFunc(startHandler)
	unit.Path("/stop").Methods("POST").HandlerFunc(stopHandler)
	unit.Path("/load").Methods("POST").HandlerFunc(loadHandler)

	// websocket
	r.Path("/ws/journal/{id}").HandlerFunc(wsHandler)

	n := negroni.New()
	n.UseHandler(r)

	n.Run(":3000")
}

func destroyHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("destroy %s unit", key)
	if err := fleetClient.Destroy(key); err != nil {
		log.Printf("unit destroy error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func startHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("start %s unit", key)
	if err := fleetClient.Start(key); err != nil {
		log.Printf("unit start error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func stopHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("stop %s unit", key)
	if err := fleetClient.Stop(key); err != nil {
		log.Printf("unit stop error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func loadHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("load %s unit", key)
	if err := fleetClient.Load(key); err != nil {
		log.Printf("unit load error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func submitUnitHandler(w http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	service := req.FormValue("service")

	if _, err := os.Stat(tempDir); os.IsNotExist(err) {
		os.Mkdir(tempDir, 0755)
	}

	tempFile, err := ioutil.TempFile(tempDir, name)
	if err != nil {
		log.Println(err)
	}
	err = ioutil.WriteFile(tempFile.Name(), []byte(service), 0644)
	if err != nil {
		log.Printf("Write file errpr: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	// err = fleetClient.Submit(name, tempFile.Name())
	// if err != nil {
	// 	log.Printf("Fleet submit error: %s", err)
	// 	renderer.JSON(w, http.StatusBadRequest, err)
	// }
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func machineAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.MachineAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.StatusAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	status, _ := fleetClient.StatusUnit(key)
	renderer.JSON(w, http.StatusOK, status)
}

// websocket handler

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// write journal message
	key := mux.Vars(r)["id"]
	output, _ := fleetClient.JournalF(key)
	for line := range output {
		conn.WriteMessage(websocket.TextMessage, []byte(line))
	}
}
<commit_msg>unit submit 완성<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"gopkg.in/unrolled/render.v1"
	"log"
	"net/http"
	"os"
	"strings"
)

var (
	renderer    = render.New(render.Options{})
	fleetClient = NewClientCLIWithPeer("http://192.168.81.101:4001")
	tempDir     = "./tmp"
)

func main() {
	r := mux.NewRouter().StrictSlash(false)

	api := r.PathPrefix("/api/v1").Subrouter()

	// machines collection
	machines := api.Path("/machines").Subrouter()
	machines.Methods("GET").HandlerFunc(machineAllHandler)

	// Units collection
	units := api.Path("/units").Subrouter()
	units.Methods("GET").HandlerFunc(statusAllHandler)
	units.Methods("POST").HandlerFunc(submitUnitHandler)

	// Units singular
	unit := api.PathPrefix("/units/{id}").Subrouter()
	unit.Methods("GET").HandlerFunc(statusHandler)
	unit.Methods("DELETE").HandlerFunc(destroyHandler)
	unit.Path("/start").Methods("POST").HandlerFunc(startHandler)
	unit.Path("/stop").Methods("POST").HandlerFunc(stopHandler)
	unit.Path("/load").Methods("POST").HandlerFunc(loadHandler)

	// websocket
	r.Path("/ws/journal/{id}").HandlerFunc(wsHandler)

	n := negroni.New()
	n.UseHandler(r)

	n.Run(":3000")
}

func destroyHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("destroy %s unit", key)
	if err := fleetClient.Destroy(key); err != nil {
		log.Printf("unit destroy error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func startHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("start %s unit", key)
	if err := fleetClient.Start(key); err != nil {
		log.Printf("unit start error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func stopHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("stop %s unit", key)
	if err := fleetClient.Stop(key); err != nil {
		log.Printf("unit stop error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func loadHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("load %s unit", key)
	if err := fleetClient.Load(key); err != nil {
		log.Printf("unit load error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func submitUnitHandler(w http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	service := req.FormValue("service")

	if _, err := os.Stat(tempDir); os.IsNotExist(err) {
		os.Mkdir(tempDir, 0755)
	}

	serviceFile := fmt.Sprintf("%s/%s", tempDir, name)
	lines := strings.Split(string(service), "\\n")

	fo, err := os.Create(serviceFile)
	if err != nil {
		log.Printf("Open file errpr: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}

	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	for _, str := range lines {
		fmt.Fprintln(fo, str)
	}

	err = fleetClient.Submit(name, serviceFile)
	if err != nil {
		log.Printf("Fleet submit error: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func machineAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.MachineAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.StatusAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	status, _ := fleetClient.StatusUnit(key)
	renderer.JSON(w, http.StatusOK, status)
}

// websocket handler

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// write journal message
	key := mux.Vars(r)["id"]
	output, _ := fleetClient.JournalF(key)
	for line := range output {
		conn.WriteMessage(websocket.TextMessage, []byte(line))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"strconv"

	"github.com/gorilla/mux"
)

const (
	NB_SERVER    = 5
	DEFAULT_FLV  = 1234
	DEFAULT_RTMP = 1935
	DOCKER_IMG   = "eip:server1"
)

type ServerConfig struct {
	Id       int64
	Name     string
	PortRTMP int
	PortFLV  int
}

var pnsEnv []ServerEnv = make([]ServerEnv, NB_SERVER)
var maxId = int64(0)

func launch_crtmpd(id int, quit_chan chan int) {
	portflv := putValueInTemplate("{{.PortFLV}}:1234", pnsEnv[id].config)
	portrtmp := putValueInTemplate("{{.PortRTMP}}:1935", pnsEnv[id].config)
	cmd := exec.Command("docker", "run", "-d", "--name", pnsEnv[id].config.Name, "-p", portflv, "-p", portrtmp, DOCKER_IMG)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}

	err = cmd.Start()
	if err != nil {
		log.Fatal("Can't start the crtmpd server. ", err)
	}
	lol := make([]byte, 4096)
	stderr.Read(lol)
	log.Printf(string(lol))
	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
}

/*
POST /create
	-> name
	=> { ip, portRTMP, portFLV, id }
*/
func new_server(w http.ResponseWriter, req *http.Request) {
	params := mux.Vars(req)
	log.Printf("New Server: %s", params["name"])
	// EMPECHER 2x le meme name
	id := getFirstFree()
	if id == -1 {
		AnswerError(w, -1, "Server is full, please wait or take another one.")
		return
	}

	portflv, portrtmp := getPortsForId(id)
	pnsEnv[id].Add(params["name"], portflv, portrtmp)
	// VOIR SI Y'A UNE ERREUR OU PAS !
	go launch_crtmpd(id, pnsEnv[id].server_channel)
	b, err := json.Marshal(pnsEnv[id].config)
	if err != nil {
		AnswerError(w, -2, "Can't answer in JSON...")
		return
	} else {
		w.Write(b)
	}
}

/*
GET /list
	=> json of the containers
*/
func list_server(w http.ResponseWriter, req *http.Request) {
	list := ""
	// MODIFIER CECI POUR ENVOYER DU JSON
	for _, val := range pnsEnv {
		list += fmt.Sprintf("* %v\n", val.config)
	}
	w.Write([]byte(list))
}

/*
POST /delete
	-> id
	=> json
*/
func delete_server(w http.ResponseWriter, req *http.Request) {
	params := mux.Vars(req)
	id, _ := strconv.ParseInt(params["id"], 10, 32)
	container, id_container := getServerConfigForId(id)

	if container == nil {
		AnswerError(w, -3, "Cannot find a container with this id.")
		return
	}

	cmd := exec.Command("docker", "rm", "-f", container.Name)
	err := cmd.Start()
	if err != nil {
		AnswerError(w, -4, "Can't shutdown the container.")
		return
	}
	pnsEnv[id_container].Del() // RECUP ERREUR SI Y'EN A UNE
	log.Printf("deleting id: %d", id)
	AnswerError(w, 1, "Successfuly deleted.")
}

func main() {

	//cmd := exec.Command("docker", "build", "-t", DOCKER_IMG, ".")
	//err := cmd.Run()
	//if err != nil {
	//	log.Fatal("Can't create the Docker image... => ", err)
	//} else {
	//	log.Print("Docker image created.")
	//}

	maxId = 0

	r := mux.NewRouter()
	r.HandleFunc("/new/{name}", new_server).Methods("GET")
	r.HandleFunc("/delete/{id}", delete_server).Methods("GET")
	r.HandleFunc("/list", list_server).Methods("GET")
	log.Printf("Listening ...")
	http.Handle("/", r)
	http.ListenAndServe(":3001", nil)
}
<commit_msg>Modifying the tag of the image to be consistant with the documentation<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"strconv"

	"github.com/gorilla/mux"
)

const (
	NB_SERVER    = 5
	DEFAULT_FLV  = 1234
	DEFAULT_RTMP = 1935
	DOCKER_IMG   = "pns:server"
)

type ServerConfig struct {
	Id       int64
	Name     string
	PortRTMP int
	PortFLV  int
}

var pnsEnv []ServerEnv = make([]ServerEnv, NB_SERVER)
var maxId = int64(0)

func launch_crtmpd(id int, quit_chan chan int) {
	portflv := putValueInTemplate("{{.PortFLV}}:1234", pnsEnv[id].config)
	portrtmp := putValueInTemplate("{{.PortRTMP}}:1935", pnsEnv[id].config)
	cmd := exec.Command("docker", "run", "-d", "--name", pnsEnv[id].config.Name, "-p", portflv, "-p", portrtmp, DOCKER_IMG)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}

	err = cmd.Start()
	if err != nil {
		log.Fatal("Can't start the crtmpd server. ", err)
	}
	lol := make([]byte, 4096)
	stderr.Read(lol)
	log.Printf(string(lol))
	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
}

/*
POST /create
	-> name
	=> { ip, portRTMP, portFLV, id }
*/
func new_server(w http.ResponseWriter, req *http.Request) {
	params := mux.Vars(req)
	log.Printf("New Server: %s", params["name"])
	// EMPECHER 2x le meme name
	id := getFirstFree()
	if id == -1 {
		AnswerError(w, -1, "Server is full, please wait or take another one.")
		return
	}

	portflv, portrtmp := getPortsForId(id)
	pnsEnv[id].Add(params["name"], portflv, portrtmp)
	// VOIR SI Y'A UNE ERREUR OU PAS !
	go launch_crtmpd(id, pnsEnv[id].server_channel)
	b, err := json.Marshal(pnsEnv[id].config)
	if err != nil {
		AnswerError(w, -2, "Can't answer in JSON...")
		return
	} else {
		w.Write(b)
	}
}

/*
GET /list
	=> json of the containers
*/
func list_server(w http.ResponseWriter, req *http.Request) {
	list := ""
	// MODIFIER CECI POUR ENVOYER DU JSON
	for _, val := range pnsEnv {
		list += fmt.Sprintf("* %v\n", val.config)
	}
	w.Write([]byte(list))
}

/*
POST /delete
	-> id
	=> json
*/
func delete_server(w http.ResponseWriter, req *http.Request) {
	params := mux.Vars(req)
	id, _ := strconv.ParseInt(params["id"], 10, 32)
	container, id_container := getServerConfigForId(id)

	if container == nil {
		AnswerError(w, -3, "Cannot find a container with this id.")
		return
	}

	cmd := exec.Command("docker", "rm", "-f", container.Name)
	err := cmd.Start()
	if err != nil {
		AnswerError(w, -4, "Can't shutdown the container.")
		return
	}
	pnsEnv[id_container].Del() // RECUP ERREUR SI Y'EN A UNE
	log.Printf("deleting id: %d", id)
	AnswerError(w, 1, "Successfuly deleted.")
}

func main() {

	//cmd := exec.Command("docker", "build", "-t", DOCKER_IMG, ".")
	//err := cmd.Run()
	//if err != nil {
	//	log.Fatal("Can't create the Docker image... => ", err)
	//} else {
	//	log.Print("Docker image created.")
	//}

	maxId = 0

	r := mux.NewRouter()
	r.HandleFunc("/new/{name}", new_server).Methods("GET")
	r.HandleFunc("/delete/{id}", delete_server).Methods("GET")
	r.HandleFunc("/list", list_server).Methods("GET")
	log.Printf("Listening ...")
	http.Handle("/", r)
	http.ListenAndServe(":3001", nil)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package fuseutil

import (
	"bazil.org/fuse"
	fusefs "bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

// A struct representing the status of a mount operation, with methods for
// waiting on the mount to complete, waiting for unmounting, and causing
// unmounting.
type MountedFileSystem struct {
	dir string
}

// Wait until the mount point is ready to be used. After a successful return
// from this function, the contents of the mounted file system should be
// visible in the directory supplied to NewMountPoint. May be called multiple
// times.
func (mfs *MountedFileSystem) WaitForReady(ctx context.Context) error

// Block until the file system has been unmounted. The return value will be
// non-nil if anything unexpected happened while mounting or serving. May be
// called multiple times.
func (mfs *MountedFileSystem) Join() error

// Attempt to unmount the file system. Use Join to wait for it to actually be
// unmounted. You must first call WaitForReady to ensure there is no race with
// mounting.
func (mfs *MountedFileSystem) Unmount() error

// Runs in the background.
func (mfs *MountedFileSystem) mountAndServe(
	fs fusefs.FS,
	options []fuse.MountOption)

// Attempt to mount the supplied file system on the given directory.
// mfs.WaitForReady() must be called to find out whether the mount was
// successful.
func MountFileSystem(
	dir string,
	fs fusefs.FS,
	options ...fuse.MountOption) (mfs *MountedFileSystem) {
	// Initialize the struct.
	mfs = &MountedFileSystem{
		dir: dir,
	}

	// Mount in the background.
	go mfs.mountAndServe(fs, options)

	return mfs
}
<commit_msg>Implemented WaitForReady.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package fuseutil

import (
	"bazil.org/fuse"
	fusefs "bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

// A struct representing the status of a mount operation, with methods for
// waiting on the mount to complete, waiting for unmounting, and causing
// unmounting.
type MountedFileSystem struct {
	dir string

	// The result to return from WaitForReady. Not valid until the channel is closed.
	readyStatus          error
	readyStatusAvailable chan struct{}
}

// Wait until the mount point is ready to be used. After a successful return
// from this function, the contents of the mounted file system should be
// visible in the directory supplied to NewMountPoint. May be called multiple
// times.
func (mfs *MountedFileSystem) WaitForReady(ctx context.Context) error {
	select {
	case <-mfs.readyStatusAvailable:
		return mfs.readyStatus
	case <-ctx.Done():
		return ctx.Err()
	}
}

// Block until the file system has been unmounted. The return value will be
// non-nil if anything unexpected happened while mounting or serving. May be
// called multiple times.
func (mfs *MountedFileSystem) Join() error

// Attempt to unmount the file system. Use Join to wait for it to actually be
// unmounted. You must first call WaitForReady to ensure there is no race with
// mounting.
func (mfs *MountedFileSystem) Unmount() error

// Runs in the background.
func (mfs *MountedFileSystem) mountAndServe(
	fs fusefs.FS,
	options []fuse.MountOption)

// Attempt to mount the supplied file system on the given directory.
// mfs.WaitForReady() must be called to find out whether the mount was
// successful.
func MountFileSystem(
	dir string,
	fs fusefs.FS,
	options ...fuse.MountOption) (mfs *MountedFileSystem) {
	// Initialize the struct.
	mfs = &MountedFileSystem{
		dir:                  dir,
		readyStatusAvailable: make(chan struct{}),
	}

	// Mount in the background.
	go mfs.mountAndServe(fs, options)

	return mfs
}
<|endoftext|>


<commit_before>package tokenizer

// WordProps qualifies a token whose type is one of `TokMayBeWord` or
// `TokWord`.
//
// It holds information regarding the so-called IOB (Inside, Outside,
// Beginning) status of the token, its lemma form (in case of a word),
// its part of speech (in case of a word), etc.
type WordProps struct {
	Word   Token  // The token being qualified.
	IsWord bool   // TokMayBeWord, etc. (false) vs. TokWord (true)
	IOB    byte   // 'B', 'I' or 'O'
	Lemma  string // Lemma form
	PoS    string // Part of Speech
}
<commit_msg>Add a `Word` type of token<commit_after>package tokenizer

// Word represents a token whose type is one of `TokMayBeWord` or
// `TokWord`, and qualifies it.
//
// It holds information regarding the so-called IOB (Inside, Outside,
// Beginning) status of the token, its lemma form (in case of a word),
// its part of speech (in case of a word), etc.
type Word struct {
	token TextToken // Actual text and its properties
	iob   byte      // 'B', 'I' or 'O'
	lemma string    // Lemma form
	pos   string    // Part of Speech
}

func (w *Word) Text() string {
	return w.token.text
}

func (w *Word) Begin() int {
	return w.token.begin
}

func (w *Word) End() int {
	return w.token.end
}

func (w *Word) Type() TokenType {
	return w.token.ttype
}

func (w *Word) IOB() byte {
	return w.iob
}

func (w *Word) Lemma() string {
	return w.lemma
}

func (w *Word) POS() string {
	return w.pos
}
<|endoftext|>


<commit_before><commit_msg>remove url from log<commit_after><|endoftext|>


<commit_before>package channels

import (
	"testing"

	"github.com/couchbase/sync_gateway/base"
	goassert "github.com/couchbaselabs/go.assert"
	"github.com/stretchr/testify/assert"
)

func TestRequireUser(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireUser(oldDoc._names) }`
	runner, err := NewSyncRunner(funcSource)
	assert.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{"_names": "alpha"}`), parse(`{"name": "alpha"}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_names": ["beta", "gamma"]}`), parse(`{"name": "beta"}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_names": ["delta"]}`), parse(`{"name": "beta"}`))
	assertRejected(t, result, base.HTTPErrorf(403, base.SyncFnErrorWrongUser))
}

func TestRequireRole(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireRole(oldDoc._roles) }`
	runner, err := NewSyncRunner(funcSource)
	assert.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{"_roles": ["alpha"]}`), parse(`{"name": "", "roles": {"alpha":""}}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_roles": ["beta", "gamma"]}`), parse(`{"name": "", "roles": {"beta": ""}}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_roles": ["delta"]}`), parse(`{"name": "", "roles": {"beta":""}}`))
	assertRejected(t, result, base.HTTPErrorf(403, base.SyncFnErrorMissingRole))
}

func TestRequireAccess(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireAccess(oldDoc._access) }`
	runner, err := NewSyncRunner(funcSource)
	assert.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{"_access": ["alpha"]}`), parse(`{"name": "", "channels": ["alpha"]}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_access": ["beta", "gamma"]}`), parse(`{"name": "", "channels": ["beta"]}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_access": ["delta"]}`), parse(`{"name": "", "channels": ["beta"]}`))
	assertRejected(t, result, base.HTTPErrorf(403, base.SyncFnErrorMissingChannelAccess))
}

func TestRequireAdmin(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireAdmin() }`
	runner, err := NewSyncRunner(funcSource)
	assert.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{"name": ""}`))
	assertRejected(t, result, base.HTTPErrorf(403, base.SyncFnErrorAdminRequired))
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{"name": "GUEST"}`))
	assertRejected(t, result, base.HTTPErrorf(403, base.SyncFnErrorAdminRequired))
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{"name": "beta"}`))
	assertRejected(t, result, base.HTTPErrorf(403, base.SyncFnErrorAdminRequired))
}

// Helpers
func assertRejected(t *testing.T, result interface{}, err *base.HTTPError) {
	r, ok := result.(*ChannelMapperOutput)
	goassert.True(t, ok)
	goassert.DeepEquals(t, r.Rejection, err)
}

func assertNotRejected(t *testing.T, result interface{}) {
	r, ok := result.(*ChannelMapperOutput)
	if !ok || r.Rejection != nil {
		t.Fatalf("%v", r.Rejection)
	}
}
<commit_msg>Refactor sync runner tests to stop the test when NewSyncRunner instance creation fails (#4820)<commit_after>package channels

import (
	"net/http"
	"testing"

	"github.com/couchbase/sync_gateway/base"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestRequireUser(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireUser(oldDoc._names) }`
	runner, err := NewSyncRunner(funcSource)
	require.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{"_names": "alpha"}`), parse(`{"name": "alpha"}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_names": ["beta", "gamma"]}`), parse(`{"name": "beta"}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_names": ["delta"]}`), parse(`{"name": "beta"}`))
	assertRejected(t, result, base.HTTPErrorf(http.StatusForbidden, base.SyncFnErrorWrongUser))
}

func TestRequireRole(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireRole(oldDoc._roles) }`
	runner, err := NewSyncRunner(funcSource)
	require.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{"_roles": ["alpha"]}`), parse(`{"name": "", "roles": {"alpha":""}}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_roles": ["beta", "gamma"]}`), parse(`{"name": "", "roles": {"beta": ""}}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_roles": ["delta"]}`), parse(`{"name": "", "roles": {"beta":""}}`))
	assertRejected(t, result, base.HTTPErrorf(http.StatusForbidden, base.SyncFnErrorMissingRole))
}

func TestRequireAccess(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireAccess(oldDoc._access) }`
	runner, err := NewSyncRunner(funcSource)
	require.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{"_access": ["alpha"]}`), parse(`{"name": "", "channels": ["alpha"]}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_access": ["beta", "gamma"]}`), parse(`{"name": "", "channels": ["beta"]}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{"_access": ["delta"]}`), parse(`{"name": "", "channels": ["beta"]}`))
	assertRejected(t, result, base.HTTPErrorf(http.StatusForbidden, base.SyncFnErrorMissingChannelAccess))
}

func TestRequireAdmin(t *testing.T) {
	const funcSource = `function(doc, oldDoc) { requireAdmin() }`
	runner, err := NewSyncRunner(funcSource)
	require.NoError(t, err)
	var result interface{}
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{}`))
	assertNotRejected(t, result)
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{"name": ""}`))
	assertRejected(t, result, base.HTTPErrorf(http.StatusForbidden, base.SyncFnErrorAdminRequired))
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{"name": "GUEST"}`))
	assertRejected(t, result, base.HTTPErrorf(http.StatusForbidden, base.SyncFnErrorAdminRequired))
	result, _ = runner.Call(parse(`{}`), parse(`{}`), parse(`{"name": "beta"}`))
	assertRejected(t, result, base.HTTPErrorf(http.StatusForbidden, base.SyncFnErrorAdminRequired))
}

// Helpers
func assertRejected(t *testing.T, result interface{}, err *base.HTTPError) {
	r, ok := result.(*ChannelMapperOutput)
	assert.True(t, ok)
	assert.Equal(t, r.Rejection, err)
}

func assertNotRejected(t *testing.T, result interface{}) {
	r, ok := result.(*ChannelMapperOutput)
	assert.True(t, ok)
	assert.NoError(t, r.Rejection)
}
<|endoftext|>