tyler-johnson / stripe-meteor

A Meteor package containing Stripe.js, Node-Stripe, and Stripe Checkout.
https://atmospherejs.com/mrgalaxy/stripe
150 stars 44 forks source link

Meteor code can't exist in callbacks provided to Stripe, and Fiber doesn't exist? #10

Closed faceyspacey closed 11 years ago

faceyspacey commented 11 years ago

The callbacks I'm providing can't use Meteor code. Other people on stackoverflow are wrapping such code in Fibers, but Fiber isn't defined for me and I can't seem to be able to get it defined, i.e. with npm install fibers or require statements and whatnot.

What's the typical solution here. Basically stripe is useless if you can't take the data passed to the callback and do things like store it back in your Mongo customer objects for example.

faceyspacey commented 11 years ago

Any word on how to solve this?

merrillii commented 11 years ago

faceyspace - I thought it might be helpful to let you know that I do not have problems running Meteor code within the stripe callback. Here's a snippet from my working code that stores the user's token in the user collection. Does that help?

function setupStripeKey( name, num, ccv, creditDateMonth, creditDateYear ) { console.log("Stripe Init"); Stripe.setPublishableKey(StripeKey); console.log("OK"); Stripe.createToken({ name: name, number: num, // string cvc: ccv, // string exp_month: 12,// creditDateMonth, (testing only) exp_year: 2013 // creditDateYear (testing only) }, stripeHandleResponse ); }

function stripeHandleResponse(status, response) { if (response.error) { console.log( "error setting up stripe, error = " + response.error.value ); } else {

    console.log( "stripe token id = " + response.id );

    // add the stripe token to the current user profile
    Meteor.users.update( {_id:Meteor.userId()}, {$set:{ "profile.stripe_key": response.id }} );
    console.log( "stored stripe key" );

}

}

faceyspacey commented 11 years ago

that's client side code. I'm referring to server side code where you do most of the heavy lifting like creating customers and subscriptions. Unless I'm mistaken and you can make the calls clientside too, but you don't seem to be able to.

here's my client side code: Template.editBillingInfo.events({ 'click #save-billing-info-btn' : function(){ console.log($('#user_stripe_card_token').val()); var card = { number: $('#user_card_number').val(), cvc: $('#user_card_code').val(), expMonth: $('#user_card_month').val(), expYear: $('#user_card_year').val() }; Stripe.createToken(card, handleStripeResponse);

    Router.go('myProfile');
}

});

var handleStripeResponse = function(status, response) { if (status === 200) { var stripeCardToken = response.id; Meteor.call('updateBillingInfo', stripeCardToken) } else { alert(response.error.message); //$('#new_subscription input[type=submit]').attr('disabled', false); } }

and here's my server side code:

Stripe = StripeAPI('sdfg');

Meteor.methods({ updateBillingInfo: function(stripeCardToken) { console.log('stripeCardToken', stripeCardToken); var stripeReturn = Stripe.customers.create({ card: stripeCardToken, plan: 'weekly', email: Meteor.user().emails[0].address, quantity: 1 }, function(error, result) { console.log(error, result);

        //you gotta use a fiber or something to use meteor code in async callbacks
        //Meteor.users.update(Meteor.userId(), {$set: {stripeCustomerToken: result.id}});
    });

    //in case somehow the meteor stripe library immediately returns rather than works async style
    console.log('stripeReturn', stripeReturn);
}

});

faceyspacey commented 11 years ago

got it working on the server. you need to install fibers via: npm install fibers

then in your code you need to require it like so: Fiber = Npm.require('fibers');

and then in your callbacks to stripe methods, you need to run the code in a fiber so the meteor code (such as updating collections will still work):

Meteor.methods({ updateBillingInfo: function(stripeCardToken) { var _this = this;

    var stripeReturn = Stripe.customers.create({
        card: stripeCardToken,
        email: Meteor.user().emails[0].address
    }, function(error, result) {

                   //NOW SEE HOW THE CODE THAT USES METEOR TOOLS IS PASSED TO A FIBER
                   //AND THEN EXECUTED VIA RUN()?? THATS WHAT YOU NEED TO DO IN STRIPE-METEOR
                   //SERVER CODE USED IN STRIPE METHOD CALLBACKS
        Fiber(function() {
            Meteor.users.update(_this.userId, {$set: {stripeCustomerToken: result.id}});
        }).run();

    });
}

});

merrillii commented 11 years ago

Thanks for posting that - I would have bumped into that eventually. It would be nice if this meteor package could find a way to wrap that into a more obvious way. At least it could add depends for fibers to the package.js and Npm.require to stripe_server.js?

faceyspacey commented 11 years ago

we could also rewrite some of the stripe js lib code so that callbacks before being called are passed into a fiber. and then it's fully automated.

tyler-johnson commented 11 years ago

@faceyspacey You are very close, however I do not recommend wrapping calls to a collection in Fibers. The methods are already wrapped in Fiber calls, but the async results are not and that is why it is throwing the error. Here is a better way to do this:

var stripe = StripeAPI('mykeygoeshere');  // secret stripe API key
var Future = Npm.require('fibers/future');

Meteor.methods({
updateBillingInfo: function(stripeCardToken) {
    var _this = this,
         fut = new Future();

    var stripeReturn = Stripe.customers.create({
        card: stripeCardToken,
        email: Meteor.user().emails[0].address
    }, function(error, result) {
        if (error) {
            console.error(error);
            fut.ret();
        } else fut.ret(result);
    });

    var result = fut.wait();
    Meteor.users.update(_this.userId, {$set: {stripeCustomerToken: result.id}});
}
});

Here is a link to a StackOverflow question about Meteor methods and making them async: http://stackoverflow.com/questions/12569712/meteor-calling-an-asynchronous-function-inside-a-meteor-method-and-returning-th