I try to use Deno ws to reload the document, but it will throw an error after second reload
Uncaught ConnectionReset: Socket has already been closed throw new Deno.errors.ConnectionReset("Socket has already been closed");
var ws = new WebSocket("ws://127.0.0.1:8080/ws")
ws.onopen = function () {
ws.send('ws open')
console.log('ws open');
}
ws.addEventListener("message", (e) => {
if (e.data === 'fileUpdate') {
// ws.send('close')
location.replace(location.href);
}
})
seem location.replace(location.href) raise an error
any solution?
The error is happening because you're sending a message after the socket is closed.
When you do: location.replace(location.href); the page is refreshed and the current socket is closed.
You can either catch the error, or check for ws.isClosed before sending the message.
for await (const e of ws) {
if (e === 'close') {
ob.remove("fileUpdate")
continue
}
ob.on("fileUpdate", () => {
console.log('sending')
if(!ws.isClosed)
ws.send("fileUpdate")
})
}
While that will fix the error, it won't fix the cause. Your ob.on('fileUpdate') event is firing after the socket is closed. You should clear that listener on the WebSocket close event, you can do that using ws.isWebSocketCloseEvent
import { acceptWebSocket, isWebSocketCloseEvent } from "https://deno.land/std#0.51.0/ws/mod.ts";
/* ... */
for await (const e of ws) {
if(isWebSocketCloseEvent(e) || e === 'close') {
// clear listeners here
ob.remove("fileUpdate")
// if e === 'close' you may want to close the socket
}
}
here is Deno code :
import { Application } from "https://deno.land/x/abc/mod.ts";
import { acceptWebSocket } from "https://deno.land/std#0.51.0/ws/mod.ts";
new Application()
.file("/", "./index.html")
.file("/module.js", "./module.js")
// .file("sw.js", "ServiceWorker.js")
.get('/ws', async (c: any) => {
const { conn, headers, r: bufReader, w: bufWriter } = c.request;
const ws = await acceptWebSocket({
conn,
headers,
bufReader,
bufWriter,
});
for await (const e of ws) {
if (e === 'close') {
ob.remove("fileUpdate")
continue
}
ob.on("fileUpdate", () => {
ws.send("fileUpdate")
})
}
})
.start({ port: 8080 })
ob like this :
class Ob {
private list: ObList[] = []
send(event: string) {
this.list.forEach((e: ObList) => {
if (e.event === event) {
e.cb && e.cb()
}
})
}
on(event: string, cb: Function) {
this.list.push({ event, cb })
}
remove(event:string){
this.list=this.list.filter((e:ObList)=>{
return e.event!==event
})
}
}
the framework is abc
Related
I am working with WebSocket in reactjs, but WebSocket.send is not executing on the onClick event.
here I create WebSocket
const ws = new WebSocket("ws://192.168.18.112:8000/ws/notification/");
connect to WebSocket
ws.onopen = (e) => {
console.log("connect");
};
here is my onClick function
const sendNotification = (e) => {
console.log("click");
if (ws.readyState === WebSocket.OPEN && message !== "") {
ws.send("message");
console.log("Sending message"); // this console is execute
} else if (ws.readyState === WebSocket.CONNECTING) {
ws.addEventListener("open", () => sendNotification());
console.log("Connecting state");
console.log("Not Send");
} else {
console.log("nothing happen");
}
};
so here is my problem I am unable to find bug or problem in my code.
try this W3CWebSocket. Also i don't think there si a "/" after notification after ws/notification double check if your end point correct or not.
mport React, { Component } from 'react';
import { w3cwebsocket as W3CWebSocket } from "websocket";
const client = new W3CWebSocket('ws://192.168.18.112:8000/ws/notification/');
class App extends Component {
componentWillMount() {
client.onopen = () => {
console.log('WebSocket Client Connected');
};
client.onmessage = (message) => {
console.log(message);
};
}
render() {
return (
<div>
Practical Intro To WebSockets.
</div>
);
}
}
export default App;
I'm working on app which send message via websockets (managed by django channels) and in return it receives json from django db as a message and renders frontend based on that json.
I have Invalid State Error when I try to send message by websocket, why? Messages send are usually Json. I works properly all the time but commented part doesn't and I don't know why please explain me.
function main() {
configGame();
}
function configGame() {
const socket = "ws://" + window.location.host + window.location.pathname;
const websocket = new WebSocket(socket);
const playerName = document.querySelector(".playerName_header").textContent;
function asignEvents() {
const ready_btn = document.querySelector(".--ready_btn");
const start_btn = document.querySelector(".--start_btn");
ready_btn.addEventListener("click", () => {
let mess = JSON.stringify({
player: playerName,
action: "ready",
});
sendMess(mess);
});
start_btn.addEventListener("click", () => {
let mess = JSON.stringify({
player: playerName,
action: "start",
});
sendMess(mess);
});
}
function openWebsocket() {
console.log("Establishing Websocket Connection...");
websocket.onopen = () => {
console.log("Websocket Connection Established!");
};
}
function setWebsocket() {
websocket.onmessage = (mess) => {
console.log(`Message: ${mess.data}`);
dataJson = JSON.parse(mess.data);
dataJson = JSON.parse(dataJson.message);
//Player Ready (jeszcze z max_players zrobic kontrolke)
if (dataJson.action === "player_ready") {
const playersReadyText = document.querySelector(".players_ready_text");
playersReadyText.textContent = `Players ready: ${dataJson.players_ready}`;
}
};
websocket.onclose = () => {
console.log("Websocket Connection Terminated!");
};
}
/*
function checkState() {
let mess = JSON.stringify({
player: playerName,
action: "game state",
});
sendMess(mess);
}
*/
function sendMess(messText) {
websocket.send(messText);
}
openWebsocket();
checkState(); //This one doesn't work
asignEvents();
setWebsocket();
}
// Asigning Event Listneres to DOM ELEMENTS
function asignEvents() {
const ready_btn = document.querySelector(".--ready_btn");
const start_btn = document.querySelector(".--start_btn");
ready_btn.addEventListener("click", () => {
console.log("Ready");
});
start_btn.addEventListener("click", () => {
console.log("Start");
});
}
main();
Error:
Console (Safari) returns InvalidState error and points to
method checkState and sendMess.
InvalidStateError: The object is in an invalid state.
Is the websocket connected?
sendMess(messText) {
if (websocket.readyState === WebSocket.OPEN) {
websocket.send(messText);
} else {
console.warn("websocket is not connected");
}
}
I'm building an Electron application and I'm stuck with the following problem.
I'm getting information using a socket from an apparatus, and It was working fine. I wanted to change the html of the page if the program gets a type of message, so basically I used the loadUrl method, but then, after sending a message to the renderer process I't seems like it's not being received.
My code:
photoViewOn = false;
...
app.on('ready', function(){
// Create new window
mainWindow = new BrowserWindow({
backgroundColor: '#000000',
fullscreen : true,
frame : false,
icon : __dirname + "/res/logo.png",
webPreferences: {
nodeIntegration : true
}
});
mainWindow.webContents.openDevTools();
// Load html in window
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'bigNames.html'),
protocol: 'file:',
slashes:true,
}))...)
function HTMLupdate(msg) {
mainWindow && mainWindow.webContents.send('update', msg);
var server = socketBuilder('localhost', '7777', {
message: (msg, rinfo) => {
try {
console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
var infoMap = processCyrano(msg);
//if (infoMap["Com"] === "")
if (infoMap != null) {
if (infoMap["Com"] === "INFO") {
if (photoViewOn) {
photoViewOn = false;
bigNamesView();
}
console.log("Inside Infomap");
console.log(`Left Fencer: ${infoMap["LeftName"]}`);
console.log(`Right Fencer: ${infoMap["RightName"]}`);
HTMLupdate(infoMap);
}
}
}
catch (error) {
console.log(`Error ${error}`);
}
},
error: (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
},
listen: () => {
const address = server.address();
console.log(`server listening ${address.address}:${address.port}`);
}
});
function photoView() {
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'photos.html'),
protocol: 'file:',
slashes:true,
}));
}
function bigNamesView() {
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'bigNames.html'),
protocol: 'file:',
slashes:true,
}));
}
function processCyrano(msg) {
try {
let stripMsg = msg.toString().split("%");
let info = {};
let compInfo = stripMsg[0].split("|");
console.log(compInfo);
if(compInfo[2] === "INFO" || compInfo[2] === "DISP") {
let firstFencerInfo = stripMsg[1].split("|")
let secondFencerInfo = stripMsg[2].split("|")
info.Protocol = compInfo[1];
info.Com = compInfo[2]
info.Piste = compInfo[3]
info.Compe = compInfo[4];
info.Phase = compInfo[5];
info.PoulTab = compInfo[6];
info.Match = compInfo[7];
info.Round = compInfo[8];
info.RightId = firstFencerInfo[1];
info.RightName = firstFencerInfo[2];
info.RightNat = firstFencerInfo[3];
info.Rscore = firstFencerInfo[4];
info.Rstatus = firstFencerInfo[5];
info.RYcard = firstFencerInfo[6];
info.Rrcard = firstFencerInfo[7];
info.Rlight = firstFencerInfo[8];
info.RWlight = firstFencerInfo[9];
info.LeftId = secondFencerInfo[1];
info.LeftName = secondFencerInfo[2];
info.LeftNat = secondFencerInfo[3];
info.Lscore = secondFencerInfo[4];
info.Lstatus = secondFencerInfo[5];
info.LYcard = secondFencerInfo[6];
info.Lrcard = secondFencerInfo[7];
info.Llight = secondFencerInfo[8];
info.LWlight = secondFencerInfo[9];
lastMatch = info;
return info;
}
else if (compInfo[2] === "PHOTO-NEXT") {
console.log("Photo-Next received");
photoViewOn = true;
photoView();
}
else if (compInfo[2] === "PHOTO-SCORE") {
console.log("Photo-score received");
photoViewOn = true;
photoView();
}
else if (compInfo[2] === "PHOTO-STOP") {
console.log("Photo-Stop received");
return lastMatch;
}
return null;
}
catch (error) {
//Avoid empty messages of the protocol
console.log(`Error ${error}`);
return null;
}
}
Basically my attempt is, if I get a "Photo-Score" message, call photoView() (this works fine), and if "Photo-Stop" is received, call bigNamesView() and start sending information agoin using HTMLUpdate(msg), but it doesn't work for me. Any clue why this is happening?
Note that I remove some irrelevant code. Thanks.
hi my friend you problem is that lastMatch = info only happens inside
if(compInfo[2] === "INFO" || compInfo[2] === "DISP") {
So Only When "Photo-Stop" is received then you return lastMatch
.
inside the code your logic says only when we receive INFO call bigNamesView()
but you want only when we receive PHOTO-STOP call bigNamesView()
.
Also about the loadurl method you call mainWindow.webContents.send('update', msg); in HTMLupdate immediately you should wait for event did-finish-load then call send update msg
win.webContents.on('did-finish-load', () => {
HTMLupdate(infoMap);
})
In your server you have the condition
if (photoViewOn) {bigNamesView()}
but in function processCyrano your condition for 'PHOTO-STOP' doesn't set photoViewOn to true.
else if (compInfo[2] === "PHOTO-STOP") {
console.log("Photo-Stop received");
return lastMatch;
}
Change to
else if (compInfo[2] === "PHOTO-STOP") {
console.log("Photo-Stop received");
photoViewOn = true;
return lastMatch;
}
So this is weird, when i try to connect to websocket (this is only a Microsoft edge issue) it makes so on every second page refresh webworker will not accept messages onMessage wont trigger at all:
consider the following:
main.js
var worker = new Worker("webworker.js");
worker.postMessage({ type: 'INIT_SOCKET' });
worker.addEventListener('message', (event) => {
let data = event.data;
if (typeof data === 'string') {
data = JSON.parse(data);
}
if (data.type === 'SOCKET_INITIALIZED') {
console.log('inititalized');
}
});
webworker.js
var io = require('socket.io-client');
var socket;
onmessage = function(event) {
var data = event.data;
console.log('got a event');
if (typeof data === 'string') {
data = JSON.parse(data);
}
switch (data.type) {
case 'INIT_SOCKET':
try {
socket = io('xxxx', { transports: [ 'websocket' ], secure: true }); // this line causes the error
socket.on('connect', function () {
postMessage({
type: Consts.SOCKET_INITIALIZED
});
});
} catch(e) {
console.log('some error ', e);
}
break;
};
};
require does not appear to be defined at Worker context. Use importScripts() to import external scripts into DedicatedWorkerGlobalScope. For example
importScripts("socket.io.js");
Could not determine how to stop io() call from polling and getting error, probably due to 404 error
socket.io.js:7370 WebSocket connection to
'ws://echo.websocket.org/socket.io/?EIO=3&transport=websocket' failed:
Error during WebSocket handshake: Unexpected response code: 404
probably due to being unfamiliar, here, as to how io() is implemented. Though was able to define Socket object within Worker scope.
Approach using WebSocket returns expected result
const worker = new Worker("webworker.js");
worker.addEventListener('message', (event) => {
let data = event.data;
if (typeof data === 'string') {
console.log(data)
}
if (data.type === 'SOCKET_INITIALIZED') {
console.log('inititalized');
}
});
worker.postMessage({
type: 'INIT_SOCKET'
});
importScripts("socket.io.js");
let sock = io();
console.log(sock); // to demonstrate `Socket` is defined
sock.close(); // closing socket here to prevent `404` polling errors
self.socket = void 0;
self.onmessage = function(event) {
var data = event.data;
console.log('got a event');
if (typeof data === 'string') {
data = JSON.parse(data);
}
switch (data.type) {
case 'INIT_SOCKET':
if (!self.socket) {
try {
self.socket = new WebSocket("ws://echo.websocket.org/");
self.socket.onopen = function(e) {
socket.send("WebSocket rocks");
console.log("self.socket event.type:", e.type);
self.postMessage({
type: 'SOCKET_INITIALIZED'
});
};
self.socket.onmessage = function(e) {
console.log(e.data);
self.socket.close()
};
self.socket.onerror = function(e) {
console.log("self.socket error", e);
};
self.socket.onclose = function(e) {
console.log("self.socket event.type", e.type);
};
} catch (e) {
console.log('some error ', e);
}
break;
};
}
};
plnkr http://plnkr.co/edit/zVnLE6qG7Kf4yVSb0aJt?p=preview
When my page loads, I try to send a message to the server to initiate a connection, but it's not working. This script block is near the top of my file:
var connection = new WrapperWS();
connection.ident();
// var autoIdent = window.addEventListener('load', connection.ident(), false);
Most of the time, I see the error in the title:
Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state
So I tried to catch the exception, as you can see below, but now it seems InvalidStateError is not defined and that produces a ReferenceError.
Here's the wrapper object for my websocket connection:
// Define WrapperWS
function WrapperWS() {
if ("WebSocket" in window) {
var ws = new WebSocket("ws://server:8000/");
var self = this;
ws.onopen = function () {
console.log("Opening a connection...");
window.identified = false;
};
ws.onclose = function (evt) {
console.log("I'm sorry. Bye!");
};
ws.onmessage = function (evt) {
// handle messages here
};
ws.onerror = function (evt) {
console.log("ERR: " + evt.data);
};
this.write = function () {
if (!window.identified) {
connection.ident();
console.debug("Wasn't identified earlier. It is now.");
}
ws.send(theText.value);
};
this.ident = function () {
var session = "Test";
try {
ws.send(session);
} catch (error) {
if (error instanceof InvalidStateError) {
// possibly still 'CONNECTING'
if (ws.readyState !== 1) {
var waitSend = setInterval(ws.send(session), 1000);
}
}
}
window.identified = true;
theText.value = "Hello!";
say.click();
theText.disabled = false;
};
};
}
I am testing using Chromium on Ubuntu.
You could send messages via a proxy function that waits for the readyState to be 1.
this.send = function (message, callback) {
this.waitForConnection(function () {
ws.send(message);
if (typeof callback !== 'undefined') {
callback();
}
}, 1000);
};
this.waitForConnection = function (callback, interval) {
if (ws.readyState === 1) {
callback();
} else {
var that = this;
// optional: implement backoff for interval here
setTimeout(function () {
that.waitForConnection(callback, interval);
}, interval);
}
};
Then use this.send in place of ws.send, and put the code that should be run afterwards in a callback:
this.ident = function () {
var session = "Test";
this.send(session, function () {
window.identified = true;
theText.value = "Hello!";
say.click();
theText.disabled = false;
});
};
For something more streamlined you could look into promises.
This error is raised because you are sending your message before the WebSocket connection is established.
You can solve it by doing this simply:
conn.onopen = () => conn.send("Message");
This onopen function waits for your WebSocket connection to establish before sending your message.
if you use one websocket client object and connect from random app places then object can be in connecting mode (concurent access).
if you want to exchange through only one websoket then
create class with promise and keep it in property
class Ws {
get newClientPromise() {
return new Promise((resolve, reject) => {
let wsClient = new WebSocket("ws://demos.kaazing.com/echo");
console.log(wsClient)
wsClient.onopen = () => {
console.log("connected");
resolve(wsClient);
};
wsClient.onerror = error => reject(error);
})
}
get clientPromise() {
if (!this.promise) {
this.promise = this.newClientPromise
}
return this.promise;
}
}
create singleton
window.wsSingleton = new Ws()
use clientPromise property in any place of app
window.wsSingleton.clientPromise
.then( wsClient =>{wsClient.send('data'); console.log('sended')})
.catch( error => alert(error) )
http://jsfiddle.net/adqu7q58/11/
Method 1: Check connection
You can resolve a promise when socket is connected:
async function send(data) {
await checkConnection();
ws.send(data);
}
Implementation
This trick is implemented using an array of resolvers.
let ws = new WebSocket(url);
let connection_resolvers = [];
let checkConnection = () => {
return new Promise((resolve, reject) => {
if (ws.readyState === WebSocket.OPEN) {
resolve();
}
else {
connection_resolvers.push({resolve, reject});
}
});
}
ws.addEventListener('open', () => {
connection_resolvers.forEach(r => r.resolve())
});
Method 2: Wait for connection
You can resolve a promise when socket is not connected:
const MAX_RETRIES = 4;
async function send(data, retries = 0) {
try {
ws.send(data);
}
catch (error) {
if (retries < MAX_RETRIES error.name === "InvalidStateError") {
await waitForConnection();
send(data, retries + 1);
}
else {
throw error;
}
}
}
Implementation
This trick is implemented using an array of resolvers.
let ws = new WebSocket(url);
let connection_resolvers = [];
let waitForConnection = () => {
return new Promise((resolve, reject) => {
connection_resolvers.push({resolve, reject});
});
}
ws.addEventListener('open', () => {
connection_resolvers.forEach(r => r.resolve())
});
My opinion is that the second method has a little bit good performance!
It is possible to use functions and readyState with setTimeout.
function openSocket()
{
webSocket = new WebSocket("");
}
function sendData()
{
if(webSocket.readyState)
{
webSocket.send(JSON.stringify(
{
"event" : "",
"message" : ""
}));
}
else
{
setTimeout(sendData, 1000);
}
}
function eventHandler()
{
webSocket.onmessage = function(e)
{
data = JSON.parse(e.data);
event = data.event;
switch (event)
{...}
}
}
openSocket();
sendData();
enentHandler();