fix
This commit is contained in:
@@ -73,13 +73,13 @@ func (g gameSettler) RecordGameResult(userID int64, won bool) {
|
|||||||
g.eco.RecordGameResult(context.Background(), userID, won)
|
g.eco.RecordGameResult(context.Background(), userID, won)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayerProfile سکه و نشانِ رتبهی بازیکن را برای نمایش سرِ میز برمیگرداند.
|
// PlayerProfile سکه، نشانِ رتبه و آواتارِ بازیکن را برای نمایش سرِ میز برمیگرداند.
|
||||||
func (g gameSettler) PlayerProfile(userID int64) (int64, string) {
|
func (g gameSettler) PlayerProfile(userID int64) (int64, string, string) {
|
||||||
p, err := g.eco.GetProfile(context.Background(), userID)
|
p, err := g.eco.GetProfile(context.Background(), userID)
|
||||||
if err != nil || p == nil {
|
if err != nil || p == nil {
|
||||||
return 0, ""
|
return 0, "", ""
|
||||||
}
|
}
|
||||||
return p.Coins, p.RankTier
|
return p.Coins, p.RankTier, p.Avatar
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChargeTicket یک بلیت برای بُرِ مجدد مصرف میکند (خطا اگر بلیت کافی نباشد).
|
// ChargeTicket یک بلیت برای بُرِ مجدد مصرف میکند (خطا اگر بلیت کافی نباشد).
|
||||||
|
|||||||
@@ -11,18 +11,29 @@ cd "$(dirname "$0")"
|
|||||||
|
|
||||||
echo "==> build linux/amd64 (CGO off, pure-Go sqlite)"
|
echo "==> build linux/amd64 (CGO off, pure-Go sqlite)"
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /tmp/hakemsho-linux ./cmd/server
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /tmp/hakemsho-linux ./cmd/server
|
||||||
|
LOCAL_SHA=$(shasum -a 256 /tmp/hakemsho-linux | cut -d' ' -f1)
|
||||||
|
echo " sha256=$LOCAL_SHA"
|
||||||
|
|
||||||
echo "==> upload to $HOST"
|
echo "==> upload to $HOST"
|
||||||
scp -i "$KEY" -o StrictHostKeyChecking=no /tmp/hakemsho-linux "$HOST:$REMOTE_DIR/hakemsho.new"
|
scp -i "$KEY" -o StrictHostKeyChecking=no /tmp/hakemsho-linux "$HOST:$REMOTE_DIR/hakemsho.new"
|
||||||
|
|
||||||
echo "==> swap in + restart (zero-config; data & env untouched)"
|
# چکسام را روی سرور تأیید کن و فقط در صورتِ سالمبودن باینری را جابهجا کن.
|
||||||
ssh -i "$KEY" -o StrictHostKeyChecking=no "$HOST" '
|
# این از سناریوی «انتقالِ ناقص ⇒ باینریِ خراب ⇒ SEGV» جلوگیری میکند.
|
||||||
|
echo "==> verify checksum + swap in + restart (data & env untouched)"
|
||||||
|
ssh -i "$KEY" -o StrictHostKeyChecking=no "$HOST" "
|
||||||
set -e
|
set -e
|
||||||
|
REMOTE_SHA=\$(sha256sum ~/hakemsho/hakemsho.new | cut -d' ' -f1)
|
||||||
|
if [ \"\$REMOTE_SHA\" != \"$LOCAL_SHA\" ]; then
|
||||||
|
echo \"checksum mismatch (\$REMOTE_SHA != $LOCAL_SHA) — aborting, service untouched\"
|
||||||
|
rm -f ~/hakemsho/hakemsho.new
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
chmod +x ~/hakemsho/hakemsho.new
|
||||||
mv ~/hakemsho/hakemsho.new ~/hakemsho/hakemsho
|
mv ~/hakemsho/hakemsho.new ~/hakemsho/hakemsho
|
||||||
chmod +x ~/hakemsho/hakemsho
|
sudo systemctl reset-failed hakemsho || true
|
||||||
sudo systemctl restart hakemsho
|
sudo systemctl restart hakemsho
|
||||||
sleep 2
|
sleep 3
|
||||||
systemctl is-active hakemsho
|
systemctl is-active hakemsho
|
||||||
curl -s -m5 http://127.0.0.1:8080/health && echo
|
curl -s -m5 http://127.0.0.1:8080/health && echo
|
||||||
'
|
"
|
||||||
echo "==> done: https://hakem.approagency.ir/health"
|
echo "==> done: https://hakem.approagency.ir/health"
|
||||||
|
|||||||
@@ -60,21 +60,23 @@ type Profile struct {
|
|||||||
RankPoints int64 `json:"rank_points"`
|
RankPoints int64 `json:"rank_points"`
|
||||||
RankTier string `json:"rank_tier"` // bronze..king
|
RankTier string `json:"rank_tier"` // bronze..king
|
||||||
RankIndex int `json:"rank_index"` // ۰..۴
|
RankIndex int `json:"rank_index"` // ۰..۴
|
||||||
|
Avatar string `json:"avatar"` // seed آواتار (برای نمایش سرِ میز)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProfile وضعیت اقتصادی کاربر را میخواند.
|
// GetProfile وضعیت اقتصادی کاربر را میخواند.
|
||||||
func (s *Service) GetProfile(ctx context.Context, userID int64) (*Profile, error) {
|
func (s *Service) GetProfile(ctx context.Context, userID int64) (*Profile, error) {
|
||||||
var p Profile
|
var p Profile
|
||||||
var vipUntil sql.NullString
|
var vipUntil, avatar sql.NullString
|
||||||
err := s.db.QueryRowContext(ctx,
|
err := s.db.QueryRowContext(ctx,
|
||||||
`SELECT coins, tickets, xp, trophies, vip_until, selected_card, selected_carpet, rank_points FROM users WHERE id = ?`, userID).
|
`SELECT coins, tickets, xp, trophies, vip_until, selected_card, selected_carpet, rank_points, avatar FROM users WHERE id = ?`, userID).
|
||||||
Scan(&p.Coins, &p.Tickets, &p.XP, &p.Trophies, &vipUntil, &p.SelectedCard, &p.SelectedCarpet, &p.RankPoints)
|
Scan(&p.Coins, &p.Tickets, &p.XP, &p.Trophies, &vipUntil, &p.SelectedCard, &p.SelectedCarpet, &p.RankPoints, &avatar)
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
p.Avatar = avatar.String
|
||||||
p.Level, p.XPInto, p.XPNeed = LevelInfo(p.XP)
|
p.Level, p.XPInto, p.XPNeed = LevelInfo(p.XP)
|
||||||
p.RankTier, p.RankIndex = RankTier(p.RankPoints)
|
p.RankTier, p.RankIndex = RankTier(p.RankPoints)
|
||||||
if vipUntil.Valid {
|
if vipUntil.Valid {
|
||||||
|
|||||||
+5
-3
@@ -391,10 +391,12 @@ func (h *Hub) removeFromTable(t *pendingTable, c *Client) {
|
|||||||
func (h *Hub) broadcastLobby(t *pendingTable) {
|
func (h *Hub) broadcastLobby(t *pendingTable) {
|
||||||
players := make([]lobbyPlayer, len(t.clients))
|
players := make([]lobbyPlayer, len(t.clients))
|
||||||
for i, cl := range t.clients {
|
for i, cl := range t.clients {
|
||||||
|
_, _, avatar := h.settler.PlayerProfile(cl.UserID)
|
||||||
players[i] = lobbyPlayer{
|
players[i] = lobbyPlayer{
|
||||||
Name: cl.Name,
|
Name: cl.Name,
|
||||||
Host: cl.UserID == t.host,
|
Avatar: avatar,
|
||||||
Seat: t.seatOf(i),
|
Host: cl.UserID == t.host,
|
||||||
|
Seat: t.seatOf(i),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, cl := range t.clients {
|
for i, cl := range t.clients {
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ type chatMsg struct {
|
|||||||
|
|
||||||
// lobbyPlayer یک بازیکن در اتاق انتظارِ میز خصوصی.
|
// lobbyPlayer یک بازیکن در اتاق انتظارِ میز خصوصی.
|
||||||
type lobbyPlayer struct {
|
type lobbyPlayer struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Host bool `json:"host"`
|
Avatar string `json:"avatar"` // seed آواتارِ کاربر
|
||||||
Seat int `json:"seat"` // جایگاهِ مطلق (۰..۳)
|
Host bool `json:"host"`
|
||||||
|
Seat int `json:"seat"` // جایگاهِ مطلق (۰..۳)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tableLobbyMsg وضعیت اتاق انتظارِ میز خصوصی (دورهمی).
|
// tableLobbyMsg وضعیت اتاق انتظارِ میز خصوصی (دورهمی).
|
||||||
@@ -64,6 +65,7 @@ type PlayerInfo struct {
|
|||||||
Connected bool `json:"connected"`
|
Connected bool `json:"connected"`
|
||||||
Coins int64 `json:"coins"`
|
Coins int64 `json:"coins"`
|
||||||
RankTier string `json:"rank_tier"` // bronze..king (برای نشانِ رتبه)
|
RankTier string `json:"rank_tier"` // bronze..king (برای نشانِ رتبه)
|
||||||
|
Avatar string `json:"avatar"` // seed آواتارِ کاربر
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchedMsg به کلاینت پس از تشکیل میز.
|
// matchedMsg به کلاینت پس از تشکیل میز.
|
||||||
|
|||||||
+3
-2
@@ -39,6 +39,7 @@ type seatInfo struct {
|
|||||||
left bool // خروج دائمی داوطلبانه (در تسویه از بازگشت ورودی محروم)
|
left bool // خروج دائمی داوطلبانه (در تسویه از بازگشت ورودی محروم)
|
||||||
coins int64 // برای نمایش سرِ میز
|
coins int64 // برای نمایش سرِ میز
|
||||||
rankTier string // نشانِ رتبه برای نمایش سرِ میز
|
rankTier string // نشانِ رتبه برای نمایش سرِ میز
|
||||||
|
avatar string // seed آواتارِ انتخابیِ کاربر (برای نمایش سرِ میز)
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto مشخص میکند جایگاه باید خودکار بازی شود (بات یا قطعشده).
|
// auto مشخص میکند جایگاه باید خودکار بازی شود (بات یا قطعشده).
|
||||||
@@ -143,7 +144,7 @@ func (r *Room) start() {
|
|||||||
if s.isBot || s.userID == 0 {
|
if s.isBot || s.userID == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.coins, s.rankTier = r.settler.PlayerProfile(s.userID)
|
s.coins, s.rankTier, s.avatar = r.settler.PlayerProfile(s.userID)
|
||||||
}
|
}
|
||||||
for seat, s := range r.seats {
|
for seat, s := range r.seats {
|
||||||
if s.client != nil {
|
if s.client != nil {
|
||||||
@@ -567,7 +568,7 @@ func (r *Room) playersInfo() []PlayerInfo {
|
|||||||
out[i] = PlayerInfo{
|
out[i] = PlayerInfo{
|
||||||
Seat: i, Name: s.name, Bot: s.isBot,
|
Seat: i, Name: s.name, Bot: s.isBot,
|
||||||
Connected: s.isBot || s.connected,
|
Connected: s.isBot || s.connected,
|
||||||
Coins: s.coins, RankTier: s.rankTier,
|
Coins: s.coins, RankTier: s.rankTier, Avatar: s.avatar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ type Settler interface {
|
|||||||
RecordHand(userID int64, won, kot, asHakem bool) // پایان یک هَند
|
RecordHand(userID int64, won, kot, asHakem bool) // پایان یک هَند
|
||||||
RecordCut(userID int64) // بُرِش با حکم
|
RecordCut(userID int64) // بُرِش با حکم
|
||||||
RecordGameResult(userID int64, won bool) // پایان بازی (برد/باخت)
|
RecordGameResult(userID int64, won bool) // پایان بازی (برد/باخت)
|
||||||
// PlayerProfile سکه و نشانِ رتبهی بازیکن را برای نمایش سرِ میز برمیگرداند.
|
// PlayerProfile سکه، نشانِ رتبه و seedِ آواتارِ بازیکن را برای نمایش سرِ میز برمیگرداند.
|
||||||
PlayerProfile(userID int64) (coins int64, rankTier string)
|
PlayerProfile(userID int64) (coins int64, rankTier string, avatar string)
|
||||||
// ChargeTicket یک بلیت برای بُرِ مجدد در فازِ انتخابِ حکم مصرف میکند.
|
// ChargeTicket یک بلیت برای بُرِ مجدد در فازِ انتخابِ حکم مصرف میکند.
|
||||||
ChargeTicket(userID int64) error
|
ChargeTicket(userID int64) error
|
||||||
// ChargeCoins/AwardCoins برای شرطِ سکهایِ میزِ خصوصی (pot). Charge در صورتِ
|
// ChargeCoins/AwardCoins برای شرطِ سکهایِ میزِ خصوصی (pot). Charge در صورتِ
|
||||||
@@ -38,7 +38,7 @@ func (noopSettler) RecordGame(string, string, int, bool) {}
|
|||||||
func (noopSettler) RecordHand(int64, bool, bool, bool) {}
|
func (noopSettler) RecordHand(int64, bool, bool, bool) {}
|
||||||
func (noopSettler) RecordCut(int64) {}
|
func (noopSettler) RecordCut(int64) {}
|
||||||
func (noopSettler) RecordGameResult(int64, bool) {}
|
func (noopSettler) RecordGameResult(int64, bool) {}
|
||||||
func (noopSettler) PlayerProfile(int64) (int64, string) { return 0, "" }
|
func (noopSettler) PlayerProfile(int64) (int64, string, string) { return 0, "", "" }
|
||||||
func (noopSettler) ChargeTicket(int64) error { return nil }
|
func (noopSettler) ChargeTicket(int64) error { return nil }
|
||||||
func (noopSettler) ChargeCoins(int64, int64, string) error { return nil }
|
func (noopSettler) ChargeCoins(int64, int64, string) error { return nil }
|
||||||
func (noopSettler) AwardCoins(int64, int64, string) {}
|
func (noopSettler) AwardCoins(int64, int64, string) {}
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ func (s *recordingSettler) RecordGameResult(int64, bool) {
|
|||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *recordingSettler) PlayerProfile(int64) (int64, string) { return 0, "" }
|
func (s *recordingSettler) PlayerProfile(int64) (int64, string, string) { return 0, "", "" }
|
||||||
func (s *recordingSettler) ChargeTicket(int64) error { return nil }
|
func (s *recordingSettler) ChargeTicket(int64) error { return nil }
|
||||||
func (s *recordingSettler) ChargeCoins(int64, int64, string) error { return nil }
|
func (s *recordingSettler) ChargeCoins(int64, int64, string) error { return nil }
|
||||||
func (s *recordingSettler) AwardCoins(int64, int64, string) {}
|
func (s *recordingSettler) AwardCoins(int64, int64, string) {}
|
||||||
|
|||||||
Reference in New Issue
Block a user