Meteor + FineUploader + s3 - meteor

Right now I'm using the CLIENT ONLY implementation of FineUploader in my meteor app. With how tightly Meteor is coupled with the server, it doesn't make sense to add this layer of complexity. What also doesn't make sense to me is how to go about this properly.
The FineUploader code is documented - you set an endpoint.
There are packages like https://atmospherejs.com/mrt/s3policies, but they don't work with endpoints (as far as I can tell).
There is the nodejs server example, but I haven't a clue how to use it as part of my meteor project.
What is a working way to call a method on the server,
if (Meteor.isServer) {
Meteor.methods({
's3policy': function(options) {
// use something like https://atmospherejs.com/mrt/s3policies
// or something like https://github.com/FineUploader/server-examples/blob/master/nodejs/s3/s3handler.js
}
});
}
From the client and use it in the uploader
var uploader = new qq.s3.FineUploader({
signature: {
endpoint: '/s3/signature'
// with the server side code from
// https://github.com/FineUploader/server-examples/blob/master/nodejs/s3/s3handler.js
// but this seems like it bypasses meteor's awesome
// and I don't know how to go about it
endpoint: Meteor.call('s3policy', {});
// this makes more sense to me but I'm not knowledgable enough
// about both technologies to make this work
}
});

Related

Call frontend methods from external meteor application

I am making a dockerized services-based application. Some of the services will be written in meteor, some won't.
One of the services is a registration service, where users can register for the platform.
When doing microservices, normally I do the following:
var MyService = DDP.connect(service_url);
var MyOtherService = DDP.connect(other_service_url);
var RegistrationService = DDP.connect(registration_service_url);
What I want to do is use the loginWithFacebook method. The issue is that using Meteor.loginWithFacebook on the frontend will invoke its backend methods on the main frontend server.
However, I want to invoke its backend methods on the RegistrationService server (which has the relevant packages). The reason is because I am using the Accounts.onCreateUser hook to do extra stuff, and also because I want to keep the registration service separate from the frontend.
Just for clarity, even though it is not correct, imagine I have this:
'click #facebook-login': function() {
Meteor.loginWithFacebook(data, callback)
}
However, I want the loginWithFacebook method to use the server-side methods from RegistrationService when calling the client-side method .loginWithFacebook, so I actually want to do something to the effect of the following:
'click #facebook-login': function() {
RegistrationService.loginWithFacebook(data, callback)
}
Any help on this will be greatly appreciated. Thank you!
I believe you are looking for DDP.connect. Basically underneath meteor all calls to the server from the client and all communication from the server to the client use Distributed Data Protocol. (https://www.meteor.com/ddp) As the documentation points out by default a client opens a DDP connection to the server it is loaded from. However, in your case, you'd want to use DDP.connect to connect to other servers for various different tasks, such as a registration services server for RegistrationService. (http://docs.meteor.com/#/full/ddp_connect) As a simplified example you'll be looking to do something like this:
if (Meteor.isClient) {
var registrationServices = DDP.connect("http://your.registrationservices.com:3000");
Template.registerSomething.events({
'click #facebook-login': function(){
registrationServices.call('loginWithFacebook', data, function(error, results){ ... }); // registration services points to a different service from your default.
}
});
}
Don't forget that you can also have various DDP.connect's to your various microservices. These are akin to web service connections in other applications.
You can maybe achieve connection through your other service by specifying the service's remote connection to Accounts and Meteor.users:
var RegistrationService = DDP.connect(registration_service_url);
Accounts.connection = RegistrationService;
Meteor.users = new Meteor.Collection('users',{connection: RegistrationService});
Then would call Meteor.loginWithFacebook and it should use the other app's methods for logging in.

Durandal and ASP.Net - Interrupting the routing

I am using Durandal in an asp.net application which is all working well. What I would like to achieve is to put something into the routing of it so if required I can stop the current route and redirect.
The reason for this is I want to permission base some routes where the permissions are stored in a database. So during the routing I want to check the route, use web api accordingly to check if they have access to that route and redirect if so OR use a method on the viewmodel to check this and redirect accordingly. I do use the activate function on the viewmodel, I wondered if the route can be redirected here perhaps?
Has anyone done this before?
EDIT:
Following the great answer below the following is the code I eventually used on a test route to get this working. The web api function HasAccessToRoute part returns a bool:
define(['durandal/http', 'plugins/router', 'knockout', 'durandal/app'], function (http, router, ko, app) {
function viewModel() {
var self = this;
self.canActivate = function () {
return http.ajaxRequest("get", "/api/route/hasaccesstoroute?route=test")
.done(function (result) {
if (!result) {
app.showMessage("Test area cannot be accessed");
}
});
};
}
var model = new viewModel();
return model;
});
Yes, it is possible. Take a look at canActivate here. You can return a promise in your canActivate handler and fetch your authorization profiles asynchronously. Once you have the authorization profile, you can then resolve your canActivate with either true or false, accordingly. This is what we do.
Also, the routes in Durandal are client-side, not server-side. Or are you doing server-side rendering with, say, Razor? If not, then the only time you would be going out to the server, essentially, is to obtain data, usually through a RESTful Web API (although you can do this with action-based routes as well).
This is an important point since canActivate is a client-side handler.

Meteor: Anyway to use Iron Router methods to call a route with post data?

Using iron router I can currently pass query parameter data to the route by doing something like:
Router.go Router.current().path.split("?")[0] + '?searchTerm=apple'
Which appends a searchTerm to the routes current path. Then in my router file I can access the search term with: this.params.searchTerm
But what if I want to send this data to the route in the body of the request? If I do not want to affect the URL then sending data to the route over the body would be useful. Just like a post ajax request? How can I do that with Router.go or anything else iron router supports?
Basically I want to get data to my route, but I dont want to use session, or affect the url in any way. So my last option is to pass the data in the body, but how?
Meteor doesn't work with old school ajax requests.
If you really must accept ajax requests you could (ab)use server-side routes in iron-router:
this.route('serverRoute', {
where: 'server',
action: function() {
this.response.end("THIS IS A SERVER ROUTE..");
}
})
But the accepted meteor way for handling what you described, would be to use Meteor methods on the server side define methods:
Meteor.methods({
foo: function (arg1, arg2) {
doStuff(arg1, arg2);
});
Then on the client you call them like so:
Meteor.call('foo', 1, 2, function (error, result) { /* CallbackHandleingCode */ } );
This does not affect the url whatsoever, as internally meteor uses websockets for exchanging data between client and server.

Meteor client side methods

I have a Meteor.method defined on the server side (in .js in /server) and I can call it just fine (with callback) from a client-side template script.
I want to do a similar thing but would like it all to be client side so I moved the method to a client script but the result comes back as 'undefined'.
Template.showDialog.events({
'click #clickme' : function() {
Meteor.call('foo', 'ola', function(error, result) {
alert('here');
alert(result);
});
}
});
Meteor.methods({
foo: function (myarg) {
return myarg+'CLI';
}
});
See the Meteor docs, where it is explained that methods on the client are stubs, not actual methods:
If you do define a stub, when a client invokes a server method it will also run its stub in parallel. On the client, the return value of a stub is ignored. Stubs are run for their side-effects: they are intended to simulate the result of what the server's method will do, but without waiting for the round trip delay. If a stub throws an exception it will be logged to the console.
Since the result is ignored, you're seeing undefined. Don't use methods on the client for this purpose. Just use a javascript function.
From the docs:
Calling methods on the client defines stub functions associated with server methods of the same name.
Basically, you need to define the method on the server side. It's also not clear why you'd want to define a method on the client and then call it on the client as well. Would a vanilla javascript function not do the job perfectly well?
Apologies if I've misunderstood what you're trying to achieve here.

Connect to different Hubs on different pages

I am building a single page app which uses sammy.js, knockout.js and SignalR. The main page (index.html) loads additional html pages into a div based upon the client side route.
I have 2 SignalR hubs, one is connected to by the initial page for server side push data and this works fine. However one of the pages which are loaded when the user navigates to it should also connect to a different hub.
In the main page I am doing the following:
window.hubReady = $.connection.hub.start()
var hub1 = $.connection.hub1;
hub1.updateReceived = function () {
alert('data from server');
}
window.hubReady.done(function() {
hub1.server.start();
});
In the second page I have:
var hub2 = $.connection.hub2;
hub2.updateReceived = function () {
alert('data from server');
}
window.hubReady.done(function() {
hub2.server.start();
});
However I never receive any updates in the second page.
Any idea where I am going wrong?
In order to receive updates from a hub you must have at least 1 client side function declared for that hub when the connection is started. Judging from the libraries you are using I'm assuming you have a single page application and therefore don't instantiate your hub2 data until the connection has already started.
So an easy fix would be to just declare a hub2 client side function alongside your hub1 client side function before start is called. If you want to add more client side functions after the connection has started you'll have to use the .on method.
AKA:
hub2.on("updateReceived", function () {
alert("data from server");
});
I have created a lib called SignalR.EventAggregatorProxy.
it proxies between server side domain events and client side code. Its designed with MVVM and SPA in mind and takes care of all the hub plumbing. Check the wiki for how to set it up.
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki
once its configured all you need to subscribe to a event is
ViewModel = function() {
signalR.eventAggregator.subscribe(MyApp.Events.TestEvent, this.onTestEvent, this);
};
MyApp.Events.TestEvent corresponds to a server side .NET event. You can also constraint which event should go to which usera

Resources