Resubscribe to the websocket channel using setTimeout - javascript

I have written a code in vue.js which creates a websocket connection and subscribe to a channel to get the data of BTC in USD.
But that channel one sends the updated data of size for some prices but I need a way to resubscribe to the channel to get the update prices as well.
Here is the link for bybit api documentation
Here is the code I tried:
function GetData(that) {
var ws_bybit_ita = new WebSocket("wss://stream.bybit.com/realtime");
ws_bybit_ita.onopen = function () {
ws_bybit_ita.send(
JSON.stringify({ op: "subscribe", args: ["orderBook_200.100ms.BTCUSD"] })
)
}
ws_bybit_ita.onmessage = function (msgEvent) {
let response = JSON.parse(msgEvent.data)
const data = response;
if (data.data && data.type == "snapshot") {
console.log(data.data);
} else if (data.type == "delta") {
}
CheckState(that,ws_bybit_ita)
};
function CheckState(that, ws_bybit_ita) {
if (ws_bybit_ita.readyState === 1) {
ws_bybit_ita.send(
JSON.stringify({ op: "unsubscribe", args: ["orderBook_200.100ms.BTCUSD"] })
)
ws_bybit_ita.close();
}
setTimeout(function () {
GetData(that);
}, 500);
};

Related

Broadcasting to all clients with Deno websocket

I want to add notifications to an application I've developed.
Unfortunately, Deno has removed the ws package.(https://deno.land/std#0.110.0/ws/mod.ts)
That's why I'm using the websocket inside the denon itself. Since it doesn't have many functions, I have to add some things myself.
For example, sending all messages to open clients.
What I want to do is when the pdf is created, a (data, message) comes from the socket and update the notifications on the page according to the incoming data.
I keep all open clients in a Map. and when the pdf is created, I return this Map and send it to all sockets (data, message).
However, this works for one time.
server conf...
import {
path,
paths,
ctid,
} from "../deps.ts";
const users = new Map();
const sockets = new Map()
const userArr = [];
export const startNotif = (socket,req) => {
const claims = req.get("claims");
const org = req.get("org");
claims.org = org;
console.log("connected")
users.set(claims.sub, {"username":claims.sub,"socket":socket})
users.forEach((user)=>{
if(userArr.length === 0){
userArr.push(user)
}
else if(userArr.every((w)=> w.username !== user.username) )
userArr.push(user)
})
sockets.set(org, userArr)
function broadcastMessage(message) {
sockets.get(org).map((u)=>{
console.log(u.socket.readyState)
u.socket.send(message)
})
}
if (socket.readyState === 3) {
sockets.delete(uid)
return
}
const init = (msg) => {
socket.send(
JSON.stringify({
status: "creating",
})
);
};
const ondata = async (msg) => {
const upfilepath = path.join(paths.work, `CT_${msg.sid}_report.pdf`);
try {
const s=await Deno.readTextFile(upfilepath);
if(s){
socket.send(
JSON.stringify({
status: "end",
})
);
} else {
socket.send(
JSON.stringify({
status: "creating",
})
);
}
} catch(e) {
if(e instanceof Deno.errors.NotFound)
console.error('file does not exists');
}
};
const end = () => {
try {
const endTime = Date.now()
const msg = "Your PDF has been created"
const id = ctid(12) // random id create
broadcastMessage(
JSON.stringify({
id: id,
date: endTime,
status: "done",
message: msg,
read: 'negative',
action: 'pdf'
})
);
} catch (e) {
console.log(400, "Cannot send.", e);
}
}
socket.onmessage = async (e) => {
const cmd = JSON.parse(e.data);
if(cmd.bid === 'start'){
await init(cmd)
}
if(!cmd.bid && cmd.sid){
await ondata(cmd)
}
if(cmd.bid === 'end'){
await end();
}
}
socket.onerror = (e) => {
console.log(e);
};
}
client conf...
export const webSocketHandler = (request) =>
new Promise((res, rej) => {
let url;
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
url = `http://localhost:8080/api/notifications/ws`.replace('http', 'ws');
} else {
url = `${window.location.origin}/api/notifications/ws`.replace('http', 'ws');
}
const token = JSON.parse(sessionStorage.getItem('token'));
const orgname = localStorage.getItem('orgname');
const protocol = `${token}_org_${orgname}`;
const socket = new WebSocket(url, protocol);
const response = Object.create({});
socket.onopen = function () {
socket.send(
JSON.stringify({
bid: 'start',
})
);
};
socket.onmessage = function (event) {
response.data = JSON.parse(event.data);
if (response.data.status === 'creating') {
socket.send(
JSON.stringify({
sid: request.sid,
})
);
} else if (response.data.status === 'end') {
socket.send(
JSON.stringify({
bid: 'end',
})
);
} else if (response.data.status === 'done') {
try {
res(response);
} catch (err) {
rej(err);
}
}
};
socket.onclose = function (event) {
response.state = event.returnValue;
};
socket.onerror = function (error) {
rej(error);
};
});
onclick function of button I use in component...
const donwloadReport = async (type) => {
const query = `?sid=${sid}&reportType=${type}`;
const fileName = `CT_${sid}_report.${type}`;
try {
type === 'pdf' && setLoading(true);
const response = await getScanReportAction(query);
const request = {
sid,
};
webSocketHandler(request)
.then((data) => {
console.log(data);
dispatch({
type: 'update',
data: {
id: data.data.id,
date: data.data.date,
message: data.data.message,
action: data.data.action,
read: data.data.read,
},
});
})
.catch((err) => {
console.log(err);
});
if (type === 'html') {
downloadText(response.data, fileName);
} else {
const blobUrl = await readStream(response.data);
setLoading(false);
downloadURL(blobUrl, fileName);
}
} catch (err) {
displayMessage(err.message);
}
};
Everything works perfectly the first time. When I press the download button for the pdf, the socket works, then a data is returned and I update the notification count with the context I applied according to this data.
Later I realized that this works in a single tab. When I open a new client in the side tab, my notification count does not increase. For this, I wanted to keep all sockets in Map and return them all and send a message to each socket separately. But in this case, when I press the download button for the second time, no data comes from the socket.
Actually, I think that I should do the socket initialization process on the client in the context. When you do this, it starts the socket 2 times in a meaningless way.
In summary, consider an application with organizations and users belonging to those organizations. If the clients of A, B, C users belonging to X organization are open at the same time and user A pressed a pdf download button, I want A, B, C users to be notified when the pdf is downloaded.
I would be very grateful if someone could show me a way around this issue.
Have you looked at the BroadcastChannel API? Maybe that could solve your issue. See for example:
Deno specific: https://medium.com/deno-the-complete-reference/broadcast-channel-in-deno-f76a0b8893f5
Web/Browser API: https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API

The fetch code in onNewScanResult is executed more than once once a QR code has been scanned, and also updating database. How to stop it from running?

executing the fetch code in onNewScanResult multiplt time and hence updating the database accordingly................
initialization of qr scanner.........
this.html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId,
config,
verbose
); ```Executing scanner when qrcode is scanned```
this.html5QrcodeScanner.render(
this.props.qrCodeSuccessCallback,
this.props.qrCodeErrorCallback
);
}
}
this is main qr code class........
class QrCode extends React.Component {
constructor() {
super();
this.state = {
decodedResults: [],
};
this.onNewScanResult = this.onNewScanResult.bind(this);
}
this is where the executing multiple time is happing.......
onNewScanResult(decodedText, decodedResult) {
`geting data from loacal storage as we saved data earlier in the process about acess level`
const qrRes = decodedText;
const obj = JSON.parse(qrRes);
const token = localStorage.getItem("user");
const userData = JSON.parse(token);
const username = userData[0].userId;
const accesslevel = userData[0].accessLevel;
const result = JSON.parse(qrRes);
const ele = result.ele_name;
const newdata = { ele, username, accesslevel };
const data = {
Element_detail: obj,
accessLevel: newdata.accesslevel,
};
const verifyUser = localStorage.getItem("accessLeveldetails");
const accessdetail = JSON.parse(verifyUser);
```checking is user is verified or not```......
`checking the acess level you can ignore the checking focus on fetch part`....
This particular part is we have to stop executing multiple time so database is only entered with one value
if (accessdetail.accessLevel === data.accessLevel) {
try { ``` this fetch is updating database with multiple entries```
fetch(
data.accessLevel === 20
? `/v0/all_elements_image`
: `/v0/${accessdetail.msg}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(obj),
}
).then((res) => {
console.log(res);
if (!res) {
throw res;
}
return res.json();
});
} catch (error) {
console.log("Error:", error);
}
} else {
alert("WRONG USER");
}
}
}

How to call a function after subscriber complete in angular 8+

Hello everyone I am learning angular and firebase. So the idea is I fetch some ticket from my ticket collection and after fetching add some new property in it but the problem is when I receive half data my ordering function call (the function which is responsible for adding a property). or in simple word we can say I receive data in stream form.
get_ticket() {
console.log('have permission');
this.get_ticket_service
.get_ticket_company(this.user.company)
.subscribe((res) => {
console.log('get response');
this.unStructure_ticket = res.map((e) => {
return {
id: e.payload.doc.id,
item: e.payload.doc.data(),
};
});
this.odering_ticket(this.unStructure_ticket)
});
ordering function
odering_ticket(data) {
const info = [];
console.log('hi');
data.map((ticket) => {
if (ticket.item.seen == false) {
ticket.item.ticketID = ticket.id;
ticket.item.ticketType = 'new';
info.push(ticket.item);
} else if (
ticket.item.new == true &&
ticket.item.currently_handle_sme_ID == undefined
) {
ticket.item.ticketID = ticket.id;
ticket.item.ticketType = 'not assigned';
info.push(ticket.item);
} else if (
ticket.item.currently_handle_sme_ID == localStorage.getItem('uid') &&
!this.has_view_all_ticket_permission
) {
ticket.item.ticketID = ticket.id;
ticket.item.ticketType = 'assigned';
info.push(ticket.item);
} else if (
ticket.item.currently_handle_sme_ID != undefined &&
this.has_view_all_ticket_permission
) {
ticket.item.ticketID = ticket.id;
ticket.item.ticketType = 'assigned';
info.push(ticket.item);
}
});
console.log('end map');
return info;
}
service.ts
get_ticket_company(company) {
return this.firebase_store
.collection('Ticket', (ref) => ref.where('company', '==', company))
.snapshotChanges();
}
output
have permission ,
get response ,
hi ,
end map ,
get response ,
hi ,
end map,
I want to call my ordering function one's after I receive all data
You must try to use the last RxJs operator which will make your pipeline wait until the last emitted value.
this.get_ticket_service
.get_ticket_company(this.user.company).pipe(
tap((poRes) => {
console.log('get response');
if (this.unStructure_ticket === undefined) {
// Initialize your data structure.
this.unStructure_ticket = res.map((e) => {
return {
id: e.payload.doc.id,
item: e.payload.doc.data(),
};
});
} else {
// Add or concate the data received
// this.unStructure_ticket.push()//;
}
}),
last(), // Wait for the last emitted value.
tap((poRes) => {
this.odering_ticket(this.unStructure_ticket);
}),
).subscribe();
Example of how this should work, but not tested code.

Can you pass error messages from Service Workers to DOM

I've been trying to work on this for a while. I'm working with google drive api -> and I'm trying to try to get the main script to re-run the request of the accessToken is incorrect and causes an error.
Can that be sent to the main script somehow?
Adding some code to show I've actually worked on this lol - left out some bc it's alot of other unrelated stuff.
I am using IndexedDB to pass info between SW and main Script
//////////////////////////////////////////////////////////////
//////////////// Check Database onload ///////////////////////
//////////////////////////////////////////////////////////////
window.addEventListener("load", checkUpload(), false);
function checkUpload() {
if (supportCheck()) {
let openRequest = indexedDB.open("GoogleDrive", 1);
openRequest.onsuccess = (e) => {
var db = e.target.result;
var objectStore = db
.transaction(["backups"], "readwrite")
.objectStore("backups");
var request = objectStore.get("1");
request.onerror = function () {
// Handle errors!
};
request.onsuccess = function (event) {
var data = event.target.result;
if (googleSignin.isAuthorizedForGDrive()) {
// Call SW Function
}
else {
//Google Sign in Error
}
let accessToken = gapi.auth.getToken().access_token;
data.access = accessToken;
// Put this updated object back into the database.
var requestUpdate = objectStore.put(data);
requestUpdate.onerror = function (event) {
// Do something with the error
};
requestUpdate.onsuccess = function (event) {
// Success - the data is updated!
// Call SW Function
};
}
}
}
}
}
//////////////////////////////////////////////////////////////
//////////////// Initialize Database Function ///////////////
//////////////////////////////////////////////////////////////
uploadBtn.addEventListener("click", handleUploadClick, false);
save.addEventListener("click", handleUploadClick, false);
//Adds/Create Data that is stored in IndexedDB so that the Service Worker can
access and use it
//ServiceWorker Call Function
function initSW() {
console.log("Script: Called InitSW()");
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("serviceWorker.js")
.then((registration) => navigator.serviceWorker.ready)
.then((registration) => {
registration.sync.register("sendFile-sync").then(() => {
//Do Function using sync
try {
console.log("Script : Sync Registered");
} catch {
console.log("Script : Sync Not Registered");
}
});
});
}
}
SW
self.addEventListener("sync", (e) => {
if (e.tag === "sendFile-sync") {
console.log("SW Sync : Sync Found!");
e.waitUntil(fetchFile());
} else {
console.log("SW Sync : No Sync Found");
}
});
//Function Called above when sync is fired
function fetchFile() {
let openRequest = indexedDB.open("GoogleDrive", 1);
openRequest.onerror = function () {
};
openRequest.onsuccess = function () {
let db = openRequest.result;
let transaction = db.transaction(["backups"], 'readwrite');
let backups = transaction.objectStore("backups");
let request = backups.get("1");
request.onsuccess = function (event) {
let date = Date();
let accessToken = request.result.access;
console.log("SW Sync: Access Token - " + accessToken);
let BlobContent = request.result.text;
let file = BlobContent;
let metadata = {
name: "Backup " + date, // Filename
mimeType: "application/pdf", // mimeType at Google Drive
parents: ["root"], // Root Folder ID for testing
};
let form = new FormData();
form.append(
"metadata",
new Blob([JSON.stringify(metadata)], { type: "application/json" })
);
form.append("file", file);
fetch(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id",
{
method: "POST",
headers: new Headers({ Authorization: "Bearer " + accessToken }),
body: form,
}
)
.then((res) => {
return res.json();
})
.then(function (val) {
console.log(val.error.message);
<!-- message is "invalid credentials --> in our scenario
}
})
}
request.onerror = function () {
console.log("SW Sync : Getting IndexedDB values error");
};
};
}
Sure, the ServiceWorker's clients are exposed in its self.clients property, from where you can find the correct Client with which you can communicate thanks to its postMessage() method.
How to find the correct client will depend on the situation, for instance in the install or activate events there should be only one client, so you should be able to reach it by doing
const clients = await self.clients.matchAll();
const client = clients[0];
client.postMessage("something bad happenned...");
In a fetch event, the clientId is exposed on the event instance, so you can do
const client = await self.clients.get(evt.clientId);
client.postMessage("something bad happenned...");
I must admit I don't know well the BackgroundSync API, so I'm not sure if in this sync event your page would be the only one client, however, you can certainly make your page open a private communication channel with the SW even before, which by the way, sounds like a better mean of passing your API's credentials than through IDB:
const channel = new MessageChannel();
channel.port1.onmessage = SWTalksToMe; // handle messages from SW
navigator.serviceWorker
.register("serviceWorker.js")
.then((registration) => navigator.serviceWorker.ready)
.then((registration) => {
registration.postMessage("", [channel.port2]));
return registration.sync.register("sendFile-sync")
})
//...
And in your ServiceWorker
self.addEventListener("message", evt => {
if(evt.ports) {
client_port = evt.ports[0];
}
});
Finally, if you wanted to communicate with all the clients, you could use a BroadcastChannel.

TypeError: Cannot read property 'charCodeAt' of undefined - Button sometimes does not work

I'm updating a Facebook ChatBot to DialogFlow Version 2. I have a problem with buttons, they don't work the first time, but if the user sends a text message, and then try again, the buttons start working. I'm working whit Heroku and Node.js, these are the results of heroku log
This is my function sendToDialogFlow
async function sendToDialogFlow(sender, textString, params) {
try {
const sessionPath = sessionClient.sessionPath(
config.GOOGLE_PROJECT_ID,
sessionIds.get(sender)
);
const request = {
session: sessionPath,
queryInput: {
text: {
text: textString,
languageCode: config.DF_LANGUAGE_CODE,
},
},
queryParams: {
payload: {
data: params
}
}
};
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
handleDialogFlowResponse(sender, result);
} catch (e) {
console.log('error');
console.log(e);
}
}
And here it is handleDialogFlowResponse function
function handleDialogFlowResponse(sender, response) {
let responseText = response.fulfillmentMessages.fulfillmentText;
let messages = response.fulfillmentMessages;
let action = response.action;
let contexts = response.outputContexts;
let parameters = response.parameters;
var delay = 4000;
if (isDefined(action)) {
sendTypingOn(sender);
setTimeout(function(){
sendTypingOff(sender);
handleDialogFlowAction(sender, action, messages, contexts, parameters);
},delay);
} else if (isDefined(messages) && (messages.length == 1 && messages[0].type != 0 || messages.length > 1) ) {
sendTypingOn(sender);
setTimeout(function(){
sendTypingOff(sender);
handleMessages(messages, sender);
},delay);
} else if (responseText == '' && !isDefined(action)) {
} else if (isDefined(responseText)) {
sendTypingOn(sender);
setTimeout(function(){
sendTypingOff(sender);
sendTextMessage(sender, responseText);
},delay);
}
}
Thank you

Categories

Resources