Cервер на Go для мобильной стратегии

27
Сервер на Go для мобильной стратегии armor5games.com

Transcript of Cервер на Go для мобильной стратегии

Page 1: Cервер на Go для мобильной стратегии

Сервер на Go для мобильной стратегии

armor5games.com

Page 2: Cервер на Go для мобильной стратегии
Page 3: Cервер на Go для мобильной стратегии

github.com/gocraft/web

github.com/gocraft/dbr

github.com/gocraft/health

github.com/penlook/daemon

github.com/pmylund/go-cache

bonus/dbr

Page 4: Cервер на Go для мобильной стратегии

github.com/gocraft/web

RoutersContext

Middleware

Page 5: Cервер на Go для мобильной стратегии

type Context struct { ReadSession *dbr.Session WriteSession *dbr.Session HealthStream *health.Stream Cache *cache.Cache User *user.Params}

router := web.New(context.Context{}).Middleware((*context.Context).AddDbrSession).Middleware((*context.Context).LogURL)

router.Get("/crossdomain.xml",CrossDomainHandler)

Page 6: Cервер на Go для мобильной стратегии

func (c *Context) AddDbrSession(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {

c.HealthStream = health.NewStream() c.ReadSession = GetReadSession() c.WriteSession = GetWriteSession() next(rw, req)}

func CrossDomainHandler(rw web.ResponseWriter, req *web.Request) {rw.Header().Set("Content-type", "application/xml; charset=utf-8")fmt.Fprintln(rw, `<?xml version="1.0"?>

<cross-domain-policy><allow-access-from domain="*"/></cross-domain-policy>`)}

Page 7: Cервер на Go для мобильной стратегии

userRouter := router.Subrouter(context.Context{}, "/user")userRouter.Middleware((*context.Context).UserRequired)userRouter.Get("/", user.UserGet)

func (c *Context) UserRequired(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {

c.User := new(user.Params)if err := c.User.LoadFromAccessToken(req); err == nil {

go userLastActive(c)next(rw, req)return

}fmt.Fprintln(rw, “invalid access token”)

}

Page 8: Cервер на Go для мобильной стратегии

func UserGet(c *context.Context, rw web.ResponseWriter, req *web.Request) {job := c.HealthStream.NewJob("user/get")answer.AnswerJson(c.User, rw, req)job.Complete(health.Success)

}

Page 9: Cервер на Go для мобильной стратегии

github.com/gocraft/dbrMySql

Query BuilderTransactions

Interpolate

Page 10: Cервер на Go для мобильной стратегии

type UserParams struct { ID int64 `db:"ID"` Name string `db:"Name"` AccessToken dbr.NullString `db:"AccessToken"`}

func LoadFromAccessToken(req *web.Request) {user_params := new(UserParams)err := ReadSession.Select("*").From("users").

Where("AccessToken=?", req.GetAccessToken()).LoadStruct(user_params)

return err}

Page 11: Cервер на Go для мобильной стратегии

func userLastActive(c *Context) {c.WriteSession.

Update("user_session").Set("Last", time.Now().Unix()).Where("User=?", c.User.ID).

Exec()}

Page 12: Cервер на Go для мобильной стратегии

type User_stats struct { User int64 `db:"User"` AdvWins int64 `db:"AdvWins"` AdvLose int64 `db:"AdvLose"` DailyWin int64 `db:"DailyWin"` DailyLose int64 `db:"DailyLose"` PvpaAttacks int64 `db:"PvpaAttacks"` PvpaWins int64 `db:"PvpaWins"` PvpaDefs int64 `db:"PvpaDefs"` Sieges int64 `db:"Sieges"` SiegesWins int64 `db:"SiegesWins"` SiegesDefs int64 `db:"SiegesDefs"`}

Page 13: Cервер на Go для мобильной стратегии

func CreateUserStatistics() error {stats := new(User_stats)

tx, err := WriteSession.Begin()

defer tx.RollbackUnlessCommitted()

result, err := tx.InsertInto("user_stats"). Columns("User", "AdvWins", "AdvLose", "DailyWin", "DailyLose", "PvpaAttacks", "PvpaWins", "PvpaDefs",

"Sieges", "SiegesWins", "SiegesDefs").Record(stats).Exec()

tx.Commit()}

Page 14: Cервер на Go для мобильной стратегии

github.com/gocraft/healthJobs

EventsTimings

Errors

Page 15: Cервер на Go для мобильной стратегии

var stream = health.NewStream()

// jsonSink for healthTopsink := health.NewJsonPollingSink(time.Minute, time.Minute * 5)stream.AddSink(sink)

// stdout sinkstream.AddSink(&health.WriterSink{os.Stdout})

// https://bugsnag.com/ sinkstream.AddSink(bugsnag.NewSink(&bugsnag.Config{APIKey: "supersecretapikey"}))

Page 16: Cервер на Go для мобильной стратегии

func UserBuildingsUpgrade(c *context.Context, rw web.ResponseWriter, req *web.Request) {

job := c.HealthStream.NewJob(“user/building/upgrade”)type := req.GetBuildingType()if isBuildingTypeValid(type) == false {

answer.answerErrorString(“invalid building type”, rw, req)job.Event(“invalid building type”)job.Complete(health.Junk)return

}if c.User.Money < getBuildingUpgradePrice(type) {

answer.answerErrorString(“no money”, rw, req)job.EventKv(“cheater detected”,

map[string]string{“User” : c.User.ID, “cheater” : ”true”})job.Complete(health.Junk)return

}

Page 17: Cервер на Go для мобильной стратегии

if err := buildingUpgrade(type, c.User); err != nil {answer.answerErrorString(“db error”, rw, req)job.EventErr(“buildingUpgrade: ”, err)job.Complete(health.Error)return

}

if err := userMoneyMinus(c.User, price); err != nil {answer.answerErrorString(“db error”, rw, req)job.EventErr(“userMoneyMinus: ”, err)job.Complete(health.Error)return

}

job.Complete(health.Success)}

Page 18: Cервер на Go для мобильной стратегии

github.com/penlook/daemon

ServiceSignals

Daemon

Page 19: Cервер на Go для мобильной стратегии

...go serv.Serve(listener)interrupt := make(chan os.Signal, 1)signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)for {

select {case killSignal := <-interrupt:

stdlog.Println("Got signal:", killSignal) stdlog.Println("Stoping listening on ", serv.Addr) listener.Close() if killSignal == os.Interrupt { return "Daemon was interruped by system signal", nil }

return "Daemon was killed", nil}

}

Page 20: Cервер на Go для мобильной стратегии

github.com/pmylund/go-cache

CacheCache

CacheCache

Page 21: Cервер на Go для мобильной стратегии

package context

c.Cache = cache.New(time.Minute * 100, time.Minute * 1)----------------------------------------------------------------------------package static

import ( "strconv"

"github.com/gocraft/web" "github.com/pmylund/go-cache")

const ( CACHE_STATIC_EQUIP string = "static/equip")

Page 22: Cервер на Go для мобильной стратегии

func StaticEquip(c *context.Context, rw web.ResponseWriter, req *web.Request) { if data, ok := c.Cache.Get(CACHE_STATIC_EQUIP); ok { answer.CachedAnswer(data, rw, req) return } var equips []*Equip _, err := c.ReadSession.Select("*").From("equipments").LoadStructs(&equips)

forCache := make(map[string][]*Equip) forCache[“Equip”] = equips answerJsonString := json.Marshal(&forCache) c.Cache.Set(CACHE_STATIC_EQUIP, answerJsonString,

cache.DefaultExpiration) answer.CachedAnswer(answerJsonString, rw, req)}

Page 23: Cервер на Go для мобильной стратегии

BonusЭрик Реймонд: Искусство программирования в UNIX

Правило генерации: Избегайте ручного набора кода; при любом удобном случае пишите

программы, которые бы писали программы.

Page 24: Cервер на Go для мобильной стратегии

CREATE TABLE Persons(

PersonID int,LastName varchar(255),FirstName varchar(255),Address varchar(255),City varchar(255)

);type Persons struct {

PersonID int64 `db:"PersonID"`LastName string `db:"LastName"`FirstName string `db:"FirstName"`Address dbr.NullString `db:"Address"`City dbr.NullString `db:"City"`

}

Page 25: Cервер на Go для мобильной стратегии

"show full tables where Table_Type != 'VIEW'"

Page 26: Cервер на Go для мобильной стратегии

package databasemodels

import {{.DbrUsed}}"github.com/gocraft/dbr"

type {{.Table}} struct { {{range .Fields}}{{.Name}} {{.Type}} {{.Tag}} {{end}}}