What's the optimal way to execute a nodejs script from golang, that returns a string, and then communicate that string back to a golang variable?

huangapple go评论116阅读模式
英文:

What's the optimal way to execute a nodejs script from golang, that returns a string, and then communicate that string back to a golang variable?

问题

我目前正在使用os/execStdout在Golang端进行操作,并使用console.log("string")在Node.js端进行操作。

基本上,我需要生成一个字符串,但只能在Node.js中完成,而我的大部分代码都是用Golang编写的,所以我试图使我的代码中的这个小部分尽可能无缝、安全和可靠,但是对于将如此重要的部分放在"console.log"和从shell输出中读取上,我有些不安。

简而言之:我想知道是否存在比console.log + shell输出更好、更标准的通信方式,或者这已经足够优化了?

哦,还有,我程序的这个特定部分的功能是使用markdown-it将一个Markdown文本文件转换为HTML。

一些想法:

  • 通过HTTP通信(将数据/字符串发送到Golang的HTTP监听器)
  • 通过文件系统通信(将字符串写入临时文件,并用Golang读取)
  • 通过"类似于HTTP但特定于本地应用程序数据共享的东西"进行通信

P.S.

我不能使用otto,因为markdown-it不能在那里运行。

实际代码:

parser.go

package main

import (
	"os"
	"os/exec"
	"fmt"
	"bytes"
)

func main() {
    cmd := "node"
    args := []string{"parser.js", "/home/user1/dev/current/wikis/Bob's Pain/markup/index.md"}
    process := exec.Command(cmd, args...)
    stdin, err := process.StdinPipe()
    if err != nil {
        fmt.Println(err)
    }
    defer stdin.Close()
    buf := new(bytes.Buffer) // 这里存储了Node.js的输出
    process.Stdout = buf
    process.Stderr = os.Stderr

    if err = process.Start(); err != nil {
        fmt.Println("An error occured: ", err) 
    }

    process.Wait()
    fmt.Println("Generated string:", buf)
}

parser.js

var md = require('markdown-it')();
var yaml = require('js-yaml');
var fs = require('fs');

if (process.argv.length < 3) {
  console.log('Usage: node ' + process.argv[1] + ' FILENAME');
  process.exit(1);
}

var filename = process.argv[2];
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) {
  	throw err;
  }
  parse(data)
});

function parse(data) {
	data = data.split("---")
	yamlData = data[1];
	markData = data[2];
	y = yamlProcess(yamlData);
	markData = "# "+y.title+"\n\n"+markData
	html = markdownToHTML(markData);
	console.log(html) // 将数据发送回Golang
}

function yamlProcess(data) {
	try {
	  var doc = yaml.safeLoad(data);
	  return doc;
	} catch (e) {
	  console.log(e);
	  return {};
	}
}

function markdownToHTML(data) {
	return md.render(data);
}
英文:

I'm currently doing it with os/exec and Stdout on golang's side, and console.log(&quot;string&quot;) on nodejs's side.

Basically I need to generate a string but can only do so within nodejs but the majority of my code is in golang, so I'm trying to make this little blip in my code as seamless, secure, and reliable as possible and I'm a little uneasy about resting such an important part of my program on "console.log" and reading from shell output.

In short: I'm wondering if there exists a better and more standard communication line between my node and go code then console.log + shell output, or is that perhaps optimal enough?

Oh and the function of this particular part of my program is to take a markdown text file and convert it to HTML using markdown-it.

Some ideas:

  • Communicate through HTTP (send the data/string to a golang http listener)
  • Communicate through the filesystem (write the string to a temporary file and read it with golang)
  • Communicate through "something similiar to HTTP but specific to local application data sharing"

P.S.

I can't use otto, since markdown-it doesn't run there.

Actual code:

parser.go

package main

import (
	&quot;os&quot;
	&quot;os/exec&quot;
	&quot;fmt&quot;
	&quot;bytes&quot;
)

func main() {
    cmd := &quot;node&quot;
    args := []string{&quot;parser.js&quot;, &quot;/home/user1/dev/current/wikis/Bob&#39;s Pain/markup/index.md&quot;}
    process := exec.Command(cmd, args...)
    stdin, err := process.StdinPipe()
    if err != nil {
        fmt.Println(err)
    }
    defer stdin.Close()
    buf := new(bytes.Buffer) // THIS STORES THE NODEJS OUTPUT
    process.Stdout = buf
    process.Stderr = os.Stderr

    if err = process.Start(); err != nil {
        fmt.Println(&quot;An error occured: &quot;, err) 
    }

    process.Wait()
    fmt.Println(&quot;Generated string:&quot;, buf)
}

parser.js

var md = require(&#39;markdown-it&#39;)();
var yaml = require(&#39;js-yaml&#39;);
var fs = require(&#39;fs&#39;);

if (process.argv.length &lt; 3) {
  console.log(&#39;Usage: node &#39; + process.argv[1] + &#39; FILENAME&#39;);
  process.exit(1);
}

var filename = process.argv[2];
fs.readFile(filename, &#39;utf8&#39;, function(err, data) {
  if (err) {
  	throw err;
  }
  parse(data)
});

function parse(data) {
	data = data.split(&quot;---&quot;)
	yamlData = data[1];
	markData = data[2];
	y = yamlProcess(yamlData);
	markData = &quot;# &quot;+y.title+&quot;\n\n&quot;+markData
	html = markdownToHTML(markData);
	console.log(html) // SEND THE DATA BACK TO GOLANG
}

function yamlProcess(data) {
	try {
	  var doc = yaml.safeLoad(data);
	  return doc;
	} catch (e) {
	  console.log(e);
	  return {};
	}
}

function markdownToHTML(data) {
	return md.render(data);
}

答案1

得分: 13

使用os/exec是实现这个的最简单方法:

command := "node parser.js /path/to/some/file.md"
parts := strings.Fields(command)		
data, err := exec.Command(parts[0], parts[1:]...).Output()
if err != nil {
	panic(err)
}

output := string(data)

"output" 是从你的 NodeJS 脚本打印出来的数据。"command" 是任何命令的字符串形式。

英文:

The easiest way to do this with os/exec:

command := &quot;node parser.js /path/to/some/file.md&quot;
parts := strings.Fields(command)		
data, err := exec.Command(parts[0], parts[1:]...).Output()
if err != nil {
	panic(err)
}

output := string(data)

"output" is the data that is printed from your NodeJS script. "command" is any command as a string.

答案2

得分: 0

我以两种方式处理了类似的需求。

对于构建流水线扩展,我会编写一个Python脚本,从命令行接收参数,并将结果输出到标准输出。这是一个简单的接口,适用于“运行一次,要么全部成功要么快速失败”的使用方式。如果你的情况也是如此,我会保持现有的实现方式。

对于Web应用程序,我有一个Java服务,只用于特定的功能(在我的情况下,从自然语言字符串中识别日期Natty)。这样做的好处是,在调用时应用程序已经“预热”了,因此响应速度肯定比每次请求时启动应用程序要快。选择使用REST接口可能会带来更多的好处,例如更简单的客户端实现、监控、部署选项、在不更改客户端的情况下切换实现等。这只是更常规的做法。

英文:

I've approached similar requirement both ways.

For a build pipeline extension, I'd write a Python script that takes arguments from command line and outputs results to stdout. It's a simple interface, for a "run once", "everything succeeds otherwise fail fast" usage. If that's the same in your case, I'd keep the implementation as-is.

For a web application, I had Java service for just a specific function (in my case, Natty date recognition from a natural language string). This has the benefit that the application is already "warmed up" at the time of the call, and will definitely respond faster rather than booting up each time the request comes in. Going with a rest interface will probably reveal more benefits over time - e.g. simpler client implementation, monitoring, deployment options, switch implementation without changing clients, etc. It's just more conventional this way.

huangapple
  • 本文由 发表于 2015年10月12日 01:44:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/33068128.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定