CAF Receiver: Error handling - chromecast

We've created a custom CAF receiver with generic error listener based on cast.framework.events.EventType.ERROR event:
playerManager.addEventListener(cast.framework.events.EventType.ERROR, event => {
if (playerManager.getPlayerState() != "IDLE") {
let errorCode = (event.detailedErrorCode != undefined ?event.detailedErrorCode : null);
let errorMessage = null;
if ((event.error != undefined) && (event.error.reason != null)) errorMessage = event.error.reason;
playerManager.setIdleReason(cast.framework.messages.IdleReason.ERROR);
customErrorCodeClass.display(errorCode, errorMessage);
});
This handler works properly, but sometimes the player rise a "404 fragment error" for a single fragment, causing video stopping. We aren't able to know if that error is related for that particular fragment or there will be other 404 fragments, so we can't exclude that errors from error handler.
Does someone knows a better way to work around this issue?

Add following logs so you would know what happens with the fragments
playerManager.addEventListener(cast.framework.events.EventType.PLAYER_LOAD_COMPLETE, () => {
log('[mediacast:events:PLAYER_LOAD_COMPLETE');
console.log(playerManager.getStats());
console.log(playerManager.getMediaInformation());
});
playerManager.addEventListener(cast.framework.events.EventType.BITRATE_CHANGED, (event) => {
log('[mediacast:events:BITRATE_CHANGED - ' + event.totalBitrate);
stats.bitrate = event.totalBitrate;
console.log(playerManager.getStats());
});
playerManager.addEventListener(cast.framework.events.EventType.PLAYING, (event) => {
log('[mediacast:events:PLAYING - ', JSON.stringify(event));
});
playerManager.addEventListener(cast.framework.events.EventType.PAUSE, (event) => {
log('[mediacast:events:PAUSE - ', JSON.stringify(event));
});
playerManager.addEventListener(cast.framework.events.EventType.SEEKING, (event) => {
log('[mediacast:events:SEEKING - ', JSON.stringify(event));
});
playerManager.addEventListener(cast.framework.events.EventType.BUFFERING, (event) => {
log('[mediacast:events:BUFFERING - ', JSON.stringify(event));
});
playerManager.addEventListener(cast.framework.events.EventType.TIME_UPDATE, (event) => {
// log('[mediacast:events:TIME_UPDATE - ', JSON.stringify(event));
stats.currentMediaTime = event.currentMediaTime;
});
playerManager.addEventListener(cast.framework.events.EventType.MEDIA_STATUS, (event) => {
log('[mediacast:events:MEDIA_STATUS - ', JSON.stringify(event));
stats.state = event.mediaStatus.playerState;
});
and don't forget to set debug as logger level
cast.framework.CastReceiverContext.getInstance().setLoggerLevel(cast.framework.LoggerLevel.DEBUG);

Related

Download an image to React Native from a Laravel server?

I am looking to download an image stored on a server into my React Native app.
I had a function that looked like this:
public function image(Request $request, $id)
{
$company = Company::find($id);
$filePath = storage_path() . '/app/' . $company->image;
return response()->file($filePath);
}
And it returned nothing I could read within the app when I tried the following function:
setCompany = async () => {
let company = await AsyncStorage.getItem('currentCompany');
company = JSON.parse(company);
if (company.image !== null) {
let image = await getCompanyPicture({company_id: company.id});
console.log('Here: ', image);
// This is blank, react native returns a warning about data not being of a readable type
}
this.setState({company});
};
I am able to get the image in base_64 using this method:
public function image(Request $request, $id)
{
$company = Company::find($id);
$file_path = storage_path('/app/' . $company->image);
if (file_exists($file_path)) {
$fileData = file_get_contents($file_path);
$fileEncode = base64_encode($fileData);
return response()->json(['status' => 'success', 'data' => ['file' => $fileEncode, 'file_path' => $file_path]]);
}
return response()->json(['status' => 'failure', 'data' => ['file' => null, 'file_path' => $file_path]]);
}
Here is my Axios method too just in case:
export const sendRequest = async (url, data, token, method) => {
let headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
};
if (typeof token !== 'undefined' && token !== 'undefined' && token.length) {
headers.Authorization = 'Bearer ' + token;
}
if (method === 'get' && data) {
url +=
'?' +
Object.keys(data)
.map((value) => {
return value + '=' + data[value];
})
.join('&');
data = null;
}
return await axios({
headers: headers,
method: method ? method : 'post',
url: url,
data: data,
})
.then((response) => {
return response;
})
.then((json) => {
return json.data;
})
.catch((error) => {
console.error(error);
if (
error.message !== 'Network Error' &&
error.response.status !== 500 &&
error.response.status !== 413
) {
return error.response.data;
} else if (error.message === 'Network Error') {
return {
status: 'error',
message: 'Unable to connect to server',
};
} else if (error.response.status === 500) {
return {
status: 'error',
message: 'Internal Server Error',
};
} else if (error.response.status === 413) {
return {
status: 'error',
message: 'The file(s) size is too large',
};
} else {
return {
status: 'error',
message: error.message,
};
}
});
};
If anyone could comment on the performance impact of using base_64 instead of the straight file download that would also be helpful
But ultimately I would like a solution for handling the Laravel response()->file() if possible (which I'll use if base_64 is less efficient)
I'm not sure about RN code syntax, but I've ready code with jQuery+poorJS, which looks like this:
$.ajax({
url: "load-image-url", // URL FOR GET REQUEST
cache:false,
xhr: function() { // ACTUALLY THIS PART CAN BE USED AND CUSTOMIZED BY YOU
let xhr = new XMLHttpRequest();
xhr.responseType= 'blob'
return xhr;
},
success: function(data) {
let url = window.URL || window.webkitURL;
$('#image').attr('src', url.createObjectURL(data));
},
error: function(err) {
// console.log(err);
}
}).fail(function() {
$('#ss_product_image').attr('src', "default-image-url.jpg");
});
In my example I've used GET request (but you can try to modify it and test if you want, honestly IDK about that).
This is the back-end part:
public function image(Request $request, $id)
{
// HERE YOU NEED TO GET YOUR IMAGE (using $id or/and $request params) CONTENT FROM SOMEWHERE YOU WANT
$content = <CONTENT>;
return response()->make($content, 200, [
'Content-Type' => (new \finfo(FILEINFO_MIME))->buffer($content),
'Content-length' => strlen($content),
]);
}
I was able to solve this issue by using rn-blob-fetch.
The files are downloaded into a temp cache which can then be accessed for previewing and saving.
this is my function now:
downloadFiles = async (isReply) => {
let {enquiry, reply} = this.state;
this.setState({isLoading: true});
const token = await AsyncStorage.getItem('userToken');
let filePaths = [];
let fileCount = 0;
let files = enquiry.files;
if (isReply) {
files = reply.files;
}
const dirToSave =
Platform.OS == 'ios'
? RNFetchBlob.fs.dirs.DocumentDir
: RNFetchBlob.fs.dirs.DownloadDir;
new Promise((resolve, reject) => {
for (var i = 0; i < files.length; i++) {
var id = files[i].file_id;
var name = files[i].file.file_name;
var ext = extension(name);
const configOptions = Platform.select({
ios: {
appendExt: ext,
fileCache: true,
title: name,
path: `${dirToSave}/${name}`,
},
android: {
useDownloadManager: true,
notification: true,
mediaScannable: true,
fileCache: true,
title: name,
path: `${dirToSave}/${name}`,
},
});
var mime = content(ext);
let headers = {
'Content-Type': mime,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
Authorization: 'Bearer ' + token,
};
RNFetchBlob.config(configOptions)
.fetch('GET', BASE_API + '/enquiries/files/download/' + id, headers)
.then(async (response) => {
RNFetchBlob.fs.writeFile(
configOptions.path,
response.data,
'base64',
);
filePaths.push({
title: configOptions.title,
path: configOptions.path,
ext: extension(configOptions.title),
mime,
});
fileCount++;
if (fileCount >= files.length) {
resolve('Download Successful!');
}
})
.catch((error) => {
console.log('File Download Error: ', error.message);
reject('Download Failed');
});
}
})
.then((data) => {
this.setState({isLoading: false, filePaths});
})
.catch((error) => {
console.log('Download Promise Error: ', error);
this.setState({isLoading: false});
});
};
previewDocument = (id) => {
let {filePaths} = this.state;
if (Platform.OS == 'ios') {
RNFetchBlob.ios.openDocument(filePaths[id].path);
} else if (Platform.OS == 'android') {
RNFetchBlob.android.actionViewIntent(
filePaths[id].path,
filePaths[id].mime,
);
}
};

How to throw error after subscription timeout?

I'm simply trying to display in the view ( when for example user's connection is too slow and results won't come from subscription) after 30 seconds.
I'm surely missing something because even when results all arrive, the console timeout error message is still appearing.
This is what I tried:
searchInfo() {
this.isLoading = true;
this.info= [];
const source = this.infoService.searchInfo('help');
source.pipe(
timeout(30000),
takeUntil(this.onDestroy$)
).subscribe((infoTable: infoTableContent) => {
this.info.push(infoTable);
this.isLoading = false;
}),
(err) => {
this.isLoading = false;
console.log(err, 'Sorry, ...') //not working
}
I want to be able to display a message like "Sorry, took too long to retrieve data" after 30 seconds of trying to subscribe.
Thank you all in advance
You have an extra ) right after your next callback in the subscribe.
Therefore, your error callback is ignored.
.subscribe((infoTable: infoTableContent) => {
this.info.push(infoTable);
this.isLoading = false;
}), // <-- This paranthesis closes the subscribe method
The following works as expected
.subscribe(
(infoTable: infoTableContent) => {
this.info.push(infoTable);
this.isLoading = false;
},
(err) => {
this.isLoading = false;
console.log(err, 'Sorry, ...');
}
);
When I run this with Mocked Services it runs just fine for me:
const mockService = {
searchInfo: msg => NEVER.pipe(startWith({key: msg}))
};
const onDestroy$ = timer(5000);
let isLoading = true;
const info = [];
mockService.searchInfo('help').pipe(
timeout(1000),
takeUntil(onDestroy$)
).subscribe({
next: (mockTable: any) => {
info.push(mockTable);
isLoading = false;
},
error: err => {
isLoading = false;
console.log('Sorry, ...', err);
}
});
I suspect your bug might be due to miss-formatting (brackets in the wrong place etc)

Receiving Flux SSE in Angular 5

I have succesfully implemented this mechanism in my application:
https://vividcode.io/Spring-5-WebFlux-with-Server-Sent-Events/
I can receive events with curl every second, as shown in the example.
My problem is: I cannot receive these events in Angular 5. I have tried many things. Currently my service code looks like this:
public getMigrationProgress(processName: string): Observable<any> {
let headers: HttpHeaders = new HttpHeaders();
headers = headers.append('X-Authorization', this._sessionService.getAuthToken());
headers = headers.append('accept', 'text/event-stream');
let url = config.restApi.url + this.getResource() + '/' + processName;
return Observable.create(observer => {
let eventSource = new EventSourcePolyfill(url, { headers: headers });
eventSource.onmessage = (event => {
observer.next(event);
this.zone.run(() => {
console.log('prpprpr');
});
});
eventSource.onopen = (event) => {
observer.next(event);
};
eventSource.onerror = (error) => {
if (eventSource.readyState === 0) {
console.log('The stream has been closed by the server.');
eventSource.close();
observer.complete();
} else {
observer.error('EventSource error: ' + error);
}
};
});
}
It only opens connection, does not receive events (Method onopen works once, onmessage - never). Server sends them though.
Any ideas how to fix this?
Turned out that if you set event name on server, you cannot receive it by onmessage method.
In the example the event name was set to "random". In order to receive it you have to do it like this:
eventSource.addEventListener('random', function (event) {
console.log(event);
});

ionic 1 pushPlugin $cordovaPush:notificationReceived case message not fired when app is in background

I am using cordova pushPlugin
In that the code in my app.js under $ionicPlatform.ready I have,
$cordovaPush.register(androidConfig).then(function(result) {
// Success
// console.log(result);
}, function(err) {
// Error
// console.log(err);
});
$rootScope.$on('$cordovaPush:notificationReceived',
function(event, notification) {
console.log('event',notification.event)
switch(notification.event) {
case 'registered':
if (notification.regid.length > 0 ) {
//alert('registration ID = ' + notification.regid);
window.localStorage['push_token'] = notification.regid;
if(window.localStorage.getItem('id') != null){
console.log(3, 'api')
var addDevicetoken = myConfig.ApiBaseUrl+'api/addDeviceToken';
var postData = {
'id' : window.localStorage['id'],
'device_token' : notification.regid,
'device_type' : 0, // android
'uuid' : uuid
};
appRequestApi.requestPost(addDevicetoken,postData).then(function(result){
console.log(result);
});
}
}
break;
case 'message':
console.log(notification);
// this is the actual push notification. its format depends on the data model from the push server
alert('message = ' + notification.message + ' msgCount = ' + notification.msgcnt);
break;
case 'error':
alert('GCM error = ' + notification.msg);
break;
default:
alert('An unknown GCM event has occurred');
break;
}
});`
the message event does not trigger when my app is in background.
And also I am sending the payload from laravel as
$push = new PushNotification('fcm');
$push->setMessage([
'data' => [
'title' => $title,
'body' => $message,
'content-available' => 1,
'notification_type' => $notification_type,
'icon' => 'ic_launcher',
]
])
->setDevicesToken($tokens)
->send();
// dd($push->getFeedback());
return true;
Please help

Ionic 2: calling function after xhr.onload

In ionic 2, I'm using below code to upload the file(.pdf and .doc extension) into server via API. But I'm not able to call any function after resp.success == 1 or not able to use any global variables.I'm getting error like property doesn't exist on type xmlhttpeventtarget As I want to navigate user to next page on successful submission of the file I need call some function inside success.
xhr.open('POST', "myurl", true);
xhr.onload = function() {
if (xhr.status == 200) {
var resp = JSON.parse(xhr.response);
console.log('Server got: in IOS ', resp);
console.log('Server got: in IOS ', resp.message);
if(resp.success == 1)
{
console.log("THIS IS SUCCESS")
}
else{
alert(resp.message)
return
}
};
}
xhr.send(this.fd);
A better way to solve this would be by using arrow functions like this:
xhr.open('POST', "myurl", true);
xhr.onload = () => {
if (xhr.status == 200) {
var resp = JSON.parse(xhr.response);
console.log('Server got: in IOS ', resp);
console.log('Server got: in IOS ', resp.message);
if(resp.success == 1) {
console.log("THIS IS SUCCESS");
// Now 'this' points to the component :) !!
this.yourcustomfunction();
this.yourvariableblename;
} else{
alert(resp.message)
return
}
};
}
xhr.send(this.fd);
Notice that now we do
xhr.onload = () => {...});
instead of
xhr.onload = function() {...});
By using arrow functions, the this property is not overwritten and still references the component instance (otherwise, the this keyword points to the inner function, and your custom method and variable are not defined in it).
Hi I found solution to this problem.By creating a variable which has this reference, the snippet is as below.
var self = this;
xhr.open('POST', "myurl", true);
xhr.onload = function() {
if (xhr.status == 200) {
var resp = JSON.parse(xhr.response);
console.log('Server got: in IOS ', resp);
console.log('Server got: in IOS ', resp.message);
if(resp.success == 1)
{
console.log("THIS IS SUCCESS")
self.yourcustomfunction()
self.yourvariableblename
}
else{
alert(resp.message)
return
}
};
}
xhr.send(this.fd);

Resources