Is it possible to have smaller packets when uploading images in Alamofire? - alamofire

my code is something like this:
Alamofire.upload(multipartFormData: { (data) in
// add bunch of large size images
}
.uploadProgress { progress in
// print progress
}
.downloadProgress { progress in
// print progress
}
the problem is that uploadProgress takes too long to refresh compared to downloadProgress
is there any way to make uploadProgress update more frequently?
btw: im using alamofire 5

No. Alamofire is at the mercy of the progress callbacks from URLSession. You should also know that if your upload is over the threshold, it's first written to disk, which is not reflected in the progress. So you'll see a period of no progress, then the real upload progress, then quick download progress, as the download part is usually just the server acknowledging the upload and is much smaller.

Related

React Native - Network request failed when uploading image second time

I have found what seems to be a bug on Android. I have not tested it on IOS.
updateProfilePhoto() is a redux thunk that just sends a PUT request to my node server.
The problem is this, I can upload an image to my node server using fetch. The image is received and saved successfully on the server. If I wait for about 1 second and the upload another image, it goes through successfully. However, if I upload an image and then upload another immediately after the first one goes through, I get the error 'Network request failed' and the second image will not be received on the server.
It seems to me that I cannot constantly upload images back to back really quickly, one will go through, the next one will fail and the next will go through... and so on.
I am testing on an Android Emulator. API level 30. I have not tested on a real device yet, I will try that when I'm able to.
The error happens for the built-in fetch() and XMLHttpRequest. Both behave the same. On XMLHttpRequest I can check the progress and it says 100% and then fails with xhr.status equal to 0.
I need a sure fire way to upload an image to my server without it failing for no reason. I can add a delay of something like 500ms between uploads and show the user that it's loading but that's a silly way to resolve the issue. I can't find out why the upload fails on the second try.
const onSelectProfileImage = (pickerResponse: ImagePickerResponse) =>
{
const uri = pickerResponse?.assets && pickerResponse.assets[0].uri;
const name = pickerResponse?.assets && pickerResponse.assets[0].fileName;
const type = pickerResponse?.assets && pickerResponse.assets[0].type;
if(uri)
{
const photo = new FormData();
photo.append('photo', {name,type,uri});
dispatch(updateProfilePhoto({photo, uri, user_id: id, headers: {...headers,"content-type": "multipart/form-data"}}))
}
}

React native Image prefetch

I am having difficulties to understand Image prefetch. In the doc's there is not much explanation about it:
"Prefetches a remote image for later use by downloading it to the disk
cache"
Could you please help me understand the following about Image prefetch:
Suppose a user uploads a profile image, and the image's URL is stored in the AsyncStorage.
Should I run Image.prefetch(UserStore.profileImageUrl) only once after successful upload. And use prefetched image in the components normally like <Imagesource={{uri: UserStore.profileImageUrl}}/>
Or should I always run Image.prefetch(UserStore.profileImageUrl) before using that image in the component, then only run <Imagesource={{uri: UserStore.profileImageUrl}}/>
Suppose, later on, the user changes their profile image by uploading a new image and after successful upload, I will prefetch the new image. Will the previously cached image still exist on the disk?
If yes, won't it occupy a lot of space in the device if there are lots of prefetched images?
Is there any way to manually remove the prefetched image from the disk?
With the above questions in mind, if there are alternate solutions to achieve caching of images when using react native with expo, could you please help me with it.
It was indeed a question that I was dealing with for a while, and I learned a few things about Image.prefetch:
In the current React-Native version (0.48), this method is still in progress. To be more precise:
the ios implementation is still incomplete.
There is no complete guide on it.
There is no way to clear cache (you can check if the url is cached, however as far as I know you cannot clear it now).
As a result, I don't suggest you use it. Regardless, if you want to know how the API works, it is how:
Purpose
The purpose is quite obvious I think, this API:
Prefetches a remote image for later use by downloading it to the disk cache
It means that you can use Image.prefetch(url) in your constructor or componentWillMount. It tries to fetch image asynchronically, then, render your page with some kind of an ActivityIndicator, Finally, when the image is successfully fetched you can re-render your component.
Image.prefetch(url) actually saves the image to disk (not memory), as a result, whenever or wherever you try to use
<Image source={{uri:url}}/>
At firsts it checks the list of caches urls, if you have prefetched that url before (and it is located on the disk), it won't bother to re-fetch (unless you run function `Image.prefetch(url)' again (I am not sure if it works properly).
The implications of this issue are so complicated. It means that if you prefetch an image inside one component (for example <Component1/>), when you try to show this specific image in another component (for example <Component12>), It won't fetch the image and just uses the disk cache.
Therefore, either don't use this Image.prefetch at all (until there is a complete API, with cache control) or use it at your own risk.
on Android
On Android, you have 3 APIs for prefetch, and only one of them is presented in the documentation:
prefetch:
var response = Image.prefetch(imageUrl,callbackFunction)
Image.prefetch can have an optional second argument callbackFunction, which a function that runs Before fetching image. It can be written in the following format:
var response = Image.prefetch(imageUrl,()=>console.log('Image is being fetched'))
It might be worthy to note that, callbackFunction can have an argument called requestId, (indicating the number of prefetch among all other prefetches) which can be then used to abort the fetch.
var response = Image.prefetch(imageUrl,(id)=>console.log(id))
Moreover, response is a promise, you can use .then to do more after the image is pre-fetched.
abortPrefetch
Image.abortPrefetch(requestId) ;
used to abort the pending prefetch. requestId used as argument is the same as the one seen in prefetch.
queryCache
Image.queryCache([url1,url2, ...])
.then((data)=>console.log(data));
Used to check if a certain url is already cached, and if so where is it cached (disk or memory)
on IOS
I think that only Image.prefetch(url) is currently available on IOS, and there is no callback function to be called as the second argument.
if there are alternate solutions to achieve caching of images when
using react native with expo, could you please help me with it.
You may be interested in my higher order component module that adds performance related image caching and "permanent cache" functionality to the native <Image> component.
React Native Image Cache HOC
Tl;DR Code Example:
import imageCacheHoc from 'react-native-image-cache-hoc';
const CacheableImage = imageCacheHoc(Image);
export default class App extends Component<{}> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<CacheableImage style={styles.image} source={{uri: 'https://i.redd.it/rc29s4bz61uz.png'}} />
<CacheableImage style={styles.image} source={{uri: 'https://i.redd.it/hhhim0kc5swz.jpg'}} permanent={true} />
</View>
);
}
}
The first image will be cached until the total local cache grows past 15 MB (by default) then cached images are deleted oldest first until total cache is below 15 MB again.
The second image will be stored to local disk permanently. People use this as a drop in replacement for shipping static image files with your app.
Personally I would not overcomplicate things by writing over files over and over when the file changes, that's just asking for a massive headache. Instead I would create a unique filename for each upload. So the user's profile pic the first time they upload is "profile-uniqueIdHere.jpg" and when they change their profile pic you just create a new file "profile-anotherUniqueIdHere.jpg" and update their user data to reflect the new file location. For help with creating unique Ids look at react-native-uuid.

Browser web cam stream has extremely low performance/frame rate

I am trying to test WebRTC and want to display my own stream as well as the peer's stream. I currently have a simple shim to obtain the camera's stream and pipe that into a video element, however the frame rate is extremely low. The rare thing about this is that I can try examples from the WebRTC site and they work flawlessly.. The video is smooth and there are no problems. I go to the console and my code resembles theirs.. What could be happening? I tried to create both a fiddle and run that code within brackets but it still performs horribly.
video = document.getElementById('usr-cam');
navigator.mediaDevices.getUserMedia({video : {
width : {exact : 320},
height : {exact: 240}
}})
.then(function(stream){
if(navigator.mozGetUserMedia)
{
video.mozSrcObject = stream;
}
else
{
video.srcObject = stream;
}
})
.catch(function(e){
alert(e);
});
Pretty much everything I do. Take into account that I am using the new navigator.mediaDevices() API instead of navigator.getUserMedia() but I don't see how that would matter since 1.I am using a shim provided by the WebRTC group named adapter.js which they themselves use. 2. I don't think how you obtain hold of the video stream would affect performance.
Alright, I feel very stupid for this one... I was kind of deceived by the fact that the video element will update the displayed image without you having to do anything but pipe the output stream, which means the image will update but just at really long intervals, making it seem as if the video is lagging. What I forgot to do was actually play() the video or add autoplay as its property... it works well now.

Safari html5 video timeupdate event gets disabled

We are playing videos from a server. We attach an 'ontimeupdate' event which fires periodically, as the video plays. For slow connections, we can compare where the video currently IS, to where it SHOULD be. Then we can do some other things we need to do, if it is lagging. Everything works fine in Chrome, FF, IE. In Safari, when the connection is slow, the event only fires twice. Why does it get removed? Is there a way to add the event again, inside of the handler for the event? Thanks
The HTML5 audio/video element is still less than perfect. The biggest issues I've noticed is that it doesn't always behave the same way in every browser. I do not know why the timeupdate event stops firing in Safari, but one option you have is to monitor whether the video is playing or not and verifying the information independently. Example,
$(video).bind('play', function() {
playing = true;
}).bind('pause', function() {
playing = false;
}).bind('ended', function() {
playing = false;
})
function yourCheck() {
if (playing) {
if (video.currentTime != timeItShouldBe) {
//do something
}
} else {
return;
}
setTimeout( yourCheck(), 100);
}
Something to that effect. Its not perfect, but neither is the current HTML5 audio/video element. Good luck.
The event will not fire if the currentTime does not change, so it may not be firing if the video has stopped playing to buffer. However, there are other events you can listen for:
1) "stalled" - browser is trying to load the video file, but it's not getting anything from the network.
2) "waiting" - playback has stopped because you ran out of buffered data, but it will probably pick up again once more data comes in from the network. This is probably the most useful one for you.
3) "playing" - playback has resumed. Not to be confused with "play" which just means it's "trying" to play. This event fires when the video is actually playing.
4) "progress" - browser got more data from the network. Sometimes just fires every so often, but it can also fire after it recovers from the "stalled" state.
See the spec for reference.
I've heard some people say that these events can be unreliable in some browsers, but they seem to be working just fine here: http://www.w3.org/2010/05/video/mediaevents.html
If you want to be extra cautious, you can also poll periodically (with a timeout as tpdietz wrote) and check the state of the video. The readyState property will tell you whether you have enough data to show the current frame ( >= 2 ), enough to keep playing at least a little bit into the future ( >= 3 ) or enough to play all the way to the end (probably). You can also use the buffered property to see how much of the video has actually been buffered ahead of where you're playing, so you can roughly estimate the data rate (if you know how big the file is).
MDN has a great reference on all these properties and events.

Speed up phantomjs screen capture time?

While running the rasterize.js example provided by PhantomJS, I find it I have to wait 20 seconds or more until a web page image is produced.
Is there any possible way to speed this up without consuming a lot of resource? I am basically looking to rapidly produce series of sequential images captured from webpages loaded with PhantomJS. It would be really great if I could output Phantomjs somehow to a video stream even.
For now I would look for something that just takes a screenshot of a web page within 1~2 second range with PhantomJS. If there's already a project or library which accomplishes this that would be great too.
In case your images URL are hardcoded into html response, then you can do next things:
Get html body
Parse it and get your images
And then render them into something like PhantomJS or anything else WebKit based.
You can take a look to this sample, https://github.com/eugenehp/node-crawler/blob/master/test/simple.js
Like:
var Crawler = require("../lib/crawler").Crawler;
var c = new Crawler({
"maxConnections":10,
// "timeout":60,
"debug":true,
callback:function(error,result,$) {
console.log("Got page");
$("img").each(function(i,img) {
console.log(img.src);
})
}
});
c.queue(["http://jamendo.com/","http://tedxparis.com"]);