问题:
在Meteor中,如何从客户端调用方法(传递name
(,让服务器执行一些shell命令?
方法的基本功能是:创建一个目录,然后用给定的name
克隆git-reo。
这是非常简单的东西,但流星不会这么做。我已经绕了好几个小时了。所有东西都可以在常规bash或node中工作。目前:
目录被创建->服务器重新启动->流星抛出错误,声称目录已经存在->流星删除目录->服务器重新开始
代码:
var cmd, exec, fs;
if (Meteor.isClient) {
Template.app.events({
'click button': function() {
Meteor.call('clone', "NAMEHERE", function(error, result) {
if (error) {
console.log(error);
} else {
console.log(result);
}
});
}
});
}
if (Meteor.isServer) {
fs = Npm.require('fs');
exec = Npm.require('child_process').exec;
cmd = Meteor.wrapAsync(exec);
Meteor.methods({
'clone': function(name) {
var dir;
dir = process.env.PWD + "/projects/" + name;
cmd("mkdir " + dir + "; git clone git@gitlab.com:username/" + name + ".git " + dir, Meteor.bindEnvironment(function(error, stdout, stderr) {
if (error) {
throw new Meteor.Error('error...');
} else {
console.log('done');
}
}));
return 'cloning...';
}
});
}
更新1
如果我事先手动创建文件夹,以下代码将成功克隆repo:
if (Meteor.isClient) {
Template.all.events({
'click button': function() {
Meteor.call('clone', this.name);
}
});
}
if (Meteor.isServer) {
exec = Npm.require('child_process').exec;
cmd = Meteor.wrapAsync(exec);
Meteor.methods({
'clone': function(name) {
var dir, res;
dir = process.env.PWD + "/projects/" + name;
res = cmd(git clone git@gitlab.com:username/" + name + ".git " + dir);
return res;
}
});
}
然而,如果我将"mkdir " + dir
添加到cmd
,我仍然会遇到同样的问题:
目录被创建->服务器重新启动->流星抛出错误,声称目录已经存在->流星删除目录->服务器重新开始
解决方案:
Meteor正在重新启动,因为其目录中的某些内容发生了更改(projects
(。然后在启动时重新运行该方法。这是方法调用的另一个问题。
更新1/@Rebolon的答案就是解决方案。
您的Meteor.call正常,问题似乎出在服务器端:您正确地使用wrapAsync来打包exec-npm对象,但随后您错误地使用了cmd-var:您只需要发送一个参数,如下所示:
var res = cmd("mkdir " + dir + "; git clone git@gitlab.com:username/" + name + ".git " + dir);
return res;
实际上,你的代码显示你想向客户端返回不同的信息:
- 我接到电话,命令挂起
- 命令已完成且正常或出现错误
但事实上,它无法工作,因为使用wrapAsync cmd(…(将等到它完成后再返回"Pending…"因此,客户端将只收到"挂起…"响应。
你真的需要通知客户端命令挂起,然后它就完成了吗?如果是,您可以使用状态集合来存储命令的状态(received/pending/ok/error…(,然后在您的方法中,您只需要更新集合,而在您的客户端中,只需订阅此状态集合。
你可以看看这个项目,我在服务器上使用exec(带有重试包(和一个集合来管理挂起状态:https://github.com/MeteorLyon/satis-easy
您的Meteor.call
代码不在事件的功能块中。像这样的东西应该起作用:
if (Meteor.isClient) {
Template.app.events({
'click button': function() {
Meteor.call('clone', "NAMEHERE", function(error, result) {
if (error) {
return console.log(error);
} else {
return console.log(result);
}
});
}
});
}