You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
Merge branch 'main' of https://github.com/NoobishSVK/fm-dx-webserver
This commit is contained in:
@@ -22,24 +22,41 @@ function parsePluginConfig(filePath) {
|
|||||||
// Check if pluginConfig has frontEndPath defined
|
// Check if pluginConfig has frontEndPath defined
|
||||||
if (pluginConfig.frontEndPath) {
|
if (pluginConfig.frontEndPath) {
|
||||||
const sourcePath = path.join(path.dirname(filePath), pluginConfig.frontEndPath);
|
const sourcePath = path.join(path.dirname(filePath), pluginConfig.frontEndPath);
|
||||||
const destinationDir = path.join(path.dirname(filePath), '../web/js/plugins', pluginConfig.frontEndPath, '..');
|
const destinationDir = path.join(__dirname, '../web/js/plugins', path.dirname(pluginConfig.frontEndPath));
|
||||||
|
|
||||||
|
// Check if the source path exists
|
||||||
|
if (!fs.existsSync(sourcePath)) {
|
||||||
|
console.error(`Error: source path ${sourcePath} does not exist.`);
|
||||||
|
return pluginConfig;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the destination directory exists, if not, create it
|
// Check if the destination directory exists, if not, create it
|
||||||
if (!fs.existsSync(destinationDir)) {
|
if (!fs.existsSync(destinationDir)) {
|
||||||
fs.mkdirSync(destinationDir, { recursive: true }); // Create directory recursively
|
fs.mkdirSync(destinationDir, { recursive: true }); // Create directory recursively
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the file to the destination directory
|
|
||||||
const destinationFile = path.join(destinationDir, path.basename(sourcePath));
|
const destinationFile = path.join(destinationDir, path.basename(sourcePath));
|
||||||
fs.copyFileSync(sourcePath, destinationFile);
|
|
||||||
setTimeout(function() {
|
// Platform-specific handling for symlinks/junctions
|
||||||
consoleCmd.logInfo(`Plugin ${pluginConfig.name} ${pluginConfig.version} initialized successfully.`);
|
if (process.platform !== 'win32') {
|
||||||
}, 500)
|
// On Linux, create a symlink
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(destinationFile)) {
|
||||||
|
fs.unlinkSync(destinationFile); // Remove existing file/symlink
|
||||||
|
}
|
||||||
|
fs.symlinkSync(sourcePath, destinationFile);
|
||||||
|
setTimeout(function() {
|
||||||
|
consoleCmd.logInfo(`Plugin ${pluginConfig.name} ${pluginConfig.version} initialized successfully.`);
|
||||||
|
}, 500)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error creating symlink at ${destinationFile}: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(`Error: frontEndPath is not defined in ${filePath}`);
|
console.error(`Error: frontEndPath is not defined in ${filePath}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Error parsing plugin config from ${filePath}: ${err}`);
|
console.error(`Error parsing plugin config from ${filePath}: ${err.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pluginConfig;
|
return pluginConfig;
|
||||||
@@ -62,9 +79,37 @@ function collectPluginConfigs() {
|
|||||||
return pluginConfigs;
|
return pluginConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the web/js/plugins directory exists
|
||||||
|
const webJsPluginsDir = path.join(__dirname, '../web/js/plugins');
|
||||||
|
if (!fs.existsSync(webJsPluginsDir)) {
|
||||||
|
fs.mkdirSync(webJsPluginsDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function to create symlinks/junctions for plugins
|
||||||
|
function createLinks() {
|
||||||
|
const pluginsDir = path.join(__dirname, '../plugins');
|
||||||
|
const destinationPluginsDir = path.join(__dirname, '../web/js/plugins');
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
// On Windows, create a junction
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(destinationPluginsDir)) {
|
||||||
|
fs.rmSync(destinationPluginsDir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.symlinkSync(pluginsDir, destinationPluginsDir, 'junction');
|
||||||
|
setTimeout(function() {
|
||||||
|
consoleCmd.logInfo(`Plugin ${pluginConfig.name} ${pluginConfig.version} initialized successfully.`);
|
||||||
|
}, 500)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error creating junction at ${destinationPluginsDir}: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Usage example
|
// Usage example
|
||||||
const allPluginConfigs = collectPluginConfigs();
|
const allPluginConfigs = collectPluginConfigs();
|
||||||
|
createLinks();
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
allPluginConfigs
|
allPluginConfigs
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ let cachedData = {};
|
|||||||
let lastFetchTime = 0;
|
let lastFetchTime = 0;
|
||||||
const fetchInterval = 3000;
|
const fetchInterval = 3000;
|
||||||
|
|
||||||
|
const esSwitchCache = {"lastCheck":0, "esSwitch":false};
|
||||||
|
const esFetchInterval = 300000;
|
||||||
|
|
||||||
// Fetch data from maps
|
// Fetch data from maps
|
||||||
function fetchTx(freq, piCode, rdsPs) {
|
function fetchTx(freq, piCode, rdsPs) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -46,6 +49,7 @@ function processData(data, piCode, rdsPs) {
|
|||||||
let maxScore = -Infinity; // Initialize maxScore with a very low value
|
let maxScore = -Infinity; // Initialize maxScore with a very low value
|
||||||
let txAzimuth;
|
let txAzimuth;
|
||||||
let maxDistance;
|
let maxDistance;
|
||||||
|
let esMode = checkEs();
|
||||||
|
|
||||||
for (const cityId in data.locations) {
|
for (const cityId in data.locations) {
|
||||||
const city = data.locations[cityId];
|
const city = data.locations[cityId];
|
||||||
@@ -53,7 +57,11 @@ function processData(data, piCode, rdsPs) {
|
|||||||
for (const station of city.stations) {
|
for (const station of city.stations) {
|
||||||
if (station.pi === piCode.toUpperCase() && !station.extra && station.ps && station.ps.toLowerCase().includes(rdsPs.replace(/ /g, '_').replace(/^_*(.*?)_*$/, '$1').toLowerCase())) {
|
if (station.pi === piCode.toUpperCase() && !station.extra && station.ps && station.ps.toLowerCase().includes(rdsPs.replace(/ /g, '_').replace(/^_*(.*?)_*$/, '$1').toLowerCase())) {
|
||||||
const distance = haversine(serverConfig.identification.lat, serverConfig.identification.lon, city.lat, city.lon);
|
const distance = haversine(serverConfig.identification.lat, serverConfig.identification.lon, city.lat, city.lon);
|
||||||
const score = (10*Math.log10(station.erp*1000)) / distance.distanceKm; // Calculate score
|
let weightDistance = distance.distanceKm
|
||||||
|
if (esMode && (distance.distanceKm > 200)) {
|
||||||
|
weightDistance = Math.abs(distance.distanceKm-1500);
|
||||||
|
}
|
||||||
|
const score = (10*Math.log10(station.erp*1000)) / weightDistance; // Calculate score
|
||||||
if (score > maxScore) {
|
if (score > maxScore) {
|
||||||
maxScore = score;
|
maxScore = score;
|
||||||
txAzimuth = distance.azimuth;
|
txAzimuth = distance.azimuth;
|
||||||
@@ -82,6 +90,37 @@ function processData(data, piCode, rdsPs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkEs() {
|
||||||
|
const now = Date.now();
|
||||||
|
const url = "https://fmdx.org/includes/tools/get_muf.php";
|
||||||
|
let esSwitch = false;
|
||||||
|
|
||||||
|
if (now - esSwitchCache.lastCheck < esFetchInterval) {
|
||||||
|
esSwitch = esSwitchCache.esSwitch;
|
||||||
|
} else {
|
||||||
|
esSwitchCache.lastCheck = now;
|
||||||
|
fetch(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (serverConfig.identification.lon < -32) {
|
||||||
|
if (data.north_america.max_frequency != "No data") {
|
||||||
|
esSwitch = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data.europe.max_frequency != "No data") {
|
||||||
|
esSwitch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
esSwitchCache.esSwitch = esSwitch;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return esSwitch;
|
||||||
|
}
|
||||||
|
|
||||||
function haversine(lat1, lon1, lat2, lon2) {
|
function haversine(lat1, lon1, lat2, lon2) {
|
||||||
const R = 6371; // Earth radius in kilometers
|
const R = 6371; // Earth radius in kilometers
|
||||||
const dLat = deg2rad(lat2 - lat1);
|
const dLat = deg2rad(lat2 - lat1);
|
||||||
|
|||||||
@@ -433,7 +433,7 @@
|
|||||||
FM-DX Webserver <span style="color: var(--color-3);" class="version-string"></span>
|
FM-DX Webserver <span style="color: var(--color-3);" class="version-string"></span>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-small m-0 color-3">by <a href="https://noobish.eu" target="_blank">Noobish</a>, <a href="https://fmdx.pl" target="_blank">kkonradpl</a> & the OpenRadio community.</p>
|
<p class="text-small m-0 color-3">by <a href="https://noobish.eu" target="_blank">Noobish</a>, <a href="https://fmdx.pl" target="_blank">kkonradpl</a> & the OpenRadio community.</p>
|
||||||
<span class="text-small" style="color: var(--color-3);">[<a href="https://list.fmdx.pl" target="_blank">Receiver Map</a>]</span>
|
<span class="text-small" style="color: var(--color-3);">[<a href="https://servers.fmdx.org/" target="_blank">Receiver Map</a>]</span>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<% if(ownerContact){ %>
|
<% if(ownerContact){ %>
|
||||||
@@ -486,6 +486,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="js/websocket.js"></script>
|
||||||
<script src="js/webserver.js"></script>
|
<script src="js/webserver.js"></script>
|
||||||
<% plugins?.forEach(function(plugin) { %>
|
<% plugins?.forEach(function(plugin) { %>
|
||||||
<script src="js/plugins/<%= plugin %>"></script>
|
<script src="js/plugins/<%= plugin %>"></script>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ var _3LAS = /** @class */ (function () {
|
|||||||
};
|
};
|
||||||
_3LAS.prototype.Start = function () {
|
_3LAS.prototype.Start = function () {
|
||||||
this.ConnectivityFlag = false;
|
this.ConnectivityFlag = false;
|
||||||
|
this.Stop(); // Attempt to mitigate the 0.5x speed/multiple stream bug
|
||||||
|
|
||||||
// This is stupid, but required for Android.... thanks Google :(
|
// This is stupid, but required for Android.... thanks Google :(
|
||||||
if (this.WakeLock)
|
if (this.WakeLock)
|
||||||
@@ -128,11 +129,50 @@ var _3LAS = /** @class */ (function () {
|
|||||||
this.ConnectivityFlag = false;
|
this.ConnectivityFlag = false;
|
||||||
if (this.ConnectivityCallback)
|
if (this.ConnectivityCallback)
|
||||||
this.ConnectivityCallback(false);
|
this.ConnectivityCallback(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldReconnect) {
|
||||||
|
if (!this.ConnectivityFlag) {
|
||||||
|
console.log("Initial reconnect attempt...");
|
||||||
|
this.Stop(); // Attempt to mitigate the 0.5x speed/multiple stream bug
|
||||||
|
this.Start();
|
||||||
}
|
}
|
||||||
this.Start();
|
|
||||||
};
|
// Delay launch of subsequent reconnect attempts by 3 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
let streamReconnecting = false;
|
||||||
|
|
||||||
|
let intervalReconnect = setInterval(() => {
|
||||||
|
if (this.ConnectivityFlag || typeof Stream === 'undefined' || Stream === null) {
|
||||||
|
console.log("Reconnect attempts aborted.");
|
||||||
|
clearInterval(intervalReconnect);
|
||||||
|
} else if (!streamReconnecting) {
|
||||||
|
streamReconnecting = true;
|
||||||
|
console.log("Attempting to restart stream...");
|
||||||
|
this.Stop(); // Attempt to mitigate the 0.5x speed/multiple stream bug
|
||||||
|
this.Start();
|
||||||
|
// Wait for reconnect attempt
|
||||||
|
setTimeout(() => {
|
||||||
|
streamReconnecting = false;
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
// Restore user set volume
|
||||||
|
if (Stream && typeof newVolumeGlobal !== 'undefined' && newVolumeGlobal !== null) {
|
||||||
|
Stream.Volume = newVolumeGlobal;
|
||||||
|
console.log(`User volume restored: ${Math.round(newVolumeGlobal * 100)}%`);
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.Logger.Log("Reconnection is disabled.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
_3LAS.prototype.OnSocketDataReady = function (data) {
|
_3LAS.prototype.OnSocketDataReady = function (data) {
|
||||||
this.Fallback.OnSocketDataReady(data);
|
this.Fallback.OnSocketDataReady(data);
|
||||||
};
|
};
|
||||||
return _3LAS;
|
return _3LAS;
|
||||||
}());
|
}());
|
||||||
|
|||||||
@@ -1,43 +1,69 @@
|
|||||||
const DefaultVolume = 0.5;
|
const DefaultVolume = 0.5;
|
||||||
let Stream;
|
let Stream;
|
||||||
|
let shouldReconnect = true;
|
||||||
|
let newVolumeGlobal = 1;
|
||||||
|
|
||||||
function Init(_ev) {
|
function Init(_ev) {
|
||||||
try {
|
|
||||||
const settings = new _3LAS_Settings();
|
|
||||||
if (!Stream) { // Ensure Stream is not re-initialized
|
|
||||||
Stream = new _3LAS(null, settings);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream.ConnectivityCallback = OnConnectivityCallback;
|
|
||||||
$(".playbutton").off('click').on('click', OnPlayButtonClick); // Ensure only one event handler is attached
|
$(".playbutton").off('click').on('click', OnPlayButtonClick); // Ensure only one event handler is attached
|
||||||
$("#volumeSlider").off("input").on("input", updateVolume); // Ensure only one event handler is attached
|
$("#volumeSlider").off("input").on("input", updateVolume); // Ensure only one event handler is attached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createStream() {
|
||||||
|
try {
|
||||||
|
const settings = new _3LAS_Settings();
|
||||||
|
Stream = new _3LAS(null, settings);
|
||||||
|
Stream.ConnectivityCallback = OnConnectivityCallback;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Initialization Error: ", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyStream() {
|
||||||
|
if (Stream) {
|
||||||
|
Stream.Stop();
|
||||||
|
Stream = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function OnConnectivityCallback(isConnected) {
|
function OnConnectivityCallback(isConnected) {
|
||||||
Stream.Volume = isConnected ? 1.0 : DefaultVolume;
|
console.log("Connectivity changed:", isConnected);
|
||||||
|
if (Stream) {
|
||||||
|
Stream.Volume = isConnected ? 1.0 : DefaultVolume;
|
||||||
|
} else {
|
||||||
|
console.warn("Stream is not initialized.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function OnPlayButtonClick(_ev) {
|
function OnPlayButtonClick(_ev) {
|
||||||
const $playbutton = $('.playbutton');
|
const $playbutton = $('.playbutton');
|
||||||
$playbutton.find('.fa-solid').toggleClass('fa-play fa-stop');
|
if (Stream) {
|
||||||
|
console.log("Stopping stream...");
|
||||||
if (Stream.ConnectivityFlag) {
|
shouldReconnect = false;
|
||||||
Stream.Stop();
|
destroyStream();
|
||||||
|
$playbutton.find('.fa-solid').toggleClass('fa-stop fa-play');
|
||||||
} else {
|
} else {
|
||||||
|
console.log("Starting stream...");
|
||||||
|
shouldReconnect = true;
|
||||||
|
createStream();
|
||||||
Stream.Start();
|
Stream.Start();
|
||||||
$playbutton.addClass('bg-gray').prop('disabled', true);
|
$playbutton.find('.fa-solid').toggleClass('fa-play fa-stop');
|
||||||
setTimeout(() => {
|
|
||||||
$playbutton.removeClass('bg-gray').prop('disabled', false);
|
|
||||||
}, 3000);
|
|
||||||
}
|
}
|
||||||
|
$playbutton.addClass('bg-gray').prop('disabled', true);
|
||||||
|
setTimeout(() => {
|
||||||
|
$playbutton.removeClass('bg-gray').prop('disabled', false);
|
||||||
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVolume() {
|
function updateVolume() {
|
||||||
Stream.Volume = $(this).val();
|
if (Stream) {
|
||||||
|
const newVolume = $(this).val();
|
||||||
|
newVolumeGlobal = newVolume;
|
||||||
|
console.log("Volume updated to:", newVolume);
|
||||||
|
Stream.Volume = newVolume;
|
||||||
|
} else {
|
||||||
|
console.warn("Stream is not initialized.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(Init);
|
$(document).ready(Init);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
var url = new URL('text', window.location.href);
|
// WebSocket connection located in ./websocket.js
|
||||||
url.protocol = url.protocol.replace('http', 'ws');
|
|
||||||
var socketAddress = url.href;
|
|
||||||
var socket = new WebSocket(socketAddress);
|
|
||||||
var parsedData, signalChart, previousFreq;
|
var parsedData, signalChart, previousFreq;
|
||||||
var signalData = [];
|
var signalData = [];
|
||||||
var data = [];
|
var data = [];
|
||||||
@@ -10,7 +10,7 @@ let updateCounter = 0;
|
|||||||
const europe_programmes = [
|
const europe_programmes = [
|
||||||
"No PTY", "News", "Current Affairs", "Info",
|
"No PTY", "News", "Current Affairs", "Info",
|
||||||
"Sport", "Education", "Drama", "Culture", "Science", "Varied",
|
"Sport", "Education", "Drama", "Culture", "Science", "Varied",
|
||||||
"Pop M", "Rock M", "Easy Listening", "Light Classical",
|
"Pop Music", "Rock Music", "Easy Listening", "Light Classical",
|
||||||
"Serious Classical", "Other Music", "Weather", "Finance",
|
"Serious Classical", "Other Music", "Weather", "Finance",
|
||||||
"Children's Programmes", "Social Affairs", "Religion", "Phone-in",
|
"Children's Programmes", "Social Affairs", "Religion", "Phone-in",
|
||||||
"Travel", "Leisure", "Jazz Music", "Country Music", "National Music",
|
"Travel", "Leisure", "Jazz Music", "Country Music", "National Music",
|
||||||
@@ -873,7 +873,7 @@ function initTooltips() {
|
|||||||
// Add a delay of 500 milliseconds before creating and appending the tooltip
|
// Add a delay of 500 milliseconds before creating and appending the tooltip
|
||||||
$(this).data('timeout', setTimeout(() => {
|
$(this).data('timeout', setTimeout(() => {
|
||||||
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
var tooltip = $('<div class="tooltiptext"></div>').html(tooltipText);
|
||||||
$('body').append(tooltip);
|
if ($('.tooltiptext').length === 0) { $('body').append(tooltip); } // Don't allow more than one tooltip
|
||||||
|
|
||||||
var posX = e.pageX;
|
var posX = e.pageX;
|
||||||
var posY = e.pageY;
|
var posY = e.pageY;
|
||||||
@@ -888,6 +888,7 @@ function initTooltips() {
|
|||||||
// Clear the timeout if the mouse leaves before the delay completes
|
// Clear the timeout if the mouse leaves before the delay completes
|
||||||
clearTimeout($(this).data('timeout'));
|
clearTimeout($(this).data('timeout'));
|
||||||
$('.tooltiptext').remove();
|
$('.tooltiptext').remove();
|
||||||
|
setTimeout(() => { $('.tooltiptext').remove(); }, 500); // Ensure no tooltips remain stuck
|
||||||
}).mousemove(function(e){
|
}).mousemove(function(e){
|
||||||
var tooltipWidth = $('.tooltiptext').outerWidth();
|
var tooltipWidth = $('.tooltiptext').outerWidth();
|
||||||
var tooltipHeight = $('.tooltiptext').outerHeight();
|
var tooltipHeight = $('.tooltiptext').outerHeight();
|
||||||
|
|||||||
30
web/js/websocket.js
Normal file
30
web/js/websocket.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
var url = new URL('text', window.location.href);
|
||||||
|
url.protocol = url.protocol.replace('http', 'ws');
|
||||||
|
var socketAddress = url.href;
|
||||||
|
var socket = new WebSocket(socketAddress);
|
||||||
|
|
||||||
|
const socketPromise = new Promise((resolve, reject) => {
|
||||||
|
// Event listener for when the WebSocket connection is open
|
||||||
|
socket.addEventListener('open', () => {
|
||||||
|
console.log('WebSocket connection open');
|
||||||
|
resolve(socket); // Resolve the promise with the WebSocket instance
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event listener for WebSocket errors
|
||||||
|
socket.addEventListener('error', (error) => {
|
||||||
|
console.error('WebSocket error', error);
|
||||||
|
reject(error); // Reject the promise on error
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event listener for WebSocket connection closure
|
||||||
|
socket.addEventListener('close', () => {
|
||||||
|
console.warn('WebSocket connection closed');
|
||||||
|
reject(new Error('WebSocket connection closed')); // Reject with closure warning
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assign the socketPromise to window.socketPromise for global access
|
||||||
|
window.socketPromise = socketPromise;
|
||||||
|
|
||||||
|
// Assign the socket instance to window.socket for global access
|
||||||
|
window.socket = socket;
|
||||||
Reference in New Issue
Block a user