<commit_before>/*
Package easy is an easier interface to use cirello.io/supervisor. Its lifecycle
is managed through context.Context. Stop a given supervisor by cancelling its
context.

	package main

	import supervisor "cirello.io/supervisor/easy"

	func main() {
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()
		// use cancel() to stop the supervisor
		ctx = supervisor.WrapContext(ctx)
		supervisor.Add(ctx, func(ctx context.Context) {
			// ...
		})
	}
*/
package easy

import (
	"context"
	"errors"
	"fmt"
	"math/rand"
	"sync"

	"cirello.io/supervisor"
)

type ctxKey int

const supervisorName ctxKey = 0

var (
	// ErrNoSupervisorAttached means that the given context has not been wrapped
	// with WrapContext, and thus this package cannot detect which supervisore
	// you are referring to.
	ErrNoSupervisorAttached = errors.New("no supervisor attached to context")

	mu          sync.Mutex
	supervisors map[string]*supervisor.Group // map of supevisor name to supervisor.Supervisor
)

func init() {
	supervisors = make(map[string]*supervisor.Group)
}

// Add inserts supervised function to the attached supervisor, it launches
// automatically. If the context is not correctly prepared, it returns an
// ErrNoSupervisorAttached error
func Add(ctx context.Context, f func(context.Context), opts ...supervisor.ServiceOption) (string, error) {
	name, ok := extractName(ctx)
	if !ok {
		return "", ErrNoSupervisorAttached
	}
	mu.Lock()
	svr, ok := supervisors[name]
	mu.Unlock()
	if !ok {
		panic("supervisor not found")
	}
	svcName := svr.AddFunc(f, opts...)
	return svcName, nil
}

// Remove stops and removes the given service from the attached supervisor. If
// the context is not correctly prepared, it returns an ErrNoSupervisorAttached
// error
func Remove(ctx context.Context, name string) error {
	name, ok := extractName(ctx)
	if !ok {
		return ErrNoSupervisorAttached
	}
	mu.Lock()
	svr, ok := supervisors[name]
	mu.Unlock()
	if !ok {
		panic("supervisor not found")
	}
	svr.Remove(name)
	return nil
}

// WrapContext takes a context and prepare it to be used by easy supervisor
// package. Internally, it creates a supervisor in group mode. In this mode,
// every time a service dies, the whole supervisor is restarted.
func WrapContext(ctx context.Context) context.Context {
	chosenName := fmt.Sprintf("supervisor-%d", rand.Uint64())

	wrapped := context.WithValue(ctx, supervisorName, chosenName)
	svr := &supervisor.Group{
		Supervisor: &supervisor.Supervisor{
			Log: func(interface{}) {},
		},
	}
	mu.Lock()
	supervisors[chosenName] = svr
	mu.Unlock()
	go svr.Serve(wrapped)

	return wrapped
}

func extractName(ctx context.Context) (string, bool) {
	name, ok := ctx.Value(supervisorName).(string)
	return name, ok
}
<commit_msg>Make sure that the easy supervisor is persistent<commit_after>/*
Package easy is an easier interface to use cirello.io/supervisor. Its lifecycle
is managed through context.Context. Stop a given supervisor by cancelling its
context.

	package main

	import supervisor "cirello.io/supervisor/easy"

	func main() {
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()
		// use cancel() to stop the supervisor
		ctx = supervisor.WrapContext(ctx)
		supervisor.Add(ctx, func(ctx context.Context) {
			// ...
		})
	}
*/
package easy

import (
	"context"
	"errors"
	"fmt"
	"math/rand"
	"sync"

	"cirello.io/supervisor"
)

type ctxKey int

const supervisorName ctxKey = 0

var (
	// ErrNoSupervisorAttached means that the given context has not been wrapped
	// with WrapContext, and thus this package cannot detect which supervisore
	// you are referring to.
	ErrNoSupervisorAttached = errors.New("no supervisor attached to context")

	mu          sync.Mutex
	supervisors map[string]*supervisor.Group // map of supevisor name to supervisor.Supervisor
)

func init() {
	supervisors = make(map[string]*supervisor.Group)
}

// Add inserts supervised function to the attached supervisor, it launches
// automatically. If the context is not correctly prepared, it returns an
// ErrNoSupervisorAttached error
func Add(ctx context.Context, f func(context.Context), opts ...supervisor.ServiceOption) (string, error) {
	name, ok := extractName(ctx)
	if !ok {
		return "", ErrNoSupervisorAttached
	}
	mu.Lock()
	svr, ok := supervisors[name]
	mu.Unlock()
	if !ok {
		panic("supervisor not found")
	}
	svcName := svr.AddFunc(f, opts...)
	return svcName, nil
}

// Remove stops and removes the given service from the attached supervisor. If
// the context is not correctly prepared, it returns an ErrNoSupervisorAttached
// error
func Remove(ctx context.Context, name string) error {
	name, ok := extractName(ctx)
	if !ok {
		return ErrNoSupervisorAttached
	}
	mu.Lock()
	svr, ok := supervisors[name]
	mu.Unlock()
	if !ok {
		panic("supervisor not found")
	}
	svr.Remove(name)
	return nil
}

// WrapContext takes a context and prepare it to be used by easy supervisor
// package. Internally, it creates a supervisor in group mode. In this mode,
// every time a service dies, the whole supervisor is restarted.
func WrapContext(ctx context.Context) context.Context {
	chosenName := fmt.Sprintf("supervisor-%d", rand.Uint64())

	wrapped := context.WithValue(ctx, supervisorName, chosenName)
	svr := &supervisor.Group{
		Supervisor: &supervisor.Supervisor{
			MaxRestarts: supervisor.AlwaysRestart,
			Log:         func(interface{}) {},
		},
	}
	mu.Lock()
	supervisors[chosenName] = svr
	mu.Unlock()
	go svr.Serve(wrapped)

	return wrapped
}

func extractName(ctx context.Context) (string, bool) {
	name, ok := ctx.Value(supervisorName).(string)
	return name, ok
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
)

var (
	dataFile = flag.String("file", "store.json", "data store file name")
	status   = flag.String("status", "stopped|pending|terminated", "the status you would like to poll")
	useToml  = flag.Bool("toml", false, "A switch to use creds from tomlfile instead of ENV")
)

var store *StatusStore

type Conn struct {
	aw2  *ec2.EC2
	data map[string]string
}

// create a struct to map toml config file
// TODO: add this as an switch in init()
type AwsConfig struct {
	AwsSecretKey string `toml:"AWS_ACCESS_KEY_ID"`
	AwsAccessKey string `toml:"AWS_SECRET_ACCESS_KEY"`
	Region       string `toml:"AWS_REGION"`
}

func recieveStatus(dataMap map[string]string) <-chan string {
	c := make(chan string)
	go func() {
		for _, v := range dataMap {
			c <- fmt.Sprintf("%s", v)
			//			time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
		}
	}()
	return c

}

func (c *Conn) iterateResToMap(resp *ec2.DescribeInstancesOutput) {
	insMap := make(map[string]string)
	for idx, _ := range resp.Reservations {
		for _, inst := range resp.Reservations[idx].Instances {
			// fmt.Printf("   Instance State: %v InstanceID: %v \n", *inst.State.Name, *inst.InstanceID)
			// dereference pointer
			var id, state string
			id = *inst.PrivateDNSName
			state = *inst.State.Name
			insMap[id] = state
		}
	}
	c.data = insMap
}

func (c *Conn) GetEc2Data() {

	resp, err := c.aw2.DescribeInstances(nil)
	if err != nil {
		log.Fatal(err)
	}

	c.iterateResToMap(resp)

}

func NewEc2() *Conn {
	c := new(Conn)
	c.aw2 = ec2.New(&aws.Config{Region: "us-west-2"})

	return c
}

func (d *StatusStore) AddDataToFile(status string, c *Conn) {
	for k, v := range c.data {
		if v == status {
			if _, ok := d.status[k]; ok {
			} else {
				err := d.save(k, v)
				if err != nil {
					log.Printf("something went wrong save %s", k)
				}
			}
		}
	}
}

func Add(value string) {
	key := store.Put(value)
	fmt.Println(key)
}

func main() {
	// Create an EC2 service object in the "us-west-2" region
	// Note that you can also configure your region globally by
	// exporting the AWS_REGION environment variable
	flag.Parse()

	// instantiate new ec2 "object"
	c := NewEc2()

	// Get new Status store
	d := NewStatusStore(*dataFile)

	// Get a data set to work with
	c.GetEc2Data()

	// lets save some data
	d.AddDataToFile(*status, c)

}
<commit_msg>skel function TODO: added<commit_after>package main

import (
	"flag"
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
)

var (
	dataFile = flag.String("file", "store.json", "data store file name")
	status   = flag.String("status", "stopped|pending|terminated", "the status you would like to poll")
	useToml  = flag.Bool("toml", false, "A switch to use creds from tomlfile instead of ENV")
)

var store *StatusStore

type Conn struct {
	aw2  *ec2.EC2
	data map[string]string
}

// create a struct to map toml config file
// TODO: add this as an switch in init()
type AwsConfig struct {
	AwsSecretKey string `toml:"AWS_ACCESS_KEY_ID"`
	AwsAccessKey string `toml:"AWS_SECRET_ACCESS_KEY"`
	Region       string `toml:"AWS_REGION"`
}

func recieveStatus(dataMap map[string]string) <-chan string {
	c := make(chan string)
	go func() {
		for _, v := range dataMap {
			c <- fmt.Sprintf("%s", v)
			//			time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
		}
	}()
	return c

}

func (c *Conn) iterateResToMap(resp *ec2.DescribeInstancesOutput) {
	insMap := make(map[string]string)
	for idx, _ := range resp.Reservations {
		for _, inst := range resp.Reservations[idx].Instances {
			// fmt.Printf("   Instance State: %v InstanceID: %v \n", *inst.State.Name, *inst.InstanceID)
			// dereference pointer
			var id, state string
			id = *inst.PrivateDNSName
			state = *inst.State.Name
			insMap[id] = state
		}
	}
	c.data = insMap
}

func (c *Conn) GetEc2Data() {

	resp, err := c.aw2.DescribeInstances(nil)
	if err != nil {
		log.Fatal(err)
	}

	c.iterateResToMap(resp)

}

func NewEc2() *Conn {
	c := new(Conn)
	c.aw2 = ec2.New(&aws.Config{Region: "us-west-2"})

	return c
}

func (d *StatusStore) AddDataToFile(status string, c *Conn) {
	for k, v := range c.data {
		if v == status {
			if _, ok := d.status[k]; ok {
			} else {
				err := d.save(k, v)
				if err != nil {
					log.Printf("something went wrong save %s", k)
				}
			}
		}
	}
}

func Run() {
	// do something here to poll refresh data and other things
}

func Add(value string) {
	key := store.Put(value)
	fmt.Println(key)
}

func main() {
	// Create an EC2 service object in the "us-west-2" region
	// Note that you can also configure your region globally by
	// exporting the AWS_REGION environment variable
	flag.Parse()

	// instantiate new ec2 "object"
	c := NewEc2()

	// Get new Status store
	d := NewStatusStore(*dataFile)

	// Get a data set to work with
	c.GetEc2Data()

	// lets save some data
	d.AddDataToFile(*status, c)

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/standard"
	"github.com/labstack/echo/middleware"
)

func main() {
	m := echo.New()
	m.Use(middleware.Logger())
	m.Use(middleware.Recover())

	m.GET("/", func(ctx echo.Context) error {
		return ctx.String(200, "Hello World")
	})

	m.GET("/json", func(ctx echo.Context) error {
		return ctx.JSON(200, map[string]string{
			"hello": "world",
		})
	})

	m.Run(standard.New(":9090"))
}
<commit_msg>Passing variables to context in Echo<commit_after>package main

import (
	"github.com/labstack/echo"
	"github.com/labstack/echo/engine/standard"
	"github.com/labstack/echo/middleware"
)

type repository interface {
	All() []string
}

type dummy struct{}

func (d dummy) All() []string {
	return []string{"Go", "Echo"}
}

func repositoryMiddleware(r repository) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(ctx echo.Context) error {
			ctx.Set("repository", r)
			return next(ctx)
		}
	}
}

func main() {
	m := echo.New()
	m.Use(middleware.Logger())
	m.Use(middleware.Recover())
	m.Use(repositoryMiddleware(dummy{}))

	m.Get("/", func(ctx echo.Context) error {
		return ctx.String(200, "Hello World")
	})

	m.Get("/json", func(ctx echo.Context) error {
		repo := ctx.Get("repository").(repository)

		return ctx.JSON(200, repo.All())
	})

	m.Run(standard.New(":9090"))
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"errors"
	"os"
	"os/signal"

	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/client"
)

// NewWatchCommand returns the CLI command for "watch".
func NewWatchCommand() cli.Command {
	return cli.Command{
		Name:  "watch",
		Usage: "watch a key for changes",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "forever", Usage: "forever watch a key until CTRL+C"},
			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
			cli.BoolFlag{Name: "recursive", Usage: "returns all values for key and child keys"},
		},
		Action: func(c *cli.Context) {
			watchCommandFunc(c, mustNewKeyAPI(c))
		},
	}
}

// watchCommandFunc executes the "watch" command.
func watchCommandFunc(c *cli.Context, ki client.KeysAPI) {
	if len(c.Args()) == 0 {
		handleError(ExitBadArgs, errors.New("key required"))
	}
	key := c.Args()[0]
	recursive := c.Bool("recursive")
	forever := c.Bool("forever")
	index := 0
	if c.Int("after-index") != 0 {
		index = c.Int("after-index") + 1
	}

	stop := false
	w := ki.Watcher(key, &client.WatcherOptions{AfterIndex: uint64(index), Recursive: recursive})

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, os.Interrupt)

	go func() {
		<-sigch
		os.Exit(0)
	}()

	for !stop {
		resp, err := w.Next(context.TODO())
		if err != nil {
			handleError(ExitServerError, err)
		}
		if resp.Node.Dir {
			continue
		}
		printResponseKey(resp, c.GlobalString("output"))

		if !forever {
			stop = true
		}
	}
}
<commit_msg>etcdctl: print out key and action when watching recursively<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package command

import (
	"errors"
	"fmt"
	"os"
	"os/signal"

	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/client"
)

// NewWatchCommand returns the CLI command for "watch".
func NewWatchCommand() cli.Command {
	return cli.Command{
		Name:  "watch",
		Usage: "watch a key for changes",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "forever", Usage: "forever watch a key until CTRL+C"},
			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
			cli.BoolFlag{Name: "recursive", Usage: "returns all values for key and child keys"},
		},
		Action: func(c *cli.Context) {
			watchCommandFunc(c, mustNewKeyAPI(c))
		},
	}
}

// watchCommandFunc executes the "watch" command.
func watchCommandFunc(c *cli.Context, ki client.KeysAPI) {
	if len(c.Args()) == 0 {
		handleError(ExitBadArgs, errors.New("key required"))
	}
	key := c.Args()[0]
	recursive := c.Bool("recursive")
	forever := c.Bool("forever")
	index := 0
	if c.Int("after-index") != 0 {
		index = c.Int("after-index") + 1
	}

	stop := false
	w := ki.Watcher(key, &client.WatcherOptions{AfterIndex: uint64(index), Recursive: recursive})

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, os.Interrupt)

	go func() {
		<-sigch
		os.Exit(0)
	}()

	for !stop {
		resp, err := w.Next(context.TODO())
		if err != nil {
			handleError(ExitServerError, err)
		}
		if resp.Node.Dir {
			continue
		}
		if recursive {
			fmt.Printf("[%s] %s\n", resp.Action, resp.Node.Key)
		}

		printResponseKey(resp, c.GlobalString("output"))

		if !forever {
			stop = true
		}
	}
}
<|endoftext|>


<commit_before>package etcdhttp

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
	"time"

	"code.google.com/p/go.net/context"

	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/raft"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/store"
)

func nopSave(st raftpb.State, ents []raftpb.Entry) {}
func nopSend(m []raftpb.Message)                   {}

func TestSet(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	st := store.New()

	n := raft.Start(1, []int64{1})
	n.Campaign(ctx)

	srv := &etcdserver.Server{
		Node:  n,
		Store: st,
		Send:  etcdserver.SendFunc(nopSend),
		Save:  func(st raftpb.State, ents []raftpb.Entry) {},
	}
	etcdserver.Start(srv)
	defer srv.Stop()

	h := Handler{
		Timeout: time.Hour,
		Server:  srv,
	}

	s := httptest.NewServer(h)
	defer s.Close()

	resp, err := http.PostForm(s.URL+"/keys/foo", url.Values{"value": {"bar"}})
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != 201 {
		t.Errorf("StatusCode = %d, expected %d", 201, resp.StatusCode)
	}

	g := new(store.Event)
	if err := json.NewDecoder(resp.Body).Decode(&g); err != nil {
		t.Fatal(err)
	}

	w := &store.NodeExtern{
		Key:           "/foo/1",
		Value:         stringp("bar"),
		ModifiedIndex: 1,
		CreatedIndex:  1,
	}
	if !reflect.DeepEqual(g.Node, w) {
		t.Errorf("g = %+v, want %+v", g.Node, w)
	}
}

func stringp(s string) *string { return &s }
<commit_msg>etcdhttp: fix test build<commit_after>package etcdhttp

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
	"time"

	"code.google.com/p/go.net/context"

	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/raft"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/store"
)

func nopSave(st raftpb.State, ents []raftpb.Entry) {}
func nopSend(m []raftpb.Message)                   {}

func TestSet(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	st := store.New()

	n := raft.Start(1, []int64{1}, 0, 0)
	n.Campaign(ctx)

	srv := &etcdserver.Server{
		Node:  n,
		Store: st,
		Send:  etcdserver.SendFunc(nopSend),
		Save:  func(st raftpb.State, ents []raftpb.Entry) {},
	}
	etcdserver.Start(srv)
	defer srv.Stop()

	h := Handler{
		Timeout: time.Hour,
		Server:  srv,
	}

	s := httptest.NewServer(h)
	defer s.Close()

	resp, err := http.PostForm(s.URL+"/keys/foo", url.Values{"value": {"bar"}})
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != 201 {
		t.Errorf("StatusCode = %d, expected %d", 201, resp.StatusCode)
	}

	g := new(store.Event)
	if err := json.NewDecoder(resp.Body).Decode(&g); err != nil {
		t.Fatal(err)
	}

	w := &store.NodeExtern{
		Key:           "/foo/1",
		Value:         stringp("bar"),
		ModifiedIndex: 1,
		CreatedIndex:  1,
	}
	if !reflect.DeepEqual(g.Node, w) {
		t.Errorf("g = %+v, want %+v", g.Node, w)
	}
}

func stringp(s string) *string { return &s }
<|endoftext|>


<commit_before>
package core

import ("fmt"
	"os"
	"strconv"
	"runtime"
	"math"
	"bytes"
	"time"
	"github.com/jackyb/go-sdl2/sdl"
	"github.com/op/go-nanomsg"
	"github.com/fire/go-ogre3d"
	"github.com/jmckaskill/go-capnproto")

type InputState struct {
	yawSens float32
	pitchSens float32
	orientationFactor float32 // +1/-1 easy switch between look around and manipulate something
	yaw float32 // degrees, modulo [-180,180] range
	pitch float32 // degrees, clamped [-90,90] range
	roll float32
	orientation ogre.Quaternion // current orientation
}

func InitCore() {
	var gameThreadParams GameThreadParams
	gameThreadParams.start = time.Now() // There's an small time before this variable is initalized,
	// it probably doesn't matter... Someone timed Go initalization at 1.94us on Linux.

	sdl.Init(sdl.INIT_EVERYTHING)
	var event sdl.Event
	window := sdl.CreateWindow("es_core::SDL",
		sdl.WINDOWPOS_UNDEFINED,
		sdl.WINDOWPOS_UNDEFINED,
		800,
		600,
		sdl.WINDOW_OPENGL|sdl.WINDOW_SHOWN)
	if window == nil {
		panic(fmt.Sprintf("sdl.CreateWindow failed: %s\n", sdl.GetError()))
	}
	defer sdl.Quit()
	glContext := sdl.GL_CreateContext(window)

	var info sdl.SysWMInfo
	if !window.GetWMInfo(&info) {
		panic(fmt.Sprintf("window.GetWMInfo failed.\n"))
	}
	var version sdl.Version
	sdl.GetVersion(&version)

	fmt.Printf("Sdl Major Version: %d\n", version.Major)
	fmt.Printf("Sdl Minor Version: %d\n", version.Minor)
	fmt.Printf("Sdl Patch level: %d\n", version.Patch)
	fmt.Printf("Sdl Subsystem: %s\n", getSubsystemString(info))
	root := ogre.NewRoot("", "", "ogre.log")
	defer root.Destroy()
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if runtime.GOOS == "windows" {
		root.LoadPlugin(wd  + "/RenderSystem_GL3Plus")
		}
	if runtime.GOOS == "darwin" {
		root.LoadPlugin(wd  + "/../frameworks/RenderSystem_GL3Plus")
	}

	renderers := root.GetAvailableRenderers()
	if renderers.RenderSystemListSize() != 1 {

		panic(fmt.Sprintf("Failed to initalize RendererRenderSystem_GL"))
	}
	root.SetRenderSystem(renderers.RenderSystemListGet(0))
	root.Initialise(false, "es_core::ogre")
	params := ogre.CreateNameValuePairList()
	if runtime.GOOS == "windows" {
		params.AddPair("externalGLControl", "1")
		params.AddPair("externalGLContext", strconv.FormatUint(uint64(uintptr(glContext)), 10))

		windowsInfo := info.GetWindowsInfo()
		windowString := strconv.FormatUint(uint64(uintptr(windowsInfo.Window)), 10)
		params.AddPair("externalWindowHandle", windowString)
	}
	if runtime.GOOS == "darwin" {
		params.AddPair("externalGLControl", "1")
		params.AddPair("externalGLContext", strconv.FormatUint(uint64(uintptr(glContext)), 10))
		params.AddPair("macAPI", "cocoa")
		cocoaInfo := info.GetCocoaInfo()
		params.AddPair("externalWindowHandle", strconv.FormatUint(uint64(*(*uint32)(cocoaInfo.Window)), 10))
	}

	renderWindow := root.CreateRenderWindow("es_core::ogre", 800, 600, false, params)
	if runtime.GOOS == "darwin" {
		// I suspect triple buffering is on by default, which makes vsync pointless?
		// except maybe for poorly implemented render loops which will then be forced to wait
		// window->SetVSyncEnabled(false)
	} else {
		// NOTE: SDL_GL_SWAP_CONTROL was SDL 1.2 and has been retired
		sdl.GL_SetSwapInterval(1);
	}

	renderWindow.SetVisible(true)

	nnGameSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
        if err != nil {
                panic(err)
        }
        _, err = nnGameSocket.Bind("tcp://127.0.0.1:60206")
        if err != nil {
                panic(err)
        }

	nnRenderSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
	if err != nil {
                panic(err)
        }
        _, err = nnRenderSocket.Bind("tcp://127.0.0.1:60207")
        if err != nil {
                panic(err)
        }

	nnInputPub, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PUB)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPub.Bind("tcp://127.0.0.1:60208")
        if err != nil {
                panic(err)
        }

	nnInputPull, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PULL)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPull.Bind("tcp://127.0.0.1:60209")
        if err != nil {
                panic(err)
        }
	go gameThread(gameThreadParams)
	var renderThreadParams RenderThreadParams
	renderThreadParams.start = gameThreadParams.start
	renderThreadParams.root = root
	renderThreadParams.window = window
	renderThreadParams.glContext = glContext
	renderThreadParams.ogreWindow = renderWindow

	sdl.GL_MakeCurrent(window, nil)
	go renderThread(renderThreadParams)

	window.SetGrab(true)
	sdl.SetRelativeMouseMode(true)

	shutdownRequested := false
	var is InputState
	is.yawSens = 0.1
	is.yaw = 0.0
	is.pitchSens = 0.1
	is.pitch = 0.0
	is.roll = 0.0
	is.orientationFactor = -1.0 // Look around config

	for !shutdownRequested /* && SDL_GetTicks() < MAX_RUN_TIME */ {
		// We wait here.
		b, err := nnInputPull.Recv(0)
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		s, _, err := capn.ReadFromMemoryZeroCopy(b)
		if err != nil {
			fmt.Printf("Read error %v\n", err)
			return
		}
		state := ReadRootState(s)
		fmt.Printf("Game push received:\n")
		// poll for events before processing the request
		// NOTE: this is how SDL builds the internal mouse and keyboard state
		// TODO: done this way does not meet the objectives of smooth, frame independent mouse view control,
		// Plus it throws some latency into the calling thread

		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent {
			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				fmt.Printf("SDL keyboard event:\n")
			case *sdl.KeyUpEvent:
				fmt.Printf("SDL keyboard event:\n")
				if t.Keysym.Scancode == sdl.SCANCODE_ESCAPE {
					sendShutdown(nnRenderSocket, nnGameSocket)
					shutdownRequested = true
				}
			case *sdl.MouseMotionEvent:
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.yaw += is.orientationFactor * is.yawSens * float32(t.XRel)
				if is.yaw >= 0.0 {
					is.yaw = float32(math.Mod(float64(is.yaw) + 180.0, 360.0) - 180.0)
				} else {
					is.yaw = float32(math.Mod(float64(is.yaw) - 180.0, 360.0) + 180.0)
				}
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.pitch += is.orientationFactor * is.pitchSens * float32(t.YRel)
				if is.pitch > 90.0 {
					is.pitch = 90.0
				} else if ( is.pitch < -90.0 ) {
					is.pitch = -90.0
				}
				// build a quaternion of the current orientation
				var r ogre.Matrix3
				r.FromEulerAnglesYXZ( deg2Rad(is.yaw), deg2Rad(is.pitch), deg2Rad(is.roll))
				is.orientation.FromRotationMatrix(r)
			case *sdl.MouseButtonEvent:
				fmt.Printf("SDL mouse button event:\n")
			case *sdl.QuitEvent:
			    // push a shutdown on the control socket, game and render will pick it up later
				// NOTE: if the message patterns change we may still have to deal with hangs here
				sendShutdown(nnRenderSocket, nnGameSocket)
				shutdownRequested = true
			default:
				fmt.Printf("SDL_Event: %T\n", t);

			}
		}
		switch {
		// we are ready to process the request now
		case state.Mouse():
			buttons := sdl.GetMouseState(nil, nil)
			fmt.Printf("buttons: %d\n", buttons)
			s := capn.NewBuffer(nil)
			ms := NewRootInputMouse(s)
			ms.SetW(is.orientation.W())
			ms.SetX(is.orientation.X())
			ms.SetY(is.orientation.Y())
			ms.SetZ(is.orientation.Z())
			ms.SetButtons(buttons)
			buf := bytes.Buffer{}
			s.WriteTo(&buf)
			nnInputPub.Send(append([]byte("input.mouse:"), buf.Bytes()...), 0)
			fmt.Printf("Mouse input sent.\n")

		case state.Kb():
		// looking at a few hardcoded keys for now
		// NOTE: I suspect it would be perfectly safe to grab that pointer once, and read it from a different thread?
			state := sdl.GetKeyboardState()
			t := capn.NewBuffer(nil)
			kbs := NewRootInputKb(t)
			kbs.SetW(state[sdl.SCANCODE_W] != 0)
			kbs.SetA(state[sdl.SCANCODE_A] != 0)
			kbs.SetS(state[sdl.SCANCODE_S] != 0)
			kbs.SetD(state[sdl.SCANCODE_D] != 0)
			kbs.SetSpace(state[sdl.SCANCODE_SPACE] != 0)
			kbs.SetLalt(state[sdl.SCANCODE_LALT] != 0)
			b := bytes.Buffer{}
			t.WriteTo(&b)
			nnInputPub.Send(append([]byte("input.kb:"), b.Bytes()...), 0)
			fmt.Printf("Keyboard input sent.\n")

		case state.MouseReset():
			var q ogre.Quaternion;
			is.orientation = q.FromValues(state.Quaternion().W(), state.Quaternion().X(),
				state.Quaternion().Y(), state.Quaternion().Z())
			var r ogre.Matrix3
			is.orientation.ToRotationMatrix(&r)
			var rfYAngle, rfPAngle, rfRAngle float32
			r.ToEulerAnglesYXZ(&rfYAngle, &rfPAngle, &rfRAngle)
			is.yaw = rad2Deg(rfYAngle)
			is.pitch = rad2Deg(rfPAngle)
			is.roll = rad2Deg(rfRAngle)
		case state.ConfigLookAround():
			if state.LookAround().ManipulateObject() {
				fmt.Printf("Input configuration: manipulate object\n");
				is.orientationFactor = 1.0;
			} else {
				fmt.Printf("Input configuration: look around\n");
				is.orientationFactor = -1.0
			}
		}
	}
	if !shutdownRequested {
      sendShutdown(nnRenderSocket, nnGameSocket)
      shutdownRequested = true
    }
    // make the GL context again before proceeding with the teardown
    if runtime.GOOS != "darwin" {
		sdl.GL_MakeCurrent(window, glContext)
	}
    waitShutdown(nnInputPull, &gameThreadParams)
}

func deg2Rad(deg float32) float32 {
	return deg * math.Pi / 180
}

func rad2Deg (rad float32) float32 {
	return rad * 180 / math.Pi
}

func sendShutdown(nnRenderSocket *nanomsg.Socket, nnGameSocket *nanomsg.Socket) {
	s := capn.NewBuffer(nil)
	stop := NewRootStop(s)
	stop.SetStop(true)
	buf := bytes.Buffer{}
	s.WriteTo(&buf)
	fmt.Printf("Render socket shutdown.\n")
	nnRenderSocket.Send(buf.Bytes(), 0)
	fmt.Printf("Game socket shutdown.\n")
	nnGameSocket.Send(buf.Bytes(), 0)
}

func waitShutdown(nnInputPull *nanomsg.Socket, params *GameThreadParams) {
	// For now, loop the input thread for a bit to flush out any events
	continueTime := time.Since(params.start) + 500 * time.Millisecond  // An eternity.
	for time.Since(params.start) < continueTime {
		msg, _ := nnInputPull.Recv(nanomsg.DontWait)
		if msg == nil {
			sdl.Delay(10)
		}
	}
}

func getSubsystemString(info sdl.SysWMInfo) string {
	switch info.Subsystem {
	case 0:
	    return "Unknown"
	case 1:
		return "Windows"
	case 2:
		return "X11"
	case 3:
		return "DirectFB"
	case 4:
		return "Cocoa"
	case 5:
		return "UiKit"
	}
	return "Unknown"
}
<commit_msg>Fix bug with the loop.<commit_after>
package core

import ("fmt"
	"os"
	"strconv"
	"runtime"
	"math"
	"bytes"
	"time"
	"reflect"
	"github.com/jackyb/go-sdl2/sdl"
	"github.com/op/go-nanomsg"
	"github.com/fire/go-ogre3d"
	"github.com/jmckaskill/go-capnproto")

type InputState struct {
	yawSens float32
	pitchSens float32
	orientationFactor float32 // +1/-1 easy switch between look around and manipulate something
	yaw float32 // degrees, modulo [-180,180] range
	pitch float32 // degrees, clamped [-90,90] range
	roll float32
	orientation ogre.Quaternion // current orientation
}

func InitCore() {
	var gameThreadParams GameThreadParams
	gameThreadParams.start = time.Now() // There's an small time before this variable is initalized,
	// it probably doesn't matter... Someone timed Go initalization at 1.94us on Linux.
	sdl.Init(sdl.INIT_EVERYTHING)
	window := sdl.CreateWindow("es_core::SDL",
		sdl.WINDOWPOS_UNDEFINED,
		sdl.WINDOWPOS_UNDEFINED,
		800,
		600,
		sdl.WINDOW_OPENGL|sdl.WINDOW_SHOWN)
	if window == nil {
		panic(fmt.Sprintf("sdl.CreateWindow failed: %s\n", sdl.GetError()))
	}
	defer sdl.Quit()
	glContext := sdl.GL_CreateContext(window)

	var info sdl.SysWMInfo
	if !window.GetWMInfo(&info) {
		panic(fmt.Sprintf("window.GetWMInfo failed.\n"))
	}
	var version sdl.Version
	sdl.GetVersion(&version)

	fmt.Printf("Sdl Major Version: %d\n", version.Major)
	fmt.Printf("Sdl Minor Version: %d\n", version.Minor)
	fmt.Printf("Sdl Patch level: %d\n", version.Patch)
	fmt.Printf("Sdl Subsystem: %s\n", getSubsystemString(info))
	root := ogre.NewRoot("", "", "ogre.log")
	defer root.Destroy()
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if runtime.GOOS == "windows" {
		root.LoadPlugin(wd  + "/RenderSystem_GL3Plus")
		}
	if runtime.GOOS == "darwin" {
		root.LoadPlugin(wd  + "/../frameworks/RenderSystem_GL3Plus")
	}

	renderers := root.GetAvailableRenderers()
	if renderers.RenderSystemListSize() != 1 {

		panic(fmt.Sprintf("Failed to initalize RendererRenderSystem_GL"))
	}
	root.SetRenderSystem(renderers.RenderSystemListGet(0))
	root.Initialise(false, "es_core::ogre")
	params := ogre.CreateNameValuePairList()
	if runtime.GOOS == "windows" {
		params.AddPair("externalGLControl", "1")
		params.AddPair("externalGLContext", strconv.FormatUint(uint64(uintptr(glContext)), 10))

		windowsInfo := info.GetWindowsInfo()
		windowString := strconv.FormatUint(uint64(uintptr(windowsInfo.Window)), 10)
		params.AddPair("externalWindowHandle", windowString)
	}
	if runtime.GOOS == "darwin" {
		params.AddPair("externalGLControl", "1")
		params.AddPair("externalGLContext", strconv.FormatUint(uint64(uintptr(glContext)), 10))
		params.AddPair("macAPI", "cocoa")
		cocoaInfo := info.GetCocoaInfo()
		params.AddPair("externalWindowHandle", strconv.FormatUint(uint64(*(*uint32)(cocoaInfo.Window)), 10))
	}

	renderWindow := root.CreateRenderWindow("es_core::ogre", 800, 600, false, params)
	if runtime.GOOS == "darwin" {
		// I suspect triple buffering is on by default, which makes vsync pointless?
		// except maybe for poorly implemented render loops which will then be forced to wait
		// window->SetVSyncEnabled(false)
	} else {
		// NOTE: SDL_GL_SWAP_CONTROL was SDL 1.2 and has been retired
		sdl.GL_SetSwapInterval(1);
	}

	renderWindow.SetVisible(true)

	nnGameSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
        if err != nil {
                panic(err)
        }
        _, err = nnGameSocket.Bind("tcp://127.0.0.1:60206")
        if err != nil {
                panic(err)
        }

	nnRenderSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
	if err != nil {
                panic(err)
        }
        _, err = nnRenderSocket.Bind("tcp://127.0.0.1:60207")
        if err != nil {
                panic(err)
        }

	nnInputPub, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PUB)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPub.Bind("tcp://127.0.0.1:60208")
        if err != nil {
                panic(err)
        }

	nnInputPull, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PULL)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPull.Bind("tcp://127.0.0.1:60209")
        if err != nil {
                panic(err)
        }
	go gameThread(gameThreadParams)
	var renderThreadParams RenderThreadParams
	renderThreadParams.start = gameThreadParams.start
	renderThreadParams.root = root
	renderThreadParams.window = window
	renderThreadParams.glContext = glContext
	renderThreadParams.ogreWindow = renderWindow

	sdl.GL_MakeCurrent(window, nil)
	go renderThread(renderThreadParams)

	window.SetGrab(true)
	sdl.SetRelativeMouseMode(true)

	shutdownRequested := false
	var is InputState
	is.yawSens = 0.1
	is.yaw = 0.0
	is.pitchSens = 0.1
	is.pitch = 0.0
	is.roll = 0.0
	is.orientationFactor = -1.0 // Look around config

	for !shutdownRequested /* && SDL_GetTicks() < MAX_RUN_TIME */ {
		// We wait here.
		b, err := nnInputPull.Recv(0)
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		s, _, err := capn.ReadFromMemoryZeroCopy(b)
		if err != nil {
			fmt.Printf("Read error %v\n", err)
			return
		}
		state := ReadRootState(s)
		fmt.Printf("Game push received:\n")
		// poll for events before processing the request
		// NOTE: this is how SDL builds the internal mouse and keyboard state
		// TODO: done this way does not meet the objectives of smooth, frame independent mouse view control,
		// Plus it throws some latency into the calling thread

		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch t := event.(type) {
			default:
				fmt.Printf("SDL_Event: %s\n", reflect.TypeOf(t).String()[5:]);
			case *sdl.KeyDownEvent:
				fmt.Printf("SDL keyboard event:\n")
			case *sdl.KeyUpEvent:
				fmt.Printf("SDL keyboard event:\n")
				if t.Keysym.Scancode == sdl.SCANCODE_ESCAPE {
					sendShutdown(nnRenderSocket, nnGameSocket)
					shutdownRequested = true
				}
			case *sdl.MouseMotionEvent:
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.yaw += is.orientationFactor * is.yawSens * float32(t.XRel)
				if is.yaw >= 0.0 {
					is.yaw = float32(math.Mod(float64(is.yaw) + 180.0, 360.0) - 180.0)
				} else {
					is.yaw = float32(math.Mod(float64(is.yaw) - 180.0, 360.0) + 180.0)
				}
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.pitch += is.orientationFactor * is.pitchSens * float32(t.YRel)
				if is.pitch > 90.0 {
					is.pitch = 90.0
				} else if ( is.pitch < -90.0 ) {
					is.pitch = -90.0
				}
				// build a quaternion of the current orientation
				var r ogre.Matrix3
				r.FromEulerAnglesYXZ( deg2Rad(is.yaw), deg2Rad(is.pitch), deg2Rad(is.roll))
				is.orientation.FromRotationMatrix(r)
			case *sdl.MouseButtonEvent:
				fmt.Printf("SDL mouse button event:\n")
			case *sdl.QuitEvent:
			    // push a shutdown on the control socket, game and render will pick it up later
				// NOTE: if the message patterns change we may still have to deal with hangs here
				sendShutdown(nnRenderSocket, nnGameSocket)
				shutdownRequested = true
			}
		}
		switch {
		// we are ready to process the request now
		case state.Mouse():
			buttons := sdl.GetMouseState(nil, nil)
			fmt.Printf("buttons: %d\n", buttons)
			s := capn.NewBuffer(nil)
			ms := NewRootInputMouse(s)
			ms.SetW(is.orientation.W())
			ms.SetX(is.orientation.X())
			ms.SetY(is.orientation.Y())
			ms.SetZ(is.orientation.Z())
			ms.SetButtons(buttons)
			buf := bytes.Buffer{}
			s.WriteTo(&buf)
			nnInputPub.Send(append([]byte("input.mouse:"), buf.Bytes()...), 0)
			fmt.Printf("Mouse input sent.\n")

		case state.Kb():
		// looking at a few hardcoded keys for now
		// NOTE: I suspect it would be perfectly safe to grab that pointer once, and read it from a different thread?
			state := sdl.GetKeyboardState()
			t := capn.NewBuffer(nil)
			kbs := NewRootInputKb(t)
			kbs.SetW(state[sdl.SCANCODE_W] != 0)
			kbs.SetA(state[sdl.SCANCODE_A] != 0)
			kbs.SetS(state[sdl.SCANCODE_S] != 0)
			kbs.SetD(state[sdl.SCANCODE_D] != 0)
			kbs.SetSpace(state[sdl.SCANCODE_SPACE] != 0)
			kbs.SetLalt(state[sdl.SCANCODE_LALT] != 0)
			b := bytes.Buffer{}
			t.WriteTo(&b)
			nnInputPub.Send(append([]byte("input.kb:"), b.Bytes()...), 0)
			fmt.Printf("Keyboard input sent.\n")

		case state.MouseReset():
			var q ogre.Quaternion;
			is.orientation = q.FromValues(state.Quaternion().W(), state.Quaternion().X(),
				state.Quaternion().Y(), state.Quaternion().Z())
			var r ogre.Matrix3
			is.orientation.ToRotationMatrix(&r)
			var rfYAngle, rfPAngle, rfRAngle float32
			r.ToEulerAnglesYXZ(&rfYAngle, &rfPAngle, &rfRAngle)
			is.yaw = rad2Deg(rfYAngle)
			is.pitch = rad2Deg(rfPAngle)
			is.roll = rad2Deg(rfRAngle)
		case state.ConfigLookAround():
			if state.LookAround().ManipulateObject() {
				fmt.Printf("Input configuration: manipulate object\n");
				is.orientationFactor = 1.0;
			} else {
				fmt.Printf("Input configuration: look around\n");
				is.orientationFactor = -1.0
			}
		}
	}
	if !shutdownRequested {
      sendShutdown(nnRenderSocket, nnGameSocket)
      shutdownRequested = true
    }
    // make the GL context again before proceeding with the teardown
    if runtime.GOOS != "darwin" {
		sdl.GL_MakeCurrent(window, glContext)
	}
    waitShutdown(nnInputPull, &gameThreadParams)
}

func deg2Rad(deg float32) float32 {
	return deg * math.Pi / 180
}

func rad2Deg (rad float32) float32 {
	return rad * 180 / math.Pi
}

func sendShutdown(nnRenderSocket *nanomsg.Socket, nnGameSocket *nanomsg.Socket) {
	s := capn.NewBuffer(nil)
	stop := NewRootStop(s)
	stop.SetStop(true)
	buf := bytes.Buffer{}
	s.WriteTo(&buf)
	fmt.Printf("Render socket shutdown.\n")
	nnRenderSocket.Send(buf.Bytes(), 0)
	fmt.Printf("Game socket shutdown.\n")
	nnGameSocket.Send(buf.Bytes(), 0)
}

func waitShutdown(nnInputPull *nanomsg.Socket, params *GameThreadParams) {
	// For now, loop the input thread for a bit to flush out any events
	continueTime := time.Since(params.start) + 500 * time.Millisecond  // An eternity.
	for time.Since(params.start) < continueTime {
		msg, _ := nnInputPull.Recv(nanomsg.DontWait)
		if msg == nil {
			sdl.Delay(10)
		}
	}
}

func getSubsystemString(info sdl.SysWMInfo) string {
	switch info.Subsystem {
	case 0:
	    return "Unknown"
	case 1:
		return "Windows"
	case 2:
		return "X11"
	case 3:
		return "DirectFB"
	case 4:
		return "Cocoa"
	case 5:
		return "UiKit"
	}
	return "Unknown"
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"path"
	"sort"
	"strconv"
	"strings"

	"io/ioutil"
)

var (
	PY_WRITER  io.Writer
	PY_TYPES   map[string]bool
	PY_OBJECTS map[string]*Object
)

const PY_HEADER = `#-*- coding: utf-8 -*-
# Generated by ibelie-rpc.  DO NOT EDIT!
`

func Python(dir string, name string, types []Type) {
	var buffer bytes.Buffer
	buffer.Write([]byte(PY_HEADER))
	buffer.Write([]byte(`
import typy
`))

	PY_WRITER = &buffer
	PY_TYPES = make(map[string]bool)
	var codes []string
	for _, t := range types {
		codes = append(codes, t.Python())
	}
	PY_TYPES = nil
	PY_WRITER = nil

	buffer.Write([]byte(strings.Join(codes, "")))
	ioutil.WriteFile(path.Join(dir, name+".py"), buffer.Bytes(), 0666)
}

func (t *Enum) Python() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	}

	PY_TYPES[t.Name] = true
	var enums []string
	for _, name := range t.Sorted() {
		enums = append(enums, fmt.Sprintf(`
	%s = %d, "%s"`, name, t.Values[name], name))
	}

	return fmt.Sprintf(`
class %s(typy.Enum):%s
`, t.Name, strings.Join(enums, ""))
}

func (t *Object) Python() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	}

	PY_TYPES[t.Name] = true
	var fields []string
	var sequences []string
	for _, f := range t.VisibleFields() {
		sequences = append(sequences, fmt.Sprintf("'%s'", f.Name))
		fields = append(fields, fmt.Sprintf(`
	%s = %s`, f.Name, strings.Replace(f.Python(), "typy.", "typy.pb.", 1)))
	}

	var sequence string
	if sequences == nil {
		return ""
	} else if len(sequences) > 1 {
		sequence = fmt.Sprintf(`
	____propertySequence__ = %s`, strings.Join(sequences, ", "))
	}

	parent := "typy.Object"
	if t.HasParent() {
		parent = t.Parent.Name
	}

	return fmt.Sprintf(`
class %s(%s):%s%s
`, t.Name, parent, sequence, strings.Join(fields, ""))
}

func (t UnknownType) Python() string {
	return ""
}

func (t SimpleType) Python() string {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		return "typy.Integer"
	case SimpleType_FLOAT32:
		fallthrough
	case SimpleType_FLOAT64:
		return "typy.Float"
	case SimpleType_BYTES:
		return "typy.Bytes"
	case SimpleType_STRING:
		return "typy.String"
	case SimpleType_BOOL:
		return "typy.Boolean"
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Python: %d", t)
		return "Unknown"
	}
}

func (t *EnumType) Python() string {
	PY_WRITER.Write([]byte(t.Enum.Python()))
	return fmt.Sprintf("typy.Enum(%s)", t.Name)
}

func (t *InstanceType) Python() string {
	if object, ok := TS_OBJECTS[t.Name]; ok {
		PY_WRITER.Write([]byte(object.Python()))
		return fmt.Sprintf("typy.Instance(%s)", t.Name)
	} else {
		return fmt.Sprintf("typy.Python(%s)", t.Name)
	}
}

func (t *FixedPointType) Python() string {
	return fmt.Sprintf("typy.FixedPoint(%d, %d)", t.Precision, t.Floor)
}

func (t *ListType) Python() string {
	return fmt.Sprintf("typy.List(%s)", t.E.Python())
}

func (t *DictType) Python() string {
	return fmt.Sprintf("typy.Dict(%s, %s)", t.K.Python(), t.V.Python())
}

func (t *VariantType) Python() string {
	var variants []string
	for _, v := range t.Ts {
		if inst, ok := v.(*InstanceType); ok {
			if object, ok := TS_OBJECTS[inst.Name]; ok {
				PY_WRITER.Write([]byte(object.Python()))
				variants = append(variants, inst.Name)
				continue
			}
		}
		variants = append(variants, v.Python())
	}
	return fmt.Sprintf("typy.Instance(%s)", strings.Join(variants, ", "))
}

const (
	TYPYD_ENUM       = 0
	TYPYD_INT32      = 1
	TYPYD_INT64      = 2
	TYPYD_UINT32     = 3
	TYPYD_UINT64     = 4
	TYPYD_FIXEDPOINT = 5
	TYPYD_DOUBLE     = 6
	TYPYD_FLOAT      = 7
	TYPYD_BOOL       = 8
	TYPYD_BYTES      = 9
	TYPYD_STRING     = 10
	TYPYD_OBJECT     = 11
	TYPYD_VARIANT    = 12
	TYPYD_LIST       = 13
	TYPYD_DICT       = 14
	TYPYD_PYTHON     = 15
	MAX_TYPYD_TYPE   = 16
)

func Typyd(dir string, name string, types []Type) {
	var buffer bytes.Buffer
	buffer.Write([]byte(PY_HEADER))
	buffer.Write([]byte(`
import _typyd
`))

	PY_WRITER = &buffer
	PY_OBJECTS = ObjectMap(types)
	PY_TYPES = make(map[string]bool)
	var codes []string
	for _, t := range types {
		codes = append(codes, t.Typyd())
	}
	PY_TYPES = nil
	PY_WRITER = nil
	PY_OBJECTS = nil

	buffer.Write([]byte(strings.Join(codes, "")))
	ioutil.WriteFile(path.Join(dir, name+".py"), buffer.Bytes(), 0666)
}

func (t *Enum) Typyd() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	} else {
		PY_TYPES[t.Name] = true
		return fmt.Sprintf(`
%s = _typyd.Enum('%s')`, t.Name, t.Name)
	}
}

func (t *Object) Typyd() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	}

	PY_TYPES[t.Name] = true
	var fields []string
	for i, f := range t.AllFields(PY_OBJECTS, true) {
		wiretype := f.WireType()
		fields = append(fields, fmt.Sprintf(`
	('%s', %d, %d, %d, %s),`, f.Name, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), wiretype, f.Typyd()))
	}

	if len(fields) <= 0 {
		return ""
	}

	return fmt.Sprintf(`
%s = _typyd.Object('%s', (%s
))`, t.Name, t.Name, strings.Join(fields, ""))
}

func (t UnknownType) Typyd() string {
	return ""
}

func (t SimpleType) Typyd() string {
	switch t {
	case SimpleType_INT32:
		return strconv.Itoa(TYPYD_INT32)
	case SimpleType_INT64:
		return strconv.Itoa(TYPYD_INT64)
	case SimpleType_UINT32:
		return strconv.Itoa(TYPYD_UINT32)
	case SimpleType_UINT64:
		return strconv.Itoa(TYPYD_UINT64)
	case SimpleType_FLOAT32:
		return strconv.Itoa(TYPYD_FLOAT)
	case SimpleType_FLOAT64:
		return strconv.Itoa(TYPYD_DOUBLE)
	case SimpleType_BYTES:
		return strconv.Itoa(TYPYD_BYTES)
	case SimpleType_STRING:
		return strconv.Itoa(TYPYD_STRING)
	case SimpleType_BOOL:
		return strconv.Itoa(TYPYD_BOOL)
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Typyd: %d", t)
		return "unknown"
	}
}

func (t *EnumType) Typyd() string {
	PY_WRITER.Write([]byte(t.Enum.Typyd()))
	return fmt.Sprintf("%d, %s", TYPYD_ENUM, t.Name)
}

func (t *InstanceType) Typyd() string {
	if _, ok := TS_OBJECTS[t.Name]; ok {
		return t.Name
	} else {
		return "Type"
	}
}

func (t *FixedPointType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.FixedPoint(%d, %d)`, identifier, t.Floor, t.Precision)))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_FIXEDPOINT, identifier)
}

func (t *ListType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.List('%s', (%d, %s))`, identifier, identifier, t.E.WireType(), t.E.Typyd())))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_LIST, identifier)
}

func (t *DictType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.Dict('%s', (%d, %s), (%d, %s))`, identifier, identifier,
			t.K.WireType(), t.K.Typyd(), t.V.WireType(), t.V.Typyd())))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_DICT, identifier)
}

func (t *VariantType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		properties := make(map[string]Type)
		for _, typ := range t.Ts {
			switch v := typ.(type) {
			case SimpleType:
				switch v {
				case SimpleType_INT32:
					fallthrough
				case SimpleType_INT64:
					fallthrough
				case SimpleType_UINT32:
					fallthrough
				case SimpleType_UINT64:
					properties["Integer"] = v
				case SimpleType_FLOAT32:
					properties["Float"] = v
				case SimpleType_FLOAT64:
					properties["Double"] = v
				case SimpleType_BYTES:
					properties["Bytes"] = v
				case SimpleType_STRING:
					properties["String"] = v
				case SimpleType_BOOL:
					properties["Boolean"] = v
				default:
					log.Fatalf("[Tygo][VariantType] Unexpect enum value for SimpleType: %d", v)
				}
			case *EnumType:
				properties["Enum"] = v
			case *InstanceType:
				properties[v.Name] = v
			case *FixedPointType:
				properties["Dict"] = v
			case *ListType:
				properties["Dict"] = v
			case *DictType:
				properties["Dict"] = v
			default:
				log.Fatalf("[Tygo][VariantType] Unexpect type for Typyd: %v", v)
			}
		}

		var sortedProperties []string
		for n, _ := range properties {
			sortedProperties = append(sortedProperties, n)
		}
		sort.Strings(sortedProperties)

		var fields []string
		for i, n := range sortedProperties {
			wiretype := properties[n].WireType()
			fields = append(fields, fmt.Sprintf(`
	('%s', %d, %d, %d, %s),`, n, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), wiretype, properties[n].Typyd()))
		}

		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.Variant('%s', (%s
))`, identifier, identifier, strings.Join(fields, ""))))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_VARIANT, identifier)
}
<commit_msg>fix bug<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"path"
	"sort"
	"strconv"
	"strings"

	"io/ioutil"
)

var (
	PY_WRITER  io.Writer
	PY_TYPES   map[string]bool
	PY_OBJECTS map[string]*Object
)

const PY_HEADER = `#-*- coding: utf-8 -*-
# Generated by ibelie-rpc.  DO NOT EDIT!
`

func Python(dir string, name string, types []Type) {
	var buffer bytes.Buffer
	buffer.Write([]byte(PY_HEADER))
	buffer.Write([]byte(`
import typy
`))

	PY_WRITER = &buffer
	PY_TYPES = make(map[string]bool)
	var codes []string
	for _, t := range types {
		codes = append(codes, t.Python())
	}
	PY_TYPES = nil
	PY_WRITER = nil

	buffer.Write([]byte(strings.Join(codes, "")))
	ioutil.WriteFile(path.Join(dir, name+".py"), buffer.Bytes(), 0666)
}

func (t *Enum) Python() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	}

	PY_TYPES[t.Name] = true
	var enums []string
	for _, name := range t.Sorted() {
		enums = append(enums, fmt.Sprintf(`
	%s = %d, "%s"`, name, t.Values[name], name))
	}

	return fmt.Sprintf(`
class %s(typy.Enum):%s
`, t.Name, strings.Join(enums, ""))
}

func (t *Object) Python() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	}

	PY_TYPES[t.Name] = true
	var fields []string
	var sequences []string
	for _, f := range t.VisibleFields() {
		sequences = append(sequences, fmt.Sprintf("'%s'", f.Name))
		fields = append(fields, fmt.Sprintf(`
	%s = %s`, f.Name, strings.Replace(f.Python(), "typy.", "typy.pb.", 1)))
	}

	var sequence string
	if sequences == nil {
		return ""
	} else if len(sequences) > 1 {
		sequence = fmt.Sprintf(`
	____propertySequence__ = %s`, strings.Join(sequences, ", "))
	}

	parent := "typy.Object"
	if t.HasParent() {
		parent = t.Parent.Name
	}

	return fmt.Sprintf(`
class %s(%s):%s%s
`, t.Name, parent, sequence, strings.Join(fields, ""))
}

func (t UnknownType) Python() string {
	return ""
}

func (t SimpleType) Python() string {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		return "typy.Integer"
	case SimpleType_FLOAT32:
		fallthrough
	case SimpleType_FLOAT64:
		return "typy.Float"
	case SimpleType_BYTES:
		return "typy.Bytes"
	case SimpleType_STRING:
		return "typy.String"
	case SimpleType_BOOL:
		return "typy.Boolean"
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Python: %d", t)
		return "Unknown"
	}
}

func (t *EnumType) Python() string {
	PY_WRITER.Write([]byte(t.Enum.Python()))
	return fmt.Sprintf("typy.Enum(%s)", t.Name)
}

func (t *InstanceType) Python() string {
	if object, ok := TS_OBJECTS[t.Name]; ok {
		PY_WRITER.Write([]byte(object.Python()))
		return fmt.Sprintf("typy.Instance(%s)", t.Name)
	} else {
		return fmt.Sprintf("typy.Python(%s)", t.Name)
	}
}

func (t *FixedPointType) Python() string {
	return fmt.Sprintf("typy.FixedPoint(%d, %d)", t.Precision, t.Floor)
}

func (t *ListType) Python() string {
	return fmt.Sprintf("typy.List(%s)", t.E.Python())
}

func (t *DictType) Python() string {
	return fmt.Sprintf("typy.Dict(%s, %s)", t.K.Python(), t.V.Python())
}

func (t *VariantType) Python() string {
	var variants []string
	for _, v := range t.Ts {
		if inst, ok := v.(*InstanceType); ok {
			if object, ok := TS_OBJECTS[inst.Name]; ok {
				PY_WRITER.Write([]byte(object.Python()))
				variants = append(variants, inst.Name)
				continue
			}
		}
		variants = append(variants, v.Python())
	}
	return fmt.Sprintf("typy.Instance(%s)", strings.Join(variants, ", "))
}

const (
	TYPYD_ENUM       = 0
	TYPYD_INT32      = 1
	TYPYD_INT64      = 2
	TYPYD_UINT32     = 3
	TYPYD_UINT64     = 4
	TYPYD_FIXEDPOINT = 5
	TYPYD_DOUBLE     = 6
	TYPYD_FLOAT      = 7
	TYPYD_BOOL       = 8
	TYPYD_BYTES      = 9
	TYPYD_STRING     = 10
	TYPYD_OBJECT     = 11
	TYPYD_VARIANT    = 12
	TYPYD_LIST       = 13
	TYPYD_DICT       = 14
	TYPYD_PYTHON     = 15
	MAX_TYPYD_TYPE   = 16
)

func Typyd(dir string, name string, types []Type) {
	var buffer bytes.Buffer
	buffer.Write([]byte(PY_HEADER))
	buffer.Write([]byte(`
from typy import _typyd
`))

	PY_WRITER = &buffer
	PY_OBJECTS = ObjectMap(types)
	PY_TYPES = make(map[string]bool)
	var codes []string
	for _, t := range types {
		codes = append(codes, t.Typyd())
	}
	PY_TYPES = nil
	PY_WRITER = nil
	PY_OBJECTS = nil

	buffer.Write([]byte(strings.Join(codes, "")))
	ioutil.WriteFile(path.Join(dir, name+".py"), buffer.Bytes(), 0666)
}

func (t *Enum) Typyd() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	} else {
		PY_TYPES[t.Name] = true
		return fmt.Sprintf(`
%s = _typyd.Enum('%s')`, t.Name, t.Name)
	}
}

func (t *Object) Typyd() string {
	if ok, exist := PY_TYPES[t.Name]; exist && ok {
		return ""
	}

	PY_TYPES[t.Name] = true
	var fields []string
	for i, f := range t.AllFields(PY_OBJECTS, true) {
		wiretype := f.WireType()
		fields = append(fields, fmt.Sprintf(`
	('%s', %d, %d, %d, %s),`, f.Name, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), wiretype, f.Typyd()))
	}

	if len(fields) <= 0 {
		return ""
	}

	return fmt.Sprintf(`
%s = _typyd.Object('%s', (%s
))`, t.Name, t.Name, strings.Join(fields, ""))
}

func (t UnknownType) Typyd() string {
	return ""
}

func (t SimpleType) Typyd() string {
	switch t {
	case SimpleType_INT32:
		return strconv.Itoa(TYPYD_INT32)
	case SimpleType_INT64:
		return strconv.Itoa(TYPYD_INT64)
	case SimpleType_UINT32:
		return strconv.Itoa(TYPYD_UINT32)
	case SimpleType_UINT64:
		return strconv.Itoa(TYPYD_UINT64)
	case SimpleType_FLOAT32:
		return strconv.Itoa(TYPYD_FLOAT)
	case SimpleType_FLOAT64:
		return strconv.Itoa(TYPYD_DOUBLE)
	case SimpleType_BYTES:
		return strconv.Itoa(TYPYD_BYTES)
	case SimpleType_STRING:
		return strconv.Itoa(TYPYD_STRING)
	case SimpleType_BOOL:
		return strconv.Itoa(TYPYD_BOOL)
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Typyd: %d", t)
		return "unknown"
	}
}

func (t *EnumType) Typyd() string {
	PY_WRITER.Write([]byte(t.Enum.Typyd()))
	return fmt.Sprintf("%d, %s", TYPYD_ENUM, t.Name)
}

func (t *InstanceType) Typyd() string {
	if _, ok := TS_OBJECTS[t.Name]; ok {
		return t.Name
	} else {
		return "Type"
	}
}

func (t *FixedPointType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.FixedPoint(%d, %d)`, identifier, t.Floor, t.Precision)))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_FIXEDPOINT, identifier)
}

func (t *ListType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.List('%s', (%d, %s))`, identifier, identifier, t.E.WireType(), t.E.Typyd())))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_LIST, identifier)
}

func (t *DictType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.Dict('%s', (%d, %s), (%d, %s))`, identifier, identifier,
			t.K.WireType(), t.K.Typyd(), t.V.WireType(), t.V.Typyd())))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_DICT, identifier)
}

func (t *VariantType) Typyd() string {
	identifier := t.Identifier()
	if ok, exist := PY_TYPES[identifier]; !exist || !ok {
		properties := make(map[string]Type)
		for _, typ := range t.Ts {
			switch v := typ.(type) {
			case SimpleType:
				switch v {
				case SimpleType_INT32:
					fallthrough
				case SimpleType_INT64:
					fallthrough
				case SimpleType_UINT32:
					fallthrough
				case SimpleType_UINT64:
					properties["Integer"] = v
				case SimpleType_FLOAT32:
					properties["Float"] = v
				case SimpleType_FLOAT64:
					properties["Double"] = v
				case SimpleType_BYTES:
					properties["Bytes"] = v
				case SimpleType_STRING:
					properties["String"] = v
				case SimpleType_BOOL:
					properties["Boolean"] = v
				default:
					log.Fatalf("[Tygo][VariantType] Unexpect enum value for SimpleType: %d", v)
				}
			case *EnumType:
				properties["Enum"] = v
			case *InstanceType:
				properties[v.Name] = v
			case *FixedPointType:
				properties["Dict"] = v
			case *ListType:
				properties["Dict"] = v
			case *DictType:
				properties["Dict"] = v
			default:
				log.Fatalf("[Tygo][VariantType] Unexpect type for Typyd: %v", v)
			}
		}

		var sortedProperties []string
		for n, _ := range properties {
			sortedProperties = append(sortedProperties, n)
		}
		sort.Strings(sortedProperties)

		var fields []string
		for i, n := range sortedProperties {
			wiretype := properties[n].WireType()
			fields = append(fields, fmt.Sprintf(`
	('%s', %d, %d, %d, %s),`, n, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), wiretype, properties[n].Typyd()))
		}

		PY_WRITER.Write([]byte(fmt.Sprintf(`
%s = _typyd.Variant('%s', (%s
))`, identifier, identifier, strings.Join(fields, ""))))
		PY_TYPES[identifier] = true
	}
	return fmt.Sprintf("%d, %s", TYPYD_VARIANT, identifier)
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"bytes"
	"fmt"
	"path"
	"strings"

	"io/ioutil"

	"github.com/ibelie/rpc/typescript"
	"github.com/ibelie/tygo"
)

func Typescript(identName string, tsOut string, inputs []string) (entities []*Entity) {
	pkg := typescript.Extract(inputs)

	components := make(map[string]*Component)
	for _, o := range pkg.Objects {
		if len(o.Parents) != 1 || o.Parents[0] == nil || o.Parents[0].Simple != "ibelie.rpc.Component" {
			continue
		}
		components[o.Name] = &Component{Name: o.Name}
	}

	behaviors := make(map[string]*Behavior)
	for _, o := range pkg.Objects {
		if len(o.Parents) != 1 || o.Parents[0] == nil || o.Parents[0].Simple != "ibelie.rpc.Behavior" {
			continue
		}

		behavior := &Behavior{Name: o.Name}
		for _, f := range o.Fields {
			if f.Type == nil || !strings.HasSuffix(f.Type.Simple, "."+f.Name) {
				continue
			}

			component, ok := components[f.Name]
			if !ok {
				component = &Component{Name: f.Name}
				components[f.Name] = component
			}
			component.Path = strings.Replace(f.Type.Simple[:len(f.Type.Simple)-len(f.Name)-1], ".", "/", -1)
			behavior.Components = append(behavior.Components, component)
		}

		for _, m := range o.Methods {
			behavior.Methods = append(behavior.Methods, m.Name)
		}

		behaviors[behavior.Name] = behavior
	}

	for _, o := range pkg.Objects {
		if len(o.Parents) != 1 || o.Parents[0] == nil || o.Parents[0].Simple != "ibelie.rpc.Entity" {
			continue
		}

		entity := &Entity{Name: o.Name}
		for _, f := range o.Fields {
			if f.Type == nil || !strings.HasSuffix(f.Type.Simple, "."+f.Name) {
				continue
			}

			component, ok := components[f.Name]
			if !ok {
				component = &Component{Name: f.Name}
				components[f.Name] = component
			}
			component.Path = strings.Replace(f.Type.Simple[:len(f.Type.Simple)-len(f.Name)-1], ".", "/", -1)
			entity.Components = append(entity.Components, component)
		}

		for _, b := range behaviors {
			hasBehavior := true
			for _, bc := range b.Components {
				for _, ec := range entity.Components {
					if bc != ec {
						hasBehavior = false
						break
					}
				}
				if !hasBehavior {
					break
				}
			}
			if hasBehavior {
				entity.Behavior = append(entity.Behavior, b)
			}
		}

		entities = append(entities, entity)
	}

	types := resolveEntities(entities)
	tygo.JS_EXTENS = map[string]string{"Entity": "ibelie.rpc"}
	tygo.Typescript(tsOut, "types", "", types, PROP_PRE)
	tygo.JS_EXTENS = nil
	injectJavascript(identName, tsOut, entities)
	injectTypescript(tsOut, entities, types)
	return entities
}

func injectTypescript(dir string, entities []*Entity, types []tygo.Type) {
	var buffer bytes.Buffer
	var methods []string
	methodsMap := make(map[string]bool)
	tygo.TS_OBJECTS = tygo.ObjectMap(types, true)
	for _, e := range entities {
		for _, c := range e.Components {
			if c.Protocol == nil {
				continue
			}
			for _, m := range c.Protocol.Methods {
				if ok, exist := methodsMap[m.Name]; exist && ok {
					continue
				} else if len(m.Results) > 0 {
					continue
				}
				var params []string
				for i, p := range m.Params {
					params = append(params, fmt.Sprintf("a%d: %s", i, p.Typescript()))
				}
				methods = append(methods, fmt.Sprintf(`
		%s(%s): void;`, m.Name, strings.Join(params, ", ")))
				methodsMap[m.Name] = true
			}
		}
	}
	tygo.TS_OBJECTS = nil

	buffer.Write([]byte(fmt.Sprintf(`// Generated by ibelie-rpc.  DO NOT EDIT!

declare module ibelie.rpc {
	interface Type {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
	}

	interface Entity {
		__class__: string;
		isAwake: boolean;
		Awake(entity: Type): any;
		Drop(entity: Type): any;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;%s
	}

	interface Behavior extends Entity {}

	class Connection {
		socket: WebSocket;
		entities: {[index: string]: Entity};
		constructor(url: string);
		disconnect(): void;
	}
}
`, strings.Join(methods, ""))))

	ioutil.WriteFile(path.Join(dir, "rpc.d.ts"), buffer.Bytes(), 0666)
}
<commit_msg>set extension package setting<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"bytes"
	"fmt"
	"path"
	"strings"

	"io/ioutil"

	"github.com/ibelie/rpc/typescript"
	"github.com/ibelie/tygo"
)

func Typescript(identName string, tsOut string, inputs []string) (entities []*Entity) {
	pkg := typescript.Extract(inputs)

	components := make(map[string]*Component)
	for _, o := range pkg.Objects {
		if len(o.Parents) != 1 || o.Parents[0] == nil || o.Parents[0].Simple != "ibelie.rpc.Component" {
			continue
		}
		components[o.Name] = &Component{Name: o.Name}
	}

	behaviors := make(map[string]*Behavior)
	for _, o := range pkg.Objects {
		if len(o.Parents) != 1 || o.Parents[0] == nil || o.Parents[0].Simple != "ibelie.rpc.Behavior" {
			continue
		}

		behavior := &Behavior{Name: o.Name}
		for _, f := range o.Fields {
			if f.Type == nil || !strings.HasSuffix(f.Type.Simple, "."+f.Name) {
				continue
			}

			component, ok := components[f.Name]
			if !ok {
				component = &Component{Name: f.Name}
				components[f.Name] = component
			}
			component.Path = strings.Replace(f.Type.Simple[:len(f.Type.Simple)-len(f.Name)-1], ".", "/", -1)
			behavior.Components = append(behavior.Components, component)
		}

		for _, m := range o.Methods {
			behavior.Methods = append(behavior.Methods, m.Name)
		}

		behaviors[behavior.Name] = behavior
	}

	for _, o := range pkg.Objects {
		if len(o.Parents) != 1 || o.Parents[0] == nil || o.Parents[0].Simple != "ibelie.rpc.Entity" {
			continue
		}

		entity := &Entity{Name: o.Name}
		for _, f := range o.Fields {
			if f.Type == nil || !strings.HasSuffix(f.Type.Simple, "."+f.Name) {
				continue
			}

			component, ok := components[f.Name]
			if !ok {
				component = &Component{Name: f.Name}
				components[f.Name] = component
			}
			component.Path = strings.Replace(f.Type.Simple[:len(f.Type.Simple)-len(f.Name)-1], ".", "/", -1)
			entity.Components = append(entity.Components, component)
		}

		for _, b := range behaviors {
			hasBehavior := true
			for _, bc := range b.Components {
				for _, ec := range entity.Components {
					if bc != ec {
						hasBehavior = false
						break
					}
				}
				if !hasBehavior {
					break
				}
			}
			if hasBehavior {
				entity.Behavior = append(entity.Behavior, b)
			}
		}

		entities = append(entities, entity)
	}

	types := resolveEntities(entities)
	tygo.EXTENS_PKG = map[string]string{"Entity": "ibelie.rpc"}
	tygo.Typescript(tsOut, "types", "", types, PROP_PRE)
	tygo.EXTENS_PKG = nil
	injectJavascript(identName, tsOut, entities)
	injectTypescript(tsOut, entities, types)
	return entities
}

func injectTypescript(dir string, entities []*Entity, types []tygo.Type) {
	var buffer bytes.Buffer
	var methods []string
	methodsMap := make(map[string]bool)
	tygo.TS_OBJECTS = tygo.ObjectMap(types, true)
	for _, e := range entities {
		for _, c := range e.Components {
			if c.Protocol == nil {
				continue
			}
			for _, m := range c.Protocol.Methods {
				if ok, exist := methodsMap[m.Name]; exist && ok {
					continue
				} else if len(m.Results) > 0 {
					continue
				}
				var params []string
				for i, p := range m.Params {
					params = append(params, fmt.Sprintf("a%d: %s", i, p.Typescript()))
				}
				methods = append(methods, fmt.Sprintf(`
		%s(%s): void;`, m.Name, strings.Join(params, ", ")))
				methodsMap[m.Name] = true
			}
		}
	}
	tygo.TS_OBJECTS = nil

	buffer.Write([]byte(fmt.Sprintf(`// Generated by ibelie-rpc.  DO NOT EDIT!

declare module ibelie.rpc {
	interface Type {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
	}

	interface Entity {
		__class__: string;
		isAwake: boolean;
		Awake(entity: Type): any;
		Drop(entity: Type): any;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;%s
	}

	interface Behavior extends Entity {}

	class Connection {
		socket: WebSocket;
		entities: {[index: string]: Entity};
		constructor(url: string);
		disconnect(): void;
	}
}
`, strings.Join(methods, ""))))

	ioutil.WriteFile(path.Join(dir, "rpc.d.ts"), buffer.Bytes(), 0666)
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"regexp"
	"strings"

	"io/ioutil"

	"github.com/ibelie/tygo"
)

func Typescript(input string, tsOut string, goOut string) {
	text, err := ioutil.ReadFile(input)
	if err != nil {
		log.Fatalf("[RPC][Typescript] Cannot read file:\n>>>>%v", err)
		return
	}

	componentReg := regexp.MustCompile(`([_\d\w]+)\s*:\s*([\._\d\w]+)\s*;`)
	entityReg := regexp.MustCompile(`class\s+([_\d\w]+)\s+extends\s+ibelie.rpc.Entity\s*{`)
	entityText := entityReg.Split(string(text), -1)
	entityMap := make(map[string]map[string][]string)
	for i, e := range entityReg.FindAllStringSubmatch(string(text), -1) {
		entityMap[e[1]] = make(map[string][]string)
		for _, c := range componentReg.FindAllStringSubmatch(entityText[i+1], -1) {
			if !strings.HasSuffix(c[2], c[1]) {
				continue
			}
			pkg := strings.Replace(c[2][:len(c[2])-len(c[1])-1], ".", "/", -1)
			entityMap[e[1]][pkg] = append(entityMap[e[1]][pkg], c[1])
		}
	}
	entities, types := resolveEntities(entityMap)
	tygo.Typescript(tsOut, "types", "ibelie.rpc", types, nil)
	injectJavascript(tsOut, entities)
	injectTypescript(tsOut, entities)
}

func injectTypescript(dir string, entities []*Entity) {
	var buffer bytes.Buffer
	var methods []string

	buffer.Write([]byte(fmt.Sprintf(`// Generated by ibelie-rpc.  DO NOT EDIT!

declare module ibelie.rpc {
	class Entity {
		__class__: string;
		isAwake: boolean;
		Awake(): void;
		Sleep(): void;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;%s
	}

	class Component {
		Entity: Entity;
		constructor(entity: Entity);
	}
}
`, strings.Join(methods, ""))))

	ioutil.WriteFile(path.Join(dir, "rpc.d.ts"), buffer.Bytes(), 0666)
}
<commit_msg>inject ts ok<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package rpc

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"regexp"
	"strings"

	"io/ioutil"

	"github.com/ibelie/tygo"
)

func Typescript(input string, tsOut string, goOut string) {
	text, err := ioutil.ReadFile(input)
	if err != nil {
		log.Fatalf("[RPC][Typescript] Cannot read file:\n>>>>%v", err)
		return
	}

	componentReg := regexp.MustCompile(`([_\d\w]+)\s*:\s*([\._\d\w]+)\s*;`)
	entityReg := regexp.MustCompile(`class\s+([_\d\w]+)\s+extends\s+ibelie.rpc.Entity\s*{`)
	entityText := entityReg.Split(string(text), -1)
	entityMap := make(map[string]map[string][]string)
	for i, e := range entityReg.FindAllStringSubmatch(string(text), -1) {
		entityMap[e[1]] = make(map[string][]string)
		for _, c := range componentReg.FindAllStringSubmatch(entityText[i+1], -1) {
			if !strings.HasSuffix(c[2], c[1]) {
				continue
			}
			pkg := strings.Replace(c[2][:len(c[2])-len(c[1])-1], ".", "/", -1)
			entityMap[e[1]][pkg] = append(entityMap[e[1]][pkg], c[1])
		}
	}

	entities, types := resolveEntities(entityMap)
	objects := make(map[string]*tygo.Object)
	for _, t := range types {
		if object, ok := t.(*tygo.Object); ok {
			if o, exist := objects[object.Name]; exist {
				log.Fatalf("[RPC][Typescript] Object already exists: %v %v", o, object)
			}
			objects[object.Name] = object
		}
	}

	tygo.Typescript(tsOut, "types", "ibelie.rpc", types, []tygo.Type{tygo.SimpleType_UINT64, tygo.SimpleType_UINT64})
	injectJavascript(tsOut, entities)
	injectTypescript(tsOut, entities, objects)
}

func injectTypescript(dir string, entities []*Entity, objects map[string]*tygo.Object) {
	var buffer bytes.Buffer
	var methods []string
	for _, e := range entities {
		methodsMap := make(map[string]bool)
		for _, c := range e.Components {
			for _, m := range c.Methods {
				if ok, exist := methodsMap[m.Name]; exist && ok {
					continue
				} else if len(m.Results) > 0 {
					continue
				}
				var params []string
				for i, p := range m.Params {
					params = append(params, fmt.Sprintf("a%d: %s", i, p.Typescript(objects, nil)))
				}
				methods = append(methods, fmt.Sprintf(`
		%s(%s): void;`, m.Name, strings.Join(params, ", ")))
				methodsMap[m.Name] = true
			}
		}
	}

	buffer.Write([]byte(fmt.Sprintf(`// Generated by ibelie-rpc.  DO NOT EDIT!

declare module ibelie.rpc {
	class Entity {
		__class__: string;
		isAwake: boolean;
		Awake(): void;
		Sleep(): void;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;%s
	}

	class Component {
		Entity: Entity;
		constructor(entity: Entity);
	}
}
`, strings.Join(methods, ""))))

	ioutil.WriteFile(path.Join(dir, "rpc.d.ts"), buffer.Bytes(), 0666)
}
<|endoftext|>


<commit_before>package boardgame

import (
	"encoding/json"
	"github.com/workfit/tester/assert"
	"io/ioutil"
	"reflect"
	"testing"
)

func TestPlayerIndex(t *testing.T) {

	equivalentTests := []struct {
		p        PlayerIndex
		other    PlayerIndex
		expected bool
	}{
		{
			0,
			0,
			true,
		},
		{
			0,
			1,
			false,
		},
		{
			AdminPlayerIndex,
			0,
			true,
		},
		{
			AdminPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
		{
			ObserverPlayerIndex,
			1,
			false,
		},
		{
			0,
			AdminPlayerIndex,
			true,
		},
		{
			AdminPlayerIndex,
			AdminPlayerIndex,
			true,
		},
		{
			ObserverPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
	}

	for i, test := range equivalentTests {
		result := test.p.Equivalent(test.other)

		assert.For(t, "equivalent", i).ThatActual(result).Equals(test.expected)
	}
}

func TestState(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	record, err := game.Manager().Storage().State(game.Id(), game.Version())

	if err != nil {
		t.Error("Unexpected error", err)
	}

	state, err := game.Manager().stateFromRecord(record)
	state.game = game

	if err != nil {
		t.Error("StateFromBlob err", err)
	}

	if state == nil {
		t.Error("State could not be created")
	}

	currentJson, _ := json.Marshal(state)
	golden := goldenJSON("basic_state.json", t)

	compareJSONObjects(currentJson, golden, "Basic state", t)

	stateCopy := state.Copy(false)

	copyJson, _ := DefaultMarshalJSON(stateCopy)

	compareJSONObjects(copyJson, currentJson, "Copy was not same", t)

	_, playerStatesCopy := concreteStates(stateCopy)

	playerStatesCopy[0].MovesLeftThisTurn = 10

	_, playerStates := concreteStates(state)

	if playerStates[0].MovesLeftThisTurn == 10 {
		t.Error("Modifying a copy change the original")
	}

	if state.Sanitized() {
		t.Error("State reported being sanitized even when it wasn't")
	}

	sanitizedStateCopy := stateCopy.Copy(true)

	if !sanitizedStateCopy.Sanitized() {
		t.Error("A copy that was told it was sanitized did not report being sanitized.")
	}

	//TODO: test that GAmeState and UserStates are also copies
}

func TestStateSerialization(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	gameState, _ := concreteStates(game.CurrentState())

	if gameState.Timer.statePtr == nil {
		t.Error("The set up timer did no thave a stateptr")
	}

	if err := <-game.ProposeMove(&testMove{
		AString:           "bam",
		ScoreIncrement:    3,
		TargetPlayerIndex: 0,
		ABool:             true,
	}); err != nil {
		t.Fatal("Couldn't make move", err)
	}

	blob, err := json.Marshal(game.CurrentState())

	if err != nil {
		t.Fatal("Couldn't serialize state:", err)
	}

	reconstitutedState, err := game.Manager().stateFromRecord(blob)

	if err != nil {
		t.Error("StateFromBlob returned unexpected err", err)
	}

	reconstitutedState.game = game

	gameState, _ = concreteStates(reconstitutedState)

	if !gameState.DrawDeck.Inflated() {
		t.Error("The stack was not inflated when it came back from StateFromBlob")
	}

	if !gameState.DrawDeck.ComponentAt(0).DynamicValues(reconstitutedState).(*testingComponentDynamic).Stack.Inflated() {
		t.Error("The stack on a component's dynamic value was not inflated coming back from storage.")
	}

	if gameState.Timer.statePtr == nil {
		t.Error("The timer did not come back inflated from storage")
	}

	//This is lame, but when you create json for a State, it touches Computed,
	//which will make it non-nil, so if you're doing direct comparison they
	//won't compare equal even though they basically are. At this point
	//CurrentState has already been touched above by creating a json blob. So
	//just touch reconstitutedState, too. ¯\_(ツ)_/¯

	_, _ = json.Marshal(reconstitutedState)

	if !reflect.DeepEqual(reconstitutedState, game.CurrentState()) {

		rStateBlob, _ := json.Marshal(reconstitutedState)
		oStateBlob, _ := json.Marshal(game.CurrentState())

		t.Error("Reconstituted state and original state were not the same. Got", string(rStateBlob), "wanted", string(oStateBlob))
	}
}

func compareJSONObjects(in []byte, golden []byte, message string, t *testing.T) {

	//recreated in server/internal/teststoragemanager

	var deserializedIn interface{}
	var deserializedGolden interface{}

	json.Unmarshal(in, &deserializedIn)
	json.Unmarshal(golden, &deserializedGolden)

	assert.For(t).ThatActual(deserializedIn).IsNotNil()

	assert.For(t).ThatActual(deserializedGolden).IsNotNil()

	assert.For(t, message).ThatActual(deserializedGolden).Equals(deserializedIn).ThenDiffOnFail()

}

func goldenJSON(fileName string, t *testing.T) []byte {
	contents, err := ioutil.ReadFile("./test/" + fileName)

	if !assert.For(t, fileName).ThatActual(err).IsNil().Passed() {
		t.FailNow()
	}

	return contents

}
<commit_msg>Added tests for PlayerIndex.Valid. Part of #236.y<commit_after>package boardgame

import (
	"encoding/json"
	"github.com/workfit/tester/assert"
	"io/ioutil"
	"reflect"
	"testing"
)

func TestPlayerIndexValid(t *testing.T) {

	gameTwoPlayers := testGame()

	gameTwoPlayers.SetUp(2)

	stateTwoPlayers := gameTwoPlayers.CurrentState()

	tests := []struct {
		p        PlayerIndex
		state    State
		expected bool
	}{
		{
			0,
			stateTwoPlayers,
			true,
		},
		{
			ObserverPlayerIndex,
			stateTwoPlayers,
			true,
		},
		{
			AdminPlayerIndex,
			stateTwoPlayers,
			true,
		},
		{
			AdminPlayerIndex - 1,
			stateTwoPlayers,
			false,
		},
		{
			3,
			stateTwoPlayers,
			false,
		},
		{
			2,
			stateTwoPlayers,
			false,
		},
	}

	for i, test := range tests {
		result := test.p.Valid(test.state)
		assert.For(t, "valid", i).ThatActual(result).Equals(test.expected)
	}
}

func TestPlayerIndexEquivalent(t *testing.T) {

	equivalentTests := []struct {
		p        PlayerIndex
		other    PlayerIndex
		expected bool
	}{
		{
			0,
			0,
			true,
		},
		{
			0,
			1,
			false,
		},
		{
			AdminPlayerIndex,
			0,
			true,
		},
		{
			AdminPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
		{
			ObserverPlayerIndex,
			1,
			false,
		},
		{
			0,
			AdminPlayerIndex,
			true,
		},
		{
			AdminPlayerIndex,
			AdminPlayerIndex,
			true,
		},
		{
			ObserverPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
	}

	for i, test := range equivalentTests {
		result := test.p.Equivalent(test.other)

		assert.For(t, "equivalent", i).ThatActual(result).Equals(test.expected)
	}
}

func TestState(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	record, err := game.Manager().Storage().State(game.Id(), game.Version())

	if err != nil {
		t.Error("Unexpected error", err)
	}

	state, err := game.Manager().stateFromRecord(record)
	state.game = game

	if err != nil {
		t.Error("StateFromBlob err", err)
	}

	if state == nil {
		t.Error("State could not be created")
	}

	currentJson, _ := json.Marshal(state)
	golden := goldenJSON("basic_state.json", t)

	compareJSONObjects(currentJson, golden, "Basic state", t)

	stateCopy := state.Copy(false)

	copyJson, _ := DefaultMarshalJSON(stateCopy)

	compareJSONObjects(copyJson, currentJson, "Copy was not same", t)

	_, playerStatesCopy := concreteStates(stateCopy)

	playerStatesCopy[0].MovesLeftThisTurn = 10

	_, playerStates := concreteStates(state)

	if playerStates[0].MovesLeftThisTurn == 10 {
		t.Error("Modifying a copy change the original")
	}

	if state.Sanitized() {
		t.Error("State reported being sanitized even when it wasn't")
	}

	sanitizedStateCopy := stateCopy.Copy(true)

	if !sanitizedStateCopy.Sanitized() {
		t.Error("A copy that was told it was sanitized did not report being sanitized.")
	}

	//TODO: test that GAmeState and UserStates are also copies
}

func TestStateSerialization(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	gameState, _ := concreteStates(game.CurrentState())

	if gameState.Timer.statePtr == nil {
		t.Error("The set up timer did no thave a stateptr")
	}

	if err := <-game.ProposeMove(&testMove{
		AString:           "bam",
		ScoreIncrement:    3,
		TargetPlayerIndex: 0,
		ABool:             true,
	}); err != nil {
		t.Fatal("Couldn't make move", err)
	}

	blob, err := json.Marshal(game.CurrentState())

	if err != nil {
		t.Fatal("Couldn't serialize state:", err)
	}

	reconstitutedState, err := game.Manager().stateFromRecord(blob)

	if err != nil {
		t.Error("StateFromBlob returned unexpected err", err)
	}

	reconstitutedState.game = game

	gameState, _ = concreteStates(reconstitutedState)

	if !gameState.DrawDeck.Inflated() {
		t.Error("The stack was not inflated when it came back from StateFromBlob")
	}

	if !gameState.DrawDeck.ComponentAt(0).DynamicValues(reconstitutedState).(*testingComponentDynamic).Stack.Inflated() {
		t.Error("The stack on a component's dynamic value was not inflated coming back from storage.")
	}

	if gameState.Timer.statePtr == nil {
		t.Error("The timer did not come back inflated from storage")
	}

	//This is lame, but when you create json for a State, it touches Computed,
	//which will make it non-nil, so if you're doing direct comparison they
	//won't compare equal even though they basically are. At this point
	//CurrentState has already been touched above by creating a json blob. So
	//just touch reconstitutedState, too. ¯\_(ツ)_/¯

	_, _ = json.Marshal(reconstitutedState)

	if !reflect.DeepEqual(reconstitutedState, game.CurrentState()) {

		rStateBlob, _ := json.Marshal(reconstitutedState)
		oStateBlob, _ := json.Marshal(game.CurrentState())

		t.Error("Reconstituted state and original state were not the same. Got", string(rStateBlob), "wanted", string(oStateBlob))
	}
}

func compareJSONObjects(in []byte, golden []byte, message string, t *testing.T) {

	//recreated in server/internal/teststoragemanager

	var deserializedIn interface{}
	var deserializedGolden interface{}

	json.Unmarshal(in, &deserializedIn)
	json.Unmarshal(golden, &deserializedGolden)

	assert.For(t).ThatActual(deserializedIn).IsNotNil()

	assert.For(t).ThatActual(deserializedGolden).IsNotNil()

	assert.For(t, message).ThatActual(deserializedGolden).Equals(deserializedIn).ThenDiffOnFail()

}

func goldenJSON(fileName string, t *testing.T) []byte {
	contents, err := ioutil.ReadFile("./test/" + fileName)

	if !assert.For(t, fileName).ThatActual(err).IsNil().Passed() {
		t.FailNow()
	}

	return contents

}
<|endoftext|>


<commit_before>package boardgame

import (
	"encoding/json"
	"github.com/workfit/tester/assert"
	"io/ioutil"
	"reflect"
	"testing"
)

func TestPlayerIndexValid(t *testing.T) {

	gameTwoPlayers := testGame()

	gameTwoPlayers.SetUp(2)

	stateTwoPlayers := gameTwoPlayers.CurrentState()

	tests := []struct {
		p        PlayerIndex
		state    State
		expected bool
	}{
		{
			0,
			stateTwoPlayers,
			true,
		},
		{
			ObserverPlayerIndex,
			stateTwoPlayers,
			true,
		},
		{
			AdminPlayerIndex,
			stateTwoPlayers,
			true,
		},
		{
			AdminPlayerIndex - 1,
			stateTwoPlayers,
			false,
		},
		{
			3,
			stateTwoPlayers,
			false,
		},
		{
			2,
			stateTwoPlayers,
			false,
		},
	}

	for i, test := range tests {
		result := test.p.Valid(test.state)
		assert.For(t, "valid", i).ThatActual(result).Equals(test.expected)
	}
}

func TestPlayerIndexEquivalent(t *testing.T) {

	equivalentTests := []struct {
		p        PlayerIndex
		other    PlayerIndex
		expected bool
	}{
		{
			0,
			0,
			true,
		},
		{
			0,
			1,
			false,
		},
		{
			AdminPlayerIndex,
			0,
			true,
		},
		{
			AdminPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
		{
			ObserverPlayerIndex,
			1,
			false,
		},
		{
			0,
			AdminPlayerIndex,
			true,
		},
		{
			AdminPlayerIndex,
			AdminPlayerIndex,
			true,
		},
		{
			ObserverPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
	}

	for i, test := range equivalentTests {
		result := test.p.Equivalent(test.other)

		assert.For(t, "equivalent", i).ThatActual(result).Equals(test.expected)
	}
}

func TestState(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	record, err := game.Manager().Storage().State(game.Id(), game.Version())

	if err != nil {
		t.Error("Unexpected error", err)
	}

	state, err := game.Manager().stateFromRecord(record)
	state.game = game

	if err != nil {
		t.Error("StateFromBlob err", err)
	}

	if state == nil {
		t.Error("State could not be created")
	}

	currentJson, _ := json.Marshal(state)
	golden := goldenJSON("basic_state.json", t)

	compareJSONObjects(currentJson, golden, "Basic state", t)

	stateCopy := state.Copy(false)

	copyJson, _ := DefaultMarshalJSON(stateCopy)

	compareJSONObjects(copyJson, currentJson, "Copy was not same", t)

	_, playerStatesCopy := concreteStates(stateCopy)

	playerStatesCopy[0].MovesLeftThisTurn = 10

	_, playerStates := concreteStates(state)

	if playerStates[0].MovesLeftThisTurn == 10 {
		t.Error("Modifying a copy change the original")
	}

	if state.Sanitized() {
		t.Error("State reported being sanitized even when it wasn't")
	}

	sanitizedStateCopy := stateCopy.Copy(true)

	if !sanitizedStateCopy.Sanitized() {
		t.Error("A copy that was told it was sanitized did not report being sanitized.")
	}

	//TODO: test that GAmeState and UserStates are also copies
}

func TestStateSerialization(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	gameState, _ := concreteStates(game.CurrentState())

	if gameState.Timer.statePtr == nil {
		t.Error("The set up timer did no thave a stateptr")
	}

	if err := <-game.ProposeMove(&testMove{
		AString:           "bam",
		ScoreIncrement:    3,
		TargetPlayerIndex: 0,
		ABool:             true,
	}); err != nil {
		t.Fatal("Couldn't make move", err)
	}

	blob, err := json.Marshal(game.CurrentState())

	if err != nil {
		t.Fatal("Couldn't serialize state:", err)
	}

	reconstitutedState, err := game.Manager().stateFromRecord(blob)

	if err != nil {
		t.Error("StateFromBlob returned unexpected err", err)
	}

	reconstitutedState.game = game

	gameState, _ = concreteStates(reconstitutedState)

	if !gameState.DrawDeck.Inflated() {
		t.Error("The stack was not inflated when it came back from StateFromBlob")
	}

	if !gameState.DrawDeck.ComponentAt(0).DynamicValues(reconstitutedState).(*testingComponentDynamic).Stack.Inflated() {
		t.Error("The stack on a component's dynamic value was not inflated coming back from storage.")
	}

	if gameState.Timer.statePtr == nil {
		t.Error("The timer did not come back inflated from storage")
	}

	//This is lame, but when you create json for a State, it touches Computed,
	//which will make it non-nil, so if you're doing direct comparison they
	//won't compare equal even though they basically are. At this point
	//CurrentState has already been touched above by creating a json blob. So
	//just touch reconstitutedState, too. ¯\_(ツ)_/¯

	_, _ = json.Marshal(reconstitutedState)

	if !reflect.DeepEqual(reconstitutedState, game.CurrentState()) {

		rStateBlob, _ := json.Marshal(reconstitutedState)
		oStateBlob, _ := json.Marshal(game.CurrentState())

		t.Error("Reconstituted state and original state were not the same. Got", string(rStateBlob), "wanted", string(oStateBlob))
	}
}

func compareJSONObjects(in []byte, golden []byte, message string, t *testing.T) {

	//recreated in server/internal/teststoragemanager

	var deserializedIn interface{}
	var deserializedGolden interface{}

	json.Unmarshal(in, &deserializedIn)
	json.Unmarshal(golden, &deserializedGolden)

	assert.For(t).ThatActual(deserializedIn).IsNotNil()

	assert.For(t).ThatActual(deserializedGolden).IsNotNil()

	assert.For(t, message).ThatActual(deserializedGolden).Equals(deserializedIn).ThenDiffOnFail()

}

func goldenJSON(fileName string, t *testing.T) []byte {
	contents, err := ioutil.ReadFile("./test/" + fileName)

	if !assert.For(t, fileName).ThatActual(err).IsNil().Passed() {
		t.FailNow()
	}

	return contents

}
<commit_msg>Added tests for PlayerIndex.Next, Previous. Part of #236.<commit_after>package boardgame

import (
	"encoding/json"
	"github.com/workfit/tester/assert"
	"io/ioutil"
	"reflect"
	"testing"
)

func TestPlayerIndexNextPrevious(t *testing.T) {

	game := testGame()

	game.SetUp(3)

	state := game.CurrentState()

	tests := []struct {
		p            PlayerIndex
		expectedNext PlayerIndex
		expectedPrev PlayerIndex
	}{
		{
			0,
			1,
			2,
		},
		{
			2,
			0,
			1,
		},
		{
			AdminPlayerIndex,
			AdminPlayerIndex,
			AdminPlayerIndex,
		},
		{
			ObserverPlayerIndex,
			ObserverPlayerIndex,
			ObserverPlayerIndex,
		},
	}

	for i, test := range tests {
		result := test.p.Next(state)
		assert.For(t, "next", i).ThatActual(result).Equals(test.expectedNext)

		result = test.p.Previous(state)

		assert.For(t, "prev", i).ThatActual(result).Equals(test.expectedPrev)
	}
}

func TestPlayerIndexValid(t *testing.T) {

	gameTwoPlayers := testGame()

	gameTwoPlayers.SetUp(2)

	stateTwoPlayers := gameTwoPlayers.CurrentState()

	tests := []struct {
		p        PlayerIndex
		state    State
		expected bool
	}{
		{
			0,
			stateTwoPlayers,
			true,
		},
		{
			ObserverPlayerIndex,
			stateTwoPlayers,
			true,
		},
		{
			AdminPlayerIndex,
			stateTwoPlayers,
			true,
		},
		{
			AdminPlayerIndex - 1,
			stateTwoPlayers,
			false,
		},
		{
			3,
			stateTwoPlayers,
			false,
		},
		{
			2,
			stateTwoPlayers,
			false,
		},
	}

	for i, test := range tests {
		result := test.p.Valid(test.state)
		assert.For(t, "valid", i).ThatActual(result).Equals(test.expected)
	}
}

func TestPlayerIndexEquivalent(t *testing.T) {

	equivalentTests := []struct {
		p        PlayerIndex
		other    PlayerIndex
		expected bool
	}{
		{
			0,
			0,
			true,
		},
		{
			0,
			1,
			false,
		},
		{
			AdminPlayerIndex,
			0,
			true,
		},
		{
			AdminPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
		{
			ObserverPlayerIndex,
			1,
			false,
		},
		{
			0,
			AdminPlayerIndex,
			true,
		},
		{
			AdminPlayerIndex,
			AdminPlayerIndex,
			true,
		},
		{
			ObserverPlayerIndex,
			ObserverPlayerIndex,
			false,
		},
	}

	for i, test := range equivalentTests {
		result := test.p.Equivalent(test.other)

		assert.For(t, "equivalent", i).ThatActual(result).Equals(test.expected)
	}
}

func TestState(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	record, err := game.Manager().Storage().State(game.Id(), game.Version())

	if err != nil {
		t.Error("Unexpected error", err)
	}

	state, err := game.Manager().stateFromRecord(record)
	state.game = game

	if err != nil {
		t.Error("StateFromBlob err", err)
	}

	if state == nil {
		t.Error("State could not be created")
	}

	currentJson, _ := json.Marshal(state)
	golden := goldenJSON("basic_state.json", t)

	compareJSONObjects(currentJson, golden, "Basic state", t)

	stateCopy := state.Copy(false)

	copyJson, _ := DefaultMarshalJSON(stateCopy)

	compareJSONObjects(copyJson, currentJson, "Copy was not same", t)

	_, playerStatesCopy := concreteStates(stateCopy)

	playerStatesCopy[0].MovesLeftThisTurn = 10

	_, playerStates := concreteStates(state)

	if playerStates[0].MovesLeftThisTurn == 10 {
		t.Error("Modifying a copy change the original")
	}

	if state.Sanitized() {
		t.Error("State reported being sanitized even when it wasn't")
	}

	sanitizedStateCopy := stateCopy.Copy(true)

	if !sanitizedStateCopy.Sanitized() {
		t.Error("A copy that was told it was sanitized did not report being sanitized.")
	}

	//TODO: test that GAmeState and UserStates are also copies
}

func TestStateSerialization(t *testing.T) {

	game := testGame()

	game.SetUp(0)

	gameState, _ := concreteStates(game.CurrentState())

	if gameState.Timer.statePtr == nil {
		t.Error("The set up timer did no thave a stateptr")
	}

	if err := <-game.ProposeMove(&testMove{
		AString:           "bam",
		ScoreIncrement:    3,
		TargetPlayerIndex: 0,
		ABool:             true,
	}); err != nil {
		t.Fatal("Couldn't make move", err)
	}

	blob, err := json.Marshal(game.CurrentState())

	if err != nil {
		t.Fatal("Couldn't serialize state:", err)
	}

	reconstitutedState, err := game.Manager().stateFromRecord(blob)

	if err != nil {
		t.Error("StateFromBlob returned unexpected err", err)
	}

	reconstitutedState.game = game

	gameState, _ = concreteStates(reconstitutedState)

	if !gameState.DrawDeck.Inflated() {
		t.Error("The stack was not inflated when it came back from StateFromBlob")
	}

	if !gameState.DrawDeck.ComponentAt(0).DynamicValues(reconstitutedState).(*testingComponentDynamic).Stack.Inflated() {
		t.Error("The stack on a component's dynamic value was not inflated coming back from storage.")
	}

	if gameState.Timer.statePtr == nil {
		t.Error("The timer did not come back inflated from storage")
	}

	//This is lame, but when you create json for a State, it touches Computed,
	//which will make it non-nil, so if you're doing direct comparison they
	//won't compare equal even though they basically are. At this point
	//CurrentState has already been touched above by creating a json blob. So
	//just touch reconstitutedState, too. ¯\_(ツ)_/¯

	_, _ = json.Marshal(reconstitutedState)

	if !reflect.DeepEqual(reconstitutedState, game.CurrentState()) {

		rStateBlob, _ := json.Marshal(reconstitutedState)
		oStateBlob, _ := json.Marshal(game.CurrentState())

		t.Error("Reconstituted state and original state were not the same. Got", string(rStateBlob), "wanted", string(oStateBlob))
	}
}

func compareJSONObjects(in []byte, golden []byte, message string, t *testing.T) {

	//recreated in server/internal/teststoragemanager

	var deserializedIn interface{}
	var deserializedGolden interface{}

	json.Unmarshal(in, &deserializedIn)
	json.Unmarshal(golden, &deserializedGolden)

	assert.For(t).ThatActual(deserializedIn).IsNotNil()

	assert.For(t).ThatActual(deserializedGolden).IsNotNil()

	assert.For(t, message).ThatActual(deserializedGolden).Equals(deserializedIn).ThenDiffOnFail()

}

func goldenJSON(fileName string, t *testing.T) []byte {
	contents, err := ioutil.ReadFile("./test/" + fileName)

	if !assert.For(t, fileName).ThatActual(err).IsNil().Passed() {
		t.FailNow()
	}

	return contents

}
<|endoftext|>