如何发送一个variables从服务器到客户端meteor?

我有一个文本input和一个button的页面。 当我将链接插入YouTubevideo到文本字段,然后按下button – video下载到本地文件夹。

问题:我怎么能发送链接到本地​​副本的下载video回客户端?

更一般的问题:我如何发送一个variables从服务器到客户端(这个variables是临时的,不会被存储在任何地方)?

我现在的代码是:

客户端代码

if (Meteor.isClient) { Path = new Meteor.Collection("path"); Meteor.subscribe("path"); Template.hello.events( { 'submit .form' : function() { var link = document.getElementById("youtube-url").value; Meteor.call('download', link); event.preventDefault(); } } ); } 

服务器代码('收集'部分不工作)

 if (Meteor.isServer) { Meteor.startup(function () { Meteor.methods({ download: function (link) { var youtubedl = Npm.require('youtube-dl'); var Fiber = Npm.require("fibers"); var dl = youtubedl.download(link, './videos'); // called when youtube-dl finishes dl.on('end', function(data) { console.log('\nDownload finished!'); Fiber(function() { Path = new Meteor.Collection("path"); Path.insert({path: './videos/' + data.filename}); }) }); } }); }); } 

谢谢!

问题的答案分为两部分:(a)处理Meteor方法中的asynchronous函数,(b)使用youtube-dl包。

Meteor方法中的asynchronous函数

基本上有2种方法可以在Meteor的方法中使用asynchronous函数:使用futurewrapAsync 。 如果你看看meteor的来源,你会看到使用future wrapAsync本身: https : //github.com/meteor/meteor/blob/master/packages/meteor/helpers.js#L90 。 您也可以直接使用fibers ,但不推荐使用 。

以下是如何使用它们的通用示例:

 'use strict'; if (Meteor.isClient) { Template.methods.events({ 'click #btnAsync' : function() { console.log('Meteor.call(asyncMethod)'); Meteor.call('asyncMethod', 1000, function(error, result) { if (error) { console.log('Meteor.call(asyncMethod): error:', error); } else { console.log('Meteor.call(asyncMethod): result:', result); } }); }, 'click #btnFuture' : function() { console.log('Meteor.call(futureMethod)'); Meteor.call('futureMethod', 1000, function(error, result) { if (error) { console.log('Meteor.call(futureMethod): error:', error); } else { console.log('Meteor.call(futureMethod): result:', result); } }); }, 'click #btnFiber' : function() { console.log('Meteor.call(fiberMethod)'); Meteor.call('fiberMethod', 1000, function(error, result) { if (error) { console.log('Meteor.call(fiberMethod): error:', error); } else { console.log('Meteor.call(fiberMethod): result:', result); } }); } }); } if (Meteor.isServer) { var demoFunction = function(duration, callback) { console.log('asyncDemoFunction: enter.'); setTimeout(function() { console.log('asyncDemoFunction: finish.'); callback(null, { result: 'this is result' }); }, duration); console.log('asyncDemoFunction: exit.'); }; var asyncDemoFunction = Meteor.wrapAsync(demoFunction); var futureDemoFunction = function(duration) { var Future = Npm.require('fibers/future'); var future = new Future(); demoFunction(duration, function(error, result) { if (error) { future.throw(error); } else { future.return(result); } }); return future.wait(); }; var fiberDemoFunction = function(duration) { var Fiber = Npm.require('fibers'); var fiber = Fiber.current; demoFunction(duration, function(error, result) { if (error) { fiber.throwInto(new Meteor.Error(error)); } else { fiber.run(result); } }); return Fiber.yield(); }; Meteor.methods({ asyncMethod: function (duration) { return asyncDemoFunction(duration); }, futureMethod: function (duration) { return futureDemoFunction(duration); }, fiberMethod: function (duration) { return fiberDemoFunction(duration); } }); } 

你可能也想看看Meteor.bindEnvironment()future.resolver()更复杂的情况。

Christian Fritz为wrapAsync使用提供了正确的模式,然而,从最初的问题开始的两年内, youtube-dl软件包的API已经发生了变化。

使用youtube-dl软件包

由于API的更改,如果您运行其代码,则服务器会在其控制台中引发可见的exception:

 Exception while invoking method 'download' TypeError: Object function (videoUrl, args, options) { ... } has no method 'download' 

meteor返回给客户端undefined值:

 here is the path: undefined 

下面的代码正在工作(只需用您的pathreplacedownloadDir)并返回文件名到客户端:

 here is the path: test.mp4 

文件index.html

 <head> <title>meteor-methods</title> </head> <body> {{> hello}} </body> <template name="hello"> <form> <input type="text" id="youtube-url" value="https://www.youtube.com/watch?v=alIq_wG9FNk"> <input type="button" id="downloadBtn" value="Download by click"> <input type="submit" value="Download by submit"> </form> </template> 

文件index.js

 'use strict'; if (Meteor.isClient) { //Path = new Meteor.Collection("path"); //Meteor.subscribe("path"); Template.hello.events( { 'submit .form, click #downloadBtn' : function() { var link = document.getElementById("youtube-url").value; //Meteor.call('download', link); Meteor.call('download', link, function(err, path) { if (err) { console.log('Error:', err); } else { console.log("here is the path:", path); } }); event.preventDefault(); } } ); } if (Meteor.isServer) { var fs = Npm.require('fs'); var youtubedl = Npm.require('youtube-dl'); var downloadSync = Meteor.wrapAsync(function(link, callback) { var fname = 'test.mp4'; // by default it will be downloaded to // <project-root>/.meteor/local/build/programs/server/ var downloadDir = './'; console.log('\nStarting download...'); // var dl = youtubedl.download(link, './videos'); var dl = youtubedl(link, [], []); dl.on('info', function(info) { console.log('\nDownload started: ' + info._filename); }); // dl.on('end', function(data) { dl.on('end', function() { console.log('\nDownload finished!'); //callback(null, './videos/' + data.filename); callback(null, fname); }); dl.on('error', function(error) { console.log('\nDownload error:', error); callback(new Meteor.Error(error.message) ); }); dl.pipe(fs.createWriteStream(downloadDir + fname)); }); Meteor.methods({ download: function (link) { return downloadSync(link); } }); } 

当前的API不允许在保存文件时获取youtube的文件名。 如果你想用youtube的文件名保存文件(如第一个问题所提供的),你需要使用youtube-dl软件包的getInfo()方法。

你可以使用这个小包装: https : //atmosphere.meteor.com/package/client-call 。 它允许从服务器调用客户端方法,方式与Meteor.methods相反。

我觉得如果你刚从方法调用中返回你想要的path,会更容易。 所有你需要做的就是让YouTube下载同步 – 这就是meteor的做事方式。

这应该工作:

 if (Meteor.isServer) { var youtubedl = Npm.require('youtube-dl'); var sync = Meteor.wrapAsync(function(url, callback) { var dl = youtubedl.download(link, './videos'); dl.on('end', function(data) { console.log('\nDownload finished!'); callback(null, './videos/' + data.filename); }); }); Meteor.methods({ download: function (link) { return sync(link); } }); } 

然后,在客户端上,使用:

 Meteor.call('download', link, function(err, path) { console.log("here is the path:", path); }); 

您必须在方法定义中使用asynchronousFuture,如本答案所述 。 然后,只有在asynchronous下载操作完成之后,您才能够等待回拨到客户端