Cервер на Go для мобильной стратегии
-
Upload
artem-kovardin -
Category
Internet
-
view
1.475 -
download
3
Transcript of Cервер на Go для мобильной стратегии
Сервер на Go для мобильной стратегии
armor5games.com
github.com/gocraft/web
github.com/gocraft/dbr
github.com/gocraft/health
github.com/penlook/daemon
github.com/pmylund/go-cache
bonus/dbr
github.com/gocraft/web
RoutersContext
Middleware
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)
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>`)}
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”)
}
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)
}
github.com/gocraft/dbrMySql
Query BuilderTransactions
Interpolate
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}
func userLastActive(c *Context) {c.WriteSession.
Update("user_session").Set("Last", time.Now().Unix()).Where("User=?", c.User.ID).
Exec()}
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"`}
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()}
github.com/gocraft/healthJobs
EventsTimings
Errors
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"}))
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
}
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)}
github.com/penlook/daemon
ServiceSignals
Daemon
...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}
}
github.com/pmylund/go-cache
CacheCache
CacheCache
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")
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)}
BonusЭрик Реймонд: Искусство программирования в UNIX
Правило генерации: Избегайте ручного набора кода; при любом удобном случае пишите
программы, которые бы писали программы.
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"`
}
"show full tables where Table_Type != 'VIEW'"
package databasemodels
import {{.DbrUsed}}"github.com/gocraft/dbr"
type {{.Table}} struct { {{range .Fields}}{{.Name}} {{.Type}} {{.Tag}} {{end}}}
Виталий Симирнин[email protected]://golang-ru.slack.com/team/finalist