Meteor method gets data as undefined


#1

So I have this method in my component

uploadCallback (file) {
    // TODO: Integrate dropbox with its SDK
    // TODO: Pass the link to the editor
    return new Promise(
      (resolve, reject) => {
        console.log('uploadCallback promise')
        console.log('file', file)
        const dataObject = {
          file,
          resolve,
          reject
        }
        console.log('dataObject', dataObject)
        Meteor.call('uploadToDropbox', dataObject, function (error, result) {
          console.log('uploadToDropbox callback')
          if (error) {
            console.log('error', error)
          }
          if (result) {
            console.log('result', result)
          }
        })
      }
    )
  }

In my dataObject I am getting everything as needed. Here is what the console logs

uploadCallback promise
file File {name: "nodejs-2560x1440.png", lastModified: 1485410804857, lastModifiedDate: Thu Jan 26 2017 10:06:44 GMT+0400 (+04), webkitRelativePath: "", size: 1699460…}
dataObject Object {file: File}
uploadToDropbox callback

So everything seems to be ok here.

And here is my server code

import { Meteor } from 'meteor/meteor'
import Dropbox from 'dropbox'

console.log('dropbox settings', Meteor.settings.dropbox)
const dbx = new Dropbox({accessToken: Meteor.settings.dropbox.accessToken})

Meteor.methods({
  'uploadToDropbox': function (dataObject) {
    console.log('dataObject', dataObject)
    const { file } = dataObject
    console.log('file', file)
    const { resolve, reject } = dataObject
    console.log('resolve', resolve)
    console.log('reject', reject)
    dbx.filesUpload({path: '/' + file.name, contents: file})
      .then(function (response) {
        console.log(response)
        resolve({ data: { link: 'http://dummy_image_src.com' } })
      })
      .catch(function (error) {
        console.error(error)
        reject('some error')
      })
    return false
  }
})

The problem is here. dataObject is being passed almost empty
This is what the server logs

I20170217-11:44:36.141(4)? dataObject { file: {} }
I20170217-11:44:36.143(4)? file {}
I20170217-11:44:36.143(4)? resolve undefined
I20170217-11:44:36.144(4)? reject undefined
W20170217-11:44:36.371(4)? (STDERR) [TypeError: first argument must be a string or Buffer]

So why is this happening?


#2

Functions and so callbacks are not EJSONable, so this:

const dataObject = {
  file,
  resolve,
  reject
}

can’t be passed to to a method.


#3

Hi Rob!
Thanks for your reply.
It explains why the resolve and reject are not passed. But what do you think about the file? Probably it should be already uploaded to the server so that a server method can work on it, what do you think?


#4

The full object is truncated in the console.log - it may contain methods which cause the entire object to be dropped from conversion to EJSON. Hard to be sure what’s happening here - especially as the dropbox API docs don’t seem to be that good.

However, given that you need to pass an access token to dropbox, I’d be putting all this on the server, so it’s hidden from the client.


#5

Hi Rob!
After some research and with your very dear help this is what my code looks like now

This is the client

uploadCallback (file) {
    // TODO: Integrate dropbox with its SDK
    // TODO: Pass the link to the editor
    console.log('file', file)
    this.getBase64(file, this)
  }
  getBase64 (file, self) {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = function () {
      console.log('reader.result', reader.result)
      self.sendFileToServer(reader.result)
    }
    reader.onerror = function (error) {
      console.log('Error: ', error)
    }
  }
  sendFileToServer (base64File) {
    return new Promise(
      (resolve, reject) => {
        console.log('uploadCallback promise')
        Meteor.call('uploadToDropbox', base64File, function (error, result) {
          console.log('uploadToDropbox callback')
          if (error) {
            console.log('error', error)
          }
          if (result) {
            console.log('result', result)
          }
        })
      }
    )
  }

And on the server

import { Meteor } from 'meteor/meteor'
import Dropbox from 'dropbox'
// import atob from 'atob'
import FileAPI from 'file-api'

const { File } = FileAPI

console.log('dropbox settings', Meteor.settings.dropbox)
const dbx = new Dropbox({accessToken: Meteor.settings.dropbox.accessToken})

Meteor.methods({
  'uploadToDropbox': function (base64File) {
    console.log('base64File', base64File.slice(5))
    const b64 = base64File.split(',')
    const name = `${Math.random().toString(36).slice(-5)}.png`
    const file = new File({buffer: new Buffer(b64[1]), name, type: 'image/png'})
    console.log('file', file)
    dbx.filesUpload({path: '/' + file.name, contents: file.buffer})
      .then(function (response) {
        console.log(response)
      })
      .catch(function (error) {
        console.error('dropbox error', error)
      })
    return false
  }
})

Basically I am converting the file to base64 and then sending it to the method and in the backend I convert it back to a file and send it to dropbox. Or at least that’s what I intend to do.
And the file successfully gets the dropbox. I get the success response like this

{ name: 'uerk9.png',
I20170221-16:59:13.190(4)?   path_lower: '/uerk9.png',
I20170221-16:59:13.191(4)?   path_display: '/uerk9.png',
I20170221-16:59:13.191(4)?   id: 'id:oG8Il4LqaSAAAAAAAAAAAw',
I20170221-16:59:13.192(4)?   client_modified: '2017-02-21T12:59:12Z',
I20170221-16:59:13.192(4)?   server_modified: '2017-02-21T12:59:12Z',
I20170221-16:59:13.193(4)?   rev: '153c8973b',
I20170221-16:59:13.193(4)?   size: 349904,
I20170221-16:59:13.193(4)?   content_hash: 'a00a09d85b5c2cfd8663444af78b9ba93d03402b9b2f5c0066fa013f870b8cb2' }

And I can see the file in my dropbox. However the image itself is empty. Do you have any idea what may be the case here?


#6

I’ve never tried this, so don’t feel qualified to comment, other than to ask if you’ve compared the content of the uploaded file vs the original?