I want to deploy a meteor app to meteor.com.
Unfortunately I have to write some tmp files to the public folder of meteor.
Example Code:
var fs = Npm.require('fs');
var filepath = "../../../../../public/resizing/tmp~";
fs.open(localpath, 'w', function(err,fd)
{
if(err) throw "error opening file";
fs.close(fd,function(){});
}
( ../../../../../public is the location of the meteor public folder after bundling! )
This works fine on my local machine, because I have write privileges inside the public folder. Is there a way how I can write to a tmp file in an app that is deployed to meteor?
Most cloud providers don't allow access to file system, because this would put too much constraints on the architecture. Meteor.com is not different. For Meteor, there's also a problem of /public dir being precached by the engine, so every change to that folder would result in server being restarted (you can see that on your local machine as well).
Whatever you're trying to achieve, there are different ways. The most common ones are:
Use an external storage system, such as Amazon S3.
Simply, write the files you need as a new collection in the database. It's obvious how to do it for text files, but as easy for binary ones - just convert them to base64.
Meteor allows people to deploy apps to meteor.com as a courtesy, but I agree that writing to the file system dynamically would be a security risk for them. You can package your app and deploy it to your own server somewhere if that's easier, but you might want to rewrite the app logic itself to keep that data somewhere other than the same location of your app (S3, for instance). I'm assuming you're trying to store images or something. If it's not, just use Meteor's data stores and keep it there.
Related
I am working on a personal project and there are two things that keep bugging me.
This project is written in React and I am using an express node app for backend. In my frontend, I can load and send images to the server and I am saving the files inside an upload file and the path is stored inside a mongo database.
After the build, the files look like this:
As you can see, my uploads folder is inside the public folder. The public folder is the build of the react app. I just renamed it. The problem is, if I want to update the build, I have to save the uploads file in someplace else and than reintroduce it inside the new build(public) folder. And that sounds impractical to me. Is there a way around that? A best practice?
That would be the first thing.
The second one is the path that I am using to link the image folder to the <img src=''/>.
Right now, the path looks like this: http://localhost:5000/${ filePath }. And works just fine. But I don't think that in a production scenario I will be able to use this path.
The question is: Do I have to link the port as well? Something like: http://localhost:${PORT}/${ filePath } and the port is const PORT = process.env.PORT? Or is there a better practice? A way to get your own domain?
Hope I delivered all the info needed for an accurate answer. If not, I am waiting for feedback. Thanks!
"Best practice" would be uploading the files to static file server like S3 and storing a reference to they file key.
But short of that, I believe Express lets you set multiple static file directories using
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
so you could then keep your uploads directory outside your build folder.
As for including port in your asset URIs, what I've done in the past was to use an environment variable called domain that specified the web address of the current environment (including protocol, domain, and port). This way your dev enviornment can use localhost, but if you decied to deploy your production app to the public, you can just set the environment to the domain name -- and could tell your express server to listen on the 80/443 ports.
I tried upload file to Heroku using https://www.npmjs.com/package/express-fileupload, on my PC it works great, but on Heroku there are this error:
{"errno":-2,"code":"ENOENT","syscall":"open","path":"./public/owner_photo/f28397baea8fb4d6f6dafed9f5586a9ac0b46843acf1120a0ecad24755cfff57.jpeg"}
How can I fix it?
Heroku has an immutable file system, meaning you can't make changes to, or additions to the file system. You'll need to store your uploads somewhere else, like Amazon S3.
Also, many upload packages by default store the uploaded file in a temp directory. So even if you are sending them to S3, you'll still need to make sure the methods you use don't attempt to do that, or set an option to disable it. I'm not familiar with express-fileupload so I can't say what methods do or do not attempt to store copies on the filesystem.
I have successfully implemented this using multiparty so I could be of more specific help with that package.
I have a nodejs application using hapi.js and I'm trying to download an image from a url. Heroku is giving me errors with the pathing.
My code:
Request(uri).pipe(fs.createWriteStream(__dirname+'/../public/images/'+filename)).on('close', callback);
My errors:
Error: ENOENT: no such file or directory, open '/app/../public/images/1430540759757341747_4232065786.jpg'
My file structure is simple:
app.js
-public
-images
-sampleimage.jpg
-videos
-samplevideo.mp4
-audio
-sampleaudio.wav
As you can see the __dirname for heroku application is /app. I've tried using __dirname+'all sorts of pathing ../ ./ etc' and I've also tried it without __dirname.
I will be creating a lot of these files using ffmpeg and a speech tool. So could anyone explain to me what kind of problem I am having? Is it something that can be solved by using the correct path name or is it my hapijs server configurations that I need to configure?
You just have the wrong path in your project.
On Heroku, you can't write to the folder BELOW the root of your project.
In your case, your code is running in app.js, which is in the 'root' folder of your project.
So, on Heroku's filesystem, this means your project looks like this:
/app
/app/app.js
/app/public
/app/public/images
...
Heroku puts all your code into a folder called app.
Now, in your code pasted above, you show:
Request(uri).pipe(fs.createWriteStream(__dirname+'/../public/images/'+filename)).on('close', callback);
If this code is running in your app.js, it means that by going BACK a folder (eg: ..), you're trying to write to a non-writable part of Heroku's filesystem.
Instead, you want to write to:
Request(uri).pipe(fs.createWriteStream(__dirname+'/public/images/'+filename)).on('close', callback);
This will correctly write your file into the images folder like you want.
HOWEVER
Here's where things are going to get complicated for a moment.
On Heroku, you can indeed write files to the filesystem, but they will DISAPPEAR after a short period of time.
Heroku's filesystem is EPHEMERAL, this means that you should treat it like it doesn't exist.
The reason Heroku does this is because they try to force you to write scalable software.
If your application writes files to your webserver disk, it won't scale very much. The reason why is that disk space is limited. Each web server has its own disk. This can lead to confusing / odd behavior where each webserver has a copy of the same file(s), etc. It just isn't a good practice.
Instead: what you should do is use a file storage service (usually Amazon S3) to store your files in a central location.
This service lets you store all of your files in a central location. This means:
You can easily access your files from ALL of your web servers.
You can have 'reliable' storage that is managed by a company.
You can scale your web applications better.
The folder you hosted on heroku is considered as "app" which you can see from the error you got. I m commenting this after 5 years just to let future viewers know. If any folder is empty, it is not pushed to github or heroku when you pushed the entire project as the folder is empty.
When we try to access a folder which is empty initially, we get the above error as the folder is not pushed in the first place. So, if you want to get rid of the error, place a temp file of any type ( I used a txt file) and push the code. Now the error won't be there anymore as this time the folder is pushed and it can access it.
I created a project, which is here: https://github.com/dartem/upload_files, and it uploads a file and saves it using FilesCollection. However, it looks like that an actual file is getting saved only temporarily in /cdn/storage and once I restart Meteor or if I open an incognito window an actual file doesn't exist.
I specify the path directory, which is assets/app/uploads/Images, but an image doesn't get saved in that directory. How can I save an actual file in that directory?
I ran your demo up, and it does save files to that directory.
It's not advisable to store files in .meteor/local - basically the files there are temporary - meteor will remove and replace them as it rebuilds the app. This explains why you can't find them again later.
It is also possible to write the files to the public directory, but that will trigger a rebuild of your app every time you save a file, which isn't a good side effect.
I would recommend that you only save the files to gridFS or AWS (or any of the other storage options). You could save them to a folder somewhere else in the file system, as long as you have a way of serving them up (some kind of web server like apache, express or whatever). Your choice based on what sysadmin capability you have.
I'm working on a Windows Store App (JavaScript/HTML/CSS) that will be deployed directly to devices in our enterprise.
I want to keep the datasources (urls to Restful web APIs) as part of the configuration rather than built into the app itself so that I can set them during deployment (e.g. to set test urls and prod urls).
More generally I want to store text variables in config that is external to the app and can be pulled in by the app somehow.
I thought I could set some environment variables or something but Windows Store Apps can't read them it seems.
Any ideas?
You could certainly make an HTTP request from the app on startup to retrieve a configuration file, but that of course assumes connectivity which may or may not work in your scenario. For a Store-acquired app, this is really the only choice.
In your scenario, however, you'll be doing side-loading through a Powershell, correct? (This is implied in installing directly to devices.) In that case, the Powershell script is running in full trust and will have access to the file system during the process. This means that the script can easily deploy a configuration file into the app's local appdata folder, which the app then picks up when it runs. The app package should also contain a default configuration file that it copies into that appdata folder if such a file doesn't exist on startup.
The documentation for the add-appxpackage script that does the install is here: https://technet.microsoft.com/en-us/library/hh856048.aspx.
Another option you might be able to use is to build different versions of your packages for test and production deployment. It is possible to configure the build process in Visual Studio to selectively bring in different versions of a file depending on your build target (e.g. Debug or Release). I have a blog that describes this technique on http://www.kraigbrockschmidt.com/2014/02/25/differentiate-debug-release-builds-javascript/. This would allow you to package different versions of a configuration file into the package, which you'd then read from the package install location at runtime or copy to appdata if you wanted to make changes at runtime.
I mention this method for building different packages because it's something that doesn't need you to do anything other than change the build target. It accomplishes what you would do with #ifdef precompiler directives in other languages, which aren't available for JavaScript.