gojs

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2026 License: MIT Imports: 15 Imported by: 0

README

gojs

Go Reference Go Report Card License Go Version

A high-performance JavaScript runtime library based on goja, designed for Go applications. Features script caching, concurrent execution, and rich built-in libraries.

一个基于 goja 的高性能 JavaScript 运行时库,专为 Go 应用程序设计。支持脚本缓存、并发执行、丰富的内置库。

English | 中文


Features

  • High Performance: Based on goja engine with script pre-compilation and caching support
  • Concurrent Safe: Supports multi-goroutine concurrent script execution
  • Rich Built-in Libraries: Integrated lodash, moment.js, CryptoJS, xml-js, formulajs, etc.
  • Buffer Extensions: Supports BigInt64/BigUInt64 read/write operations
  • CRC Checksum: Supports CRC16/CRC32/CRC64/Modbus CRC checksums
  • Compression: Supports gzip and zip decompression
  • Encoding Conversion: Supports iconv encoding conversion
  • Logging Integration: Supports structured logging output

Installation

go get github.com/felix-186/gojs

Quick Start

Basic Usage
package main

import (
    "fmt"
    "github.com/felix-186/gojs"
)

func main() {
    script := `
    function handler(input) {
        return _.map(input, function(x) { return x * 2; });
    }
    `

    result, err := gojs.Run(script, []interface{}{1, 2, 3, 4, 5}...)
    if err != nil {
        panic(err)
    }
    fmt.Println(result.Export()) // [2, 4, 6, 8, 10]
}
Using Cache
// Cache script with ID
result, err := gojs.RunByIdAndScript("my-script-id", script, args...)

// Execute cached script
_, err := gojs.GetJsVm("my-script", script)
result, err := gojs.RunById("my-script", args...)

API Reference

Core Functions
Function Description
Run(script string, values ...interface{}) Execute JavaScript script
RunByIdAndScript(id, script string, values ...interface{}) Execute with ID caching
RunById(id string, values ...interface{}) Execute cached script
GetJsVm(id, script string) Get or create VM instance
GetVm() Create new VM instance
GetVmCallback(cb Callback) Create VM with custom configuration
Buffer Operations
Function Description
BufferToBytes(bufferVal goja.Value) Convert JS Buffer to Go bytes
BytesToBuffer(vm *goja.Runtime, bs []byte) Convert Go bytes to JS Buffer
Utility Functions
Function Description
IsValid(value goja.Value) Check if value is valid (not nil/undefined/NaN/null)
IsBuffer(value goja.Value) Check if value is a Buffer

Built-in Libraries

Library Global Variable Description
lodash _ Utility library
moment.js moment Date/time handling
CryptoJS CryptoJS Encryption library
xml-js xmlJs XML to JSON conversion
formulajs formulajs Excel formula library
iconv-lite iconv Encoding conversion
pako pako zlib compression
forge forge Crypto utilities
Buffer Extensions
// BigInt64 read/write
buffer.writeBigInt64LE(value, offset);
buffer.writeBigInt64BE(value, offset);
buffer.readBigInt64LE(offset);
buffer.readBigInt64BE(offset);

// BigUInt64 read/write
buffer.writeBigUInt64LE(value, offset);
buffer.writeBigUInt64BE(value, offset);
buffer.readBigUInt64LE(offset);
buffer.readBigUInt64BE(offset);
CRC Checksum
crc.checksum16(buffer, poly);      // CRC16
crc.checksum32(buffer, poly);      // CRC32
crc.checksum64(buffer, poly);      // CRC64
crc.checksumModbus(buffer);        // Modbus CRC
API Library
apilib.SleepMill(1000);           // Sleep (milliseconds)
apilib.UnGzip(gzipData);           // Decompress gzip
apilib.Unzip(zipData);             // Decompress zip
Logging
logger.Debug("debug message", 1);
logger.Info("info message", 2);
logger.Warn("warn message", 3);
logger.Error("error message", 4);

Examples

Data Processing
script := `
function handler(data) {
    return _.map(data, function(item) {
        return {
            id: item.id,
            value: item.value * 2,
            timestamp: moment().format('YYYY-MM-DD HH:mm:ss')
        };
    });
}
`

data := []map[string]interface{}{
    {"id": "1", "value": 10},
    {"id": "2", "value": 20},
}

result, err := gojs.Run(script, data)
Encryption
script := `
function handler(text) {
    var encrypted = CryptoJS.AES.encrypt(text, "secret-key").toString();
    var decrypted = CryptoJS.AES.decrypt(encrypted, "secret-key").toString(CryptoJS.enc.Utf8);
    return { encrypted: encrypted, decrypted: decrypted };
}
`
XML Conversion
script := `
function handler(xmlString) {
    return xmlJs.xml2json(xmlString, { compact: true });
}
`

Performance

Script Caching
// First execution compiles and caches
gojs.RunByIdAndScript("script-1", script, data...)

// Subsequent executions use cache
gojs.RunById("script-1", data...)
Concurrent Execution
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
    wg.Add(1)
    go func(idx int) {
        defer wg.Done()
        result, _ := gojs.RunById("script-1", idx)
    }(i)
}
wg.Wait()

Error Codes

Code Description
100040001 Failed to set object in VM
100040002 Failed to run pre-compiled program
100040003 Failed to run script
100040004 Handler function not found
100040005 Failed to call handler function
100040006 VM not found
100040007 Parameter is not Object
100040008 Buffer not found
100040009 Parameter is not ArrayBuffer
100040010 Offset or length exceeds buffer size
100040011 Buffer not loaded
100040012 Buffer.from method not loaded
100040013 Buffer.from is not FunctionCall

Testing

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

# Run benchmarks
go test -bench=. ./...

Dependencies

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License


特性

  • 高性能: 基于 goja 引擎,支持脚本预编译和缓存
  • 并发安全: 支持多 goroutine 并发执行脚本
  • 内置库丰富: 集成 lodash、moment.js、CryptoJS、xml-js、formulajs 等常用库
  • Buffer 扩展: 支持 BigInt64/BigUInt64 读写操作
  • CRC 校验: 支持 CRC16/CRC32/CRC64/Modbus CRC 校验
  • 压缩解压: 支持 gzip、zip 格式的压缩解压
  • 编码转换: 支持 iconv 编码转换
  • 日志集成: 支持结构化日志输出

安装

go get github.com/felix-186/gojs

快速开始

基本使用
package main

import (
    "fmt"
    "github.com/felix-186/gojs"
)

func main() {
    script := `
    function handler(input) {
        return _.map(input, function(x) { return x * 2; });
    }
    `

    result, err := gojs.Run(script, []interface{}{1, 2, 3, 4, 5}...)
    if err != nil {
        panic(err)
    }
    fmt.Println(result.Export()) // [2, 4, 6, 8, 10]
}
使用缓存执行
// 使用 ID 缓存脚本
result, err := gojs.RunByIdAndScript("my-script-id", script, args...)

// 使用已有缓存执行
_, err := gojs.GetJsVm("my-script", script)
result, err := gojs.RunById("my-script", args...)

API 文档

核心函数
函数 说明
Run(script string, values ...interface{}) 执行 JavaScript 脚本
RunByIdAndScript(id, script string, values ...interface{}) 使用指定 ID 执行脚本,支持缓存
RunById(id string, values ...interface{}) 使用已缓存的脚本执行
GetJsVm(id, script string) 获取或创建 JavaScript 虚拟机实例
GetVm() 创建新的 JavaScript 虚拟机实例
GetVmCallback(cb Callback) 创建虚拟机并执行回调函数进行自定义配置
Buffer 操作
函数 说明
BufferToBytes(bufferVal goja.Value) 将 JavaScript Buffer 对象转换为 Go 字节切片
BytesToBuffer(vm *goja.Runtime, bs []byte) 将 Go 字节切片转换为 JavaScript Buffer 对象
工具函数
函数 说明
IsValid(value goja.Value) 判断 JavaScript 值是否有效(非 nil、undefined、NaN、null)
IsBuffer(value goja.Value) 判断值是否为 Buffer 对象

内置库

库名 全局变量 说明
lodash _ 实用工具库
moment.js moment 日期时间处理
CryptoJS CryptoJS 加密库
xml-js xmlJs XML 与 JSON 转换
formulajs formulajs Excel 公式库
iconv-lite iconv 编码转换
pako pako zlib 压缩
forge forge 加密工具库
Buffer 扩展方法
// BigInt64 读写
buffer.writeBigInt64LE(value, offset);
buffer.writeBigInt64BE(value, offset);
buffer.readBigInt64LE(offset);
buffer.readBigInt64BE(offset);

// BigUInt64 读写
buffer.writeBigUInt64LE(value, offset);
buffer.writeBigUInt64BE(value, offset);
buffer.readBigUInt64LE(offset);
buffer.readBigUInt64BE(offset);
CRC 校验
crc.checksum16(buffer, poly);      // CRC16
crc.checksum32(buffer, poly);      // CRC32
crc.checksum64(buffer, poly);      // CRC64
crc.checksumModbus(buffer);        // Modbus CRC
API 库
apilib.SleepMill(1000);           // 休眠(毫秒)
apilib.UnGzip(gzipData);           // 解压 gzip
apilib.Unzip(zipData);             // 解压 zip
日志
logger.Debug("debug message", 1);
logger.Info("info message", 2);
logger.Warn("warn message", 3);
logger.Error("error message", 4);

示例

数据处理
script := `
function handler(data) {
    return _.map(data, function(item) {
        return {
            id: item.id,
            value: item.value * 2,
            timestamp: moment().format('YYYY-MM-DD HH:mm:ss')
        };
    });
}
`

data := []map[string]interface{}{
    {"id": "1", "value": 10},
    {"id": "2", "value": 20},
}

result, err := gojs.Run(script, data)
加密解密
script := `
function handler(text) {
    var encrypted = CryptoJS.AES.encrypt(text, "secret-key").toString();
    var decrypted = CryptoJS.AES.decrypt(encrypted, "secret-key").toString(CryptoJS.enc.Utf8);
    return { encrypted: encrypted, decrypted: decrypted };
}
`
XML 转换
script := `
function handler(xmlString) {
    return xmlJs.xml2json(xmlString, { compact: true });
}
`

性能优化

脚本缓存
// 首次执行会编译并缓存
gojs.RunByIdAndScript("script-1", script, data...)

// 后续执行直接使用缓存
gojs.RunById("script-1", data...)
并发执行
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
    wg.Add(1)
    go func(idx int) {
        defer wg.Done()
        result, _ := gojs.RunById("script-1", idx)
    }(i)
}
wg.Wait()

错误码

错误码 说明
100040001 VM 设置对象失败
100040002 运行预编译程序失败
100040003 运行脚本失败
100040004 脚本函数 handler 未找到
100040005 调用 handler 函数失败
100040006 未找到 VM
100040007 参数格式非 Object
100040008 未找到 buffer
100040009 参数格式非 arrayBuffer
100040010 offset 或 length 超出 buffer 大小
100040011 未加载 Buffer
100040012 未加载 Buffer from 方法
100040013 Buffer from 方法类型非 FunctionCall

测试

# 运行所有测试
go test ./...

# 运行测试并显示覆盖率
go test -cover ./...

# 生成覆盖率报告
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

# 运行性能测试
go test -bench=. ./...

依赖

贡献

欢迎提交 Pull Request 参与贡献!

许可证

MIT License

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var HandlerError = errors.New400Response(100040004, "脚本函数handler未找到")

Functions

func AttachCrc

func AttachCrc(vm *goja.Runtime) error

AttachCrc 向 VM 中添加 crc 函数

func BufferToBytes

func BufferToBytes(bufferVal goja.Value) ([]byte, error)

func BytesToBuffer

func BytesToBuffer(vm *goja.Runtime, bs []byte) (goja.Value, error)

func GetVm

func GetVm() (*goja.Runtime, error)

func GetVmCallback

func GetVmCallback(cb Callback) (*goja.Runtime, error)

func IsBuffer

func IsBuffer(value goja.Value) bool

IsBuffer 判断是否为 Buffer 对象

func IsValid

func IsValid(value goja.Value) bool

IsValid 判断是否为一个有效值 如果 value 为 nil, 或者为 js 中的 undefined, null 值返回 false

func Run

func Run(script string, values ...interface{}) (goja.Value, error)
Example
script := `
	function handler(input) {
		return _.map(input, function(x) { return x * 2; });
	}
	`

result, err := Run(script, []interface{}{1, 2, 3, 4, 5}...)
if err != nil {
	fmt.Println("Error:", err)
	return
}
// Output varies based on goja's internal representation
fmt.Printf("%v\n", result.Export())

func RunById

func RunById(id string, values ...interface{}) (goja.Value, error)

func RunByIdAndScript

func RunByIdAndScript(id, script string, values ...interface{}) (goja.Value, error)
Example
script := `
	function handler(data) {
		return {
			processed: true,
			count: data.length
		};
	}
	`

result, err := RunByIdAndScript("example-script", script, []interface{}{1, 2, 3})
if err != nil {
	fmt.Println("Error:", err)
	return
}
fmt.Printf("%v\n", result.Export())

Types

type Callback

type Callback func(vm *goja.Runtime) error

type Crc16

type Crc16 struct {
	// contains filtered or unexported fields
}

func (*Crc16) Checksum

func (crc *Crc16) Checksum(data []byte, poly uint16) uint16

type Crc32

type Crc32 struct {
	// contains filtered or unexported fields
}

func (*Crc32) Checksum

func (crc *Crc32) Checksum(data []byte, poly uint32) uint32

type Crc64

type Crc64 struct {
	// contains filtered or unexported fields
}

func (*Crc64) Checksum

func (crc *Crc64) Checksum(data []byte, poly uint64) uint64

type CrcModbus

type CrcModbus struct {
}

func (CrcModbus) Checksum

func (crc CrcModbus) Checksum(data []byte) uint16

type JSvm

type JSvm struct {
	VM      *goja.Runtime
	Handler goja.Callable
	Script  string
	// contains filtered or unexported fields
}

func GetJsVm

func GetJsVm(id, script string) (*JSvm, error)

func NewJsVm

func NewJsVm(id, script string) (*JSvm, error)

func (*JSvm) SetObj

func (j *JSvm) SetObj(key string, obj interface{}) error

type ParseResult

type ParseResult struct {
	// 设备ID
	ID string `json:"id"`
	// 设备所属工作表标识
	Table string `json:"table"`
	// 子设备ID
	CID string `json:"cid"`
	// 上数时间
	Time int64 `json:"time"`
	// 数据点信息
	// key: 数据点标识
	// value: 数据点的值
	Values map[string]interface{} `json:"values"`
}

ParseResult 数据处理函数返回结果数据格式

type Parser

type Parser struct {
	IDKey     string `json:"id"`
	TableKey  string `json:"table"`
	CIDKey    string `json:"cid"`
	TimeKey   string `json:"time"`
	ValuesKey string `json:"values"`
}

func NewParser

func NewParser() *Parser

func (Parser) Parse

func (p Parser) Parse(result goja.Value) ([]ParseResult, error)

Parse 解析脚本返回值. 从返回值中解析出设备编号, 表标识, 时间和数据等信息

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL