Hend El-Sahli
Hend El-Sahli

Reputation: 6742

How to create a session-like variable on Meteor Server?

I want to create a single tmp directory using tmp. And I would like to to reference the path of this directory inside Meteor.method implementation...

import tmp from 'tmp';

tmp.dir(function _tempDirCreated(err, path, cleanupCallback) {
 if (err) throw err;

 // Store path as a session variable

});

I know that Session is only available on the client, and the thing is tmp is only available on the server.

So, is there anyway I could create a session-like variable on the server for the "path variable", and have it accessible on the server meteor.methods

Upvotes: 1

Views: 416

Answers (2)

Hend El-Sahli
Hend El-Sahli

Reputation: 6742

I found a solution that solves my issue using:

  1. A Meteor method.
  2. Redux store.

I'm using React for the client-side

Redux should be setup with a reducer called tmpReducer that has dirPath field, and a redux action for changing this dirPath field called: changeTmpDirPath

tmpReducer

import { CHANGE_TMP_DIR_PATH } from '../constants/actions';

const INITIAL_STATE = {
  dirPath: ''
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case CHANGE_TMP_DIR_PATH: {
      return { dirPath: action.payload };
    }

    default:
      return state;
  }
};

changeTmpDirPath

import { CHANGE_TMP_DIR_PATH } from '../constants/actions';

export const changeTmpDirPath = path => {
  return { type: CHANGE_TMP_DIR_PATH, payload: path };
};

Then: Create a Meteor method for creating tmp directory [returns DirPath as a result]

Meteor.methods({
  createTmpDir() {
    if (Meteor.isServer) {
      const tmpDir = tmp.dirSync();

      return tmpDir.name;
    }
  }
});

Then:

  1. Call this Meteor method on the client's startup.

  2. Pass the result of the Meteor method call to the Redux action to store the dirPath on the application level state [Redux Store].

     Meteor.call('createTmpDir', function(err, result) {
       if (err) {
         console.log('createTmpDir err', err);
       } else {
         this.props.changeTmpDirPath(result); // Call Redux action
       }
    });
    
  3. The dirPath will be then available as a Redux piece of state, and ready to be passed to any Meteor method that needs access to it.

    class MyComponent extends React.Component {
    
      componentDidMount() {
        Meteor.call('methodThatNeedDirPath', this.props.tmp.dirPath);
      }
    
      // ...
    
    const mapStateToProps = ({ tmp }) => ({ tmp });
    
    export default connect(mapStateToProps)(MyComponent);
    

Upvotes: 0

Jankapunkt
Jankapunkt

Reputation: 8423

You can create a Mongo collection that acts as your temp-cache. Since there are handy packages, suchs as dburles:mongo-collection-instances, you can access this collection anywhere in your code where the collection has been created.

server/main.js

const TempCollection = new Mongo.Collection('temp');

Meteor.startup(()=>{

  // flush all temps at startup
  TempCollection.remove({});

});

server/methods.js

Meteor.methods({

  storeTempDir() {

    const path = // ... get your temp dir from somewhere
    const key =  // ... give this path an id or key

    // the following requires dburles:mongo-collection-instances
    const TempCollection = Mongo.Collection.get('temp');
    TempCollection.insert({key, path});
  },

  doWithTempDir() {

    const key = // ... use a key to access the temp path

    // the following requires dburles:mongo-collection-instances
    const TempCollection = Mongo.Collection.get('temp');
    const path = TempCollection.insert({key});

    // ... do something with your path
  }

}); 

For a more modular approach, you can also create a Wrapper class around this:

server/tmp.js

const TempCollection = new Mongo.Collection('temp');

Meteor.startup(()=>{

  // flush all temps at startup
  TempCollection.remove({});

});

export const tmp = {

  get(key) {
    TempCollection.findOne({key});
  }

  set(key, value) {
    const exist = this.get(key);
    if (exist)
      TempCollection.update(exist._id, { $set: { key, value } });
    else
      TempCollection.insert({key, value});
  }

} 

And use it in your methods like so:

server/methods.js

import { tmp } from './tmp.js';

Meteor.methods({

  storeTempDir() {

    const path = // ... get your temp dir from somewhere
    const key =  // ... give this path an id or key

    tmp.set(key, path);
  },

  doWithTempDir() {

    const key = // ... use a key to access the temp path

    const path = tmp.get(key).value;

    // ... do something with your path
  }

}); 

Some comments on this in order to keep it easy but safe:

  • don't attach a schema to the TempCollection so you can have a real session-like behavior
  • because this collection accepts anything, keep in mind that it should not be accessible by clients (they can use Session anyway).
  • don't publish this content as it may be very sensitive information about internals
  • don't overuse it. A good database design with well thought schemata is to be favored.
  • maybe there are already packages out there that implement this exact behavior. Tested and production ready. These are to be favored, too.

Upvotes: 2

Related Questions