如何在meteor中将变量从服务器发送到客户端? [英] How to send a variable from server to client in meteor?

查看:38
本文介绍了如何在meteor中将变量从服务器发送到客户端?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有文本输入和按钮的页面.当我将指向 youtube 视频的链接插入文本字段并按下按钮时 - 视频下载到本地文件夹中.

I have a page with text input and a button. When I insert link to youtube video into text field and press the button - video downloads into the local folder.

问题:如何将下载视频的本地副本链接发送回客户端?

The problem: how can I send link to local copy of the downloaded video back to the client?

更一般的问题:如何将变量从服务器发送到客户端(此变量是临时的,不会存储在任何地方)?

More general question: How can I send a variable from server to client (this variable is temporary and is not going to be stored anywhere) ?

我现在拥有的代码:

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 的方法中处理异步函数和 (b) 使用 youtube-dl 包.

The answer to the question splits into 2 parts: (a) handling async functions inside Meteor's methods and (b) using youtube-dl package.

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

There are basically 2+ ways to work with async functions inside Meteor's methods: using future and using wrapAsync. If you look into Meteor's sources, you'll see that wrapAsync itself using future: https://github.com/meteor/meteor/blob/master/packages/meteor/helpers.js#L90. You can also use fibers directly, but it is not recommended.

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

Below are generic examples how to use them:

'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().

You may also want look to Meteor.bindEnvironment() and future.resolver() for more complex cases.

Christian FritzwrapAsync 的使用提供了正确的模式,但是,在 2 年内从提出最初的问题开始,youtube-dl 包的 API 已更改.

Christian Fritz provided correct pattern for wrapAsync usage, however, during 2 years starting from the time the initial question was asked, the API of youtube-dl package has changed.

由于 API 的变化,如果你运行他的代码,服务器会抛出在其控制台中可见的异常:

Because of changes in API, if you run his code, the server throws the exception visible in its console:

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

并且 Meteor 返回给客户端 undefined 值:

And Meteor returns to client undefined value:

here is the path: undefined

下面的代码正在运行(只需将 downloadDir 替换为您的路径)并将文件名返回给客户端:

The code below is working (just replace downloadDir with your path) and returning filename to the client:

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() 方法.

Current API does not allow to get youtube's filename when saving the file. If you want to save the file with the youtube's filename (as provided in initial question), you need to use getInfo() method of youtube-dl package.

这篇关于如何在meteor中将变量从服务器发送到客户端?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆