feat: move native communication to FFI (#1457)

This commit is contained in:
Levi authored and GitHub committed 2026-09-05 20:18:42 +08:00
1 parent 177c225f16
commit 39cd9034cd
86 files changed
+4558 -886

No files matched your search

+41
View File
@@ -1,6 +1,8 @@
package model
import (
"errors"
"github.com/GopeedLab/gopeed/pkg/base"
enginewebview "github.com/GopeedLab/gopeed/pkg/download/engine/webview"
"io/fs"
@@ -16,6 +18,7 @@ const (
type StartConfig struct {
Network string `json:"network"`
Address string `json:"address"`
ApiEnable *bool `json:"apiEnable,omitempty"`
RefreshInterval int `json:"refreshInterval"`
Storage Storage `json:"storage"`
StorageDir string `json:"storageDir"`
@@ -25,6 +28,7 @@ type StartConfig struct {
WebViewRPCConfig *enginewebview.RPCConfig `json:"webViewRpcConfig,omitempty"`
ProductionMode bool
NativeMode bool
WebViewProvider enginewebview.Provider `json:"-"`
WebEnable bool
@@ -32,6 +36,26 @@ type StartConfig struct {
WebAuth *WebAuth
}
func (cfg *StartConfig) APIEnabled() bool {
if cfg == nil || cfg.WebEnable {
return true
}
// Preserve the behavior of existing CLI and library callers. Native
// Flutter explicitly sends false when it wants an in-process-only runtime.
return cfg.ApiEnable == nil || *cfg.ApiEnable
}
func (cfg *StartConfig) Validate() error {
if cfg == nil {
return nil
}
if cfg.WebEnable && cfg.ApiToken != "" &&
(cfg.WebAuth == nil || cfg.WebAuth.Username == "" || cfg.WebAuth.Password == "") {
return errors.New("web authentication username and password are required when API token is enabled for the web server")
}
return nil
}
func (cfg *StartConfig) Init() *StartConfig {
if cfg.Network == "" {
cfg.Network = "tcp"
@@ -55,3 +79,20 @@ type WebAuth struct {
Username string
Password string
}
// APIServerState describes the listener that is actually running. The
// persisted APIServerConfig remains the desired state.
type APIServerState struct {
Enabled bool `json:"enabled"`
Running bool `json:"running"`
Network string `json:"network"`
Address string `json:"address"`
RunningPort int `json:"runningPort"`
PendingApply bool `json:"pendingApply"`
LastError string `json:"lastError"`
}
type APIServerOperationResult struct {
State *APIServerState `json:"state"`
Error string `json:"error"`
}
+45
View File
@@ -0,0 +1,45 @@
package model
import "testing"
func TestStartConfigValidateWebAPIToken(t *testing.T) {
tests := []struct {
name string
config *StartConfig
wantErr bool
}{
{
name: "web API token without web auth",
config: &StartConfig{WebEnable: true, ApiToken: "token"},
wantErr: true,
},
{
name: "web API token with web auth",
config: &StartConfig{
WebEnable: true,
ApiToken: "token",
WebAuth: &WebAuth{
Username: "admin",
Password: "secret",
},
},
},
{
name: "web without authentication",
config: &StartConfig{WebEnable: true},
},
{
name: "native REST API token",
config: &StartConfig{NativeMode: true, ApiToken: "token"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.config.Validate()
if (err != nil) != tt.wantErr {
t.Fatalf("Validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}