Help us shape the future of Go! Take the 2026 Go Developer Survey

source

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT Imports: 8 Imported by: 0

README

Source · 脚本来源模块

Go Version

Go Scripts 的脚本加载与变更监听核心接口

中文 · English · 日本語


概述

Source 模块定义了脚本来源的核心接口,为所有引擎提供统一的脚本加载和热更新能力。它包含三个核心接口、六种内置实现和多个扩展子模块。

核心接口
接口 说明
Reader 脚本加载接口,Load(ctx, key) 按键加载脚本源码
Watcher 变更监听接口,Watch(ctx, key) 返回变更通知 channel
ReadWatcher Reader + Watcher 组合接口
TransformFunc 源码变换钩子,用于解密/解压/过滤(中间件模式)
内置实现
实现 文件 热更新机制 说明
FileSource file.go mtime 轮询 本地文件系统
FileSystemSource fs.go 不支持(不可变源) 基于 io/fs.FS(embed / zip / os.DirFS)
MemSource memory.go 内嵌 channel 通知 内存存储,用于测试和注入
MultiSource multiple.go 转发子 Source 事件 多源聚合(Fallback / FirstOK)
TransformSource transform.go 透传内部源 中间件:解密/解压/过滤钩子链
CachedSource cached.go 自动失效缓存 缓存层:内存缓存 + TTL + Watch 自动失效
扩展子模块
子模块 底层库 热更新机制
s3 AWS SDK v2 ETag 比对轮询
etcd etcd clientv3 原生 Watch API
consul Consul API ModifyIndex 轮询
redis go-redis/v9 值比对轮询
http net/http CRC32 校验和比对
git go-git/v6 commit hash 比对轮询
database database/sql checksum 列比对轮询

接口定义

// Reader - 脚本加载
type Reader interface {
    Load(ctx context.Context, key string) (code string, err error)
    Close() error
}

// Watcher - 变更监听
type Watcher interface {
    Watch(ctx context.Context, key string) (<-chan struct{}, error)
}

// ReadWatcher - 组合接口
type ReadWatcher interface {
    Reader
    Watcher
}

快速开始

package main

import (
    "context"
    "fmt"
    "os"
    "github.com/liujitcn/go-scripts/source"
)

func main() {
    ctx := context.Background()

    // 使用 FileSource
    fileSrc := source.NewFileSource()
    defer fileSrc.Close()
    code, _ := fileSrc.Load(ctx, "/path/to/script.lua")
    fmt.Println(code)

    // 使用 FileSystemSource(基于 io/fs.FS)
    // 适用于 go:embed、archive/zip、os.DirFS 等
    fsSrc, _ := source.NewFileSystemSource(os.DirFS("/scripts"))
    defer fsSrc.Close()
    code, _ = fsSrc.Load(ctx, "hello.lua")

    // 使用 MemSource
    memSrc := source.NewMemSource()
    defer memSrc.Close()
    memSrc.Set("hello.lua", `print("hello")`)
    code, _ = memSrc.Load(ctx, "hello.lua")

    // Fallback 聚合(File → Memory 回退)
    multi, _ := source.NewFallbackSource(fileSrc, memSrc)
    code, _ = multi.Load(ctx, "backup.lua")

    // CachedSource:S3 远程源 + 内存缓存
    // cached, _ := source.NewCachedSource(s3Source, source.WithTTL(5*time.Minute))
    // defer cached.Close()
    // code, _ = cached.Load(ctx, "script.lua")

    // TransformSource:解密中间件
    // decrypt := source.TransformFunc(func(key, raw string) (string, error) {
    //     return aesDecrypt(raw, secretKey)
    // })
    // transformSrc, _ := source.NewTransformSource(cached, decrypt)
    // defer transformSrc.Close()
    // code, _ = transformSrc.Load(ctx, "script.lua")
}

TransformSource 源码变换中间件

TransformSource 在 Load 之后、返回给引擎之前,对脚本源码执行可配置的变换链。

典型场景:

  • 解密:S3 / Git / DB 中存储的 AES/XXTEA 加密脚本
  • 解压:gzip / zstd 压缩的脚本
  • 过滤:去除敏感信息、编码转换
// 解密钩子
decrypt := source.TransformFunc(func(key string, raw string) (string, error) {
    return aesDecrypt(raw, secretKey)
})

// 包装 S3 Source
src, _ := source.NewTransformSource(s3Source, decrypt)

// 链式追加:解密后再解压
src, _ = src.Then(decompress)

CachedSource 缓存层

CachedSource 在远程源(S3 / DB / HTTP)之上添加内存缓存,大幅减少网络 IO。

特性:

  • 缓存命中时零网络开销
  • 支持 TTL 自动过期(WithTTL)
  • 如果远程源实现 Watcher,变更信号自动失效缓存
  • 支持手动失效(Invalidate / InvalidateAll)
// S3 + 内存缓存,TTL 5 分钟
cached, _ := source.NewCachedSource(s3Source, source.WithTTL(5*time.Minute))

// 叠加解密中间件
decrypted, _ := source.NewTransformSource(cached, decrypt)

code, _ := decrypted.Load(ctx, "script.lua")

MultiSource 聚合策略

策略 构造函数 说明
Fallback NewFallbackSource(srcs...) 按顺序尝试每个 Source,第一个成功即返回
FirstOK NewFirstOKSource(srcs...) 并发请求所有 Source,返回最先成功的结果

测试

cd source && go test -v ./...

相关文档

License

MIT License

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IdentityTransform

func IdentityTransform(_ string, raw string) (string, error)

Types

type CachedOption

type CachedOption func(*CachedSource)

CachedOption 配置 CachedSource。

func WithTTL

func WithTTL(ttl time.Duration) CachedOption

WithTTL 设置缓存条目的存活时间;零值关闭 TTL 过期。

type CachedSource

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

CachedSource 为远程 Reader 增加 MemSource 内存缓存,并可按 TTL 或 Watch 通知失效。

func NewCachedSource

func NewCachedSource(remote Reader, opts ...CachedOption) (*CachedSource, error)

NewCachedSource 为 remote 创建缓存包装;remote 不能为 nil。

func (*CachedSource) Close

func (c *CachedSource) Close() error

Close 停止后台监听并关闭远程脚本源。

func (*CachedSource) Invalidate

func (c *CachedSource) Invalidate(key string)

Invalidate 删除 key 的缓存,强制下一次 Load 访问远程源。

func (*CachedSource) InvalidateAll

func (c *CachedSource) InvalidateAll()

InvalidateAll 清空全部缓存。

func (*CachedSource) Load

func (c *CachedSource) Load(ctx context.Context, key string) (string, error)

Load 优先返回未过期缓存,否则读取远程源并更新缓存。

func (*CachedSource) Watch

func (c *CachedSource) Watch(ctx context.Context, key string) (<-chan struct{}, error)

Watch 将监听请求转发给远程脚本源。

type FSSourceOption

type FSSourceOption func(*FileSystemSource)

FSSourceOption 配置 FileSystemSource。

func WithFSPrefix

func WithFSPrefix(prefix string) FSSourceOption

WithFSPrefix 设置读取 fs.FS 时追加到 key 前的路径前缀。 前缀开头的斜杠会移除,末尾缺少斜杠时自动补充。

type FileSource

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

FileSource 从本地文件系统读取脚本,并通过修改时间轮询支持 Watch。

func NewFileSource

func NewFileSource() *FileSource

NewFileSource 创建空的本地文件脚本源。

func (*FileSource) Close

func (fs *FileSource) Close() error

Close 无需执行任何操作,FileSource 不持有外部资源。

func (*FileSource) Load

func (fs *FileSource) Load(ctx context.Context, key string) (string, error)

Load 读取 key 指定文件并记录其修改时间。

func (*FileSource) Watch

func (fs *FileSource) Watch(ctx context.Context, key string) (<-chan struct{}, error)

Watch 每秒轮询文件修改时间,变化时发送通知,ctx 取消时关闭通道。

type FileSystemSource

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

FileSystemSource 从任意 fs.FS 实现读取脚本,不负责监听文件变化。

func NewFileSystemSource

func NewFileSystemSource(fsys fs.FS, opts ...FSSourceOption) (*FileSystemSource, error)

NewFileSystemSource 使用 fsys 创建文件系统脚本源;fsys 为 nil 时返回错误。

func (*FileSystemSource) Close

func (s *FileSystemSource) Close() error

Close 无需执行任何操作,底层 fs.FS 由调用方管理。

func (*FileSystemSource) Load

func (s *FileSystemSource) Load(ctx context.Context, key string) (string, error)

Load 读取 prefix + key 对应的 fs.FS 文件。

type MemSource

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

func NewMemSource

func NewMemSource() *MemSource

func (*MemSource) Close

func (ms *MemSource) Close() error

func (*MemSource) Delete

func (ms *MemSource) Delete(key string)

func (*MemSource) Load

func (ms *MemSource) Load(ctx context.Context, key string) (string, error)

func (*MemSource) Set

func (ms *MemSource) Set(key, code string)

func (*MemSource) Watch

func (ms *MemSource) Watch(ctx context.Context, key string) (<-chan struct{}, error)

type MultiSource

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

MultiSource 按配置策略组合多个 Reader,并将读取和关闭操作统一转发。

func NewFallbackSource

func NewFallbackSource(sources ...Reader) (*MultiSource, error)

NewFallbackSource 创建按顺序回退的组合脚本源。

func NewFirstOKSource

func NewFirstOKSource(sources ...Reader) (*MultiSource, error)

NewFirstOKSource 创建并发读取并返回首个成功结果的组合脚本源。

func NewMultiSource

func NewMultiSource(strategy MultiStrategy, sources ...Reader) (*MultiSource, error)

NewMultiSource 创建组合脚本源;sources 不能为空且不能包含 nil。

func (*MultiSource) Close

func (ms *MultiSource) Close() error

Close 关闭所有子脚本源,并聚合关闭错误。

func (*MultiSource) Load

func (ms *MultiSource) Load(ctx context.Context, key string) (string, error)

func (*MultiSource) Watch

func (ms *MultiSource) Watch(ctx context.Context, key string) (<-chan struct{}, error)

type MultiStrategy

type MultiStrategy int

MultiStrategy 定义多个脚本源的读取策略。

const (
	// MultiStrategyFallback 按顺序读取,返回第一个成功结果。
	MultiStrategyFallback MultiStrategy = iota

	// MultiStrategyFirstOK 并发读取,返回第一个成功结果并取消其他请求。
	MultiStrategyFirstOK
)

type ReadWatcher

type ReadWatcher interface {
	Reader
	Watcher
}

type Reader

type Reader interface {
	Load(ctx context.Context, key string) (code string, err error)

	Close() error
}

type TransformFunc

type TransformFunc func(key string, raw string) (string, error)

type TransformSource

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

func NewTransformSource

func NewTransformSource(inner Reader, transforms ...TransformFunc) (*TransformSource, error)

func (*TransformSource) Close

func (ts *TransformSource) Close() error

func (*TransformSource) Load

func (ts *TransformSource) Load(ctx context.Context, key string) (string, error)

func (*TransformSource) Then

func (*TransformSource) Watch

func (ts *TransformSource) Watch(ctx context.Context, key string) (<-chan struct{}, error)

type Watcher

type Watcher interface {
	Watch(ctx context.Context, key string) (<-chan struct{}, error)
}

支持热更新的实现会在底层脚本源发生变化时通过通道发送通知。

Jump to

Keyboard shortcuts

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