package main import ( "context" "fmt" "time" ) type command interface { run(context.Context) } type commandHandler struct { commandChan chan command } func newCommandHandler() *commandHandler { return &commandHandler{ commandChan: make(chan command, 50), } } func (h *commandHandler) handle(c command) { h.commandChan <- c } func (h *commandHandler) run(ctx context.Context) { for { select { case <-ctx.Done(): return case c := <-h.commandChan: // TODO if close ?? c.run(ctx) } } } type joinCommand struct { name string } func (c *joinCommand) run(ctx context.Context) { db := getDB(ctx) log := getLogger(ctx) pb := getDPlayersBoard(ctx) ms := getMessageStorage(ctx) err := ms.apply(ctx, fmt.Sprintf("join:%s", c.name), time.Minute/2, func(d interface{}) (string, interface{}) { if v, _ := d.(bool); v { return fmt.Sprintf("%s подключился снова", c.name), true } return fmt.Sprintf("%s подключился", c.name), true }) if err != nil { log.Error(err) } p, err := db.getPlayerByName(ctx, c.name) if err != nil { log.Error(err) return } if p == nil { p, err = db.createPlayer(ctx, c.name, time.Now()) if err != nil { log.Error(err) return } } else { err = db.updatePlayerLastLogin(ctx, p.id, time.Now()) if err != nil { log.Error(err) return } } pb.getPlayerBoard(p.id).setOnline(true) err = pb.update(ctx, achievementVeryLongOnline) if err != nil { log.Error(err) } } type quitCommand struct { name string } func (c *quitCommand) run(ctx context.Context) { db := getDB(ctx) log := getLogger(ctx) pb := getDPlayersBoard(ctx) ms := getMessageStorage(ctx) err := ms.apply(ctx, fmt.Sprintf("quit:%s", c.name), time.Minute/2, func(d interface{}) (string, interface{}) { if v, _ := d.(bool); v { return fmt.Sprintf("%s отключился снова", c.name), true } return fmt.Sprintf("%s отключился", c.name), true }) if err != nil { log.Error(err) } p, err := db.getPlayerByName(ctx, c.name) if err != nil { log.Error(err) return } err = db.updatePlayerLastLogout(ctx, p.id, time.Now()) if err != nil { log.Error(err) } err = db.increasePlayerOnlineDuration(ctx, p.id, time.Since(p.lastLogin)) if err != nil { log.Error(err) } pb.getPlayerBoard(p.id).setOnline(false) err = pb.update(ctx, achievementVeryLongOnline) if err != nil { log.Error(err) } } type deathCommand struct { name string deathType string } func (c *deathCommand) run(ctx context.Context) { db := getDB(ctx) log := getLogger(ctx) pb := getDPlayersBoard(ctx) ms := getMessageStorage(ctx) err := ms.apply(ctx, fmt.Sprintf("death:%s", c.name), time.Minute/2, func(d interface{}) (string, interface{}) { if v, _ := d.(bool); v { return fmt.Sprintf("%s умудрился опять помереть от %s", c.name, c.deathType), true } return fmt.Sprintf("%s пал смертью храбрых от %s", c.name, c.deathType), true }) if err != nil { log.Error(err) } p, err := db.getPlayerByName(ctx, c.name) if err != nil { log.Error(err) return } err = db.increasePlayerDeath(ctx, p.id, 1) if err != nil { log.Error(err) } err = pb.update(ctx, achievementDeathless, achievementBestFeeder) if err != nil { log.Error(err) } } type killCommand struct { name string entity string } func (c *killCommand) run(ctx context.Context) { db := getDB(ctx) log := getLogger(ctx) pb := getDPlayersBoard(ctx) ms := getMessageStorage(ctx) p, err := db.getPlayerByName(ctx, c.name) if err != nil { log.Error(err) return } err = db.increasePlayerEntryKills(ctx, p.id, c.entity, 1) if err != nil { log.Error(err) } f := func(d interface{}) (string, interface{}) { if fragsNum, ok := d.(int); ok { fragsNum++ return fmt.Sprintf("%s убил %s ✗ *%d*", p.name, c.entity, fragsNum), fragsNum } return fmt.Sprintf("%s убил %s", p.name, c.entity), 1 } err = ms.apply(ctx, fmt.Sprintf("kill:%s:%s", p.id, c.entity), time.Minute/2, f) if err != nil { log.Error(err) } err = pb.update(ctx, achievementMaxFrags, achievementPeaceable) if err != nil { log.Error(err) } } type changeLevelCommand struct { name string newLevel int } func (c *changeLevelCommand) run(ctx context.Context) { db := getDB(ctx) log := getLogger(ctx) pb := getDPlayersBoard(ctx) p, err := db.getPlayerByName(ctx, c.name) if err != nil { log.Error(err) return } err = db.updatePlayerLevel(ctx, p.id, c.newLevel) if err != nil { log.Error(err) } err = pb.update(ctx, achievementMaxLevel) if err != nil { log.Error(err) } }