Merge pull request 'feauture' (#3) from feauture into main
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m9s
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m9s
Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
6
auth.go
Normal file
6
auth.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type AuthMessage struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
InitData string `json:"initData"`
|
||||||
|
}
|
||||||
5
go.mod
5
go.mod
@@ -2,7 +2,4 @@ module server
|
|||||||
|
|
||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require github.com/gorilla/websocket v1.5.3
|
||||||
github.com/google/uuid v1.6.0
|
|
||||||
github.com/gorilla/websocket v1.5.3
|
|
||||||
)
|
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -1,4 +1,2 @@
|
|||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
|||||||
47
main.go
47
main.go
@@ -4,7 +4,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,22 +12,47 @@ var upgrader = websocket.Upgrader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ServeWS(room *Room, w http.ResponseWriter, r *http.Request) {
|
func ServeWS(room *Room, w http.ResponseWriter, r *http.Request) {
|
||||||
conn, _ := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
id := uuid.New().String()
|
return
|
||||||
player := &Player{
|
|
||||||
ID: id,
|
|
||||||
Conn: conn,
|
|
||||||
X: 180,
|
|
||||||
Y: 320,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
room.Players[id] = player
|
var auth AuthMessage
|
||||||
|
if err := conn.ReadJSON(&auth); err != nil || auth.Type != "auth" {
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, ok := VerifyTelegramInitData(auth.InitData, "7697757472:AAESD9HfkWwbIZe-HXR7IazUShr69hZTLmE")
|
||||||
|
if !ok {
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := data["user.id"]
|
||||||
|
username := data["user.username"]
|
||||||
|
|
||||||
|
if username == "" {
|
||||||
|
username = data["user.first_name"]
|
||||||
|
}
|
||||||
|
if username == "" {
|
||||||
|
username = "user_" + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
player := &Player{
|
||||||
|
ID: userID,
|
||||||
|
Username: username,
|
||||||
|
Conn: conn,
|
||||||
|
X: 180,
|
||||||
|
Y: 320,
|
||||||
|
}
|
||||||
|
|
||||||
|
room.Players[player.ID] = player
|
||||||
|
|
||||||
player.Conn.WriteJSON(map[string]any{
|
player.Conn.WriteJSON(map[string]any{
|
||||||
"type": "init",
|
"type": "init",
|
||||||
"payload": map[string]string{
|
"payload": map[string]string{
|
||||||
"id": id,
|
"id": player.ID,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -41,6 +65,7 @@ func readLoop(room *Room, player *Player) {
|
|||||||
err := player.Conn.ReadJSON(&msg)
|
err := player.Conn.ReadJSON(&msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
delete(room.Players, player.ID)
|
delete(room.Players, player.ID)
|
||||||
|
player.Conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
ID string
|
ID string
|
||||||
Conn *websocket.Conn
|
Username string
|
||||||
|
Conn *websocket.Conn
|
||||||
|
|
||||||
X, Y float64
|
X, Y float64
|
||||||
DX, DY float64
|
DX, DY float64
|
||||||
|
|||||||
24
room.go
24
room.go
@@ -1,12 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Room struct {
|
type Room struct {
|
||||||
Players map[string]*Player
|
Players map[string]*Player
|
||||||
Input chan InputMessage
|
Input chan InputMessage
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRoom() *Room {
|
func NewRoom() *Room {
|
||||||
@@ -17,36 +19,46 @@ func NewRoom() *Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Room) update() {
|
func (r *Room) update() {
|
||||||
|
// 1️⃣ обрабатываем input
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case input := <-r.Input:
|
case input := <-r.Input:
|
||||||
|
r.mu.Lock()
|
||||||
p := r.Players[input.PlayerID]
|
p := r.Players[input.PlayerID]
|
||||||
if p != nil {
|
if p != nil {
|
||||||
p.DX = input.DX
|
p.DX = input.DX
|
||||||
p.DY = input.DY
|
p.DY = input.DY
|
||||||
}
|
}
|
||||||
|
r.mu.Unlock()
|
||||||
default:
|
default:
|
||||||
goto DONE
|
goto DONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DONE:
|
DONE:
|
||||||
|
|
||||||
|
// 2️⃣ двигаем игроков
|
||||||
|
r.mu.Lock()
|
||||||
for _, p := range r.Players {
|
for _, p := range r.Players {
|
||||||
p.X += p.DX * 4
|
p.X += p.DX * 4
|
||||||
p.Y += p.DY * 4
|
p.Y += p.DY * 4
|
||||||
}
|
}
|
||||||
|
r.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Room) broadcast() {
|
func (r *Room) broadcast() {
|
||||||
state := map[string]map[string]float64{}
|
r.mu.Lock()
|
||||||
|
|
||||||
|
state := make(map[string]map[string]any, len(r.Players))
|
||||||
for id, p := range r.Players {
|
for id, p := range r.Players {
|
||||||
state[id] = map[string]float64{
|
state[id] = map[string]any{
|
||||||
"x": p.X,
|
"x": p.X,
|
||||||
"y": p.Y,
|
"y": p.Y,
|
||||||
|
"name": p.Username,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.mu.Unlock()
|
||||||
|
|
||||||
msg := StateMessage{
|
msg := StateMessage{
|
||||||
Type: "state",
|
Type: "state",
|
||||||
Payload: map[string]any{
|
Payload: map[string]any{
|
||||||
@@ -54,13 +66,15 @@ func (r *Room) broadcast() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// отправляем БЕЗ mutex — важно
|
||||||
for _, p := range r.Players {
|
for _, p := range r.Players {
|
||||||
p.Conn.WriteJSON(msg)
|
_ = p.Conn.WriteJSON(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Room) Run() {
|
func (r *Room) Run() {
|
||||||
ticker := time.NewTicker(time.Second / 30)
|
ticker := time.NewTicker(time.Second / 30)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
r.update()
|
r.update()
|
||||||
|
|||||||
41
telegram.go
Normal file
41
telegram.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VerifyTelegramInitData(initData, botToken string) (map[string]string, bool) {
|
||||||
|
values, _ := url.ParseQuery(initData)
|
||||||
|
|
||||||
|
hash := values.Get("hash")
|
||||||
|
values.Del("hash")
|
||||||
|
|
||||||
|
var data []string
|
||||||
|
for k, v := range values {
|
||||||
|
data = append(data, k+"="+v[0])
|
||||||
|
}
|
||||||
|
sort.Strings(data)
|
||||||
|
|
||||||
|
checkString := strings.Join(data, "\n")
|
||||||
|
|
||||||
|
secret := sha256.Sum256([]byte(botToken))
|
||||||
|
h := hmac.New(sha256.New, secret[:])
|
||||||
|
h.Write([]byte(checkString))
|
||||||
|
|
||||||
|
expected := hex.EncodeToString(h.Sum(nil))
|
||||||
|
|
||||||
|
return valuesToMap(values), expected == hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func valuesToMap(v url.Values) map[string]string {
|
||||||
|
m := make(map[string]string)
|
||||||
|
for k, val := range v {
|
||||||
|
m[k] = val[0]
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user