Updating client image after interval when server sends new image - javascript

In my ASP.NET MVC application, server is broadcasting image URL to all clients after 5 seconds
I am using SignalR to send image URL from server which invokes Javascript function.
In the Javascript function I am using following code to auto-refresh <img> element to update the src attribute but though it is updating my src I am not able to see on browser.
// Defining a connection to the server hub.
var myHub = $.connection.myHub;
// Setting logging to true so that we can see whats happening in the browser console log. [OPTIONAL]
$.connection.hub.logging = true;
// Start the hub
$.connection.hub.start();
// This is the client method which is being called inside the MyHub constructor method every 3 seconds
myHub.client.SendServerImageUrl = function (serverImageUrl) {
var N = 5;
// Function that refreshes image
function refresh(imageId, imageSrc) {
var image = document.getElementById(imageId);
var timestamp = new Date().getTime();
image.src = imageSrc + '?' + timestamp;
};
// Refresh image every N seconds
setTimeout(function () {
refresh('SampleImage', serverImageUrl);
}, N * 1000);
My HTML file contains only following code:
<img id="SampleImage">
Backend C# code
public class MyHub : Hub
{
public MyHub()
{
// Create a Long running task to do an infinite loop which will keep sending the server time
// to the clients every 5 seconds.
var taskTimer = Task.Factory.StartNew(async () =>
{
while(true)
{
Random rnd = new Random();
int number = rnd.Next(1,10);
string str = "~/Images/Sample";
Clients.All.SendServerImageUrl(str+Convert.ToString(number)+".jpg");
//Delaying by 5 seconds.
await Task.Delay(5000);
}
}, TaskCreationOptions.LongRunning
);
}
}

Try changing the casing in your callbacks:
myHub.client.sendServerImageUrl = ...;
Clients.All.sendServerImageUrl(...);
There should be no need for polling so get rid of setTimeout() on the client.
Keep an eye on the Console and make sure HTTP requests are working.

Related

How can I receive data on client side before calling .end() on the server side for a gRPC stream

I am currently trying to setup a server stream with the gRPC Node.js API. For that I want to achieve that when I write on server side to the stream that the client immediately receives the data event.
At the moment I don't receive anything on client side if I only call write on server side. However as soon as I call the end function on the server the client receives all data events.
To test this I used an endless while loop for writing messages on server side. Then the client does not receive messages (data events). If instead I use a for loop and call end afterwards the client receives all the messages (data events) when end is called.
My .proto file:
syntax = "proto3";
message ControlMessage {
enum Control {
Undefined = 0;
Start = 1;
Stop = 2;
}
Control control = 1;
}
message ImageMessage {
enum ImageType {
Raw = 0;
Mono8 = 1;
RGB8 = 2;
}
ImageType type = 1;
int32 width = 2;
int32 height = 3;
bytes image = 4;
}
service StartImageTransmission {
rpc Start(ControlMessage) returns (stream ImageMessage);
}
On the server side I implement the start function and try to endlessly write messages to the call:
function doStart(call) {
var imgMsg = {type: "Mono8", width: 600, height: 600, image: new ArrayBuffer(600*600)};
//for(var i = 0; i < 10; i++) {
while(true) {
call.write(imgMsg);
console.log("Message sent");
}
call.end();
}
I register the function as service in the server:
var server = new grpc.Server();
server.addService(protoDescriptor.StartImageTransmission.service, {Start: doStart});
On client side I generate an appropriate call and register the data and end event:
var call = client.Start({control: 0});
call.on('data', (imgMessage) => {
console.log('received image message');
});
call.read();
call.on('end', () => {console.log('end');});
I also tried to write the server side in python. In this case the node client instantly receives messages and not only after stream was ended on server side. So I guess this should be also possible for the server written with the Node API.
It seems that the problem was that the endless while loop is blocking all background tasks in node. A possible solution is to use setTimeout to create the loop. The following code worked for me:
First in the gRPC call store the call object in an array:
function doStart(call) {
calls.push(call);
}
For sending to all clients I use a setTimeout:
function sendToAllClients() {
calls.forEach((call) => {
call.write(imgMsg);
});
setTimeout(sendToAllClients, 10);
}
setTimeout(sendToAllClients, 10);
Helpful stackoverflow atricle: Why does a while loop block the event loop?
I was able to use uncork which comes from Node.js's Writable.
Here is an example. Pseudocode, but pulled from across a working implementation:
import * as grpc from '#grpc/grpc-js';
import * as proto from './src/proto/generated/organizations'; // via protoc w/ ts-proto
const OrganizationsGrpcServer: proto.OrganizationsServer = {
async getMany(call: ServerWritableStream<proto.Empty, proto.OrganizationCollection>) {
call.write(proto.OrganizationCollection.fromJSON({ value: [{}] }));
call.uncork();
// do some blocking stuff
call.write(proto.OrganizationCollection.fromJSON({ value: [{}] }));
call.uncork();
// call.end(), or client.close() below, at some point?
},
ping(call, callback) {
callback(null);
}
};
const client = new proto.OrganizationsClient('127.0.0.1:5000', grpc.credentials.createInsecure());
const stream = client.getMany(null);
stream.on('data', data => {
// this cb should run twice
});
export default OrganizationsGrpcServer;
//.proto
service Organizations {
rpc GetMany (google.protobuf.Empty) returns (stream OrganizationCollection) {}
}
message OrganizationCollection {
repeated Organization value = 1;
}
Versions:
#grpc/grpc-js 1.4.4
#grpc/proto-loader 0.6.7
ts-proto 1.92.1
npm 8.1.4
node 17

JavaScript immediately closes after opening it

I am working on a Raspberry3 model B.
I've written a code that I want to launch on reboot.
If I launch the script in the bash it works perfectly. But when I try to start the script via doubleclick (execute in terminal) it opens the terminal for a very short duration and closes it immediatly after.
Same thing happens if I want to start this script at reboot.
Can anyone tell me what I'm doing wrong?
var blynkLib = require('blynk-
library');
var sensorLib = require('node-dht-
sensor');
var AUTH = 'xxx';
// Setup Blynk
var blynk = new
blynkLib.Blynk(AUTH);
// Setup sensor, exit if failed
var sensorType = 22; // 11 for DHT11, 22 for DHT22 and AM2302
var sensorPin = 2; // The GPIO pin number for sensor signal
if
(!sensorLib.initialize(sensorType,
sensorPin)) {
console.warn('Failed to
initialize sensor');
process.exit(1);
}
// Automatically update sensor value every 2 seconds
setInterval(function() {
var readout = sensorLib.read();
blynk.virtualWrite(3,
readout.temperature.toFixed(1));
blynk.virtualWrite(4,
readout.humidity.toFixed(1));
console.log('Temperature:',
readout.temperature.toFixed(1) +
'C');
console.log('Humidity: ',
readout.humidity.toFixed(1) +
'%');
}, 2000);
Assuming your question is How can i pause my program :
using python : you should import os then os.system("pause"); :
import os;
os.system("pause");
Using nodejs : use one of the module from npm :
https://www.npmjs.com/package/system-sleep
https://www.npmjs.com/package/pause

Scheduling Web Audio Api playback, multiple plays issue

I am trying to schedule the beep sound to play 3x one second apart. However, the sound is only playing once. Any thoughts on why this might be? (It's included within a larger javascript funciton that declares context etc. . .)
var beepBuffer;
var loadBeep = function() {
var getSound = new XMLHttpRequest(); // Load the Sound with XMLHttpRequest
getSound.open("GET", "/static/music/chime.wav", true); // Path to Audio File
getSound.responseType = "arraybuffer"; // Read as Binary Data
getSound.onload = function() {
context.decodeAudioData(getSound.response, function(buffer){
beepBuffer = buffer; // Decode the Audio Data and Store it in a Variable
});
}
getSound.send(); // Send the Request and Load the File
}
var playBeep = function() {
for (var j = 0;j<3;j++) {
var beeper = context.createBufferSource(); // Declare a New Sound
beeper.buffer = beepBuffer; // Attatch our Audio Data as it's Buffer
beeper.connect(context.destination); // Link the Sound to the Output
console.log(j);
beeper.start(j); // Play the Sound Immediately
}
};
Close - and the other answer's code will work - but it's not the synchronicity, it's that you're not asking context.current time to the start time. Start() doesn't take an offset from "now" - it takes an absolute time. Add context.currentTime to the start param, and you should be good.
Your code assumes that beeper.start(j) is a synchronous method, i.e. it waits for the sound to complete playing. This is not the case, so your loop is probably playing all 3 instances at nearly the same exact time.
One solution is to delay the playing of each instance, by passing a time parameter to the start() method:
var numSecondsInBeep = 3;
for (var j = 0; j < 3; j++) {
var beeper = context.createBufferSource(); // Declare a New Sound
beeper.buffer = beepBuffer; // Attatch our Audio Data as it's Buffer
beeper.connect(context.destination); // Link the Sound to the Output
console.log(j);
beeper.start(context.currentTime + j * numSecondsInBeep);
}
See here for more info on the play() API.

How to detect client disconnection from node.js server

I am new to node.js. How to detect client is disconnected from node.js server .
Here is my code:
var net = require('net');
var http = require('http');
var host = '192.168.1.77';
var port = 12345;//
var server = net.createServer(function (stream) {
stream.setEncoding('utf8');
stream.on('data', function (data) {
var comm = JSON.parse(data);
if (comm.action == "Join_Request" && comm.gameId =="game1") // join request getting from client
{
var reply0 = new Object();
reply0.message = "WaitRoom";
stream.write(JSON.stringify(reply0) + "\0");
}
});
stream.on('disconnect', function() {
});
stream.on('close', function () {
console.log("Close");
});
stream.on('error', function () {
console.log("Error");
});
});
server.listen(port,host);
How to know client side internet disconnection.
The best way to detect "dead sockets" is to send periodic application-level ping/keepalive messages. What that message looks like depends on the protocol you're using for communicating over the socket. Then it's just a matter of using a timer or other means of checking if you've received a "ping response" within a certain period of time after you sent the ping/keepalive message to the client.
On a semi-related note, it looks like you're using JSON messages for communication, but you're assuming a complete JSON string on every data event which is a bad assumption. Try using a delimiter (a newline is pretty common for something like this, and it makes debugging the communication more human-readable) instead.
Here is a simple example of how to achieve this:
var PING_TIMEOUT = 5000, // how long to wait for client to respond
WAIT_TIMEOUT = 5000; // duration of "silence" from client until a ping is sent
var server = net.createServer(function(stream) {
stream.setEncoding('utf8');
var buffer = '',
pingTimeout,
waitTimeout;
function send(obj) {
stream.write(JSON.stringify(obj) + '\n');
}
stream.on('data', function(data) {
// stop our timers if we've gotten any kind of data
// from the client, whether it's a ping response or
// not, we know their connection is still good.
clearTimeout(waitTimeout);
clearTimeout(pingTimeout);
buffer += data;
var idx;
// because `data` can be a chunk of any size, we could
// have multiple messages in our buffer, so we check
// for that here ...
while (~(idx = buffer.indexOf('\n'))) {
try {
var comm = JSON.parse(buffer.substring(0, idx));
// join request getting from client
if (comm.action === "Join_Request" && comm.gameId === "game1") {
send({ message: 'WaitRoom' });
}
} catch (ex) {
// some error occurred, probably from trying to parse invalid JSON
}
// update our buffer
buffer = buffer.substring(idx + 1);
}
// we wait for more data, if we don't see anything in
// WAIT_TIMEOUT milliseconds, we send a ping message
waitTimeout = setTimeout(function() {
send({ message: 'Ping' });
// we sent a ping, now we wait for a ping response
pingTimeout = setTimeout(function() {
// if we've gotten here, we are assuming the
// connection is dead because the client did not
// at least respond to our ping message
stream.destroy(); // or stream.end();
}, PING_TIMEOUT);
}, WAIT_TIMEOUT);
});
// other event handlers and logic ...
});
You could also just have one interval instead of two timers that checks a "last data received" timestamp against the current timestamp and if it exceeds some length of time and we have sent a ping message recently, then you assume the socket/connection is dead. You could also instead send more than one ping message and if after n ping messages are sent and no response is received, close the connection at that point (this is basically what OpenSSH does).
There are many ways to go about it. However you may also think about doing the same on the client side, so that you know the server didn't lose its connection either.

delay of 5 seconds between each request in Node Js

Here is my code:
I have more than 500,000 records in my database and I want to loop and request some information from another server. I've successfully wrote all functions except delays between each request. If I send all request with node.js remote server goes downs or can not answer each request. So I need to create a queue for looping But my code is not working still sending all request very fast.
var http = require('http')
, mysql = require('mysql');
var querystring = require('querystring');
var fs = require('fs');
var url = require('url');
var client = mysql.createClient({
user: 'root',
password: ''
});
client.useDatabase('database');
client.query("SELECT * from datatable",
function(err, results, fields) {
if (err) throw err;
for (var index in results) {
username = results[index].username;
setInterval(function() {
requestinfo(username);
}, 5000 );
}
}
);
client.end();
}
Your problem lies in the for loop since you set all the requests to go off every 5 seconds. Meaning after 5 seconds all the requests will be fired relatively simultaneously. And since it is done with setInterval then it will happen every 5 seconds.
You can solve it in 2 ways.
First choice is to set an interval to create a new request every 5 seconds if the index is a number, so instead of a for loop you do something like:
var index = 0;
setInterval(function(){
requestinfo(results[index].username);
index++;
}, 5000)
The second choice is to set all the requests with an increasing timeout so you modify your current script like so:
var timeout = 0;
for (var index in results) {
username = results[index].username;
setTimeout(function() {
requestinfo(username);
}, timeout );
timeout += 5000;
}
This will set timeouts for 0,5,10,15... etc seconds so every 5 seconds a new request is fired.

Categories