Problem passing data from server to client - asynch


#1

I am sending potential email combinations (from client to server) and in the server I am using the email-existence package to check whether the email is valid.

I track the result on the server and it’s working fine, but I can’t pass that result to the client. I am trying using using promises and wait/asynch.

In the client, I have (for App.js) this code:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Promise } from 'meteor/promise';

// App component - represents the whole app
export default class App extends Component {
  handleSubmit(event) {
    event.preventDefault();
    console.log("form submited");
    const name = ReactDOM.findDOMNode(this.refs.first).value.trim();
    const last = ReactDOM.findDOMNode(this.refs.last).value.trim();
    const domain = ReactDOM.findDOMNode(this.refs.domain).value.trim();
    let data = {
      fi: name.charAt(0),
      li: last.charAt(0),
      fn: name,
      ln: last,
      domain: domain
    };

    const emails = this.runCombinations(data);
    console.log(emails);
    emails.map((email) => (
      this.main(email)
      ))
  };

  async main(email) {
      let result = await this.callMeteorMethod('checkEmail', email)
      console.log(result)
  }

  callMeteorMethod(methodName, ...args) {
    return new Promise((resolve, reject) => {
        Meteor.call(methodName, ...args, (error, result) => {
            if (error) reject(error)
            else {
              resolve(result)
              console.log("result: "+result)
            }
        })
    })
  }


  runCombinations(data) {
    let combinations = [];
    combinations.push(data.fn+"@"+data.domain);
    combinations.push(data.fi+"@"+data.domain);
    combinations.push(data.fn+data.ln+"@"+data.domain);
    combinations.push(data.fn+"."+data.ln+"@"+data.domain);
    combinations.push(data.fi+data.ln+"@"+data.domain);
    combinations.push(data.fi+"."+data.ln+"@"+data.domain);
    combinations.push(data.ln+"@"+data.domain);
    combinations.push(data.fn+data.li+"@"+data.domain);
    combinations.push(data.fn+"."+data.li+"@"+data.domain);

    combinations.push(data.fi+data.li+"@"+data.domain);
    combinations.push(data.fi+"."+data.li+"@"+data.domain);

    combinations.push(data.ln+data.fn+"@"+data.domain);
    combinations.push(data.ln+"."+data.fn+"@"+data.domain);
    combinations.push(data.ln+data.fi+"@"+data.domain);
    combinations.push(data.ln+"."+data.fi+"@"+data.domain);
    combinations.push(data.li+data.fn+"@"+data.domain);
    combinations.push(data.li+"."+data.fn+"@"+data.domain);
    combinations.push(data.li+data.fi+"@"+data.domain);
    combinations.push(data.li+"."+data.fi+"@"+data.domain);

    combinations.push(data.fn+"-"+data.ln+"@"+data.domain);
    combinations.push(data.fi+"-"+data.ln+"@"+data.domain);
    combinations.push(data.fn+"-"+data.li+"@"+data.domain);
    combinations.push(data.fi+"-"+data.li+"@"+data.domain);
    combinations.push(data.ln+"-"+data.fn+"@"+data.domain);
    combinations.push(data.ln+"-"+data.fi+"@"+data.domain);
    combinations.push(data.li+"-"+data.fn+"@"+data.domain);
    combinations.push(data.li+"-"+data.fi+"@"+data.domain);

    combinations.push(data.fn+"_"+data.ln+"@"+data.domain);
    combinations.push(data.fi+"_"+data.ln+"@"+data.domain);
    combinations.push(data.fn+"_"+data.li+"@"+data.domain);
    combinations.push(data.fi+"_"+data.li+"@"+data.domain);
    combinations.push(data.ln+"_"+data.fn+"@"+data.domain);
    combinations.push(data.ln+"_"+data.fi+"@"+data.domain);
    combinations.push(data.li+"_"+data.fn+"@"+data.domain);
    combinations.push(data.li+"_"+data.fi+"@"+data.domain);


    return combinations;
  }

  render() {
    return (
      <div className="container">
        <header>
          <h1>Email Finder</h1>
        </header>

        <form onSubmit={this.handleSubmit.bind(this)}>
         <label>
           First Name:
           <input ref="first" type="text" placeholder="Bill" />
         </label>
         <label>
           Last Name:
           <input ref="last" type="text" placeholder="Gates" />
         </label>
         <label>
           Domain:
           <input ref="domain" type="text" placeholder="microsoft.com" />
         </label>
         <input type="submit" value="Submit" />
       </form>

       <div>

       </div>
      </div>
    );
  }
}

And on the server I have:

import { Meteor } from 'meteor/meteor';
import emailExistence from "email-existence";

Meteor.startup(() => {
  // code to run on server at startup
});

Meteor.methods({
  'checkEmail'( email ) {
    return emailExistence.check(email, function(err,res){
      if(res) {
        result = res;
         console.log('email: '+email);
         return email;
      }
      if (err) {
        console.log("error" +err);
        return err;
      }
    });
  }
});

The code above doesn’t produce any errors, but the client it’s not getting the expected results.
Any suggestions?

I tried also using the ServerSession package, but I get a fiber error.


#2

Hi - if you can’t get this Promise approach working, you might want to try Futures. I find using Futures easy enough.

For Futures the client call is as usual, for example:

Meteor.call( “getUserAvatarUrl”,
function( error , useravatarurl ) {
if ( error ) {
alert( "** ERROR ** occurred during Avatar Lookup save. Error = " + error.message ) ;
return false ;
} else {
this.USERAVATARURL = useravatarurl ? useravatarurl.profile.image : “” ;
return true ;
}
}) ;

Then in MeteorMethods.js on the server you have:

import Future from ‘fibers/future’ ;
import { Meteor } from ‘meteor/meteor’ ;
import swearjar from ‘swearjar’ ;

Meteor.methods({

getUserAvatarUrl: function() {

let future = new Future() ;

let USERAVATARURL = null ;
USERAVATARURL = Accounts.users.findOne({ _id: Meteor.userId() },
  { "profile.image": 1, _id: 0 }) ;
future.return( USERAVATARURL ) ;

return future.wait() ;

},

Easy!-- jw


#3

This might work for you. I just use normal js promises as async and await work fine. Say I’m doing something like setting a value on a log object in db.

On client:

export function setLGSoptionPromise(logId, option, value) {
  if (checkLog(logId)) {
    check(option, Match.OneOf(
      'name', 'data', 'path',
    ));

    const updateModifier = {
      logId: logId,
      logAction: 'setGeneralSettings',
      logInformation: {
        option: option,
        value: value,
      },
    };

    return new Promise((resolve, reject) => {
      updateLogGeneralSettings.call(updateModifier, (err, result) => {
        (err) ? reject(err) : resolve(result);
      });
    });
  }
}

On Server:

export const updateLogGeneralSettings = new ValidatedMethod({
  name: 'logGeneralSettings.update',
  validate: LogUpdate.validator(),
  async run ({ logId, logAction, logInformation }) {
    if (Meteor.isServer) {
      switch (logAction) {
        case ('setGeneralSettings'): {
          let setModifier = { $set: {} };

          setModifier.$set[
            'logGeneralSettings'
            + '.'
            + logInformation.option
          ] = logInformation.value;

          return await Logs.update(logId, setModifier);
        }
        default: {
          throw new Meteor.Error(
            'logGeneralSettings.update.failure',
            `Method ${logAction} was not recognized...`,
          );
        }
      }
    }
  }
});

I would normally use it like:

generalSettings(logId, option, value) {
  if (checkLog(logId)) {
    setLGSoptionPromise(logId, option, value)
      .then((result) => { // do stuff here });
  }
}