Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func Init() {
bootstrap.Log()
bootstrap.InitDB()
data.InitData()
bootstrap.InitPlugins()
bootstrap.InitStreamLimit()
bootstrap.InitIndex()
bootstrap.InitUpgradePatch()
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/OpenListTeam/sftpd-openlist v1.0.1
github.com/OpenListTeam/tache v0.2.0
github.com/OpenListTeam/times v0.1.0
github.com/OpenListTeam/wazero-wasip2 v0.0.0-20251015145605-cd3a2c9131d9
github.com/OpenListTeam/wopan-sdk-go v0.1.5
github.com/ProtonMail/go-crypto v1.3.0
github.com/SheltonZhu/115driver v1.1.1
Expand Down Expand Up @@ -63,6 +64,7 @@ require (
github.com/stretchr/testify v1.10.0
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5
github.com/tchap/go-patricia/v2 v2.3.3
github.com/tetratelabs/wazero v1.9.0
github.com/u2takey/ffmpeg-go v0.5.0
github.com/upyun/go-sdk/v3 v3.0.4
github.com/winfsp/cgofuse v1.6.0
Expand Down Expand Up @@ -192,7 +194,7 @@ require (
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bytedance/sonic v1.13.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-semver v0.3.1
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
Expand Down Expand Up @@ -303,3 +305,5 @@ replace github.com/ProtonMail/go-proton-api => github.com/henrybear327/go-proton
replace github.com/cronokirby/saferith => github.com/Da3zKi7/saferith v0.33.0-fixed

// replace github.com/OpenListTeam/115-sdk-go => ../../OpenListTeam/115-sdk-go

replace google.golang.org/genproto => google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ github.com/OpenListTeam/tache v0.2.0 h1:Q4MjuyECn0CZCf1ZF91JaVaZTaps1mOTAm8bFj8s
github.com/OpenListTeam/tache v0.2.0/go.mod h1:qmnZ/VpY2DUlmjg3UoDeNFy/LRqrw0biN3hYEEGc/+A=
github.com/OpenListTeam/times v0.1.0 h1:qknxw+qj5CYKgXAwydA102UEpPcpU8TYNGRmwRyPYpg=
github.com/OpenListTeam/times v0.1.0/go.mod h1:Jx7qen5NCYzKk2w14YuvU48YYMcPa1P9a+EJePC15Pc=
github.com/OpenListTeam/wazero-wasip2 v0.0.0-20251015145605-cd3a2c9131d9 h1:yddTD9Fxh6bLMLmG0hSR7Eh6XkoK0RMlE4N1e6/+Iy8=
github.com/OpenListTeam/wazero-wasip2 v0.0.0-20251015145605-cd3a2c9131d9/go.mod h1:+BpydPG2cUQHYFwH3/lVmvXyMl/zxHW+XM+XTSzqu2Q=
github.com/OpenListTeam/wopan-sdk-go v0.1.5 h1:iKKcVzIqBgtGDbn0QbdWrCazSGxXFmYFyrnFBG+U8dI=
github.com/OpenListTeam/wopan-sdk-go v0.1.5/go.mod h1:otynv0CgSNUClPpUgZ44qCZGcMRe0dc83Pkk65xAunI=
github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57/go.mod h1:HecWFHognK8GfRDGnFQbW/LiV7A3MX3gZVs45vk5h8I=
Expand Down Expand Up @@ -688,6 +690,8 @@ github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 h1:6Y51mutOvRGRx6K
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow=
github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc=
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
Expand Down
24 changes: 24 additions & 0 deletions internal/alloc/alloc_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//go:build !unix && !windows

package alloc // import "github.com/ncruces/go-sqlite3/internal/alloc"

import "github.com/tetratelabs/wazero/experimental"

func NewMemory(cap, max uint64) experimental.LinearMemory {
return &sliceMemory{make([]byte, 0, cap)}
}

type sliceMemory struct {
buf []byte
}

func (b *sliceMemory) Free() {}

func (b *sliceMemory) Reallocate(size uint64) []byte {
if cap := uint64(cap(b.buf)); size > cap {
b.buf = append(b.buf[:cap], make([]byte, size-cap)...)
} else {
b.buf = b.buf[:size]
}
return b.buf
}
14 changes: 14 additions & 0 deletions internal/alloc/alloc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package alloc_test // import "github.com/ncruces/go-sqlite3/internal/alloc"

import (
"math"
"testing"

"github.com/OpenListTeam/OpenList/v4/internal/alloc"
)

func TestVirtual(t *testing.T) {
defer func() { _ = recover() }()
alloc.NewMemory(math.MaxInt+2, math.MaxInt+2)
t.Error("want panic")
}
75 changes: 75 additions & 0 deletions internal/alloc/alloc_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//go:build unix

package alloc // import "github.com/ncruces/go-sqlite3/internal/alloc"

import (
"math"

"github.com/tetratelabs/wazero/experimental"
"golang.org/x/sys/unix"
)

func NewMemory(cap, max uint64) experimental.LinearMemory {
// Round up to the page size.
rnd := uint64(unix.Getpagesize() - 1)
res := (max + rnd) &^ rnd

if res > math.MaxInt {
// This ensures int(res) overflows to a negative value,
// and unix.Mmap returns EINVAL.
res = math.MaxUint64
}

com := res
prot := unix.PROT_READ | unix.PROT_WRITE
if cap < max { // Commit memory only if cap=max.
com = 0
prot = unix.PROT_NONE
}

// Reserve res bytes of address space, to ensure we won't need to move it.
// A protected, private, anonymous mapping should not commit memory.
b, err := unix.Mmap(-1, 0, int(res), prot, unix.MAP_PRIVATE|unix.MAP_ANON)
if err != nil {
panic(err)
}
return &mmappedMemory{buf: b[:com]}
}

// The slice covers the entire mmapped memory:
// - len(buf) is the already committed memory,
// - cap(buf) is the reserved address space.
type mmappedMemory struct {
buf []byte
}

func (m *mmappedMemory) Reallocate(size uint64) []byte {
com := uint64(len(m.buf))
res := uint64(cap(m.buf))
if com < size && size <= res {
// Grow geometrically, round up to the page size.
rnd := uint64(unix.Getpagesize() - 1)
new := com + com>>3
new = min(max(size, new), res)
new = (new + rnd) &^ rnd

// Commit additional memory up to new bytes.
err := unix.Mprotect(m.buf[com:new], unix.PROT_READ|unix.PROT_WRITE)
if err != nil {
return nil
}

m.buf = m.buf[:new] // Update committed memory.
}
// Limit returned capacity because bytes beyond
// len(m.buf) have not yet been committed.
return m.buf[:size:len(m.buf)]
}

func (m *mmappedMemory) Free() {
err := unix.Munmap(m.buf[:cap(m.buf)])
if err != nil {
panic(err)
}
m.buf = nil
}
76 changes: 76 additions & 0 deletions internal/alloc/alloc_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package alloc // import "github.com/ncruces/go-sqlite3/internal/alloc"

import (
"math"
"unsafe"

"github.com/tetratelabs/wazero/experimental"
"golang.org/x/sys/windows"
)

func NewMemory(cap, max uint64) experimental.LinearMemory {
// Round up to the page size.
rnd := uint64(windows.Getpagesize() - 1)
res := (max + rnd) &^ rnd

if res > math.MaxInt {
// This ensures uintptr(res) overflows to a large value,
// and windows.VirtualAlloc returns an error.
res = math.MaxUint64
}

com := res
kind := windows.MEM_COMMIT
if cap < max { // Commit memory only if cap=max.
com = 0
kind = windows.MEM_RESERVE
}

// Reserve res bytes of address space, to ensure we won't need to move it.
r, err := windows.VirtualAlloc(0, uintptr(res), uint32(kind), windows.PAGE_READWRITE)
if err != nil {
panic(err)
}
buf := unsafe.Slice((*byte)(unsafe.Pointer(r)), int(max))
mem := virtualMemory{addr: r, buf: buf[:com:res]}
return &mem
}

// The slice covers the entire mmapped memory:
// - len(buf) is the already committed memory,
// - cap(buf) is the reserved address space.
type virtualMemory struct {
buf []byte
addr uintptr
}

func (m *virtualMemory) Reallocate(size uint64) []byte {
com := uint64(len(m.buf))
res := uint64(cap(m.buf))
if com < size && size <= res {
// Grow geometrically, round up to the page size.
rnd := uint64(windows.Getpagesize() - 1)
new := com + com>>3
new = min(max(size, new), res)
new = (new + rnd) &^ rnd

// Commit additional memory up to new bytes.
_, err := windows.VirtualAlloc(m.addr, uintptr(new), windows.MEM_COMMIT, windows.PAGE_READWRITE)
if err != nil {
return nil
}

m.buf = m.buf[:new] // Update committed memory.
}
// Limit returned capacity because bytes beyond
// len(m.buf) have not yet been committed.
return m.buf[:size:len(m.buf)]
}

func (m *virtualMemory) Free() {
err := windows.VirtualFree(m.addr, 0, windows.MEM_RELEASE)
if err != nil {
panic(err)
}
m.addr = 0
}
23 changes: 23 additions & 0 deletions internal/bootstrap/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// internal/bootstrap/plugin.go
package bootstrap

import (
"context"
"fmt"

"github.com/OpenListTeam/OpenList/v4/cmd/flags"
"github.com/OpenListTeam/OpenList/v4/internal/plugin"
)

// InitPlugins 初始化插件管理器
func InitPlugins() {
// 2. 创建并初始化 Manager
// "data" 目录应从配置中获取
manager, err := plugin.NewManager(context.Background(), flags.DataDir)
if err != nil {
// 在启动时,如果插件系统失败,应该 panic
panic(fmt.Sprintf("Failed to initialize plugin manager: %v", err))
}

plugin.PluginManager = manager
}
2 changes: 1 addition & 1 deletion internal/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var db *gorm.DB

func Init(d *gorm.DB) {
db = d
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem), new(model.SSHPublicKey), new(model.SharingDB))
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem), new(model.SSHPublicKey), new(model.SharingDB), new(model.Plugin))
if err != nil {
log.Fatalf("failed migrate database: %s", err.Error())
}
Expand Down
47 changes: 47 additions & 0 deletions internal/db/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package db

import (
"context"

"github.com/OpenListTeam/OpenList/v4/internal/model"
"gorm.io/gorm"
)

// CreatePlugin 在数据库中插入一条新的插件记录
// 如果记录已存在,则会更新它 (Upsert)
func CreatePlugin(ctx context.Context, plugin *model.Plugin) error {
return db.WithContext(ctx).Save(plugin).Error
}

// GetPluginByID 从数据库中根据 ID 查询单个插件
func GetPluginByID(ctx context.Context, id string) (*model.Plugin, error) {
var plugin model.Plugin
err := db.WithContext(ctx).First(&plugin, "id = ?", id).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil // 返回 nil, nil 表示未找到
}
return nil, err
}
return &plugin, nil
}

// GetAllPlugins 从数据库中获取所有已安装的插件
func GetAllPlugins(ctx context.Context) ([]*model.Plugin, error) {
var plugins []*model.Plugin
err := db.WithContext(ctx).Find(&plugins).Error
return plugins, err
}

// DeletePluginByID 从数据库中根据 ID 删除一个插件
func DeletePluginByID(ctx context.Context, id string) error {
return db.WithContext(ctx).Delete(&model.Plugin{}, "id = ?", id).Error
}

// UpdatePluginStatus 更新指定插件的状态和消息
func UpdatePluginStatus(ctx context.Context, pluginID string, status model.PluginStatus, message string) error {
return db.WithContext(ctx).Model(&model.Plugin{}).Where("id = ?", pluginID).Updates(map[string]interface{}{
"status": status,
"message": message,
}).Error
}
4 changes: 4 additions & 0 deletions internal/driver/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ type Info struct {
Config Config `json:"config"`
}

type IGetItem interface {
GetItems() []Item
}

type IRootPath interface {
GetRootPath() string
}
Expand Down
42 changes: 42 additions & 0 deletions internal/model/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package model

import "time"

// PluginStatus 定义了插件的几种可能状态
type PluginStatus string

const (
// StatusActive 表示插件已成功加载并正在运行
StatusActive PluginStatus = "active"
// StatusInactive 表示插件已安装但未加载(例如,等待重启)
StatusInactive PluginStatus = "inactive"
// StatusError 表示插件在加载或运行时遇到错误
StatusError PluginStatus = "error"
)

type Plugin struct {
// 插件的唯一标识符,例如 "com.openlist.driver.s3"
// 这是主键
ID string `gorm:"primaryKey" json:"id"`

// --- 来自插件元数据 ---
Name string `json:"name"`
Version string `json:"version"`
Author string `json:"author"`
Description string `gorm:"type:text" json:"description"`
IconURL string `json:"icon_url"`

// --- 管理器需要的信息 ---
// 插件的下载源地址
SourceURL string `json:"source_url"`
// Wasm 文件在本地的存储路径
WasmPath string `json:"wasm_path"`

// 新增状态字段
Status PluginStatus `gorm:"default:'inactive'" json:"status"`
Message string `gorm:"type:text" json:"message"` // 用于存储错误信息

// --- GORM 自动管理字段 ---
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
Loading
Loading