Studio: UUID yerine sanal IP gösterimi

Akış:
  - scope sonrası allocAPIPAddress() → 10.x.x.x al
  - PeerInfo.set('ip', ip) → auth/info → tüm mevcut pairlere yayımlar
  - accepted/pair sonrası tekrar set() → yeni paire de ulaşır
  - pair/info sinyali → peer.info.info.ip güncellenir (SDK zaten yapıyor)

Araç çubuğu ID kartı:
  - Sanal IP: büyük, mavi (10.x.x.x) — IP alındıkça güncellenir
  - Kısa UUID: küçük, soluk (son 8 karakter) — scope'ta dolar
  - Tıkla → tam UUID kopyalanır (paylaşmak için hâlâ gerekli)

Eşler kolonunda:
  - Etiket: peer.info.info.ip (varsa) yoksa kısa UUID
  - Meta: kısa UUID · bağlantı türü · akış sayısı

Eş eylem kolonu başlığı: IP veya kısa UUID
Oda üyeleri: kendi kaydı için sanal IP gösterilir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
abdussamedulutas 2026-06-17 13:46:27 +03:00
parent d9598ba15f
commit 0c654ae4c8
2 changed files with 58 additions and 18 deletions

View File

@ -26,6 +26,16 @@ export default class Studio {
await this._loadDevices(); await this._loadDevices();
this._pushRootColumn(); this._pushRootColumn();
// Scope sonrası sanal IP al ve kendime ata.
this.mwse.scope(async () => {
try {
const ip = await this.mwse.virtualPressure.allocAPIPAddress();
// PeerInfo.set → auth/info → mevcut tüm pairlere yayımlar.
this.mwse.me.info.set('ip', ip);
this._updateMyIP(ip);
} catch (_) {}
});
// ── Gelen eşleme isteği → bildirim banner'ı ────────────────────── // ── Gelen eşleme isteği → bildirim banner'ı ──────────────────────
this.mwse.me.on('request/pair', peer => { this.mwse.me.on('request/pair', peer => {
this._showPairRequest(peer); this._showPairRequest(peer);
@ -34,19 +44,32 @@ export default class Studio {
// Eşleşme onaylandı (istek gönderen taraf) // Eşleşme onaylandı (istek gönderen taraf)
this.mwse.me.on('accepted/pair', peer => { this.mwse.me.on('accepted/pair', peer => {
this._watchIncoming(peer); this._watchIncoming(peer);
// Yeni paire kendi IP'mizi paylaş.
if (this.mwse.virtualPressure.APIPAddress) {
this.mwse.me.info.set('ip', this.mwse.virtualPressure.APIPAddress);
}
this._view.refresh(); this._view.refresh();
this._setStatus('online', `${peer.socketId.slice(-8)} eşleşmesi kuruldu`); this._setStatus('online', `${this._peerLabel(peer)} eşleşmesi kuruldu`);
}); });
// Eşleşme bitti // Pair info değişince (karşı tarafın IP'si gelince) kolonları yenile.
this.mwse.me.on('accepted/pair', () => this._view.refresh());
this.mwse.on('room', () => this._view.refresh());
this.mwse.me.on('end/pair', () => this._view.refresh()); this.mwse.me.on('end/pair', () => this._view.refresh());
// Oda değişimi
this.mwse.on('room', () => this._view.refresh());
return this; return this;
} }
// Toolbar'daki IP/ID kartını güncelle.
_updateMyIP(ip) {
if (this._myIPEl) this._myIPEl.textContent = ip;
}
// Bir peer için görünen ad: sanal IP varsa onu, yoksa kısa UUID.
_peerLabel(peer) {
return peer.info?.info?.ip || peer.socketId.slice(-8);
}
// ── Araç çubuğu ────────────────────────────────────────────────────────── // ── Araç çubuğu ──────────────────────────────────────────────────────────
_buildToolbar() { _buildToolbar() {
@ -59,15 +82,21 @@ export default class Studio {
logo.innerHTML = 'MWSE <span style="color:#0078d4">Studio</span>'; logo.innerHTML = 'MWSE <span style="color:#0078d4">Studio</span>';
bar.appendChild(logo); bar.appendChild(logo);
// Benim ID kartı // Benim IP + ID kartı (tıkla → UUID kopyalanır)
const idCard = document.createElement('div'); const idCard = document.createElement('div');
idCard.className = 'mwse-id-card'; idCard.className = 'mwse-id-card';
idCard.title = 'Tıkla → Kopyala'; idCard.title = 'Socket ID\'yi kopyala (paylaşmak için)';
const idLabel = document.createElement('span'); const idLabel = document.createElement('span');
idLabel.className = 'mwse-id-card__label'; idLabel.className = 'mwse-id-card__label';
idLabel.textContent = 'Kimliğim'; idLabel.textContent = 'Kimliğim';
// Sanal IP (önce boş, allocAPIPAddress sonrası dolar)
this._myIPEl = document.createElement('span');
this._myIPEl.className = 'mwse-id-card__ip';
this._myIPEl.textContent = '';
// Kısa UUID (ID paylaşımı için)
const idValue = document.createElement('span'); const idValue = document.createElement('span');
idValue.className = 'mwse-id-card__value'; idValue.className = 'mwse-id-card__value';
idValue.textContent = '…'; idValue.textContent = '…';
@ -76,7 +105,7 @@ export default class Studio {
idCopy.className = 'mwse-id-card__copy'; idCopy.className = 'mwse-id-card__copy';
idCopy.textContent = '⎘'; idCopy.textContent = '⎘';
idCard.append(idLabel, idValue, idCopy); idCard.append(idLabel, this._myIPEl, idValue, idCopy);
idCard.addEventListener('click', () => { idCard.addEventListener('click', () => {
const id = this.mwse.me.socketId; const id = this.mwse.me.socketId;
if (!id || id === '…') return; if (!id || id === '…') return;
@ -90,7 +119,7 @@ export default class Studio {
}); });
}); });
this.mwse.me.on('scope', () => { idValue.textContent = this.mwse.me.socketId; }); this.mwse.me.on('scope', () => { idValue.textContent = this.mwse.me.socketId.slice(-8); });
bar.appendChild(idCard); bar.appendChild(idCard);
// Durum // Durum
@ -201,7 +230,7 @@ export default class Studio {
const pairs = [...this.mwse.pairs.values()]; const pairs = [...this.mwse.pairs.values()];
const items = pairs.map(peer => ({ const items = pairs.map(peer => ({
icon: peer.rtc?.active ? '◉' : '●', icon: peer.rtc?.active ? '◉' : '●',
label: peer.socketId, label: this._peerLabel(peer),
meta: () => this._peerMeta(peer), meta: () => this._peerMeta(peer),
onSelect: () => { this._view.popTo(2); this._pushPeerColumn(peer); } onSelect: () => { this._view.popTo(2); this._pushPeerColumn(peer); }
})); }));
@ -236,9 +265,10 @@ export default class Studio {
_peerMeta(peer) { _peerMeta(peer) {
const streams = peer.rtc?._streams?.list() ?? []; const streams = peer.rtc?._streams?.list() ?? [];
if (streams.length) return `p2p · ${streams.length} akış`; const id = peer.socketId.slice(-8);
if (peer.rtc?.active) return `p2p · ${peer.rtc.connectionStatus}`; if (streams.length) return `${id} · p2p · ${streams.length} akış`;
return 'websocket'; if (peer.rtc?.active) return `${id} · p2p`;
return `${id} · websocket`;
} }
// ── Eş eylem kolonu ─────────────────────────────────────────────────────── // ── Eş eylem kolonu ───────────────────────────────────────────────────────
@ -294,7 +324,7 @@ export default class Studio {
} }
}); });
this._view.pushColumn(peer.socketId.slice(-12), items, { searchable: false }); this._view.pushColumn(this._peerLabel(peer), items, { searchable: false });
} }
// ── Odalar kolonu ───────────────────────────────────────────────────────── // ── Odalar kolonu ─────────────────────────────────────────────────────────
@ -348,7 +378,7 @@ export default class Studio {
_pushRoomMembersColumn(room) { _pushRoomMembersColumn(room) {
const items = [...room.peers.values()].map(peer => ({ const items = [...room.peers.values()].map(peer => ({
icon: peer.selfSocket ? '★' : '●', icon: peer.selfSocket ? '★' : '●',
label: peer.socketId, label: peer.selfSocket ? (this.mwse.virtualPressure.APIPAddress || 'Ben') : this._peerLabel(peer),
meta: () => this._peerMeta(peer), meta: () => this._peerMeta(peer),
onSelect: () => { this._view.popTo(3); this._pushPeerColumn(peer); } onSelect: () => { this._view.popTo(3); this._pushPeerColumn(peer); }
})); }));

View File

@ -316,14 +316,24 @@
flex-shrink: 0; flex-shrink: 0;
} }
/* Sanal IP (büyük, belirgin) */
.mwse-id-card__ip {
font-family: 'Consolas', 'Menlo', monospace;
font-size: 13px;
font-weight: 600;
color: #60cdff;
white-space: nowrap;
}
.mwse-id-card__ip:empty { display: none; }
/* UUID (küçük, soluk) */
.mwse-id-card__value { .mwse-id-card__value {
font-family: 'Consolas', 'Menlo', monospace; font-family: 'Consolas', 'Menlo', monospace;
font-size: 11px; font-size: 10px;
color: #b0b0b0; color: #666;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
flex: 1;
} }
.mwse-id-card__copy { .mwse-id-card__copy {