Merge pull request 'perfectnogation' (#20) from perfectnogation into stable

Reviewed-on: #20
This commit is contained in:
saqut 2025-07-14 23:25:51 +03:00
commit 41b7a052ab
11 changed files with 1521 additions and 56 deletions

View File

@ -7,7 +7,7 @@ addListener('disconnect',(global, xclient)=>{
{ {
client?.send([ client?.send([
{ {
id: clientid id: xclient.id
}, },
"peer/disconnect" "peer/disconnect"
]) ])

View File

@ -1,11 +1,11 @@
import MWSE from "frontend";
export interface IConnection{ export interface IConnection{
endpoint: string; endpoint: string;
autoReconnect?: boolean | { autoReconnect?: boolean | {
timeout: number; timeout: number;
} }
} }
const RootURL : string = ( <HTMLScriptElement> document.currentScript).src
export class Connection export class Connection
{ {
public ws! : WebSocket; public ws! : WebSocket;
@ -16,10 +16,11 @@ export class Connection
public autoReconnect : boolean = true; public autoReconnect : boolean = true;
public autoReconnectTimeout : number = 3000; public autoReconnectTimeout : number = 3000;
public autoReconnectTimer? : number; public autoReconnectTimer? : number;
constructor(options: IConnection){ constructor(mwse:MWSE, options: IConnection){
if(options.endpoint == "auto") if(options.endpoint == "auto")
{ {
const RootURL : string = ( <HTMLScriptElement> document.currentScript).src
let scriptPath = new URL(RootURL); let scriptPath = new URL(RootURL);
let isSecurity = scriptPath.protocol == "https:"; let isSecurity = scriptPath.protocol == "https:";
let dumeUrl = scriptPath.pathname.split('/').slice(0,-1).join('/') + '/'; let dumeUrl = scriptPath.pathname.split('/').slice(0,-1).join('/') + '/';
@ -83,7 +84,7 @@ export class Connection
this.connected = false; this.connected = false;
if(this.autoReconnect) if(this.autoReconnect)
{ {
this.autoReconnectTimer = setTimeout(() => this.connect(), this.autoReconnectTimeout) this.autoReconnectTimer = setTimeout(() => this.connect(), this.autoReconnectTimeout) as unknown as number;
} }
} }
private eventError() private eventError()

View File

@ -1,4 +1,3 @@
import "webrtc-adapter";
import WebRTC from "./WebRTC"; import WebRTC from "./WebRTC";
import Peer from "./Peer"; import Peer from "./Peer";

View File

@ -22,21 +22,18 @@ export default class Peer extends EventTarget
public selfSocket : boolean = false; public selfSocket : boolean = false;
public active : boolean = false; public active : boolean = false;
public info : PeerInfo; public info : PeerInfo;
public rtc? : WebRTC; public rtc : WebRTC;
public peerConnection : boolean = false; public peerConnection : boolean = false;
public primaryChannel : "websocket" | "datachannel" = "datachannel"; public primaryChannel : "websocket" | "datachannel" = "datachannel";
constructor(wsts:MWSE){ constructor(wsts:MWSE){
super(); super();
this.mwse = wsts; this.mwse = wsts;
this.rtc = this.createRTC();
this.info = new PeerInfo(this); this.info = new PeerInfo(this);
this.on('pack',(data:{type?:string,action?:IMessageSymbase,payload?:any}) => { this.on('pack',(data:{type?:string,action?:IMessageSymbase,payload?:any}) => {
if(data.type == ':rtcpack:') if(data.type == ':rtcpack:')
{
if(this.rtc)
{ {
return this.rtc.emit("input", data.payload) return this.rtc.emit("input", data.payload)
}
return console.warn("Not active rtc but recaived rtc packs")
}; };
this.emit("message", data); this.emit("message", data);
}); });

View File

@ -1,6 +1,5 @@
import P2PFileSender from "./P2PFileSender"; import P2PFileSender from "./P2PFileSender";
import Peer from "./Peer"; import Peer from "./Peer";
import "webrtc-adapter";
interface TransferStreamInfo interface TransferStreamInfo
{ {
senders : RTCRtpSender[]; senders : RTCRtpSender[];
@ -32,6 +31,12 @@ export default class WebRTC
rtcpMuxPolicy:"require", rtcpMuxPolicy:"require",
}; };
public isPolite() : boolean
{
let myId = this.peer?.mwse.peer('me').socketId as string;
let peerId = this.peer?.socketId as string;
return myId < peerId;
}
public static defaultICEServers : RTCIceServer[] = [{ public static defaultICEServers : RTCIceServer[] = [{
urls: "stun:stun.l.google.com:19302" urls: "stun:stun.l.google.com:19302"
@ -49,6 +54,13 @@ export default class WebRTC
public FileTransportChannel? : P2PFileSender; public FileTransportChannel? : P2PFileSender;
public makingOffer = false;
public ignoreOffer = false;
public isSettingRemoteAnswerPending = false;
candicatePack : RTCIceCandidate[] = [];
constructor( constructor(
rtcConfig?: RTCConfiguration, rtcConfig?: RTCConfiguration,
rtcServers?: RTCIceServer[] rtcServers?: RTCIceServer[]
@ -101,11 +113,40 @@ export default class WebRTC
switch(data.type) switch(data.type)
{ {
case "icecandidate":{ case "icecandidate":{
try{
if(this.rtc.remoteDescription){
await this.rtc.addIceCandidate(new RTCIceCandidate(data.value)); await this.rtc.addIceCandidate(new RTCIceCandidate(data.value));
}else{
this.candicatePack.push(new RTCIceCandidate(data.value))
}
}catch(error){
debugger;
}finally{
console.log("ICE Canbet")
}
break; break;
} }
case "offer":{ case "offer":{
let readyForOffer = !this.makingOffer && (this.rtc.signalingState == "stable" || this.isSettingRemoteAnswerPending);
const offerCollision = !readyForOffer;
this.ignoreOffer = !this.isPolite() && offerCollision;
if(this.ignoreOffer){
return;
}
this.isSettingRemoteAnswerPending = false;
await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value)); await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value));
this.isSettingRemoteAnswerPending = false;
for (const candidate of this.candicatePack) {
await this.rtc.addIceCandidate(candidate);
}
let answer = await this.rtc.createAnswer({ let answer = await this.rtc.createAnswer({
offerToReceiveAudio: true, offerToReceiveAudio: true,
offerToReceiveVideo: true offerToReceiveVideo: true
@ -119,6 +160,10 @@ export default class WebRTC
} }
case "answer":{ case "answer":{
await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value)) await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value))
for (const candidate of this.candicatePack) {
await this.rtc.addIceCandidate(candidate);
}
break; break;
} }
case "streamInfo":{ case "streamInfo":{
@ -270,7 +315,13 @@ export default class WebRTC
this.emit('connected'); this.emit('connected');
} }
}; };
if(this.connectionStatus == 'failed' || this.connectionStatus == "disconnected" || this.connectionStatus == "closed")
if(this.connectionStatus == 'failed')
{
this.rtc.restartIce();
};
if(this.connectionStatus == "closed")
{ {
if(this.active) if(this.active)
{ {
@ -298,6 +349,8 @@ export default class WebRTC
} }
public async eventNogationNeeded() public async eventNogationNeeded()
{ {
try{
this.makingOffer = true;
let offer = await this.rtc.createOffer({ let offer = await this.rtc.createOffer({
iceRestart: true, iceRestart: true,
offerToReceiveAudio: true, offerToReceiveAudio: true,
@ -308,6 +361,12 @@ export default class WebRTC
type: 'offer', type: 'offer',
value: offer value: offer
}); });
}catch(error){
console.error(`Nogation Error:`, error)
}
finally{
this.makingOffer = false;
}
} }
public eventSignalingState() public eventSignalingState()
{ {

View File

@ -34,7 +34,8 @@ export default class MWSE extends EventTarget {
}*/ }*/
constructor(options: IConnection){ constructor(options: IConnection){
super(); super();
this.server = new Connection(options); MWSE.rtc = MWSE as unknown as WebRTC;
this.server = new Connection(this,options);
this.WSTSProtocol = new WSTSProtocol(this); this.WSTSProtocol = new WSTSProtocol(this);
this.EventPooling = new EventPool(this); this.EventPooling = new EventPool(this);
this.virtualPressure = new IPPressure(this); this.virtualPressure = new IPPressure(this);

View File

@ -4,7 +4,7 @@
"description": "Mikro WebSocket Engine", "description": "Mikro WebSocket Engine",
"scripts": { "scripts": {
"compile": "parcel watch --no-hmr", "compile": "parcel watch --no-hmr",
"build": "parcel build" "build": "parcel build --no-optimize"
}, },
"source": "./frontend/index.ts", "source": "./frontend/index.ts",
"targets": { "targets": {

View File

@ -14,7 +14,7 @@
</div> </div>
</div> </div>
<script src="index.js?v=42"></script> <script src="./index.js?v=42"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</body> </body>
</html> </html>

View File

@ -6,14 +6,6 @@ let mwse;
* @type {string} * @type {string}
*/ */
let mySocketId; let mySocketId;
/**
* @type {string}
*/
let myIPAddress;
/**
* @type {string}
*/
let myNumber;
/** /**
* @type {string} * @type {string}
*/ */
@ -42,6 +34,14 @@ function connect()
endpoint: "wss://ws.saqut.com" endpoint: "wss://ws.saqut.com"
}); });
MWSE.rtc.defaultICEServers = [{
urls: "turn:20.166.82.187:3478",
username: "turnserver",
credential: "turnserver"
},{
urls: "stun:stun.l.google.com:19302"
}];
mwse.scope(beginEngine); mwse.scope(beginEngine);
} }
@ -71,7 +71,7 @@ function templateVideo(name, stream,infinitedMute)
<video autoplay playsinline muted data-name="${name}"> <video autoplay playsinline muted data-name="${name}">
</video> </video>
<div class="tool-container"> <!--div class="tool-container">
<div class="tools"> <div class="tools">
<button> <button>
<i class="material-icons">home</i> <i class="material-icons">home</i>
@ -80,7 +80,7 @@ function templateVideo(name, stream,infinitedMute)
<i class="material-icons">close</i> <i class="material-icons">close</i>
</button> </button>
</div> </div>
</div> </div--->
</div> </div>
`,"text/html"); `,"text/html");
@ -108,9 +108,9 @@ function addVideoList(name, stream, peer, infinitedMute)
function removeVideoList(name) function removeVideoList(name)
{ {
if(videoContainer.querySelector(`[data-name="${name}"]`)) if(videoContainer.querySelector(`[data-user="${name}"]`))
{ {
let k = videoContainer.querySelector(`[data-name="${name}"]`); let k = videoContainer.querySelector(`[data-user="${name}"]`);
if(k.dataset.user == activeVideo?.dataset.user || !activeVideo) if(k.dataset.user == activeVideo?.dataset.user || !activeVideo)
{ {
activePeer = null; activePeer = null;
@ -124,8 +124,6 @@ async function beginEngine()
let me = mwse.peer("me"); let me = mwse.peer("me");
me.disablePairAuth(); me.disablePairAuth();
mySocketId = me.socketId; mySocketId = me.socketId;
myIPAddress = await mwse.virtualPressure.allocAPIPAddress();
myNumber = await mwse.virtualPressure.allocAPNumber();
let url = new URL(window.location); let url = new URL(window.location);
roomid = url.searchParams.get("room"); roomid = url.searchParams.get("room");
@ -207,7 +205,9 @@ async function connectRoom()
room.on("eject", peer => OutgoingPeer(peer)); room.on("eject", peer => OutgoingPeer(peer));
for (const peer of await room.fetchPeers()) { for (const peer of await room.fetchPeers()) {
IncomingPeer(peer) if(peer.socketId != mwse.peer('me').socketId){
IncomingPeer(peer,false)
}
} }
addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true) addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true)
@ -219,21 +219,13 @@ async function connectRoom()
*/ */
function IncomingPeer(peer,activeConnect) function IncomingPeer(peer,activeConnect)
{ {
peer.createRTC({
iceCandidatePoolSize: 0
},[{
urls: "turn:20.166.82.187:3478",
username: "turnserver",
credential: "turnserver"
},{
urls: "stun:stun.l.google.com:19302"
}]);
if(activeConnect) if(activeConnect)
{ {
peer.rtc.connect(); peer.rtc.connect();
} }
peer.rtc.rtc.turboBitrate = 0; peer.rtc.rtc.turboBitrate = 0;
peer.rtc.on('connected',() => { peer.rtc.on('connected',() => {
console.log("Connected");
if(!activeConnect) if(!activeConnect)
{ {
peer.rtc.sendStream(outgoingStream, "Webcam", {}); peer.rtc.sendStream(outgoingStream, "Webcam", {});
@ -241,6 +233,7 @@ function IncomingPeer(peer,activeConnect)
} }
}); });
peer.rtc.on('disconnected',() => { peer.rtc.on('disconnected',() => {
console.log("Disconnected");
removeVideoList(peer.streamY, peer); removeVideoList(peer.streamY, peer);
delete activePeers[peer.socketId]; delete activePeers[peer.socketId];
}); });
@ -258,7 +251,7 @@ function IncomingPeer(peer,activeConnect)
*/ */
function OutgoingPeer(peer) function OutgoingPeer(peer)
{ {
removeVideoList(peer.streamY, peer); removeVideoList(peer.socketId, peer);
} }
let relative; let relative;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long