215 lines
7.3 KiB
Markdown
215 lines
7.3 KiB
Markdown
# MWSE — Micro Web Socket Engine
|
||
|
||
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; 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.
|
||
|
||
## Durum (Go engine, v1.0.0)
|
||
|
||
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. Yük testi: 150 bağlantı, ~210 k msg/s relay, RSS ~43 MB.
|
||
|
||
| Ö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) | ✅ |
|
||
| Sanal IP / numara / kısa kod + alt ağ | ✅ |
|
||
| WebRTC kütüphanesi (perfect negotiation, çoklu track) | ✅ |
|
||
| Studio UI (Miller kolonlar) | ✅ |
|
||
| İkili çerçeveleme (binary framing) | ⏳ 2.5.0 |
|
||
| SRS entegrasyonu (binlerce izleyici) | ⏳ 2.0.0 |
|
||
|
||
## Kurulum ve çalıştırma
|
||
|
||
### Gereksinimler
|
||
|
||
- Go 1.22+
|
||
|
||
### Sunucuyu başlat
|
||
|
||
```bash
|
||
go mod tidy
|
||
go run .
|
||
# Varsayılan: 0.0.0.0:7707
|
||
```
|
||
|
||
### Ortam değişkenleri
|
||
|
||
| Değişken | Varsayılan | Açıklama |
|
||
|---|---|---|
|
||
| `MWSE_HOST` | `0.0.0.0` | Bind adresi |
|
||
| `MWSE_PORT` | `7707` | Dinleme portu |
|
||
| `MWSE_PUBLIC_DIR` | `./public` | Statik dosyalar (`/status.xml` vb.) |
|
||
| `MWSE_SDK_DIR` | `./sdk` | ES modül SDK (`/sdk/`) |
|
||
| `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ığı |
|
||
| `MWSE_SHUTDOWN_TIMEOUT` | `10s` | Graceful shutdown bekleme süresi |
|
||
| `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 saf vanilla ES modülü olarak `/sdk/` endpoint'inden sunulur. Bundler gerekmez;
|
||
native `import` ile çalışır.
|
||
|
||
```html
|
||
<script type="module">
|
||
import MWSE from 'http://localhost:7707/sdk/index.js';
|
||
|
||
const mwse = new MWSE(); // endpoint: otomatik aynı sunucudan
|
||
|
||
mwse.on('scope', async () => {
|
||
console.log('Bağlandı:', mwse.me.socketId);
|
||
const room = mwse.room({ name: 'genel', joinType: 'free', ifexistsJoin: true });
|
||
await room.createRoom();
|
||
room.on('message', (pack, peer) => console.log(peer.socketId, ':', pack));
|
||
room.send({ text: 'merhaba!' });
|
||
});
|
||
</script>
|
||
```
|
||
|
||
### WebRTC (P2P ses/video/dosya)
|
||
|
||
```js
|
||
import MWSE from '/sdk/index.js';
|
||
import { MediaSources } from '/sdk/webrtc/index.js';
|
||
|
||
const mwse = new MWSE();
|
||
|
||
mwse.me.on('accepted/pair', async peer => {
|
||
const polite = mwse.me.socketId < peer.socketId;
|
||
peer.rtc.connect({ polite });
|
||
|
||
// Kamera + mikrofon
|
||
const stream = await MediaSources.cameraAndMic();
|
||
peer.rtc.addStream('cam', stream);
|
||
|
||
// Gelen video/ses
|
||
peer.rtc.on('track', (track, streams) => {
|
||
const video = document.createElement('video');
|
||
video.srcObject = streams[0];
|
||
video.autoplay = true;
|
||
document.body.appendChild(video);
|
||
});
|
||
|
||
// Dosya gönderme
|
||
await peer.rtc.sendFile(file);
|
||
});
|
||
```
|
||
|
||
### Studio UI
|
||
|
||
```js
|
||
import MWSE from '/sdk/index.js';
|
||
import Studio from '/sdk/studio/index.js';
|
||
|
||
const mwse = new MWSE();
|
||
const studio = new Studio(mwse, '#app');
|
||
mwse.on('scope', () => studio.mount());
|
||
```
|
||
|
||
## Demo dosyaları
|
||
|
||
Sunucu çalışırken `http://localhost:7707/demos/` altında:
|
||
|
||
| Demo | Dosya | Açıklama |
|
||
|---|---|---|
|
||
| Chat | `chat.html` | ~20 satır JS ile odalı gerçek zamanlı sohbet |
|
||
| Sesli görüşme | `audio.html` | P2P WebRTC mikrofon (çift yönlü) |
|
||
| Video görüşme | `video.html` | P2P WebRTC kamera ızgara görünümü |
|
||
|
||
## API kontrolü (/api)
|
||
|
||
```bash
|
||
# API 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/<id>/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
|
||
|
||
```
|
||
Tarayıcı (WebSocket)
|
||
│
|
||
▼
|
||
ws.Hub — router + client registry
|
||
├─ services/yourid.go Bağlantı açılınca wsts/hello + id sinyalleri
|
||
├─ services/auth.go Pairing, 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 & pasif veri senkronizasyonu
|
||
├─ services/bridge.go 3. parti sunucu inbox
|
||
├─ services/ippressure.go Sanal IP / numara / kısa kod + alt ağ (/24)
|
||
└─ services/session.go Oturum bayrakları (readable/writable/pairinfo)
|
||
|
||
httpserver
|
||
├─ GET /sdk.js → /sdk/index.js (301 yönlendirme)
|
||
├─ GET /sdk/* ES modül SDK dosyaları
|
||
├─ GET /demos/* Demo HTML dosyaları
|
||
├─ GET|POST /api/* Kontrol düzlemi
|
||
└─ GET /* Statik public/ dosyaları
|
||
|
||
sdk/
|
||
├─ index.js MWSE ana sınıf (bağlantı + sinyal yönlendirme)
|
||
├─ webrtc/ WebRTC kütüphanesi
|
||
│ ├─ index.js RTCEngine (PeerConnection yönetimi, ICE restart)
|
||
│ ├─ PeerConnection.js RTCPeerConnection wrapper + full event izleme
|
||
│ ├─ Negotiator.js Perfect negotiation (RFC 8829)
|
||
│ ├─ StreamManager.js addStream/replaceTrack/setEncodings
|
||
│ ├─ DataChannel.js Birincil veri kanalı + oto-yeniden bağlanma
|
||
│ ├─ MediaSources.js getUserMedia/getDisplayMedia/AudioContext fabrikaları
|
||
│ ├─ FileSender.js Paralel DataChannel dosya transferi
|
||
│ └─ CanvasCompositor.js Çoklu video track birleştirme (grid/pip/focus)
|
||
└─ studio/
|
||
├─ index.js Studio UI giriş noktası
|
||
├─ ColumnView.js Miller kolon yöneticisi
|
||
├─ Column.js Tek kolon (başlık + arama + liste)
|
||
└─ style.css Koyu masaüstü teması
|
||
```
|
||
|
||
## Güvenlik
|
||
|
||
- İstemci mesajları **uygulama katmanında doğrulanmaz**. Hassas veriler için
|
||
imzalama/şifreleme ekleyin.
|
||
- 3. parti köprü (`BRIDGE_APPROVE_URL`) kullanılıyorsa bağlantı onayı uygulama
|
||
sunucusuna delege edilir (fail-closed).
|
||
- `.gitea-auth.json` dosyası commit'e asla girmez (`.gitignore`'da).
|
||
|
||
## Geliştirici dökümanı
|
||
|
||
Wiki: <https://git.saqut.com/saqut/MWSE/wiki>
|