# 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 ./... ```