74 lines
5.1 KiB
Markdown
74 lines
5.1 KiB
Markdown
# PORT-PROGRESS — MWSE Node.js → Go Çekirdek Portu
|
||
|
||
> Bu oturumun çıktısı. Branch: `go-rewrite`. `stable`'a dokunulmadı, deploy yapılmadı, hiçbir issue kapatılmadı. Yarın insan incelemesi için yazıldı.
|
||
|
||
## TL;DR
|
||
|
||
MWSE engine (Node.js `Source/`) **performans odaklı, race-free bir Go projesine** taşındı. SDK ile konuşulan **WSTS tel formatı (giriş/çıkış sözleşmesi) korundu**. Frontend (`frontend/`) hiç dokunulmadan yerinde duruyor. İkinci bir Go projesi (`loadtest/`) yük testi + benchmark için yazıldı.
|
||
|
||
- `go build ./...` ✅ · `go vet ./...` ✅ · `go test -race ./...` ✅
|
||
- Uçtan uca doğrulandı: engine + loadtest birlikte çalıştırıldı.
|
||
- **ping** modu: ~140k istek/sn, p50 ~200µs, 0 hata.
|
||
- **relay** modu: ~190k mesaj/sn, %98.5 teslim, bağlantı çökmesi yok.
|
||
|
||
## Klasör yapısı (karar: Go repo kökünde)
|
||
|
||
```
|
||
go.mod # modül: git.saqut.com/saqut/mwse
|
||
main.go # giriş noktası, graceful shutdown, sinyal yönetimi
|
||
internal/
|
||
protocol/ # WSTS tel formatı (encode/decode) — DONMUŞ sözleşme
|
||
ws/ # çekirdek: Client, Room, Hub, Server (concurrency burada)
|
||
services/ # handler portu: YourID, Session, Auth, Room, IPPressure, DataTransfer
|
||
config/ # env tabanlı yapılandırma
|
||
httpserver/ # HTTP yüzeyi: WS upgrade + statik + /api + graceful shutdown
|
||
testutil/ # testler için in-memory sahte bağlantı (FakeConn)
|
||
loadtest/ # AYRI Go modülü: yük/benchmark istemcisi (ping + relay)
|
||
frontend/ # DOKUNULMADI (TS SDK, parcel ile derleniyor)
|
||
Source/ # eski Node.js engine — referans olarak bırakıldı
|
||
```
|
||
|
||
## Concurrency modeli (#22 — ASIL SEBEP)
|
||
|
||
Node'daki "biri odadan ayrılırken başka thread o peer'e yazınca race" sorunu, Go'da **iki katmanlı bir garantiyle** kökten çözüldü:
|
||
|
||
1. **Bağlantı başına TEK yazıcı goroutine.** Sokete yazan tek şey `writePump`'tır. Üreticiler sokete asla dokunmaz; mesajı `outbound` kanalına koyar. Böylece gorilla'nın "aynı anda tek yazıcı" kuralı yapısal olarak garanti edilir, eşzamanlı yazma imkânsızdır.
|
||
2. **`Send` her zaman `done` kanalını da seçer.** Bir gönderim, kapanmakta olan bir peer ile yarışırsa panik/race yerine **sessizce düşürülür**. Bu, "ayrılırken-yazma" senaryosunu güvenli kılan tam noktadır.
|
||
3. **Paylaşılan durum kilitli.** `Hub` (client/room kayıtları), `Room` (üyelik) ve `Client` (info/store/pairs/rooms) her biri kendi `sync.RWMutex`'i ile korunur. `Room.Broadcast` üyeleri kilit altında **snapshot**'lar, sonra kilit olmadan gönderir → ne deadlock ne race.
|
||
|
||
Neden actor değil de RWMutex + tek-yazıcı? → `decisions.md`. Özet: gerçek race zaten (1)+(2) ile çözülüyor; RWMutex versiyonu yeni başlayan bir Go geliştiricisi için çok daha okunaklı. Bu seçim `REVIEW.md`'de insan onayına bırakıldı.
|
||
|
||
**Regresyon testi:** `internal/ws/ws_test.go → TestLeaveWhileSendRace` — bir odaya 4 goroutine broadcast ederken 30 üye eşzamanlı `Eject`/`Join` yapar; `-race` ile temiz geçer. Node'da çöken senaryonun bire bir karşılığı.
|
||
|
||
## Ne yapıldı (issue eşlemesi — SADECE spec olarak okundu, KAPATILMADI)
|
||
|
||
- **#21** WS sunucu iskeleti + yaşam döngüsü → `internal/ws/server.go` (upgrade, read loop, heartbeat `saQut` ping/pong, tek-yazıcı writePump).
|
||
- **#22** Concurrency modeli → yukarıdaki tasarım + regresyon testi.
|
||
- **#23** WSTS protokolü → `internal/protocol/` (request/response/stream/signal, numeric id round-trip dahil). Frontend ile bire bir uyumlu.
|
||
- **#24** MessageRouter + Services → `internal/ws/hub.go` (router + event bus) + `internal/services/*`.
|
||
- **#25** Config + HTTP + graceful shutdown → `internal/config`, `internal/httpserver`, `main.go`.
|
||
- **#26** `go test -race` süreç/yarış testleri → `internal/ws/ws_test.go`, `internal/services/services_test.go`, `internal/protocol/protocol_test.go`.
|
||
|
||
## Ne kaldı / sonraki adımlar
|
||
|
||
- `/api` kontrol düzleminde **server'ın odaya katılması (join/leave)** ve **webhook** uçları ertelendi (Node'daki sahte-client deseni Go'da farklı tasarlanmalı). Detay → `REVIEW.md`.
|
||
- P2P `request/to` + `response/to` zincirinde Node'dan gelen **bir tasarım uyumsuzluğu** var (request, action 'R' ile gönderildiği için sunucu hemen 'E' ile yanıtlıyor; eş yanıtı sonra geliyor). Sadık port yapıldı, sözleşme değiştirilmedi → `REVIEW.md`.
|
||
- Binary protokol (2.5.0), WebRTC signaling (1.0.0+), studio (2.0.0) kapsam dışı.
|
||
- IPPressure'ın çok-süreçli "canlı panel" IPC'si (`process.send`) tek-node çekirdek için `Announcer` arayüzünün arkasına soyutlandı (varsayılan no-op). Cluster entegrasyonu sonra.
|
||
|
||
## Çalıştırma
|
||
|
||
```bash
|
||
# Engine
|
||
go run . # 0.0.0.0:7707
|
||
MWSE_PORT=8080 go run . # env ile yapılandırma
|
||
|
||
# Yük testi / benchmark (engine ayaktayken, ayrı modül)
|
||
cd loadtest
|
||
go run . -mode ping -clients 100 -dur 10s
|
||
go run . -mode relay -clients 100 -dur 10s
|
||
|
||
# Testler
|
||
go test -race ./...
|
||
```
|