<commit_before>// Package tracer provides an interface to attach execution metadata to a context.
package tracer

import (
	"fmt"
	"net/http"
	"strconv"
	"sync"
	"time"

	"golang.org/x/net/context"
)

type Tracer struct {
	ID                 uint64
	startTime, endTime time.Time
	Duration           time.Duration `json:"-"`
	DurationMicros     int64
	DurationMillis     int64

	mu      sync.Mutex
	Queries int
}

func New(id uint64) *Tracer {
	return &Tracer{
		ID:        id,
		startTime: time.Now(),
	}
}

func FromRequest(r *http.Request) (*Tracer, error) {
	tID := r.Header.Get("X-Trace-ID")
	if tID == "" {
		return nil, fmt.Errorf("tracer: missing X-Trace-ID header")
	}
	traceId, err := strconv.ParseUint(tID, 10, 0)
	if err != nil {
		return nil, err
	}
	return New(traceId), nil
}

func (t *Tracer) IncQueries(n int) int {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.Queries += n
	return t.Queries
}

func (t *Tracer) Done() {
	t.endTime = time.Now()
	t.Duration = t.endTime.Sub(t.startTime)
	t.DurationMicros = t.Duration.Nanoseconds() / 1000
	t.DurationMillis = t.Duration.Nanoseconds() / 1000000
}

// The key type is unexported to prevent collisions with context keys defined in
// other packages.
type key int

// tracerKey is the context key for the tracers attached to a context.
const tracerKey = 0

// NewContext returns a new Context carrying tracer.
func NewContext(ctx context.Context, t *Tracer) context.Context {
	return context.WithValue(ctx, tracerKey, t)
}

// FromContext extracts the tracer from ctx, if present.
func FromContext(ctx context.Context) (*Tracer, bool) {
	// ctx.Value returns nil if ctx has no value for the key;
	// the net.IP type assertion returns ok=false for nil.
	t, ok := ctx.Value(tracerKey).(*Tracer)
	return t, ok
}
<commit_msg>Add flexible tracing field<commit_after>// Package tracer provides an interface to attach execution metadata to a context.
package tracer

import (
	"fmt"
	"net/http"
	"strconv"
	"sync"
	"time"

	"golang.org/x/net/context"
)

type Tracer struct {
	ID                 uint64
	startTime, endTime time.Time
	Duration           time.Duration `json:"-"`
	DurationMicros     int64
	DurationMillis     int64
	Extra              map[string]interface{} `json:",omitempty"`

	mu      sync.Mutex
	Queries int
}

func New(id uint64) *Tracer {
	return &Tracer{
		ID:        id,
		startTime: time.Now(),
	}
}

func FromRequest(r *http.Request) (*Tracer, error) {
	tID := r.Header.Get("X-Trace-ID")
	if tID == "" {
		return nil, fmt.Errorf("tracer: missing X-Trace-ID header")
	}
	traceId, err := strconv.ParseUint(tID, 10, 0)
	if err != nil {
		return nil, err
	}
	return New(traceId), nil
}

func (t *Tracer) IncQueries(n int) int {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.Queries += n
	return t.Queries
}

func (t *Tracer) WithLock(fn func(*Tracer)) {
	t.mu.Lock()
	defer t.mu.Unlock()
	fn(t)
}

func (t *Tracer) Done() {
	t.endTime = time.Now()
	t.Duration = t.endTime.Sub(t.startTime)
	t.DurationMicros = t.Duration.Nanoseconds() / 1000
	t.DurationMillis = t.Duration.Nanoseconds() / 1000000
}

// The key type is unexported to prevent collisions with context keys defined in
// other packages.
type key int

// tracerKey is the context key for the tracers attached to a context.
const tracerKey = 0

// NewContext returns a new Context carrying tracer.
func NewContext(ctx context.Context, t *Tracer) context.Context {
	return context.WithValue(ctx, tracerKey, t)
}

// FromContext extracts the tracer from ctx, if present.
func FromContext(ctx context.Context) (*Tracer, bool) {
	// ctx.Value returns nil if ctx has no value for the key;
	// the net.IP type assertion returns ok=false for nil.
	t, ok := ctx.Value(tracerKey).(*Tracer)
	return t, ok
}
<|endoftext|>


<commit_before>package zwave

import "github.com/bjyoungblood/gozw/zwave/commandclass"

type Node struct {
	NodeId byte

	Capability          byte
	Security            byte
	BasicDeviceClass    byte
	GenericDeviceClass  byte
	SpecificDeviceClass byte

	SupportedCommandClasses []byte

	manager *Manager
}

func NewNode(manager *Manager, nodeId byte) *Node {
	return &Node{
		NodeId:  nodeId,
		manager: manager,
	}
}

func (n *Node) IsSecure() bool {
	for _, cc := range n.SupportedCommandClasses {
		if cc == commandclass.CommandClassSecurity {
			return true
		}
	}

	return false
}

func (n *Node) IsListening() bool {
	return n.Capability&0x80 == 0x80
}

func (n *Node) HasOptionalFunctions() bool {
	return n.Security&0x80 == 0x80
}

func (n *Node) GetBasicDeviceClassName() string {
	return GetBasicTypeName(n.BasicDeviceClass)
}

func (n *Node) GetGenericDeviceClassName() string {
	return GetGenericTypeName(n.GenericDeviceClass)
}

func (n *Node) GetSpecificDeviceClassName() string {
	return GetSpecificTypeName(n.GenericDeviceClass, n.SpecificDeviceClass)
}
<commit_msg>node set data and to string functions<commit_after>package zwave

import (
	"fmt"

	"github.com/bjyoungblood/gozw/zwave/commandclass"
)

type Node struct {
	NodeId byte

	Capability          byte
	Security            byte
	BasicDeviceClass    byte
	GenericDeviceClass  byte
	SpecificDeviceClass byte

	SupportedCommandClasses []byte

	manager *Manager
}

func NewNode(manager *Manager, nodeId byte) *Node {
	return &Node{
		NodeId: nodeId,

		SupportedCommandClasses: []byte{},

		manager: manager,
	}
}

func (n *Node) IsSecure() bool {
	for _, cc := range n.SupportedCommandClasses {
		if cc == commandclass.CommandClassSecurity {
			return true
		}
	}

	return false
}

func (n *Node) IsListening() bool {
	return n.Capability&0x80 == 0x80
}

func (n *Node) HasOptionalFunctions() bool {
	return n.Security&0x80 == 0x80
}

func (n *Node) GetBasicDeviceClassName() string {
	return GetBasicTypeName(n.BasicDeviceClass)
}

func (n *Node) GetGenericDeviceClassName() string {
	return GetGenericTypeName(n.GenericDeviceClass)
}

func (n *Node) GetSpecificDeviceClassName() string {
	return GetSpecificTypeName(n.GenericDeviceClass, n.SpecificDeviceClass)
}

func (n *Node) setFromAddNodeCallback(nodeInfo *AddRemoveNodeCallback) {
	n.NodeId = nodeInfo.Source
	n.BasicDeviceClass = nodeInfo.Basic
	n.GenericDeviceClass = nodeInfo.Generic
	n.SpecificDeviceClass = nodeInfo.Specific
	n.SupportedCommandClasses = nodeInfo.CommandClasses
}

func (n *Node) setFromNodeProtocolInfo(nodeInfo *NodeProtocolInfoResponse) {
	n.Capability = nodeInfo.Capability
	n.Security = nodeInfo.Security
	n.BasicDeviceClass = nodeInfo.BasicDeviceClass
	n.GenericDeviceClass = nodeInfo.GenericDeviceClass
	n.SpecificDeviceClass = nodeInfo.SpecificDeviceClass
}

func (n *Node) String() string {
	str := fmt.Sprintf("Node %d: \n", n.NodeId)
	str += fmt.Sprintf("  Is listening? %t\n", n.IsListening())
	str += fmt.Sprintf("  Basic device class: %s\n", n.GetBasicDeviceClassName())
	str += fmt.Sprintf("  Generic device class: %s\n", n.GetGenericDeviceClassName())
	str += fmt.Sprintf("  Specific device class: %s\n", n.GetSpecificDeviceClassName())
	str += fmt.Sprintf("  Supported command classes:\n")
	for _, cc := range n.GetSupportedCommandClassStrings() {
		str += fmt.Sprintf("    - %s\n", cc)
	}
	return str
}

func (n *Node) GetSupportedCommandClassStrings() []string {
	if len(n.SupportedCommandClasses) == 0 {
		return []string{
			"None (probably not loaded; need to request a NIF)",
		}
	}

	ccStrings := make([]string, len(n.SupportedCommandClasses))

	for i, cc := range n.SupportedCommandClasses {
		ccStrings[i] = commandclass.GetCommandClassString(cc)
	}

	return ccStrings
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"time"
	"log"
	"github.com/cactus/go-statsd-client/statsd"
)

func main() {

	address := flag.String("address", "127.0.0.1:8125", "Address:port of statsd")
	prefix := flag.String("prefix", "test-client", "Statsd prefix")
	name := flag.String("name", "counter", "stat name")
	rate := flag.Float64("rate", 1.0, "Sample rate")
	statType := flag.String("type", "count", "Stat type to send. Can be timing, count, guage")
	statValue := flag.Int64("value", 1, "Value to send")
	volume := flag.Int("volume", 1000, "Number of stats to send")
	duration := flag.Duration("duration", 10*time.Second, "How long to spread the volume across. Each second of duration volume/seconds events will be sent.")
	flag.Parse()

	client, err := statsd.Dial(*address, *prefix)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	var stat func(stat string, value int64, rate float32) error
	switch *statType {
	case "count":
		stat = func(stat string, value int64, rate float32) error {
			return client.Inc(stat, value, rate)
		}
	case "guage":
		stat = func(stat string, value int64, rate float32) error {
			return client.Guage(stat, value, rate)
		}
	case "timing":
		stat = func(stat string, value int64, rate float32) error {
			return client.Timing(stat, value, rate)
		}
	default:
		log.Fatal("Unsupported state type")
	}

	pertick := *volume / int(duration.Seconds())
	// add an extra second, because the first tick takes a while
	ender := time.After(*duration + 100 * time.Millisecond)
	c := time.Tick(time.Second)
	count := 0
	for {
		select {
		case <-c:
			for x := 0; x < pertick; x++ {
				err := stat(*name, *statValue, float32(*rate))
				if err != nil {
					log.Printf("Got Error: %+v", err)
					break
				}
				count += 1
			}
		case <-ender:
			log.Printf("%d events called", count)
			return
		}
	}
}
<commit_msg>space the ticks out a bit<commit_after>package main

import (
	"flag"
	"time"
	"log"
	"github.com/cactus/go-statsd-client/statsd"
)

func main() {

	address := flag.String("address", "127.0.0.1:8125", "Address:port of statsd")
	prefix := flag.String("prefix", "test-client", "Statsd prefix")
	name := flag.String("name", "counter", "stat name")
	rate := flag.Float64("rate", 1.0, "Sample rate")
	statType := flag.String("type", "count", "Stat type to send. Can be timing, count, guage")
	statValue := flag.Int64("value", 1, "Value to send")
	volume := flag.Int("volume", 1000, "Number of stats to send")
	duration := flag.Duration("duration", 10*time.Second, "How long to spread the volume across. Each second of duration volume/seconds events will be sent.")
	flag.Parse()

	client, err := statsd.Dial(*address, *prefix)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	var stat func(stat string, value int64, rate float32) error
	switch *statType {
	case "count":
		stat = func(stat string, value int64, rate float32) error {
			return client.Inc(stat, value, rate)
		}
	case "guage":
		stat = func(stat string, value int64, rate float32) error {
			return client.Guage(stat, value, rate)
		}
	case "timing":
		stat = func(stat string, value int64, rate float32) error {
			return client.Timing(stat, value, rate)
		}
	default:
		log.Fatal("Unsupported state type")
	}

	pertick := *volume / int(duration.Seconds()) / 10
	// add some extra tiem, because the first tick takes a while
	ender := time.After(*duration + 100 * time.Millisecond)
	c := time.Tick(time.Second/10)
	count := 0
	for {
		select {
		case <-c:
			for x := 0; x < pertick; x++ {
				err := stat(*name, *statValue, float32(*rate))
				if err != nil {
					log.Printf("Got Error: %+v", err)
					break
				}
				count += 1
			}
		case <-ender:
			log.Printf("%d events called", count)
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package stmts_test

import (
	. "github.com/pingcap/check"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/stmt/stmts"
)

func (s *testStmtSuite) TestReplace(c *C) {
	testSQL := `drop table if exists replace_test;
    create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1);
    replace replace_test (c1) values (1),(2),(NULL);`
	mustExec(c, s.testDB, testSQL)

	errReplaceSelectSQL := `replace replace_test (c1) values ();`
	tx := mustBegin(c, s.testDB)
	_, err := tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSelectSQL = `replace replace_test (c1, c2) values (1,2),(1);`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSelectSQL = `replace replace_test (xxx) values (3);`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSelectSQL = `replace replace_test_xxx (c1) values ();`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	replaceSetSQL := `replace replace_test set c1 = 3;`
	mustExec(c, s.testDB, replaceSetSQL)

	stmtList, err := tidb.Compile(replaceSetSQL)
	c.Assert(err, IsNil)
	c.Assert(stmtList, HasLen, 1)

	testStmt, ok := stmtList[0].(*stmts.ReplaceIntoStmt)
	c.Assert(ok, IsTrue)
	c.Assert(testStmt.IsDDL(), IsFalse)
	c.Assert(len(testStmt.OriginText()), Greater, 0)

	errReplaceSelectSQL = `replace replace_test set c1 = 4, c1 = 5;`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSelectSQL = `replace replace_test set xxx = 6;`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	replaceSelectSQL := `create table replace_test_1 (id int, c1 int); replace replace_test_1 select id, c1 from replace_test;`
	mustExec(c, s.testDB, replaceSelectSQL)

	replaceSelectSQL = `create table replace_test_2 (id int, c1 int);
	replace replace_test_1 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test;`
	mustExec(c, s.testDB, replaceSelectSQL)

	errReplaceSelectSQL = `replace replace_test_1 select c1 from replace_test;`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()
}
<commit_msg>stmt: add replace primary key and unique index test<commit_after>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package stmts_test

import (
	. "github.com/pingcap/check"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/stmt/stmts"
)

func (s *testStmtSuite) TestReplace(c *C) {
	testSQL := `drop table if exists replace_test;
    create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1);
    replace replace_test (c1) values (1),(2),(NULL);`
	mustExec(c, s.testDB, testSQL)

	errReplaceSQL := `replace replace_test (c1) values ();`
	tx := mustBegin(c, s.testDB)
	_, err := tx.Exec(errReplaceSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSQL = `replace replace_test (c1, c2) values (1,2),(1);`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSQL = `replace replace_test (xxx) values (3);`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSQL = `replace replace_test_xxx (c1) values ();`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	replaceSetSQL := `replace replace_test set c1 = 3;`
	mustExec(c, s.testDB, replaceSetSQL)
	stmtList, err := tidb.Compile(replaceSetSQL)
	c.Assert(err, IsNil)
	c.Assert(stmtList, HasLen, 1)

	testStmt, ok := stmtList[0].(*stmts.ReplaceIntoStmt)
	c.Assert(ok, IsTrue)
	c.Assert(testStmt.IsDDL(), IsFalse)
	c.Assert(len(testStmt.OriginText()), Greater, 0)

	errReplaceSetSQL := `replace replace_test set c1 = 4, c1 = 5;`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSetSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	errReplaceSetSQL = `replace replace_test set xxx = 6;`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSetSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	replaceSelectSQL := `create table replace_test_1 (id int, c1 int);
	replace replace_test_1 select id, c1 from replace_test;`
	mustExec(c, s.testDB, replaceSelectSQL)

	replaceSelectSQL = `create table replace_test_2 (id int, c1 int);
	replace replace_test_1 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test;`
	mustExec(c, s.testDB, replaceSelectSQL)

	errReplaceSelectSQL := `replace replace_test_1 select c1 from replace_test;`
	tx = mustBegin(c, s.testDB)
	_, err = tx.Exec(errReplaceSelectSQL)
	c.Assert(err, NotNil)
	tx.Rollback()

	replaceUniqueIndexSQL := `create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2));
	replace into replace_test_3 set c2=1;`
	mustExec(c, s.testDB, replaceUniqueIndexSQL)
	replaceUniqueIndexSQL = `replace into replace_test_3 set c2=1;`
	ret := mustExec(c, s.testDB, replaceUniqueIndexSQL)
	rows, err := ret.RowsAffected()
	c.Assert(err, IsNil)
	c.Assert(rows, Equals, int64(2))

	replaceUniqueIndexSQL = `replace into replace_test_3 set c2=NULL;`
	mustExec(c, s.testDB, replaceUniqueIndexSQL)
	replaceUniqueIndexSQL = `replace into replace_test_3 set c2=NULL;`
	ret = mustExec(c, s.testDB, replaceUniqueIndexSQL)
	rows, err = ret.RowsAffected()
	c.Assert(err, IsNil)
	c.Assert(rows, Equals, int64(1))

	replaceUniqueIndexSQL = `create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2));
	replace into replace_test_4 set c2=NULL;`
	mustExec(c, s.testDB, replaceUniqueIndexSQL)
	replaceUniqueIndexSQL = `replace into replace_test_4 set c2=NULL;`
	ret = mustExec(c, s.testDB, replaceUniqueIndexSQL)
	rows, err = ret.RowsAffected()
	c.Assert(err, IsNil)
	c.Assert(rows, Equals, int64(1))

	replacePrimaryKeySQL := `create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2));
	replace into replace_test_5 set c1=1, c2=2;`
	mustExec(c, s.testDB, replacePrimaryKeySQL)
	replacePrimaryKeySQL = `replace into replace_test_5 set c1=1, c2=2;`
	ret = mustExec(c, s.testDB, replacePrimaryKeySQL)
	rows, err = ret.RowsAffected()
	c.Assert(err, IsNil)
	c.Assert(rows, Equals, int64(2))
}
<|endoftext|>


<commit_before>package main

import (
	"./subtitle"
	"errors"
	"fmt"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/ttf"
	"log"
	"strings"
	"time"
)

const (
	DEFAULT_FONT_PATH = "/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf"
	DEFAULT_FONT_SIZE = 70
)

var (
	BG_COLOR    = sdl.Color{0, 0, 0, 0}
	TEXT_COLOR  = sdl.Color{255, 255, 255, 0}
	waitFinishC = make(chan bool)
)

type sdlCtx struct {
	surface *sdl.Surface
	w, h    int

	currScript *subtitle.Script
	font       *ttf.Font
	lineHeight int

	fontSize int
	fontPath string
}

func NewSdlContext(w, h int) *sdlCtx {
	if sdl.Init(sdl.INIT_EVERYTHING) != 0 {
		log.Fatal("failed to init sdl", sdl.GetError())
		return nil
	}

	if ttf.Init() != 0 {
		log.Fatal("failed to init ttf", sdl.GetError())
		return nil
	}

	var ctx sdlCtx
	if err := ctx.setSurface(w, h); err != nil {
		log.Fatal(err)
	}

	var vInfo = sdl.GetVideoInfo()
	log.Println("HW_available = ", vInfo.HW_available)
	log.Println("WM_available = ", vInfo.WM_available)
	log.Println("Video_mem = ", vInfo.Video_mem, "kb")

	title := "Subtitle Player"
	icon := "" // path/to/icon
	sdl.WM_SetCaption(title, icon)

	sdl.EnableUNICODE(1)

	go func() {
	EVENT_LOOP:
		for {
			err := ctx.handelEvent()
			if err != nil {
				fmt.Println(err)
				break EVENT_LOOP
			}
		}
		log.Println("sdl: exit event loop")
	}()

	return &ctx
}

func (c *sdlCtx) Release() {
	if c.font != nil {
		c.font.Close()
	}
	if c.surface != nil {
		c.surface.Free()
	}
	ttf.Quit()
	sdl.Quit()

	/* log.Printf("sdl Released...") */
}

func (c *sdlCtx) DisplayScript(script *subtitle.Script) {
	c.displayScript(script, true, false)
}

func (c *sdlCtx) Clear() {
	if c.currScript == nil {
		return
	}
	log.Println("clear")
	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	c.surface.Flip()
	c.currScript = nil
}

func (c *sdlCtx) setFont(path string, size int) error {
	if size < 10 {
		log.Println("set font size to minimum, 10")
		size = 10
	}

	c.font = ttf.OpenFont(path, size)
	if c.font == nil {
		errMsg := fmt.Sprintf("failed to open font from %s: %s",
			path, sdl.GetError())
		return errors.New(errMsg)
	}

	c.fontSize = size
	c.fontPath = path
	c.lineHeight = c.font.LineSkip()

	log.Println(c.fontSize, c.lineHeight)
	/* ctx.font.SetStyle(ttf.STYLE_UNDERLINE) */
	return nil
}

func (c *sdlCtx) changeFontSize(by int) {
	if c.font == nil {
		return
	}
	c.setFont(c.fontPath, c.fontSize+by)
	c.displayScript(c.currScript, false, true)
}

func (c *sdlCtx) setSurface(w, h int) error {
	log.Printf("setSurface to %dx%d", w, h)
	c.surface = sdl.SetVideoMode(w, h, 32, sdl.RESIZABLE) /* sdl.FULLSCREEN */
	if c.surface == nil {
		errMsg := fmt.Sprintf("sdl: failed to set video to %dx%d: %s",
			w, h, sdl.GetError())
		return errors.New(errMsg)
	}

	c.w, c.h = w, h
	if c.currScript != nil {
		c.displayScript(c.currScript, false, true)
	}

	return nil
}

func (c *sdlCtx) handelEvent() error {
	// KeySym to time.Duration mapping
	kmVias := map[uint32]time.Duration{
		sdl.K_z:       -100 * time.Microsecond,
		sdl.K_x:       +100 * time.Microsecond,
		sdl.K_LEFT:    -1 * time.Second,
		sdl.K_RIGHT:   +1 * time.Second,
		sdl.K_DOWN:    -10 * time.Second,
		sdl.K_UP:      +10 * time.Second,
		sdl.K_LESS:    -100 * time.Microsecond,
		sdl.K_GREATER: +100 * time.Microsecond,
	}

	kmFontSize := map[uint32]int{
		sdl.K_PLUS:     +5,
		sdl.K_KP_PLUS:  +5,
		sdl.K_MINUS:    -5,
		sdl.K_KP_MINUS: -5,
	}

	select {
	case event := <-sdl.Events:
		/* log.Printf("%#v\n", event) */
		switch e := event.(type) {
		case sdl.QuitEvent:
			return errors.New("sdl: received QuitEvent")
		case sdl.KeyboardEvent:
			// Ignore release key
			if e.State == 0 {
				return nil
			}
			// log.Printf("Sim:%08x, Mod:%04x, Unicode:%02x, %t\n",
			// 	e.Keysym.Sym, e.Keysym.Mod, e.Keysym.Unicode,
			// 	e.Keysym.Unicode)
			if vias, ok := kmVias[e.Keysym.Sym]; ok {
				viasC <- vias
				break
			}
			if vias, ok := kmFontSize[e.Keysym.Sym]; ok {
				c.changeFontSize(vias)
				break
			}
		case sdl.ResizeEvent:
			if err := c.setSurface(int(e.W), int(e.H)); err != nil {
				log.Fatal(err)
			}
		}
	}
	return nil
}

func (c *sdlCtx) displayScript(script *subtitle.Script,
	andClear bool, forceUpdate bool) {
	if forceUpdate == false && c.currScript == script {
		return
	}
	c.currScript = script

	log.Printf("display %s", script.Text)

	if c.font == nil {
		log.Println("set default font")
		err := c.setFont(DEFAULT_FONT_PATH, DEFAULT_FONT_SIZE)
		if err != nil {
			log.Fatal("failed to set default font")
			return
		}
	}

	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	offsetX := 10
	offsetY := 10

	for _, line := range strings.Split(script.Text, "\n") {
		w, _, err := c.font.SizeUTF8(line)
		if err != 0 {
			log.Fatal("Failed to get size of the font")
		}
		offsetX = (c.w - w) / 2

		glypse := ttf.RenderUTF8_Blended(c.font, line, TEXT_COLOR)
		lt := sdl.Rect{int16(offsetX), int16(offsetY), 0, 0}
		c.surface.Blit(&lt, glypse, nil)
		offsetY += c.lineHeight

	}
	c.surface.Flip()

	if andClear == false {
		return
	}

	go func() {
		<-time.After(script.Duration())
		if c.currScript != nil && c.currScript == script {
			c.surface.FillRect(nil, 0 /* BG_COLOR */)
			c.surface.Flip()
		}
	}()
}
<commit_msg>Implemented soft line feed for long line<commit_after>package main

import (
	"./subtitle"
	"errors"
	"fmt"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/ttf"
	"log"
	"sort"
	"strings"
	"time"
)

const (
	DEFAULT_FONT_PATH = "/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf"
	DEFAULT_FONT_SIZE = 70
)

var (
	BG_COLOR    = sdl.Color{0, 0, 0, 0}
	TEXT_COLOR  = sdl.Color{255, 255, 255, 0}
	waitFinishC = make(chan bool)
)

type sdlCtx struct {
	surface *sdl.Surface
	w, h    int

	currScript *subtitle.Script
	font       *ttf.Font
	lineHeight int

	fontSize int
	fontPath string
}

func NewSdlContext(w, h int) *sdlCtx {
	if sdl.Init(sdl.INIT_EVERYTHING) != 0 {
		log.Fatal("failed to init sdl", sdl.GetError())
		return nil
	}

	if ttf.Init() != 0 {
		log.Fatal("failed to init ttf", sdl.GetError())
		return nil
	}

	var ctx sdlCtx
	if err := ctx.setSurface(w, h); err != nil {
		log.Fatal(err)
	}

	var vInfo = sdl.GetVideoInfo()
	log.Println("HW_available = ", vInfo.HW_available)
	log.Println("WM_available = ", vInfo.WM_available)
	log.Println("Video_mem = ", vInfo.Video_mem, "kb")

	title := "Subtitle Player"
	icon := "" // path/to/icon
	sdl.WM_SetCaption(title, icon)

	sdl.EnableUNICODE(1)

	go func() {
	EVENT_LOOP:
		for {
			err := ctx.handelEvent()
			if err != nil {
				fmt.Println(err)
				break EVENT_LOOP
			}
		}
		log.Println("sdl: exit event loop")
	}()

	return &ctx
}

func (c *sdlCtx) Release() {
	if c.font != nil {
		c.font.Close()
	}
	if c.surface != nil {
		c.surface.Free()
	}
	ttf.Quit()
	sdl.Quit()

	/* log.Printf("sdl Released...") */
}

func (c *sdlCtx) DisplayScript(script *subtitle.Script) {
	c.displayScript(script, true, false)
}

func (c *sdlCtx) Clear() {
	if c.currScript == nil {
		return
	}
	log.Println("clear")
	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	c.surface.Flip()
	c.currScript = nil
}

func (c *sdlCtx) setFont(path string, size int) error {
	if size < 10 {
		log.Println("set font size to minimum, 10")
		size = 10
	}

	c.font = ttf.OpenFont(path, size)
	if c.font == nil {
		errMsg := fmt.Sprintf("failed to open font from %s: %s",
			path, sdl.GetError())
		return errors.New(errMsg)
	}

	c.fontSize = size
	c.fontPath = path
	c.lineHeight = c.font.LineSkip()

	log.Println(c.fontSize, c.lineHeight)
	/* ctx.font.SetStyle(ttf.STYLE_UNDERLINE) */
	return nil
}

func (c *sdlCtx) changeFontSize(by int) {
	if c.font == nil {
		return
	}
	c.setFont(c.fontPath, c.fontSize+by)
	c.displayScript(c.currScript, false, true)
}

func (c *sdlCtx) setSurface(w, h int) error {
	log.Printf("setSurface to %dx%d", w, h)
	c.surface = sdl.SetVideoMode(w, h, 32, sdl.RESIZABLE) /* sdl.FULLSCREEN */
	if c.surface == nil {
		errMsg := fmt.Sprintf("sdl: failed to set video to %dx%d: %s",
			w, h, sdl.GetError())
		return errors.New(errMsg)
	}

	c.w, c.h = w, h
	if c.currScript != nil {
		c.displayScript(c.currScript, false, true)
	}

	return nil
}

func (c *sdlCtx) handelEvent() error {
	// KeySym to time.Duration mapping
	kmVias := map[uint32]time.Duration{
		sdl.K_z:       -100 * time.Microsecond,
		sdl.K_x:       +100 * time.Microsecond,
		sdl.K_LEFT:    -1 * time.Second,
		sdl.K_RIGHT:   +1 * time.Second,
		sdl.K_DOWN:    -10 * time.Second,
		sdl.K_UP:      +10 * time.Second,
		sdl.K_LESS:    -100 * time.Microsecond,
		sdl.K_GREATER: +100 * time.Microsecond,
	}

	kmFontSize := map[uint32]int{
		sdl.K_PLUS:     +5,
		sdl.K_KP_PLUS:  +5,
		sdl.K_MINUS:    -5,
		sdl.K_KP_MINUS: -5,
	}

	select {
	case event := <-sdl.Events:
		/* log.Printf("%#v\n", event) */
		switch e := event.(type) {
		case sdl.QuitEvent:
			return errors.New("sdl: received QuitEvent")
		case sdl.KeyboardEvent:
			// Ignore release key
			if e.State == 0 {
				return nil
			}
			// log.Printf("Sim:%08x, Mod:%04x, Unicode:%02x, %t\n",
			// 	e.Keysym.Sym, e.Keysym.Mod, e.Keysym.Unicode,
			// 	e.Keysym.Unicode)
			if vias, ok := kmVias[e.Keysym.Sym]; ok {
				viasC <- vias
				break
			}
			if vias, ok := kmFontSize[e.Keysym.Sym]; ok {
				c.changeFontSize(vias)
				break
			}
		case sdl.ResizeEvent:
			if err := c.setSurface(int(e.W), int(e.H)); err != nil {
				log.Fatal(err)
			}
		}
	}
	return nil
}

func (c *sdlCtx) displayScript(script *subtitle.Script,
	andClear bool, forceUpdate bool) {
	if forceUpdate == false && c.currScript == script {
		return
	}
	c.currScript = script

	log.Printf("display %s", script.Text)

	if c.font == nil {
		log.Println("set default font")
		err := c.setFont(DEFAULT_FONT_PATH, DEFAULT_FONT_SIZE)
		if err != nil {
			log.Fatal("failed to set default font")
			return
		}
	}

	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	offsetX := 10
	offsetY := 10

	for _, line := range strings.Split(script.Text, "\n") {
		runeLine := []rune(line)
		runeLineLen := len(runeLine)
		runeLineStart := 0

		for runeLineStart != runeLineLen {
			/* log.Println("start =", runeLineStart, "len =", runeLineLen) */
			runeSubLine := runeLine[runeLineStart:]
			i := sort.Search(len(runeSubLine), func(i int) bool {
				w, _, _ := c.font.SizeUTF8(string(runeSubLine[:i]))
				return (w - 20) >= c.w
			})
			/* log.Println("runeSubLine=", string(runeSubLine)) */

			if i != len(runeSubLine) && i > 1 {
				i -= 1
			}
			if i > runeLineLen {
				i = runeLineLen
			}
			/* log.Println("returned i=", i) */

			subline := string(runeLine[runeLineStart : runeLineStart+i])
			subline = strings.TrimSpace(subline)
			/* log.Println("subline=", subline) */
			runeLineStart += i
			if runeLineStart > runeLineLen {
				runeLineStart = runeLineLen
			}

			w, _, err := c.font.SizeUTF8(subline)
			if err != 0 {
				log.Fatal("Failed to get size of the font")
			}
			offsetX = (c.w - w) / 2

			glypse := ttf.RenderUTF8_Blended(c.font, subline, TEXT_COLOR)
			lt := sdl.Rect{int16(offsetX), int16(offsetY), 0, 0}
			c.surface.Blit(&lt, glypse, nil)
			offsetY += c.lineHeight
		}

	}
	c.surface.Flip()

	if andClear == false {
		return
	}

	go func() {
		<-time.After(script.Duration())
		if c.currScript != nil && c.currScript == script {
			c.surface.FillRect(nil, 0 /* BG_COLOR */)
			c.surface.Flip()
		}
	}()
}
<|endoftext|>


<commit_before>//
//  sed.go
//  sed
//
// Copyright (c) 2009 Geoffrey Clements
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

package sed

import (
	"bufio"
	"bytes"
	"container/list"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"unicode"
	"utf8"
)

const (
	versionMajor = 0
	versionMinor = 2
	versionPoint = 1
)

var versionString string

func init() {
	versionString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPoint)
}

var show_version = flag.Bool("version", false, "Show version information.")
var show_help = flag.Bool("h", false, "Show help information.")
var quiet = flag.Bool("n", false, "Don't print the pattern space at the end of each script cycle.")
var script = flag.String("e", "", "The script used to process the input file.")
var script_file = flag.String("f", "", "Specify a file to read as the script. Ignored if -e present")
var edit_inplace = flag.Bool("i", false, "This option specifies that files are to be edited in-place. Otherwise output is printed to stdout.")
var line_wrap = flag.Uint("l", 0, "Specify the default line-wrap length for the l command. A length of 0 (zero) means to never wrap long lines. If not specified, it is taken to be 70.")
var unbuffered = flag.Bool("u", false, "Buffer both input and output as minimally as practical. (ignored)")
var treat_files_as_seperate = flag.Bool("s", false, "Treat files as searate entites. Line numbers reset to 1 for each file")

var usageShown bool = false

var newLine = []byte{'\n'}

type Sed struct {
	inputFile               *os.File
	input                   *bufio.Reader
	lineNumber              int
	currentLine             string
	beforeCommands          *list.List
	commands                *list.List
	afterCommands           *list.List
	outputFile              *os.File
	patternSpace, holdSpace []byte
	scriptLines             [][]byte
	scriptLineNumber        int
}

func (s *Sed) Init() {
	s.beforeCommands = new(list.List)
	s.commands = new(list.List)
	s.afterCommands = new(list.List)
	s.outputFile = os.Stdout
	s.patternSpace = make([]byte, 0)
	s.holdSpace = make([]byte, 0)
}

func copyByteSlice(a []byte) []byte {
	newSlice := make([]byte, len(a))
	copy(newSlice, a)
	return newSlice
}

func usage() {
	// only show usage once.
	if !usageShown {
		usageShown = true
		fmt.Fprint(os.Stdout, "sed [options] [script] input_file\n\n")
		flag.PrintDefaults()
	}
}

var inputFilename string

func (s *Sed) getNextScriptLine() ([]byte, os.Error) {
	if s.scriptLineNumber < len(s.scriptLines) {
		val := s.scriptLines[s.scriptLineNumber]
		s.scriptLineNumber++
		return val, nil
	}
	return nil, os.EOF
}

func trimSpaceFromBeginning(s []byte) []byte {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[start])
		if rune >= utf8.RuneSelf {
			rune, wid = utf8.DecodeRune(s[start:end])
		}
		if !unicode.IsSpace(rune) {
			break
		}
		start += wid
	}
	return s[start:end]
}

func (s *Sed) parseScript(scriptBuffer []byte) (err os.Error) {
	// a script may be a single command or it may be several
	s.scriptLines = bytes.Split(scriptBuffer, []byte{'\n'}, -1)
	s.scriptLineNumber = 0
	var line []byte
	var serr os.Error
	for line, serr = s.getNextScriptLine(); serr == nil; line, serr = s.getNextScriptLine() {
		// line = bytes.TrimSpace(line);
		line = trimSpaceFromBeginning(line)
		if len(line) == 0 {
			// zero length line
			continue
		}
		if line[0] == '#' {
			if s.scriptLineNumber == 1 && len(line) > 1 && line[1] == 'n' {
				// spcial case where the first 2 characters of the file are #n which is
				// equivalent to passing -n on the command line
				*quiet = true
			}
			continue
		}
		c, err := NewCmd(s, line)
		if err != nil {
			fmt.Printf("Script error: %s -> %d: %s\n", err.String(), s.scriptLineNumber, line)
			os.Exit(-1)
		}
		if _, ok := c.(*i_cmd); ok {
			s.beforeCommands.PushBack(c)
		} else if _, ok := c.(*a_cmd); ok {
			s.afterCommands.PushBack(c)
		} else {
			s.commands.PushBack(c)
		}
	}
	return nil
}

func (s *Sed) printLine(line []byte) {
	l := len(line)
	if *line_wrap <= 0 || l < int(*line_wrap) {
		fmt.Fprintf(s.outputFile, "%s\n", line)
	} else {
		// print the line in segments
		for i := 0; i < l; i += int(*line_wrap) {
			endOfLine := i + int(*line_wrap)
			if endOfLine > l {
				endOfLine = l
			}
			fmt.Fprintf(s.outputFile, "%s\n", line[i:endOfLine])
		}
	}
}

func (s *Sed) printPatternSpace() {
	lines := bytes.Split(s.patternSpace, newLine, -1)
	for _, line := range lines {
		s.printLine(line)
	}
}

func (s *Sed) process() {
	if *treat_files_as_seperate || *edit_inplace {
		s.lineNumber = 0
	}
	var err os.Error
	s.patternSpace, err = s.input.ReadSlice('\n')
	for err != os.EOF {
		lineLength := len(s.patternSpace)
		if lineLength > 0 {
			s.patternSpace = s.patternSpace[0 : lineLength-1]
		}
		s.currentLine = string(s.patternSpace)
		// track line number starting with line 1
		s.lineNumber++
		stop := false
		// process i commands
		for c := range s.beforeCommands.Iter() {
			// ask the sed if we should process this command, based on address
			if cmd, ok := c.(*i_cmd); ok {
				if c.(Address).match(s.patternSpace, s.lineNumber) {
					s.outputFile.Write(cmd.text)
				}
			}
		}
		for c := range s.commands.Iter() {
			// ask the sed if we should process this command, based on address
			if c.(Address).match(s.patternSpace, s.lineNumber) {
				var err os.Error
				stop, err = c.(Cmd).processLine(s)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error: %s\n", err.String())
					fmt.Fprintf(os.Stderr, "Line: %d:%s\n", s.lineNumber, s.currentLine)
					fmt.Fprintf(os.Stderr, "Command: %s\n", c.(Cmd).String())
					os.Exit(-1)
				}
				if stop {
					break
				}
			}
		}
		if !*quiet && !stop {
			s.printPatternSpace()
		}
		// process a commands
		for c := range s.afterCommands.Iter() {
			// ask the sed if we should process this command, based on address
			if cmd, ok := c.(*a_cmd); ok {
				if c.(Address).match(s.patternSpace, s.lineNumber) {
					fmt.Fprintf(s.outputFile, "%s\n", cmd.text)
				}
			}
		}
		s.patternSpace, err = s.input.ReadSlice('\n')
	}
}

func Main() {
	var err os.Error
	s := new(Sed)
	s.Init()
	flag.Parse()
	if *show_version {
		fmt.Fprintf(os.Stdout, "Version: %s (c)2009-2010 Geoffrey Clements All Rights Reserved\n\n", versionString)
	}
	if *show_help {
		usage()
		return
	}

	// the first parameter may be a script or an input file. This helps us track which
	currentFileParameter := 0
	var scriptBuffer []byte = make([]byte, 0)

	// we need a script
	if len(*script) == 0 {
		// no -e so try -f
		if len(*script_file) > 0 {
			sb, err := ioutil.ReadFile(*script_file)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error reading script file %s\n", *script_file)
				os.Exit(-1)
			}
			scriptBuffer = sb
		} else if flag.NArg() > 1 {
			scriptBuffer := make([]byte, len(flag.Arg(0)))
			for i := 0; i < len(flag.Arg(0)); i++ {
				scriptBuffer[i] = flag.Arg(0)[i]
			}

			// change semicoluns to newlines for scripts on command line
			idx := bytes.IndexByte(scriptBuffer, ';')
			for idx >= 0 {
				scriptBuffer[idx] = '\n'
				s := scriptBuffer[idx+1:]
				idx = bytes.IndexByte(s, ';')
			}
			// first parameter was the script so move to second parameter
			currentFileParameter++
		}
	} else {
		scriptBuffer := make([]byte, len(*script))
		for i := 0; i < len(*script); i++ {
			scriptBuffer[i] = (*script)[i]
		}
		// change semicoluns to newlines for scripts on command line
		idx := bytes.IndexByte(scriptBuffer, ';')
		for idx >= 0 {
			scriptBuffer[idx] = '\n'
			s := scriptBuffer[idx+1:]
			idx = bytes.IndexByte(s, ';')
		}
	}

	// if script still isn't set we are screwed, exit.
	if len(scriptBuffer) == 0 {
		fmt.Fprint(os.Stderr, "No script found.\n\n")
		usage()
		os.Exit(-1)
	}

	// parse script
	s.parseScript(scriptBuffer)

	if currentFileParameter >= flag.NArg() {
		if *edit_inplace {
			fmt.Fprintf(os.Stderr, "Warning: Option -i ignored\n")
		}
		s.input = bufio.NewReader(os.Stdin)
		s.process()
	} else {
		for ; currentFileParameter < flag.NArg(); currentFileParameter++ {
			inputFilename = flag.Arg(currentFileParameter)
			// actually do the processing
			s.inputFile, err = os.Open(inputFilename, os.O_RDONLY, 0)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error openint input file: %s.\n\n", inputFilename)
				usage()
				os.Exit(-1)
			}
			s.input = bufio.NewReader(s.inputFile)
			var tempFilename string
			if *edit_inplace {
				tempFilename = inputFilename + ".tmp"
				tmpc := 0
				dir, _ := os.Stat(tempFilename)
				for dir != nil {
					tmpc++
					tempFilename = inputFilename + "-" + strconv.Itoa(tmpc) + ".tmp"
					dir, _ = os.Stat(tempFilename)
				}
				f, err := os.Open(tempFilename, os.O_RDWR|os.O_TRUNC|os.O_CREAT, 0600)
				if err != nil {
					s.inputFile.Close()
					fmt.Fprintf(os.Stderr, "Error opening temp file file for inplace editing: %s\n", err.String())
					os.Exit(-1)
				}
				s.outputFile = f
			}
			s.process()
			// done processing, close input file
			s.inputFile.Close()
			s.input = nil
			if *edit_inplace {
				s.outputFile.Seek(0, 0)
				// find out about
				dir, err := os.Stat(inputFilename)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error getting information about input file: %s %v\n", err)
					// os.Remove(tempFilename);
					os.Exit(-1)
				}
				// reopen input file
				s.inputFile, err = os.Open(inputFilename, os.O_WRONLY|os.O_TRUNC, dir.Mode)
				if err != nil {
					fmt.Fprint(os.Stderr, "Error opening input file for inplace editing: %s\n", err.String())
					// os.Remove(tempFilename);
					os.Exit(-1)
				}

				_, e := io.Copy(s.inputFile, s.outputFile)
				s.outputFile.Close()
				s.inputFile.Close()
				if e != nil {
					fmt.Fprintf(os.Stderr, "Error copying temp file back to input file: %s\nFull output is in %s", err.String(), tempFilename)
				} else {
					os.Remove(tempFilename)
				}
			}
		}
	}
}
<commit_msg>Update for latest version of Go.<commit_after>//
//  sed.go
//  sed
//
// Copyright (c) 2009 Geoffrey Clements
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

package sed

import (
	"bufio"
	"bytes"
	"container/list"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"unicode"
	"utf8"
)

const (
	versionMajor = 0
	versionMinor = 2
	versionPoint = 1
)

var versionString string

func init() {
	versionString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPoint)
}

var show_version = flag.Bool("version", false, "Show version information.")
var show_help = flag.Bool("h", false, "Show help information.")
var quiet = flag.Bool("n", false, "Don't print the pattern space at the end of each script cycle.")
var script = flag.String("e", "", "The script used to process the input file.")
var script_file = flag.String("f", "", "Specify a file to read as the script. Ignored if -e present")
var edit_inplace = flag.Bool("i", false, "This option specifies that files are to be edited in-place. Otherwise output is printed to stdout.")
var line_wrap = flag.Uint("l", 0, "Specify the default line-wrap length for the l command. A length of 0 (zero) means to never wrap long lines. If not specified, it is taken to be 70.")
var unbuffered = flag.Bool("u", false, "Buffer both input and output as minimally as practical. (ignored)")
var treat_files_as_seperate = flag.Bool("s", false, "Treat files as searate entites. Line numbers reset to 1 for each file")

var usageShown bool = false

var newLine = []byte{'\n'}

type Sed struct {
	inputFile               *os.File
	input                   *bufio.Reader
	lineNumber              int
	currentLine             string
	beforeCommands          *list.List
	commands                *list.List
	afterCommands           *list.List
	outputFile              *os.File
	patternSpace, holdSpace []byte
	scriptLines             [][]byte
	scriptLineNumber        int
}

func (s *Sed) Init() {
	s.beforeCommands = new(list.List)
	s.commands = new(list.List)
	s.afterCommands = new(list.List)
	s.outputFile = os.Stdout
	s.patternSpace = make([]byte, 0)
	s.holdSpace = make([]byte, 0)
}

func copyByteSlice(a []byte) []byte {
	newSlice := make([]byte, len(a))
	copy(newSlice, a)
	return newSlice
}

func usage() {
	// only show usage once.
	if !usageShown {
		usageShown = true
		fmt.Fprint(os.Stdout, "sed [options] [script] input_file\n\n")
		flag.PrintDefaults()
	}
}

var inputFilename string

func (s *Sed) getNextScriptLine() ([]byte, os.Error) {
	if s.scriptLineNumber < len(s.scriptLines) {
		val := s.scriptLines[s.scriptLineNumber]
		s.scriptLineNumber++
		return val, nil
	}
	return nil, os.EOF
}

func trimSpaceFromBeginning(s []byte) []byte {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[start])
		if rune >= utf8.RuneSelf {
			rune, wid = utf8.DecodeRune(s[start:end])
		}
		if !unicode.IsSpace(rune) {
			break
		}
		start += wid
	}
	return s[start:end]
}

func (s *Sed) parseScript(scriptBuffer []byte) (err os.Error) {
	// a script may be a single command or it may be several
	s.scriptLines = bytes.Split(scriptBuffer, []byte{'\n'}, -1)
	s.scriptLineNumber = 0
	var line []byte
	var serr os.Error
	for line, serr = s.getNextScriptLine(); serr == nil; line, serr = s.getNextScriptLine() {
		// line = bytes.TrimSpace(line);
		line = trimSpaceFromBeginning(line)
		if len(line) == 0 {
			// zero length line
			continue
		}
		if line[0] == '#' {
			if s.scriptLineNumber == 1 && len(line) > 1 && line[1] == 'n' {
				// spcial case where the first 2 characters of the file are #n which is
				// equivalent to passing -n on the command line
				*quiet = true
			}
			continue
		}
		c, err := NewCmd(s, line)
		if err != nil {
			fmt.Printf("Script error: %s -> %d: %s\n", err.String(), s.scriptLineNumber, line)
			os.Exit(-1)
		}
		if _, ok := c.(*i_cmd); ok {
			s.beforeCommands.PushBack(c)
		} else if _, ok := c.(*a_cmd); ok {
			s.afterCommands.PushBack(c)
		} else {
			s.commands.PushBack(c)
		}
	}
	return nil
}

func (s *Sed) printLine(line []byte) {
	l := len(line)
	if *line_wrap <= 0 || l < int(*line_wrap) {
		fmt.Fprintf(s.outputFile, "%s\n", line)
	} else {
		// print the line in segments
		for i := 0; i < l; i += int(*line_wrap) {
			endOfLine := i + int(*line_wrap)
			if endOfLine > l {
				endOfLine = l
			}
			fmt.Fprintf(s.outputFile, "%s\n", line[i:endOfLine])
		}
	}
}

func (s *Sed) printPatternSpace() {
	lines := bytes.Split(s.patternSpace, newLine, -1)
	for _, line := range lines {
		s.printLine(line)
	}
}

func (s *Sed) process() {
	if *treat_files_as_seperate || *edit_inplace {
		s.lineNumber = 0
	}
	var err os.Error
	s.patternSpace, err = s.input.ReadSlice('\n')
	for err != os.EOF {
		lineLength := len(s.patternSpace)
		if lineLength > 0 {
			s.patternSpace = s.patternSpace[0 : lineLength-1]
		}
		s.currentLine = string(s.patternSpace)
		// track line number starting with line 1
		s.lineNumber++
		stop := false
		// process i commands
  	for c := s.beforeCommands.Front(); c != nil; c = c.Next() {
			// ask the sed if we should process this command, based on address
			if cmd, ok := c.Value.(*i_cmd); ok {
				if c.Value.(Address).match(s.patternSpace, s.lineNumber) {
					s.outputFile.Write(cmd.text)
				}
			}
		}
		for c := s.commands.Front(); c != nil; c = c.Next() {
			// ask the sed if we should process this command, based on address
			if c.Value.(Address).match(s.patternSpace, s.lineNumber) {
				var err os.Error
				stop, err = c.Value.(Cmd).processLine(s)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error: %s\n", err.String())
					fmt.Fprintf(os.Stderr, "Line: %d:%s\n", s.lineNumber, s.currentLine)
					fmt.Fprintf(os.Stderr, "Command: %s\n", c.Value.(Cmd).String())
					os.Exit(-1)
				}
				if stop {
					break
				}
			}
		}
		if !*quiet && !stop {
			s.printPatternSpace()
		}
		// process a commands
		for c := s.afterCommands.Front(); c != nil; c = c.Next() {
			// ask the sed if we should process this command, based on address
			if cmd, ok := c.Value.(*a_cmd); ok {
				if c.Value.(Address).match(s.patternSpace, s.lineNumber) {
					fmt.Fprintf(s.outputFile, "%s\n", cmd.text)
				}
			}
		}
		s.patternSpace, err = s.input.ReadSlice('\n')
	}
}

func Main() {
	var err os.Error
	s := new(Sed)
	s.Init()
	flag.Parse()
	if *show_version {
		fmt.Fprintf(os.Stdout, "Version: %s (c)2009-2010 Geoffrey Clements All Rights Reserved\n\n", versionString)
	}
	if *show_help {
		usage()
		return
	}

	// the first parameter may be a script or an input file. This helps us track which
	currentFileParameter := 0
	var scriptBuffer []byte = make([]byte, 0)

	// we need a script
	if len(*script) == 0 {
		// no -e so try -f
		if len(*script_file) > 0 {
			sb, err := ioutil.ReadFile(*script_file)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error reading script file %s\n", *script_file)
				os.Exit(-1)
			}
			scriptBuffer = sb
		} else if flag.NArg() > 1 {
			scriptBuffer := make([]byte, len(flag.Arg(0)))
			for i := 0; i < len(flag.Arg(0)); i++ {
				scriptBuffer[i] = flag.Arg(0)[i]
			}

			// change semicoluns to newlines for scripts on command line
			idx := bytes.IndexByte(scriptBuffer, ';')
			for idx >= 0 {
				scriptBuffer[idx] = '\n'
				s := scriptBuffer[idx+1:]
				idx = bytes.IndexByte(s, ';')
			}
			// first parameter was the script so move to second parameter
			currentFileParameter++
		}
	} else {
		scriptBuffer := make([]byte, len(*script))
		for i := 0; i < len(*script); i++ {
			scriptBuffer[i] = (*script)[i]
		}
		// change semicoluns to newlines for scripts on command line
		idx := bytes.IndexByte(scriptBuffer, ';')
		for idx >= 0 {
			scriptBuffer[idx] = '\n'
			s := scriptBuffer[idx+1:]
			idx = bytes.IndexByte(s, ';')
		}
	}

	// if script still isn't set we are screwed, exit.
	if len(scriptBuffer) == 0 {
		fmt.Fprint(os.Stderr, "No script found.\n\n")
		usage()
		os.Exit(-1)
	}

	// parse script
	s.parseScript(scriptBuffer)

	if currentFileParameter >= flag.NArg() {
		if *edit_inplace {
			fmt.Fprintf(os.Stderr, "Warning: Option -i ignored\n")
		}
		s.input = bufio.NewReader(os.Stdin)
		s.process()
	} else {
		for ; currentFileParameter < flag.NArg(); currentFileParameter++ {
			inputFilename = flag.Arg(currentFileParameter)
			// actually do the processing
			s.inputFile, err = os.Open(inputFilename, os.O_RDONLY, 0)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error openint input file: %s.\n\n", inputFilename)
				usage()
				os.Exit(-1)
			}
			s.input = bufio.NewReader(s.inputFile)
			var tempFilename string
			if *edit_inplace {
				tempFilename = inputFilename + ".tmp"
				tmpc := 0
				dir, _ := os.Stat(tempFilename)
				for dir != nil {
					tmpc++
					tempFilename = inputFilename + "-" + strconv.Itoa(tmpc) + ".tmp"
					dir, _ = os.Stat(tempFilename)
				}
				f, err := os.Open(tempFilename, os.O_RDWR|os.O_TRUNC|os.O_CREAT, 0600)
				if err != nil {
					s.inputFile.Close()
					fmt.Fprintf(os.Stderr, "Error opening temp file file for inplace editing: %s\n", err.String())
					os.Exit(-1)
				}
				s.outputFile = f
			}
			s.process()
			// done processing, close input file
			s.inputFile.Close()
			s.input = nil
			if *edit_inplace {
				s.outputFile.Seek(0, 0)
				// find out about
				dir, err := os.Stat(inputFilename)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Error getting information about input file: %s %v\n", err)
					// os.Remove(tempFilename);
					os.Exit(-1)
				}
				// reopen input file
				s.inputFile, err = os.Open(inputFilename, os.O_WRONLY|os.O_TRUNC, dir.Mode)
				if err != nil {
					fmt.Fprint(os.Stderr, "Error opening input file for inplace editing: %s\n", err.String())
					// os.Remove(tempFilename);
					os.Exit(-1)
				}

				_, e := io.Copy(s.inputFile, s.outputFile)
				s.outputFile.Close()
				s.inputFile.Close()
				if e != nil {
					fmt.Fprintf(os.Stderr, "Error copying temp file back to input file: %s\nFull output is in %s", err.String(), tempFilename)
				} else {
					os.Remove(tempFilename)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package tests

import (
	"github.com/go-openapi/strfmt"
	"time"
)

type PerfSession struct {
}

func (self *PerfSession) CheckBool(expected bool, actual bool, message string) {
	if expected != actual {
		panic(message)
	}
}
func (self *PerfSession) CheckInt(expected int, actual int, message string) {
	if expected != actual {
		panic(message)
	}
}
func (self *PerfSession) CheckInt32(expected int32, actual int32, message string) {
	if expected != actual {
		panic(message)
	}
}
func (self *PerfSession) CheckInt64(expected int64, actual int64, message string) {
	if expected != actual {
		panic(message)
	}
}
func (self *PerfSession) CheckStr(expected string, actual string, message string) {
	if expected != actual {
		panic(message)
	}
}
func (self *PerfSession) CheckHash(expected PHash, actual string, message string) {
	if expected != Hash(actual) {
		panic(message)
	}
}
func (self *PerfSession) CheckDate(expected *strfmt.DateTime, actual *strfmt.DateTime, message string) {
	if !time.Time(*expected).UTC().Equal(time.Time(*actual).UTC()) {
		log.Panicf("Unexpected data (%s != %s): %s", expected.String(), actual.String(), message)
	}
}
func (self *PerfSession) CheckVersion(before PVersion, after PVersion) bool {
	return true
}
func (self *PerfSession) Finish(before PVersion, after PVersion) {

}
<commit_msg>Более внятные сообщения об ошибках<commit_after>package tests

import (
	"github.com/go-openapi/strfmt"
	"time"
)

type PerfSession struct {
}

func (self *PerfSession) CheckBool(expected bool, actual bool, message string) {
	if expected != actual {
		panic(message)
	}
}
func (self *PerfSession) CheckInt(expected int, actual int, message string) {
	if expected != actual {
		log.Panicf("Unexpected data (%d != %d): %s", expected, actual, message)
	}
}
func (self *PerfSession) CheckInt32(expected int32, actual int32, message string) {
	if expected != actual {
		log.Panicf("Unexpected data (%d != %d): %s", expected, actual, message)
	}
}
func (self *PerfSession) CheckInt64(expected int64, actual int64, message string) {
	if expected != actual {
		log.Panicf("Unexpected data (%d != %d): %s", expected, actual, message)
	}
}
func (self *PerfSession) CheckStr(expected string, actual string, message string) {
	if expected != actual {
		log.Panicf("Unexpected data (%s != %s): %s", expected, actual, message)
	}
}
func (self *PerfSession) CheckHash(expected PHash, actual string, message string) {
	if expected != Hash(actual) {
		log.Panicf("Unexpected string (%s): %s", actual, message)
	}
}
func (self *PerfSession) CheckDate(expected *strfmt.DateTime, actual *strfmt.DateTime, message string) {
	if !time.Time(*expected).UTC().Equal(time.Time(*actual).UTC()) {
		log.Panicf("Unexpected data (%s != %s): %s", expected.String(), actual.String(), message)
	}
}
func (self *PerfSession) CheckVersion(before PVersion, after PVersion) bool {
	return true
}
func (self *PerfSession) Finish(before PVersion, after PVersion) {

}
<|endoftext|>


<commit_before>/* Copyright (C) 2013 CompleteDB LLC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PubSubSQL.  If not, see <http://www.gnu.org/licenses/>.
 */

package server

import (
	"runtime"
	"fmt"
	"os"
	"time"
)

// Controller is a container that initializes, binds and controls server components.
type Controller struct {
	network			*network
	requests chan	*requestItem
	quit			*Quitter
}

// Run is a main server entry function. It processes command line options and runs the server in the appropriate mode.
func (this *Controller) Run() {
	runtime.GOMAXPROCS(runtime.NumCPU() - 1)
	if !config.processCommandLine(os.Args[1:]) {
		return
	}
	this.quit = NewQuitter()
	// process commands
	switch config.COMMAND {
	case "help":
		this.displayHelp()
	case "cli":
		this.runAsClient()
	case "start":
		this.runAsServer()
	case "stop":
		this.runOnce("stop")
	}
}

// displayHelp displays help to the cli user.
func (this *Controller) displayHelp() {
	fmt.Println("")
	fmt.Println("commands:")
	fmt.Println(validCommandsUsageString())
	fmt.Println("")
	fmt.Println("options:")
	config.flags.PrintDefaults()
}

// runAsClient runs the program in cli mode.
func (this *Controller) runAsClient() {
	client := newCli()
	// start cli event loop
	client.run()
}

// run command once
func (this *Controller) runOnce(command string) {
	client := newCli()
	client.runOnce(command)
}

// runAsServer runs the program in server mode.
func (this *Controller) runAsServer() {
	// initialize server components
	// requests
	this.requests = make(chan *requestItem)
	// data service
	dataService := newDataService(this.quit)
	go dataService.run()
	// router
	router := newRequestRouter(dataService)
	router.controllerRequests = this.requests
	// network context
	context := new(networkContext)
	context.quit = this.quit
	context.router = router
	// network
	this.network = newNetwork(context)
	if !this.network.start(config.netAddress()) {
		this.quit.Quit(0)
		return
	}
	info("started")
	// watch for quit (q) input
	go this.readInput()
	// wait for command to process or stop event
LOOP:
	for {
		select {
		case <-this.quit.GetChan():
			break LOOP
		case item := <-this.requests:
			this.onCommandRequest(item)
		}
	}
	// shutdown
	this.network.stop()
	this.quit.Quit(0)
	this.quit.Wait(time.Millisecond * config.WAIT_MILLISECOND_SERVER_SHUTDOWN)
	info("stopped")
}

// readInput reads a command line input from the standard until quit (q) input.
func (this *Controller) readInput() {
	cin := newLineReader("q")
	for cin.readLine() {
	}
	this.quit.Quit(0)
	debug("controller done readInput")
}

// onCommandRequest processes request from a connected client, sending respond back to the client.
func (this *Controller) onCommandRequest(item *requestItem) {
	switch item.req.(type) {
	case *cmdStatusRequest:
		logInfo("client connection:", item.sender.connectionId, "requested server status")
		if item.req.isStreaming() {
			return
		}
		res := newCmdStatusResponse(this.network.connectionCount())
		res.requestId = item.getRequestId()
		item.sender.send(res)
	case *cmdStopRequest:
		logInfo("client connection:", item.sender.connectionId, "requested to stop the server")
		this.quit.Quit(0)
	case *mysqlConnectRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql connect")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlConnectRequest)
		response := newCmdMysqlConnectResponse(request)
		response.requestId = item.getRequestId()
		//
		item.dbConn.connect(request.address)
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		}
		//
		item.sender.send(response)
	case *mysqlDisconnectRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql diconnect")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlDisconnectRequest)
		response := newCmdMysqlDisconnectResponse(request)
		response.requestId = item.getRequestId()
		//
		item.dbConn.disconnect()
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		}
		//
		item.sender.send(response)
	case *mysqlStatusRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql status")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlStatusRequest)
		response := newCmdMysqlStatusResponse(request)
		response.requestId = item.getRequestId()
		//
		connected := item.dbConn.isConnected()
		response.setOnline(connected)
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		}
		//
		item.sender.send(response)
	case *mysqlSubscribeRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql subscribe")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlSubscribeRequest)
		response := newCmdMysqlSubscribeResponse(request)
		response.requestId = item.getRequestId()
		item.sender.send(response)
	case *mysqlUnsubscribeRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql unsubscribe")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlUnsubscribeRequest)
		response := newCmdMysqlUnsubscribeResponse(request)
		response.requestId = item.getRequestId()
		item.sender.send(response)
	case *mysqlTablesRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql tables")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlTablesRequest)
		response := newCmdMysqlTablesResponse(request)
		response.requestId = item.getRequestId()
		//
		tables := item.dbConn.findTables()
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		} else {
			response.tables = tables
		}
		//
		item.sender.send(response)
	}
}
<commit_msg>add proxy<commit_after>/* Copyright (C) 2013 CompleteDB LLC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PubSubSQL.  If not, see <http://www.gnu.org/licenses/>.
 */

package server

import (
	"runtime"
	"fmt"
	"os"
	"time"
)

// Controller is a container that initializes, binds and controls server components.
type Controller struct {
	network			*network
	requests chan	*requestItem
	quit			*Quitter
}

// Run is a main server entry function. It processes command line options and runs the server in the appropriate mode.
func (this *Controller) Run() {
	runtime.GOMAXPROCS(runtime.NumCPU() - 1)
	if !config.processCommandLine(os.Args[1:]) {
		return
	}
	this.quit = NewQuitter()
	// process commands
	switch config.COMMAND {
	case "help":
		this.displayHelp()
	case "cli":
		this.runAsClient()
	case "start":
		this.runAsServer()
	case "stop":
		this.runOnce("stop")
	}
}

// displayHelp displays help to the cli user.
func (this *Controller) displayHelp() {
	fmt.Println("")
	fmt.Println("commands:")
	fmt.Println(validCommandsUsageString())
	fmt.Println("")
	fmt.Println("options:")
	config.flags.PrintDefaults()
}

// runAsClient runs the program in cli mode.
func (this *Controller) runAsClient() {
	client := newCli()
	// start cli event loop
	client.run()
}

// run command once
func (this *Controller) runOnce(command string) {
	client := newCli()
	client.runOnce(command)
}

// runAsServer runs the program in server mode.
func (this *Controller) runAsServer() {
	// initialize server components
	// requests
	this.requests = make(chan *requestItem)
	// data service
	dataService := newDataService(this.quit)
	go dataService.run()
	// router
	router := newRequestRouter(dataService)
	router.controllerRequests = this.requests
	// network context
	context := new(networkContext)
	context.quit = this.quit
	context.router = router
	// network
	this.network = newNetwork(context)
	if !this.network.start(config.netAddress()) {
		this.quit.Quit(0)
		return
	}
	info("started")
	// watch for quit (q) input
	go this.readInput()
	// wait for command to process or stop event
LOOP:
	for {
		select {
		case <-this.quit.GetChan():
			break LOOP
		case item := <-this.requests:
			this.onCommandRequest(item)
		}
	}
	// shutdown
	this.network.stop()
	this.quit.Quit(0)
	this.quit.Wait(time.Millisecond * config.WAIT_MILLISECOND_SERVER_SHUTDOWN)
	info("stopped")
}

// readInput reads a command line input from the standard until quit (q) input.
func (this *Controller) readInput() {
	cin := newLineReader("q")
	for cin.readLine() {
	}
	this.quit.Quit(0)
	debug("controller done readInput")
}

// onCommandRequest processes request from a connected client, sending respond back to the client.
func (this *Controller) onCommandRequest(item *requestItem) {
	switch item.req.(type) {
	case *cmdStatusRequest:
		logInfo("client connection:", item.sender.connectionId, "requested server status")
		if item.req.isStreaming() {
			return
		}
		res := newCmdStatusResponse(this.network.connectionCount())
		res.requestId = item.getRequestId()
		item.sender.send(res)
	case *cmdStopRequest:
		logInfo("client connection:", item.sender.connectionId, "requested to stop the server")
		this.quit.Quit(0)
	case *mysqlConnectRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql connect")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlConnectRequest)
		response := newCmdMysqlConnectResponse(request)
		response.requestId = item.getRequestId()
		//
		item.dbConn.connect(request.address)
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		}
		//
		item.sender.send(response)
	case *mysqlDisconnectRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql diconnect")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlDisconnectRequest)
		response := newCmdMysqlDisconnectResponse(request)
		response.requestId = item.getRequestId()
		//
		item.dbConn.disconnect()
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		}
		//
		item.sender.send(response)
	case *mysqlStatusRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql status")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlStatusRequest)
		response := newCmdMysqlStatusResponse(request)
		response.requestId = item.getRequestId()
		//
		connected := item.dbConn.isConnected()
		response.setOnline(connected)
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		}
		//
		item.sender.send(response)
	case *mysqlSubscribeRequest:
		request := item.req.(*mysqlSubscribeRequest)
		item.req = request.sqlSubscribeReq
		this.network.context.router.dataSrv.onSqlRequest(item)
		/*
		logInfo("client connection:", item.sender.connectionId, "requested mysql subscribe")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlSubscribeRequest)
		response := newCmdMysqlSubscribeResponse(request)
		response.requestId = item.getRequestId()
		item.sender.send(response)
		*/
	case *mysqlUnsubscribeRequest:
		request := item.req.(*mysqlUnsubscribeRequest)
		item.req = request.sqlUnsubscribeReq
		this.network.context.router.dataSrv.onSqlRequest(item)
		/*
		logInfo("client connection:", item.sender.connectionId, "requested mysql unsubscribe")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlUnsubscribeRequest)
		response := newCmdMysqlUnsubscribeResponse(request)
		response.requestId = item.getRequestId()
		item.sender.send(response)
		*/
	case *mysqlTablesRequest:
		logInfo("client connection:", item.sender.connectionId, "requested mysql tables")
		if item.req.isStreaming() {
			return
		}
		request := item.req.(*mysqlTablesRequest)
		response := newCmdMysqlTablesResponse(request)
		response.requestId = item.getRequestId()
		//
		tables := item.dbConn.findTables()
		if item.dbConn.hasError() {
			response.error = item.dbConn.getLastError()
		} else {
			response.tables = tables
		}
		//
		item.sender.send(response)
	}
}
<|endoftext|>


<commit_before>// GameServer: main gameserver struct and functions
// does not know or care about where Packets come from,
// they just arrive on our In port.
package main

import (
	"fmt"
	"github.com/aarzilli/golua/lua"
	"github.com/mischief/goland/game"
	"github.com/mischief/goland/game/gnet"
	"github.com/mischief/goland/game/gutil"
	"github.com/stevedonovan/luar"
	"github.com/trustmaster/goflow"
	"image"
	"log"
	"net"
	"reflect"
)

var (
	Actions = map[game.Action]func(*GameServer, *ClientPacket){
		game.ACTION_ITEM_PICKUP:         Action_ItemPickup,
		game.ACTION_ITEM_DROP:           Action_ItemDrop,
		game.ACTION_ITEM_LIST_INVENTORY: Action_Inventory,
	}

	GS *GameServer
)

type GameServer struct {
	flow.Graph // graph for our procs; see goflow

	Listener   net.Listener       // acceptor of client connections
	PacketChan chan *ClientPacket // channel where clients packets arrive

	*game.DefaultSubject

	Sessions map[int]*WorldSession //client list

	Objects *game.GameObjectMap
	Map     *game.MapChunk

	config *gutil.LuaConfig

	Lua *lua.State
}

func NewGameServer(config *gutil.LuaConfig, ls *lua.State) (*GameServer, error) {
	gs := &GameServer{
		config: config,
	}

	GS = gs

	gs.InitGraphState()

	// add nodes
	gs.Add(NewPacketRouter(gs), "router")
	gs.Add(new(PacketLogger), "logger")

	// connect processes
	gs.Connect("router", "Log", "logger", "In")

	// map external ports
	gs.MapInPort("In", "router", "In")

	gs.PacketChan = make(chan *ClientPacket, 5)
	gs.SetInPort("In", gs.PacketChan)

	// observers setup
	gs.DefaultSubject = game.NewDefaultSubject()

	// objects setup
	gs.Objects = game.NewGameObjectMap()

	// lua state
	gs.Lua = ls

	return gs, nil
}

func (gs *GameServer) Debug() bool {
	if debug, err := gs.config.Get("debug", reflect.Bool); err != nil {
		log.Println("GameServer: 'debug' not found in config. defaulting to false")
		return false
	} else {
		return debug.(bool)
	}
}

func (gs *GameServer) Run() {
	gs.Start()

	for {
		conn, err := gs.Listener.Accept()
		if err != nil {
			log.Println("GameServer: acceptor: ", err)
			continue
		}

		ws := NewWorldSession(gs, conn)
		gs.Attach(ws)

		log.Printf("GameServer: New connection from %s", ws.Con.RemoteAddr())

		go ws.ReceiveProc()
	}

	gs.End()
}

func (gs *GameServer) Start() {
	var err error

	// load assets
	log.Print("GameServer: Loading assets")
	if gs.LoadAssets() != true {
		log.Printf("GameServer: LoadAssets failed")
		return
	}

	// setup tcp listener
	log.Printf("GameServer: Starting listener")

	var dialstr string
	defaultdialstr := ":61507"
	if dialconf, err := gs.config.Get("listener", reflect.String); err != nil {
		log.Println("GameServer: 'listen' not found in config. defaulting to ", defaultdialstr)
		dialstr = defaultdialstr
	} else {
		dialstr = dialconf.(string)
	}

	if gs.Listener, err = net.Listen("tcp", dialstr); err != nil {
		log.Fatalf("GameServer: %s", err)
	}

	// setup goflow network
	log.Print("GameServer: Starting flow")

	flow.RunNet(gs)
}

func (gs *GameServer) End() {
}

func (gs *GameServer) LoadMap(file string) bool {
	if gs.Map = game.MapChunkFromFile(file); gs.Map == nil {
		log.Printf("GameServer: LoadMap: failed loading %s", file)
		return false
	}

	log.Printf("GameServer: LoadMap: loaded map %s", file)
	return true
}

func (gs *GameServer) AddObject(obj game.Object) {
	log.Printf("Adding object %s", obj)

	// tell clients about new object
	gs.SendPkStrAll("Rnewobject", obj)
	gs.Objects.Add(obj)
}

func (gs *GameServer) LuaLog(fmt string, args ...interface{}) {
	log.Printf("GameServer: Lua: "+fmt, args...)
}

func (gs *GameServer) GetScriptPath() string {
	defaultpath := "../scripts/?.lua"
	if scriptconf, err := gs.config.Get("scriptpath", reflect.String); err != nil {
		log.Printf("GameServer: GetScriptPath defaulting to %s: %s", defaultpath, err)
		return defaultpath
	} else {
		return scriptconf.(string)
	}
}

// TODO: move these bindings into another file
func (gs *GameServer) BindLua() {
	luar.Register(gs.Lua, "", luar.Map{
		"gs": gs,
	})

	// add our script path here..
	pkgpathscript := `package.path = package.path .. ";" .. gs.GetScriptPath() --";../?.lua"`
	if err := gs.Lua.DoString(pkgpathscript); err != nil {
	}

	Lua_OpenObjectLib(gs.Lua)
}

// load everything from lua scripts
func (gs *GameServer) LoadAssets() bool {
	gs.BindLua()

	if err := gs.Lua.DoString("require('system')"); err != nil {
		log.Printf("GameServer: LoadAssets: %s", err)
		return false
	}

	return true
}

func (gs *GameServer) SendPkStrAll(tag string, data interface{}) {
	gs.SendPacketAll(gnet.NewPacket(tag, data))
}

// send a packet to all clients
func (gs *GameServer) SendPacketAll(pk *gnet.Packet) {
	gs.DefaultSubject.Lock()
	defer gs.DefaultSubject.Unlock()
	for s := gs.DefaultSubject.Observers.Front(); s != nil; s = s.Next() {
		s.Value.(*WorldSession).SendPacket(pk)
	}
}

func (gs *GameServer) HandlePacket(cp *ClientPacket) {

	switch cp.Tag {

	// Tchat: chat message from a client
	case "Tchat":
		// broadcast chat
		chatline := cp.Data.(string)
		gs.SendPacketAll(gnet.NewPacket("Rchat", fmt.Sprintf("[chat] %s: %s", cp.Client.Username, chatline)))

		// Taction: movement request
	case "Taction":
		gs.HandleActionPacket(cp)

		// Tconnect: user establishes new connection
	case "Tconnect":
		username, ok := cp.Data.(string)

		if !ok {
			cp.Reply(gnet.NewPacket("Rerror", "invalid username or conversion failed"))
			break
		} else {
			cp.Client.Username = username
		}

		// make new player for client
		var newplayer game.Object
		newplayer = game.NewGameObject(username)
		newplayer.SetTag("player", true)
		newplayer.SetTag("visible", true)

		// setting this lets players pick up other players, lol
		//newplayer.SetTag("gettable", true)
		newplayer.SetGlyph(game.GLYPH_HUMAN)
		newplayer.SetPos(256/2, 256/2)

		// set the session's object
		cp.Client.Player = newplayer

		// put player object in world
		gs.Objects.Add(newplayer)

		// tell client about all other objects
		for o := range gs.Objects.Chan() {
			if o.GetID() != newplayer.GetID() {
				cp.Reply(gnet.NewPacket("Rnewobject", o))
			}
		}

		// tell all clients about the new player
		gs.SendPacketAll(gnet.NewPacket("Rnewobject", newplayer))

		// greet our new player
		cp.Reply(gnet.NewPacket("Rchat", "Welcome to Goland!"))

	case "Tdisconnect":
		// notify clients this player went away
		Action_ItemDrop(gs, cp)
		gs.Objects.RemoveObject(cp.Client.Player)
		gs.Detach(cp.Client)
		gs.SendPacketAll(gnet.NewPacket("Rdelobject", cp.Client.Player))

	case "Tgetplayer":
		if cp.Client.Player != nil {
			cp.Reply(gnet.NewPacket("Rgetplayer", cp.Client.Player.GetID()))
		} else {
			cp.Reply(gnet.NewPacket("Rerror", "nil Player in WorldSession"))
		}

	case "Tloadmap":
		cp.Reply(gnet.NewPacket("Rloadmap", gs.Map))

	default:
		log.Printf("GameServer: HandlePacket: unknown packet type %s", cp.Tag)
	}
}

// Prevent User from re-adding / picking up item
// Disassociate item with map after action successful
func Action_ItemPickup(gs *GameServer, cp *ClientPacket) {
	p := cp.Client.Player

	// we assume our cp.Data is a game.Action of type ACTION_ITEM_PICKUP
	// act accordingly

	for o := range gs.Objects.Chan() {
		// if same pos.. and gettable
		if game.SamePos(o, p) && o.GetTag("gettable") {
			// pickup item.
			log.Printf("GameServer: Action_ItemPickup: %s picking up %s", p, o)
			o.SetTag("visible", false)
			o.SetTag("gettable", false)
			o.SetPos(0, 0)
			p.AddSubObject(o)

			// update clients with the new state of this object
			gs.SendPacketAll(gnet.NewPacket("Raction", o))
			cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You pick up a %s.", o.GetName())))
		}
	}
}

// Player drops the item indicated by the ID from their inventory
// TODO: this drops all items right now. make it drop individual items
func Action_ItemDrop(gs *GameServer, cp *ClientPacket) {
	p := cp.Client.Player
	for sub := range p.GetSubObjects().Chan() {
		log.Printf("GameServer: Action_ItemDrop: %s dropping %s", p, sub)

		// remove item from player
		p.RemoveSubObject(sub)
		// put it where the player was
		sub.SetPos(p.GetPos())
		// make it visible
		sub.SetTag("visible", true)
		sub.SetTag("gettable", true)

		// update clients with the new state of this object
		gs.SendPacketAll(gnet.NewPacket("Raction", sub))
		cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You drop a %s.", sub.GetName())))
	}
}

// List items in Player's inventory
func Action_Inventory(gs *GameServer, cp *ClientPacket) {
	plobj := cp.Client.Player

	inv := plobj.GetSubObjects().Chan()

	if len(inv) == 0 {
		cp.Reply(gnet.NewPacket("Rchat", "You have 0 items."))
	} else {
		counts := make(map[string]int)
		for sub := range inv {
			n := sub.GetName()
			if _, ok := counts[n]; ok {
				counts[n]++
			} else {
				counts[n] = 1
			}
		}

		for n, c := range counts {
			if c == 1 {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You have a %s.", n)))
			} else {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You have %d %ss.", c, n)))
			}

		}
	}

}

// Top level handler for Taction packets
func (gs *GameServer) HandleActionPacket(cp *ClientPacket) {
	action := cp.Data.(game.Action)
	p := cp.Client.Player

	_, isdir := game.DirTable[action]
	if isdir {
		gs.HandleMovementPacket(cp)
	}

	// check if this action is in our Actions table, if so execute it
	if f, ok := Actions[action]; ok {
		f(gs, cp)
	}

	gs.SendPacketAll(gnet.NewPacket("Raction", p))
}

// Handle Directionals
func (gs *GameServer) HandleMovementPacket(cp *ClientPacket) {
	action := cp.Data.(game.Action)
	p := cp.Client.Player
	offset := game.DirTable[action]
	oldposx, oldposy := p.GetPos()
	newpos := image.Pt(oldposx+offset.X, oldposy+offset.Y)
	valid := true

	// check terrain collision
	if !gs.Map.CheckCollision(nil, newpos) {
		valid = false
		cp.Reply(gnet.NewPacket("Rchat", "Ouch! You bump into a wall."))
	}

	// check gameobject collision
	for o := range gs.Objects.Chan() {

		// check if collision with Item and item name is flag
		px, py := o.GetPos()
		if px == newpos.X && py == newpos.Y {
			collfn := luar.NewLuaObjectFromName(gs.Lua, "collide")
			res, err := collfn.Call(p, o)
			if err != nil {
				log.Printf("GameServer: HandleMovementPacket: Lua error: %s", err)
				return
			}

			// only update position if collide returns true
			if thebool, ok := res.(bool); !ok || !thebool {
				log.Printf("GameServer: HandleMovementPacket: Lua collision failed")
				valid = false
			} else {
				// tell everyone that the colliders changed
				gs.SendPacketAll(gnet.NewPacket("Raction", o))
			}

			if o.GetTag("player") {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("Ouch! You bump into %s.", o.GetName())))

				// check if other player's got the goods
				for sub := range o.GetSubObjects().Chan() {
					if sub.GetTag("item") == true {
						// swap pop'n'lock

						// remove item from player
						swap := o.RemoveSubObject(sub)
						p.AddSubObject(swap)
						cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You steal a %s!", swap.GetName())))
					}
				}
			}

			if o.GetTag("item") && o.GetTag("gettable") && valid {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You see a %s here.", o.GetName())))
			}
		}
	}

	if valid {
		cp.Client.Player.SetPos(newpos.X, newpos.Y)
		//gs.SendPacketAll(gnet.NewPacket("Raction", p))
	}

}
<commit_msg>Added comment about gs.Graph.Connect.<commit_after>// GameServer: main gameserver struct and functions
// does not know or care about where Packets come from,
// they just arrive on our In port.
package main

import (
	"fmt"
	"github.com/aarzilli/golua/lua"
	"github.com/mischief/goland/game"
	"github.com/mischief/goland/game/gnet"
	"github.com/mischief/goland/game/gutil"
	"github.com/stevedonovan/luar"
	"github.com/trustmaster/goflow"
	"image"
	"log"
	"net"
	"reflect"
)

var (
	Actions = map[game.Action]func(*GameServer, *ClientPacket){
		game.ACTION_ITEM_PICKUP:         Action_ItemPickup,
		game.ACTION_ITEM_DROP:           Action_ItemDrop,
		game.ACTION_ITEM_LIST_INVENTORY: Action_Inventory,
	}

	GS *GameServer
)

type GameServer struct {
	flow.Graph // graph for our procs; see goflow

	Listener   net.Listener       // acceptor of client connections
	PacketChan chan *ClientPacket // channel where clients packets arrive

	*game.DefaultSubject

	Sessions map[int]*WorldSession //client list

	Objects *game.GameObjectMap
	Map     *game.MapChunk

	config *gutil.LuaConfig

	Lua *lua.State
}

func NewGameServer(config *gutil.LuaConfig, ls *lua.State) (*GameServer, error) {
	gs := &GameServer{
		config: config,
	}

	GS = gs

	gs.InitGraphState()

	// add nodes
	gs.Add(NewPacketRouter(gs), "router")
	gs.Add(new(PacketLogger), "logger")

	// connect processes
	// Used to be this, was throwing an error about too many arguments to gs.Graph.Connect:
	// gs.Connect("router", "Log", "logger", "In", make(chan *ClientPacket))
	gs.Connect("router", "Log", "logger", "In")

	// map external ports
	gs.MapInPort("In", "router", "In")

	gs.PacketChan = make(chan *ClientPacket, 5)
	gs.SetInPort("In", gs.PacketChan)

	// observers setup
	gs.DefaultSubject = game.NewDefaultSubject()

	// objects setup
	gs.Objects = game.NewGameObjectMap()

	// lua state
	gs.Lua = ls

	return gs, nil
}

func (gs *GameServer) Debug() bool {
	if debug, err := gs.config.Get("debug", reflect.Bool); err != nil {
		log.Println("GameServer: 'debug' not found in config. defaulting to false")
		return false
	} else {
		return debug.(bool)
	}
}

func (gs *GameServer) Run() {
	gs.Start()

	for {
		conn, err := gs.Listener.Accept()
		if err != nil {
			log.Println("GameServer: acceptor: ", err)
			continue
		}

		ws := NewWorldSession(gs, conn)
		gs.Attach(ws)

		log.Printf("GameServer: New connection from %s", ws.Con.RemoteAddr())

		go ws.ReceiveProc()
	}

	gs.End()
}

func (gs *GameServer) Start() {
	var err error

	// load assets
	log.Print("GameServer: Loading assets")
	if gs.LoadAssets() != true {
		log.Printf("GameServer: LoadAssets failed")
		return
	}

	// setup tcp listener
	log.Printf("GameServer: Starting listener")

	var dialstr string
	defaultdialstr := ":61507"
	if dialconf, err := gs.config.Get("listener", reflect.String); err != nil {
		log.Println("GameServer: 'listen' not found in config. defaulting to ", defaultdialstr)
		dialstr = defaultdialstr
	} else {
		dialstr = dialconf.(string)
	}

	if gs.Listener, err = net.Listen("tcp", dialstr); err != nil {
		log.Fatalf("GameServer: %s", err)
	}

	// setup goflow network
	log.Print("GameServer: Starting flow")

	flow.RunNet(gs)
}

func (gs *GameServer) End() {
}

func (gs *GameServer) LoadMap(file string) bool {
	if gs.Map = game.MapChunkFromFile(file); gs.Map == nil {
		log.Printf("GameServer: LoadMap: failed loading %s", file)
		return false
	}

	log.Printf("GameServer: LoadMap: loaded map %s", file)
	return true
}

func (gs *GameServer) AddObject(obj game.Object) {
	log.Printf("Adding object %s", obj)

	// tell clients about new object
	gs.SendPkStrAll("Rnewobject", obj)
	gs.Objects.Add(obj)
}

func (gs *GameServer) LuaLog(fmt string, args ...interface{}) {
	log.Printf("GameServer: Lua: "+fmt, args...)
}

func (gs *GameServer) GetScriptPath() string {
	defaultpath := "../scripts/?.lua"
	if scriptconf, err := gs.config.Get("scriptpath", reflect.String); err != nil {
		log.Printf("GameServer: GetScriptPath defaulting to %s: %s", defaultpath, err)
		return defaultpath
	} else {
		return scriptconf.(string)
	}
}

// TODO: move these bindings into another file
func (gs *GameServer) BindLua() {
	luar.Register(gs.Lua, "", luar.Map{
		"gs": gs,
	})

	// add our script path here..
	pkgpathscript := `package.path = package.path .. ";" .. gs.GetScriptPath() --";../?.lua"`
	if err := gs.Lua.DoString(pkgpathscript); err != nil {
	}

	Lua_OpenObjectLib(gs.Lua)
}

// load everything from lua scripts
func (gs *GameServer) LoadAssets() bool {
	gs.BindLua()

	if err := gs.Lua.DoString("require('system')"); err != nil {
		log.Printf("GameServer: LoadAssets: %s", err)
		return false
	}

	return true
}

func (gs *GameServer) SendPkStrAll(tag string, data interface{}) {
	gs.SendPacketAll(gnet.NewPacket(tag, data))
}

// send a packet to all clients
func (gs *GameServer) SendPacketAll(pk *gnet.Packet) {
	gs.DefaultSubject.Lock()
	defer gs.DefaultSubject.Unlock()
	for s := gs.DefaultSubject.Observers.Front(); s != nil; s = s.Next() {
		s.Value.(*WorldSession).SendPacket(pk)
	}
}

func (gs *GameServer) HandlePacket(cp *ClientPacket) {

	switch cp.Tag {

	// Tchat: chat message from a client
	case "Tchat":
		// broadcast chat
		chatline := cp.Data.(string)
		gs.SendPacketAll(gnet.NewPacket("Rchat", fmt.Sprintf("[chat] %s: %s", cp.Client.Username, chatline)))

		// Taction: movement request
	case "Taction":
		gs.HandleActionPacket(cp)

		// Tconnect: user establishes new connection
	case "Tconnect":
		username, ok := cp.Data.(string)

		if !ok {
			cp.Reply(gnet.NewPacket("Rerror", "invalid username or conversion failed"))
			break
		} else {
			cp.Client.Username = username
		}

		// make new player for client
		var newplayer game.Object
		newplayer = game.NewGameObject(username)
		newplayer.SetTag("player", true)
		newplayer.SetTag("visible", true)

		// setting this lets players pick up other players, lol
		//newplayer.SetTag("gettable", true)
		newplayer.SetGlyph(game.GLYPH_HUMAN)
		newplayer.SetPos(256/2, 256/2)

		// set the session's object
		cp.Client.Player = newplayer

		// put player object in world
		gs.Objects.Add(newplayer)

		// tell client about all other objects
		for o := range gs.Objects.Chan() {
			if o.GetID() != newplayer.GetID() {
				cp.Reply(gnet.NewPacket("Rnewobject", o))
			}
		}

		// tell all clients about the new player
		gs.SendPacketAll(gnet.NewPacket("Rnewobject", newplayer))

		// greet our new player
		cp.Reply(gnet.NewPacket("Rchat", "Welcome to Goland!"))

	case "Tdisconnect":
		// notify clients this player went away
		Action_ItemDrop(gs, cp)
		gs.Objects.RemoveObject(cp.Client.Player)
		gs.Detach(cp.Client)
		gs.SendPacketAll(gnet.NewPacket("Rdelobject", cp.Client.Player))

	case "Tgetplayer":
		if cp.Client.Player != nil {
			cp.Reply(gnet.NewPacket("Rgetplayer", cp.Client.Player.GetID()))
		} else {
			cp.Reply(gnet.NewPacket("Rerror", "nil Player in WorldSession"))
		}

	case "Tloadmap":
		cp.Reply(gnet.NewPacket("Rloadmap", gs.Map))

	default:
		log.Printf("GameServer: HandlePacket: unknown packet type %s", cp.Tag)
	}
}

// Prevent User from re-adding / picking up item
// Disassociate item with map after action successful
func Action_ItemPickup(gs *GameServer, cp *ClientPacket) {
	p := cp.Client.Player

	// we assume our cp.Data is a game.Action of type ACTION_ITEM_PICKUP
	// act accordingly

	for o := range gs.Objects.Chan() {
		// if same pos.. and gettable
		if game.SamePos(o, p) && o.GetTag("gettable") {
			// pickup item.
			log.Printf("GameServer: Action_ItemPickup: %s picking up %s", p, o)
			o.SetTag("visible", false)
			o.SetTag("gettable", false)
			o.SetPos(0, 0)
			p.AddSubObject(o)

			// update clients with the new state of this object
			gs.SendPacketAll(gnet.NewPacket("Raction", o))
			cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You pick up a %s.", o.GetName())))
		}
	}
}

// Player drops the item indicated by the ID from their inventory
// TODO: this drops all items right now. make it drop individual items
func Action_ItemDrop(gs *GameServer, cp *ClientPacket) {
	p := cp.Client.Player
	for sub := range p.GetSubObjects().Chan() {
		log.Printf("GameServer: Action_ItemDrop: %s dropping %s", p, sub)

		// remove item from player
		p.RemoveSubObject(sub)
		// put it where the player was
		sub.SetPos(p.GetPos())
		// make it visible
		sub.SetTag("visible", true)
		sub.SetTag("gettable", true)

		// update clients with the new state of this object
		gs.SendPacketAll(gnet.NewPacket("Raction", sub))
		cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You drop a %s.", sub.GetName())))
	}
}

// List items in Player's inventory
func Action_Inventory(gs *GameServer, cp *ClientPacket) {
	plobj := cp.Client.Player

	inv := plobj.GetSubObjects().Chan()

	if len(inv) == 0 {
		cp.Reply(gnet.NewPacket("Rchat", "You have 0 items."))
	} else {
		counts := make(map[string]int)
		for sub := range inv {
			n := sub.GetName()
			if _, ok := counts[n]; ok {
				counts[n]++
			} else {
				counts[n] = 1
			}
		}

		for n, c := range counts {
			if c == 1 {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You have a %s.", n)))
			} else {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You have %d %ss.", c, n)))
			}

		}
	}

}

// Top level handler for Taction packets
func (gs *GameServer) HandleActionPacket(cp *ClientPacket) {
	action := cp.Data.(game.Action)
	p := cp.Client.Player

	_, isdir := game.DirTable[action]
	if isdir {
		gs.HandleMovementPacket(cp)
	}

	// check if this action is in our Actions table, if so execute it
	if f, ok := Actions[action]; ok {
		f(gs, cp)
	}

	gs.SendPacketAll(gnet.NewPacket("Raction", p))
}

// Handle Directionals
func (gs *GameServer) HandleMovementPacket(cp *ClientPacket) {
	action := cp.Data.(game.Action)
	p := cp.Client.Player
	offset := game.DirTable[action]
	oldposx, oldposy := p.GetPos()
	newpos := image.Pt(oldposx+offset.X, oldposy+offset.Y)
	valid := true

	// check terrain collision
	if !gs.Map.CheckCollision(nil, newpos) {
		valid = false
		cp.Reply(gnet.NewPacket("Rchat", "Ouch! You bump into a wall."))
	}

	// check gameobject collision
	for o := range gs.Objects.Chan() {

		// check if collision with Item and item name is flag
		px, py := o.GetPos()
		if px == newpos.X && py == newpos.Y {
			collfn := luar.NewLuaObjectFromName(gs.Lua, "collide")
			res, err := collfn.Call(p, o)
			if err != nil {
				log.Printf("GameServer: HandleMovementPacket: Lua error: %s", err)
				return
			}

			// only update position if collide returns true
			if thebool, ok := res.(bool); !ok || !thebool {
				log.Printf("GameServer: HandleMovementPacket: Lua collision failed")
				valid = false
			} else {
				// tell everyone that the colliders changed
				gs.SendPacketAll(gnet.NewPacket("Raction", o))
			}

			if o.GetTag("player") {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("Ouch! You bump into %s.", o.GetName())))

				// check if other player's got the goods
				for sub := range o.GetSubObjects().Chan() {
					if sub.GetTag("item") == true {
						// swap pop'n'lock

						// remove item from player
						swap := o.RemoveSubObject(sub)
						p.AddSubObject(swap)
						cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You steal a %s!", swap.GetName())))
					}
				}
			}

			if o.GetTag("item") && o.GetTag("gettable") && valid {
				cp.Reply(gnet.NewPacket("Rchat", fmt.Sprintf("You see a %s here.", o.GetName())))
			}
		}
	}

	if valid {
		cp.Client.Player.SetPos(newpos.X, newpos.Y)
		//gs.SendPacketAll(gnet.NewPacket("Raction", p))
	}

}
<|endoftext|>


<commit_before>// Package main is the irmad executable.
package main

import "github.com/privacybydesign/irmago/server/irmad/cmd"

func main() {
	cmd.Execute()
}
<commit_msg>Remove old irmad executable<commit_after><|endoftext|>


<commit_before>package server

import (
	"net"
	"testing"
	"time"

	"github.com/cashshuffle/cashshuffle/message"
	"github.com/stretchr/testify/assert"
)

func TestTrackStats(t *testing.T) {
	tracker := &Tracker{
		connections: map[net.Conn]*trackerData{
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
		},
		pools: map[int]map[uint32]interface{}{
			1: {
				1: nil,
				2: nil,
				3: nil,
				4: nil,
				5: nil,
			},
			2: {
				6: nil,
				7: nil,
				8: nil,
			},
		},
		poolAmounts: map[int]uint64{
			1: 100,
			2: 1000,
		},
		poolTypes: map[int]message.ShuffleType{
			1: 0,
			2: 0,
		},
		fullPools: map[int]interface{}{
			1: nil,
		},
		poolSize:    5,
		shufflePort: 3000,
	}

	stats := tracker.Stats()

	assert.Equal(t, 8, stats.Connections)
	assert.Equal(t, 5, stats.PoolSize)
	assert.Equal(t, 2, len(stats.Pools))
	assert.Equal(t, 3000, stats.ShufflePort)
	assert.Contains(t, stats.Pools,
		PoolStats{
			Members: 5,
			Amount:  100,
			Type:    "DEFAULT",
			Full:    true,
		},
		PoolStats{
			Members: 3,
			Amount:  1000,
			Type:    "DEFAULT",
			Full:    false,
		},
	)
}

type fakeConn struct {
	f interface{}
}

func (fc *fakeConn) Read(b []byte) (n int, err error)   { return 0, nil }
func (fc *fakeConn) Write(b []byte) (n int, err error)  { return 0, nil }
func (fc *fakeConn) Close() error                       { return nil }
func (fc *fakeConn) LocalAddr() net.Addr                { return &fakeAddr{} }
func (fc *fakeConn) RemoteAddr() net.Addr               { return &fakeAddr{} }
func (fc *fakeConn) SetDeadline(t time.Time) error      { return nil }
func (fc *fakeConn) SetReadDeadline(t time.Time) error  { return nil }
func (fc *fakeConn) SetWriteDeadline(t time.Time) error { return nil }

type fakeAddr struct{}

func (fa *fakeAddr) Network() string { return "" }
func (fa *fakeAddr) String() string  { return "" }
<commit_msg>Test for Dust type<commit_after>package server

import (
	"net"
	"testing"
	"time"

	"github.com/cashshuffle/cashshuffle/message"
	"github.com/stretchr/testify/assert"
)

func TestTrackStats(t *testing.T) {
	tracker := &Tracker{
		connections: map[net.Conn]*trackerData{
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
			&fakeConn{}: {},
		},
		pools: map[int]map[uint32]interface{}{
			1: {
				1: nil,
				2: nil,
				3: nil,
				4: nil,
				5: nil,
			},
			2: {
				6: nil,
				7: nil,
				8: nil,
			},
		},
		poolAmounts: map[int]uint64{
			1: 100,
			2: 1000,
		},
		poolTypes: map[int]message.ShuffleType{
			1: 0,
			2: 1,
		},
		fullPools: map[int]interface{}{
			1: nil,
		},
		poolSize:    5,
		shufflePort: 3000,
	}

	stats := tracker.Stats()

	assert.Equal(t, 8, stats.Connections)
	assert.Equal(t, 5, stats.PoolSize)
	assert.Equal(t, 2, len(stats.Pools))
	assert.Equal(t, 3000, stats.ShufflePort)
	assert.Contains(t, stats.Pools,
		PoolStats{
			Members: 5,
			Amount:  100,
			Type:    "DEFAULT",
			Full:    true,
		},
		PoolStats{
			Members: 3,
			Amount:  1000,
			Type:    "DUST",
			Full:    false,
		},
	)
}

type fakeConn struct {
	f interface{}
}

func (fc *fakeConn) Read(b []byte) (n int, err error)   { return 0, nil }
func (fc *fakeConn) Write(b []byte) (n int, err error)  { return 0, nil }
func (fc *fakeConn) Close() error                       { return nil }
func (fc *fakeConn) LocalAddr() net.Addr                { return &fakeAddr{} }
func (fc *fakeConn) RemoteAddr() net.Addr               { return &fakeAddr{} }
func (fc *fakeConn) SetDeadline(t time.Time) error      { return nil }
func (fc *fakeConn) SetReadDeadline(t time.Time) error  { return nil }
func (fc *fakeConn) SetWriteDeadline(t time.Time) error { return nil }

type fakeAddr struct{}

func (fa *fakeAddr) Network() string { return "" }
func (fa *fakeAddr) String() string  { return "" }
<|endoftext|>