This commit is contained in:
cnk3x 2026-01-25 09:23:07 +08:00
parent dea0429297
commit 07d9228a4b
14 changed files with 57 additions and 54 deletions

View File

@ -39,3 +39,7 @@ debian:: amd64
test:: amd64
wsl -d debian -- sshpass -p wan scp ./artifacts/xlp-amd64 cnk3x@192.168.99.9:~/apps/xunlei/xlp
xll::
cd xll; GOOS=linux GOARCH=amd64 $(GBuild) -v -o ../artifacts/xll
sshpass -p wan scp artifacts/xll cnk3x@192.168.99.9:~/apps/xll/xll

View File

@ -44,6 +44,7 @@ words:
- NOSUID
- nsynobios
- oldname
- pgid
- PKGDEST
- PKGNAME
- PKGROOT
@ -54,6 +55,7 @@ words:
- rootfs
- shenzhen
- softprops
- sshpass
- succ
- SYNO
- synobios

6
go.sum
View File

@ -1,9 +1,3 @@
github.com/cnk3x/flags v0.3.2 h1:zV4USqwimJmG3g5EyNV0T28VsAHd9uqYGOcOhpDXbOg=
github.com/cnk3x/flags v0.3.2/go.mod h1:PXix1gE56E8XZA1ZBfWCGyFwZTPL4TkA3jA3D2AbrmQ=
github.com/cnk3x/flags v0.4.1 h1:Y6cXiGLFByT4vw/PnjGZ37Io3oO9Dr8JhWT6bTdTB+M=
github.com/cnk3x/flags v0.4.1/go.mod h1:O72yC9Pv2V98yI89VT43jcu1naG/JktM2Med/ZQ5+XE=
github.com/cnk3x/flags v0.5.0 h1:YvXsauhC7ygXE+wJs2RwMWx+Rp+gcX3FdlNWnqNVATA=
github.com/cnk3x/flags v0.5.0/go.mod h1:O72yC9Pv2V98yI89VT43jcu1naG/JktM2Med/ZQ5+XE=
github.com/cnk3x/flags v0.5.1 h1:NVVjWbdMJy8vUc7kTUhbNBmt4rWlVyqKhfWIYgOvIhQ=
github.com/cnk3x/flags v0.5.1/go.mod h1:O72yC9Pv2V98yI89VT43jcu1naG/JktM2Med/ZQ5+XE=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=

View File

@ -11,8 +11,6 @@ import (
"path/filepath"
"strings"
"github.com/cnk3x/xunlei/pkg/log"
"github.com/cnk3x/xunlei/pkg/vms/sys"
"github.com/ulikunitz/xz"
)
@ -53,7 +51,17 @@ func Extract(ctx context.Context, src io.Reader, dstDir string) (err error) {
return
}()
slog.Log(ctx, log.ErrDebug(err), "extract package", "perm", sys.Perm2s(perm), "target_dir", dstDir, "name", h.Name, "err", err)
msg := "extract package"
attrs := []slog.Attr{
slog.String("perm", perm2s(perm)),
slog.String("target_dir", dstDir),
slog.String("name", h.Name),
}
if err != nil {
slog.LogAttrs(ctx, slog.LevelWarn, msg, append(attrs, slog.String("err", err.Error()))...)
} else {
slog.LogAttrs(ctx, slog.LevelDebug, msg, attrs...)
}
return
}, Xz), io.EOF)
}
@ -99,3 +107,21 @@ func Xz(src io.Reader) (io.ReadCloser, error) {
type Decoder func(io.Reader) (io.ReadCloser, error)
type WalkFunc func(r io.Reader, h *tar.Header) (err error)
func HasExt(name string, exts ...string) bool {
for _, ext := range exts {
if len(name) >= len(ext) && strings.EqualFold(name[len(name)-len(ext):], ext) {
return true
}
}
return false
}
func StartWith(name string, prefixes ...string) bool {
for _, prefix := range prefixes {
if len(name) >= len(prefix) && strings.EqualFold(name[:len(prefix)], prefix) {
return true
}
}
return false
}

View File

@ -10,30 +10,22 @@ import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/cnk3x/xunlei/pkg/fo"
"github.com/cnk3x/xunlei/pkg/utils"
"github.com/cnk3x/xunlei/pkg/vms/sys"
)
var DownloadUrl = utils.Iif(runtime.GOARCH == "amd64",
"https://down.sandai.net/nas/nasxunlei-DSM7-x86_64.spk",
"https://down.sandai.net/nas/nasxunlei-DSM7-armv8.spk",
)
// 检查并下载, 如果 force忽略检查直接下载
func Download(ctx context.Context, spkUrl string, dir string, force bool) (err error) {
if !force && allExists(ctx, dir) {
slog.InfoContext(ctx, "check spk all spk file exists")
if !force && allExists(dir) {
slog.Info("check spk all spk file exists")
return
}
switch {
case utils.HasPrefix(spkUrl, "file://", true):
case StartWith(spkUrl, "file://"):
err = download_file(ctx, spkUrl, dir)
case utils.HasPrefix(spkUrl, "http://", true) || utils.HasPrefix(spkUrl, "https://", true):
case StartWith(spkUrl, "http://", "https://"):
err = download_http(ctx, spkUrl, dir)
default:
err = fmt.Errorf("spk url is not support: %s", spkUrl)
@ -43,7 +35,7 @@ func Download(ctx context.Context, spkUrl string, dir string, force bool) (err e
func download_file(ctx context.Context, spkUrl string, dir string) (err error) {
spkUrl = strings.TrimPrefix(spkUrl, "file://")
slog.InfoContext(ctx, "download spk file", "url", spkUrl)
slog.Info("download spk file", "url", spkUrl)
f, e := os.Open(spkUrl)
if err = e; err != nil {
return
@ -55,7 +47,7 @@ func download_file(ctx context.Context, spkUrl string, dir string) (err error) {
}
func download_http(ctx context.Context, spkUrl string, dir string) (err error) {
slog.InfoContext(ctx, "download spk file", "url", spkUrl)
slog.Info("download spk file", "url", spkUrl)
var req *http.Request
if req, err = http.NewRequestWithContext(ctx, http.MethodGet, spkUrl, nil); err != nil {
return
@ -91,7 +83,7 @@ func download_http(ctx context.Context, spkUrl string, dir string) (err error) {
return
}
func allExists(ctx context.Context, dir string) bool {
func allExists(dir string) bool {
files := []string{
filepath.Join(dir, "bin/bin/version"),
filepath.Join(dir, "bin/bin/xunlei-pan-cli-launcher.{arch}"),
@ -99,22 +91,28 @@ func allExists(ctx context.Context, dir string) bool {
filepath.Join(dir, "ui/index.cgi"),
}
version := fo.Cat(files[0], true)
d, _ := os.ReadFile(files[0])
version := strings.TrimSpace(string(d))
if version == "" {
slog.DebugContext(ctx, "check spk fail, version not found")
slog.Debug("check spk fail, version not found")
return false
}
slog.DebugContext(ctx, "check spk", "version", version)
slog.Debug("check spk", "version", version)
repl := strings.NewReplacer("{arch}", runtime.GOARCH, "{version}", version)
for _, f := range files[1:] {
f = repl.Replace(f)
stat, err := os.Stat(f)
if err != nil || !stat.Mode().IsRegular() {
slog.DebugContext(ctx, "check spk fail", "file", f, "err", err)
slog.Debug("check spk fail", "file", f, "err", err)
return false
}
slog.DebugContext(ctx, "check spk", "perm", sys.Perm2s(stat.Mode()), "size", utils.HumanBytes(stat.Size()), "modtime", stat.ModTime(), "file", f)
slog.Debug("check spk", "perm", perm2s(stat.Mode()), "modtime", stat.ModTime(), "file", f)
}
return true
}
func perm2s(perm os.FileMode) string {
// return fmt.Sprintf("%s(0%s)", perm.Perm().String(), strconv.FormatInt(int64(perm.Perm()), 8))
return "0" + strconv.FormatInt(int64(perm.Perm()), 8)
}

22
xlp.go
View File

@ -6,7 +6,6 @@ import (
"os"
"path/filepath"
"runtime"
"syscall"
"github.com/cnk3x/xunlei/pkg/log"
"github.com/cnk3x/xunlei/pkg/vms"
@ -141,24 +140,3 @@ func mockEnv(dirData, dirDownload string) []string {
// "LD_LIBRARY_PATH=/lib"+utils.Iif(ld_lib == "", "", ":")+ld_lib,
)
}
// NewnsRun 在unshare后执行 fn执行完成后恢复
//
// 参数:
// - ctx: 上下文
// - fn: 要在新命名空间中执行的函数
func NewnsRun(ctx context.Context, fn func()) {
// 创建新的挂载命名空间、PID命名空间和UTS命名空间
syscall.Unshare(syscall.CLONE_NEWNS | syscall.CLONE_NEWPID | syscall.CLONE_NEWUTS)
// 设置根目录为私有挂载,防止影响父命名空间
syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, "")
// 挂载新的proc文件系统
syscall.Mount("none", "/proc", "proc", syscall.MS_NOSUID|syscall.MS_NOEXEC|syscall.MS_NODEV, "")
// 执行指定函数
fn()
// 清理操作卸载挂载的proc文件系统
syscall.Unmount("/proc", syscall.MNT_DETACH)
// 注意由于CLONE_NEWPID的存在子进程退出后会自动清理PID命名空间
// 挂载命名空间会在进程结束时自动恢复到原始状态
// 但由于我们设置了MS_PRIVATE所以不会影响原始挂载树
}

View File

@ -9,7 +9,6 @@ import (
"strings"
"github.com/cnk3x/xunlei/pkg/utils"
"github.com/cnk3x/xunlei/spk"
)
func Banner(fPrint func(string)) {
@ -55,7 +54,7 @@ func ConfigCheck(cfg *Config) (err error) {
//设置默认值
cfg.DashboardPort = cmp.Or(cfg.DashboardPort, 2345) //端口默认2345
cfg.SpkUrl = cmp.Or(cfg.SpkUrl, spk.DownloadUrl) //下载链接
cfg.SpkUrl = cmp.Or(cfg.SpkUrl, SPK_URL) //下载链接
cfg.Root = cmp.Or(cfg.Root, "xunlei") //根目录默认 ./xunlei
cfg.DirData = cmp.Or(cfg.DirData, filepath.Join(cfg.Root, "data")) //数据默认 ${root}/data

View File

@ -3,4 +3,5 @@ package xunlei
const (
SYNO_PLATFORM = "geminilake"
SYNO_MODEL = "DS920+"
SPK_URL = "https://down.sandai.net/nas/nasxunlei-DSM7-x86_64.spk"
)

View File

@ -3,4 +3,5 @@ package xunlei
const (
SYNO_PLATFORM = "rtd1296"
SYNO_MODEL = "DS220j"
SPK_URL = "https://down.sandai.net/nas/nasxunlei-DSM7-armv8.spk"
)