Can't write to public folder on galaxy

Using Meteor 1.2

I’m using a server side route to create, write to and display an html file from a subfolder in the public directory on galaxy. I’m using fs.writeFileSync and fs.readFileSync. But the only thing rendered to the browser is ‘server error’. And what you see below is written to the server logs. I use another remote server (Ubuntu) for development. And it works fine on the dev server. I’m able to render files that i’ve pushed to the galaxy public server. But I can’t see files I’m trying to create programmatically.

2016-07-04 14:03:32-04:00Error: ENOENT, no such file or directory '/app/bundle/public/special/filename.html’
2016-07-04 14:03:32-04:00 at Object.fs.openSync (fs.js:439:18)
2016-07-04 14:03:32-04:00 at Object.fs.writeFileSync (fs.js:978:15)
2016-07-04 14:03:32-04:00 at saveFile (lib/router.js:257:6)
2016-07-04 14:03:32-04:00 at [object Object].Router.route.onBeforeAction (lib/router.js:296:18)
2016-07-04 14:03:32-04:00 at boundNext (packages/iron_middleware-stack/lib/middleware_stack.js:251:1)
2016-07-04 14:03:32-04:00 at runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1)
2016-07-04 14:03:32-04:00 at packages/meteor/dynamics_nodejs.js:123:1
2016-07-04 14:03:32-04:00 at [object Object].urlencodedParser (/app/bundle/programs/server/npm/iron_router/node_modules/body-parser/lib/types/urlencoded.js:84:40)
2016-07-04 14:03:32-04:00 at packages/iron_router/lib/router.js:277:1
2016-07-04 14:03:32-04:00 at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
2016-07-04 14:03:32-04:00 at [object Object].hookWithOptions (packages/iron_router/lib/router.js:276:1)
2016-07-04 14:03:32-04:00 at boundNext (packages/iron_middleware-stack/lib/middleware_stack.js:251:1)
2016-07-04 14:03:32-04:00 at runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1)
2016-07-04 14:03:32-04:00 at packages/meteor/dynamics_nodejs.js:123:1
2016-07-04 14:03:32-04:00 at [object Object].jsonParser (/app/bundle/programs/server/npm/iron_router/node_modules/body-parser/lib/types/json.js:96:40)
2016-07-04 14:03:32-04:00 at packages/iron_router/lib/router.js:277:1

I’ve found that I can write to the root public folder. And I can read from it, but only if I navigate directly there in the browser. example.com/filename.html

However. I can’t write to a sub folder, public/special. I might be able to, but all I’m sure of is that I can’t read from there. And since galaxy has no ftp or ssh access as far as I can tell, I have no way of knowing.

You should not write to your application directory or anything below that. Instead try to use some temp file if you really need to use files. Alternatives for storing files are are: database, s3, etc. Best solution can only be based on your project.

I found a solution which I’ll document for posterity.

My intention was to have the user download the html file in a zip. What I did is, instead of writing to a file, I wrote the html to a variable and then ‘appended’ that into a zip file using Node archiver (https://github.com/archiverjs/node-archiver).

I have a static image that is included in every zip file along with the html file. The image is permanently located on the server in the public folder. But fs.createReadStream would always return an error when I tried to read it. This wasn’t a problem on the dev server.

The problem was how meteor production, or at least galaxy, changes the ‘public’ folder path. Following this method -> How to list images inside public/? - I was able to find the right path to the ‘public’ folder. The following works on both production and development environments.

var meteorRoot = fs.realpathSync( process.cwd() + ‘/…/’ );
var publicPath = meteorRoot + ‘/web.browser/app/’;

It looks like I can write to ‘public’ on galaxy. I just couldn’t read from it because its path is in a different place than on the dev server.

If you have it in a variable why not just stream it to the client?

… because the user has/wants to download the html file as a zip. (There’s a very good reason for that so that’s not something that can be changed). So I appended the variable (i.e. html data) into the node-archiver instead of writing the file then passing its path into a read stream and passing all of that to the node-archiver, since I couldn’t read the file anyway because I had the wrong path.

You don’t need to actually write the file. There is no need for that in most cases. You can pipe them through the processing applications and with the right headers it will force a download on the client in the end.

I know. You keep saying that. And I said, four posts ago, that I’m not. I’m getting the feeling that you didn’t read anything beyond the second paragraph in the solution I posted last week -> Can’t write to public folder on galaxy
I’m using node-archiver, which doesn’t write to the server. It just pipes the file to the client in a zip.

1 Like