How to handle stream down error in chat application - javascript

I am using METEOR DDPSubscription for creating the messaging stream, When I am sending messages continuously and then I see the following error,
subscribe(eventName, args) {
return new Promise((resolve, reject) => {
if (this.subscriptions[eventName]) {
return resolve();
}
const subscription = Tracker.nonreactive(() => this.ddpConnection.subscribe(
this.subscriptionName,
eventName,
{ useCollection: this.useCollection, args },
{
onStop: () => reject(this.unsubscribe(eventName)),
onReady: resolve
}
));
this.subscriptions[eventName] = { subscription };
})
}
From the above code, I am getting error at the following line,
onStop: () => reject(this.unsubscribe(eventName)),
So I decided to add timeout at regular intervals as follows,
useEffect(() => {
if (!subscriptionQuery.data) {
return;
}
UserAction.addStream(rid);
return (): void => {
setTimeout(() => {
UserAction.cancel(rid);
}, 2000);
};
}, [rid, subscriptionQuery.data]);
Can anyone suggest am I doing in the right way. Thanks.

Related

Event Listener running only once with Promise

I created a Promise here to connect to the storage and I also need to listen for changes.
With window.onstorage inside the promise it only listens once, even though it dispatches two events.
I can only listen to the two events dispatched if I put it directly in useEffect and without Promise.
Is it possible to listen to an event inside a Promise?
If so how should I do it and what is wrong?
CODE
const connect = useCallback(
() =>
new Promise<IConnectFunction>((resolve, reject) => {
Promise.all([infuraStorageData, metamaskStorageData])
.then(response => {
window.onstorage = e => {
resolve({
infuraData: response[0],
metamaskData: response[1],
});
};
})
.catch((error: DOMException) => reject(error));
}),
[infuraStorageData, metamaskStorageData]
);
useEffect(() => {
useStorageDBHook
.connect()
.then(e => {
console.log(e);
// window.onstorage = e => {
// console.log(e);
// };
})
.catch(e => {
console.log(e);
});
}, [useStorageDBHook]);
A Promise by design can only resolve once. Further call to resolve(value) has no effect.
If you want to receive (get notified) multiple events, you need some kind of stream interface (aka an observable, or subscribable), which will continuously feed you new data whenever available (in your case, whenever onstorage event fires).
A hand-rolled subscribable interface can be implemented like this:
class Subscribable {
constructor(source) {
this.subscribers = [];
source(this.notify.bind(this));
}
subscribe(sink) {
this.subscribers = this.subscribers.concat(push);
const unsubscribe = () => {
this.subscribers = this.subscribers.filter((_sink) => _sink !== sink);
};
return unsubscribe;
}
notify(newValue, error) {
this.subscribers.forEach((sink) => sink(newValue, error));
}
}
The usage is very close to Promise, you replace (resolve, reject) with a single notify callback, you cannot chain it with a .catch though, which is admittedly a bit drawback.
const connect = useCallback(
() =>
new Subscribable((notify) => {
// I took the liberty to change your code a bit
// cus it looks confusing, I guess your real intention is like:
window.onstorage = (e) => { notify(e) };
Promise.all([infuraStorageData, metamaskStorageData])
.then((response) => {
notify({
infuraData: response[0],
metamaskData: response[1],
});
})
.catch((error) => notify(null, error));
}),
[infuraStorageData, metamaskStorageData]
);
useEffect(() => {
const unsubscribe = connect().subscribe((newValue, error) => {
if (error) {
// handle error
} else {
console.log(newValue);
}
});
return unsubscribe;
}, [connect]);

How to handle specific errors code in a geolocation promise?

I have a function that fetches the user's location. It was working this way:
const fetchGeoLocation: SearchService["fetchGeoLocation"] = async () => {
const geo = navigator.geolocation;
if (!geo) throw new Error("error.geolocation-unavailable");
const handleError = (err: any) => {
if (err.code === 1) throw new Error("error.geolocation-permission_denied");
if (err.code === 2) throw new Error("error.geolocation-unavailable");
if (err.code === 3) throw new Error("error.geolocation-timeout");
};
const handleSuccess = (position) => {
return { location: [position.coords.longitude, position.coords.latitude] };
};
geo.getCurrentPosition(handleSuccess, handleError, { maximumAge: 10000 });
};
const onUpdateLocation = async () => {
onLoad();
fetchGeoLocation()
.then((res) => onSave(res.data))
.catch(({ message }) => onError(message));
};
Because it was not a promise, the onSave() function triggered before fetchGeolocation ended. So I have to promisify it. Writing this would work:
function fetchGeolocation () {
return new Promise((resolve, reject) =>{
navigator.geolocation.getCurrentPosition(resolve, reject);
});
};
fetchGeolocation()
.then(res => onSave(res)
.catch(err => onError(err.message);
But I would need to handle all the error codes in the catch callback. I want to handle everything inside the fetchGeolocation function. How to do it?
Thanks!
If I followed your idea properly, then the next snippet might help you out:
const fetchGeoLocation: SearchService["fetchGeoLocation"] = async () => {
return new Promise((resolve, reject) => {
const { geolocation } = navigator;
if (!geolocation) reject("error.geolocation-unavailable");
const handleError = ({ code }) => {
if (code === 1) reject("error.geolocation-permission_denied");
if (code === 2) reject("error.geolocation-unavailable");
if (code === 3) reject("error.geolocation-timeout");
};
const handleSuccess = (position) => {
resolve({ location: [position.coords.longitude, position.coords.latitude] });
};
geo.getCurrentPosition(handleSuccess, handleError, { maximumAge: 10000 });
});
};
Notice instead of throw'ing, it's reject'ing the promise with the error string.

Mock stream finish on jest

I have a function that downloads a file using got and uses fs.createWritableStream to write file on disk. The code is working smooth but the unit test are being a pain:
download(twilioPath, destFile) {
return new Promise(function(resolve, reject) {
const uri = `${TWILIO_BASE_URL}${twilioPath}`.replace('json', 'mp3')
let file = fs.createWriteStream(`/tmp/${destFile}`)
console.log(got)
let str = got.stream(uri)
console.log(uri)
str.on('error', function(err) {
console.log('Error dl', err)
reject(err)
})
str.pipe(file)
file.on('finish', function() {
console.log('banana')
let cb = function() {
console.log('Download completed')
resolve(file)
}
file.close(cb)
})
})
My resolve or reject is not being called and I don't know how to fix that:
const Recording = require('./Recording')
const Readable = require('stream')
var mockedStream = new Readable();
var mockedWrite = new Readable.Writable()
jest.mock('fs', () => ({
createWriteStream: jest.fn((file_name) => {
return mockedWrite;
})
}));
jest.mock('got', () => {
return {
stream: () => {
return mockedStream
}
}
})
describe('Recording', () => {
test('should download a file from twilio', async () => {
...
mockedStream.emit('error')
mockedWrite.emit('finish')
console.log(result)
....
})
})
I've tried to force emit events but no lucky.

Trying to convert a script that involves webrtc into async/await failing

I am following this tutorial to make webrtc work. I would like to return the streams I get in resolve() to the component I call this getDrone() from. I created a returnStreamArray() function as a child promise which I tried to add as a then() to the stream to add it to the array, however I am stuck. I would appreciate any directions.
export default function getDrone() {
return new Promise((resolve, reject) => {
const drone = new Scaledrone('fBAkzbVAOmA2wbU0');
const roomName = 'observable-room';
const configuration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
}
]
};
let room;
let pc;
const streamArr = [];
...
drone.on('open', error => {
if (error) {
console.error(error);
}
room = drone.subscribe(roomName);
room.on('open', error => {
if (error) {
onError(error);
}
});
..
..
pc.ontrack = event => {
const stream = event.streams[0];
streamArr.push(stream);
};
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true
})
.then(stream => {
streamArr.push(stream);
stream.getTracks().forEach(track => pc.addTrack(track, stream));
}, onError)
.then(returnStreamArray => {
console.log(stream);
});
..
..
});
}
function returnStreamArray() {
return Promise.resolve({
streamArray: streamArr
});
}

Nodejs - Retry same function on error callback in production

I have a javascript function with setTimeOut and I am retrying to call same function, if any error from API call.I am calling same function in catch block.Is my node server is going crash and resources will be blocked or it will keep calling getData() function
let retry = ()=> {
setTimeout(() => {
getData()
retry()
}, 3000);
}
let getData = () =>{
Someapi.getData().then((token) => {
console.log(`Data after 3 seconds->${token}`)
}).catch((err) => {
getData()
})
}
I do not know if this work.
let retry = () => {
setTimeout(() => {
getData();
retry();
}, 3000);
};
while (true) {
let getData = () => {
Someapi.getData()
.then(token => {
console.log(`Data after 3 seconds->${token}`);
return false;
})
.catch(err => {
return true;
});
};
}
I use this retry code in my project, it works well in production:
const pause = (duration) => {
return new Promise(resolve => setTimeout(resolve, duration));
};
const retry = (retryTimes, func, delay) => {
return func().catch(
(err) => {
if(retryTimes > 0) {
return pause(delay).then(
() => retry(retryTimes - 1, func, delay * 2)
);
} else {
return Promise.reject(err);
}
}
);
};

Categories

Resources