はじめに
TWSNMPシリーズを開発している時、Go言語で開発したプログラムの中でユーザーが入力した何等かのスクリプトを実行して結果をGo言語側に戻した場面がありました。
その時使ったottoというパッケージ
の紹介です。
インストール
$ go get github.com/robertkrimen/otto/otto
サンプルプログラム
ottoのGitHUBのトップページにあるサンプルを、まとめて実行可能にしたものです。
main.go
package main
import (
"log"
"github.com/robertkrimen/otto"
)
func main() {
// JavaScript仮想マシンの作成
vm := otto.New()
// スクリプトの実行
vm.Run(`
abc = 2 + 2;
console.log("The value of abc is " + abc); // 4
`)
// 変数をGo言語からJavaScriptに渡す
vm.Set("def", 11)
vm.Run(`
console.log("The value of def is " + def);
// The value of def is 11
`)
// 文字列変数の場合
vm.Set("xyzzy", "Nothing happens.")
vm.Run(`
console.log(xyzzy.length); // 16
`)
// JavaScriptの実行結果をGo言語で受け取る
value, _ := vm.Run("xyzzy.length")
{
// value is an int64 with a value of 16
l, _ := value.ToInteger()
log.Println(l)
}
// エラー処理
value, err := vm.Run("abcdefghijlmnopqrstuvwxyz.length")
if err != nil {
// err = ReferenceError: abcdefghijlmnopqrstuvwxyz is not defined
// If there is an error, then value.IsUndefined() is true
log.Println(err, value.IsUndefined())
}
// 関数の登録
vm.Set("sayHello", func(call otto.FunctionCall) otto.Value {
log.Printf("Hello, %s.\n", call.Argument(0).String())
return otto.Value{}
})
vm.Set("twoPlus", func(call otto.FunctionCall) otto.Value {
right, _ := call.Argument(0).ToInteger()
result, _ := vm.ToValue(2 + right)
return result
})
// 関数の実行
result, _ := vm.Run(`
sayHello("Xyzzy"); // Hello, Xyzzy.
sayHello(); // Hello, undefined
result = twoPlus(2.0); // 4
`)
log.Println(result)
}
# 実行結果
```terminal
$go run main.go
The value of abc is 4
The value of def is 11
16
2024/10/08 07:16:54 16
2024/10/08 07:16:54 ReferenceError: 'abcdefghijlmnopqrstuvwxyz' is not defined true
2024/10/08 07:16:54 Hello, Xyzzy.
2024/10/08 07:16:54 Hello, undefined.
2024/10/08 07:16:54 4
余談
TWSNMP FC/FKではポーリングの結果を判定するために使っています。
Go言語の処理で取得した値をJavaScriptの変数に渡して判定しています。gNMIのように取得した値がJSONの場合には、otto側でパースできるので便利です。
のような感じです。
この機能で、より複雑な判定ができるようになっています。