Posting JSON request and reading EventStreams in Angular11 - javascript

Tried following the article below to read eventstreams. Instead of using formData like it is done in the article, I'm using Json to post. It works smoothly with a 200 response. Even tells that some kb of data was sent over the wire, but the eventstream tab shows nothing. The same curl works on my terminal.
https://medium.com/swlh/how-do-server-sent-events-sse-or-eventsource-work-in-angular-e9e27b6a3295

As shown in the article
return Observable.create((observer) => {
const eventSource = this.sseService.getEventSourceWithPost(url, data);
// Launch query
eventSource.stream();
// on answer from message listener
eventSource.onmessage = (event) => {
this.zone.run(() => {
observer.next(event.progress);
});
};
eventSource.onerror = (error) => {
this.zone.run(() => {
observer.error(error);
});
};
});
Changing this part to
return Observable.create((observer) => {
const eventSource = this.sseService.getEventSourceWithPost(url, data);
// Launch query
eventSource.stream();
// on answer from message listener
eventSource.addEventListener('EVENT_NAME_FROM_STREAM', (event) => {
this.zone.run(() => {
observer.next(event.data);
});
};
});
Got the data to show up. But in the network tab I still don't see the events.

Related

CORS Error on uploading image/video file to google cloud in react js

When user drag and drop the Image, I need to call a method of the server to get the Media_id for that particluar image/video, in the response of that I am getting this ->
MAIN RESPONSE -->>
{
"status": 1,
"media": {"media_id": 27, "media_type": 1, "media_file_name": "a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png", "media_placeholder": null, "media_ext": "png"},
"upload":
{
"upload_url": "https://storage.googleapis.com/fnc-59aa2e6b-71552c9d-6441d628-951a8f6f/l.img/ori/a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png?Expires=1603388214&GoogleAccessId=12345678-compute%40developer.gserviceaccount.com&Signature=UNt8nS3%2BJYiS4AuYdZ7Z2fvfDZ0fAKf8bSZbeRlHyhqxb5i6xjpqnqgR7JYp9Q3FgJItcYr%2BHDL90WiUpbMQi%2B4s0XNW683CaSoUChkRMjj1AvkH%2Be0u8%2Fw5VVIMF9j52bTFePWISTLvwQ1RlEdNPNkrpbcamTsJFyBVi89%2BIpXArsVlhvDzK55Zvj%2Fvzh00GgdNrH%2BRog8Q%2BkGITE8bW%2FxRpQ30OdMZLjpLtp%2FNg5KVotHrx6Bet7vidKymiJQ9BbwCxTRGzBdAITr2rsKTMGZJzfvEKnIczsoiY91Zmc3hjGzUD9OxHGR%2BiRdN%2F2FbotOIVR48RE%2BoAdIGIEfKlw%3D%3D",
"file_name": "a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png",
"content_type": "image/png", "exp": "2020-10-22 17:36:54.447484"
}}
So, I need to hit this upload url which is coming from the response.Below is my file where I am hitting this as soon as user drop the image ->
UploadImage.js
await this.props.getFirstMediaId(postdata).then(res => {
if (res.value && res.value.status === 1) {
let media_idArr = this.state.media_id.concat(res.value.media.media_id)
this.setState({ media_id: media_idArr, mediaUrl: res.value.upload })
customStatus = 'done';
}
}) //First call to the server to get Media_id and the cloud **upload URL**
***** FOR THIS API RESPONSE, PLEASE SEE THE ABOVE MAIN RESPONSE *****
const getUploadParams = () => {
console.log(this.state.mediaUrl, ' -->>> this.state.mediaUrl')
if (this.state.mediaUrl !== null) {
console.log(' in get upload param.')
return this.props.postImageToCloud(this.state.mediaUrl).then(res => {
console.log(res, '===>> here is cloud res.')
})
.catch(err => {
console.log(' here is error cloud -->>> ', err)
})
}
}
Below is the file where the method actually call API ->
service.js
export const getFirstMediaId = (data) => {
return {
type: GET_FIRST_LISTING_MEDIA,
async payload() {
let response = await callAxios.post(SUBMIT_LISTING_FIRST_MEDIA, data);
return objectPath.get(response, 'data', []);
}
}
}
export const postImageToCloud = (url) => {
return {
type: PUT_MEDIA_TO_CLOUD,
async payload() {
let response = await axios.put(url.upload_url, {}, {
headers: {
'Content-Type': `${url.content_type}`
}
})
return objectPath.get(response, 'data', []);
}
}
}
So, the first call is success and I got the above MAIN RESPONSE but as soon as it completes, I call the cloud PUT request and got this CORS error ->
Access to XMLHttpRequest at 'https://storage.googleapis.com/fnc-59aa2e6b-71552c9d-6441d628-951a8f6f/l.img/ori/a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png?Expires=1603388214&GoogleAccessId=123456789-compute%40developer.gserviceaccount.com&Signature=UNt8nS3%2BJYiS4AuYdZ7Z2fvfDZ0fAKf8bSZbeRlHyhqxb5i6xjpqnqgR7JYp9Q3FgJItcYr%2BHDL90WiUpbMQi%2B4s0XNW683CaSoUChkRMjj1AvkH%2Be0u8%2Fw5VVIMF9j52bTFePWISTLvwQ1RlEdNPNkrpbcamTsJFyBVi89%2BIpXArsVlhvDzK55Zvj%2Fvzh00GgdNrH%2BRog8Q%2BkGITE8bW%2FxRpQ30OdMZLjpLtp%2FNg5KVotHrx6Bet7vidKymiJQ9BbwCxTRGzBdAITr2rsKTMGZJzfvEKnIczsoiY91Zmc3hjGzUD9OxHGR%2BiRdN%2F2FbotOIVR48RE%2BoAdIGIEfKlw%3D%3D' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Please suggest me anything for make it working.
Thanks.
Finally after lot of efforts I came to know that I have to pass the file in the body of PUT request, here ->
let response = await axios.put(url.upload_url, { **file here** }, {
headers: {
'Content-Type': `${url.content_type}`
}
})
But I tried passing the image file object simple the html file object using formData and passing as it is, still getting the same error. Then i started using
react-dropzone and converted the image file into the string buffer as one of the example in React-dropzone. I am going to paste here that example maybe it can help anyone. See below ->
import React, {useCallback} from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const onDrop = useCallback((acceptedFiles) => {
acceptedFiles.forEach((file) => {
const reader = new FileReader()
reader.onabort = () => console.log('file reading was aborted')
reader.onerror = () => console.log('file reading has failed')
reader.onload = () => {
// Do whatever you want with the file contents
const binaryStr = reader.result
console.log(binaryStr)
*****PASS THIS (binaryStr) AS IN THE BODY OF PUT TO AXIOS****
}
reader.readAsArrayBuffer(file)
})
}, [])
const {getRootProps, getInputProps} = useDropzone({onDrop})
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
)
}
This is one of the Official examples of React-Dropzone, So I just pass that string buffer obj and finally It worked, no CORS issue nothing.
The Google Storage API does simply not accept requests initiated from a browser in another domain, so you won't be able to achieve this.
You should not call the API from a client but from your backend. Here is the list of the suggested libraries: https://cloud.google.com/storage/docs/reference/libraries?hl=fr
Note that JavaScript in a browser environment is not suggested (only Node.js is)

Service worker offline page won't load

This used to work for me but stopped a couple of months ago and I've tinkered my way right out of being able to figure this out anymore. What am I doing wrong here?
Call the service worker template, no problem:
if(navigator.serviceWorker){
window.addEventListener('load',() => {
navigator.serviceWorker
.register('/sw.js')
.then(console.log('[ServiceWorker] Registered Successfully'))
.catch(err => console.log(`[ServiceWorker] Error: ${err}`));
});
} else {
console.log('Service Worker not supported.');
}
Setup a cache version and preloaded the cache, no problem:
const cacheName='2020.10.06-01';
var cacheFiles = ['/offline.html'];
Installed the Services Worker, no problem:
addEventListener('install', e => {
e.waitUntil(
caches.open(cacheName).then(cache => {
return cache.addAll(cacheFiles);
})
);
});
Activated the Services Worker for auto cache rollover, no problem:
addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keyList => {
return Promise.all(keyList.map(key => {
if(key !== cacheName) {
return caches.delete(key);
}
}));
})
);
});
Fetching from cache or network, no problem:
addEventListener('fetch', e => {
e.respondWith(async function() {
try {
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match(e.request);
const networkResponsePromise = fetch(e.request);
e.waitUntil(async function() {
const networkResponse = await networkResponsePromise;
await cache.put(e.request, networkResponse.clone());
}());
// Returned the cached response if we have one, otherwise return the network response.
return cachedResponse || networkResponsePromise;
} catch (error) {
console.log('Fetch failed; returning offline page instead.', error);
const cache = await caches.open(cacheName);
const cachedResponse = await cache.match('/offline.html');
return cachedResponse;
}
}());
});
But if the page/resource I'm trying to request is not already in the cache AND the network is not available it refuses to display my 'offline.html' page. (Which I know IS in the cache)
Any ideas?
Here's the Fetch code I wrote in the end that works perfectly for me:
self.addEventListener('fetch', (event) => {
event.respondWith((async() => {
const cache = await caches.open(cacheName);
try {
const cachedResponse = await cache.match(event.request);
if(cachedResponse) {
console.log('cachedResponse: ', event.request.url);
return cachedResponse;
}
const fetchResponse = await fetch(event.request);
if(fetchResponse) {
console.log('fetchResponse: ', event.request.url);
await cache.put(event.request, fetchResponse.clone());
return fetchResponse;
}
} catch (error) {
console.log('Fetch failed: ', error);
const cachedResponse = await cache.match('/en/offline.html');
return cachedResponse;
}
})());
});
This does everything I need, in a very specific order. It checks the cache first, if found it's returned. It checks the network next, if found it caches it first then returns it. Or it displays a custom offline page with a big Reload button to encourage visitors to try again when they are back online.
But the most important this to realise is that doing it this way alows me to display a page and all it's resources with or without network access.
UPDATE: In order to deal with changes to CORS security requirements that where implemented in all browsers between March and August of 2020, I had to make one small change to the 'fetch' event.
Changed from:
const fetchResponse = await fetch(event.request);
To:
const fetchResponse = await fetch(event.request, {mode:'no-cors'});
Replace your fetch event code with this one. For every request your fetch event will be invoked and it will check if your request is found in the cache file list then it will serve the file from there otherwise it will make the fetch call to get the file from server.
self.addEventListener("fetch", function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
})
);
});
Also you don't need a separate "offline.html" file in your cache file list. Instead add your main application html file and your relevant css and js files in that list. That will make your application completely offline in case of no network.

Checking if a server is online with javascript

What Ive tried is this
function checkServer(url, timeout) {
const controller = new AbortController();
const signal = controller.signal;
const options = { mode: 'no-cors', signal };
return fetch(url, options)
.then(setTimeout(() => { controller.abort() }, timeout))
.then(response => console.log('Check server response:', response.statusText))
.catch(error => console.error('Check server error:', error.message));
}
var check = checkServer("https://www.youtube.com/xxxxxxxxxxx", 2000)
But the programm I am using doesnt work with it it says:
Error: empty expression not allowed (line 6)
Edit: This is not for a website so I cant use html but I can use a server with a php file if thats any help to making this work

Responding to fetch request via cache xor indexedDB

I am trying to have a service worker respond to fetch events depending on the type of request made. For static resources I use cache:
// TODO: make cache update when item found
const _fetchOrCache = (cache, request) => {
return cache.match(request).then(cacheResponse => {
// found in cache
if (cacheResponse) {
return cacheResponse
}
// has to add to cache
return fetch(request)
.then(fetchResponse => {
// needs cloning since a response works only once
cache.put(request, fetchResponse.clone())
return fetchResponse
});
}).catch(e => { console.error(e) })
}
for api responses I have already wired up IndexedDB with Jake Archibald's IndexedDB Promised to return content like this:
const fetchAllItems = () => {
return self.idbPromise
.then(conn => conn.transaction(self.itemDB, 'readonly'))
.then(tx => tx.objectStore(self.itemDB))
.then(store => store.getAll())
.then(storeContents => JSON.stringify(storeContents));
}
when I call everything in the service worker the cache part works, but the indexedDB fails miserably throwing an error that it cannot get at the api url:
self.addEventListener("fetch", event => {
// analyzes request url and constructs a resource object
const resource = getResourceInfo(event.request.url);
// handle all cachable requests
if (resource.type == "other") {
event.respondWith(
caches.open(self.cache)
.then(cache => _fetchOrCache(cache, event.request))
);
}
// handle api requests
if (resource.type == "api") {
event.respondWith(
new Response(fetchAllItems());
);
}
});
My questions would be as follows:
1.) Is there any point in separating storing fetch requests like this?
2.) How do I make the indexedDB part work?
good catch on using Jake Archibalds promise based idb. There are many ways to install his idb. The quickest - download the idb.js file somewhere(this is the library). Then import it on the first line in the service worker likeso:
importScripts('./js/idb.js');
.....
//SW installation event
self.addEventListener('install', function (event) {
console.log("[ServiceWorker] Installed");
});
//SW Actication event (where we create the idb)
self.addEventListener('activate', function(event) {
console.log("[ServiceWorker] Activating");
createIndexedDB();
});
.....
//Intercept fetch events and save data in IDB
.....
//IndexedDB
function createIndexedDB() {
self.indexedDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB;
if (!(self.indexedDB)) { console.console.log('IDB not supported'); return null;}
return idb.open('mydb', 1, function(upgradeDb) {
if (!upgradeDb.objectStoreNames.contains('items')) {
upgradeDb.createObjectStore('items', {keyPath: 'id'});
}
});
}
Judging by the code you pasted above to retrieve IDB data, it is unclear to me what exactly is idbPromise... Are you sure you declared this variable?
You should have something like this
importScripts('./js/idb.js');
//...
//createIdb and store
//...
var idbPromise = idb.open('mydb');
//and after that you have your code like idbPromise.then().then()...
So you create the IDB and the tables during the SW activation. After that you intercept the fetch events and start using the indexeddb like in the tutorials you've seen.
Good luck

Kurento IceConnection not resolving

I'm currently experimenting with Kurento Media Server to rebuild the One2Many example with NodeJS, Socket.io and React but I cannot seem to establish a conenction between the publisher and KMS.
The SDP offer is transmitted to KMS and the answer is transmitted to the client. Every ICECandidates from KMS and the client are transmitted too. The video feedback is showing on the app but nothing is sent to the server and there is no errors. Here's is the chrome://webrtc-internals for my app.
The example app is perfectly working with the same Kurento server, I checked every line and I'm doing the same calls on the backend and on the frontend. Here's the chrome://webrtc-internals for the example app.
For reference, here's the code I'm using on the backend (the errors checking have been removed for this example but nothing is raising an error when I'm using it):
io.on('connect', (socket) => {
const socketInfo = {};
socketInfo.webrtcEndpointCreation = new Promise((resolve, reject) => {
socketInfo.webrtcEndpointCreationResolve = resolve;
socketInfo.webrtcEndpointCreationReject = reject;
});
socket.on('broadcast', (infos, callback) => {
kms.client.create('MediaPipeline', (mediaPipelineError, pipeline) => {
mediaPipeline = pipeline;
mediaPipeline.create('WebRtcEndpoint', (webRtcEndpointError, webRtcEndpoint) => {
socketInfo.webRtcEndpoint = webRtcEndpoint;
presenterWebRtc = webRtcEndpoint;
socketInfo.webrtcEndpointCreationResolve();
webRtcEndpoint.on('OnIceCandidate', (event) => {
socket.emit('iceCandidate',
new kms.lib.register.complexTypes.IceCandidate(event.candidate));
});
webRtcEndpoint.processOffer(infos.sdpOffer, (error, sdpAnswer) => {
callback(null, sdpAnswer);
});
webRtcEndpoint.gatherCandidates();
});
});
});
socket.on('iceCandidate', (candidate) => {
socketInfo.webrtcEndpointCreation.then(() => {
socketInfo.webRtcEndpoint.addIceCandidate(candidate);
});
});
});
And this is the client code:
const options = {
localVideo: document.getElementById('video'),
onicecandidate: (candidate) => {
global.socket.emit('iceCandidate', candidate);
}
};
this.kurentoSocket = new WebRtcPeer.WebRtcPeerSendonly(options, (error) => {
this.kurentoSocket.generateOffer((err, sdpOffer) => {
global.socket.on('iceCandidate', (iceCandidate) => {
this.kurentoSocket.addIceCandidate(iceCandidate);
});
global.socket.emit('broadcast', { sdpOffer }, (broadcastErr, sdpAnswer) => {
this.kurentoSocket.processAnswer(sdpAnswer);
});
});
});
I finally found the problem, it was a Backend issue.
I need to create a IceCandidate object with new kms.lib.register.complexTypes.IceCandidate(candidate) from the message sent by the client before adding it. Because of the way promises works, the error was ignored.

Categories

Resources