diff --git a/README.md b/README.md
index e32881f..2eb9df0 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,161 @@
-# MWSE Nedir?
+# MWSE — Micro Web Socket Engine
-MWSE yani Micro Web Socket Engine, kendisine bağlanan eşleri birbirleriyle ile eşleştirerek, eşler arası veri tünelleri oluşturan geniş ölçekli bir mikroservistir.
+MWSE, kendisine bağlanan eşleri birbirleriyle eşleştirerek eşler arası veri
+tünelleri oluşturan geniş ölçekli bir WebSocket mikroservis altyapısıdır.
-Servis, bağlantı sağlayan cihazların verilerini kendi aralarında senkron etmek için kullanılabilir, cihazları gruplayabilir, odalar oluşturabilir, sohbet ve görüntülü görüşme yazılımları için alt yapı olarak kullanılabilir
+Servis; cihazları senkronize etmek, odalar oluşturmak, sohbet ve görüntülü
+görüşme yazılımları için gerçek zamanlı altyapı sağlamak amacıyla kullanılır.
+Sunucu cihazları sanallaştırdığı için eşler birbirlerinin gerçek IP adresini veya
+cihaz bilgisini bilmeden düşük gecikmeli, çift yönlü iletişim kurabilir.
-Bağlantı TCP tabanlı yüksek hızlı WebSocket protokolüne dayanır ve sunucunun cihazları sanallaştırması sayesinde diğer kişilerin IP adreslerini veya cihaz türü gibi bilgilere ihtiyaç duymadan düşük gecikmeli çift taraflı serbest iletişim kurmalarını sağlar.
+## Durum (Go engine, v0.1.0 paritesi ✅)
-[Geliştirici Dökümanı](https://git.saqut.com/saqut/MWSE/wiki/Entegrasyon)
+Motor Node.js'ten **Go** ile yeniden yazıldı. Concurrency modeli goroutine +
+`sync.RWMutex` + bağlantı başına tek-yazıcı (actor) deseni üzerine kuruludur;
+Node.js'teki "leave-while-send" race condition ve EventPool promise takılması
+(#33) giderildi.
-# Güvenlik !
+| Özellik | Durum |
+|---|---|
+| WebSocket bağlantı yaşam döngüsü | ✅ |
+| Oda oluşturma / katılma / çıkma | ✅ |
+| Eşleme (pair) sistemi | ✅ |
+| Paket tünelleme (pack/to, pack/room) | ✅ |
+| Veri senkronizasyonu (data/sync, sync/pool) | ✅ |
+| Bildirim + suit yanıtı (notify/send, notify/reply) | ✅ |
+| 3. parti sunucu köprüsü (bridge) | ✅ |
+| İkili çerçeveleme (binary framing) | ⏳ 2.5.0 |
+| Studio (akış/WebRTC sunucusu) | ⏳ 2.0.0 |
-Framework, bağlı tüm cihazlar arasında mesajları doğru hedefe, verinin bozulmadığını garanti ederek iletmekden sorumludur.
+## Kurulum ve çalıştırma
-Bunların dışında hassas verilerin soket üzerinden iletilmesi şimdilik önerilmez, clientlerin ileteceği mesajlar **SOKETE İLETİLMEDEN ÖNCE** kullanıcılar tarafından manipüle edilebilir veya taklit edilebilir ve MWSE bunun doğrulamasını **YAPMAZ**
+### Gereksinimler
-## WebSocket topolojisi
+- Go 1.22+
+- (Opsiyonel) TypeScript — SDK derlemek için `npm run build`
-
+### Sunucuyu başlat
-## Proje tarafından uygulanan load balance teknolojisi
+```bash
+# Bağımlılıklar
+go mod tidy
-
\ No newline at end of file
+# Çalıştır (varsayılan: 0.0.0.0:7707)
+go run .
+
+# Yapılandırma env değişkenleriyle:
+MWSE_ADDR=:8080 \
+MWSE_OUTBOUND_BUFFER=2048 \
+MWSE_MAX_MESSAGE_SIZE=33554432 \
+go run .
+```
+
+### Ortam değişkenleri
+
+| Değişken | Varsayılan | Açıklama |
+|---|---|---|
+| `MWSE_ADDR` | `:7707` | Dinleme adresi |
+| `MWSE_OUTBOUND_BUFFER` | `1024` | Bağlantı başına gönderim kuyruğu |
+| `MWSE_MAX_MESSAGE_SIZE` | `16777216` | Maksimum gelen frame boyutu (bayt) |
+| `MWSE_PING_INTERVAL` | `10s` | Heartbeat ping aralığı |
+| `BRIDGE_APPROVE_URL` | — | Bağlantı onay URL'i (3. parti köprü) |
+| `BRIDGE_TRIGGER_URL` | — | Suit yanıtı push URL'i |
+| `BRIDGE_INBOX` | — | `1` ile inbox'ı etkinleştir |
+
+### Testler
+
+```bash
+go test -race ./...
+```
+
+## Frontend SDK entegrasyonu
+
+SDK, TypeScript ile yazılmış ve derlenmiş JavaScript olarak `/script`
+endpoint'inden sunulur. Herhangi bir bundler gerekmez.
+
+```html
+
+
+
+
+```
+
+## Demo dosyaları
+
+| Demo | Yol | Açıklama |
+|---|---|---|
+| Chat | `/demos/chat.html` | ~20 satır JS ile odalı sohbet |
+| Sesli görüşme | `/demos/audio.html` | P2P WebRTC ses (eşler arası) |
+| Video görüşme | `/demos/video.html` | P2P WebRTC video (kamera ızgara görünümü) |
+
+## API kontrolü (/api)
+
+API anahtarı al, sonra kullan:
+
+```bash
+# Anahtar al
+KEY=$(curl -s -X POST localhost:7707/api/auth/key \
+ -H 'Content-Type: application/json' \
+ -d '{"domain":"myapp"}' | jq -r .key)
+
+# Tüm odaları listele
+curl -s localhost:7707/api/rooms | jq .
+
+# Belirli bir istemciye mesaj gönder
+curl -s -X POST localhost:7707/api/client//send \
+ -H "x-api-key: $KEY" \
+ -H 'Content-Type: application/json' \
+ -d '{"pack": {"hello": "world"}}'
+
+# 3. parti köprü — inbox boşalt
+curl -s -X POST localhost:7707/api/bridge/inbox \
+ -H "x-api-key: $KEY"
+```
+
+## Mimari
+
+```
+Client (WebSocket)
+ │
+ ▼
+ws.Hub (router + registry)
+ ├─ services/auth.go Pairing, IP adresi, erişilebilirlik
+ ├─ services/room.go Oda oluşturma / yönetimi
+ ├─ services/datatransfer.go pack/to, request/to, response/to tünelleri
+ ├─ services/notify.go Store-and-forward bildirim + suit yanıtı
+ ├─ services/datastore.go Aktif senkronizasyon (CRUD broadcast)
+ │ Pasif senkronizasyon (hash-dedup merge pool)
+ ├─ services/bridge.go 3. parti sunucu inbox (bridge/send)
+ └─ services/ippressure.go Sanal IP basıncı
+
+httpserver
+ ├─ GET/POST /api/* Kontrol düzlemi (API anahtarı, oda/istemci yönetimi)
+ ├─ POST /api/bridge/inbox 3. parti sunucu inbox boşaltma
+ └─ /* (WebSocket değilse) SDK (script/index.js) + statik dosyalar
+```
+
+## Güvenlik
+
+- Bağlı cihazların mesajları **sokete iletilmeden önce** kullanıcılar tarafından
+ manipüle edilebilir; MWSE bu doğrulamayı yapmaz. Hassas veriler için
+ uygulama katmanında imzalama/şifreleme ekleyin.
+- 3. parti köprü (`BRIDGE_APPROVE_URL`) kullanılıyorsa bağlantı onayı uygulama
+ sunucusuna delege edilir (fail-closed: onay gelmezse bağlantı reddedilir).
+
+## Geliştirici dökümanı
+
+Tüm wiki sayfaları:
diff --git a/internal/config/config.go b/internal/config/config.go
index 8d2caf8..eba4316 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -15,7 +15,8 @@ type Config struct {
Port int // listen port, default 7707
PublicDir string // static assets directory (default "./public")
- ScriptDir string // built SDK directory (default "./script")
+ ScriptDir string // legacy compiled SDK bundle directory (default "./script")
+ SDKDir string // ES-module SDK directory (default "./sdk")
ReadHeaderTimeout time.Duration // HTTP read-header timeout
ShutdownTimeout time.Duration // grace period for in-flight work on shutdown
@@ -65,6 +66,7 @@ func Load() Config {
Port: envInt("MWSE_PORT", 7707),
PublicDir: env("MWSE_PUBLIC_DIR", "./public"),
ScriptDir: env("MWSE_SCRIPT_DIR", "./script"),
+ SDKDir: env("MWSE_SDK_DIR", "./sdk"),
ReadHeaderTimeout: 10 * time.Second,
ShutdownTimeout: time.Duration(envInt("MWSE_SHUTDOWN_TIMEOUT", 10)) * time.Second,
TermOutput: envBool("MWSE_TERM_OUTPUT", false),
diff --git a/internal/httpserver/httpserver.go b/internal/httpserver/httpserver.go
index 86b981d..c5c3a67 100644
--- a/internal/httpserver/httpserver.go
+++ b/internal/httpserver/httpserver.go
@@ -68,7 +68,9 @@ func New(hub *ws.Hub, cfg config.Config, srvOpts ...ServerOptions) *http.Server
// registerStatic wires the asset routes:
//
-// - /script -> the built SDK entry (script/index.js)
+// - /sdk.js -> redirect to /sdk/index.js (so import.meta.url resolves correctly)
+// - /sdk/ -> ES-module SDK files (sdk/EventTarget.js, etc.)
+// - /script -> legacy compiled SDK entry (script/index.js)
// - /script/ -> files under the script directory
// - / -> the SDK entry (so a bare visit returns the script)
// - / -> a matching file under the public directory
@@ -77,6 +79,13 @@ func registerStatic(mux *http.ServeMux, cfg config.Config) {
scriptIndex := filepath.Join(cfg.ScriptDir, "index.js")
statusDoc := filepath.Join(cfg.ScriptDir, "status.xml")
+ // ES-module SDK: redirect /sdk.js → /sdk/index.js so that import.meta.url
+ // resolves to /sdk/index.js and all relative imports go to /sdk/*.
+ mux.HandleFunc("/sdk.js", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/sdk/index.js", http.StatusMovedPermanently)
+ })
+ mux.Handle("/sdk/", http.StripPrefix("/sdk/", http.FileServer(http.Dir(cfg.SDKDir))))
+
mux.HandleFunc("/script", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, scriptIndex)
})
diff --git a/internal/protocol/version.go b/internal/protocol/version.go
new file mode 100644
index 0000000..8909606
--- /dev/null
+++ b/internal/protocol/version.go
@@ -0,0 +1,15 @@
+package protocol
+
+// WSTSVersion is the wire protocol version. The SDK checks this against its own
+// version constant (sdk/version.js) on every connection: if they differ the SDK
+// refuses to proceed. Bump both together when making a breaking wire change.
+//
+// Current versioning scheme:
+// "1.x.x" JSON text frames (codec id 0) — v0.1.0 → current
+// "2.x.x" Binary frames (codec id 1) — planned, issue #42
+const WSTSVersion = "1.0.0"
+
+// WSTSCodecJSON is the codec identifier for the current JSON text framing.
+// The server lists supported codecs in the wsts/hello signal so the client can
+// negotiate the best mode it understands.
+const WSTSCodecJSON = 0
diff --git a/internal/services/yourid.go b/internal/services/yourid.go
index cc1252f..846aaa1 100644
--- a/internal/services/yourid.go
+++ b/internal/services/yourid.go
@@ -1,11 +1,25 @@
package services
-import "git.saqut.com/saqut/mwse/internal/ws"
+import (
+ "git.saqut.com/saqut/mwse/internal/protocol"
+ "git.saqut.com/saqut/mwse/internal/ws"
+)
-// registerYourID tells a freshly connected client its own socket id, exactly as
-// the Node YourID service did: client.send([{type:'id', value: id}, 'id']).
+// registerYourID sends two signals on every new connection:
+//
+// 1. wsts/hello — version handshake. The SDK checks this version against its own
+// constant (sdk/version.js) and refuses to proceed if they differ. The codecs
+// list advertises which frame encodings the server supports (0 = JSON, 1 =
+// binary once #42 is ready). This signal is sent first so the SDK can gate
+// all subsequent processing on a successful version check.
+//
+// 2. id — the client's own socket id, exactly as the original Node YourID did.
func registerYourID(hub *ws.Hub) {
hub.OnConnect(func(c *ws.Client) {
+ c.Signal("wsts/hello", map[string]any{
+ "v": protocol.WSTSVersion,
+ "codecs": []int{protocol.WSTSCodecJSON},
+ })
c.Signal("id", map[string]any{"type": "id", "value": c.ID})
})
}
diff --git a/public/demos/audio.html b/public/demos/audio.html
new file mode 100644
index 0000000..ea3a4fb
--- /dev/null
+++ b/public/demos/audio.html
@@ -0,0 +1,127 @@
+
+
+
+
+ MWSE — Sesli Görüşme Demo
+
+
+
+
+
MWSE Sesli Görüşme Demo
+
+ Aynı anda birden fazla sekme ya da kullanıcı açın. Odaya katılan herkese
+ otomatik çift yönlü ses bağlantısı kurulur (P2P WebRTC, max ~10–15 kişi için
+ mesh topolojisi; daha fazlası için SRS entegrasyonu gerekir).
+