<commit_before>package gom

import (
	"fmt"
	"reflect"
)

type CreateSql func(TableModel) (string, []interface{})

type BinaryUnmarshaler interface {
	UnmarshalBinary(dbytes []byte) (interface{}, error)
}

type SqlGenerator struct {
	createSql   CreateSql
	tableModels []TableModel
}
type SqlFactory interface {
	Insert(TableModel) (string, []interface{})
	Update(TableModel) (string, []interface{})
	Replace(TableModel) (string, []interface{})
	Delete(TableModel) (string, []interface{})
	Query(TableModel) (string, []interface{})
}
type RowChooser interface {
	Scan(dest ...interface{}) error
}

type TableModel struct {
	ModelType  reflect.Type
	ModelValue reflect.Value
	TableName  string
	Columns    []Column
	Primary    Column
	Cnd        Condition
}
type Column struct {
	ColumnType reflect.Type
	ColumnName string
	FieldName  string
	QueryField string
	IsPrimary  bool
	Auto       bool
}
type OrderType int

const (
	_ OrderType = iota
	Asc
	Desc
)

type linkType int

const (
	_ linkType = iota
	And
	Or
)

type Condition interface {
	State() string
	Value() []interface{}
	Or(sql string, values ...interface{}) Condition
	And(sql string, values ...interface{}) Condition
	AndIn(name string, values ...interface{}) Condition
	OrIn(name string, values ...interface{}) Condition
	Pager(index int, size int) Condition
	OrderBy(name string, tp OrderType) Condition
}
type Order interface {
	Order() string
}
type Orders struct {
	orderName string
	orderType OrderType
}

func (o Orders) Order() string {
	result := " ORDER BY `" + o.orderName + "` "
	if o.orderType == Asc {
		result += "ASC"
	} else {
		result += "DESC"
	}
	return result
}

type Pager interface {
	Pager() (int, int)
}
type Pagers struct {
	pageIndex int
	pageSize  int
}

func (p Pagers) Pager() (int, int) {
	return p.pageIndex, p.pageSize
}

type Conditions struct {
	conditionItems []ConditionItem
	order          Order
	pager          Pager
}
type ConditionItem struct {
	linkType linkType
	states   string
	values   []interface{}
}

func Cnd(sql string, values ...interface{}) Condition {
	if sql == "" {
		return &Conditions{}
	} else {
		return &Conditions{conditionItems: []ConditionItem{{linkType: And, states: sql, values: splitArrays(values)}}}
	}
}
func (c *Conditions) State() string {
	results := ""
	length := len(c.conditionItems)
	if length > 0 {
		if debug {
			fmt.Println(length, c.conditionItems)
		}
		for i := 0; i < length; i++ {
			if i == 0 {
				results += " WHERE "
			} else {
				if c.conditionItems[i].linkType == And {
					results += " AND "
				} else {
					results += " OR "
				}
			}
			results += c.conditionItems[i].states
		}
	}
	if c.order != nil {
		results += c.order.Order()
	}
	if c.pager != nil {
		results += " LIMIT ?,?;"
	}
	return results
}
func (c *Conditions) Value() []interface{} {
	results := []interface{}{}
	length := len(c.conditionItems)
	if length > 0 {
		for i := 0; i < length; i++ {

			results = append(results, c.conditionItems[i].values...)
		}
	}
	if c.pager != nil {
		page, index := c.pager.Pager()
		results = append(results, page, index)
	}
	return results
}
func (c *Conditions) And(sql string, values ...interface{}) Condition {
	c.conditionItems = append(c.conditionItems, ConditionItem{linkType: And, states: sql, values: splitArrays(values)})
	return c
}
func (c *Conditions) Or(sql string, values ...interface{}) Condition {
	c.conditionItems = append(c.conditionItems, ConditionItem{linkType: Or, states: sql, values: splitArrays(values)})
	return c
}
func (c *Conditions) AndIn(name string, values ...interface{}) Condition {
	if len(values) > 0 {
		sql, datas := makeInSql(name, values...)
		c.conditionItems = append(c.conditionItems, ConditionItem{linkType: And, states: sql, values: splitArrays(datas)})
	}
	return c
}

func (c *Conditions) OrIn(name string, values ...interface{}) Condition {
	if len(values) > 0 {
		sql, datas := makeInSql(name, values...)
		c.conditionItems = append(c.conditionItems, ConditionItem{linkType: Or, states: sql, values: splitArrays(datas)})
	}
	return c
}
func (c *Conditions) Pager(index int, size int) Condition {
	c.pager = Pagers{index, size}
	return c
}

func (c *Conditions) OrderBy(name string, tp OrderType) Condition {
	c.order = Orders{name, tp}
	return c
}
func splitArrays(values interface{}) []interface{} {
	var results []interface{}
	val := reflect.ValueOf(values)
	_, ptr, sli := getType(values)
	if ptr {
		val = val.Elem()
	}
	if sli {
		lens := val.Len()
		if lens > 0 {
			for i := 0; i < lens; i++ {
				datas := splitArrays(val.Index(i).Interface())
				results = append(results, datas...)
			}
		}
	} else {
		results = append(results, val.Interface())
	}
	return results

}

func makeInSql(name string, values ...interface{}) (string, []interface{}) {
	sql := name + " in ("
	var datas []interface{}
	if len(values) == 0 {
		return "", datas
	}
	datas = splitArrays(values)
	for i := 0; i < len(datas); i++ {
		if i == 0 {
			sql += " ? "
		} else {
			sql += ", ? "
		}
	}
	sql += ")"
	if debug {
		fmt.Println("make in sql was :", sql, datas)
	}
	return sql, datas
}

func (mo TableModel) InsertValues() []interface{} {
	var interfaces []interface{}
	results := reflect.Indirect(reflect.ValueOf(&interfaces))
	for _, column := range mo.Columns {
		vars := reflect.ValueOf(mo.ModelValue.FieldByName(column.FieldName).Interface())
		if results.Kind() == reflect.Ptr {
			results.Set(reflect.Append(results, vars.Addr()))
		} else {
			results.Set(reflect.Append(results, vars))
		}
	}
	return interfaces
}
func (m TableModel) GetPrimary() interface{} {
	return m.ModelValue.FieldByName(m.Primary.FieldName).Interface()
}
func (m TableModel) GetPrimaryCondition() Condition {
	if IsEmpty(m.GetPrimary()) || m.Primary.IsPrimary == false {
		return nil
	} else {
		return &Conditions{conditionItems: []ConditionItem{{And, "`" + m.Primary.ColumnName + "` = ?", []interface{}{m.GetPrimary()}}}}
	}
}
<commit_msg>修复Cnd解析错误的bug<commit_after>package gom

import (
	"fmt"
	"reflect"
)

type CreateSql func(TableModel) (string, []interface{})

type BinaryUnmarshaler interface {
	UnmarshalBinary(dbytes []byte) (interface{}, error)
}

type SqlGenerator struct {
	createSql   CreateSql
	tableModels []TableModel
}
type SqlFactory interface {
	Insert(TableModel) (string, []interface{})
	Update(TableModel) (string, []interface{})
	Replace(TableModel) (string, []interface{})
	Delete(TableModel) (string, []interface{})
	Query(TableModel) (string, []interface{})
}
type RowChooser interface {
	Scan(dest ...interface{}) error
}

type TableModel struct {
	ModelType  reflect.Type
	ModelValue reflect.Value
	TableName  string
	Columns    []Column
	Primary    Column
	Cnd        Condition
}
type Column struct {
	ColumnType reflect.Type
	ColumnName string
	FieldName  string
	QueryField string
	IsPrimary  bool
	Auto       bool
}
type OrderType int

const (
	_ OrderType = iota
	Asc
	Desc
)

type linkType int

const (
	_ linkType = iota
	And
	Or
)

type Condition interface {
	State() string
	Value() []interface{}
	Or(sql string, values ...interface{}) Condition
	And(sql string, values ...interface{}) Condition
	AndIn(name string, values ...interface{}) Condition
	OrIn(name string, values ...interface{}) Condition
	Pager(index int, size int) Condition
	OrderBy(name string, tp OrderType) Condition
}
type Order interface {
	Order() string
}
type Orders struct {
	orderName string
	orderType OrderType
}

func (o Orders) Order() string {
	result := " ORDER BY `" + o.orderName + "` "
	if o.orderType == Asc {
		result += "ASC"
	} else {
		result += "DESC"
	}
	return result
}

type Pager interface {
	Pager() (int, int)
}
type Pagers struct {
	pageIndex int
	pageSize  int
}

func (p Pagers) Pager() (int, int) {
	return p.pageIndex, p.pageSize
}

type Conditions struct {
	conditionItems []ConditionItem
	order          Order
	pager          Pager
}
type ConditionItem struct {
	linkType linkType
	states   string
	values   []interface{}
}

func Cnd(sql string, values ...interface{}) Condition {
	if sql == "" {
		return &Conditions{}
	} else {
		return &Conditions{conditionItems: []ConditionItem{{linkType: And, states: sql, values: splitArrays(values)}}}
	}
}
func (c *Conditions) State() string {
	results := ""
	length := len(c.conditionItems)
	if length > 0 {
		if debug {
			fmt.Println("ConditionItem=====", length, c.conditionItems)
		}
		for i := 0; i < length; i++ {
			if i == 0 {
				results += " WHERE "
			} else {
				if c.conditionItems[i].linkType == And {
					results += " AND "
				} else {
					results += " OR "
				}
			}
			results += c.conditionItems[i].states
		}
	}
	if c.order != nil {
		results += c.order.Order()
	}
	if c.pager != nil {
		results += " LIMIT ?,?;"
	}
	return results
}
func (c *Conditions) Value() []interface{} {
	results := []interface{}{}
	length := len(c.conditionItems)
	if length > 0 {
		for i := 0; i < length; i++ {

			results = append(results, c.conditionItems[i].values...)
		}
	}
	if c.pager != nil {
		page, index := c.pager.Pager()
		results = append(results, page, index)
	}
	return results
}
func (c *Conditions) And(sql string, values ...interface{}) Condition {
	c.conditionItems = append(c.conditionItems, ConditionItem{linkType: And, states: sql, values: splitArrays(values)})
	return c
}
func (c *Conditions) Or(sql string, values ...interface{}) Condition {
	c.conditionItems = append(c.conditionItems, ConditionItem{linkType: Or, states: sql, values: splitArrays(values)})
	return c
}
func (c *Conditions) AndIn(name string, values ...interface{}) Condition {
	if len(values) > 0 {
		sql, datas := makeInSql(name, values...)
		c.conditionItems = append(c.conditionItems, ConditionItem{linkType: And, states: sql, values: splitArrays(datas)})
	}
	return c
}

func (c *Conditions) OrIn(name string, values ...interface{}) Condition {
	if len(values) > 0 {
		sql, datas := makeInSql(name, values...)
		c.conditionItems = append(c.conditionItems, ConditionItem{linkType: Or, states: sql, values: splitArrays(datas)})
	}
	return c
}
func (c *Conditions) Pager(index int, size int) Condition {
	c.pager = Pagers{index, size}
	return c
}

func (c *Conditions) OrderBy(name string, tp OrderType) Condition {
	c.order = Orders{name, tp}
	return c
}
func splitArrays(values interface{}) []interface{} {
	var results []interface{}
	val := reflect.ValueOf(values)
	_, ptr, sli := getType(values)
	if ptr {
		val = val.Elem()
	}
	if sli {
		lens := val.Len()
		if lens > 0 {
			for i := 0; i < lens; i++ {
				datas := splitArrays(val.Index(i).Interface())
				results = append(results, datas...)
			}
		}
	} else {
		results = append(results, val.Interface())
	}
	return results

}

func makeInSql(name string, values ...interface{}) (string, []interface{}) {
	sql := name + " in ("
	var datas []interface{}
	if len(values) == 0 {
		return "", datas
	}
	datas = splitArrays(values)
	for i := 0; i < len(datas); i++ {
		if i == 0 {
			sql += " ? "
		} else {
			sql += ", ? "
		}
	}
	sql += ")"
	if debug {
		fmt.Println("make in sql was :", sql, datas)
	}
	return sql, datas
}

func (mo TableModel) InsertValues() []interface{} {
	var interfaces []interface{}
	results := reflect.Indirect(reflect.ValueOf(&interfaces))
	for _, column := range mo.Columns {
		vars := reflect.ValueOf(mo.ModelValue.FieldByName(column.FieldName).Interface())
		if results.Kind() == reflect.Ptr {
			results.Set(reflect.Append(results, vars.Addr()))
		} else {
			results.Set(reflect.Append(results, vars))
		}
	}
	return interfaces
}
func (m TableModel) GetPrimary() interface{} {
	return m.ModelValue.FieldByName(m.Primary.FieldName).Interface()
}
func (m TableModel) GetPrimaryCondition() Condition {
	if IsEmpty(m.GetPrimary()) || m.Primary.IsPrimary == false {
		return nil
	} else {
		return &Conditions{conditionItems: []ConditionItem{{And, "`" + m.Primary.ColumnName + "` = ?", []interface{}{m.GetPrimary()}}}}
	}
}
<|endoftext|>


<commit_before>package model

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"

	. "../common"
	"time"
)

var orm *xorm.Engine

func SetEngine() *xorm.Engine {
	Log.Info("db initializing...")
	var err error
	username := Cfg.MustValue("db", "username", "root")
	password := Cfg.MustValue("db", "password", "meet771027")
	dbName := Cfg.MustValue("db", "db_name", "im")
	orm, err = xorm.NewEngine("mysql", username+":"+password+"@/"+dbName+"?charset=utf8")
	PanicIf(err)
	orm.TZLocation = time.Local
	orm.Logger = xorm.NewSimpleLogger(Log.GetWriter())
	return orm
}
<commit_msg>删除model/base.go<commit_after><|endoftext|>


<commit_before>package scene

import (
	"image"
	"strconv"

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

const (
	ctrlPanelHeight = 220
	fps             = 60
)

// game represents a scene object for game
type game struct {
	currentStage     int
	nextScene        simra.Driver
	field            simra.Sprite
	ctrlPanel        simra.Sprite
	ctrlButton       []simra.Sprite
	currentFrame     int64
	players          map[string]uniter
	uniters          map[string]uniter
	unitPopTimeTable unitPopTimeTable
	pubsub           *simra.PubSub
	gameState        gameState
	currentRunLoop   func()
	eventqueue       chan *command
	selection        *selection
}

type gameState int

const (
	gameStateInitial gameState = iota
	gameStateRunning
)

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

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

	// initialize sprites
	g.initialize()

	simra.LogDebug("[OUT]")
}

func (g *game) updateGameState(newState gameState) {
	g.gameState = newState
	switch newState {
	case gameStateInitial:
		g.currentRunLoop = g.initialRunLoop
	case gameStateRunning:
		g.currentRunLoop = g.runningRunLoop
	default:
		//nop
	}

	// reset frame
	g.currentFrame = 0
}

type selection struct {
	selecting *simra.Sprite
	class     string
}

func (s *selection) OnEvent(i interface{}) {
	c, ok := i.(*command)
	if !ok {
		panic("unexpected command received. fatal.")
	}

	switch c.commandtype {
	case commandUpdateSelection:
		s.selecting = c.data.(*simra.Sprite)
		simra.LogDebug("selection updated: %v", s.selecting)
	case commandUnsetSelection:
		s.selecting = nil
		simra.LogDebug("selection updated: nil")
	default:
		// nop
	}
}

type ctrlButtonTouchListener struct {
	id   int
	game *game
}

func (c *ctrlButtonTouchListener) OnTouchBegin(x, y float32) {
	// nop
}

func (c *ctrlButtonTouchListener) OnTouchMove(x, y float32) {
	// nop
}

func (c *ctrlButtonTouchListener) OnTouchEnd(x, y float32) {
	c.game.eventqueue <- newCommand(commandUpdateSelection, &c.game.ctrlButton[c.id])
}

func (g *game) initCtrlPanel() {
	g.ctrlPanel.W = config.ScreenWidth
	g.ctrlPanel.H = ctrlPanelHeight
	g.ctrlPanel.X = config.ScreenWidth / 2
	g.ctrlPanel.Y = g.ctrlPanel.H / 2
	simra.GetInstance().AddSprite("ctrl_panel.png",
		image.Rect(0, 0, 1280, 240),
		&g.ctrlPanel)

	g.ctrlButton = make([]simra.Sprite, 9)
	for i := range g.ctrlButton {
		g.ctrlButton[i].W = 64
		g.ctrlButton[i].H = 64
		g.ctrlButton[i].X = (float32)(1010 + (64+45)*(i%3))
		g.ctrlButton[i].Y = (float32)(44 + (64+5)*(i/3))
		simra.GetInstance().AddSprite("player.png",
			image.Rect(0, 0, 384, 384),
			&g.ctrlButton[i])

		g.ctrlButton[i].AddTouchListener(&ctrlButtonTouchListener{id: i, game: g})
	}
}

func (g *game) initField() {
	g.field.W = config.ScreenWidth
	g.field.H = config.ScreenHeight
	g.field.X = config.ScreenWidth / 2
	g.field.Y = config.ScreenHeight / 2
	simra.GetInstance().AddSprite("field1.png",
		image.Rect(0, 0, 1280, 720),
		&g.field)
	g.field.AddTouchListener(&fieldTouchListener{game: g})
}

type fieldTouchListener struct {
	game *game
}

// OnTouchBegin is called when game scene is Touched.
func (f *fieldTouchListener) OnTouchBegin(x, y float32) {
	// nop
}

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

func (g *game) unitIDBySprite(s *simra.Sprite) string {
	var unitID string
	if s == &g.ctrlButton[6] {
		unitID = "player"
	} else if s == &g.ctrlButton[7] {
		unitID = "player"
	} else if s == &g.ctrlButton[8] {
		unitID = "player"
	} else if s == &g.ctrlButton[3] {
		unitID = "player"
	} else if s == &g.ctrlButton[4] {
		unitID = "player"
	} else if s == &g.ctrlButton[5] {
		unitID = "player"
	} else if s == &g.ctrlButton[0] {
		unitID = "player"
	} else if s == &g.ctrlButton[1] {
		unitID = "player"
	} else if s == &g.ctrlButton[2] {
		unitID = "player"
	}
	return unitID
}

// OnTouchEnd is called when game scene is Touched and it is released.
func (f *fieldTouchListener) OnTouchEnd(x, y float32) {
	if y <= ctrlPanelHeight {
		return
	}

	if f.game.selection.selecting == nil {
		return
	}

	unitID := f.game.unitIDBySprite(f.game.selection.selecting)
	id := strconv.Itoa(len(f.game.players))

	if unitID != "" {
		// TODO: every alley spawn occurs file I/O. lol
		// loading texture in advance is needed.
		p := newUnit(id, unitID, f.game)
		p.SetPosition(x, y)
		f.game.players[id] = p
		f.game.pubsub.Subscribe(p.GetID(), p)
		f.game.eventqueue <- newCommand(commandSpawn, p)
	}
}

func (g *game) initPlayer() {
	g.players = make(map[string]uniter)
	p := newUnit("player", "player", g)
	g.players["player"] = p
	g.pubsub.Subscribe(p.GetID(), p)
}

type unitPopTime struct {
	unitID          string
	popTime         int64
	initialPosition position
}

type unitPopTimeTable []*unitPopTime

func (g *game) initUnits(json string) {
	// TODO: load from json file
	units := make(map[string]uniter)
	units["unit1"] = newUnit("unit1", "", g)
	units["unit2"] = newUnit("unit2", "", g)
	units["unit3"] = newUnit("unit3", "", g)

	// TODO: unitpopTimeTable should be sorted by popTime
	g.unitPopTimeTable = append(g.unitPopTimeTable,
		&unitPopTime{
			unitID:          "unit1",
			popTime:         3 * fps,
			initialPosition: position{config.ScreenWidth - 32, config.ScreenHeight / 6 * 5},
		})
	g.unitPopTimeTable = append(g.unitPopTimeTable,
		&unitPopTime{
			unitID:          "unit2",
			popTime:         4 * fps,
			initialPosition: position{config.ScreenWidth - 32, config.ScreenHeight / 6 * 4},
		})
	g.unitPopTimeTable = append(g.unitPopTimeTable,
		&unitPopTime{
			unitID:          "unit3",
			popTime:         5 * fps,
			initialPosition: position{config.ScreenWidth - 32, config.ScreenHeight / 6 * 3},
		})

	g.uniters = units
}

func (g *game) popUnits() []uniter {
	poppedUnits := make([]uniter, 0)
	for _, v := range g.unitPopTimeTable {
		if v.popTime <= g.currentFrame {
			// pop unit
			u := g.uniters[v.unitID]
			u.SetPosition(v.initialPosition.x, v.initialPosition.y)
			poppedUnits = append(poppedUnits, u)
			continue
		}
	}

	if len(poppedUnits) != 0 {
		// remove popped units from unitPopTimeTable
		g.unitPopTimeTable = g.unitPopTimeTable[len(poppedUnits):]
	}

	return poppedUnits
}

func (g *game) initialize() {
	g.pubsub = simra.NewPubSub()
	g.eventqueue = make(chan *command, 256)
	g.initField()
	g.initCtrlPanel()
	g.initPlayer()
	g.initUnits("") // TODO: input JSON string
	g.selection = &selection{}
	simra.GetInstance().AddTouchListener(g)
	g.pubsub.Subscribe("god", g)
	g.pubsub.Subscribe("selection", g.selection)
	g.updateGameState(gameStateInitial)
}

func (g *game) eventFetch() []*command {
	// note:
	// if new events are pushed while fetching,
	// they should be fetched next run loop to
	// avoid inifinite event fetching.

	qlen := len(g.eventqueue)
	if qlen == 0 {
		return nil
	}

	c := make([]*command, qlen)
	for i := 0; i < qlen; i++ {
		c[i] = <-g.eventqueue
	}
	return c
}

func (g *game) OnEvent(i interface{}) {
	c, ok := i.(*command)
	if !ok {
		// should be a command. ignore.
		return
	}

	_, ok = c.data.(*game)
	if !ok {
		// this is not for me
		return
	}

	switch c.commandtype {
	case commandGoToInitialState:
		g.updateGameState(gameStateInitial)
	case commandGoToRunningState:
		g.updateGameState(gameStateRunning)
	}
}

func (g *game) initialRunLoop() {
	commands := g.eventFetch()
	for _, v := range commands {
		g.pubsub.Publish(v)
	}
	g.players["player"].DoAction()
}

func (g *game) runningRunLoop() {
	poppedUnits := g.popUnits()
	for _, v := range poppedUnits {
		err := g.pubsub.Subscribe(v.GetID(), v)
		if err != nil {
			panic("failed to subscribe. fatal.")
		}

		// generate spawn command
		g.eventqueue <- newCommand(commandSpawn, v)
	}

	// event fetch and publish to all subscribers
	commands := g.eventFetch()
	for _, v := range commands {
		g.pubsub.Publish(v)
	}

	// invoke action for all units
	for _, v := range g.players {
		v.DoAction()
	}
	for _, v := range g.uniters {
		v.DoAction()
	}
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (g *game) Drive() {
	defer func() {
		g.currentFrame++
	}()

	if g.nextScene != nil {
		simra.GetInstance().SetScene(g.nextScene)
	}
	g.currentRunLoop()
}

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

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

// OnTouchEnd is called when game scene is Touched and it is released.
func (g *game) OnTouchEnd(x, y float32) {
	if g.gameState == gameStateInitial {
		if y > ctrlPanelHeight {
			unitID := g.unitIDBySprite(g.selection.selecting)
			if unitID == "" {
				return
			}
			g.players[unitID].SetPosition(x, y)
			g.eventqueue <- newCommand(commandSpawn, g.players[unitID])
			g.eventqueue <- newCommand(commandGoToRunningState, g)
		}
	}
	//g.nextScene = &result{currentStage: g.currentStage}
}
<commit_msg>transition game state after first ally's summoning<commit_after>package scene

import (
	"image"
	"strconv"

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

const (
	ctrlPanelHeight = 220
	fps             = 60
)

// game represents a scene object for game
type game struct {
	currentStage     int
	nextScene        simra.Driver
	field            simra.Sprite
	ctrlPanel        simra.Sprite
	ctrlButton       []simra.Sprite
	currentFrame     int64
	players          map[string]uniter
	uniters          map[string]uniter
	unitPopTimeTable unitPopTimeTable
	pubsub           *simra.PubSub
	gameState        gameState
	currentRunLoop   func()
	eventqueue       chan *command
	selection        *selection
}

type gameState int

const (
	gameStateInitial gameState = iota
	gameStateRunning
)

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

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

	// initialize sprites
	g.initialize()

	simra.LogDebug("[OUT]")
}

func (g *game) updateGameState(newState gameState) {
	g.gameState = newState
	switch newState {
	case gameStateInitial:
		g.currentRunLoop = g.initialRunLoop
	case gameStateRunning:
		g.currentRunLoop = g.runningRunLoop
	default:
		//nop
	}

	// reset frame
	g.currentFrame = 0
}

type selection struct {
	selecting *simra.Sprite
	class     string
	game      *game
}

func (s *selection) OnEvent(i interface{}) {
	c, ok := i.(*command)
	if !ok {
		panic("unexpected command received. fatal.")
	}

	switch c.commandtype {
	case commandSpawned:
		if s.game.gameState == gameStateInitial {
			// this is first ally's summoning.
			// transition gameState from initial to running.
			s.game.eventqueue <- newCommand(commandGoToRunningState, s.game)
		}
	case commandUpdateSelection:
		s.selecting = c.data.(*simra.Sprite)
		simra.LogDebug("selection updated: %v", s.selecting)
	case commandUnsetSelection:
		s.selecting = nil
		simra.LogDebug("selection updated: nil")
	default:
		// nop
	}
}

type ctrlButtonTouchListener struct {
	id   int
	game *game
}

func (c *ctrlButtonTouchListener) OnTouchBegin(x, y float32) {
	// nop
}

func (c *ctrlButtonTouchListener) OnTouchMove(x, y float32) {
	// nop
}

func (c *ctrlButtonTouchListener) OnTouchEnd(x, y float32) {
	c.game.eventqueue <- newCommand(commandUpdateSelection, &c.game.ctrlButton[c.id])
}

func (g *game) initCtrlPanel() {
	g.ctrlPanel.W = config.ScreenWidth
	g.ctrlPanel.H = ctrlPanelHeight
	g.ctrlPanel.X = config.ScreenWidth / 2
	g.ctrlPanel.Y = g.ctrlPanel.H / 2
	simra.GetInstance().AddSprite("ctrl_panel.png",
		image.Rect(0, 0, 1280, 240),
		&g.ctrlPanel)

	g.ctrlButton = make([]simra.Sprite, 9)
	for i := range g.ctrlButton {
		g.ctrlButton[i].W = 64
		g.ctrlButton[i].H = 64
		g.ctrlButton[i].X = (float32)(1010 + (64+45)*(i%3))
		g.ctrlButton[i].Y = (float32)(44 + (64+5)*(i/3))
		simra.GetInstance().AddSprite("player.png",
			image.Rect(0, 0, 384, 384),
			&g.ctrlButton[i])

		g.ctrlButton[i].AddTouchListener(&ctrlButtonTouchListener{id: i, game: g})
	}
}

func (g *game) initField() {
	g.field.W = config.ScreenWidth
	g.field.H = config.ScreenHeight
	g.field.X = config.ScreenWidth / 2
	g.field.Y = config.ScreenHeight / 2
	simra.GetInstance().AddSprite("field1.png",
		image.Rect(0, 0, 1280, 720),
		&g.field)
	g.field.AddTouchListener(&fieldTouchListener{game: g})
}

type fieldTouchListener struct {
	game *game
}

// OnTouchBegin is called when game scene is Touched.
func (f *fieldTouchListener) OnTouchBegin(x, y float32) {
	// nop
}

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

func (g *game) unitIDBySprite(s *simra.Sprite) string {
	var unitID string
	if s == &g.ctrlButton[6] {
		unitID = "player"
	} else if s == &g.ctrlButton[7] {
		unitID = "player"
	} else if s == &g.ctrlButton[8] {
		unitID = "player"
	} else if s == &g.ctrlButton[3] {
		unitID = "player"
	} else if s == &g.ctrlButton[4] {
		unitID = "player"
	} else if s == &g.ctrlButton[5] {
		unitID = "player"
	} else if s == &g.ctrlButton[0] {
		unitID = "player"
	} else if s == &g.ctrlButton[1] {
		unitID = "player"
	} else if s == &g.ctrlButton[2] {
		unitID = "player"
	}
	return unitID
}

// OnTouchEnd is called when game scene is Touched and it is released.
func (f *fieldTouchListener) OnTouchEnd(x, y float32) {
	if y <= ctrlPanelHeight {
		return
	}

	if f.game.selection.selecting == nil {
		return
	}

	unitID := f.game.unitIDBySprite(f.game.selection.selecting)
	id := strconv.Itoa(len(f.game.players))

	if unitID != "" {
		// TODO: every alley spawn occurs file I/O. lol
		// loading texture in advance is needed.
		p := newUnit(id, unitID, f.game)
		p.SetPosition(x, y)
		f.game.players[id] = p
		f.game.pubsub.Subscribe(p.GetID(), p)
		f.game.eventqueue <- newCommand(commandSpawn, p)
	}
}

func (g *game) initPlayer() {
	g.players = make(map[string]uniter)
}

type unitPopTime struct {
	unitID          string
	popTime         int64
	initialPosition position
}

type unitPopTimeTable []*unitPopTime

func (g *game) initUnits(json string) {
	// TODO: load from json file
	units := make(map[string]uniter)
	units["unit1"] = newUnit("unit1", "", g)
	units["unit2"] = newUnit("unit2", "", g)
	units["unit3"] = newUnit("unit3", "", g)

	// TODO: unitpopTimeTable should be sorted by popTime
	g.unitPopTimeTable = append(g.unitPopTimeTable,
		&unitPopTime{
			unitID:          "unit1",
			popTime:         3 * fps,
			initialPosition: position{config.ScreenWidth - 32, config.ScreenHeight / 6 * 5},
		})
	g.unitPopTimeTable = append(g.unitPopTimeTable,
		&unitPopTime{
			unitID:          "unit2",
			popTime:         4 * fps,
			initialPosition: position{config.ScreenWidth - 32, config.ScreenHeight / 6 * 4},
		})
	g.unitPopTimeTable = append(g.unitPopTimeTable,
		&unitPopTime{
			unitID:          "unit3",
			popTime:         5 * fps,
			initialPosition: position{config.ScreenWidth - 32, config.ScreenHeight / 6 * 3},
		})

	g.uniters = units
}

func (g *game) popUnits() []uniter {
	poppedUnits := make([]uniter, 0)
	for _, v := range g.unitPopTimeTable {
		if v.popTime <= g.currentFrame {
			// pop unit
			u := g.uniters[v.unitID]
			u.SetPosition(v.initialPosition.x, v.initialPosition.y)
			poppedUnits = append(poppedUnits, u)
			continue
		}
	}

	if len(poppedUnits) != 0 {
		// remove popped units from unitPopTimeTable
		g.unitPopTimeTable = g.unitPopTimeTable[len(poppedUnits):]
	}

	return poppedUnits
}

func (g *game) initialize() {
	g.pubsub = simra.NewPubSub()
	g.eventqueue = make(chan *command, 256)
	g.initField()
	g.initCtrlPanel()
	g.initPlayer()
	g.initUnits("") // TODO: input JSON string
	g.selection = &selection{game: g}
	simra.GetInstance().AddTouchListener(g)
	g.pubsub.Subscribe("god", g)
	g.pubsub.Subscribe("selection", g.selection)
	g.updateGameState(gameStateInitial)
}

func (g *game) eventFetch() []*command {
	// note:
	// if new events are pushed while fetching,
	// they should be fetched next run loop to
	// avoid inifinite event fetching.

	qlen := len(g.eventqueue)
	if qlen == 0 {
		return nil
	}

	c := make([]*command, qlen)
	for i := 0; i < qlen; i++ {
		c[i] = <-g.eventqueue
	}
	return c
}

func (g *game) OnEvent(i interface{}) {
	c, ok := i.(*command)
	if !ok {
		// should be a command. ignore.
		return
	}

	_, ok = c.data.(*game)
	if !ok {
		// this is not for me
		return
	}

	switch c.commandtype {
	case commandGoToInitialState:
		g.updateGameState(gameStateInitial)
	case commandGoToRunningState:
		g.updateGameState(gameStateRunning)
	}
}

func (g *game) initialRunLoop() {
	commands := g.eventFetch()
	for _, v := range commands {
		g.pubsub.Publish(v)
	}
	for _, v := range g.players {
		v.DoAction()
	}
}

func (g *game) runningRunLoop() {
	poppedUnits := g.popUnits()
	for _, v := range poppedUnits {
		err := g.pubsub.Subscribe(v.GetID(), v)
		if err != nil {
			panic("failed to subscribe. fatal.")
		}

		// generate spawn command
		g.eventqueue <- newCommand(commandSpawn, v)
	}

	// event fetch and publish to all subscribers
	commands := g.eventFetch()
	for _, v := range commands {
		g.pubsub.Publish(v)
	}

	// invoke action for all units
	for _, v := range g.players {
		v.DoAction()
	}
	for _, v := range g.uniters {
		v.DoAction()
	}
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (g *game) Drive() {
	defer func() {
		g.currentFrame++
	}()

	if g.nextScene != nil {
		simra.GetInstance().SetScene(g.nextScene)
	}
	g.currentRunLoop()
}

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

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

// OnTouchEnd is called when game scene is Touched and it is released.
func (g *game) OnTouchEnd(x, y float32) {
	// nop
	//g.nextScene = &result{currentStage: g.currentStage}
}
<|endoftext|>


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

package models

import (
	"container/list"
	"fmt"
	"path"
	"strings"

	"github.com/Unknwon/com"

	"github.com/gogits/git"
)

// RepoFile represents a file object in git repository.
type RepoFile struct {
	*git.TreeEntry
	Path   string
	Size   int64
	Repo   *git.Repository
	Commit *git.Commit
}

// LookupBlob returns the content of an object.
func (file *RepoFile) LookupBlob() (*git.Blob, error) {
	if file.Repo == nil {
		return nil, ErrRepoFileNotLoaded
	}

	return file.Repo.LookupBlob(file.Id)
}

// GetBranches returns all branches of given repository.
func GetBranches(userName, reposName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	refs, err := repo.AllReferences()
	if err != nil {
		return nil, err
	}

	brs := make([]string, len(refs))
	for i, ref := range refs {
		brs[i] = ref.Name
	}
	return brs, nil
}

func GetTargetFile(userName, reposName, branchName, commitId, rpath string) (*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(branchName, commitId)
	if err != nil {
		return nil, err
	}

	parts := strings.Split(path.Clean(rpath), "/")

	var entry *git.TreeEntry
	tree := commit.Tree
	for i, part := range parts {
		if i == len(parts)-1 {
			entry = tree.EntryByName(part)
			if entry == nil {
				return nil, ErrRepoFileNotExist
			}
		} else {
			tree, err = repo.SubTree(tree, part)
			if err != nil {
				return nil, err
			}
		}
	}

	size, err := repo.ObjectSize(entry.Id)
	if err != nil {
		return nil, err
	}

	repoFile := &RepoFile{
		entry,
		rpath,
		size,
		repo,
		commit,
	}

	return repoFile, nil
}

// GetReposFiles returns a list of file object in given directory of repository.
func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(branchName, commitId)
	if err != nil {
		return nil, err
	}

	var repodirs []*RepoFile
	var repofiles []*RepoFile
	commit.Tree.Walk(func(dirname string, entry *git.TreeEntry) int {
		if dirname == rpath {
			// TODO: size get method shoule be improved
			size, err := repo.ObjectSize(entry.Id)
			if err != nil {
				return 0
			}

			var cm = commit
			var i int
			for {
				i = i + 1
				//fmt.Println(".....", i, cm.Id(), cm.ParentCount())
				if cm.ParentCount() == 0 {
					break
				} else if cm.ParentCount() == 1 {
					pt, _ := repo.SubTree(cm.Parent(0).Tree, dirname)
					if pt == nil {
						break
					}
					pEntry := pt.EntryByName(entry.Name)
					if pEntry == nil || !pEntry.Id.Equal(entry.Id) {
						break
					} else {
						cm = cm.Parent(0)
					}
				} else {
					var emptyCnt = 0
					var sameIdcnt = 0
					var lastSameCm *git.Commit
					//fmt.Println(".....", cm.ParentCount())
					for i := 0; i < cm.ParentCount(); i++ {
						//fmt.Println("parent", i, cm.Parent(i).Id())
						p := cm.Parent(i)
						pt, _ := repo.SubTree(p.Tree, dirname)
						var pEntry *git.TreeEntry
						if pt != nil {
							pEntry = pt.EntryByName(entry.Name)
						}

						//fmt.Println("pEntry", pEntry)

						if pEntry == nil {
							emptyCnt = emptyCnt + 1
							if emptyCnt+sameIdcnt == cm.ParentCount() {
								if lastSameCm == nil {
									goto loop
								} else {
									cm = lastSameCm
									break
								}
							}
						} else {
							//fmt.Println(i, "pEntry", pEntry.Id, "entry", entry.Id)
							if !pEntry.Id.Equal(entry.Id) {
								goto loop
							} else {
								lastSameCm = cm.Parent(i)
								sameIdcnt = sameIdcnt + 1
								if emptyCnt+sameIdcnt == cm.ParentCount() {
									// TODO: now follow the first parent commit?
									cm = lastSameCm
									//fmt.Println("sameId...")
									break
								}
							}
						}
					}
				}
			}

		loop:

			rp := &RepoFile{
				entry,
				path.Join(dirname, entry.Name),
				size,
				repo,
				cm,
			}

			if entry.IsFile() {
				repofiles = append(repofiles, rp)
			} else if entry.IsDir() {
				repodirs = append(repodirs, rp)
			}
		}
		return 0
	})

	return append(repodirs, repofiles...), nil
}

func GetCommit(userName, repoName, branchname, commitid string) (*git.Commit, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	return repo.GetCommit(branchname, commitid)
}

// GetCommits returns all commits of given branch of repository.
func GetCommits(userName, reposName, branchname string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}
	r, err := repo.LookupReference(fmt.Sprintf("refs/heads/%s", branchname))
	if err != nil {
		return nil, err
	}
	return r.AllCommits()
}

type DiffFile struct {
	Name               string
	Addition, Deletion int
	Type               string
	Content            []string
}

type Diff struct {
	NumFiles                     int // Number of file has been changed.
	TotalAddition, TotalDeletion int
	Files                        []*DiffFile
}

func GetDiff(repoPath, commitid string) (*Diff, error) {
	stdout, _, err := com.ExecCmdDir(repoPath, "git", "show", commitid)
	if err != nil {
		return nil, err
	}

	// Sperate parts by file.
	parts := strings.Split(stdout, "diff --git ")

	// First part is commit information.
	// Check if it's a merge.
	mergeIndex := strings.Index(parts[0], "merge")
	if mergeIndex > -1 {
		mergeCommit := strings.SplitN(strings.Split(parts[0], "\n")[1], "", 3)[2]
		return GetDiff(repoPath, mergeCommit)
	}

	diff := &Diff{NumFiles: len(parts[1:])}
	diff.Files = make([]*DiffFile, 0, diff.NumFiles)
	for _, part := range parts[1:] {
		infos := strings.SplitN(part, "\n", 6)
		infos[5] = strings.TrimSuffix(strings.TrimSuffix(infos[5], "\n"), "\n\\ No newline at end of file")

		file := &DiffFile{
			Name:    strings.TrimPrefix(strings.Split(infos[0], " ")[0], "a/"),
			Content: strings.Split(infos[5], "\n"),
		}
		diff.Files = append(diff.Files, file)
	}
	return diff, nil
}
<commit_msg>More on diff page<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"container/list"
	"fmt"
	"path"
	"strings"

	"github.com/Unknwon/com"

	"github.com/gogits/git"
)

// RepoFile represents a file object in git repository.
type RepoFile struct {
	*git.TreeEntry
	Path   string
	Size   int64
	Repo   *git.Repository
	Commit *git.Commit
}

// LookupBlob returns the content of an object.
func (file *RepoFile) LookupBlob() (*git.Blob, error) {
	if file.Repo == nil {
		return nil, ErrRepoFileNotLoaded
	}

	return file.Repo.LookupBlob(file.Id)
}

// GetBranches returns all branches of given repository.
func GetBranches(userName, reposName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	refs, err := repo.AllReferences()
	if err != nil {
		return nil, err
	}

	brs := make([]string, len(refs))
	for i, ref := range refs {
		brs[i] = ref.Name
	}
	return brs, nil
}

func GetTargetFile(userName, reposName, branchName, commitId, rpath string) (*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(branchName, commitId)
	if err != nil {
		return nil, err
	}

	parts := strings.Split(path.Clean(rpath), "/")

	var entry *git.TreeEntry
	tree := commit.Tree
	for i, part := range parts {
		if i == len(parts)-1 {
			entry = tree.EntryByName(part)
			if entry == nil {
				return nil, ErrRepoFileNotExist
			}
		} else {
			tree, err = repo.SubTree(tree, part)
			if err != nil {
				return nil, err
			}
		}
	}

	size, err := repo.ObjectSize(entry.Id)
	if err != nil {
		return nil, err
	}

	repoFile := &RepoFile{
		entry,
		rpath,
		size,
		repo,
		commit,
	}

	return repoFile, nil
}

// GetReposFiles returns a list of file object in given directory of repository.
func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(branchName, commitId)
	if err != nil {
		return nil, err
	}

	var repodirs []*RepoFile
	var repofiles []*RepoFile
	commit.Tree.Walk(func(dirname string, entry *git.TreeEntry) int {
		if dirname == rpath {
			// TODO: size get method shoule be improved
			size, err := repo.ObjectSize(entry.Id)
			if err != nil {
				return 0
			}

			var cm = commit
			var i int
			for {
				i = i + 1
				//fmt.Println(".....", i, cm.Id(), cm.ParentCount())
				if cm.ParentCount() == 0 {
					break
				} else if cm.ParentCount() == 1 {
					pt, _ := repo.SubTree(cm.Parent(0).Tree, dirname)
					if pt == nil {
						break
					}
					pEntry := pt.EntryByName(entry.Name)
					if pEntry == nil || !pEntry.Id.Equal(entry.Id) {
						break
					} else {
						cm = cm.Parent(0)
					}
				} else {
					var emptyCnt = 0
					var sameIdcnt = 0
					var lastSameCm *git.Commit
					//fmt.Println(".....", cm.ParentCount())
					for i := 0; i < cm.ParentCount(); i++ {
						//fmt.Println("parent", i, cm.Parent(i).Id())
						p := cm.Parent(i)
						pt, _ := repo.SubTree(p.Tree, dirname)
						var pEntry *git.TreeEntry
						if pt != nil {
							pEntry = pt.EntryByName(entry.Name)
						}

						//fmt.Println("pEntry", pEntry)

						if pEntry == nil {
							emptyCnt = emptyCnt + 1
							if emptyCnt+sameIdcnt == cm.ParentCount() {
								if lastSameCm == nil {
									goto loop
								} else {
									cm = lastSameCm
									break
								}
							}
						} else {
							//fmt.Println(i, "pEntry", pEntry.Id, "entry", entry.Id)
							if !pEntry.Id.Equal(entry.Id) {
								goto loop
							} else {
								lastSameCm = cm.Parent(i)
								sameIdcnt = sameIdcnt + 1
								if emptyCnt+sameIdcnt == cm.ParentCount() {
									// TODO: now follow the first parent commit?
									cm = lastSameCm
									//fmt.Println("sameId...")
									break
								}
							}
						}
					}
				}
			}

		loop:

			rp := &RepoFile{
				entry,
				path.Join(dirname, entry.Name),
				size,
				repo,
				cm,
			}

			if entry.IsFile() {
				repofiles = append(repofiles, rp)
			} else if entry.IsDir() {
				repodirs = append(repodirs, rp)
			}
		}
		return 0
	})

	return append(repodirs, repofiles...), nil
}

func GetCommit(userName, repoName, branchname, commitid string) (*git.Commit, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	return repo.GetCommit(branchname, commitid)
}

// GetCommits returns all commits of given branch of repository.
func GetCommits(userName, reposName, branchname string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}
	r, err := repo.LookupReference(fmt.Sprintf("refs/heads/%s", branchname))
	if err != nil {
		return nil, err
	}
	return r.AllCommits()
}

type DiffFile struct {
	Name               string
	Addition, Deletion int
	Type               string
	Content            []string
}

type Diff struct {
	NumFiles                     int // Number of file has been changed.
	TotalAddition, TotalDeletion int
	Files                        []*DiffFile
}

func GetDiff(repoPath, commitid string) (*Diff, error) {
	stdout, _, err := com.ExecCmdDir(repoPath, "git", "show", commitid)
	if err != nil {
		return nil, err
	}

	// Sperate parts by file.
	startIndex := strings.Index(stdout, "diff --git ") + 12

	// First part is commit information.
	// Check if it's a merge.
	mergeIndex := strings.Index(stdout[:startIndex], "merge")
	if mergeIndex > -1 {
		mergeCommit := strings.SplitN(strings.Split(stdout[:startIndex], "\n")[1], "", 3)[2]
		return GetDiff(repoPath, mergeCommit)
	}

	parts := strings.Split(stdout[startIndex:], "diff --git ")
	diff := &Diff{NumFiles: len(parts)}
	diff.Files = make([]*DiffFile, 0, diff.NumFiles)
	for _, part := range parts {
		infos := strings.SplitN(part, "\n", 6)
		maxIndex := len(infos) - 1
		infos[maxIndex] = strings.TrimSuffix(strings.TrimSuffix(infos[maxIndex], "\n"), "\n\\ No newline at end of file")

		file := &DiffFile{
			Name:    strings.TrimPrefix(strings.Split(infos[0], " ")[0], "a/"),
			Content: strings.Split(infos[maxIndex], "\n"),
		}
		diff.Files = append(diff.Files, file)
	}
	return diff, nil
}
<|endoftext|>


<commit_before>package mol2

import (
	"errors"
	"unicode"
	"unicode/utf8"
)

type Lexer struct {
	buf []byte
	line, column, pos int
	column_new, line_new, pos_new int
}

func NewLexer(buffer []byte) *Lexer {
	lex := new(Lexer)
	lex.line = 0
	lex.column = 0
	lex.pos = 0
	lex.buf = buffer

	return lex
}

func (lex *Lexer) Coords() (int, int) {
	return lex.line, lex.column
}

func (lex *Lexer) SkipWS() (bool, int) {
	return false, 0
}

func (lex *Lexer) readRune() rune {
	r, size := utf8.DecodeRune(lex.buf[lex.pos_new:])
	lex.pos_new += size
	if r == '\n' {
		lex.column_new = 0
		lex.line_new ++
	} else {
		lex.column_new ++
	}

	return r
}

func (lex *Lexer) fixCoords() {
	lex.pos = lex.pos_new
	lex.line = lex.line_new
	lex.column = lex.column_new
}

func (lex *Lexer) dropCoords() {
	lex.pos_new = lex.pos
	lex.line_new = lex.line
	lex.column_new = lex.column
}

func (lex *Lexer) NextAtom() (bool, error) {
	pattern := "@<TRIPOS>ATOM"
	err_text := "was expected '" + pattern + "'"
	if (len(lex.buf) - lex.pos) < len(pattern) {
		return false, errors.New(err_text)
	}
	for _, r := range pattern {
		buf_rune := lex.readRune()
		if r != buf_rune {
			lex.dropCoords()
			return false, errors.New(err_text)
		}
	}
	lex.fixCoords()

	return true, nil
}

func (lex *Lexer) NextId() (bool, string, error) {
	buf := ""
	r := lex.readRune()
	for unicode.IsSpace(r) == false {
		buf += string(r)
		r = lex.readRune()
	}
	if len(buf) == 0 {
		return false, "", errors.New("Id was expected")
	}

	return true, buf, nil
}
<commit_msg>fix Coords for id parsing<commit_after>package mol2

import (
	"errors"
	"unicode"
	"unicode/utf8"
)

type Lexer struct {
	buf []byte
	line, column, pos int
	column_new, line_new, pos_new int
}

func NewLexer(buffer []byte) *Lexer {
	lex := new(Lexer)
	lex.line = 0
	lex.column = 0
	lex.pos = 0
	lex.buf = buffer

	return lex
}

func (lex *Lexer) Coords() (int, int) {
	return lex.line, lex.column
}

func (lex *Lexer) SkipWS() (bool, int) {
	return false, 0
}

func (lex *Lexer) readRune() rune {
	r, size := utf8.DecodeRune(lex.buf[lex.pos_new:])
	lex.pos_new += size
	if r == '\n' {
		lex.column_new = 0
		lex.line_new ++
	} else {
		lex.column_new ++
	}

	return r
}

func (lex *Lexer) fixCoords() {
	lex.pos = lex.pos_new
	lex.line = lex.line_new
	lex.column = lex.column_new
}

func (lex *Lexer) dropCoords() {
	lex.pos_new = lex.pos
	lex.line_new = lex.line
	lex.column_new = lex.column
}

func (lex *Lexer) NextAtom() (bool, error) {
	pattern := "@<TRIPOS>ATOM"
	err_text := "was expected '" + pattern + "'"
	if (len(lex.buf) - lex.pos) < len(pattern) {
		return false, errors.New(err_text)
	}
	for _, r := range pattern {
		buf_rune := lex.readRune()
		if r != buf_rune {
			lex.dropCoords()
			return false, errors.New(err_text)
		}
	}
	lex.fixCoords()

	return true, nil
}

func (lex *Lexer) NextId() (bool, string, error) {
	buf := ""
	r := lex.readRune()
	for unicode.IsSpace(r) == false {
		buf += string(r)
		r = lex.readRune()
	}
	if len(buf) == 0 {
		return false, "", errors.New("Id was expected")
	}
	lex.fixCoords()

	return true, buf, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var (
	sequenses = regexp.MustCompile(`(?:[^/\\]|\\.)*`)
	branches  = regexp.MustCompile(`(?:[^,\\]|\\.)*`)
)

func parseExpr(expr string) ([][]string, error) {
	expr = strings.Replace(expr, `\,`, `\\,`, -1)
	expr = strings.Replace(expr, `\/`, `\\/`, -1)
	expr, err := strconv.Unquote(`"` + expr + `"`)
	if err != nil {
		return nil, err
	}
	sls := sequenses.FindAllString(expr, -1)
	tree := make([][]string, len(sls))
	for si := 0; si < len(sls); si++ {
		bls := branches.FindAllString(sls[si], -1)
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = strings.Replace(bls[bi], `\,`, `,`, -1)
			bls[bi] = strings.Replace(bls[bi], `\/`, `/`, -1)
			bls[bi] = regexp.QuoteMeta(bls[bi])
		}
		tree[si] = bls
	}
	return tree, nil
}

func newMatcher(expr string) (m *regexp.Regexp, err error) {
	tree, err := parseExpr(expr)
	if err != nil {
		return nil, err
	}
	sls := make([]string, len(tree))
	for si, bls := range tree {
		sls[si] = "(" + strings.Join(bls, "|") + ")"
	}
	return regexp.Compile(strings.Join(sls, ""))
}

func newReplacement(exprFrom, exprTo string) ([]map[string]string, error) {
	from, err := parseExpr(exprFrom)
	if err != nil {
		return nil, err
	}
	to, err := parseExpr(exprTo)
	if err != nil {
		return nil, err
	}
	if len(from) != len(to) {
		return nil, fmt.Errorf("mismatch the number of sequense")
	}
	r := make([]map[string]string, len(from))
	for si := 0; si < len(from); si++ {
		if len(from[si]) != len(to[si]) {
			return nil, fmt.Errorf("mismatch the number of branch[%q]", si)
		}
		r[si] = make(map[string]string)
		for bi := 0; bi < len(from[si]); bi++ {
			if _, exist := r[si][from[si][bi]]; exist {
				return nil, fmt.Errorf("branch[%q] has duplicate item", si)
			}
			r[si][from[si][bi]] = to[si][bi]
		}
	}
	return r, nil
}
<commit_msg>Use space<commit_after>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var (
	sequenses = regexp.MustCompile(`(?:[^/\\]|\\.)*`)
	branches  = regexp.MustCompile(`(?:[^,\\]|\\.)*`)
)

func parseExpr(expr string) ([][]string, error) {
	expr = strings.Replace(expr, `\,`, `\\,`, -1)
	expr = strings.Replace(expr, `\/`, `\\/`, -1)
	expr, err := strconv.Unquote(`"` + expr + `"`)
	if err != nil {
		return nil, err
	}

	sls := sequenses.FindAllString(expr, -1)
	tree := make([][]string, len(sls))
	for si := 0; si < len(sls); si++ {
		bls := branches.FindAllString(sls[si], -1)
		for bi := 0; bi < len(bls); bi++ {
			bls[bi] = strings.Replace(bls[bi], `\,`, `,`, -1)
			bls[bi] = strings.Replace(bls[bi], `\/`, `/`, -1)
			bls[bi] = regexp.QuoteMeta(bls[bi])
		}
		tree[si] = bls
	}
	return tree, nil
}

func newMatcher(expr string) (m *regexp.Regexp, err error) {
	tree, err := parseExpr(expr)
	if err != nil {
		return nil, err
	}

	sls := make([]string, len(tree))
	for si, bls := range tree {
		sls[si] = "(" + strings.Join(bls, "|") + ")"
	}
	return regexp.Compile(strings.Join(sls, ""))
}

func newReplacement(exprFrom, exprTo string) ([]map[string]string, error) {
	from, err := parseExpr(exprFrom)
	if err != nil {
		return nil, err
	}
	to, err := parseExpr(exprTo)
	if err != nil {
		return nil, err
	}

	if len(from) != len(to) {
		return nil, fmt.Errorf("mismatch the number of sequense")
	}

	r := make([]map[string]string, len(from))
	for si := 0; si < len(from); si++ {
		if len(from[si]) != len(to[si]) {
			return nil, fmt.Errorf("mismatch the number of branch[%q]", si)
		}

		r[si] = make(map[string]string)
		for bi := 0; bi < len(from[si]); bi++ {
			if _, exist := r[si][from[si][bi]]; exist {
				return nil, fmt.Errorf("branch[%q] has duplicate item", si)
			}
			r[si][from[si][bi]] = to[si][bi]
		}
	}
	return r, nil
}
<|endoftext|>


<commit_before>package negroniJWT

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gorilla/context"
	"net/http"
	"sync"
	"time"
)

const (
	context_key = "jwt"
)

var (
	once              sync.Once
	privKeyPEMEncoded []byte
	pubKeyPEMEncoded  []byte
	failRequest       bool
)

func Init(failRequest bool) {
	failRequest = failRequest
	once.Do(generateKeys)
}

func generateKeys() {
	privKey, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		panic(err)
	}
	privKeyPEMEncoded = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE context_key",
		Bytes: x509.MarshalPKCS1PrivateKey(privKey),
	})
	pubANS1, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
	if err != nil {
		panic(err)
	}
	pubKeyPEMEncoded = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PUBLIC context_key",
		Bytes: pubANS1,
	})
}

func getClaims(token string) (claims map[string]interface{}, err error) {
	parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return pubKeyPEMEncoded, nil
	})
	if err != nil {
		return nil, err
	}
	if parsedToken.Valid {
		return parsedToken.Claims, nil
	}
	return nil, errors.New("Token is invalid")
}

// Middleware the main middleware function. Use with negroni.HandlerFunc to apply middleware like so :
// n := negroni.Classic()
// n.Use(negroni.HandlerFunc(negroniJWT.Middleware))
func Middleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	var authToken string = r.Header.Get("Authorization")
	claims, err := getClaims(authToken)
	if err == nil || failRequest == false {
		if err == nil {
			context.Set(r, context_key, claims)
		}
		next(rw, r)
	} else {
		rw.WriteHeader(401)
	}
}

// GenerateToken generates the base64 encoded JSON Web Token including the claims map provided and and expiration time.
func GenerateToken(claims map[string]interface{}, expiration time.Time) (s string, err error) {
	t := jwt.New(jwt.GetSigningMethod("RS256"))
	t.Claims = claims
	t.Claims["exp"] = expiration.Unix()
	return t.SignedString(privKeyPEMEncoded)
}

// Get attempts to retrieve the claims map for request. If there was an error decoding the JSON Web Token.
func Get(r *http.Request) (claims map[string]interface{}, ok bool) {
	c, ok := context.GetOk(r, context_key)
	if !ok {
		return claims, ok
	}
	claims, castOk := c.(map[string]interface{})
	return claims, castOk
}
<commit_msg>clear context from request on GET<commit_after>package negroniJWT

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gorilla/context"
	"net/http"
	"sync"
	"time"
)

const (
	context_key = "jwt"
)

var (
	once              sync.Once
	privKeyPEMEncoded []byte
	pubKeyPEMEncoded  []byte
	failRequest       bool
)

func Init(alwaysFailRequest bool) {
	failRequest = alwaysFailRequest
	once.Do(generateKeys)
}

func generateKeys() {
	privKey, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		panic(err)
	}
	privKeyPEMEncoded = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE context_key",
		Bytes: x509.MarshalPKCS1PrivateKey(privKey),
	})
	pubANS1, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
	if err != nil {
		panic(err)
	}
	pubKeyPEMEncoded = pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PUBLIC context_key",
		Bytes: pubANS1,
	})
}

func getClaims(token string) (claims map[string]interface{}, err error) {
	parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return pubKeyPEMEncoded, nil
	})
	if err != nil {
		return nil, err
	}
	if parsedToken.Valid {
		return parsedToken.Claims, nil
	}
	return nil, errors.New("Token is invalid")
}

// Middleware the main middleware function. Use with negroni.HandlerFunc to apply middleware like so :
// n := negroni.Classic()
// n.Use(negroni.HandlerFunc(negroniJWT.Middleware))
func Middleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	var authToken string = r.Header.Get("Authorization")
	claims, err := getClaims(authToken)
	if err == nil || failRequest == false {
		if err == nil {
			context.Set(r, context_key, claims)
		}
		next(rw, r)
	} else {
		rw.WriteHeader(401)
	}
}

// GenerateToken generates the base64 encoded JSON Web Token including the claims map provided and and expiration time.
func GenerateToken(claims map[string]interface{}, expiration time.Time) (s string, err error) {
	t := jwt.New(jwt.GetSigningMethod("RS256"))
	t.Claims = claims
	t.Claims["exp"] = expiration.Unix()
	return t.SignedString(privKeyPEMEncoded)
}

// Get attempts to retrieve the claims map for request. If there was an error decoding the JSON Web Token.
func Get(r *http.Request) (claims map[string]interface{}, ok bool) {
	c, ok := context.GetOk(r, context_key)
	context.Clear(r)
	if !ok {
		return claims, ok
	}
	claims, castOk := c.(map[string]interface{})
	return claims, castOk
}
<|endoftext|>


<commit_before>package net

import (
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"

	dio "github.com/dilfish/tools/io"
)

type UploaderService struct {
	MaxSize  int64
	MaxMem   int64
	Curr     int64
	BasePath string
	BaseURL  string
	NameLen  int
	Expire   time.Duration
	Lock     sync.Mutex
	Map      map[string]time.Time
}

// WriteFile write reader into file
func (u *UploaderService) WriteFile(name string, rc io.Reader) (int64, string, error) {
	ext := filepath.Ext(name)
	if ext == "" {
		ext = ".noext"
	}
	name = dio.RandStr(u.NameLen) + ext
	fn := u.BasePath + "/" + name
	file, err := os.Create(fn)
	if err != nil {
		log.Println("create file name error:", name, err)
		return 0, "", err
	}
	defer file.Close()
	u.Lock.Lock()
	defer u.Lock.Unlock()
	u.Map[fn] = time.Now().Add(u.Expire)
	n, err := io.Copy(file, rc)
	return n, name, err
}

// Handler return page if get
// and write file into disk if post
func (u *UploaderService) Handler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		io.WriteString(w, "Not Supported")
		return
	}
	err := r.ParseMultipartForm(u.MaxMem)
	if err != nil {
		io.WriteString(w, "Read File Error:"+err.Error())
		return
	}

	file, header, err := r.FormFile("file")
	if err != nil {
		io.WriteString(w, "Read File error:"+err.Error())
		return
	}
	if u.Curr+header.Size > u.MaxSize {
		log.Println("too many write:", u.Curr, header.Size, u.MaxSize)
		io.WriteString(w, "Too many write")
		return
	}
	defer file.Close()
	n, name, err := u.WriteFile(header.Filename, file)
	if err != nil {
		log.Println("write file error:", err)
		io.WriteString(w, "write file error"+err.Error())
		return
	}
	u.Curr = u.Curr + n
	io.WriteString(w, "<meta charset=\"UTF-8\">
上传成功！，你可以访问这里看一看:File
")
	return
}

func NewUploadService(baseURL, basePath string, maxSize int64, expire time.Duration, nameLen int) *UploaderService {
	var u UploaderService
	u.MaxSize = maxSize
	u.MaxMem = maxSize
	u.BasePath = basePath
	u.BaseURL = baseURL
	u.NameLen = nameLen
	if expire < time.Minute {
		expire = time.Minute
	}
	u.Expire = expire
	if u.NameLen < 1 {
		u.NameLen = 10
	}
	u.Map = make(map[string]time.Time)
	go u.Patrol()
	return &u
}

func (u *UploaderService) Patrol() {
	for {
		time.Sleep(time.Minute)
		tbd := []string{}
		u.Lock.Lock()
		for k, v := range u.Map {
			if v.After(time.Now()) {
				tbd = append(tbd, k)
			}
		}
		for _, tb := range tbd {
			os.Remove(tb)
			delete(u.Map, tb)
		}
		u.Lock.Unlock()
	}
}
<commit_msg>add upload<commit_after>package net

import (
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"

	dio "github.com/dilfish/tools/io"
)

type UploaderService struct {
	MaxSize     int64
	MaxMem      int64
	Curr        int64
	BasePath    string
	BaseURL     string
	JumpBackURL string
	NameLen     int
	Expire      time.Duration
	Lock        sync.Mutex
	Map         map[string]time.Time
}

// WriteFile write reader into file
func (u *UploaderService) WriteFile(name string, rc io.Reader) (int64, string, error) {
	ext := filepath.Ext(name)
	if ext == "" {
		ext = ".noext"
	}
	name = dio.RandStr(u.NameLen) + ext
	fn := u.BasePath + "/" + name
	file, err := os.Create(fn)
	if err != nil {
		log.Println("create file name error:", name, err)
		return 0, "", err
	}
	defer file.Close()
	u.Lock.Lock()
	defer u.Lock.Unlock()
	u.Map[fn] = time.Now().Add(u.Expire)
	n, err := io.Copy(file, rc)
	return n, name, err
}

// Handler return page if get
// and write file into disk if post
func (u *UploaderService) Handler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		io.WriteString(w, "Not Supported")
		return
	}
	err := r.ParseMultipartForm(u.MaxMem)
	if err != nil {
		io.WriteString(w, "Read File Error:"+err.Error())
		return
	}

	file, header, err := r.FormFile("file")
	if err != nil {
		io.WriteString(w, "Read File error:"+err.Error())
		return
	}
	if u.Curr+header.Size > u.MaxSize {
		log.Println("too many write:", u.Curr, header.Size, u.MaxSize)
		io.WriteString(w, "Too many write")
		return
	}
	defer file.Close()
	n, name, err := u.WriteFile(header.Filename, file)
	if err != nil {
		log.Println("write file error:", err)
		io.WriteString(w, "write file error"+err.Error())
		return
	}
	u.Curr = u.Curr + n
	show := "<meta charset=\"UTF-8\">
上传成功！，你可以访问这里看一看:File
"
	if u.JumpBackURL != "" {
		show = show + "
JumpBack
"
	}
	show = show + ""
	io.WriteString(w, show)
	return
}

func NewUploadService(baseURL, basePath, jump string, maxSize int64, expire time.Duration, nameLen int) *UploaderService {
	var u UploaderService
	u.MaxSize = maxSize
	u.MaxMem = maxSize
	u.BasePath = basePath
	u.BaseURL = baseURL
	u.JumpBackURL = jump
	u.NameLen = nameLen
	if expire < time.Minute {
		expire = time.Minute
	}
	u.Expire = expire
	if u.NameLen < 1 {
		u.NameLen = 10
	}
	u.Map = make(map[string]time.Time)
	go u.Patrol()
	return &u
}

func (u *UploaderService) Patrol() {
	for {
		time.Sleep(time.Minute)
		tbd := []string{}
		u.Lock.Lock()
		for k, v := range u.Map {
			if v.After(time.Now()) {
				tbd = append(tbd, k)
			}
		}
		for _, tb := range tbd {
			os.Remove(tb)
			delete(u.Map, tb)
		}
		u.Lock.Unlock()
	}
}
<|endoftext|>


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

// +build appengine

// Package appengine contains an AppEngine app for perfdata.golang.org
package appengine

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

	_ "github.com/go-sql-driver/mysql"
	"golang.org/x/net/context"
	"golang.org/x/perf/storage/app"
	"golang.org/x/perf/storage/db"
	"golang.org/x/perf/storage/fs/gcs"
	"google.golang.org/appengine"
	aelog "google.golang.org/appengine/log"
	"google.golang.org/appengine/user"
)

// connectDB returns a DB initialized from the environment variables set in app.yaml. CLOUDSQL_CONNECTION_NAME, CLOUDSQL_USER, and CLOUDSQL_DATABASE must be set to point to the Cloud SQL instance. CLOUDSQL_PASSWORD can be set if needed.
func connectDB() (*db.DB, error) {
	var (
		connectionName = mustGetenv("CLOUDSQL_CONNECTION_NAME")
		user           = mustGetenv("CLOUDSQL_USER")
		password       = os.Getenv("CLOUDSQL_PASSWORD") // NOTE: password may be empty
		dbName         = mustGetenv("CLOUDSQL_DATABASE")
	)

	return db.OpenSQL("mysql", fmt.Sprintf("%s:%s@cloudsql(%s)/%s?interpolateParams=true", user, password, connectionName, dbName))
}

func mustGetenv(k string) string {
	v := os.Getenv(k)
	if v == "" {
		log.Panicf("%s environment variable not set.", k)
	}
	return v
}

func auth(w http.ResponseWriter, r *http.Request) (string, error) {
	ctx := appengine.NewContext(r)
	u := user.Current(ctx)
	if u == nil && r.Header.Get("Authorization") != "" {
		var err error
		u, err = user.CurrentOAuth(ctx, "https://www.googleapis.com/auth/userinfo.email")
		if err != nil {
			return "", err
		}
	}
	if u == nil {
		url, err := user.LoginURL(ctx, r.URL.String())
		if err != nil {
			return "", err
		}
		http.Redirect(w, r, url, http.StatusFound)
		return "", app.ErrResponseWritten
	}
	return u.Email, nil
}

// appHandler is the default handler, registered to serve "/".
// It creates a new App instance using the appengine Context and then
// dispatches the request to the App. The environment variable
// GCS_BUCKET must be set in app.yaml with the name of the bucket to
// write to. PERFDATA_VIEW_URL_BASE may be set to the URL that should
// be supplied in /upload responses.
func appHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	// App Engine does not return a context with a deadline set,
	// even though the request does have a deadline. urlfetch uses
	// a 5s default timeout if the context does not have a
	// deadline, so explicitly set a deadline to match the App
	// Engine timeout.
	ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
	defer cancel()
	// GCS clients need to be constructed with an AppEngine
	// context, so we can't actually make the App until the
	// request comes in.
	// TODO(quentin): Figure out if there's a way to construct the
	// app and clients once, in init(), instead of on every request.
	db, err := connectDB()
	if err != nil {
		aelog.Errorf(ctx, "connectDB: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	defer db.Close()

	fs, err := gcs.NewFS(ctx, mustGetenv("GCS_BUCKET"))
	if err != nil {
		aelog.Errorf(ctx, "gcs.NewFS: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	mux := http.NewServeMux()
	app := &app.App{DB: db, FS: fs, Auth: auth, ViewURLBase: os.Getenv("PERFDATA_VIEW_URL_BASE")}
	app.RegisterOnMux(mux)
	mux.ServeHTTP(w, r)
}

func init() {
	http.HandleFunc("/", appHandler)
}
<commit_msg>storage/appengine: support service account OAuth<commit_after>// Copyright 2016 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build appengine

// Package appengine contains an AppEngine app for perfdata.golang.org
package appengine

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"golang.org/x/net/context"
	"golang.org/x/perf/storage/app"
	"golang.org/x/perf/storage/db"
	"golang.org/x/perf/storage/fs/gcs"
	oauth2 "google.golang.org/api/oauth2/v2"
	"google.golang.org/appengine"
	aelog "google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
	"google.golang.org/appengine/user"
)

// connectDB returns a DB initialized from the environment variables set in app.yaml. CLOUDSQL_CONNECTION_NAME, CLOUDSQL_USER, and CLOUDSQL_DATABASE must be set to point to the Cloud SQL instance. CLOUDSQL_PASSWORD can be set if needed.
func connectDB() (*db.DB, error) {
	var (
		connectionName = mustGetenv("CLOUDSQL_CONNECTION_NAME")
		user           = mustGetenv("CLOUDSQL_USER")
		password       = os.Getenv("CLOUDSQL_PASSWORD") // NOTE: password may be empty
		dbName         = mustGetenv("CLOUDSQL_DATABASE")
	)

	return db.OpenSQL("mysql", fmt.Sprintf("%s:%s@cloudsql(%s)/%s?interpolateParams=true", user, password, connectionName, dbName))
}

func mustGetenv(k string) string {
	v := os.Getenv(k)
	if v == "" {
		log.Panicf("%s environment variable not set.", k)
	}
	return v
}

func auth(w http.ResponseWriter, r *http.Request) (string, error) {
	ctx := appengine.NewContext(r)
	u, err := reqUser(ctx, r)
	if err != nil {
		return "", err
	}
	if u == "" {
		url, err := user.LoginURL(ctx, r.URL.String())
		if err != nil {
			return "", err
		}
		http.Redirect(w, r, url, http.StatusFound)
		return "", app.ErrResponseWritten
	}
	return u, nil
}

// reqUser gets the username from the request, trying AE user authentication, AE OAuth authentication, and Google OAuth authentication, in that order.
// If the request contains no authentication, "", nil is returned.
// If the request contains bogus authentication, an error is returned.
func reqUser(ctx context.Context, r *http.Request) (string, error) {
	u := user.Current(ctx)
	if u != nil {
		return u.Email, nil
	}
	if r.Header.Get("Authorization") == "" {
		return "", nil
	}
	u, err := user.CurrentOAuth(ctx, "https://www.googleapis.com/auth/userinfo.email")
	if err == nil {
		return u.Email, nil
	}
	return oauthServiceUser(ctx, r)
}

// oauthServiceUser authenticates the OAuth token from r's headers.
// This is necessary because user.CurrentOAuth does not work if the token is for a service account.
func oauthServiceUser(ctx context.Context, r *http.Request) (string, error) {
	tok := r.Header.Get("Authorization")
	if !strings.HasPrefix(tok, "Bearer ") {
		return "", errors.New("unknown Authorization header")
	}
	tok = tok[len("Bearer "):]

	hc := urlfetch.Client(ctx)
	service, err := oauth2.New(hc)
	if err != nil {
		return "", err
	}
	info, err := service.Tokeninfo().AccessToken(tok).Do()
	if err != nil {
		return "", err
	}

	if !info.VerifiedEmail || info.Email == "" {
		return "", errors.New("token does not contain verified e-mail address")
	}
	return info.Email, nil
}

// appHandler is the default handler, registered to serve "/".
// It creates a new App instance using the appengine Context and then
// dispatches the request to the App. The environment variable
// GCS_BUCKET must be set in app.yaml with the name of the bucket to
// write to. PERFDATA_VIEW_URL_BASE may be set to the URL that should
// be supplied in /upload responses.
func appHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	// App Engine does not return a context with a deadline set,
	// even though the request does have a deadline. urlfetch uses
	// a 5s default timeout if the context does not have a
	// deadline, so explicitly set a deadline to match the App
	// Engine timeout.
	ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
	defer cancel()
	// GCS clients need to be constructed with an AppEngine
	// context, so we can't actually make the App until the
	// request comes in.
	// TODO(quentin): Figure out if there's a way to construct the
	// app and clients once, in init(), instead of on every request.
	db, err := connectDB()
	if err != nil {
		aelog.Errorf(ctx, "connectDB: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	defer db.Close()

	fs, err := gcs.NewFS(ctx, mustGetenv("GCS_BUCKET"))
	if err != nil {
		aelog.Errorf(ctx, "gcs.NewFS: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	mux := http.NewServeMux()
	app := &app.App{DB: db, FS: fs, Auth: auth, ViewURLBase: os.Getenv("PERFDATA_VIEW_URL_BASE")}
	app.RegisterOnMux(mux)
	mux.ServeHTTP(w, r)
}

func init() {
	http.HandleFunc("/", appHandler)
}
<|endoftext|>


<commit_before>// Package local implements local storage
package local

import (
	"github.com/OShalakhin/cloud/storage"
	"io/ioutil"
	"net/url"
	"os"
)

type (
	// Storage to hold files locally
	Storage struct {
		Provider  storage.Provider
		Container storage.Container
	}
	// Info holds storage information
	Info struct {
		URL url.URL
		Dir string
	}
)

// Create file
func (s *Storage) Create(filename string, data []byte) error {
	if err := ioutil.WriteFile(s.Info.Dir+filename, data, 0644); err != nil {
		return err
	}
	return nil
}

// Read file
func (s *Storage) Read(filename string) ([]byte, error) {
	return ioutil.ReadFile(s.Info.Dir + filename)
}

// Update file
func (s *Storage) Update(filename string, data []byte) error {
	var err error
	// Remove
	if err = s.Delete(filename); err != nil {
		return err
	}
	// Create
	if err = s.Create(filename); err != nil {
		return err
	}
	return nil
}

// Delete file
func (s *Storage) Delete(filename string) error {
	return os.Remove(s.Info.Dir + filename)
}

// Authenticate storage. Local storage doesn't need authentication as storage
// happens locally in the filesystem.
func (s *Storage) Authenticate() error {
	return nil
}

// GetContainer where to store
func (s *Storage) GetContainer() (*storage.Container, error) {
	return new(storage.Container), nil
}

// GetURL where it must be accessed
func (s *Storage) GetURL() *url.URL {
	return new(url.URL)
}
<commit_msg>Issue #11 - add missing Info to the struct<commit_after>// Package local implements local storage
package local

import (
	"github.com/OShalakhin/cloud/storage"
	"io/ioutil"
	"net/url"
	"os"
)

type (
	// Storage to hold files locally
	Storage struct {
		Provider  storage.Provider
		Container storage.Container
		Info      *Info
	}
	// Info holds storage information
	Info struct {
		URL url.URL
		Dir string
	}
)

// Create file
func (s *Storage) Create(filename string, data []byte) error {
	if err := ioutil.WriteFile(s.Info.Dir+filename, data, 0644); err != nil {
		return err
	}
	return nil
}

// Read file
func (s *Storage) Read(filename string) ([]byte, error) {
	return ioutil.ReadFile(s.Info.Dir + filename)
}

// Update file
func (s *Storage) Update(filename string, data []byte) error {
	var err error
	// Remove
	if err = s.Delete(filename); err != nil {
		return err
	}
	// Create
	if err = s.Create(filename); err != nil {
		return err
	}
	return nil
}

// Delete file
func (s *Storage) Delete(filename string) error {
	return os.Remove(s.Info.Dir + filename)
}

// Authenticate storage. Local storage doesn't need authentication as storage
// happens locally in the filesystem.
func (s *Storage) Authenticate() error {
	return nil
}

// GetContainer where to store
func (s *Storage) GetContainer() (*storage.Container, error) {
	return new(storage.Container), nil
}

// GetURL where it must be accessed
func (s *Storage) GetURL() *url.URL {
	return new(url.URL)
}
<|endoftext|>


<commit_before>package nexus_test

import (
	"fmt"
	"github.com/hanjos/nexus"
	"github.com/hanjos/nexus/credentials"
	"github.com/hanjos/nexus/search"
	"reflect"
)

func Example() {
	n := nexus.New("https://maven.java.net", credentials.None)

	// obtaining all repositories in Nexus
	repositories, err := n.Repositories()
	if err != nil {
		fmt.Printf("%v: %v", reflect.TypeOf(err), err)
		return
	}

	// printing out all artifacts which are in a hosted repository, and have
	// in their groupId 'javax.enterprise' and a 'pom' packaging.
	for _, repo := range repositories {
		if repo.Type != "hosted" {
			continue
		}

		artifacts, err := n.Artifacts(
			search.InRepository{
				repo.Id,
				search.ByCoordinates{
					GroupId:    "javax.enterprise*",
					Classifier: "sources"}})

		if err != nil {
			fmt.Printf("%v: %v", reflect.TypeOf(err), err)
			return
		}

		for _, a := range artifacts {
			fmt.Println(a)
		}
	}
}

func ExampleNexus2x_Artifacts() {
	n := nexus.New("http://maven.java.net", credentials.None)

	// using a simple search
	artifacts, err := n.Artifacts(search.ByClassname("javax.servlet.Servlet"))

	// using a composite search
	artifacts, err := n.Artifacts(
		search.InRepository{
			"releases",
			search.ByKeyword("javax.enterprise")})
}
<commit_msg>Fixing the example.<commit_after>package nexus_test

import (
	"fmt"
	"github.com/hanjos/nexus"
	"github.com/hanjos/nexus/credentials"
	"github.com/hanjos/nexus/search"
	"reflect"
)

func Example() {
	n := nexus.New("https://maven.java.net", credentials.None)

	// obtaining all repositories in Nexus
	repositories, err := n.Repositories()
	if err != nil {
		fmt.Printf("%v: %v", reflect.TypeOf(err), err)
		return
	}

	// printing out all artifacts which are in a hosted repository, and have
	// in their groupId 'javax.enterprise' and a 'sources' classifier.
	for _, repo := range repositories {
		if repo.Type != "hosted" {
			continue
		}

		artifacts, err := n.Artifacts(
			search.InRepository{
				repo.Id,
				search.ByCoordinates{
					GroupId:    "javax.enterprise*",
					Classifier: "sources"}})

		if err != nil {
			fmt.Printf("%v: %v", reflect.TypeOf(err), err)
			return
		}

		for _, a := range artifacts {
			fmt.Println(a)
		}
	}
}

func ExampleNexus2x_Artifacts() {
	n := nexus.New("http://maven.java.net", credentials.None)

	// using a simple search
	artifacts, err := n.Artifacts(search.ByClassname("javax.servlet.Servlet"))

	// using a composite search
	artifacts, err := n.Artifacts(
		search.InRepository{
			"releases",
			search.ByKeyword("javax.enterprise")})
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"strconv"

	"github.com/boltdb/bolt"
	"github.com/daved/context"
)

func (n *node) iconHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "front/assets/public/icon/"+r.URL.Path)
}

func (n *node) assetsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[1:len(n.u.conf.AdminPathPrefix)+1] == n.u.conf.AdminPathPrefix {
		http.ServeFile(w, r, "front/assets/protected/"+r.URL.Path[9+len(n.u.conf.AdminPathPrefix):])
		return
	}
	http.ServeFile(w, r, "front/assets/public/"+r.URL.Path[8:])
}

func (n *node) assetsFlexHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[1:len(n.u.conf.AdminPathPrefix)+1] == n.u.conf.AdminPathPrefix {
		http.ServeFile(w, r, "front/assets/"+r.URL.Path[1+len(n.u.conf.AdminPathPrefix):])
		return
	}
	http.ServeFile(w, r, "front/assets/"+r.URL.Path[1:])
}

func (n *node) backupHandleFunc(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	err := n.u.ds.dcbsRsrcs.DB.View(func(tx *bolt.Tx) error {
		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", `attachment; filename="my.db"`)
		w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
		_, err := tx.WriteTo(w)
		return err
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (n *node) NotFound(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	http.NotFound(w, r)
}
<commit_msg>Correct context import in node handlers file.<commit_after>package main

import (
	"net/http"
	"strconv"

	"github.com/boltdb/bolt"
	"golang.org/x/net/context"
)

func (n *node) iconHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "front/assets/public/icon/"+r.URL.Path)
}

func (n *node) assetsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[1:len(n.u.conf.AdminPathPrefix)+1] == n.u.conf.AdminPathPrefix {
		http.ServeFile(w, r, "front/assets/protected/"+r.URL.Path[9+len(n.u.conf.AdminPathPrefix):])
		return
	}
	http.ServeFile(w, r, "front/assets/public/"+r.URL.Path[8:])
}

func (n *node) assetsFlexHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[1:len(n.u.conf.AdminPathPrefix)+1] == n.u.conf.AdminPathPrefix {
		http.ServeFile(w, r, "front/assets/"+r.URL.Path[1+len(n.u.conf.AdminPathPrefix):])
		return
	}
	http.ServeFile(w, r, "front/assets/"+r.URL.Path[1:])
}

func (n *node) backupHandleFunc(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	err := n.u.ds.dcbsRsrcs.DB.View(func(tx *bolt.Tx) error {
		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", `attachment; filename="my.db"`)
		w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
		_, err := tx.WriteTo(w)
		return err
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (n *node) NotFound(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	http.NotFound(w, r)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"io"
	"strconv"
	"time"
	"unicode/utf8"

	log "github.com/Sirupsen/logrus"
	serial "go.bug.st/serial.v1"
)

type SerialConfig struct {
	Name string
	Baud int

	// Size     int // 0 get translated to 8
	// Parity   SomeNewTypeToGetCorrectDefaultOf_None
	// StopBits SomeNewTypeToGetCorrectDefaultOf_1

	// RTSFlowControl bool
	// DTRFlowControl bool
	// XONFlowControl bool

	// CRLFTranslate bool
	// TimeoutStuff int
	RtsOn bool
	DtrOn bool
}

type serport struct {
	// The serial port connection.
	portConf *SerialConfig
	portIo   io.ReadWriteCloser

	done chan bool // signals the end of this request

	// Keep track of whether we're being actively closed
	// just so we don't show scary error messages
	isClosing bool

	isClosingDueToError bool

	// counter incremented on queue, decremented on write
	itemsInBuffer int

	// buffered channel containing up to 25600 outbound messages.
	sendBuffered chan string

	// unbuffered channel of outbound messages that bypass internal serial port buffer
	sendNoBuf chan string

	// Do we have an extra channel/thread to watch our buffer?
	BufferType string
	//bufferwatcher *BufferflowDummypause
	bufferwatcher Bufferflow
}

type Cmd struct {
	data                       string
	id                         string
	skippedBuffer              bool
	willHandleCompleteResponse bool
}

type CmdComplete struct {
	Cmd     string
	Id      string
	P       string
	BufSize int    `json:"-"`
	D       string `json:"-"`
}

type qwReport struct {
	Cmd  string
	QCnt int
	Id   string
	D    string `json:"-"`
	Buf  string `json:"-"`
	P    string
}

type SpPortMessage struct {
	// P string // the port, i.e. com22
	D string // the data, i.e. G0 X0 Y0
}

type SpPortMessageRaw struct {
	// P string // the port, i.e. com22
	D []byte // the data, i.e. G0 X0 Y0
}

func (p *serport) reader() {

	//var buf bytes.Buffer
	ch := make([]byte, 1024)
	timeCheckOpen := time.Now()
	var buffered_ch bytes.Buffer

	for {

		n, err := p.portIo.Read(ch)

		//if we detect that port is closing, break out o this for{} loop.
		if p.isClosing {
			strmsg := "Shutting down reader on " + p.portConf.Name
			log.Println(strmsg)
			h.broadcastSys <- []byte(strmsg)
			break
		}

		ch = append(buffered_ch.Bytes(), ch[:n]...)
		n += len(buffered_ch.Bytes())
		buffered_ch.Reset()

		// read can return legitimate bytes as well as an error
		// so process the bytes if n > 0
		if n > 0 {
			//log.Print("Read " + strconv.Itoa(n) + " bytes ch: " + string(ch))

			data := ""

			for i, w := 0, 0; i < n; i += w {
				runeValue, width := utf8.DecodeRune(ch[i:n])
				if runeValue == utf8.RuneError {
					buffered_ch.Write(append(ch[i:n]))
					break
				}
				if i == n {
					buffered_ch.Reset()
				}
				data += string(runeValue)
				w = width
			}

			//log.Print("The data i will convert to json is:")
			//log.Print(data)

			// give the data to our bufferflow so it can do it's work
			// to read/translate the data to see if it wants to block
			// writes to the serialport. each bufferflow type will decide
			// this on its own based on its logic, i.e. tinyg vs grbl vs others
			//p.b.bufferwatcher..OnIncomingData(data)
			p.bufferwatcher.OnIncomingData(data)

			// see if the OnIncomingData handled the broadcast back
			// to the user. this option was added in case the OnIncomingData wanted
			// to do something fancier or implementation specific, i.e. TinyG Buffer
			// actually sends back data on a perline basis rather than our method
			// where we just send the moment we get it. the reason for this is that
			// the browser was sometimes getting back packets out of order which
			// of course would screw things up when parsing

			if p.bufferwatcher.IsBufferGloballySendingBackIncomingData() == false {
				//m := SpPortMessage{"Alice", "Hello"}
				m := SpPortMessage{data}
				//log.Print("The m obj struct is:")
				//log.Print(m)

				//b, err := json.MarshalIndent(m, "", "\t")
				b, err := json.Marshal(m)
				if err != nil {
					log.Println(err)
					h.broadcastSys <- []byte("Error creating json on " + p.portConf.Name + " " +
						err.Error() + " The data we were trying to convert is: " + string(ch[:n]))
					break
				}
				//log.Print("Printing out json byte data...")
				//log.Print(string(b))
				h.broadcastSys <- b
			}
		}

		// double check that we got characters in the buffer
		// before deciding if an EOF is legitimately a reason
		// to close the port because we're seeing that on some
		// os's like Linux/Ubuntu you get an EOF when you open
		// the port. Perhaps the EOF was buffered from a previous
		// close and the OS doesn't clear out that buffer on a new
		// connect. This means we'll only catch EOF's when there are
		// other characters with it, but that seems to work ok
		if n <= 0 {
			if err == io.EOF || err == io.ErrUnexpectedEOF {
				// hit end of file
				log.Println("Hit end of file on serial port")
				h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Got EOF (End of File) on port which usually means another app other than Serial Port JSON Server is locking your port. " + err.Error() + "\",\"Port\":\"" + p.portConf.Name + "\",\"Baud\":" + strconv.Itoa(p.portConf.Baud) + "}")

			}

			if err != nil {
				log.Println(err)
				h.broadcastSys <- []byte("Error reading on " + p.portConf.Name + " " +
					err.Error() + " Closing port.")
				h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Got error reading on port. " + err.Error() + "\",\"Port\":\"" + p.portConf.Name + "\",\"Baud\":" + strconv.Itoa(p.portConf.Baud) + "}")
				p.isClosingDueToError = true
				break
			}

			// Keep track of time difference between two consecutive read with n == 0 and err == nil
			// we get here if the port has been disconnected while open (cpu usage will jump to 100%)
			// let's close the port only if the events are extremely fast (<1ms)
			if err == nil {
				diff := time.Since(timeCheckOpen)
				if diff.Nanoseconds() < 1000000 {
					p.isClosingDueToError = true
					break
				}
				timeCheckOpen = time.Now()
			}
		}
	}
	if p.isClosingDueToError {
		spCloseReal(p)
	}
}

// this method runs as its own thread because it's instantiated
// as a "go" method. so if it blocks inside, it is ok
func (p *serport) writerBuffered() {

	// this method can panic if user closes serial port and something is
	// in BlockUntilReady() and then a send occurs on p.sendNoBuf

	defer func() {
		if e := recover(); e != nil {
			log.Println("Got panic: ", e)
		}
	}()

	// this for loop blocks on p.sendBuffered until that channel
	// sees something come in
	for data := range p.sendBuffered {

		// we want to block here if we are being asked to pause.
		goodToGo, _ := p.bufferwatcher.BlockUntilReady(string(data), "")

		if goodToGo == false {
			log.Println("We got back from BlockUntilReady() but apparently we must cancel this cmd")
			// since we won't get a buffer decrement in p.sendNoBuf, we must do it here
			p.itemsInBuffer--
		} else {
			// send to the non-buffered serial port writer
			//log.Println("About to send to p.sendNoBuf channel")
			p.sendNoBuf <- data
		}
	}
	msgstr := "writerBuffered just got closed. make sure you make a new one. port:" + p.portConf.Name
	log.Println(msgstr)
	h.broadcastSys <- []byte(msgstr)
}

// this method runs as its own thread because it's instantiated
// as a "go" method. so if it blocks inside, it is ok
func (p *serport) writerNoBuf() {
	// this for loop blocks on p.send until that channel
	// sees something come in
	for data := range p.sendNoBuf {

		// if we get here, we were able to write successfully
		// to the serial port because it blocks until it can write

		// decrement counter
		p.itemsInBuffer--
		log.Printf("itemsInBuffer:%v\n", p.itemsInBuffer)

		// FINALLY, OF ALL THE CODE IN THIS PROJECT
		// WE TRULY/FINALLY GET TO WRITE TO THE SERIAL PORT!
		n2, err := p.portIo.Write([]byte(data))

		log.Print("Just wrote ", n2, " bytes to serial: ", string(data))
		if err != nil {
			errstr := "Error writing to " + p.portConf.Name + " " + err.Error() + " Closing port."
			log.Print(errstr)
			h.broadcastSys <- []byte(errstr)
			break
		}
	}
	msgstr := "Shutting down writer on " + p.portConf.Name
	log.Println(msgstr)
	h.broadcastSys <- []byte(msgstr)
	p.portIo.Close()
	spListDual(false)
	spList(false)
}

func spHandlerOpen(portname string, baud int, buftype string) {

	log.Print("Inside spHandler")

	var out bytes.Buffer

	out.WriteString("Opening serial port ")
	out.WriteString(portname)
	out.WriteString(" at ")
	out.WriteString(strconv.Itoa(baud))
	out.WriteString(" baud")
	log.Print(out.String())

	conf := &SerialConfig{Name: portname, Baud: baud, RtsOn: true}

	mode := &serial.Mode{
		BaudRate: baud,
	}

	sp, err := serial.Open(portname, mode)
	log.Print("Just tried to open port")
	if err != nil {
		//log.Fatal(err)
		log.Print("Error opening port " + err.Error())
		//h.broadcastSys <- []byte("Error opening port. " + err.Error())
		h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Error opening port. " + err.Error() + "\",\"Port\":\"" + conf.Name + "\",\"Baud\":" + strconv.Itoa(conf.Baud) + "}")

		return
	}
	log.Print("Opened port successfully")
	//p := &serport{send: make(chan []byte, 256), portConf: conf, portIo: sp}
	// we can go up to 256,000 lines of gcode in the buffer
	p := &serport{sendBuffered: make(chan string, 256000), sendNoBuf: make(chan string), portConf: conf, portIo: sp, BufferType: buftype}

	var bw Bufferflow

	if buftype == "timed" {
		bw = &BufferflowTimed{Name: "timed", Port: portname, Output: h.broadcastSys, Input: make(chan string)}
	} else if buftype == "timedraw" {
		bw = &BufferflowTimedRaw{Name: "timedraw", Port: portname, Output: h.broadcastSys, Input: make(chan string)}
	} else {
		bw = &BufferflowDefault{Port: portname}
	}

	bw.Init()
	p.bufferwatcher = bw

	sh.register <- p
	defer func() { sh.unregister <- p }()

	spListDual(false)
	spList(false)

	// this is internally buffered thread to not send to serial port if blocked
	go p.writerBuffered()
	// this is thread to send to serial port regardless of block
	go p.writerNoBuf()
	p.reader()

	spListDual(false)
	spList(false)

	//go p.reader()
	//p.done = make(chan bool)
	//<-p.done
}

func spHandlerClose(p *serport) {
	p.isClosing = true
	h.broadcastSys <- []byte("Closing serial port " + p.portConf.Name)
	spCloseReal(p)
}

func spCloseReal(p *serport) {
	p.bufferwatcher.Close()
	p.portIo.Close()
	spListDual(false)
	spList(false)
}
<commit_msg>Solve serial crash (again)<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"io"
	"strconv"
	"time"
	"unicode/utf8"

	log "github.com/Sirupsen/logrus"
	serial "go.bug.st/serial.v1"
)

type SerialConfig struct {
	Name string
	Baud int

	// Size     int // 0 get translated to 8
	// Parity   SomeNewTypeToGetCorrectDefaultOf_None
	// StopBits SomeNewTypeToGetCorrectDefaultOf_1

	// RTSFlowControl bool
	// DTRFlowControl bool
	// XONFlowControl bool

	// CRLFTranslate bool
	// TimeoutStuff int
	RtsOn bool
	DtrOn bool
}

type serport struct {
	// The serial port connection.
	portConf *SerialConfig
	portIo   io.ReadWriteCloser

	done chan bool // signals the end of this request

	// Keep track of whether we're being actively closed
	// just so we don't show scary error messages
	isClosing bool

	isClosingDueToError bool

	// counter incremented on queue, decremented on write
	itemsInBuffer int

	// buffered channel containing up to 25600 outbound messages.
	sendBuffered chan string

	// unbuffered channel of outbound messages that bypass internal serial port buffer
	sendNoBuf chan string

	// Do we have an extra channel/thread to watch our buffer?
	BufferType string
	//bufferwatcher *BufferflowDummypause
	bufferwatcher Bufferflow
}

type Cmd struct {
	data                       string
	id                         string
	skippedBuffer              bool
	willHandleCompleteResponse bool
}

type CmdComplete struct {
	Cmd     string
	Id      string
	P       string
	BufSize int    `json:"-"`
	D       string `json:"-"`
}

type qwReport struct {
	Cmd  string
	QCnt int
	Id   string
	D    string `json:"-"`
	Buf  string `json:"-"`
	P    string
}

type SpPortMessage struct {
	// P string // the port, i.e. com22
	D string // the data, i.e. G0 X0 Y0
}

type SpPortMessageRaw struct {
	// P string // the port, i.e. com22
	D []byte // the data, i.e. G0 X0 Y0
}

func (p *serport) reader() {

	//var buf bytes.Buffer
	ch := make([]byte, 1024)
	timeCheckOpen := time.Now()
	var buffered_ch bytes.Buffer

	for {

		n, err := p.portIo.Read(ch)

		//if we detect that port is closing, break out o this for{} loop.
		if p.isClosing {
			strmsg := "Shutting down reader on " + p.portConf.Name
			log.Println(strmsg)
			h.broadcastSys <- []byte(strmsg)
			break
		}

		if err == nil {
			ch = append(buffered_ch.Bytes(), ch[:n]...)
			n += len(buffered_ch.Bytes())
			buffered_ch.Reset()
		}

		// read can return legitimate bytes as well as an error
		// so process the bytes if n > 0
		if n > 0 {
			//log.Print("Read " + strconv.Itoa(n) + " bytes ch: " + string(ch))

			data := ""

			for i, w := 0, 0; i < n; i += w {
				runeValue, width := utf8.DecodeRune(ch[i:n])
				if runeValue == utf8.RuneError {
					buffered_ch.Write(append(ch[i:n]))
					break
				}
				if i == n {
					buffered_ch.Reset()
				}
				data += string(runeValue)
				w = width
			}

			//log.Print("The data i will convert to json is:")
			//log.Print(data)

			// give the data to our bufferflow so it can do it's work
			// to read/translate the data to see if it wants to block
			// writes to the serialport. each bufferflow type will decide
			// this on its own based on its logic, i.e. tinyg vs grbl vs others
			//p.b.bufferwatcher..OnIncomingData(data)
			p.bufferwatcher.OnIncomingData(data)

			// see if the OnIncomingData handled the broadcast back
			// to the user. this option was added in case the OnIncomingData wanted
			// to do something fancier or implementation specific, i.e. TinyG Buffer
			// actually sends back data on a perline basis rather than our method
			// where we just send the moment we get it. the reason for this is that
			// the browser was sometimes getting back packets out of order which
			// of course would screw things up when parsing

			if p.bufferwatcher.IsBufferGloballySendingBackIncomingData() == false {
				//m := SpPortMessage{"Alice", "Hello"}
				m := SpPortMessage{data}
				//log.Print("The m obj struct is:")
				//log.Print(m)

				//b, err := json.MarshalIndent(m, "", "\t")
				b, err := json.Marshal(m)
				if err != nil {
					log.Println(err)
					h.broadcastSys <- []byte("Error creating json on " + p.portConf.Name + " " +
						err.Error() + " The data we were trying to convert is: " + string(ch[:n]))
					break
				}
				//log.Print("Printing out json byte data...")
				//log.Print(string(b))
				h.broadcastSys <- b
			}
		}

		// double check that we got characters in the buffer
		// before deciding if an EOF is legitimately a reason
		// to close the port because we're seeing that on some
		// os's like Linux/Ubuntu you get an EOF when you open
		// the port. Perhaps the EOF was buffered from a previous
		// close and the OS doesn't clear out that buffer on a new
		// connect. This means we'll only catch EOF's when there are
		// other characters with it, but that seems to work ok
		if n <= 0 {
			if err == io.EOF || err == io.ErrUnexpectedEOF {
				// hit end of file
				log.Println("Hit end of file on serial port")
				h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Got EOF (End of File) on port which usually means another app other than Serial Port JSON Server is locking your port. " + err.Error() + "\",\"Port\":\"" + p.portConf.Name + "\",\"Baud\":" + strconv.Itoa(p.portConf.Baud) + "}")

			}

			if err != nil {
				log.Println(err)
				h.broadcastSys <- []byte("Error reading on " + p.portConf.Name + " " +
					err.Error() + " Closing port.")
				h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Got error reading on port. " + err.Error() + "\",\"Port\":\"" + p.portConf.Name + "\",\"Baud\":" + strconv.Itoa(p.portConf.Baud) + "}")
				p.isClosingDueToError = true
				break
			}

			// Keep track of time difference between two consecutive read with n == 0 and err == nil
			// we get here if the port has been disconnected while open (cpu usage will jump to 100%)
			// let's close the port only if the events are extremely fast (<1ms)
			if err == nil {
				diff := time.Since(timeCheckOpen)
				if diff.Nanoseconds() < 1000000 {
					p.isClosingDueToError = true
					break
				}
				timeCheckOpen = time.Now()
			}
		}
	}
	if p.isClosingDueToError {
		spCloseReal(p)
	}
}

// this method runs as its own thread because it's instantiated
// as a "go" method. so if it blocks inside, it is ok
func (p *serport) writerBuffered() {

	// this method can panic if user closes serial port and something is
	// in BlockUntilReady() and then a send occurs on p.sendNoBuf

	defer func() {
		if e := recover(); e != nil {
			log.Println("Got panic: ", e)
		}
	}()

	// this for loop blocks on p.sendBuffered until that channel
	// sees something come in
	for data := range p.sendBuffered {

		// we want to block here if we are being asked to pause.
		goodToGo, _ := p.bufferwatcher.BlockUntilReady(string(data), "")

		if goodToGo == false {
			log.Println("We got back from BlockUntilReady() but apparently we must cancel this cmd")
			// since we won't get a buffer decrement in p.sendNoBuf, we must do it here
			p.itemsInBuffer--
		} else {
			// send to the non-buffered serial port writer
			//log.Println("About to send to p.sendNoBuf channel")
			p.sendNoBuf <- data
		}
	}
	msgstr := "writerBuffered just got closed. make sure you make a new one. port:" + p.portConf.Name
	log.Println(msgstr)
	h.broadcastSys <- []byte(msgstr)
}

// this method runs as its own thread because it's instantiated
// as a "go" method. so if it blocks inside, it is ok
func (p *serport) writerNoBuf() {
	// this for loop blocks on p.send until that channel
	// sees something come in
	for data := range p.sendNoBuf {

		// if we get here, we were able to write successfully
		// to the serial port because it blocks until it can write

		// decrement counter
		p.itemsInBuffer--
		log.Printf("itemsInBuffer:%v\n", p.itemsInBuffer)

		// FINALLY, OF ALL THE CODE IN THIS PROJECT
		// WE TRULY/FINALLY GET TO WRITE TO THE SERIAL PORT!
		n2, err := p.portIo.Write([]byte(data))

		log.Print("Just wrote ", n2, " bytes to serial: ", string(data))
		if err != nil {
			errstr := "Error writing to " + p.portConf.Name + " " + err.Error() + " Closing port."
			log.Print(errstr)
			h.broadcastSys <- []byte(errstr)
			break
		}
	}
	msgstr := "Shutting down writer on " + p.portConf.Name
	log.Println(msgstr)
	h.broadcastSys <- []byte(msgstr)
	p.portIo.Close()
	spListDual(false)
	spList(false)
}

func spHandlerOpen(portname string, baud int, buftype string) {

	log.Print("Inside spHandler")

	var out bytes.Buffer

	out.WriteString("Opening serial port ")
	out.WriteString(portname)
	out.WriteString(" at ")
	out.WriteString(strconv.Itoa(baud))
	out.WriteString(" baud")
	log.Print(out.String())

	conf := &SerialConfig{Name: portname, Baud: baud, RtsOn: true}

	mode := &serial.Mode{
		BaudRate: baud,
	}

	sp, err := serial.Open(portname, mode)
	log.Print("Just tried to open port")
	if err != nil {
		//log.Fatal(err)
		log.Print("Error opening port " + err.Error())
		//h.broadcastSys <- []byte("Error opening port. " + err.Error())
		h.broadcastSys <- []byte("{\"Cmd\":\"OpenFail\",\"Desc\":\"Error opening port. " + err.Error() + "\",\"Port\":\"" + conf.Name + "\",\"Baud\":" + strconv.Itoa(conf.Baud) + "}")

		return
	}
	log.Print("Opened port successfully")
	//p := &serport{send: make(chan []byte, 256), portConf: conf, portIo: sp}
	// we can go up to 256,000 lines of gcode in the buffer
	p := &serport{sendBuffered: make(chan string, 256000), sendNoBuf: make(chan string), portConf: conf, portIo: sp, BufferType: buftype}

	var bw Bufferflow

	if buftype == "timed" {
		bw = &BufferflowTimed{Name: "timed", Port: portname, Output: h.broadcastSys, Input: make(chan string)}
	} else if buftype == "timedraw" {
		bw = &BufferflowTimedRaw{Name: "timedraw", Port: portname, Output: h.broadcastSys, Input: make(chan string)}
	} else {
		bw = &BufferflowDefault{Port: portname}
	}

	bw.Init()
	p.bufferwatcher = bw

	sh.register <- p
	defer func() { sh.unregister <- p }()

	spListDual(false)
	spList(false)

	// this is internally buffered thread to not send to serial port if blocked
	go p.writerBuffered()
	// this is thread to send to serial port regardless of block
	go p.writerNoBuf()
	p.reader()

	spListDual(false)
	spList(false)

	//go p.reader()
	//p.done = make(chan bool)
	//<-p.done
}

func spHandlerClose(p *serport) {
	p.isClosing = true
	h.broadcastSys <- []byte("Closing serial port " + p.portConf.Name)
	spCloseReal(p)
}

func spCloseReal(p *serport) {
	p.bufferwatcher.Close()
	p.portIo.Close()
	spListDual(false)
	spList(false)
}
<|endoftext|>