<commit_before>package main

import (
	"bufio"
	"database/sql"
	"fmt"
	"io"
	"os"

	_ "github.com/mattn/go-sqlite3"
)

const dbName = "db"

// ExportCommand creates image file from CLIP STUDIO file
type ExportCommand struct{}

func (c *ExportCommand) Synopsis() string {
	return "Export an illustration from latest .clip file"
}

func (c *ExportCommand) Help() string {
	return "Usage: clip export CLIP_STUDIO_FILE IMG_NAME"
}

func (c *ExportCommand) Run(args []string) int {
	if len(args) != 2 {
		fmt.Fprintln(os.Stderr, c.Help())
		return 1
	}

	clipFileName := args[0]
	outputFileName := args[1]

	if !isExists(".clip") {
		mkClipDir()
	}

	if !isExists(clipFileName) {
		fmt.Fprintf(os.Stderr, "%s: no such file\n", clipFileName)
		return 1
	}

	f, err := os.Open(clipFileName)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	defer f.Close()

	buf := bufio.NewReader(f)
	i, err := seekSQLiteHeader(buf)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	stat, err := f.Stat()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}

	if err := extractSQLiteDB(f, int64(i), stat.Size()); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if err := extractIllustration(outputFileName); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if err := os.Remove(dbName); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	return 0
}

func seekSQLiteHeader(buf io.ByteReader) (int, error) {
	header := []byte{
		0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33,
	}

	n, at, i := 0, 0, 0
	for {
		b, err := buf.ReadByte()
		if err == io.EOF {
			return -1, fmt.Errorf("SQLite header not found")
		}

		if err != nil {
			return -1, err
		}

		if b == header[n] {
			if n == 0 {
				at = i
			}
			n++
		} else if n > 0 {
			n = 0
		}

		if n == len(header) {
			return at, nil
		}

		i++
	}
}

func extractSQLiteDB(r io.ReaderAt, at, size int64) error {
	data := make([]byte, size)
	_, err := r.ReadAt(data, at)
	if err != nil && err != io.EOF {
		return err
	}

	fmt.Println(len(data))

	// TODO: ioutil.TempFile 使う
	f, err := os.OpenFile(dbName, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	f.Write(data)

	return nil
}

func extractIllustration(illustName string) error {
	db, err := sql.Open("sqlite3", dbName)
	if err != nil {
		return err
	}
	defer db.Close()

	f, err := os.OpenFile(fmt.Sprintf(".clip/%s", illustName), os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	var length int
	err = db.QueryRow("select length(ImageData) from CanvasPreview").Scan(&length)
	if err != nil {
		return err
	}

	image := make([]byte, length)
	err = db.QueryRow("select ImageData from CanvasPreview").Scan(&image)
	if err != nil {
		return err
	}

	f.Write(image)

	return nil
}
<commit_msg>[MOD] Refactored the export mechanism<commit_after>package main

import (
	"bufio"
	"database/sql"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	_ "github.com/mattn/go-sqlite3"
)

// ExportCommand creates image file from CLIP STUDIO file
type ExportCommand struct{}

func (c *ExportCommand) Synopsis() string {
	return "Export an illustration from latest .clip file"
}

func (c *ExportCommand) Help() string {
	return "Usage: clip export CLIP_STUDIO_FILE IMG_NAME"
}

func (c *ExportCommand) Run(args []string) int {
	if len(args) != 2 {
		fmt.Fprintln(os.Stderr, c.Help())
		return 1
	}

	tempFile, cleanup, err := makeTempFile()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	defer cleanup()

	clipFileName := args[0]
	outputFileName := args[1]

	if !isExists(".clip") {
		mkClipDir()
	}

	if !isExists(clipFileName) {
		fmt.Fprintf(os.Stderr, "%s: no such file\n", clipFileName)
		return 1
	}

	f, err := os.Open(clipFileName)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	defer f.Close()

	buf := bufio.NewReader(f)
	i, err := seekSQLiteHeader(buf)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	stat, err := f.Stat()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}

	if err := extractSQLiteDB(tempFile, f, int64(i), stat.Size()); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if err := extractIllustration(tempFile.Name(), outputFileName); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	return 0
}

func makeTempFile() (*os.File, func() error, error) {
	f, err := ioutil.TempFile("", "clip")
	if err != nil {
		return nil, nil, err
	}

	return f, func() error {
		if err := f.Close(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return err
		}

		if err := os.Remove(f.Name()); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return err
		}
		return nil
	}, nil
}

func seekSQLiteHeader(buf io.ByteReader) (int, error) {
	// TODO: 最初のメタデータからデータ位置を特定したい
	header := []byte{
		0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33,
	}

	n, at, i := 0, 0, 0
	for {
		b, err := buf.ReadByte()
		if err == io.EOF {
			return -1, fmt.Errorf("SQLite header not found")
		}

		if err != nil {
			return -1, err
		}

		if b == header[n] {
			if n == 0 {
				at = i
			}
			n++
		} else if n > 0 {
			n = 0
		}

		if n == len(header) {
			return at, nil
		}

		i++
	}
}

func extractSQLiteDB(f *os.File, r io.ReaderAt, at, size int64) error {
	data := make([]byte, size)
	_, err := r.ReadAt(data, at)
	if err != nil && err != io.EOF {
		return err
	}

	f.Write(data)

	return nil
}

func extractIllustration(dbName, illustName string) error {
	db, err := sql.Open("sqlite3", dbName)
	if err != nil {
		return err
	}
	defer db.Close()

	f, err := os.OpenFile(filepath.Join(".clip", illustName), os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	var length int
	err = db.QueryRow("SELECT length(ImageData) FROM CanvasPreview").Scan(&length)
	if err != nil {
		return err
	}

	image := make([]byte, length)
	err = db.QueryRow("SELECT ImageData FROM CanvasPreview").Scan(&image)
	if err != nil {
		return err
	}

	f.Write(image)

	return nil
}
<|endoftext|>


<commit_before>/* scryptauth is a GO library for secure password handling

It uses sha256_hmac(scrypt(user_password, salt), server_key) to protect against
both dictionary attacks and DB leaks.

scryptauth additionally provides encode/decode routines using base64 to create strings
for storing into a DB.

Copyright: Michael Gebetsroither 2012 (michael \x40 mgeb \x2e org)

License: BSD 2 clause
*/
package scryptauth

import (
	"code.google.com/p/go.crypto/scrypt"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"errors"
)

type ScryptAuth struct {
	HmacKey []byte // HMAC key used to secure scrypt hash
	PwCost  uint   // PwCost parameter used to calculate N parameter of scrypt (1<<PwCost == N)

	// scrypt parameter
	R int
	P int
}

const (
	// Key length and salt length are 32 bytes (256 bits)
	KEYLENGTH = 32

	// scrypt default parameters
	SCRYPT_CONST_R = 8
	SCRYPT_CONST_P = 1
)

// Initialise ScryptAuth struct
func New(pw_cost uint, hmac_key []byte) (*ScryptAuth, error) {
	if pw_cost > 32 {
		return nil, errors.New("scryptauth new() - invalid pw_cost specified")
	}
	if len(hmac_key) != KEYLENGTH {
		return nil, errors.New("scryptauth new() - unsupported hmac_key length")
	}
	return &ScryptAuth{HmacKey: hmac_key, PwCost: pw_cost, R: SCRYPT_CONST_R, P: SCRYPT_CONST_P}, nil
}

// Create hash_ref suitable for later invocation of Check()
func (s ScryptAuth) Hash(pw_cost uint, user_password, salt []byte) (hash_ref []byte, err error) {
	scrypt_hash, err := scrypt.Key(user_password, salt, 1<<pw_cost, s.R, s.P, KEYLENGTH)
	if err != nil {
		return
	}
	hmac := hmac.New(sha256.New, s.HmacKey)
	if _, err = hmac.Write(scrypt_hash); err != nil {
		return
	}
	hash_ref = hmac.Sum(nil)
	return
}

// Check / Verify user_password against hash_ref/salt
func (s ScryptAuth) Check(pw_cost uint, hash_ref, user_password, salt []byte) (chk bool, err error) {
	result_hash, err := s.Hash(pw_cost, user_password, salt)
	if err != nil {
		return false, err
	}
	if subtle.ConstantTimeCompare(result_hash, hash_ref) != 1 {
		return false, errors.New("Error: Hash verification failed")
	}
	return true, nil
}

// Generate hash_ref and create new salt from crypto.rand
func (s ScryptAuth) Gen(user_password []byte) (hash, salt []byte, err error) {
	salt = make([]byte, KEYLENGTH)
	salt_length, err := rand.Read(salt)
	if salt_length != KEYLENGTH {
		return nil, nil, errors.New("Insufficient random bytes for salt")
	}
	if err != nil {
		return nil, nil, err
	}

	hash, err = s.Hash(s.PwCost, user_password, salt)
	if err != nil {
		return nil, nil, err
	}
	return
}
<commit_msg>add scrypt to package description so godoc.org can find it too<commit_after>/* scryptauth is a GO library for secure password handling using scrypt

It uses sha256_hmac(scrypt(user_password, salt), server_key) to protect against
both dictionary attacks and DB leaks.

scryptauth additionally provides encode/decode routines using base64 to create strings
for storing into a DB.

Copyright: Michael Gebetsroither 2012 (michael \x40 mgeb \x2e org)

License: BSD 2 clause
*/
package scryptauth

import (
	"code.google.com/p/go.crypto/scrypt"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"errors"
)

type ScryptAuth struct {
	HmacKey []byte // HMAC key used to secure scrypt hash
	PwCost  uint   // PwCost parameter used to calculate N parameter of scrypt (1<<PwCost == N)

	// scrypt parameter
	R int
	P int
}

const (
	// Key length and salt length are 32 bytes (256 bits)
	KEYLENGTH = 32

	// scrypt default parameters
	SCRYPT_CONST_R = 8
	SCRYPT_CONST_P = 1
)

// Initialise ScryptAuth struct
func New(pw_cost uint, hmac_key []byte) (*ScryptAuth, error) {
	if pw_cost > 32 {
		return nil, errors.New("scryptauth new() - invalid pw_cost specified")
	}
	if len(hmac_key) != KEYLENGTH {
		return nil, errors.New("scryptauth new() - unsupported hmac_key length")
	}
	return &ScryptAuth{HmacKey: hmac_key, PwCost: pw_cost, R: SCRYPT_CONST_R, P: SCRYPT_CONST_P}, nil
}

// Create hash_ref suitable for later invocation of Check()
func (s ScryptAuth) Hash(pw_cost uint, user_password, salt []byte) (hash_ref []byte, err error) {
	scrypt_hash, err := scrypt.Key(user_password, salt, 1<<pw_cost, s.R, s.P, KEYLENGTH)
	if err != nil {
		return
	}
	hmac := hmac.New(sha256.New, s.HmacKey)
	if _, err = hmac.Write(scrypt_hash); err != nil {
		return
	}
	hash_ref = hmac.Sum(nil)
	return
}

// Check / Verify user_password against hash_ref/salt
func (s ScryptAuth) Check(pw_cost uint, hash_ref, user_password, salt []byte) (chk bool, err error) {
	result_hash, err := s.Hash(pw_cost, user_password, salt)
	if err != nil {
		return false, err
	}
	if subtle.ConstantTimeCompare(result_hash, hash_ref) != 1 {
		return false, errors.New("Error: Hash verification failed")
	}
	return true, nil
}

// Generate hash_ref and create new salt from crypto.rand
func (s ScryptAuth) Gen(user_password []byte) (hash, salt []byte, err error) {
	salt = make([]byte, KEYLENGTH)
	salt_length, err := rand.Read(salt)
	if salt_length != KEYLENGTH {
		return nil, nil, errors.New("Insufficient random bytes for salt")
	}
	if err != nil {
		return nil, nil, err
	}

	hash, err = s.Hash(s.PwCost, user_password, salt)
	if err != nil {
		return nil, nil, err
	}
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative Authors

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 ingress

import (
	"testing"

	"k8s.io/apimachinery/pkg/util/intstr"
	"knative.dev/networking/pkg/apis/networking"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/networking/test"
)

// TestRewriteHost verifies that a RewriteHost rule can be used to implement vanity URLs.
func TestRewriteHost(t *testing.T) {
	t.Parallel()
	clients := test.Setup(t)

	name, port, cancel := CreateRuntimeService(t, clients, networking.ServicePortNameHTTP1)
	defer cancel()

	// Create a simple Ingress over the Service.
	_, _, cancel = CreateIngressReady(t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Visibility: v1alpha1.IngressVisibilityClusterLocal,
			Hosts:      []string{name + ".example.com"},
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      name,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(port),
						},
					}},
				}},
			},
		}},
	})
	defer cancel()

	hosts := []string{
		"vanity.ismy.name",
		"vanity.isalsomy.number",
	}

	// Using fixed hostnames can lead to conflicts when -count=N>1
	// so pseudo-randomize the hostnames to avoid conflicts.
	for i, host := range hosts {
		hosts[i] = name + "." + host
	}

	// Now create a RewriteHost ingress to point a custom Host at the Service
	_, client, cancel := CreateIngressReady(t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Hosts:      hosts,
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					RewriteHost: name + ".example.com",
				}},
			},
		}},
	})
	defer cancel()

	for _, host := range hosts {
		RuntimeRequest(t, client, host)
	}
}
<commit_msg>Add scheme (#96)<commit_after>/*
Copyright 2020 The Knative Authors

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 ingress

import (
	"testing"

	"k8s.io/apimachinery/pkg/util/intstr"
	"knative.dev/networking/pkg/apis/networking"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/networking/test"
)

// TestRewriteHost verifies that a RewriteHost rule can be used to implement vanity URLs.
func TestRewriteHost(t *testing.T) {
	t.Parallel()
	clients := test.Setup(t)

	name, port, cancel := CreateRuntimeService(t, clients, networking.ServicePortNameHTTP1)
	defer cancel()

	// Create a simple Ingress over the Service.
	_, _, cancel = CreateIngressReady(t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Visibility: v1alpha1.IngressVisibilityClusterLocal,
			Hosts:      []string{name + ".example.com"},
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      name,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(port),
						},
					}},
				}},
			},
		}},
	})
	defer cancel()

	hosts := []string{
		"vanity.ismy.name",
		"vanity.isalsomy.number",
	}

	// Using fixed hostnames can lead to conflicts when -count=N>1
	// so pseudo-randomize the hostnames to avoid conflicts.
	for i, host := range hosts {
		hosts[i] = name + "." + host
	}

	// Now create a RewriteHost ingress to point a custom Host at the Service
	_, client, cancel := CreateIngressReady(t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Hosts:      hosts,
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					RewriteHost: name + ".example.com",
				}},
			},
		}},
	})
	defer cancel()

	for _, host := range hosts {
		RuntimeRequest(t, client, "http://"+host)
	}
}
<|endoftext|>


<commit_before>package net4g

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/carsonsx/log4g"
	"github.com/carsonsx/net4g/util"
	"github.com/golang/protobuf/proto"
	"reflect"
)

type Serializer interface {
	SetIdStartingValue(id int)
	RegisterById(t reflect.Type, id_at_most_one ...int) (id int, err error)
	RegisterByKey(t reflect.Type, key_at_most_one ...string) (key string, err error)
	Serialize(v interface{}) (data []byte, err error)
	Deserialize(data []byte) (v interface{}, err error)
	RangeId(f func(id int, t reflect.Type))
	RangeKey(f func(key string, t reflect.Type))
}

type emptySerializer struct {
	type_id_map  map[reflect.Type]int
	type_key_map map[reflect.Type]string
	id_type_map  map[int]reflect.Type
	key_type_map map[string]reflect.Type
	ids []int
	keys []string
	id           int
	registered   bool
	byId         bool
}

func (s *emptySerializer) SetIdStartingValue(id int) {
	s.id = id
}

func (s *emptySerializer) RegisterById(t reflect.Type, id_at_most_one ...int) (id int, err error) {

	if t == nil || t.Kind() != reflect.Ptr {
		panic("type must be a pointer")
	}

	if len(s.type_key_map) > 0 {
		panic("can not registered id and key in one serializer")
	}

	if len(id_at_most_one) > 1 {
		panic("only mapping one type with one id")
	}

	if _id, ok := s.type_id_map[t]; ok {
		text := fmt.Sprintf("%s has been registered by %d", t.String(), _id)
		log4g.Error(text)
		return 0, errors.New(text)
	}

	if len(id_at_most_one) == 1 {
		id = id_at_most_one[0]
	} else {
		id = s.id
	}

	s.type_id_map[t] = id
	s.id_type_map[id] = t
	s.ids = append(s.ids, id)

	s.byId = true
	s.registered = true

	s.id++

	return
}

func (s *emptySerializer) RegisterByKey(t reflect.Type, key_at_most_one ...string) (key string, err error) {

	if t == nil || t.Kind() != reflect.Ptr {
		panic("type must be a pointer")
	}

	if len(s.type_id_map) > 0 {
		panic("can not registered key and id in one serializer")
	}

	if len(key_at_most_one) > 1 {
		panic("only mapping one type with one key")
	}

	if _key, ok := s.type_key_map[t]; ok {
		text := fmt.Sprintf("%s has been registered by %s", t.Elem().Name(), _key)
		log4g.Error(text)
		err = errors.New(text)
		return
	}

	if len(key_at_most_one) == 1 {
		key = key_at_most_one[0]
	} else {
		key = t.String()
	}

	s.type_key_map[t] = key
	s.key_type_map[key] = t
	s.keys = append(s.keys, key)

	s.byId = false
	s.registered = true

	log4g.Info("%v register by key '%s'\n", t, key)

	return
}

func (s *emptySerializer) Serialize(v interface{}) (data []byte, err error) {
	return v.([]byte), nil
}

func (s *emptySerializer) Deserialize(data []byte) (v interface{}, err error) {
	return data, nil
}

func (s *emptySerializer) RangeId(f func(id int, t reflect.Type)) {
	for _, id := range s.ids {
		f(id, s.id_type_map[id])
	}
}

func (s *emptySerializer) RangeKey(f func(key string, t reflect.Type)) {
	for _, key := range s.keys {
		f(key, s.key_type_map[key])
	}
}

func NewEmptySerializer() Serializer {
	return newEmptySerializer()
}

func newEmptySerializer() *emptySerializer {
	s := new(emptySerializer)
	s.type_id_map = make(map[reflect.Type]int)
	s.id_type_map = make(map[int]reflect.Type)
	s.type_key_map = make(map[reflect.Type]string)
	s.key_type_map = make(map[string]reflect.Type)
	s.id = 1
	return s
}

type stringSerializer struct {
	Serializer
}

func (s *stringSerializer) Serialize(v interface{}) (data []byte, err error) {
	return []byte(v.(string)), nil
}

func (s *stringSerializer) Deserialize(data []byte) (v interface{}, err error) {
	return string(data), nil
}

func NewStringSerializer() Serializer {
	s := new(stringSerializer)
	s.Serializer = newEmptySerializer()
	return s
}

type jsonSerializer struct {
	*emptySerializer
}

func (s *jsonSerializer) Serialize(v interface{}) (data []byte, err error) {

	if !s.registered {
		panic("not registered any id or key")
	}

	t := reflect.TypeOf(v)

	if s.byId {
		if id, ok := s.type_id_map[t]; ok {
			data, err = json.Marshal(v)
			if err != nil {
				log4g.Error(err)
				return
			}
			data = util.AddIntHeader(data, NetConfig.MessageIdSize, uint64(id), NetConfig.LittleEndian)
			if log4g.IsTraceEnabled() {
				log4g.Trace("serialized %v - %s", t, string(data))
			}
		} else {
			err = errors.New(fmt.Sprintf("%v is not registed by any id", t))
			log4g.Error(err)
		}
	} else {
		if key, ok := s.type_key_map[t]; ok {
			m := map[string]interface{}{key: v}
			data, err = json.Marshal(m)
			if err != nil {
				log4g.Error(err)
				return
			}
			if log4g.IsTraceEnabled() {
				log4g.Trace("serialized %v - %s", t, string(data))
			}
		} else {
			log4g.Panic("%v is not registered by any key", t)
		}
	}

	return
}

func (s *jsonSerializer) Deserialize(data []byte) (v interface{}, err error) {

	if !s.registered {
		panic("not registered any id or key")
	}

	if s.byId {
		id := int(util.GetIntHeader(data, NetConfig.MessageIdSize, NetConfig.LittleEndian))
		if t, ok := s.id_type_map[id]; ok {
			value := reflect.New(t.Elem()).Interface()
			err = json.Unmarshal(data[NetConfig.MessageIdSize:], value)
			if err != nil {
				log4g.Error(err)
			} else {
				v = value
				log4g.Trace("rcvd %v - %s", t, string(data))
			}
		} else {
			err = errors.New(fmt.Sprintf("id[%d] is not registered by any type", id))
			log4g.Error(err)
		}
	} else {
		var m_raw map[string]json.RawMessage
		err = json.Unmarshal(data, &m_raw)
		if err != nil {
			log4g.Error(err)
			return nil, err
		}
		if len(m_raw) == 0 {
			text := fmt.Sprintf("invalid json: %v", string(data))
			log4g.Error(text)
			err = errors.New(text)
			return
		}
		for key, raw := range m_raw {
			if t, ok := s.key_type_map[key]; ok {
				value := reflect.New(t.Elem()).Interface()
				err = json.Unmarshal(raw, value)
				if err != nil {
					log4g.Error(err)
				} else {
					v = value
					log4g.Trace("rcvd %v - %s", t, string(raw))
				}
			} else {
				err = errors.New(fmt.Sprintf("key '%s' is not registered by any type", key))
				log4g.Error(err)
			}
		}
	}
	return
}

func NewJsonSerializer() Serializer {
	s := new(jsonSerializer)
	s.emptySerializer = newEmptySerializer()
	return s
}

type protobufSerializer struct {
	*emptySerializer
}

func (s *protobufSerializer) Serialize(v interface{}) (data []byte, err error) {

	if !s.registered {
		log4g.Panic("not registered any id")
	}

	t := reflect.TypeOf(v)
	if id, ok := s.type_id_map[t]; ok {
		data, err = proto.Marshal(v.(proto.Message))
		if err != nil {
			log4g.Error(err)
			return
		}
		data = util.AddIntHeader(data, NetConfig.MessageIdSize, uint64(id), NetConfig.LittleEndian)
		if log4g.IsDebugEnabled() {
			bytes, _ := json.Marshal(v)
			log4g.Debug("serialize %v - %v", t, string(bytes))
		}
	} else {
		err = errors.New(fmt.Sprintf("%v is not registed by any id", t))
	}
	return
}

func (s *protobufSerializer) Deserialize(data []byte) (v interface{}, err error) {
	if !s.registered {
		log4g.Panic("not registered any id")
	}
	id := int(util.GetIntHeader(data, NetConfig.MessageIdSize, NetConfig.LittleEndian))
	if t, ok := s.id_type_map[id]; ok {
		value := reflect.New(t.Elem()).Interface()
		err = proto.UnmarshalMerge(data[NetConfig.MessageIdSize:], value.(proto.Message))
		if err != nil {
			log4g.Error(err)
		} else {
			v = value
			if log4g.IsDebugEnabled() {
				bytes, _ := json.Marshal(v)
				log4g.Debug("deserialize %v - %v", t, string(bytes))
			}
		}
	} else {
		err = errors.New(fmt.Sprintf("id[%d] is not registered by any type", id))
		log4g.Error(err)
	}
	return
}

func NewProtobufSerializer() Serializer {
	s := new(protobufSerializer)
	s.emptySerializer = newEmptySerializer()
	return s
}
<commit_msg>add serialize validation<commit_after>package net4g

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/carsonsx/log4g"
	"github.com/carsonsx/net4g/util"
	"github.com/golang/protobuf/proto"
	"reflect"
)

type Serializer interface {
	SetIdStartingValue(id int)
	RegisterById(t reflect.Type, id_at_most_one ...int) (id int, err error)
	RegisterByKey(t reflect.Type, key_at_most_one ...string) (key string, err error)
	Serialize(v interface{}) (data []byte, err error)
	Deserialize(data []byte) (v interface{}, err error)
	RangeId(f func(id int, t reflect.Type))
	RangeKey(f func(key string, t reflect.Type))
}

type emptySerializer struct {
	type_id_map  map[reflect.Type]int
	type_key_map map[reflect.Type]string
	id_type_map  map[int]reflect.Type
	key_type_map map[string]reflect.Type
	ids []int
	keys []string
	id           int
	registered   bool
	byId         bool
}

func (s *emptySerializer) SetIdStartingValue(id int) {
	s.id = id
}

func (s *emptySerializer) RegisterById(t reflect.Type, id_at_most_one ...int) (id int, err error) {

	if t == nil || t.Kind() != reflect.Ptr {
		panic("type must be a pointer")
	}

	if len(s.type_key_map) > 0 {
		panic("can not registered id and key in one serializer")
	}

	if len(id_at_most_one) > 1 {
		panic("only mapping one type with one id")
	}

	if _id, ok := s.type_id_map[t]; ok {
		text := fmt.Sprintf("%s has been registered by %d", t.String(), _id)
		log4g.Error(text)
		return 0, errors.New(text)
	}

	if len(id_at_most_one) == 1 {
		id = id_at_most_one[0]
	} else {
		id = s.id
	}

	s.type_id_map[t] = id
	s.id_type_map[id] = t
	s.ids = append(s.ids, id)

	s.byId = true
	s.registered = true

	s.id++

	return
}

func (s *emptySerializer) RegisterByKey(t reflect.Type, key_at_most_one ...string) (key string, err error) {

	if t == nil || t.Kind() != reflect.Ptr {
		panic("type must be a pointer")
	}

	if len(s.type_id_map) > 0 {
		panic("can not registered key and id in one serializer")
	}

	if len(key_at_most_one) > 1 {
		panic("only mapping one type with one key")
	}

	if _key, ok := s.type_key_map[t]; ok {
		text := fmt.Sprintf("%s has been registered by %s", t.Elem().Name(), _key)
		log4g.Error(text)
		err = errors.New(text)
		return
	}

	if len(key_at_most_one) == 1 {
		key = key_at_most_one[0]
	} else {
		key = t.String()
	}

	s.type_key_map[t] = key
	s.key_type_map[key] = t
	s.keys = append(s.keys, key)

	s.byId = false
	s.registered = true

	log4g.Info("%v register by key '%s'\n", t, key)

	return
}

func (s *emptySerializer) Serialize(v interface{}) (data []byte, err error) {
	return v.([]byte), nil
}

func (s *emptySerializer) Deserialize(data []byte) (v interface{}, err error) {
	return data, nil
}

func (s *emptySerializer) RangeId(f func(id int, t reflect.Type)) {
	for _, id := range s.ids {
		f(id, s.id_type_map[id])
	}
}

func (s *emptySerializer) RangeKey(f func(key string, t reflect.Type)) {
	for _, key := range s.keys {
		f(key, s.key_type_map[key])
	}
}

func NewEmptySerializer() Serializer {
	return newEmptySerializer()
}

func newEmptySerializer() *emptySerializer {
	s := new(emptySerializer)
	s.type_id_map = make(map[reflect.Type]int)
	s.id_type_map = make(map[int]reflect.Type)
	s.type_key_map = make(map[reflect.Type]string)
	s.key_type_map = make(map[string]reflect.Type)
	s.id = 1
	return s
}

type stringSerializer struct {
	Serializer
}

func (s *stringSerializer) Serialize(v interface{}) (data []byte, err error) {
	return []byte(v.(string)), nil
}

func (s *stringSerializer) Deserialize(data []byte) (v interface{}, err error) {
	return string(data), nil
}

func NewStringSerializer() Serializer {
	s := new(stringSerializer)
	s.Serializer = newEmptySerializer()
	return s
}

type jsonSerializer struct {
	*emptySerializer
}

func (s *jsonSerializer) Serialize(v interface{}) (data []byte, err error) {

	if !s.registered {
		panic("not registered any id or key")
	}

	t := reflect.TypeOf(v)
	if t == nil || t.Kind() != reflect.Ptr {
		panic("value type must be a pointer")
	}

	if s.byId {
		if id, ok := s.type_id_map[t]; ok {
			data, err = json.Marshal(v)
			if err != nil {
				log4g.Error(err)
				return
			}
			data = util.AddIntHeader(data, NetConfig.MessageIdSize, uint64(id), NetConfig.LittleEndian)
			if log4g.IsTraceEnabled() {
				log4g.Trace("serialized %v - %s", t, string(data))
			}
		} else {
			err = errors.New(fmt.Sprintf("%v is not registed by any id", t))
			log4g.Error(err)
		}
	} else {
		if key, ok := s.type_key_map[t]; ok {
			m := map[string]interface{}{key: v}
			data, err = json.Marshal(m)
			if err != nil {
				log4g.Error(err)
				return
			}
			if log4g.IsTraceEnabled() {
				log4g.Trace("serialized %v - %s", t, string(data))
			}
		} else {
			log4g.Panic("%v is not registered by any key", t)
		}
	}

	return
}

func (s *jsonSerializer) Deserialize(data []byte) (v interface{}, err error) {

	if !s.registered {
		panic("not registered any id or key")
	}

	if s.byId {
		id := int(util.GetIntHeader(data, NetConfig.MessageIdSize, NetConfig.LittleEndian))
		if t, ok := s.id_type_map[id]; ok {
			value := reflect.New(t.Elem()).Interface()
			err = json.Unmarshal(data[NetConfig.MessageIdSize:], value)
			if err != nil {
				log4g.Error(err)
			} else {
				v = value
				log4g.Trace("rcvd %v - %s", t, string(data))
			}
		} else {
			err = errors.New(fmt.Sprintf("id[%d] is not registered by any type", id))
			log4g.Error(err)
		}
	} else {
		var m_raw map[string]json.RawMessage
		err = json.Unmarshal(data, &m_raw)
		if err != nil {
			log4g.Error(err)
			return nil, err
		}
		if len(m_raw) == 0 {
			text := fmt.Sprintf("invalid json: %v", string(data))
			log4g.Error(text)
			err = errors.New(text)
			return
		}
		for key, raw := range m_raw {
			if t, ok := s.key_type_map[key]; ok {
				value := reflect.New(t.Elem()).Interface()
				err = json.Unmarshal(raw, value)
				if err != nil {
					log4g.Error(err)
				} else {
					v = value
					log4g.Trace("rcvd %v - %s", t, string(raw))
				}
			} else {
				err = errors.New(fmt.Sprintf("key '%s' is not registered by any type", key))
				log4g.Error(err)
			}
		}
	}
	return
}

func NewJsonSerializer() Serializer {
	s := new(jsonSerializer)
	s.emptySerializer = newEmptySerializer()
	return s
}

type protobufSerializer struct {
	*emptySerializer
}

func (s *protobufSerializer) Serialize(v interface{}) (data []byte, err error) {

	if !s.registered {
		log4g.Panic("not registered any id")
	}

	t := reflect.TypeOf(v)
	if t == nil || t.Kind() != reflect.Ptr {
		panic("value type must be a pointer")
	}

	if id, ok := s.type_id_map[t]; ok {
		data, err = proto.Marshal(v.(proto.Message))
		if err != nil {
			log4g.Error(err)
			return
		}
		data = util.AddIntHeader(data, NetConfig.MessageIdSize, uint64(id), NetConfig.LittleEndian)
		if log4g.IsDebugEnabled() {
			bytes, _ := json.Marshal(v)
			log4g.Debug("serialize %v - %v", t, string(bytes))
		}
	} else {
		err = errors.New(fmt.Sprintf("%v is not registed by any id", t))
	}
	return
}

func (s *protobufSerializer) Deserialize(data []byte) (v interface{}, err error) {
	if !s.registered {
		log4g.Panic("not registered any id")
	}
	id := int(util.GetIntHeader(data, NetConfig.MessageIdSize, NetConfig.LittleEndian))
	if t, ok := s.id_type_map[id]; ok {
		value := reflect.New(t.Elem()).Interface()
		err = proto.UnmarshalMerge(data[NetConfig.MessageIdSize:], value.(proto.Message))
		if err != nil {
			log4g.Error(err)
		} else {
			v = value
			if log4g.IsDebugEnabled() {
				bytes, _ := json.Marshal(v)
				log4g.Debug("deserialize %v - %v", t, string(bytes))
			}
		}
	} else {
		err = errors.New(fmt.Sprintf("id[%d] is not registered by any type", id))
		log4g.Error(err)
	}
	return
}

func NewProtobufSerializer() Serializer {
	s := new(protobufSerializer)
	s.emptySerializer = newEmptySerializer()
	return s
}
<|endoftext|>


<commit_before>// Copyright 2015 Garrett D'Amore
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 main

import (
	"time"

	"github.com/gdamore/tcell"
)

type ship struct {
	ship     *Sprite
	xthrust  *Sprite
	ythrust  *Sprite
	level    *Level
	lastx    int
	lasty    int
	ximpulse float64
	yimpulse float64
	bspeed   float64
	lastgrav time.Time
	launched bool
	dead     bool
}

func (o *ship) shoot() {
	// TBD: shot limiter
	x1, y, x2, _ := o.ship.Bounds()
	_, vy := o.ship.Velocity()
	props := GameObjectProps{}
	props.PropSetInt("x", x1+(x2-x1)/2)
	props.PropSetInt("y", y-1)
	props.PropSetFloat64("vy", vy-o.bspeed)
	props.PropSetInt("delay", 10)
	MakeGameObject(o.level, "bullet", props)
}

func (o *ship) thrustUp() {
	vx, vy := o.ship.Velocity()
	vy -= o.yimpulse
	o.ship.SetVelocity(vx, vy)
	o.ythrust.SetFrame("UP")
	if !o.launched {
		if sprite := GetSprite("Exhaust"); sprite != nil {
			x, y := o.ship.Position()
			sprite.SetFrame("LIFTOFF")
			sprite.SetPosition(x, y)
			sprite.SetLayer(LayerThrust)
			o.level.AddSprite(sprite)
		}
		o.launched = true
	}
}

func (o *ship) thrustLeft() {
	vx, vy := o.ship.Velocity()
	vx -= o.ximpulse
	o.ship.SetVelocity(vx, vy)
	o.xthrust.SetFrame("LEFT")
}

func (o *ship) thrustRight() {
	vx, vy := o.ship.Velocity()
	vx += o.ximpulse
	o.ship.SetVelocity(vx, vy)
	o.xthrust.SetFrame("RIGHT")
}

func (o *ship) thrustDown() {
	vx, vy := o.ship.Velocity()
	vy += o.yimpulse
	o.ship.SetVelocity(vx, vy)
	o.ythrust.SetFrame("DOWN")
}

func (o *ship) destroy() {
	o.dead = true
	o.ship.Hide()

	x, y, _, _ := o.ship.Bounds()
	props := GameObjectProps{}
	props.PropSetInt("x", x)
	props.PropSetInt("y", y)
	props.PropSetInt("count", 3)
	MakeGameObject(o.level, "explosion", props)
	props = GameObjectProps{}
	props.PropSetInt("x", x)
	props.PropSetInt("y", y)
	props.PropSetInt("count", 3)
	MakeGameObject(o.level, "smexplosion", props)
	o.level.RemoveSprite(o.ship)
	o.level.HandleEvent(&EventPlayerDeath{})
}

func (o *ship) adjustView() {
	x1, y1, x2, y2 := o.ship.Bounds()
	o.level.MakeVisible(x2+20, y2+8)
	o.level.MakeVisible(x1-20, y1-12)
	if o.ythrust != nil {
		o.ythrust.SetPosition(x1+(x2-x1)/2, y1)
	}
	if o.xthrust != nil {
		o.xthrust.SetPosition(x1+(x2-x1)/2, y1)
	}
}

func (o *ship) HandleEvent(ev tcell.Event) bool {
	if o.dead {
		return false
	}
	switch ev := ev.(type) {
	case *EventSpriteAccelerate:
		if ev.s != o.ship {
			return false
		}
		vx, _ := o.ship.Velocity()
		if vx >= 1.0 {
			o.ship.SetFrame("RIGHT")
		} else if vx <= -1.0 {
			o.ship.SetFrame("LEFT")
		} else {
			o.ship.SetFrame("FWD")
		}
	case *EventSpriteMove:
		// We don't let ship leave the map
		x, y := o.ship.Position()
		ox, oy := x, y
		vx, vy := o.ship.Velocity()
		w, h := o.level.Size()
		if x < 0 {
			x = 0
			if vx < 0 {
				vx = 0
			}
		} else if x >= w {
			x = w - 1
			if vx > 0 {
				vx = 0
			}
		}
		if y < 0 {
			y = 0
			if vy < 0 {
				vy = 0
			}
		} else if y >= h {
			y = h - 1
			if vy > 0 {
				vy = 0
			}
		}
		if ox != x || oy != y {
			o.ship.SetPosition(x, y)
			o.ship.SetVelocity(vx, vy)
		}

		if y == 0 {
			o.dead = true
			o.level.HandleEvent(&EventLevelComplete{})
		}
		o.adjustView()
	case *EventGravity:
		now := ev.When()
		if !o.lastgrav.IsZero() {
			vx, vy := o.ship.Velocity()
			frac := float64(now.Sub(o.lastgrav))
			frac /= float64(time.Second)
			vy += ev.Accel() * frac
			o.ship.SetVelocity(vx, vy)
		}
		o.lastgrav = now

	case *EventCollision:
		switch ev.Collider().Layer() {
		case LayerTerrain, LayerHazard, LayerShot:
			o.destroy()
		case LayerPad:
			// if we're on the pad, and not too
			// fast, then stay on the pad.
			// TODO: probably the max velocity (4.0)
			// should be tunable.
			vx, vy := o.ship.Velocity()
			x, y := o.ship.Position()
			if vx == 0 && vy > 0 && vy < 4.0 {
				y--
				vy = 0
				o.ship.SetPosition(x, y)
				o.ship.SetVelocity(vx, vy)
				o.launched = false
			} else {
				o.destroy()
			}
		}

	case *EventTimesUp:
		o.destroy()

	case *tcell.EventKey:
		switch ev.Key() {
		case tcell.KeySpace:
			o.shoot()
			return true

		case tcell.KeyLeft:
			o.thrustLeft()
			return true

		case tcell.KeyRight:
			o.thrustRight()
			return true

		case tcell.KeyUp:
			o.thrustUp()
			return true

		case tcell.KeyDown:
			o.thrustDown()
			return true

		case tcell.KeyRune:
			switch ev.Rune() {
			case 'j', 'J':
				o.thrustLeft()
				return true
			case 'k', 'K':
				o.thrustRight()
				return true
			case 'i', 'I':
				o.thrustUp()
				return true
			case 'm', 'M':
				o.thrustDown()
				return true
			}
		}
	case *tcell.EventResize:
		x, y := o.ship.Position()
		o.level.Center(x, y)
		o.adjustView()
	}
	return false
}

func makeShip(level *Level, props GameObjectProps) error {

	x := props.PropInt("x", 0)
	y := props.PropInt("y", 0)
	velx := props.PropFloat64("vx", 0)
	vely := props.PropFloat64("vy", 0)
	frame := props.PropString("frame", "FWD")
	sname := props.PropString("sprite", "Ship")
	xthrust := props.PropString("xthrust", "Thrust")
	ythrust := props.PropString("ythrust", "Thrust")

	sprite := GetSprite(sname)
	o := &ship{ship: sprite, level: level}

	// How much impulse does each engine fire give us?
	o.yimpulse = props.PropFloat64("yimpulse", 3.5)
	o.ximpulse = props.PropFloat64("ximpulse", 4.5)
	o.bspeed = props.PropFloat64("vshot", 20.0)

	sprite.SetLayer(LayerPlayer)
	sprite.Watch(o)
	sprite.SetFrame(frame)
	sprite.SetPosition(x, y)
	sprite.SetVelocity(velx, vely)
	level.AddSprite(sprite)

	o.xthrust = GetSprite(xthrust)
	o.ythrust = GetSprite(ythrust)
	level.AddSprite(o.xthrust)
	level.AddSprite(o.ythrust)
	o.xthrust.SetLayer(LayerThrust)
	o.ythrust.SetLayer(LayerThrust)
	o.level.Center(x, y)
	o.adjustView()

	return nil
}

func init() {
	RegisterGameObjectMaker("ship", makeShip)
}
<commit_msg>fixes #28 tcell.KeySpace no longer working<commit_after>// Copyright 2016 Garrett D'Amore
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 main

import (
	"time"

	"github.com/gdamore/tcell"
)

type ship struct {
	ship     *Sprite
	xthrust  *Sprite
	ythrust  *Sprite
	level    *Level
	lastx    int
	lasty    int
	ximpulse float64
	yimpulse float64
	bspeed   float64
	lastgrav time.Time
	launched bool
	dead     bool
}

func (o *ship) shoot() {
	// TBD: shot limiter
	x1, y, x2, _ := o.ship.Bounds()
	_, vy := o.ship.Velocity()
	props := GameObjectProps{}
	props.PropSetInt("x", x1+(x2-x1)/2)
	props.PropSetInt("y", y-1)
	props.PropSetFloat64("vy", vy-o.bspeed)
	props.PropSetInt("delay", 10)
	MakeGameObject(o.level, "bullet", props)
}

func (o *ship) thrustUp() {
	vx, vy := o.ship.Velocity()
	vy -= o.yimpulse
	o.ship.SetVelocity(vx, vy)
	o.ythrust.SetFrame("UP")
	if !o.launched {
		if sprite := GetSprite("Exhaust"); sprite != nil {
			x, y := o.ship.Position()
			sprite.SetFrame("LIFTOFF")
			sprite.SetPosition(x, y)
			sprite.SetLayer(LayerThrust)
			o.level.AddSprite(sprite)
		}
		o.launched = true
	}
}

func (o *ship) thrustLeft() {
	vx, vy := o.ship.Velocity()
	vx -= o.ximpulse
	o.ship.SetVelocity(vx, vy)
	o.xthrust.SetFrame("LEFT")
}

func (o *ship) thrustRight() {
	vx, vy := o.ship.Velocity()
	vx += o.ximpulse
	o.ship.SetVelocity(vx, vy)
	o.xthrust.SetFrame("RIGHT")
}

func (o *ship) thrustDown() {
	vx, vy := o.ship.Velocity()
	vy += o.yimpulse
	o.ship.SetVelocity(vx, vy)
	o.ythrust.SetFrame("DOWN")
}

func (o *ship) destroy() {
	o.dead = true
	o.ship.Hide()

	x, y, _, _ := o.ship.Bounds()
	props := GameObjectProps{}
	props.PropSetInt("x", x)
	props.PropSetInt("y", y)
	props.PropSetInt("count", 3)
	MakeGameObject(o.level, "explosion", props)
	props = GameObjectProps{}
	props.PropSetInt("x", x)
	props.PropSetInt("y", y)
	props.PropSetInt("count", 3)
	MakeGameObject(o.level, "smexplosion", props)
	o.level.RemoveSprite(o.ship)
	o.level.HandleEvent(&EventPlayerDeath{})
}

func (o *ship) adjustView() {
	x1, y1, x2, y2 := o.ship.Bounds()
	o.level.MakeVisible(x2+20, y2+8)
	o.level.MakeVisible(x1-20, y1-12)
	if o.ythrust != nil {
		o.ythrust.SetPosition(x1+(x2-x1)/2, y1)
	}
	if o.xthrust != nil {
		o.xthrust.SetPosition(x1+(x2-x1)/2, y1)
	}
}

func (o *ship) HandleEvent(ev tcell.Event) bool {
	if o.dead {
		return false
	}
	switch ev := ev.(type) {
	case *EventSpriteAccelerate:
		if ev.s != o.ship {
			return false
		}
		vx, _ := o.ship.Velocity()
		if vx >= 1.0 {
			o.ship.SetFrame("RIGHT")
		} else if vx <= -1.0 {
			o.ship.SetFrame("LEFT")
		} else {
			o.ship.SetFrame("FWD")
		}
	case *EventSpriteMove:
		// We don't let ship leave the map
		x, y := o.ship.Position()
		ox, oy := x, y
		vx, vy := o.ship.Velocity()
		w, h := o.level.Size()
		if x < 0 {
			x = 0
			if vx < 0 {
				vx = 0
			}
		} else if x >= w {
			x = w - 1
			if vx > 0 {
				vx = 0
			}
		}
		if y < 0 {
			y = 0
			if vy < 0 {
				vy = 0
			}
		} else if y >= h {
			y = h - 1
			if vy > 0 {
				vy = 0
			}
		}
		if ox != x || oy != y {
			o.ship.SetPosition(x, y)
			o.ship.SetVelocity(vx, vy)
		}

		if y == 0 {
			o.dead = true
			o.level.HandleEvent(&EventLevelComplete{})
		}
		o.adjustView()
	case *EventGravity:
		now := ev.When()
		if !o.lastgrav.IsZero() {
			vx, vy := o.ship.Velocity()
			frac := float64(now.Sub(o.lastgrav))
			frac /= float64(time.Second)
			vy += ev.Accel() * frac
			o.ship.SetVelocity(vx, vy)
		}
		o.lastgrav = now

	case *EventCollision:
		switch ev.Collider().Layer() {
		case LayerTerrain, LayerHazard, LayerShot:
			o.destroy()
		case LayerPad:
			// if we're on the pad, and not too
			// fast, then stay on the pad.
			// TODO: probably the max velocity (4.0)
			// should be tunable.
			vx, vy := o.ship.Velocity()
			x, y := o.ship.Position()
			if vx == 0 && vy > 0 && vy < 4.0 {
				y--
				vy = 0
				o.ship.SetPosition(x, y)
				o.ship.SetVelocity(vx, vy)
				o.launched = false
			} else {
				o.destroy()
			}
		}

	case *EventTimesUp:
		o.destroy()

	case *tcell.EventKey:
		switch ev.Key() {

		case tcell.KeyLeft:
			o.thrustLeft()
			return true

		case tcell.KeyRight:
			o.thrustRight()
			return true

		case tcell.KeyUp:
			o.thrustUp()
			return true

		case tcell.KeyDown:
			o.thrustDown()
			return true

		case tcell.KeyRune:
			switch ev.Rune() {
			case ' ':
				o.shoot()
				return true
			case 'j', 'J':
				o.thrustLeft()
				return true
			case 'k', 'K':
				o.thrustRight()
				return true
			case 'i', 'I':
				o.thrustUp()
				return true
			case 'm', 'M':
				o.thrustDown()
				return true
			}
		}
	case *tcell.EventResize:
		x, y := o.ship.Position()
		o.level.Center(x, y)
		o.adjustView()
	}
	return false
}

func makeShip(level *Level, props GameObjectProps) error {

	x := props.PropInt("x", 0)
	y := props.PropInt("y", 0)
	velx := props.PropFloat64("vx", 0)
	vely := props.PropFloat64("vy", 0)
	frame := props.PropString("frame", "FWD")
	sname := props.PropString("sprite", "Ship")
	xthrust := props.PropString("xthrust", "Thrust")
	ythrust := props.PropString("ythrust", "Thrust")

	sprite := GetSprite(sname)
	o := &ship{ship: sprite, level: level}

	// How much impulse does each engine fire give us?
	o.yimpulse = props.PropFloat64("yimpulse", 3.5)
	o.ximpulse = props.PropFloat64("ximpulse", 4.5)
	o.bspeed = props.PropFloat64("vshot", 20.0)

	sprite.SetLayer(LayerPlayer)
	sprite.Watch(o)
	sprite.SetFrame(frame)
	sprite.SetPosition(x, y)
	sprite.SetVelocity(velx, vely)
	level.AddSprite(sprite)

	o.xthrust = GetSprite(xthrust)
	o.ythrust = GetSprite(ythrust)
	level.AddSprite(o.xthrust)
	level.AddSprite(o.ythrust)
	o.xthrust.SetLayer(LayerThrust)
	o.ythrust.SetLayer(LayerThrust)
	o.level.Center(x, y)
	o.adjustView()

	return nil
}

func init() {
	RegisterGameObjectMaker("ship", makeShip)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"sync"

	"github.com/gorilla/mux"
	"github.com/thejerf/suture"
)

type Block struct {
	q     chan bool
	token suture.ServiceToken
	id    int
}

func (b *Block) Serve() {
	<-b.q
}

func (b *Block) Stop() {
	b.q <- true
}

func IDGen() func() int {
	i := 0
	return func() int {
		i += 1
		return i
	}
}

func NewBlock(id int) *Block {
	q := make(chan bool)
	return &Block{
		q: q,
	}
}

type Server struct {
	blocks     map[int]*Block
	supervisor *suture.Supervisor
	sync.Mutex
}

func NewServer() *Server {
	supervisor := suture.NewSimple("st-core")
	supervisor.ServeBackground()
	blocks := make(map[int]*Block)
	return &Server{
		supervisor: supervisor,
		blocks:     blocks,
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Write([]byte("hi!"))
}

func (s *Server) createBlockHandler(w http.ResponseWriter, r *http.Request) {
	nextID := IDGen()
	b := NewBlock(nextID())

	b.token = s.supervisor.Add(b)

	s.Lock()
	s.blocks[b.id] = b
	s.Unlock()

	w.WriteHeader(200)
	w.Write([]byte("OK"))

}

func (s *Server) deleteBlockHandler(w http.ResponseWriter, r *http.Request) {
	var blockid int
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(body, &blockid)
	if err != nil {
		log.Fatal(err)
	}
	block := s.blocks[blockid]

	s.supervisor.Remove(block.token)
	s.Lock()
	delete(s.blocks, blockid)
	s.Unlock()

	w.WriteHeader(200)
	w.Write([]byte("OK"))

}

func (s *Server) blockInfoHandler(w http.ResponseWriter, r *http.Request) {
	var blockid int
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(body, &blockid)
	if err != nil {
		log.Fatal(err)
	}
	block := s.blocks[blockid]
	w.WriteHeader(200)
	out, err := json.Marshal(block)
	if err != nil {
		log.Fatal(err)
	}
	w.Write(out)
}

func main() {

	s := NewServer()

	r := mux.NewRouter()
	r.StrictSlash(true)
	r.HandleFunc("/", rootHandler)
	r.HandleFunc("/new", s.createSessionHandler).Methods("POST")
	r.HandleFunc("/{session}/blocks", s.createBlockHandler).Methods("POST")
	r.HandleFunc("/{session}blocks/{id}", s.blockInfoHandler).Methods("GET")
	r.HandleFunc("/{session}blocks/{id}", s.deleteBlockHandler).Methods("DELETE")

	http.Handle("/", r)

	log.Println("serving on 7071")

	err := http.ListenAndServe(":7071", nil)
	if err != nil {
		log.Fatalf(err.Error())
	}
}
<commit_msg>end of this thought. Starting the next one<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"sync"

	"github.com/gorilla/mux"
	"github.com/thejerf/suture"
)

type Block struct {
	q     chan bool
	token suture.ServiceToken
	id    int
}

func (b *Block) Serve() {
	<-b.q
}

func (b *Block) Stop() {
	b.q <- true
}

func IDGen() func() int {
	i := 0
	return func() int {
		i += 1
		return i
	}
}

func NewBlock(id int) *Block {
	q := make(chan bool)
	return &Block{
		q: q,
	}
}

type Server struct {
	sessions []Session
}

type Session struct {
	blocks     map[int]*Block
	supervisor *suture.Supervisor
	sync.Mutex
}

func NewSession() Session {
	supervisor := suture.NewSimple("st-core")
	supervisor.ServeBackground()
	blocks := make(map[int]*Block)
	return Session{
		blocks:     blocks,
		supervisor: supervisor,
	}

}

func (s *Server) GetSession(r *http.Request) Session {
	vars := mux.Vars(r)
	sessionIndex, err := strconv.Atoi(vars["session"])
	if err != nil {
		log.Fatal(err)
	}
	return s.sessions[sessionIndex]
}

func NewServer() *Server {
	initialSession := NewSession()
	return &Server{
		sessions: []Session{initialSession},
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Write([]byte("hi!"))
}

func (s *Server) createBlockHandler(w http.ResponseWriter, r *http.Request) {
	nextID := IDGen()
	b := NewBlock(nextID())

	b.token = session.supervisor.Add(b)

	session.Lock()
	session.blocks[b.id] = b
	session.Unlock()

	w.WriteHeader(200)
	w.Write([]byte("OK"))

}

func (s *Server) deleteBlockHandler(w http.ResponseWriter, r *http.Request) {
	var blockid int
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(body, &blockid)
	if err != nil {
		log.Fatal(err)
	}
	block := s.blocks[blockid]

	s.supervisor.Remove(block.token)
	s.Lock()
	delete(s.blocks, blockid)
	s.Unlock()

	w.WriteHeader(200)
	w.Write([]byte("OK"))

}

func (s *Server) blockInfoHandler(w http.ResponseWriter, r *http.Request) {
	var blockid int
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(body, &blockid)
	if err != nil {
		log.Fatal(err)
	}
	block := s.blocks[blockid]
	w.WriteHeader(200)
	out, err := json.Marshal(block)
	if err != nil {
		log.Fatal(err)
	}
	w.Write(out)
}

func main() {

	s := NewServer()

	r := mux.NewRouter()
	r.StrictSlash(true)
	r.HandleFunc("/", rootHandler)
	r.HandleFunc("/new", s.createSessionHandler).Methods("POST")
	r.HandleFunc("/{session}/blocks", s.createBlockHandler).Methods("POST")
	r.HandleFunc("/{session}blocks/{id}", s.blockInfoHandler).Methods("GET")
	r.HandleFunc("/{session}blocks/{id}", s.deleteBlockHandler).Methods("DELETE")

	http.Handle("/", r)

	log.Println("serving on 7071")

	err := http.ListenAndServe(":7071", nil)
	if err != nil {
		log.Fatalf(err.Error())
	}
}
<|endoftext|>