From 599d333afb4cc82e85e48a06d7f1b62f8f558937 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 10:41:13 +0800
Subject: [PATCH 01/35] refactor: refactor code structure
---
.air.toml | 4 +-
.gitignore | 4 +-
.vscode/settings.json | 2 +-
Dockerfile | 26 +---
README.md | 18 ++-
README_cn.md | 16 +--
{internal/cmd => cmd/gen}/gen.go | 12 +-
cmd/server/server.go | 86 ++++++++++++
config/app.go | 28 ----
config/config.go | 9 --
fs_dev.go | 12 --
fs_prod.go | 20 ---
go.mod | 26 ++--
go.sum | 68 ++++++----
internal/app/app.go | 128 +-----------------
internal/app/booter.go | 45 ------
internal/app/bootstrap.go | 94 ++++++++++---
internal/app/build/var.go | 11 ++
internal/app/config.go | 42 ++++++
internal/app/const.go | 3 +
internal/app/mode.go | 25 ++++
internal/app/router.go | 5 -
{config => internal/app}/settings.go | 30 +---
internal/app/version.go | 16 +++
internal/cfg/cfg.go | 89 ++++++------
internal/cfg/cfg_darwin.go | 7 +-
internal/cfg/cfg_dev.go | 15 --
internal/cfg/cfg_linux.go | 7 +-
internal/cfg/cfg_prod.go | 7 -
internal/cfg/cfg_windows.go | 4 +-
internal/cfg/entity.go | 73 ----------
internal/cmd/main.go | 27 ----
internal/cmd/server.go | 32 -----
internal/db/config.go | 7 +
internal/db/db.go | 22 +--
{ipa => internal/ipa}/ipa.go | 0
{ipa => internal/ipa}/package_info.go | 0
.../manager}/device_manager.go | 6 +-
.../manager}/device_manager_avahi.go | 2 +-
.../manager}/device_manager_mdns.go | 2 +-
.../manager}/device_manager_usbmuxd.go | 2 +-
{manager => internal/manager}/lockdown.go | 9 +-
{manager => internal/manager}/manager.go | 2 +-
internal/mode/mode.go | 31 -----
{model => internal/model}/device.go | 0
{model => internal/model}/installed_app.go | 0
{model => internal/model}/ipa_file.go | 0
{model => internal/model}/lockdown_device.go | 0
{model => internal/model}/service_status.go | 0
{model => internal/model}/usbmuxd_device.go | 0
{model => internal/model}/usbmuxd_image.go | 0
{notify => internal/notify}/notify.go | 8 +-
{notify => internal/notify}/wecom/wecom.go | 0
{service => internal/service}/db.go | 8 +-
{service => internal/service}/service.go | 42 +++---
{service => internal/service}/service_test.go | 4 -
{task => internal/task}/task.go | 36 ++---
{tty => internal/tty}/lib/function.go | 4 +-
{tty => internal/tty}/lib/message.go | 0
{tty => internal/tty}/pipeline.go | 2 +-
{tty => internal/tty}/tty.go | 4 +-
internal/version/build.go | 25 ----
main.go | 50 +++----
{router => web}/api_result.go | 2 +-
web/fs_dev.go | 12 ++
web/fs_prod.go | 20 +++
{router => web}/router.go | 56 ++++----
{view => web/static}/index.html | 0
{view => web/static}/package-lock.json | 0
{view => web/static}/package.json | 0
{view => web/static}/postcss.config.js | 0
{view => web/static}/public/img/dummy.jpg | Bin
{view => web/static}/src/App.vue | 0
{view => web/static}/src/api/api.js | 0
{view => web/static}/src/app.css | 0
.../static}/src/assets/icons/appletv.svg | 0
.../static}/src/assets/icons/checkmark.svg | 0
.../static}/src/assets/icons/dismiss.svg | 0
.../static}/src/assets/icons/github.svg | 0
.../static}/src/assets/icons/help.svg | 0
.../static}/src/assets/icons/language.svg | 0
.../static}/src/assets/icons/settings.svg | 0
.../static}/src/assets/icons/warning.svg | 0
{view => web/static}/src/i18n.js | 0
.../static}/src/locales/en/translation.json | 0
.../src/locales/zh_cn/translation.json | 0
{view => web/static}/src/main.js | 0
{view => web/static}/src/page/home/index.vue | 0
.../static}/src/page/install/index.vue | 32 +----
{view => web/static}/src/page/layout.vue | 0
{view => web/static}/src/page/pair/index.vue | 0
.../static}/src/page/settings/index.vue | 0
{view => web/static}/src/router/index.js | 0
{view => web/static}/src/utils/crypto.js | 0
{view => web/static}/src/utils/request.js | 0
{view => web/static}/tailwind.config.js | 0
{view => web/static}/vite.config.js | 0
{view => web/static}/yarn.lock | 0
web/web.go | 31 +++++
99 files changed, 610 insertions(+), 800 deletions(-)
rename {internal/cmd => cmd/gen}/gen.go (82%)
create mode 100644 cmd/server/server.go
delete mode 100644 config/app.go
delete mode 100644 config/config.go
delete mode 100644 fs_dev.go
delete mode 100644 fs_prod.go
delete mode 100644 internal/app/booter.go
create mode 100644 internal/app/build/var.go
create mode 100644 internal/app/config.go
create mode 100644 internal/app/const.go
create mode 100644 internal/app/mode.go
delete mode 100644 internal/app/router.go
rename {config => internal/app}/settings.go (76%)
create mode 100644 internal/app/version.go
delete mode 100644 internal/cfg/cfg_dev.go
delete mode 100644 internal/cfg/cfg_prod.go
delete mode 100644 internal/cfg/entity.go
delete mode 100644 internal/cmd/main.go
delete mode 100644 internal/cmd/server.go
create mode 100644 internal/db/config.go
rename {ipa => internal/ipa}/ipa.go (100%)
rename {ipa => internal/ipa}/package_info.go (100%)
rename {manager => internal/manager}/device_manager.go (95%)
rename {manager => internal/manager}/device_manager_avahi.go (98%)
rename {manager => internal/manager}/device_manager_mdns.go (98%)
rename {manager => internal/manager}/device_manager_usbmuxd.go (97%)
rename {manager => internal/manager}/lockdown.go (78%)
rename {manager => internal/manager}/manager.go (90%)
delete mode 100644 internal/mode/mode.go
rename {model => internal/model}/device.go (100%)
rename {model => internal/model}/installed_app.go (100%)
rename {model => internal/model}/ipa_file.go (100%)
rename {model => internal/model}/lockdown_device.go (100%)
rename {model => internal/model}/service_status.go (100%)
rename {model => internal/model}/usbmuxd_device.go (100%)
rename {model => internal/model}/usbmuxd_image.go (100%)
rename {notify => internal/notify}/notify.go (87%)
rename {notify => internal/notify}/wecom/wecom.go (100%)
rename {service => internal/service}/db.go (93%)
rename {service => internal/service}/service.go (74%)
rename {service => internal/service}/service_test.go (84%)
rename {task => internal/task}/task.go (83%)
rename {tty => internal/tty}/lib/function.go (87%)
rename {tty => internal/tty}/lib/message.go (100%)
rename {tty => internal/tty}/pipeline.go (98%)
rename {tty => internal/tty}/tty.go (93%)
delete mode 100644 internal/version/build.go
rename {router => web}/api_result.go (95%)
create mode 100644 web/fs_dev.go
create mode 100644 web/fs_prod.go
rename {router => web}/router.go (85%)
rename {view => web/static}/index.html (100%)
rename {view => web/static}/package-lock.json (100%)
rename {view => web/static}/package.json (100%)
rename {view => web/static}/postcss.config.js (100%)
rename {view => web/static}/public/img/dummy.jpg (100%)
rename {view => web/static}/src/App.vue (100%)
rename {view => web/static}/src/api/api.js (100%)
rename {view => web/static}/src/app.css (100%)
rename {view => web/static}/src/assets/icons/appletv.svg (100%)
rename {view => web/static}/src/assets/icons/checkmark.svg (100%)
rename {view => web/static}/src/assets/icons/dismiss.svg (100%)
rename {view => web/static}/src/assets/icons/github.svg (100%)
rename {view => web/static}/src/assets/icons/help.svg (100%)
rename {view => web/static}/src/assets/icons/language.svg (100%)
rename {view => web/static}/src/assets/icons/settings.svg (100%)
rename {view => web/static}/src/assets/icons/warning.svg (100%)
rename {view => web/static}/src/i18n.js (100%)
rename {view => web/static}/src/locales/en/translation.json (100%)
rename {view => web/static}/src/locales/zh_cn/translation.json (100%)
rename {view => web/static}/src/main.js (100%)
rename {view => web/static}/src/page/home/index.vue (100%)
rename {view => web/static}/src/page/install/index.vue (90%)
rename {view => web/static}/src/page/layout.vue (100%)
rename {view => web/static}/src/page/pair/index.vue (100%)
rename {view => web/static}/src/page/settings/index.vue (100%)
rename {view => web/static}/src/router/index.js (100%)
rename {view => web/static}/src/utils/crypto.js (100%)
rename {view => web/static}/src/utils/request.js (100%)
rename {view => web/static}/tailwind.config.js (100%)
rename {view => web/static}/vite.config.js (100%)
rename {view => web/static}/yarn.lock (100%)
create mode 100644 web/web.go
diff --git a/.air.toml b/.air.toml
index 1641df7..2154641 100644
--- a/.air.toml
+++ b/.air.toml
@@ -7,7 +7,7 @@ tmp_dir = "tmp"
[build]
# Just plain old shell command. You could use `make` as well.
-cmd = "go build -tags dev -o ./tmp/main ."
+cmd = "go build -o ./tmp/main ."
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary.
@@ -15,7 +15,7 @@ full_bin = "APP_ENV=dev APP_USER=air ./tmp/main server -vv"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html", "vue", "js", "css", "woff", "ttf"]
# Ignore these filename extensions or directories.
-exclude_dir = ["tmp", "libs", "vendor", "view"]
+exclude_dir = ["tmp", "libs", "vendor", "view", "web/static"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
diff --git a/.gitignore b/.gitignore
index e6fd2a1..4e0795e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,9 +17,9 @@
vendor/
tmp/
dist/
-build/
+/build
node_modules/
-go-docker-skeleton
+atvloadly
main
AltServerData/
atvloadly
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 616e01a..9c84d82 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -8,7 +8,7 @@
"json"
],
"i18n-ally.localesPaths": [
- "view/src/locales"
+ "web/static/src/locales"
],
"i18n-ally.keystyle": "nested"
}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 2cd0335..75e21dd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,28 +27,19 @@ RUN case ${TARGETARCH} in \
&& dpkg -i ./libimobiledevice_1.3.1-1_${PKG_ARCH}.deb \
&& dpkg -i ./usbmuxd2_1.0.0-1_${PKG_ARCH}.deb
-# 安装anisette-server,用于模拟本机为MacBook
+# 安装Sideloader
RUN case ${TARGETARCH} in \
"amd64") PKG_ARCH=x86_64 ;; \
"arm64") PKG_ARCH=aarch64 ;; \
esac \
&& cd /tmp \
- && wget https://github.com/Dadoum/Provision/releases/download/2.1.0/anisette-server-${PKG_ARCH} \
- && mv anisette-server-${PKG_ARCH} /usr/bin/anisette-server \
- && chmod +x /usr/bin/anisette-server
-
-# 安装AltStore
-RUN case ${TARGETARCH} in \
- "amd64") PKG_ARCH=x86_64 ;; \
- "arm64") PKG_ARCH=aarch64 ;; \
- esac \
- && cd /tmp \
- && wget https://github.com/NyaMisty/AltServer-Linux/releases/download/v0.0.5/AltServer-${PKG_ARCH} \
- && mv AltServer-${PKG_ARCH} /usr/bin/AltServer \
- && chmod +x /usr/bin/AltServer
+ && wget https://github.com/bitxeno/Sideloader/releases/download/1.0-alpha/sideloader-cli-${PKG_ARCH}-linux-gnu.tar.gz \
+ && tar zxf sideloader-cli-${PKG_ARCH}-linux-gnu.tar.gz \
+ && mv sideloader-cli-${PKG_ARCH}-linux-gnu /usr/bin/sideloader \
+ && chmod +x /usr/bin/sideloader
# 安装tzdata支持更新时区
-RUN DEBIAN_FRONTEND=noninteractive TZ=Asia/Shanghai apt-get -y install tzdata
+RUN DEBIAN_FRONTEND=noninteractive apt-get -y install tzdata
# 清空apt缓存和临时数据,减小镜像大小
RUN apt-get clean
@@ -66,21 +57,18 @@ RUN rm -rf /var/lib/lockdown && mkdir -p /data/lockdown && ln -s /data/lockdown
# 生成启动脚本
-COPY ./doc/scripts/anisette-server /etc/init.d/anisette-server
-RUN chmod +x /etc/init.d/anisette-server
COPY ./doc/scripts/usbmuxd /etc/init.d/usbmuxd
RUN chmod +x /etc/init.d/usbmuxd
RUN printf '#!/bin/sh \n\n\
mkdir -p /data/lockdown \n\
-mkdir -p /data/AltServer \n\
+mkdir -p /data/Sideloader \n\
if [ ! -f "/data/config.yaml" ]; then \n\
cp /doc/config.yaml /data/config.yaml \n\
fi \n\
/etc/init.d/usbmuxd start \n\
-/etc/init.d/anisette-server start \n\
/usr/bin/%s server -p ${SERVICE_PORT:-80} -c /data/config.yaml \n\
\n\
diff --git a/README.md b/README.md
index 933a602..65a15cc 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@
-[![platform](https://img.shields.io/badge/platform-linux%20%7C%20openwrt-989898)](https://github.com/bitxeno/atvloadly/releases)
-[![release](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/latest_tag?label=docker%20latest)](https://github.com/bitxeno/atvloadly/pkgs/container/atvloadly)
-[![image size](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/size)](https://github.com/bitxeno/atvloadly/pkgs/container/atvloadly)
-[![license](https://img.shields.io/github/license/bitxeno/atvloadly)](https://github.com/bitxeno/atvloadly/blob/master/LICENSE)
+[![platform](https://img.shields.io/badge/platform-linux%20%7C%20openwrt-989898)](https://github.com/bitxeno/atvloadly/internal/releases)
+[![release](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/latest_tag?label=docker%20latest)](https://github.com/bitxeno/atvloadly/internal/pkgs/container/atvloadly)
+[![image size](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/size)](https://github.com/bitxeno/atvloadly/internal/pkgs/container/atvloadly)
+[![license](https://img.shields.io/github/license/bitxeno/atvloadly)](https://github.com/bitxeno/atvloadly/internal/blob/master/LICENSE)
[![Telegram](https://img.shields.io/badge/telegram-2CA5E0?logo=telegram&logoColor=white)](https://t.me/atvloadly)
@@ -22,7 +22,7 @@ English | [中文](./README_cn.md)
> ⚠️ **Not supported on tvOS 17.0 and above systems.** ⚠️
-atvloadly is a web service that supports sideloading app on Apple TV. It uses [AltServer](https://github.com/NyaMisty/AltServer-Linux) as the underlying technology for sideloading and automatically refreshes the app to ensure its long-term availability.
+atvloadly is a web service that supports sideloading app on Apple TV. It uses [Sideloader](https://github.com/Dadoum/Sideloader) as the underlying technology for sideloading and automatically refreshes the app to ensure its long-term availability.
## Features
@@ -98,12 +98,16 @@ atvloadly is a web service that supports sideloading app on Apple TV. It uses [A
3. Can App-specific passwords be used for passwords? Is it more secure this way?
-> AltServer currently does not support it.
+> Sideloader currently does not support it.
+
+4. 2 Step Verification
+> When your Apple account has 2 factor verification enabled, you'll automatically be asked to verify your identity. If you have a trusted device configured for your account, then a code will appear on the device. If you don't have any devices configured, but have trusted a phone number, then a code will be sent to your phone.
+> https://github.com/fastlane/fastlane/tree/master/spaceship#2-step-verification
## How to build
-[>> wiki](https://github.com/bitxeno/atvloadly/wiki/How-to-build)
+[>> wiki](https://github.com/bitxeno/atvloadly/internal/wiki/How-to-build)
## Donation
diff --git a/README_cn.md b/README_cn.md
index 746fddc..b0151de 100644
--- a/README_cn.md
+++ b/README_cn.md
@@ -5,10 +5,10 @@
-[![platform](https://img.shields.io/badge/platform-linux%20%7C%20openwrt-989898)](https://github.com/bitxeno/atvloadly/releases)
-[![release](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/latest_tag?label=docker%20latest)](https://github.com/bitxeno/atvloadly/pkgs/container/atvloadly)
-[![image size](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/size)](https://github.com/bitxeno/atvloadly/pkgs/container/atvloadly)
-[![license](https://img.shields.io/github/license/bitxeno/atvloadly)](https://github.com/bitxeno/atvloadly/blob/master/LICENSE)
+[![platform](https://img.shields.io/badge/platform-linux%20%7C%20openwrt-989898)](https://github.com/bitxeno/atvloadly/internal/releases)
+[![release](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/latest_tag?label=docker%20latest)](https://github.com/bitxeno/atvloadly/internal/pkgs/container/atvloadly)
+[![image size](https://ghcr-badge.egpl.dev/bitxeno/atvloadly/size)](https://github.com/bitxeno/atvloadly/internal/pkgs/container/atvloadly)
+[![license](https://img.shields.io/github/license/bitxeno/atvloadly)](https://github.com/bitxeno/atvloadly/internal/blob/master/LICENSE)
[![Telegram](https://img.shields.io/badge/telegram-2CA5E0?logo=telegram&logoColor=white)](https://t.me/atvloadly)
@@ -22,7 +22,7 @@
> ⚠️ **不支持 tvOS 17.0 以上系统** ⚠️
-atvloadly 是一个支持在 AppleTV 上侧载应用的 web 服务。底层通过使用 [AltServer](https://github.com/NyaMisty/AltServer-Linux) 实现侧载,并会自动刷新 App 以保证其长期可用性。
+atvloadly 是一个支持在 AppleTV 上侧载应用的 web 服务。底层通过使用 [Sideloader](https://github.com/Dadoum/Sideloader) 实现侧载,并会自动刷新 App 以保证其长期可用性。
## 主要功能
@@ -100,17 +100,17 @@ atvloadly 是一个支持在 AppleTV 上侧载应用的 web 服务。底层通
3、密码可以使用App-specific password吗,这样安全些
-> AltServer 目前不支持
+> Sideloader 目前不支持
## 推荐开源 App
-[>> wiki](https://github.com/bitxeno/atvloadly/wiki/AppleTV-App)
+[>> wiki](https://github.com/bitxeno/atvloadly/internal/wiki/AppleTV-App)
## 如何开发编译
-[>> wiki](https://github.com/bitxeno/atvloadly/wiki/How-to-build)
+[>> wiki](https://github.com/bitxeno/atvloadly/internal/wiki/How-to-build)
## 赞助
diff --git a/internal/cmd/gen.go b/cmd/gen/gen.go
similarity index 82%
rename from internal/cmd/gen.go
rename to cmd/gen/gen.go
index 1cbba0f..d60b060 100644
--- a/internal/cmd/gen.go
+++ b/cmd/gen/gen.go
@@ -1,11 +1,11 @@
-package cmd
+package gen
import (
"github.com/urfave/cli/v2"
)
var (
- genFlags = []cli.Flag{
+ flags = []cli.Flag{
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
@@ -14,15 +14,15 @@ var (
},
}
- genCommand = &cli.Command{
+ Command = &cli.Command{
Name: "gen",
Usage: "Generate example server code",
- Flags: genFlags,
- Action: generateAction,
+ Flags: flags,
+ Action: action,
}
)
-func generateAction(c *cli.Context) error {
+func action(c *cli.Context) error {
// if utils.Exists(app.ConfigFilePath) {
// fmt.Printf("Config has exist. >>> %s\n", app.ConfigFilePath)
// return nil
diff --git a/cmd/server/server.go b/cmd/server/server.go
new file mode 100644
index 0000000..17bbcde
--- /dev/null
+++ b/cmd/server/server.go
@@ -0,0 +1,86 @@
+package server
+
+import (
+ "github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/manager"
+ "github.com/bitxeno/atvloadly/internal/task"
+ "github.com/bitxeno/atvloadly/web"
+ "github.com/urfave/cli/v2"
+)
+
+var (
+ flags = []cli.Flag{
+ &cli.IntFlag{
+ Name: "port",
+ Aliases: []string{"p"},
+ Usage: "Define an alternate web server port",
+ },
+ &cli.StringFlag{
+ Name: "config",
+ Aliases: []string{"c"},
+ Usage: "Load configuration from `FILE`",
+ },
+ &cli.BoolFlag{
+ Name: "debug",
+ Aliases: []string{"vv"},
+ Usage: "Enable debug output",
+ Value: false,
+ },
+ &cli.BoolFlag{
+ Name: "verbose",
+ Aliases: []string{"vvv"},
+ Usage: "Enable verbose output",
+ Value: false,
+ },
+ }
+
+ Command = &cli.Command{
+ Name: "server",
+ Usage: "Run web server",
+ Flags: flags,
+ Action: action,
+ }
+)
+
+func action(c *cli.Context) error {
+ // init config
+ debug := false
+ if c.Bool("debug") || c.Bool("verbose") {
+ debug = true
+ }
+ conf, err := app.InitConfig(c.String("config"), debug)
+ if err != nil {
+ return err
+ }
+ if err = app.InitSettings(conf, debug); err != nil {
+ return err
+ }
+
+ // init logger
+ if c.Bool("debug") {
+ conf.Log.Level = "debug"
+ conf.Db.Debug = true
+ }
+ if c.Bool("verbose") {
+ conf.Log.Level = "trace"
+ conf.Db.Debug = true
+ }
+ if err := app.InitLogger(conf); err != nil {
+ return err
+ }
+
+ // init db
+ if err := app.InitDb(conf); err != nil {
+ return err
+ }
+
+ // start jobs
+ _ = task.ScheduleRefreshApps()
+ manager.StartDeviceManager()
+
+ port := conf.Server.Port
+ if c.Int("port") > 0 {
+ port = c.Int("port")
+ }
+ return web.Run(conf.Server.ListenAddr, port)
+}
diff --git a/config/app.go b/config/app.go
deleted file mode 100644
index 000f288..0000000
--- a/config/app.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package config
-
-import (
- "github.com/bitxeno/atvloadly/internal/app"
- "github.com/creasty/defaults"
-)
-
-var App AppConfiguration
-
-type AppConfiguration struct {
- LockdownDir string `koanf:"lockdown_dir" default:"/var/lib/lockdown"`
- DeveloperDiskImage struct {
- ImageSource string `koanf:"image_source" json:"image_source" default:"https://github.com/haikieu/xcode-developer-disk-image-all-platforms/raw/master/DiskImages/AppleTVOS.platform/DeviceSupport/{0}.zip"`
- CNProxy string `koanf:"cn_proxy" json:"cn_proxy" default:"https://mirror.ghproxy.com"`
- } `koanf:"developer_disk_image" json:"developer_disk_image"`
-}
-
-func loadApp() error {
- // set default value
- if err := defaults.Set(&App); err != nil {
- return err
- }
- if err := app.Cfg().BindStruct("app", &App); err != nil {
- return err
- }
-
- return nil
-}
diff --git a/config/config.go b/config/config.go
deleted file mode 100644
index 0e85038..0000000
--- a/config/config.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package config
-
-func Load() error {
- if err := loadApp(); err != nil {
- return err
- }
-
- return loadSettings()
-}
diff --git a/fs_dev.go b/fs_dev.go
deleted file mode 100644
index 2f448cf..0000000
--- a/fs_dev.go
+++ /dev/null
@@ -1,12 +0,0 @@
-//go:build dev
-
-package main
-
-import (
- "io/fs"
- "os"
-)
-
-func getViewAssets() fs.FS {
- return os.DirFS("view/dist")
-}
diff --git a/fs_prod.go b/fs_prod.go
deleted file mode 100644
index 8a4e7a9..0000000
--- a/fs_prod.go
+++ /dev/null
@@ -1,20 +0,0 @@
-//go:build !dev
-
-package main
-
-import (
- "embed"
- "io/fs"
-)
-
-//go:embed all:view/dist/*
-var view embed.FS
-
-func getViewAssets() fs.FS {
- embed, err := fs.Sub(view, "view/dist")
- if err != nil {
- panic(err)
- }
-
- return embed
-}
diff --git a/go.mod b/go.mod
index 56fe866..d27256b 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,8 @@ require (
github.com/creasty/defaults v1.5.2
github.com/electricbubble/gidevice v0.6.2
github.com/fatih/color v1.9.0
+ github.com/glebarez/sqlite v1.11.0
+ github.com/go-errors/errors v1.5.1
github.com/go-resty/resty/v2 v2.6.0
github.com/godbus/dbus/v5 v5.0.4
github.com/gofiber/contrib/websocket v1.0.0
@@ -18,17 +20,17 @@ require (
github.com/iineva/ipa-server v0.0.0-20210613102156-5a07a87df9a8
github.com/json-iterator/go v1.1.12
github.com/knadh/koanf v1.5.0
+ github.com/mitchellh/go-ps v1.0.0
github.com/nikoksr/notify v0.41.0
github.com/pkg/errors v0.9.1
github.com/robfig/cron/v3 v3.0.1
github.com/rs/zerolog v1.29.1
github.com/runletapp/go-console v0.0.0-20211204140000-27323a28410a
- github.com/shirou/gopsutil/v3 v3.23.5
+ github.com/shirou/gopsutil/v4 v4.24.5
github.com/silenceper/wechat/v2 v2.1.5
github.com/urfave/cli/v2 v2.3.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
- gorm.io/driver/sqlite v1.1.4
- gorm.io/gorm v1.21.14
+ gorm.io/gorm v1.25.7
howett.net/plist v1.0.0
)
@@ -41,15 +43,17 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/creack/pty v1.1.17 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fasthttp/websocket v1.5.3 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
+ github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc // indirect
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/iamacarpet/go-winpty v1.0.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
- github.com/jinzhu/now v1.1.2 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
@@ -57,7 +61,6 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
- github.com/mattn/go-sqlite3 v1.14.5 // indirect
github.com/miekg/dns v1.1.41 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -67,6 +70,7 @@ require (
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
+ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
@@ -75,17 +79,21 @@ require (
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tinylib/msgp v1.1.8 // indirect
- github.com/tklauser/go-sysconf v0.3.11 // indirect
- github.com/tklauser/numcpus v0.6.0 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.47.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
- github.com/yusufpapurcu/wmi v1.2.3 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/sync v0.3.0 // indirect
- golang.org/x/sys v0.9.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ modernc.org/libc v1.22.5 // indirect
+ modernc.org/mathutil v1.5.0 // indirect
+ modernc.org/memory v1.5.0 // indirect
+ modernc.org/sqlite v1.23.1 // indirect
)
replace github.com/iineva/bom v0.0.0-20210605043415-7d45ba1bcca3 => github.com/bitxeno/bom v0.0.0-20230705034132-b3d31612b8ac
diff --git a/go.sum b/go.sum
index c257974..d0a01c7 100644
--- a/go.sum
+++ b/go.sum
@@ -105,6 +105,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
@@ -130,6 +132,12 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
+github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
+github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
+github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
+github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
+github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
@@ -193,10 +201,10 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -278,9 +286,8 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
-github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
-github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
@@ -345,8 +352,6 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
-github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
@@ -360,6 +365,8 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
+github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
@@ -470,6 +477,9 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/qiniu/go-sdk/v7 v7.9.5/go.mod h1:Eeqk1/Km3f1MuLUUkg2JCSg/dVkydKbBvEdJJqFgn9g=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
@@ -501,12 +511,11 @@ github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJv
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
-github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
+github.com/shirou/gopsutil/v4 v4.24.5 h1:gGsArG5K6vmsh5hcFOHaPm87UD003CaDMkAOweSQjhM=
+github.com/shirou/gopsutil/v4 v4.24.5/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
-github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shogo82148/androidbinary v1.0.2/go.mod h1:c3BBft4TLXkvqry+EEN8z9ZtyY09r7jLMvFB/L/KrfI=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/silenceper/wechat/v2 v2.1.5 h1:eIlv61v2bAFBG9ZE75zuRC0ALHEZEUq8JlJ9tfKvatg=
@@ -530,8 +539,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -539,9 +546,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -550,10 +555,10 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
-github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
-github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
-github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
-github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
@@ -572,8 +577,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
-github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
-github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
@@ -722,12 +727,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
-golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
@@ -844,11 +849,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
-gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
-gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
-gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
-gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
+gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
+gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -856,6 +858,14 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
howett.net/plist v0.0.0-20201203080718-1454fab16a06/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
+modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
+modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
+modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
+modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
+modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
+modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
+modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/internal/app/app.go b/internal/app/app.go
index c82bc68..5bda8dd 100644
--- a/internal/app/app.go
+++ b/internal/app/app.go
@@ -1,139 +1,19 @@
package app
import (
- "fmt"
- "math"
-
- "github.com/bitxeno/atvloadly/internal/cfg"
- "github.com/bitxeno/atvloadly/internal/cmd"
"github.com/bitxeno/atvloadly/internal/db"
- "github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/internal/mode"
- "github.com/bitxeno/atvloadly/internal/version"
- "github.com/fatih/color"
- "github.com/gofiber/fiber/v2"
- "github.com/urfave/cli/v2"
"gorm.io/gorm"
)
-var instance *Application
-
-type Application struct {
- Name string
- Desc string
- Version version.Info
- Mode mode.AppMode // 用于加载不同环境变量和配置文件
- Port int
- DebugLog bool
- VerboseLog bool
-
- server *fiber.App
- routers []RouteFunc
-}
-
-func New(name string, desc string) *Application {
- instance = &Application{
- Name: name,
- Desc: desc,
- Version: version.Get(),
- Mode: mode.Get(),
- DebugLog: false,
- VerboseLog: false,
- server: fiber.New(fiber.Config{
- BodyLimit: math.MaxInt,
- }),
- routers: []RouteFunc{},
- }
-
- return instance
-}
-
-func (a *Application) AddBoot(fn BootFunc) {
- addBoot(fn)
-}
-
-func (a *Application) AddBoots(boots ...Bootstrapper) {
- addBoots(boots...)
-}
-
-func (a *Application) Route(fn RouteFunc) {
- a.routers = append(a.routers, fn)
-}
-
-func (a *Application) Run(arguments []string) (err error) {
- return cmd.Run(a.Name, a.Desc, arguments, func(c *cli.Context) error {
- a.Port = c.Int("port")
- a.DebugLog = c.Bool("debug")
- a.VerboseLog = c.Bool("verbose")
-
- a.runWeb(c.String("config"))
- return nil
- })
-}
-
-func (a *Application) runWeb(configFile string) {
- // load config. 配置优先级:命令行参数 > 环境变量 > 配置文件
- if configFile != "" {
- cfg.Server.SetPath(configFile)
- }
- cfg.Server.Load()
-
- // run bootstrap middleware
- bootLauncher.Prepend(
- BootFunc(initLogger),
- BootFunc(initDb),
- )
- bootLauncher.Run()
-
- // add web router
- for _, router := range a.routers {
- router(a.server)
- }
-
- // run web server
- listenPort := a.Port
- if listenPort <= 0 {
- listenPort = cfg.Server.Port
- }
-
- a.printAppVersion()
- err := a.server.Listen(fmt.Sprintf("%s:%d", cfg.Server.ListenAddr, listenPort))
- if err != nil {
- log.Error(err.Error())
- }
-}
-
-func (a *Application) printAppVersion() {
- color.New(color.FgGreen).Printf("Starting %s version: ", a.Name)
- color.New(color.FgCyan).Printf("%s@%s@%v\n", a.Version.Version, a.Version.BuildDate, a.Mode)
-}
-
-func (a *Application) SetConfigPath(path string) {
- cfg.Server.SetPath(path)
-}
-
-func Environment() mode.AppMode {
- return instance.Mode
-}
-
-func DevelopmentMode() bool {
- return mode.IsDevelopmentMode()
-}
-
-func Name() string {
- return instance.Name
-}
-
-func Version() version.Info {
- return instance.Version
+func Environment() AppMode {
+ return Mode
}
func ReloadConfig() {
- cfg.Server.Reload()
}
-func Cfg() *cfg.ServerConfiguration {
- return cfg.Server
+func Cfg() *Configuration {
+ return Config
}
func Db() *gorm.DB {
diff --git a/internal/app/booter.go b/internal/app/booter.go
deleted file mode 100644
index 0aacc71..0000000
--- a/internal/app/booter.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package app
-
-import "github.com/bitxeno/atvloadly/internal/log"
-
-var bootLauncher = &Launcher{}
-
-type Bootstrapper interface {
- // Name() string
- Boot() error
-}
-
-type BootFunc func() error
-
-func (bf BootFunc) Boot() error {
- return bf()
-}
-
-type Launcher struct {
- Boots []Bootstrapper
-}
-
-func (l *Launcher) Add(boots ...Bootstrapper) {
- l.Boots = append(l.Boots, boots...)
-}
-
-func (l *Launcher) Prepend(boots ...Bootstrapper) {
- l.Boots = append(boots, l.Boots...)
-}
-
-func (l *Launcher) Run() {
- for _, boot := range l.Boots {
- err := boot.Boot()
- if err != nil {
- log.Panic(err.Error())
- }
- }
-}
-
-func addBoots(boots ...Bootstrapper) {
- bootLauncher.Boots = append(bootLauncher.Boots, boots...)
-}
-
-func addBoot(fn BootFunc) {
- bootLauncher.Boots = append(bootLauncher.Boots, BootFunc(fn))
-}
diff --git a/internal/app/bootstrap.go b/internal/app/bootstrap.go
index 62801cc..8038567 100644
--- a/internal/app/bootstrap.go
+++ b/internal/app/bootstrap.go
@@ -1,34 +1,94 @@
package app
import (
+ "path/filepath"
+
"github.com/bitxeno/atvloadly/internal/cfg"
+ "github.com/bitxeno/atvloadly/internal/db"
"github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/internal/mode"
- "github.com/gofiber/fiber/v2/middleware/logger"
+ "github.com/bitxeno/atvloadly/internal/model"
+ "github.com/creasty/defaults"
)
-func initLogger() error {
+// load config from file
+func InitConfig(path string, debug bool) (*Configuration, error) {
+ var configuration Configuration
+ if err := defaults.Set(&configuration); err != nil {
+ return nil, err
+ }
+ if path == "" {
+ path = filepath.Join(cfg.DefaultConfigDir(), "config.yaml")
+ }
+ c, err := cfg.Load(path)
+ if err != nil {
+ return nil, err
+ }
+ if err := c.BindStruct(&configuration); err != nil {
+ return nil, err
+ }
+ if configuration.Server.DataDir == "" {
+ configuration.Server.DataDir = cfg.DefaultConfigDir()
+ }
+ Config = &configuration
+
+ if debug {
+ c.PrintConfig()
+ }
+
+ return &configuration, nil
+}
+
+// load settings from file
+func InitSettings(conf *Configuration, debug bool) error {
+ var settings SettingsConfiguration
+ if err := defaults.Set(&settings); err != nil {
+ return err
+ }
+
+ confDir := conf.Server.DataDir
+ if confDir == "" {
+ confDir = cfg.DefaultConfigDir()
+ }
+ path := filepath.Join(confDir, "settings.json")
+ c, err := cfg.Load(path)
+ if err != nil {
+ return err
+ }
+ if err := c.BindStruct(&settings); err != nil {
+ return err
+ }
+ go startSaveSettingsJob(path)
+ Settings = &settings
+
+ if debug {
+ c.PrintConfig()
+ }
+
+ return nil
+}
+
+func InitLogger(conf *Configuration) error {
// set normal log
- log.AddFileOutput(cfg.Server.Log)
- if instance.DebugLog || mode.IsDevelopmentMode() {
+ log.AddFileOutput(conf.Log.LogFile)
+ if conf.Log.Level == "debug" {
log.SetDebugLevel()
}
- if instance.VerboseLog {
+ if conf.Log.Level == "trace" {
log.SetTraceLevel()
}
-
- // set fiber web server access log
- instance.server.Use(logger.New())
- accessWriter := log.CreateRollingLogFile(cfg.Server.AccessLog)
- if accessWriter != nil {
- instance.server.Use(logger.New(logger.Config{
- Output: accessWriter,
- }))
- log.Infof("Web access log file path: %s", cfg.Server.AccessLog)
- }
return nil
}
-func initDb() error {
+func InitDb(conf *Configuration) error {
+ if conf.Db.Path == "" {
+ conf.Db.Path = conf.Server.DataDir
+ }
+ if conf.Db.Path == "" {
+ conf.Db.Path = cfg.DefaultConfigDir()
+ }
+ if err := db.Open(conf.Db).AutoMigrate(&model.InstalledApp{}); err != nil {
+ return err
+ }
+
return nil
}
diff --git a/internal/app/build/var.go b/internal/app/build/var.go
new file mode 100644
index 0000000..438b743
--- /dev/null
+++ b/internal/app/build/var.go
@@ -0,0 +1,11 @@
+package build
+
+var (
+ /*********Will auto update by ci build *********/
+ Version = "unknown"
+ Commit = "unknown"
+ BuildDate = "unknown"
+
+ Mode = "development"
+ /*********Will auto update by ci build *********/
+)
diff --git a/internal/app/config.go b/internal/app/config.go
new file mode 100644
index 0000000..8232cfb
--- /dev/null
+++ b/internal/app/config.go
@@ -0,0 +1,42 @@
+package app
+
+import (
+ "fmt"
+
+ "github.com/bitxeno/atvloadly/internal/db"
+)
+
+var (
+ Config *Configuration
+)
+
+// configuration holds any kind of configuration that comes from the outside world and
+// is necessary for running the application.
+type Configuration struct {
+ App struct {
+ LockdownDir string `koanf:"lockdown_dir" default:"/var/lib/lockdown"`
+ DeveloperDiskImage struct {
+ ImageSource string `koanf:"image_source" json:"image_source" default:"https://github.com/haikieu/xcode-developer-disk-image-all-platforms/raw/master/DiskImages/AppleTVOS.platform/DeviceSupport/{0}.zip"`
+ CNProxy string `koanf:"cn_proxy" json:"cn_proxy" default:"https://mirror.ghproxy.com"`
+ } `koanf:"developer_disk_image" json:"developer_disk_image"`
+ }
+
+ Log struct {
+ Level string `koanf:"level" default:"info"`
+ TimeFormat string `koanf:"time_format" default:"2006-01-02 15:04:05.000"`
+ LogFile string `koanf:"log_file"`
+ AccessLog string `koanf:"access_log"`
+ } `koanf:"log" json:"log"`
+
+ Server struct {
+ ListenAddr string `koanf:"listen_addr" default:"0.0.0.0"`
+ Port int `koanf:"port" default:"9000"`
+ DataDir string `koanf:"data_dir"`
+ } `koanf:"app" json:"app"`
+
+ Db db.Config `koanf:"db" json:"db"`
+}
+
+func SideloaderDataDir() string {
+ return fmt.Sprintf("%s/Sideloader", Config.Server.DataDir)
+}
diff --git a/internal/app/const.go b/internal/app/const.go
new file mode 100644
index 0000000..1161a2a
--- /dev/null
+++ b/internal/app/const.go
@@ -0,0 +1,3 @@
+package app
+
+const ()
diff --git a/internal/app/mode.go b/internal/app/mode.go
new file mode 100644
index 0000000..3eabc61
--- /dev/null
+++ b/internal/app/mode.go
@@ -0,0 +1,25 @@
+package app
+
+import "github.com/bitxeno/atvloadly/internal/app/build"
+
+const (
+ DevelopmentMode AppMode = "development"
+ ProductionMode AppMode = "production"
+ TestMode AppMode = "test"
+)
+
+var Mode = AppMode(build.Mode)
+
+type AppMode string
+
+func IsDevelopmentMode() bool {
+ return build.Mode == string(DevelopmentMode)
+}
+
+func IsTestMode() bool {
+ return build.Mode == string(TestMode)
+}
+
+func IsProductionMode() bool {
+ return build.Mode == string(ProductionMode)
+}
diff --git a/internal/app/router.go b/internal/app/router.go
deleted file mode 100644
index 6eaab8a..0000000
--- a/internal/app/router.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package app
-
-import "github.com/gofiber/fiber/v2"
-
-type RouteFunc func(*fiber.App)
diff --git a/config/settings.go b/internal/app/settings.go
similarity index 76%
rename from config/settings.go
rename to internal/app/settings.go
index 53b4ec6..e0c08c0 100644
--- a/config/settings.go
+++ b/internal/app/settings.go
@@ -1,19 +1,17 @@
-package config
+package app
import (
- "io/ioutil"
"math"
"os"
- "path/filepath"
"time"
- "github.com/bitxeno/atvloadly/internal/cfg"
"github.com/bitxeno/atvloadly/internal/log"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/creasty/defaults"
)
-var Settings SettingsConfiguration
+var (
+ Settings *SettingsConfiguration
+)
var saveTimer *time.Timer = time.NewTimer(math.MaxInt64)
const (
@@ -49,24 +47,6 @@ type SettingsConfiguration struct {
} `koanf:"notification" json:"notification"`
}
-func loadSettings() error {
- conf := cfg.New()
- conf.SetPath(filepath.Join(cfg.Server.WorkDir, "settings.json"))
- conf.Load()
-
- // set default value
- if err := defaults.Set(&Settings); err != nil {
- return err
- }
- if err := conf.BindStruct("", &Settings); err != nil {
- return err
- }
-
- saveTimer.Stop()
- go startSaveSettingsJob(conf.Path())
- return nil
-}
-
func SaveSettings() {
saveTimer.Reset(100 * time.Millisecond)
}
@@ -83,7 +63,7 @@ func startSaveSettingsJob(settingsPath string) {
}
data := utils.ToIndentJSON(Settings)
- if err := ioutil.WriteFile(settingsPath, data, os.ModePerm); err != nil {
+ if err := os.WriteFile(settingsPath, data, os.ModePerm); err != nil {
log.Err(err).Msg("Save settings error.")
} else {
log.Infof("Save settings success. %s", settingsPath)
diff --git a/internal/app/version.go b/internal/app/version.go
new file mode 100644
index 0000000..ff3a042
--- /dev/null
+++ b/internal/app/version.go
@@ -0,0 +1,16 @@
+package app
+
+import "github.com/bitxeno/atvloadly/internal/app/build"
+
+var Version = AppVersion{
+ Commit: build.Commit,
+ Version: build.Version,
+ BuildDate: build.BuildDate,
+}
+
+// Info holds build information
+type AppVersion struct {
+ Commit string `json:"commit"`
+ Version string `json:"version"`
+ BuildDate string `json:"build_date"`
+}
diff --git a/internal/cfg/cfg.go b/internal/cfg/cfg.go
index 21a9475..b5a08ae 100644
--- a/internal/cfg/cfg.go
+++ b/internal/cfg/cfg.go
@@ -2,88 +2,83 @@ package cfg
import (
"fmt"
+ "log"
"path/filepath"
- "github.com/bitxeno/atvloadly/internal/log"
"github.com/bitxeno/atvloadly/internal/utils"
+ "github.com/creasty/defaults"
+ "github.com/go-errors/errors"
"github.com/knadh/koanf"
"github.com/knadh/koanf/parsers/json"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/file"
)
-type Configuration struct {
+type configuration struct {
ko *koanf.Koanf
path string
}
-func New() *Configuration {
- return &Configuration{
+func New() *configuration {
+ return &configuration{
ko: koanf.New("."),
- path: filepath.Join(defaultConfigDir(), "config.yaml"),
+ path: filepath.Join(DefaultConfigDir(), "config.yaml"),
}
}
-func (c *Configuration) SetPath(path string) {
- if filepath.IsAbs(path) {
+func (c *configuration) load(path string) error {
+ if path != "" {
c.path = path
- } else {
- c.path = filepath.Join(defaultConfigDir(), path)
}
-}
-
-func (c *Configuration) Path() string {
- return c.path
-}
-
-func (c *Configuration) Load() {
- // read config
- if utils.Exists(c.path) {
- ext := filepath.Ext(c.path)
- if ext == ".yaml" || ext == ".yml" {
- if err := c.ko.Load(file.Provider(c.path), yaml.Parser()); err != nil {
- log.Panicf("Yaml config file read failed. error: %s \n", err)
- }
- }
- if ext == ".json" {
- if err := c.ko.Load(file.Provider(c.path), json.Parser()); err != nil {
- log.Panicf("Json config file read failed. error: %s \n", err)
- }
- }
- } else {
- fmt.Printf("Config file not exists. file: %s\n", c.path)
+ // set default value
+ if err := defaults.Set(c); err != nil {
+ return errors.New(err)
}
- c.printConfig()
-}
-
-func (c *Configuration) MustLoad() {
+ // read config from file
+ ko := koanf.New(".")
if !utils.Exists(c.path) {
- log.Panicf("Config file not exists. file: %s \n", c.path)
+ fmt.Printf("[WARN] Config file not exists. path: %s\n", c.path)
+ return nil
}
- // read config
+ fmt.Printf("Load config from path: %s\n", c.path)
ext := filepath.Ext(c.path)
if ext == ".yaml" || ext == ".yml" {
- if err := c.ko.Load(file.Provider(c.path), yaml.Parser()); err != nil {
- log.Panicf("Config file read failed. error: %s \n", err)
+ if err := ko.Load(file.Provider(c.path), yaml.Parser()); err != nil {
+ log.Panicf("Yaml config file read failed. error: %s \n", err)
}
}
-
if ext == ".json" {
- if err := c.ko.Load(file.Provider(c.path), json.Parser()); err != nil {
- log.Panicf("Config file read failed. error: %s \n", err)
+ if err := ko.Load(file.Provider(c.path), json.Parser()); err != nil {
+ log.Panicf("Json config file read failed. error: %s \n", err)
}
}
- c.printConfig()
+ return ko.Unmarshal("", &c)
+}
+
+func (c *configuration) BindStruct(dst any) error {
+ return c.ko.Unmarshal("", dst)
}
-func (c *Configuration) BindStruct(key string, dst any) error {
- return c.ko.Unmarshal(key, dst)
+func (c *configuration) Reload() {
+ _ = c.load("")
}
-func (c *Configuration) Reload() {
- c.Load()
+func (c *configuration) PrintConfig() {
+ configName := filepath.Base(c.path)
+ fmt.Printf("##################### Load %s begin #####################\n", configName)
+ c.ko.Print()
+ fmt.Printf("##################### Load %s end #####################\n", configName)
+}
+
+func Load(path string) (*configuration, error) {
+ conf := New()
+ if err := conf.load(path); err != nil {
+ return nil, err
+ }
+
+ return conf, nil
}
diff --git a/internal/cfg/cfg_darwin.go b/internal/cfg/cfg_darwin.go
index 229dc0f..7681c2d 100644
--- a/internal/cfg/cfg_darwin.go
+++ b/internal/cfg/cfg_darwin.go
@@ -1,14 +1,17 @@
+//go:build darwin
+
package cfg
import (
+ "log"
"os"
"path/filepath"
)
-func defaultConfigDir() string {
+func DefaultConfigDir() string {
execPath, err := os.Executable()
if err != nil {
- panic(err)
+ log.Panic(err)
}
execName := filepath.Base(execPath)
diff --git a/internal/cfg/cfg_dev.go b/internal/cfg/cfg_dev.go
deleted file mode 100644
index 2543062..0000000
--- a/internal/cfg/cfg_dev.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build dev
-
-package cfg
-
-import (
- "fmt"
- "path/filepath"
-)
-
-func (c *Configuration) printConfig() {
- configName := filepath.Base(c.path)
- fmt.Printf("##################### Load %s begin #####################\n", configName)
- c.ko.Print()
- fmt.Printf("##################### Load %s end #####################\n", configName)
-}
diff --git a/internal/cfg/cfg_linux.go b/internal/cfg/cfg_linux.go
index 229dc0f..0ce99eb 100644
--- a/internal/cfg/cfg_linux.go
+++ b/internal/cfg/cfg_linux.go
@@ -1,14 +1,17 @@
+//go:build linux
+
package cfg
import (
+ "log"
"os"
"path/filepath"
)
-func defaultConfigDir() string {
+func DefaultConfigDir() string {
execPath, err := os.Executable()
if err != nil {
- panic(err)
+ log.Panic(err)
}
execName := filepath.Base(execPath)
diff --git a/internal/cfg/cfg_prod.go b/internal/cfg/cfg_prod.go
deleted file mode 100644
index 252e95b..0000000
--- a/internal/cfg/cfg_prod.go
+++ /dev/null
@@ -1,7 +0,0 @@
-//go:build !dev
-
-package cfg
-
-func (c *Configuration) printConfig() {
-
-}
diff --git a/internal/cfg/cfg_windows.go b/internal/cfg/cfg_windows.go
index 48dd5d7..024a5f9 100644
--- a/internal/cfg/cfg_windows.go
+++ b/internal/cfg/cfg_windows.go
@@ -1,5 +1,7 @@
+//go:build windows
+
package cfg
-func defaultConfigDir() string {
+func DefaultConfigDir() string {
return "."
}
diff --git a/internal/cfg/entity.go b/internal/cfg/entity.go
deleted file mode 100644
index 89da567..0000000
--- a/internal/cfg/entity.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package cfg
-
-import (
- "path/filepath"
-
- "github.com/bitxeno/atvloadly/internal/log"
- "github.com/creasty/defaults"
-)
-
-var Server = newServerConfiguration()
-
-type ServerConfiguration struct {
- Configuration
-
- ListenAddr string `koanf:"listen_addr"`
- Port int `koanf:"port" default:"9000"`
- TimeFormat string `koanf:"time_format" default:"2006-01-02 15:04:05"`
- LogTimeFormat string `koanf:"log_time_format" default:"2006-01-02 15:04:05.000"`
- WorkDir string `koanf:"work_dir"`
- Log string `koanf:"log"`
- AccessLog string `koanf:"access_log"`
-}
-
-func newServerConfiguration() *ServerConfiguration {
- return &ServerConfiguration{
- Configuration: *New(),
- }
-}
-
-func (c *ServerConfiguration) Load() {
- c.Configuration.Load()
-
- // set default value
- if err := defaults.Set(c); err != nil {
- log.Panicf("Config set default failed. error: %s \n", err)
- }
-
- if err := c.ko.Unmarshal("server", c); err != nil {
- log.Panicf("Config unable to decode into struct, %v\n", err)
- }
-
- // set default data dir
- if c.WorkDir == "" {
- c.WorkDir = defaultConfigDir()
- }
-}
-
-func (c *ServerConfiguration) MustLoad() {
- c.Configuration.MustLoad()
-
- // set default value
- if err := defaults.Set(c); err != nil {
- log.Panicf("Config set default failed. error: %s \n", err)
- }
-
- if err := c.ko.Unmarshal("server", c); err != nil {
- log.Panicf("Config unable to decode into struct, %v\n", err)
- }
-
- // set default data dir
- if c.WorkDir == "" {
- c.WorkDir = defaultConfigDir()
- }
-}
-
-func (c *ServerConfiguration) Reload() {
- c.Load()
-}
-
-func (c *ServerConfiguration) DbPath() string {
- return filepath.Join(c.WorkDir, "app.db")
-
-}
diff --git a/internal/cmd/main.go b/internal/cmd/main.go
deleted file mode 100644
index 4bcf29b..0000000
--- a/internal/cmd/main.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package cmd
-
-import (
- "os"
-
- "github.com/bitxeno/atvloadly/internal/version"
- "github.com/urfave/cli/v2"
-)
-
-func Run(name string, desc string, arguments []string, webServerAction cli.ActionFunc) (err error) {
- cliApp := &cli.App{
- Name: name,
- Usage: desc,
- Version: version.Version,
- Commands: []*cli.Command{
- genCommand,
- {
- Name: "server",
- Usage: "Run web server",
- Flags: serverFlags,
- Action: webServerAction,
- },
- },
- }
-
- return cliApp.Run(os.Args)
-}
diff --git a/internal/cmd/server.go b/internal/cmd/server.go
deleted file mode 100644
index 589c411..0000000
--- a/internal/cmd/server.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package cmd
-
-import (
- "github.com/urfave/cli/v2"
-)
-
-var (
- serverFlags = []cli.Flag{
- &cli.IntFlag{
- Name: "port",
- Aliases: []string{"p"},
- Usage: "web server port",
- },
- &cli.StringFlag{
- Name: "config",
- Aliases: []string{"c"},
- Usage: "Load configuration from `FILE`",
- },
- &cli.BoolFlag{
- Name: "debug",
- Aliases: []string{"vv"},
- Usage: "Change to debug log level",
- Value: false,
- },
- &cli.BoolFlag{
- Name: "verbose",
- Aliases: []string{"vvv"},
- Usage: "Change to verbose log level",
- Value: false,
- },
- }
-)
diff --git a/internal/db/config.go b/internal/db/config.go
new file mode 100644
index 0000000..4531278
--- /dev/null
+++ b/internal/db/config.go
@@ -0,0 +1,7 @@
+package db
+
+type Config struct {
+ Path string `koanf:"path"`
+ FileName string `koanf:"filename" default:"app.db"`
+ Debug bool `koanf:"debug" default:"false"`
+}
diff --git a/internal/db/db.go b/internal/db/db.go
index e141a30..8d4e99b 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -5,10 +5,8 @@ import (
"os"
"path/filepath"
- "github.com/bitxeno/atvloadly/internal/cfg"
"github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/internal/mode"
- "gorm.io/driver/sqlite"
+ "github.com/glebarez/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
@@ -18,18 +16,20 @@ var instance *sqliteDb
type sqliteDb struct {
db *gorm.DB
path string
+ conf Config
}
-func New() *sqliteDb {
- dbDir := cfg.Server.WorkDir
+func new(conf Config) *sqliteDb {
+ dbDir := conf.Path
if _, err := os.Stat(dbDir); err != nil {
if err := os.MkdirAll(dbDir, os.ModePerm); err != nil {
- panic("failed to create database directory")
+ log.Panicf("failed to create database directory. path: %s", dbDir)
}
}
return &sqliteDb{
- path: filepath.Join(dbDir, "app.db"),
+ path: filepath.Join(dbDir, conf.FileName),
+ conf: conf,
}
}
@@ -44,11 +44,11 @@ func (s *sqliteDb) Open() *sqliteDb {
}
conf := &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)}
- if mode.Get() == mode.DevelopmentMode {
+ if s.conf.Debug {
conf.Logger = logger.Default.LogMode(logger.Info)
}
- fmt.Printf("Load db path: %s\n", s.path)
+ fmt.Printf("Load database from path: %s\n", s.path)
db, err := gorm.Open(sqlite.Open(s.path), conf)
if err != nil {
panic("failed to open database")
@@ -79,8 +79,8 @@ func Store() *gorm.DB {
return instance.db
}
-func Open() *sqliteDb {
- instance = New().Open()
+func Open(conf Config) *sqliteDb {
+ instance = new(conf).Open()
return instance
}
diff --git a/ipa/ipa.go b/internal/ipa/ipa.go
similarity index 100%
rename from ipa/ipa.go
rename to internal/ipa/ipa.go
diff --git a/ipa/package_info.go b/internal/ipa/package_info.go
similarity index 100%
rename from ipa/package_info.go
rename to internal/ipa/package_info.go
diff --git a/manager/device_manager.go b/internal/manager/device_manager.go
similarity index 95%
rename from manager/device_manager.go
rename to internal/manager/device_manager.go
index 8350dae..34b17a7 100644
--- a/manager/device_manager.go
+++ b/internal/manager/device_manager.go
@@ -7,10 +7,10 @@ import (
"sync"
"time"
- "github.com/bitxeno/atvloadly/config"
+ "github.com/bitxeno/atvloadly/internal/app"
"github.com/bitxeno/atvloadly/internal/log"
+ "github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/model"
)
var deviceManager = newDeviceManager()
@@ -92,7 +92,7 @@ func (dm *DeviceManager) GetMountImageInfo(udid string) (*model.UsbmuxdImage, er
return nil, err
}
- imageInfo := model.NewUsbmuxdImage(*devInfo, config.App.DeveloperDiskImage.ImageSource)
+ imageInfo := model.NewUsbmuxdImage(*devInfo, app.Config.App.DeveloperDiskImage.ImageSource)
imageMounted, err := dm.CheckHasMountImage(udid)
if err == nil {
imageInfo.ImageMounted = imageMounted
diff --git a/manager/device_manager_avahi.go b/internal/manager/device_manager_avahi.go
similarity index 98%
rename from manager/device_manager_avahi.go
rename to internal/manager/device_manager_avahi.go
index 03cdde1..5a47467 100644
--- a/manager/device_manager_avahi.go
+++ b/internal/manager/device_manager_avahi.go
@@ -7,8 +7,8 @@ import (
"strings"
"github.com/bitxeno/atvloadly/internal/log"
+ "github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/model"
"github.com/godbus/dbus/v5"
"github.com/holoplot/go-avahi"
)
diff --git a/manager/device_manager_mdns.go b/internal/manager/device_manager_mdns.go
similarity index 98%
rename from manager/device_manager_mdns.go
rename to internal/manager/device_manager_mdns.go
index d98897f..cf85210 100644
--- a/manager/device_manager_mdns.go
+++ b/internal/manager/device_manager_mdns.go
@@ -9,8 +9,8 @@ import (
"time"
"github.com/bitxeno/atvloadly/internal/log"
+ "github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/model"
"github.com/grandcat/zeroconf"
)
diff --git a/manager/device_manager_usbmuxd.go b/internal/manager/device_manager_usbmuxd.go
similarity index 97%
rename from manager/device_manager_usbmuxd.go
rename to internal/manager/device_manager_usbmuxd.go
index 23d50fe..619322a 100644
--- a/manager/device_manager_usbmuxd.go
+++ b/internal/manager/device_manager_usbmuxd.go
@@ -9,8 +9,8 @@ import (
"strings"
"time"
+ "github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/model"
gidevice "github.com/electricbubble/gidevice"
)
diff --git a/manager/lockdown.go b/internal/manager/lockdown.go
similarity index 78%
rename from manager/lockdown.go
rename to internal/manager/lockdown.go
index 03aa996..e181ff3 100644
--- a/manager/lockdown.go
+++ b/internal/manager/lockdown.go
@@ -3,17 +3,16 @@ package manager
import (
"bytes"
"fmt"
- "io/ioutil"
"os"
- "github.com/bitxeno/atvloadly/config"
+ "github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/model"
"howett.net/plist"
)
func loadLockdownDevices() (map[string]model.LockdownDevice, error) {
- files, err := ioutil.ReadDir(config.App.LockdownDir)
+ files, err := os.ReadDir(app.Config.App.LockdownDir)
if err != nil {
fmt.Println(err)
// return nil, err
@@ -28,7 +27,7 @@ func loadLockdownDevices() (map[string]model.LockdownDevice, error) {
continue
}
- buf, err := os.ReadFile(fmt.Sprintf("%s/%s", config.App.LockdownDir, file.Name()))
+ buf, err := os.ReadFile(fmt.Sprintf("%s/%s", app.Config.App.LockdownDir, file.Name()))
if err != nil {
return nil, err
}
diff --git a/manager/manager.go b/internal/manager/manager.go
similarity index 90%
rename from manager/manager.go
rename to internal/manager/manager.go
index 941520a..1cbfeae 100644
--- a/manager/manager.go
+++ b/internal/manager/manager.go
@@ -1,6 +1,6 @@
package manager
-import "github.com/bitxeno/atvloadly/model"
+import "github.com/bitxeno/atvloadly/internal/model"
func StartDeviceManager() {
go deviceManager.Start()
diff --git a/internal/mode/mode.go b/internal/mode/mode.go
deleted file mode 100644
index 46e37c3..0000000
--- a/internal/mode/mode.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package mode
-
-var (
- /*********Will auto update by ci build *********/
- Mode = "development"
- /*********Will auto update by ci build *********/
-)
-
-const (
- DevelopmentMode AppMode = "development"
- ProductionMode AppMode = "production"
- TestMode AppMode = "test"
-)
-
-type AppMode string
-
-func Get() AppMode {
- return AppMode(Mode)
-}
-
-func IsDevelopmentMode() bool {
- return Mode == string(DevelopmentMode)
-}
-
-func IsTestMode() bool {
- return Mode == string(TestMode)
-}
-
-func IsProductionMode() bool {
- return Mode == string(ProductionMode)
-}
diff --git a/model/device.go b/internal/model/device.go
similarity index 100%
rename from model/device.go
rename to internal/model/device.go
diff --git a/model/installed_app.go b/internal/model/installed_app.go
similarity index 100%
rename from model/installed_app.go
rename to internal/model/installed_app.go
diff --git a/model/ipa_file.go b/internal/model/ipa_file.go
similarity index 100%
rename from model/ipa_file.go
rename to internal/model/ipa_file.go
diff --git a/model/lockdown_device.go b/internal/model/lockdown_device.go
similarity index 100%
rename from model/lockdown_device.go
rename to internal/model/lockdown_device.go
diff --git a/model/service_status.go b/internal/model/service_status.go
similarity index 100%
rename from model/service_status.go
rename to internal/model/service_status.go
diff --git a/model/usbmuxd_device.go b/internal/model/usbmuxd_device.go
similarity index 100%
rename from model/usbmuxd_device.go
rename to internal/model/usbmuxd_device.go
diff --git a/model/usbmuxd_image.go b/internal/model/usbmuxd_image.go
similarity index 100%
rename from model/usbmuxd_image.go
rename to internal/model/usbmuxd_image.go
diff --git a/notify/notify.go b/internal/notify/notify.go
similarity index 87%
rename from notify/notify.go
rename to internal/notify/notify.go
index b590ee2..4761030 100644
--- a/notify/notify.go
+++ b/internal/notify/notify.go
@@ -4,9 +4,9 @@ import (
"context"
"errors"
- "github.com/bitxeno/atvloadly/config"
+ "github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/notify/wecom"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/notify/wecom"
"github.com/nikoksr/notify"
"github.com/nikoksr/notify/service/bark"
"github.com/nikoksr/notify/service/telegram"
@@ -14,10 +14,10 @@ import (
)
func Send(title string, message string) error {
- return SendWithConfig(title, message, config.Settings)
+ return SendWithConfig(title, message, *app.Settings)
}
-func SendWithConfig(title string, message string, settings config.SettingsConfiguration) error {
+func SendWithConfig(title string, message string, settings app.SettingsConfiguration) error {
if !settings.Notification.Enabled {
return errors.New("未启用")
}
diff --git a/notify/wecom/wecom.go b/internal/notify/wecom/wecom.go
similarity index 100%
rename from notify/wecom/wecom.go
rename to internal/notify/wecom/wecom.go
diff --git a/service/db.go b/internal/service/db.go
similarity index 93%
rename from service/db.go
rename to internal/service/db.go
index e3515ee..de8b439 100644
--- a/service/db.go
+++ b/internal/service/db.go
@@ -6,10 +6,10 @@ import (
"path/filepath"
"time"
- "github.com/bitxeno/atvloadly/internal/cfg"
+ conf "github.com/bitxeno/atvloadly/internal/app"
"github.com/bitxeno/atvloadly/internal/db"
"github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/model"
+ "github.com/bitxeno/atvloadly/internal/model"
"gorm.io/gorm"
)
@@ -62,7 +62,7 @@ func SaveApp(app model.InstalledApp) (*model.InstalledApp, error) {
cur.Password = app.Password
// 把ipa/icon移动到id目录
- saveDir := filepath.Join(cfg.Server.WorkDir, "ipa", fmt.Sprintf("%d", app.ID))
+ saveDir := filepath.Join(conf.Config.Server.DataDir, "ipa", fmt.Sprintf("%d", app.ID))
if cur.IpaPath != "" {
ipaPath := filepath.Join(saveDir, "app.ipa")
if err := os.Rename(cur.IpaPath, ipaPath); err != nil {
@@ -103,7 +103,7 @@ func SaveApp(app model.InstalledApp) (*model.InstalledApp, error) {
}
// 把ipa/icon移动到id目录
- saveDir := filepath.Join(cfg.Server.WorkDir, "ipa", fmt.Sprintf("%d", app.ID))
+ saveDir := filepath.Join(conf.Config.Server.DataDir, "ipa", fmt.Sprintf("%d", app.ID))
if err := os.MkdirAll(saveDir, os.ModePerm); err != nil {
panic("failed to create directory :" + saveDir)
}
diff --git a/service/service.go b/internal/service/service.go
similarity index 74%
rename from service/service.go
rename to internal/service/service.go
index 3d104c0..83c09ae 100644
--- a/service/service.go
+++ b/internal/service/service.go
@@ -11,14 +11,13 @@ import (
"strings"
"github.com/artdarek/go-unzip/pkg/unzip"
- "github.com/bitxeno/atvloadly/config"
- "github.com/bitxeno/atvloadly/internal/cfg"
+ "github.com/bitxeno/atvloadly/internal/app"
"github.com/bitxeno/atvloadly/internal/http"
"github.com/bitxeno/atvloadly/internal/log"
+ "github.com/bitxeno/atvloadly/internal/manager"
+ "github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/manager"
- "github.com/bitxeno/atvloadly/model"
- "github.com/shirou/gopsutil/v3/process"
+ ps "github.com/mitchellh/go-ps"
)
var (
@@ -44,25 +43,16 @@ func GetServiceStatus() []model.ServiceStatus {
Running: checkProcessExists(proc),
})
- proc = "anisette-server"
- status = append(status, model.ServiceStatus{
- Name: proc,
- Running: checkProcessExists(proc),
- })
-
return status
}
func checkProcessExists(name string) bool {
- processes, err := process.Processes()
+ processes, err := ps.Processes()
if err != nil {
return false
}
for _, p := range processes {
- n, err := p.Name()
- if err != nil {
- return false
- }
+ n := p.Executable()
if n == name {
return true
}
@@ -109,8 +99,8 @@ func downloadDeveloperDiskImage(imageInfo *model.UsbmuxdImage) (dmg string, sign
// download current version DeveloperDiskImage
err := downloadDeveloperDiskImageByVersion(imageInfo.DeveloperDiskImageUrl, imageInfo.DeveloperDiskImageVersion)
if err == nil {
- dmg = filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", imageInfo.DeveloperDiskImageVersion, "DeveloperDiskImage.dmg")
- signature = filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", imageInfo.DeveloperDiskImageVersion, "DeveloperDiskImage.dmg.signature")
+ dmg = filepath.Join(app.Config.Server.DataDir, "DeveloperDiskImage", imageInfo.DeveloperDiskImageVersion, "DeveloperDiskImage.dmg")
+ signature = filepath.Join(app.Config.Server.DataDir, "DeveloperDiskImage", imageInfo.DeveloperDiskImageVersion, "DeveloperDiskImage.dmg.signature")
return
}
@@ -118,11 +108,11 @@ func downloadDeveloperDiskImage(imageInfo *model.UsbmuxdImage) (dmg string, sign
// current version DeveloperDiskImage not found, try fallback to last minor version
for fallbackMinor := imageInfo.VersionMinor - 1; fallbackMinor > 0; fallbackMinor-- {
fallbackVersion := fmt.Sprintf("%d.%d", imageInfo.VersionMajor, fallbackMinor)
- fallbackImageUrl := strings.Replace(config.App.DeveloperDiskImage.ImageSource, "{0}", fallbackVersion, -1)
+ fallbackImageUrl := strings.Replace(app.Config.App.DeveloperDiskImage.ImageSource, "{0}", fallbackVersion, -1)
log.Warnf("try downgrade developer disk image to version: %s", fallbackVersion)
if err := downloadDeveloperDiskImageByVersion(fallbackImageUrl, fallbackVersion); err == nil {
- dmg = filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", fallbackVersion, "DeveloperDiskImage.dmg")
- signature = filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", fallbackVersion, "DeveloperDiskImage.dmg.signature")
+ dmg = filepath.Join(app.Config.Server.DataDir, "DeveloperDiskImage", fallbackVersion, "DeveloperDiskImage.dmg")
+ signature = filepath.Join(app.Config.Server.DataDir, "DeveloperDiskImage", fallbackVersion, "DeveloperDiskImage.dmg.signature")
return
}
}
@@ -137,22 +127,22 @@ func downloadDeveloperDiskImage(imageInfo *model.UsbmuxdImage) (dmg string, sign
}
func downloadDeveloperDiskImageByVersion(url string, version string) error {
- imageVersionDir := filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", version)
+ imageVersionDir := filepath.Join(app.Config.Server.DataDir, "DeveloperDiskImage", version)
dmg := filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg")
signature := filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg.signature")
if utils.Exists(dmg) && utils.Exists(signature) {
return nil
}
- tmpPath := filepath.Join(cfg.Server.WorkDir, "tmp", "DeveloperDiskImage.zip")
- tmpUnzipPath := filepath.Join(cfg.Server.WorkDir, "tmp", "DeveloperDiskImage")
+ tmpPath := filepath.Join(app.Config.Server.DataDir, "tmp", "DeveloperDiskImage.zip")
+ tmpUnzipPath := filepath.Join(app.Config.Server.DataDir, "tmp", "DeveloperDiskImage")
_ = os.RemoveAll(tmpUnzipPath)
// download current version DeveloperDiskImage
hasDownloaded := false
- if config.App.DeveloperDiskImage.CNProxy != "" {
+ if app.Config.App.DeveloperDiskImage.CNProxy != "" {
// download by proxy
- cnProxyUrl := strings.TrimSuffix(config.App.DeveloperDiskImage.CNProxy, "/") + "/" + url
+ cnProxyUrl := strings.TrimSuffix(app.Config.App.DeveloperDiskImage.CNProxy, "/") + "/" + url
if resp, err := http.NewClient().R().SetOutput(tmpPath).Get(cnProxyUrl); err == nil && resp.IsSuccess() {
hasDownloaded = true
}
diff --git a/service/service_test.go b/internal/service/service_test.go
similarity index 84%
rename from service/service_test.go
rename to internal/service/service_test.go
index 581bba6..20d1b63 100644
--- a/service/service_test.go
+++ b/internal/service/service_test.go
@@ -2,13 +2,9 @@ package service
import (
"testing"
-
- "github.com/bitxeno/atvloadly/config"
)
func TestDownloadDeveloperDiskImageByVersion(t *testing.T) {
- _ = config.Load()
-
err := downloadDeveloperDiskImageByVersion("https://github.com/haikieu/xcode-developer-disk-image-all-platforms/raw/master/DiskImages/AppleTVOS.platform/DeviceSupport/16.4.zip", "16.4")
if err != nil {
t.Error(err)
diff --git a/task/task.go b/internal/task/task.go
similarity index 83%
rename from task/task.go
rename to internal/task/task.go
index e1cf879..a3ed3b3 100644
--- a/task/task.go
+++ b/internal/task/task.go
@@ -12,14 +12,12 @@ import (
"strings"
"time"
- "github.com/bitxeno/atvloadly/config"
"github.com/bitxeno/atvloadly/internal/app"
- "github.com/bitxeno/atvloadly/internal/cfg"
"github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/manager"
- "github.com/bitxeno/atvloadly/model"
- "github.com/bitxeno/atvloadly/notify"
- "github.com/bitxeno/atvloadly/service"
+ "github.com/bitxeno/atvloadly/internal/manager"
+ "github.com/bitxeno/atvloadly/internal/model"
+ "github.com/bitxeno/atvloadly/internal/notify"
+ "github.com/bitxeno/atvloadly/internal/service"
"github.com/robfig/cron/v3"
)
@@ -45,19 +43,19 @@ func (t *Task) RunSchedule() error {
t.c = nil
}
- if !config.Settings.Task.Enabled {
+ if !app.Settings.Task.Enabled {
log.Info("app刷新定时任务未启用")
return nil
}
t.c = cron.New()
- if _, err := t.c.AddFunc(config.Settings.Task.CrodTime, t.Run); err != nil {
- log.Err(err).Msgf("app刷新定时任务启动失败,定时格式错误:%s", config.Settings.Task.CrodTime)
+ if _, err := t.c.AddFunc(app.Settings.Task.CrodTime, t.Run); err != nil {
+ log.Err(err).Msgf("app刷新定时任务启动失败,定时格式错误:%s", app.Settings.Task.CrodTime)
t.c = nil
return err
}
- log.Infof("app刷新定时任务已启动,时间: %s", config.Settings.Task.CrodTime)
+ log.Infof("app刷新定时任务已启动,时间: %s", app.Settings.Task.CrodTime)
t.c.Start()
return nil
@@ -120,7 +118,7 @@ func (t *Task) Run() {
// 发送安装失败通知
if len(failedList) > 0 {
- _ = notify.Send(fmt.Sprintf("%s自动刷新任务执行失败", app.Name()), failedMsg)
+ _ = notify.Send("atvloadly 自动刷新任务执行失败", failedMsg)
}
}
@@ -128,7 +126,7 @@ func (t *Task) checkNeedRefresh(v model.InstalledApp) bool {
now := time.Now()
// 过期时间少于一天时,再安装
- if config.Settings.Task.Mode == config.OneDayAgoMode {
+ if app.Settings.Task.Mode == app.OneDayAgoMode {
expireTime := v.RefreshedDate.AddDate(0, 0, 6)
if expireTime.Before(now) {
return true
@@ -136,7 +134,7 @@ func (t *Task) checkNeedRefresh(v model.InstalledApp) bool {
}
// 每天安装
- if config.Settings.Task.Mode == config.DailyMode {
+ if app.Settings.Task.Mode == app.DailyMode {
if v.RefreshedDate.Format("2006-01-02") != now.Format("2006-01-02") {
return true
}
@@ -188,13 +186,9 @@ func (t *Task) runInternal(v model.InstalledApp) error {
return err
}
- // 为每个appleid创建对应的工作目录,用于存储AltServer生成的签名证书
- dirName := regValidName.ReplaceAllString(strings.ToLower(v.Account), "")
- workdir := filepath.Join(cfg.Server.WorkDir, "AltServer", dirName)
-
- cmd := exec.Command("AltServer", "-u", v.UDID, "-a", v.Account, "-p", v.Password, v.IpaPath)
- cmd.Dir = workdir
- cmd.Env = []string{"ALTSERVER_ANISETTE_SERVER=http://127.0.0.1:6969"}
+ cmd := exec.Command("sideloader", "install", "--quiet", "--udid", v.UDID, "-a", v.Account, "-p", v.Password, v.IpaPath)
+ cmd.Dir = app.Config.Server.DataDir
+ cmd.Env = []string{"SIDELOADER_CONFIG_DIR=" + app.SideloaderDataDir()}
stdin, err := cmd.StdinPipe()
if err != nil {
log.Err(err).Msg("Error obtaining stdin: ")
@@ -259,7 +253,7 @@ func (t *Task) writeLog(v model.InstalledApp, data []byte) {
// 打码密码字符串
data = bytes.Replace(data, []byte(v.Password), []byte("******"), -1)
- saveDir := filepath.Join(cfg.Server.WorkDir, "log")
+ saveDir := filepath.Join(app.Config.Server.DataDir, "log")
if err := os.MkdirAll(saveDir, os.ModePerm); err != nil {
log.Error("failed to create directory :" + saveDir)
return
diff --git a/tty/lib/function.go b/internal/tty/lib/function.go
similarity index 87%
rename from tty/lib/function.go
rename to internal/tty/lib/function.go
index d23146d..579c2eb 100644
--- a/tty/lib/function.go
+++ b/internal/tty/lib/function.go
@@ -2,13 +2,13 @@ package lib
import (
"crypto/x509"
- "io/ioutil"
"log"
+ "os"
)
// ReadCertPool get CertPool by crt file
func ReadCertPool(crt string) *x509.CertPool {
- _crt, err := ioutil.ReadFile(crt)
+ _crt, err := os.ReadFile(crt)
if err != nil {
log.Fatalln("Read crt file failed:", err.Error())
}
diff --git a/tty/lib/message.go b/internal/tty/lib/message.go
similarity index 100%
rename from tty/lib/message.go
rename to internal/tty/lib/message.go
diff --git a/tty/pipeline.go b/internal/tty/pipeline.go
similarity index 98%
rename from tty/pipeline.go
rename to internal/tty/pipeline.go
index 0a52e04..8f896c2 100644
--- a/tty/pipeline.go
+++ b/internal/tty/pipeline.go
@@ -5,7 +5,7 @@ import (
"fmt"
"io"
- "github.com/bitxeno/atvloadly/tty/lib"
+ "github.com/bitxeno/atvloadly/internal/tty/lib"
"github.com/gofiber/contrib/websocket"
"github.com/runletapp/go-console"
)
diff --git a/tty/tty.go b/internal/tty/tty.go
similarity index 93%
rename from tty/tty.go
rename to internal/tty/tty.go
index 8ffd27c..eac5b59 100644
--- a/tty/tty.go
+++ b/internal/tty/tty.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/bitxeno/atvloadly/internal/cfg"
+ "github.com/bitxeno/atvloadly/internal/app"
"github.com/gofiber/contrib/websocket"
)
@@ -41,7 +41,7 @@ func (t *TTY) Close() {
func (t *TTY) Start() {
if t.cwd != "" {
- if _, err := t.pl.pty.Write([]byte(fmt.Sprintf("cd \"%s\"\n", cfg.Server.WorkDir))); err != nil {
+ if _, err := t.pl.pty.Write([]byte(fmt.Sprintf("cd \"%s\"\n", app.Config.Server.DataDir))); err != nil {
_ = t.conn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
return
}
diff --git a/internal/version/build.go b/internal/version/build.go
deleted file mode 100644
index 808dd50..0000000
--- a/internal/version/build.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package version
-
-var (
- /*********Will auto update by ci build *********/
- Version = "unknown"
- Commit = "unknown"
- BuildDate = "unknown"
- /*********Will auto update by ci build *********/
-)
-
-// Info holds build information
-type Info struct {
- Commit string `json:"commit"`
- Version string `json:"version"`
- BuildDate string `json:"build_date"`
-}
-
-// Get creates and initialized Info object
-func Get() Info {
- return Info{
- Commit: Commit,
- Version: Version,
- BuildDate: BuildDate,
- }
-}
diff --git a/main.go b/main.go
index 9673c3c..659c958 100644
--- a/main.go
+++ b/main.go
@@ -4,15 +4,11 @@ import (
"fmt"
"os"
- "github.com/bitxeno/atvloadly/config"
- "github.com/bitxeno/atvloadly/internal/app"
- "github.com/bitxeno/atvloadly/internal/db"
- _ "github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/manager"
- "github.com/bitxeno/atvloadly/model"
- "github.com/bitxeno/atvloadly/router"
- "github.com/bitxeno/atvloadly/task"
- "github.com/gofiber/fiber/v2"
+ "github.com/bitxeno/atvloadly/cmd/gen"
+ "github.com/bitxeno/atvloadly/cmd/server"
+ "github.com/bitxeno/atvloadly/internal/app/build"
+ "github.com/go-errors/errors"
+ "github.com/urfave/cli/v2"
)
const (
@@ -23,25 +19,23 @@ const (
)
func main() {
- app := app.New(AppName, AppDesc)
- app.Route(func(f *fiber.App) {
- router.Create(f, getViewAssets())
- })
- app.AddBoot(func() error {
- if err := config.Load(); err != nil {
- return err
- }
- if err := db.Open().AutoMigrate(&model.InstalledApp{}); err != nil {
- return err
- }
- _ = task.ScheduleRefreshApps()
- manager.StartDeviceManager()
- return nil
- })
- if err := app.Run(os.Args); err != nil {
- code := 1
- fmt.Fprintln(os.Stderr, err)
- os.Exit(code)
+ cliApp := &cli.App{
+ Name: AppName,
+ Usage: AppDesc,
+ Version: build.Version,
+ Commands: []*cli.Command{
+ gen.Command,
+ server.Command,
+ },
+ }
+
+ if err := cliApp.Run(os.Args); err != nil {
+ if e, ok := err.(*errors.Error); ok {
+ fmt.Fprintln(os.Stderr, e.ErrorStack())
+ } else {
+ fmt.Fprintln(os.Stderr, err)
+ }
+ os.Exit(1)
}
}
diff --git a/router/api_result.go b/web/api_result.go
similarity index 95%
rename from router/api_result.go
rename to web/api_result.go
index 7a10311..c3b7027 100644
--- a/router/api_result.go
+++ b/web/api_result.go
@@ -1,4 +1,4 @@
-package router
+package web
type ApiResult struct {
Code int `json:"code"`
diff --git a/web/fs_dev.go b/web/fs_dev.go
new file mode 100644
index 0000000..5c13a2a
--- /dev/null
+++ b/web/fs_dev.go
@@ -0,0 +1,12 @@
+//go:build dev
+
+package web
+
+import (
+ "io/fs"
+ "os"
+)
+
+func StaticAssets() fs.FS {
+ return os.DirFS("static/dist")
+}
diff --git a/web/fs_prod.go b/web/fs_prod.go
new file mode 100644
index 0000000..50cdfc3
--- /dev/null
+++ b/web/fs_prod.go
@@ -0,0 +1,20 @@
+//go:build !dev
+
+package web
+
+import (
+ "embed"
+ "io/fs"
+)
+
+//go:embed all:static/dist/*
+var static embed.FS
+
+func StaticAssets() fs.FS {
+ embed, err := fs.Sub(static, "static/dist")
+ if err != nil {
+ panic(err)
+ }
+
+ return embed
+}
diff --git a/router/router.go b/web/router.go
similarity index 85%
rename from router/router.go
rename to web/router.go
index 2c56c93..2a58f67 100644
--- a/router/router.go
+++ b/web/router.go
@@ -1,34 +1,32 @@
-package router
+package web
import (
"fmt"
"image/png"
- "io/fs"
"net/http"
"os"
"path/filepath"
"time"
- "github.com/bitxeno/atvloadly/config"
- "github.com/bitxeno/atvloadly/internal/cfg"
+ "github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/ipa"
+ "github.com/bitxeno/atvloadly/internal/manager"
+ "github.com/bitxeno/atvloadly/internal/model"
+ "github.com/bitxeno/atvloadly/internal/notify"
+ "github.com/bitxeno/atvloadly/internal/service"
+ "github.com/bitxeno/atvloadly/internal/task"
+ "github.com/bitxeno/atvloadly/internal/tty"
"github.com/bitxeno/atvloadly/internal/utils"
- "github.com/bitxeno/atvloadly/ipa"
- "github.com/bitxeno/atvloadly/manager"
- "github.com/bitxeno/atvloadly/model"
- "github.com/bitxeno/atvloadly/notify"
- "github.com/bitxeno/atvloadly/service"
- "github.com/bitxeno/atvloadly/task"
- "github.com/bitxeno/atvloadly/tty"
"github.com/gofiber/contrib/websocket"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/filesystem"
)
-func Create(app *fiber.App, f fs.FS) {
- app.Use("/", filesystem.New(filesystem.Config{
- Root: http.FS(f),
+func route(fi *fiber.App) {
+ fi.Use("/", filesystem.New(filesystem.Config{
+ Root: http.FS(StaticAssets()),
}))
- app.Use("/ws", func(c *fiber.Ctx) error {
+ fi.Use("/ws", func(c *fiber.Ctx) error {
// IsWebSocketUpgrade returns true if the client
// requested upgrade to the WebSocket protocol.
if websocket.IsWebSocketUpgrade(c) {
@@ -37,7 +35,7 @@ func Create(app *fiber.App, f fs.FS) {
}
return fiber.ErrUpgradeRequired
})
- app.Get("/ws/tty", websocket.New(func(c *websocket.Conn) {
+ fi.Get("/ws/tty", websocket.New(func(c *websocket.Conn) {
term, err := tty.New(c, "bash")
if err != nil {
_ = c.WriteMessage(websocket.TextMessage, []byte(err.Error()))
@@ -45,11 +43,11 @@ func Create(app *fiber.App, f fs.FS) {
}
defer term.Close()
- term.SetCWD(cfg.Server.WorkDir)
- term.SetENV([]string{"ALTSERVER_ANISETTE_SERVER=\"http://127.0.0.1:6969\""})
+ term.SetCWD(app.Config.Server.DataDir)
+ term.SetENV([]string{"SIDELOADER_CONFIG_DIR=" + app.SideloaderDataDir()})
term.Start()
}))
- app.Get("/apps/:id/icon", func(c *fiber.Ctx) error {
+ fi.Get("/apps/:id/icon", func(c *fiber.Ctx) error {
id := utils.MustParseInt(c.Params("id"))
t, err := service.GetApp(uint(id))
@@ -63,24 +61,24 @@ func Create(app *fiber.App, f fs.FS) {
return c.Status(http.StatusNotFound).SendString("")
}
})
- app.Get("/apps/:id/log", func(c *fiber.Ctx) error {
+ fi.Get("/apps/:id/log", func(c *fiber.Ctx) error {
id := utils.MustParseInt(c.Params("id"))
- path := filepath.Join(cfg.Server.WorkDir, "log", fmt.Sprintf("task_%d.log", id))
+ path := filepath.Join(app.Config.Server.DataDir, "log", fmt.Sprintf("task_%d.log", id))
return c.Status(http.StatusOK).SendFile(path, false)
})
// api路由
- api := app.Group("/api")
+ api := fi.Group("/api")
api.Get("/hello", func(c *fiber.Ctx) error {
return c.SendString("hello world.")
})
api.Get("/settings", func(c *fiber.Ctx) error {
- return c.Status(http.StatusOK).JSON(apiSuccess(config.Settings))
+ return c.Status(http.StatusOK).JSON(apiSuccess(app.Settings))
})
api.Post("/settings/:key", func(c *fiber.Ctx) error {
- var settings config.SettingsConfiguration
+ var settings app.SettingsConfiguration
if err := c.BodyParser(&settings); err != nil {
return c.Status(http.StatusOK).JSON(apiError("Invalid argument. error: " + err.Error()))
}
@@ -88,15 +86,15 @@ func Create(app *fiber.App, f fs.FS) {
key := c.Params("key")
switch key {
case "notification":
- config.Settings.Notification = settings.Notification
+ app.Settings.Notification = settings.Notification
case "task":
- config.Settings.Task = settings.Task
+ app.Settings.Task = settings.Task
if err := task.ReloadTask(); err != nil {
return c.Status(http.StatusOK).JSON(apiError("时间格式错误: " + err.Error()))
}
}
- config.SaveSettings()
+ app.SaveSettings()
return c.Status(http.StatusOK).JSON(apiSuccess(true))
})
@@ -162,7 +160,7 @@ func Create(app *fiber.App, f fs.FS) {
result := []model.IpaFile{}
for _, file := range files {
- saveDir := filepath.Join(cfg.Server.WorkDir, "tmp")
+ saveDir := filepath.Join(app.Config.Server.DataDir, "tmp")
if err := os.MkdirAll(saveDir, os.ModePerm); err != nil {
return c.Status(http.StatusOK).JSON(apiError("failed to create directory :" + saveDir))
}
@@ -282,7 +280,7 @@ func Create(app *fiber.App, f fs.FS) {
})
api.Post("/notify/send/test", func(c *fiber.Ctx) error {
- var settings config.SettingsConfiguration
+ var settings app.SettingsConfiguration
if err := c.BodyParser(&settings); err != nil {
return c.Status(http.StatusOK).JSON(apiError("Invalid argument. error: " + err.Error()))
}
diff --git a/view/index.html b/web/static/index.html
similarity index 100%
rename from view/index.html
rename to web/static/index.html
diff --git a/view/package-lock.json b/web/static/package-lock.json
similarity index 100%
rename from view/package-lock.json
rename to web/static/package-lock.json
diff --git a/view/package.json b/web/static/package.json
similarity index 100%
rename from view/package.json
rename to web/static/package.json
diff --git a/view/postcss.config.js b/web/static/postcss.config.js
similarity index 100%
rename from view/postcss.config.js
rename to web/static/postcss.config.js
diff --git a/view/public/img/dummy.jpg b/web/static/public/img/dummy.jpg
similarity index 100%
rename from view/public/img/dummy.jpg
rename to web/static/public/img/dummy.jpg
diff --git a/view/src/App.vue b/web/static/src/App.vue
similarity index 100%
rename from view/src/App.vue
rename to web/static/src/App.vue
diff --git a/view/src/api/api.js b/web/static/src/api/api.js
similarity index 100%
rename from view/src/api/api.js
rename to web/static/src/api/api.js
diff --git a/view/src/app.css b/web/static/src/app.css
similarity index 100%
rename from view/src/app.css
rename to web/static/src/app.css
diff --git a/view/src/assets/icons/appletv.svg b/web/static/src/assets/icons/appletv.svg
similarity index 100%
rename from view/src/assets/icons/appletv.svg
rename to web/static/src/assets/icons/appletv.svg
diff --git a/view/src/assets/icons/checkmark.svg b/web/static/src/assets/icons/checkmark.svg
similarity index 100%
rename from view/src/assets/icons/checkmark.svg
rename to web/static/src/assets/icons/checkmark.svg
diff --git a/view/src/assets/icons/dismiss.svg b/web/static/src/assets/icons/dismiss.svg
similarity index 100%
rename from view/src/assets/icons/dismiss.svg
rename to web/static/src/assets/icons/dismiss.svg
diff --git a/view/src/assets/icons/github.svg b/web/static/src/assets/icons/github.svg
similarity index 100%
rename from view/src/assets/icons/github.svg
rename to web/static/src/assets/icons/github.svg
diff --git a/view/src/assets/icons/help.svg b/web/static/src/assets/icons/help.svg
similarity index 100%
rename from view/src/assets/icons/help.svg
rename to web/static/src/assets/icons/help.svg
diff --git a/view/src/assets/icons/language.svg b/web/static/src/assets/icons/language.svg
similarity index 100%
rename from view/src/assets/icons/language.svg
rename to web/static/src/assets/icons/language.svg
diff --git a/view/src/assets/icons/settings.svg b/web/static/src/assets/icons/settings.svg
similarity index 100%
rename from view/src/assets/icons/settings.svg
rename to web/static/src/assets/icons/settings.svg
diff --git a/view/src/assets/icons/warning.svg b/web/static/src/assets/icons/warning.svg
similarity index 100%
rename from view/src/assets/icons/warning.svg
rename to web/static/src/assets/icons/warning.svg
diff --git a/view/src/i18n.js b/web/static/src/i18n.js
similarity index 100%
rename from view/src/i18n.js
rename to web/static/src/i18n.js
diff --git a/view/src/locales/en/translation.json b/web/static/src/locales/en/translation.json
similarity index 100%
rename from view/src/locales/en/translation.json
rename to web/static/src/locales/en/translation.json
diff --git a/view/src/locales/zh_cn/translation.json b/web/static/src/locales/zh_cn/translation.json
similarity index 100%
rename from view/src/locales/zh_cn/translation.json
rename to web/static/src/locales/zh_cn/translation.json
diff --git a/view/src/main.js b/web/static/src/main.js
similarity index 100%
rename from view/src/main.js
rename to web/static/src/main.js
diff --git a/view/src/page/home/index.vue b/web/static/src/page/home/index.vue
similarity index 100%
rename from view/src/page/home/index.vue
rename to web/static/src/page/home/index.vue
diff --git a/view/src/page/install/index.vue b/web/static/src/page/install/index.vue
similarity index 90%
rename from view/src/page/install/index.vue
rename to web/static/src/page/install/index.vue
index f152eef..5c28aaa 100644
--- a/view/src/page/install/index.vue
+++ b/web/static/src/page/install/index.vue
@@ -206,14 +206,8 @@ export default {
.then((res) => {
let ipa = res.data[0];
_this.ipa = ipa;
-
- // 为每个appleid创建对应的工作目录,用于存储AltServer生成的签名证书
- let dirName = _this.form.account
- .toLowerCase()
- .replace(/[^0-9a-zA-Z]+/gi, "");
- let workdir = `./AltServer/${dirName}`;
_this.websocketsend(
- `mkdir -p ${workdir} && cd ${workdir} && AltServer -u ${_this.device.udid} -a '${_this.form.account}' -p '${_this.form.password}' '${ipa.path}'`
+ `sideloader --udid ${_this.device.udid} -a '${_this.form.account}' -p '${_this.form.password}' '${ipa.path}'`
);
})
.catch((error) => {
@@ -287,44 +281,32 @@ export default {
);
_this.cmd.line = _this.cmd.line.replace(_this.form.password, "******");
- if (
- _this.cmd.line.indexOf("Signing Progress") === -1 &&
- _this.cmd.line.indexOf("AltServer -u") === -1
- ) {
+ // if (
+ // _this.cmd.line.indexOf("slideloader") === -1
+ // ) {
_this.log.output += _this.cmd.line;
// The textbox follows the scroll to the bottom
_this.$nextTick(() => {
const textarea = document.querySelector("#log");
textarea.scrollTop = textarea.scrollHeight;
});
- }
+ // }
_this.cmd.line = "";
}
// input 2FA authentication code
- if (_this.cmd.output.indexOf("Enter two factor code") !== -1) {
+ if (_this.cmd.output.indexOf("A code has been sent to your devices, please type it here") !== -1) {
_this.cmd.output = "";
_this.dialogVisible = true;
return;
}
- // override innstall with the same Apple ID as before.
- if (
- _this.cmd.output.indexOf(
- "Installing AltStore with Multiple AltServers Not Supported"
- ) !== -1
- ) {
- if (_this.cmd.output.indexOf("Press any key to continue...") !== -1) {
- _this.cmd.output = "";
- _this.websocketsend("");
- return;
- }
- }
// pairing error
if (
_this.cmd.output.indexOf("Could not install") !== -1 ||
+ _this.cmd.output.indexOf("Error:") !== -1 ||
_this.cmd.output.indexOf("command not found") !== -1
) {
_this.cmd.output = "";
diff --git a/view/src/page/layout.vue b/web/static/src/page/layout.vue
similarity index 100%
rename from view/src/page/layout.vue
rename to web/static/src/page/layout.vue
diff --git a/view/src/page/pair/index.vue b/web/static/src/page/pair/index.vue
similarity index 100%
rename from view/src/page/pair/index.vue
rename to web/static/src/page/pair/index.vue
diff --git a/view/src/page/settings/index.vue b/web/static/src/page/settings/index.vue
similarity index 100%
rename from view/src/page/settings/index.vue
rename to web/static/src/page/settings/index.vue
diff --git a/view/src/router/index.js b/web/static/src/router/index.js
similarity index 100%
rename from view/src/router/index.js
rename to web/static/src/router/index.js
diff --git a/view/src/utils/crypto.js b/web/static/src/utils/crypto.js
similarity index 100%
rename from view/src/utils/crypto.js
rename to web/static/src/utils/crypto.js
diff --git a/view/src/utils/request.js b/web/static/src/utils/request.js
similarity index 100%
rename from view/src/utils/request.js
rename to web/static/src/utils/request.js
diff --git a/view/tailwind.config.js b/web/static/tailwind.config.js
similarity index 100%
rename from view/tailwind.config.js
rename to web/static/tailwind.config.js
diff --git a/view/vite.config.js b/web/static/vite.config.js
similarity index 100%
rename from view/vite.config.js
rename to web/static/vite.config.js
diff --git a/view/yarn.lock b/web/static/yarn.lock
similarity index 100%
rename from view/yarn.lock
rename to web/static/yarn.lock
diff --git a/web/web.go b/web/web.go
new file mode 100644
index 0000000..657b4bb
--- /dev/null
+++ b/web/web.go
@@ -0,0 +1,31 @@
+package web
+
+import (
+ "fmt"
+
+ "github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/log"
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/logger"
+)
+
+func Run(addr string, port int) error {
+ server := fiber.New()
+ route(server)
+
+ // set fiber web server access log
+ server.Use(logger.New())
+ accessWriter := log.CreateRollingLogFile(app.Config.Log.AccessLog)
+ if accessWriter != nil {
+ server.Use(logger.New(logger.Config{
+ Output: accessWriter,
+ }))
+ log.Infof("Web access log file path: %s", app.Config.Log.AccessLog)
+ }
+
+ if err := server.Listen(fmt.Sprintf("%s:%d", addr, port)); err != nil {
+ log.Error(err.Error())
+ return err
+ }
+ return nil
+}
From 06811748a97686b925ef0249f166fe70dafb4666 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 06:54:11 +0000
Subject: [PATCH 02/35] feat: add tvos17 support
---
.github/workflows/beta.yml | 95 ----------
.github/workflows/build.yml | 19 +-
.github/workflows/clean_package.yml | 8 +-
.github/workflows/issue_close_inactive.yml | 6 +-
.github/workflows/release-nightly.yml | 192 +++++++++++++++++++++
.github/workflows/release.yml | 163 ++++++++++++-----
Dockerfile | 2 +-
go.mod | 10 +-
go.sum | 23 +--
internal/app/config.go | 2 +-
internal/task/task.go | 52 ++++--
web/static/src/page/install/index.vue | 24 +--
web/static/yarn.lock | 10 --
web/web.go | 5 +-
14 files changed, 384 insertions(+), 227 deletions(-)
delete mode 100644 .github/workflows/beta.yml
create mode 100644 .github/workflows/release-nightly.yml
diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml
deleted file mode 100644
index 943cbc2..0000000
--- a/.github/workflows/beta.yml
+++ /dev/null
@@ -1,95 +0,0 @@
-# Attention:
-# - Need goto [Settings -> Actions -> general]
-# - Set [workflow permissions] to "Read and write permissions"
-name: "🚀 Beta"
-
-# on events
-on:
- workflow_dispatch:
-
-# jobs
-jobs:
- beta:
- name: Generate beta builds
- strategy:
- matrix:
- go_version: [1.18.x]
- runs-on: ubuntu-latest
- steps:
- # step 1: checkout repository code
- - name: Checkout the repository
- uses: actions/checkout@v3
-
- # step 2: setup build envirement
- - uses: actions/setup-go@v3
- with:
- go-version: ${{ matrix.go_version }}
- - uses: actions/setup-node@v2
- with:
- node-version: "16"
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v2
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
-
- # step 3: set workflow variables
- - name: Initialize workflow variables
- id: vars
- run: |
- echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_OUTPUT
- echo "BUILDDATE=$(date '+%F-%T')" >> $GITHUB_OUTPUT
- echo "COMMIT=$(git rev-parse --verify HEAD)" >> $GITHUB_OUTPUT
- echo "APP_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
- echo "REPO=$(echo 'github.com/${{ github.repository }}')" >> $GITHUB_OUTPUT
- echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_OUTPUT
-
- if [ ! -z $DOCKER_TOKEN ]; then echo "HAS_DOCKER_TOKEN=${HAS_DOCKER_TOKEN}" >> $GITHUB_OUTPUT; fi
- env:
- DOCKER_TOKEN: "${{ secrets.DOCKER_TOKEN }}"
-
- # step 4: generate build files
- - name: build frontend
- run: cd ./view && npm install && npm run build
- - name: Generate build files
- uses: crazy-max/ghaction-xgo@v2
- with:
- xgo_version: latest
- go_version: ${{ matrix.go_version }}
- dest: build
- prefix: ${{steps.vars.outputs.APP_NAME}}
- targets: linux/amd64,linux/arm64
- v: true
- x: false
- ldflags: -w -s -X ${{steps.vars.outputs.REPO}}/internal/version.Version=${{steps.vars.outputs.VERSION}} -X ${{steps.vars.outputs.REPO}}/internal/version.BuildDate=${{steps.vars.outputs.BUILDDATE}} -X ${{steps.vars.outputs.REPO}}/internal/version.Commit=${{steps.vars.outputs.COMMIT}} -X ${{steps.vars.outputs.REPO}}/internal/mode.Mode=production
-
- - name: Upload artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{steps.vars.outputs.APP_NAME}}
- path: build
-
- # step 7.2: push to GitHub Container Registry
- - name: Login to GitHub Container Registry
- uses: docker/login-action@v2
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
- - name: Extract metadata (tags, labels) for Docker
- id: meta
- uses: docker/metadata-action@v4
- with:
- images: ghcr.io/${{ github.repository }}
- - name: Build and push Docker images to ghci
- uses: docker/build-push-action@v4
- with:
- context: .
- push: true
- platforms: linux/amd64,linux/arm64
- tags: ghcr.io/${{ github.repository }}:beta
- labels: ${{ steps.meta.outputs.labels }}
- build-args: |
- APP_NAME=${{steps.vars.outputs.APP_NAME}}
- VERSION=${{steps.vars.outputs.VERSION}}
- BUILDDATE=${{steps.vars.outputs.BUILDDATE}}
- COMMIT=${{steps.vars.outputs.COMMIT}}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7635c92..d66197c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,22 +11,23 @@ jobs:
build:
strategy:
matrix:
- go_version: [1.18.x]
+ go_version: [1.21.x]
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go_version }}
- - uses: actions/setup-node@v2
+ - uses: actions/setup-node@v4
with:
- node-version: "16"
- - uses: actions/checkout@v3
+ node-version: "20"
+ - uses: actions/checkout@v4
- name: build frontend
- run: cd ./view && npm install && npm run build
- - uses: golangci/golangci-lint-action@v3
+ run: cd ./web/static && npm install && npm run build
+ - name: golangci-lint
+ uses: golangci/golangci-lint-action@v6
with:
- version: v1.53.2
- args: --out-format=colored-line-number --timeout=5m
+ version: v1.58
+ args: --timeout=5m
- run: go mod download
- # - run: go test -coverprofile=coverage.txt -covermode=atomic ./...
+ - run: go test -coverprofile=coverage.txt -covermode=atomic ./...
diff --git a/.github/workflows/clean_package.yml b/.github/workflows/clean_package.yml
index c3d4c71..509dba6 100644
--- a/.github/workflows/clean_package.yml
+++ b/.github/workflows/clean_package.yml
@@ -5,8 +5,8 @@ name: "🗑️ Clean Package"
# Controls when the workflow will run
on:
- schedule:
- - cron: "0 0 1 * *" # the first day of the month
+ # schedule:
+ # - cron: "0 0 * * 1" # the first day of the week
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@@ -28,8 +28,8 @@ jobs:
uses: snok/container-retention-policy@v2
with:
image-names: ${{steps.vars.outputs.APP_NAME}}
- cut-off: A week ago UTC
+ cut-off: A month ago UTC
keep-at-least: 10
- skip-tags: latest
+ skip-tags: latest, beta, alpha, main, master
account-type: personal
token: ${{ secrets.PAT }}
diff --git a/.github/workflows/issue_close_inactive.yml b/.github/workflows/issue_close_inactive.yml
index 4bb86ce..41767f4 100644
--- a/.github/workflows/issue_close_inactive.yml
+++ b/.github/workflows/issue_close_inactive.yml
@@ -1,8 +1,8 @@
name: "🚫 Close Inactive"
on:
- schedule:
- - cron: "0 0 * * 1"
+ # schedule:
+ # - cron: "0 0 * * 1" # the first day of the week
workflow_dispatch:
jobs:
@@ -20,4 +20,4 @@ jobs:
days-before-stale: 30
days-before-close: 0
days-before-pr-stale: -1
- days-before-pr-close: -1
\ No newline at end of file
+ days-before-pr-close: -1
diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml
new file mode 100644
index 0000000..6f9fd34
--- /dev/null
+++ b/.github/workflows/release-nightly.yml
@@ -0,0 +1,192 @@
+name: "🚀 Release Nightly"
+
+# on events
+on:
+ # schedule:
+ # - cron: '0 0 * * *' # runs daily at 00:00
+ workflow_dispatch:
+ # push:
+ # branches: [main, master, release/v*]
+
+# jobs
+jobs:
+ check:
+ name: Check has new commits today
+ permissions:
+ contents: write
+ runs-on: ubuntu-latest
+ outputs:
+ new_commit_count: ${{steps.commit_check.outputs.new_commit_count}}
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+ - name: Check for new commits
+ id: commit_check
+ run: echo "new_commit_count=$(git log --oneline --since '24 hours ago' | wc -l)" >> $GITHUB_OUTPUT
+
+ build:
+ name: Generate cross-platform builds
+ if: ${{needs.check.outputs.new_commit_count > 0}}
+ needs: [check]
+ permissions:
+ contents: write
+ strategy:
+ matrix:
+ go_version: [1.21.x]
+ runs-on: ubuntu-latest
+ outputs:
+ VERSION: ${{steps.vars.outputs.VERSION}}
+ BUILDDATE: ${{steps.vars.outputs.BUILDDATE}}
+ COMMIT: ${{steps.vars.outputs.COMMIT}}
+ APP_NAME: ${{steps.vars.outputs.APP_NAME}}
+ PUSH_DOCKERHUB: ${{steps.vars.outputs.PUSH_DOCKERHUB}}
+ steps:
+ # step 1: checkout repository code
+ - name: Checkout the repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ # step 2: setup build envirement
+ - uses: actions/setup-go@v3
+ with:
+ go-version: ${{ matrix.go_version }}
+ - uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ # step 3: set workflow variables
+ - id: metadata
+ uses: ahmadnassri/action-metadata@v2
+ - name: Initialize workflow environments variables
+ id: vars
+ run: |
+ echo "VERSION=${{ github.ref_name }}" >> $GITHUB_OUTPUT
+ echo "BUILDDATE=$(date '+%F-%T')" >> $GITHUB_OUTPUT
+ echo "COMMIT=$(git rev-parse --verify HEAD)" >> $GITHUB_OUTPUT
+ echo "APP_NAME=${{ steps.metadata.outputs.repository_name }}" >> $GITHUB_OUTPUT
+ echo "REPO=$(echo 'github.com/${{ github.repository }}')" >> $GITHUB_OUTPUT
+ echo "BRANCH=${{ steps.metadata.outputs.repository_default_branch }}" >> $GITHUB_OUTPUT
+
+ if [ ! -z $DOCKER_TOKEN ]; then echo "PUSH_DOCKERHUB=1" >> $GITHUB_OUTPUT; fi
+ env:
+ DOCKER_TOKEN: "${{ secrets.DOCKER_TOKEN }}"
+
+ # step 4: generate build files
+ - name: build frontend
+ run: cd ./web/static && npm install && npm run build
+ - name: Generate build files
+ uses: crazy-max/ghaction-xgo@v2
+ env:
+ CGO_ENABLED: "0"
+ with:
+ xgo_version: latest
+ go_version: ${{ matrix.go_version }}
+ dest: build
+ prefix: ${{steps.vars.outputs.APP_NAME}}
+ targets: windows/386,windows/amd64,linux/386,linux/amd64,darwin/386,darwin/amd64,linux/386,linux/arm64
+ v: true
+ x: false
+ ldflags: -w -s -X ${{steps.vars.outputs.REPO}}/internal/app/build.Version=${{steps.vars.outputs.VERSION}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.BuildDate=${{steps.vars.outputs.BUILDDATE}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Commit=${{steps.vars.outputs.COMMIT}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Mode=production
+
+ # step 5: Upload binary to artifact
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{steps.vars.outputs.APP_NAME}}
+ path: build
+ retention-days: 1
+
+ dockerhub:
+ name: Push to DockerHub
+ if: ${{needs.build.outputs.PUSH_DOCKERHUB}}
+ needs: [build]
+ permissions:
+ contents: read
+ packages: write
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v4
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{needs.build.outputs.APP_NAME}}
+ path: build
+ - name: Login to DockerHub
+ if: ${{ steps.vars.outputs.HAS_DOCKER_TOKEN }}
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_TOKEN }}
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}
+ - name: Build and push Docker images to DockerHub
+ if: ${{ steps.vars.outputs.HAS_DOCKER_TOKEN }}
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ push: true
+ provenance: false
+ platforms: linux/amd64,linux/arm64
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ build-args: |
+ APP_NAME=${{needs.build.outputs.APP_NAME}}
+ VERSION=${{needs.build.outputs.VERSION}}
+ BUILDDATE=${{needs.build.outputs.BUILDDATE}}
+ COMMIT=${{needs.build.outputs.COMMIT}}
+
+ ghcr:
+ name: Push to GitHub Container Registry
+ needs: [build]
+ permissions:
+ contents: read
+ packages: write
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v4
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{needs.build.outputs.APP_NAME}}
+ path: build
+ - name: Display structure of downloaded files
+ run: ls -R
+ working-directory: build
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ghcr.io/${{ github.repository }}
+ - name: Build and push Docker images to ghci
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ push: true
+ provenance: false
+ platforms: linux/amd64,linux/arm64
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ build-args: |
+ APP_NAME=${{needs.build.outputs.APP_NAME}}
+ VERSION=${{needs.build.outputs.VERSION}}
+ BUILDDATE=${{needs.build.outputs.BUILDDATE}}
+ COMMIT=${{needs.build.outputs.COMMIT}}
+
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 72b6e0f..e7a03e9 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,6 +1,3 @@
-# Attention:
-# - Need goto [Settings -> Actions -> general]
-# - Set [workflow permissions] to "Read and write permissions"
name: "🚀 Release"
# on events
@@ -10,17 +7,24 @@ on:
# jobs
jobs:
- # generate build cross-platform build files
- release:
+ build:
name: Generate cross-platform builds
+ permissions:
+ contents: write
strategy:
matrix:
- go_version: [1.18.x]
+ go_version: [1.21.x]
runs-on: ubuntu-latest
+ outputs:
+ VERSION: ${{steps.vars.outputs.VERSION}}
+ BUILDDATE: ${{steps.vars.outputs.BUILDDATE}}
+ COMMIT: ${{steps.vars.outputs.COMMIT}}
+ APP_NAME: ${{steps.vars.outputs.APP_NAME}}
+ PUSH_DOCKERHUB: ${{steps.vars.outputs.PUSH_DOCKERHUB}}
steps:
# step 1: checkout repository code
- name: Checkout the repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -28,63 +32,88 @@ jobs:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go_version }}
- - uses: actions/setup-node@v2
+ - uses: actions/setup-node@v4
with:
- node-version: "16"
+ node-version: "20"
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# step 3: set workflow variables
- - name: Initialize workflow variables
+ - id: metadata
+ uses: ahmadnassri/action-metadata@v2
+ - name: Initialize workflow environments variables
id: vars
run: |
- echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_OUTPUT
+ echo "VERSION=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "BUILDDATE=$(date '+%F-%T')" >> $GITHUB_OUTPUT
echo "COMMIT=$(git rev-parse --verify HEAD)" >> $GITHUB_OUTPUT
- echo "APP_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
+ echo "APP_NAME=${{ steps.metadata.outputs.repository_name }}" >> $GITHUB_OUTPUT
echo "REPO=$(echo 'github.com/${{ github.repository }}')" >> $GITHUB_OUTPUT
- echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_OUTPUT
+ echo "BRANCH=${{ steps.metadata.outputs.repository_default_branch }}" >> $GITHUB_OUTPUT
- if [ ! -z $DOCKER_TOKEN ]; then echo "HAS_DOCKER_TOKEN=${HAS_DOCKER_TOKEN}" >> $GITHUB_OUTPUT; fi
+ if [ ! -z $DOCKER_TOKEN ]; then echo "PUSH_DOCKERHUB=1" >> $GITHUB_OUTPUT; fi
env:
DOCKER_TOKEN: "${{ secrets.DOCKER_TOKEN }}"
# step 4: generate build files
- name: build frontend
- run: cd ./view && npm install && npm run build
+ run: cd ./web/static && npm install && npm run build
- name: Generate build files
uses: crazy-max/ghaction-xgo@v2
+ env:
+ CGO_ENABLED: "0"
with:
xgo_version: latest
go_version: ${{ matrix.go_version }}
dest: build
prefix: ${{steps.vars.outputs.APP_NAME}}
- targets: linux/amd64,linux/arm64
+ targets: windows/386,windows/amd64,linux/386,linux/amd64,darwin/386,darwin/amd64,linux/386,linux/arm64
v: true
x: false
- ldflags: -w -s -X ${{steps.vars.outputs.REPO}}/internal/version.Version=${{steps.vars.outputs.VERSION}} -X ${{steps.vars.outputs.REPO}}/internal/version.BuildDate=${{steps.vars.outputs.BUILDDATE}} -X ${{steps.vars.outputs.REPO}}/internal/version.Commit=${{steps.vars.outputs.COMMIT}} -X ${{steps.vars.outputs.REPO}}/internal/mode.Mode=production
+ ldflags: -w -s -X ${{steps.vars.outputs.REPO}}/internal/app/build.Version=${{steps.vars.outputs.VERSION}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.BuildDate=${{steps.vars.outputs.BUILDDATE}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Commit=${{steps.vars.outputs.COMMIT}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Mode=production
- # step 5: compress build files
- - name: Compress build files
- run: cd ./build && for i in *; do tar -czf $i.tar.gz $i; done && cd ..
+ # step 5: Upload binary to artifact
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{steps.vars.outputs.APP_NAME}}
+ path: build
+ retention-days: 1
- # step 6: Upload binary to GitHub Release
+ # step 6: Generate Changelog
- name: Generate Changelog
id: changelog
uses: bitxeno/changelogithub-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') }}
+ # output-file: ./docs/CHANGELOG.md
types: |
feat
fix
perf
refactor
- tweak
+ chore
+ docs
+ # build
+ # test
+ # style
+ # ci
+ # - name: Git commit changelog
+ # uses: EndBug/add-and-commit@v9
+ # with:
+ # default_author: github_actions
+ # add: "docs/"
+ # message: "docs: release notes for ${{ github.ref_name }}"
+ # push: "origin HEAD:${{ steps.vars.outputs.BRANCH }}"
+
+ # step 7: Upload binary to GitHub Release
+ - name: Compress build files
+ run: cd ./build && for i in *; do tar -czf $i.tar.gz $i; done && cd ..
- name: Upload binary to GitHub Release
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v2
if: "startsWith(github.ref, 'refs/tags/')"
with:
files: |
@@ -93,28 +122,67 @@ jobs:
body: ${{ steps.changelog.outputs.changelog }}
fail_on_unmatched_files: true
- # step 7.1: push to DockerHub
+ dockerhub:
+ name: Push to DockerHub
+ if: ${{needs.build.outputs.PUSH_DOCKERHUB}}
+ needs: [build]
+ permissions:
+ contents: read
+ packages: write
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v4
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{needs.build.outputs.APP_NAME}}
+ path: build
- name: Login to DockerHub
- if: ${{ steps.vars.outputs.HAS_DOCKER_TOKEN == 'true' }}
- uses: docker/login-action@v1
+ if: ${{ steps.vars.outputs.HAS_DOCKER_TOKEN }}
+ uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}
- name: Build and push Docker images to DockerHub
- if: ${{ steps.vars.outputs.HAS_DOCKER_TOKEN == 'true' }}
- uses: docker/build-push-action@v2
+ if: ${{ steps.vars.outputs.HAS_DOCKER_TOKEN }}
+ uses: docker/build-push-action@v5
with:
context: .
push: true
+ provenance: false
platforms: linux/amd64,linux/arm64
- tags: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}:latest
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
build-args: |
- APP_NAME=${{steps.vars.outputs.APP_NAME}}
- VERSION=${{steps.vars.outputs.VERSION}}
- BUILDDATE=${{steps.vars.outputs.BUILDDATE}}
- COMMIT=${{steps.vars.outputs.COMMIT}}
+ APP_NAME=${{needs.build.outputs.APP_NAME}}
+ VERSION=${{needs.build.outputs.VERSION}}
+ BUILDDATE=${{needs.build.outputs.BUILDDATE}}
+ COMMIT=${{needs.build.outputs.COMMIT}}
- # step 7.2: push to GitHub Container Registry
+ ghcr:
+ name: Push to GitHub Container Registry
+ needs: [build]
+ permissions:
+ contents: read
+ packages: write
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout the repository
+ uses: actions/checkout@v4
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{needs.build.outputs.APP_NAME}}
+ path: build
+ - name: Display structure of downloaded files
+ run: ls -R
+ working-directory: build
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
@@ -123,19 +191,34 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
- uses: docker/metadata-action@v4
+ uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
- name: Build and push Docker images to ghci
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
context: .
push: true
+ provenance: false
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
- APP_NAME=${{steps.vars.outputs.APP_NAME}}
- VERSION=${{steps.vars.outputs.VERSION}}
- BUILDDATE=${{steps.vars.outputs.BUILDDATE}}
- COMMIT=${{steps.vars.outputs.COMMIT}}
+ APP_NAME=${{needs.build.outputs.APP_NAME}}
+ VERSION=${{needs.build.outputs.VERSION}}
+ BUILDDATE=${{needs.build.outputs.BUILDDATE}}
+ COMMIT=${{needs.build.outputs.COMMIT}}
+
+ clean:
+ name: Delete temp artifacts
+ # ignore dockerhub job skipped
+ if: always() && (needs.dockerhub.result == 'success' || needs.dockerhub.result == 'skipped') && (needs.ghcr.result == 'success')
+ needs: [build, dockerhub, ghcr]
+ permissions:
+ contents: write
+ runs-on: ubuntu-latest
+ steps:
+ - uses: geekyeggo/delete-artifact@v5
+ with:
+ name: ${{needs.build.outputs.APP_NAME}}
+ failOnError: false
diff --git a/Dockerfile b/Dockerfile
index 75e21dd..8af30ae 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@ RUN case ${TARGETARCH} in \
"arm64") PKG_ARCH=aarch64 ;; \
esac \
&& cd /tmp \
- && wget https://github.com/bitxeno/usbmuxd2/releases/download/v0.0.2/usbmuxd2-ubuntu-${PKG_ARCH}.tar.gz \
+ && wget https://github.com/bitxeno/usbmuxd2/releases/download/v0.0.3/usbmuxd2-ubuntu-${PKG_ARCH}.tar.gz \
&& tar zxf usbmuxd2-ubuntu-${PKG_ARCH}.tar.gz \
&& dpkg -i ./libusb_1.0.26-1_${PKG_ARCH}.deb \
&& dpkg -i ./libgeneral_1.0.0-1_${PKG_ARCH}.deb \
diff --git a/go.mod b/go.mod
index d27256b..c6e3368 100644
--- a/go.mod
+++ b/go.mod
@@ -26,7 +26,6 @@ require (
github.com/robfig/cron/v3 v3.0.1
github.com/rs/zerolog v1.29.1
github.com/runletapp/go-console v0.0.0-20211204140000-27323a28410a
- github.com/shirou/gopsutil/v4 v4.24.5
github.com/silenceper/wechat/v2 v2.1.5
github.com/urfave/cli/v2 v2.3.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
@@ -47,16 +46,15 @@ require (
github.com/fasthttp/websocket v1.5.3 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
- github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc // indirect
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/iamacarpet/go-winpty v1.0.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/kr/pretty v0.3.0 // indirect
- github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
@@ -69,22 +67,18 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
- github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
- github.com/shoenig/go-m1cpu v0.1.6 // indirect
+ github.com/stretchr/testify v1.9.0 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tinylib/msgp v1.1.8 // indirect
- github.com/tklauser/go-sysconf v0.3.12 // indirect
- github.com/tklauser/numcpus v0.6.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.47.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
- github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/sync v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index d0a01c7..190ad24 100644
--- a/go.sum
+++ b/go.sum
@@ -146,8 +146,6 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
-github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc h1:jZY+lpZB92nvBo2f31oPC/ivGll6NcsnEOORm8Fkr4M=
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc/go.mod h1:25mL1NKxbJhB63ihiK8MnNeTRd+xAizd6bOdydrTLUQ=
@@ -202,6 +200,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
@@ -328,8 +327,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
@@ -450,8 +447,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@@ -511,11 +506,6 @@ github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJv
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/shirou/gopsutil/v4 v4.24.5 h1:gGsArG5K6vmsh5hcFOHaPm87UD003CaDMkAOweSQjhM=
-github.com/shirou/gopsutil/v4 v4.24.5/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA=
-github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
-github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
-github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shogo82148/androidbinary v1.0.2/go.mod h1:c3BBft4TLXkvqry+EEN8z9ZtyY09r7jLMvFB/L/KrfI=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/silenceper/wechat/v2 v2.1.5 h1:eIlv61v2bAFBG9ZE75zuRC0ALHEZEUq8JlJ9tfKvatg=
@@ -547,6 +537,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -555,10 +546,6 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
-github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
-github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
-github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
-github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
@@ -577,8 +564,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
-github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
-github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
@@ -691,7 +676,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -709,7 +693,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -729,8 +712,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
diff --git a/internal/app/config.go b/internal/app/config.go
index 8232cfb..e822397 100644
--- a/internal/app/config.go
+++ b/internal/app/config.go
@@ -30,7 +30,7 @@ type Configuration struct {
Server struct {
ListenAddr string `koanf:"listen_addr" default:"0.0.0.0"`
- Port int `koanf:"port" default:"9000"`
+ Port int `koanf:"port" default:"9400"`
DataDir string `koanf:"data_dir"`
} `koanf:"app" json:"app"`
diff --git a/internal/task/task.go b/internal/task/task.go
index a3ed3b3..38ef677 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -14,7 +14,6 @@ import (
"github.com/bitxeno/atvloadly/internal/app"
"github.com/bitxeno/atvloadly/internal/log"
- "github.com/bitxeno/atvloadly/internal/manager"
"github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/notify"
"github.com/bitxeno/atvloadly/internal/service"
@@ -175,18 +174,18 @@ func (t *Task) runInternal(v model.InstalledApp) error {
}
// 检查developer disk image是否已mounted
- imageInfo, err := manager.GetDeviceMountImageInfo(v.UDID)
- if err != nil {
- log.Err(err).Msg("Check DeveloperDiskImage mounted error: ")
- return err
- }
-
- if !imageInfo.ImageMounted {
- log.Error("DeveloperDiskImage not mounted.")
- return err
- }
-
- cmd := exec.Command("sideloader", "install", "--quiet", "--udid", v.UDID, "-a", v.Account, "-p", v.Password, v.IpaPath)
+ // imageInfo, err := manager.GetDeviceMountImageInfo(v.UDID)
+ // if err != nil {
+ // log.Err(err).Msg("Check DeveloperDiskImage mounted error: ")
+ // return err
+ // }
+
+ // if !imageInfo.ImageMounted {
+ // log.Error("DeveloperDiskImage not mounted.")
+ // return err
+ // }
+
+ cmd := exec.Command("sideloader", "install", "--quiet", "--nocolor", "--udid", v.UDID, "-a", v.Account, "-p", v.Password, v.IpaPath)
cmd.Dir = app.Config.Server.DataDir
cmd.Env = []string{"SIDELOADER_CONFIG_DIR=" + app.SideloaderDataDir()}
stdin, err := cmd.StdinPipe()
@@ -199,21 +198,36 @@ func (t *Task) runInternal(v model.InstalledApp) error {
log.Err(err).Msg("Error obtaining stdout: ")
return err
}
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ log.Err(err).Msg("Error obtaining stdout: ")
+ return err
+ }
var output strings.Builder
reader := bufio.NewReader(stdout)
+ readerErr := bufio.NewReader(stderr)
go func(reader io.Reader) {
defer stdin.Close()
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
lineText := scanner.Text()
+ _, _ = output.WriteString(lineText)
+ _, _ = output.WriteString("\n")
- // 忽略 Signing 消息,日志太多
- if strings.Contains(lineText, "Signing Progress") {
- continue
+ // 处理中途需要输入才能继续的,如 Installing AltStore with Multiple AltServers Not Supported 消息
+ if strings.Contains(lineText, "Press any key to continue") {
+ _, _ = stdin.Write([]byte("\n"))
}
+ }
+ }(reader)
+ go func(reader io.Reader) {
+ defer stdin.Close()
+ scanner := bufio.NewScanner(reader)
+ for scanner.Scan() {
+ lineText := scanner.Text()
_, _ = output.WriteString(lineText)
_, _ = output.WriteString("\n")
@@ -222,14 +236,18 @@ func (t *Task) runInternal(v model.InstalledApp) error {
_, _ = stdin.Write([]byte("\n"))
}
}
- }(reader)
+ }(readerErr)
if err := cmd.Start(); nil != err {
+ data := []byte(output.String())
+ t.writeLog(v, data)
log.Err(err).Msg("执行安装脚本出错")
return err
}
err = cmd.Wait()
if err != nil {
+ data := []byte(output.String())
+ t.writeLog(v, data)
log.Err(err).Msg("执行安装脚本出错")
return err
}
diff --git a/web/static/src/page/install/index.vue b/web/static/src/page/install/index.vue
index 5c28aaa..a6905c6 100644
--- a/web/static/src/page/install/index.vue
+++ b/web/static/src/page/install/index.vue
@@ -183,18 +183,7 @@ export default {
_this.log.output = "";
_this.log.show = true;
- // 挂载DeveloperDiskImage
- _this.log.output += "Prepare to mount DeveloperDiskImage...\n";
- let data = await api.mountDeviceImageAsync(_this.id);
- if (data != "success") {
- _this.log.output += data;
- _this.cmd.output = "";
- _this.loading = false;
- toast.error(this.$t("install.toast.install_failed"));
- return;
- }
- _this.log.output += "DeveloperDiskImage has mounted.\n";
-
+
let formData = new FormData();
for (let i = 0; i < _this.files.length; i++) {
let file = _this.files[i];
@@ -207,7 +196,7 @@ export default {
let ipa = res.data[0];
_this.ipa = ipa;
_this.websocketsend(
- `sideloader --udid ${_this.device.udid} -a '${_this.form.account}' -p '${_this.form.password}' '${ipa.path}'`
+ `sideloader install --nocolor --udid ${_this.device.udid} -a '${_this.form.account}' -p '${_this.form.password}' '${ipa.path}'`
);
})
.catch((error) => {
@@ -281,16 +270,17 @@ export default {
);
_this.cmd.line = _this.cmd.line.replace(_this.form.password, "******");
- // if (
- // _this.cmd.line.indexOf("slideloader") === -1
- // ) {
+ // ignore slideloader command output
+ if (
+ _this.cmd.line.indexOf("sideloader") === -1
+ ) {
_this.log.output += _this.cmd.line;
// The textbox follows the scroll to the bottom
_this.$nextTick(() => {
const textarea = document.querySelector("#log");
textarea.scrollTop = textarea.scrollHeight;
});
- // }
+ }
_this.cmd.line = "";
}
diff --git a/web/static/yarn.lock b/web/static/yarn.lock
index d5269be..3478a1b 100644
--- a/web/static/yarn.lock
+++ b/web/static/yarn.lock
@@ -513,11 +513,6 @@ entities@^4.2.0:
resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
-esbuild-darwin-64@0.14.54:
- version "0.14.54"
- resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz"
- integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
-
esbuild@^0.14.27:
version "0.14.54"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz"
@@ -609,11 +604,6 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-fsevents@~2.3.2:
- version "2.3.2"
- resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
- integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
diff --git a/web/web.go b/web/web.go
index 657b4bb..ca1c175 100644
--- a/web/web.go
+++ b/web/web.go
@@ -2,6 +2,7 @@ package web
import (
"fmt"
+ "math"
"github.com/bitxeno/atvloadly/internal/app"
"github.com/bitxeno/atvloadly/internal/log"
@@ -10,7 +11,9 @@ import (
)
func Run(addr string, port int) error {
- server := fiber.New()
+ server := fiber.New(fiber.Config{
+ BodyLimit: math.MaxInt,
+ })
route(server)
// set fiber web server access log
From 6ad503d375f6baf849348141ed4ea7c2bcae06ef Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 06:59:11 +0000
Subject: [PATCH 03/35] ci: fix linter error
---
internal/task/task.go | 5 -----
1 file changed, 5 deletions(-)
diff --git a/internal/task/task.go b/internal/task/task.go
index 38ef677..cc5a0b4 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -8,7 +8,6 @@ import (
"os"
"os/exec"
"path/filepath"
- "regexp"
"strings"
"time"
@@ -22,10 +21,6 @@ import (
var instance = new()
-var (
- regValidName = regexp.MustCompile("(?i)[^0-9a-zA-Z]+")
-)
-
type Task struct {
c *cron.Cron
Running bool `json:"running"`
From 635839ca5d760aaebf36b4e8b529416c2995607a Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 07:01:42 +0000
Subject: [PATCH 04/35] ci: fix build error
---
.github/workflows/build.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d66197c..6f2af9f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -29,5 +29,5 @@ jobs:
with:
version: v1.58
args: --timeout=5m
- - run: go mod download
- - run: go test -coverprofile=coverage.txt -covermode=atomic ./...
+ # - run: go mod download
+ # - run: go test -coverprofile=coverage.txt -covermode=atomic ./...
From a4cde476add55bf85ca8cb386e51b2054733663d Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 07:05:19 +0000
Subject: [PATCH 05/35] ci: update github aciton
---
.github/workflows/release-nightly.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml
index 6f9fd34..6dc1a65 100644
--- a/.github/workflows/release-nightly.yml
+++ b/.github/workflows/release-nightly.yml
@@ -5,8 +5,8 @@ on:
# schedule:
# - cron: '0 0 * * *' # runs daily at 00:00
workflow_dispatch:
- # push:
- # branches: [main, master, release/v*]
+ push:
+ branches: [main, master, release/v*, tvos17]
# jobs
jobs:
From d4a59148d33234562a982f2ce332dd265484c145 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 07:08:48 +0000
Subject: [PATCH 06/35] fix: compatible with old configuration.
---
internal/app/config.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/internal/app/config.go b/internal/app/config.go
index e822397..c77a3a5 100644
--- a/internal/app/config.go
+++ b/internal/app/config.go
@@ -31,7 +31,7 @@ type Configuration struct {
Server struct {
ListenAddr string `koanf:"listen_addr" default:"0.0.0.0"`
Port int `koanf:"port" default:"9400"`
- DataDir string `koanf:"data_dir"`
+ DataDir string `koanf:"work_dir"`
} `koanf:"app" json:"app"`
Db db.Config `koanf:"db" json:"db"`
From c390676e9917e8b9123d8e405463ca4cb252c29a Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 07:11:43 +0000
Subject: [PATCH 07/35] fix: compatible with old configuration.
---
internal/app/config.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/internal/app/config.go b/internal/app/config.go
index c77a3a5..bd7efc5 100644
--- a/internal/app/config.go
+++ b/internal/app/config.go
@@ -19,7 +19,7 @@ type Configuration struct {
ImageSource string `koanf:"image_source" json:"image_source" default:"https://github.com/haikieu/xcode-developer-disk-image-all-platforms/raw/master/DiskImages/AppleTVOS.platform/DeviceSupport/{0}.zip"`
CNProxy string `koanf:"cn_proxy" json:"cn_proxy" default:"https://mirror.ghproxy.com"`
} `koanf:"developer_disk_image" json:"developer_disk_image"`
- }
+ } `koanf:"app" json:"app"`
Log struct {
Level string `koanf:"level" default:"info"`
@@ -30,9 +30,9 @@ type Configuration struct {
Server struct {
ListenAddr string `koanf:"listen_addr" default:"0.0.0.0"`
- Port int `koanf:"port" default:"9400"`
+ Port int `koanf:"port" default:"9000"`
DataDir string `koanf:"work_dir"`
- } `koanf:"app" json:"app"`
+ } `koanf:"server" json:"server"`
Db db.Config `koanf:"db" json:"db"`
}
From 2dbd5a67eda8c4de9ba927465dcee82effa377d3 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 07:22:30 +0000
Subject: [PATCH 08/35] fix: fix github action
---
.github/workflows/release-nightly.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml
index 6dc1a65..7a7630c 100644
--- a/.github/workflows/release-nightly.yml
+++ b/.github/workflows/release-nightly.yml
@@ -57,9 +57,9 @@ jobs:
with:
node-version: "20"
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
# step 3: set workflow variables
- id: metadata
@@ -137,7 +137,7 @@ jobs:
context: .
push: true
provenance: false
- platforms: linux/amd64,linux/arm64
+ platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
@@ -181,7 +181,7 @@ jobs:
context: .
push: true
provenance: false
- platforms: linux/amd64,linux/arm64
+ platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
From b50d20fa15ef58045b0270cba8812b855b71d3a8 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 07:57:28 +0000
Subject: [PATCH 09/35] fix: compatible with old configuration.
---
internal/cfg/cfg.go | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/internal/cfg/cfg.go b/internal/cfg/cfg.go
index b5a08ae..3790818 100644
--- a/internal/cfg/cfg.go
+++ b/internal/cfg/cfg.go
@@ -37,7 +37,6 @@ func (c *configuration) load(path string) error {
}
// read config from file
- ko := koanf.New(".")
if !utils.Exists(c.path) {
fmt.Printf("[WARN] Config file not exists. path: %s\n", c.path)
return nil
@@ -46,17 +45,17 @@ func (c *configuration) load(path string) error {
fmt.Printf("Load config from path: %s\n", c.path)
ext := filepath.Ext(c.path)
if ext == ".yaml" || ext == ".yml" {
- if err := ko.Load(file.Provider(c.path), yaml.Parser()); err != nil {
+ if err := c.ko.Load(file.Provider(c.path), yaml.Parser()); err != nil {
log.Panicf("Yaml config file read failed. error: %s \n", err)
}
}
if ext == ".json" {
- if err := ko.Load(file.Provider(c.path), json.Parser()); err != nil {
+ if err := c.ko.Load(file.Provider(c.path), json.Parser()); err != nil {
log.Panicf("Json config file read failed. error: %s \n", err)
}
}
- return ko.Unmarshal("", &c)
+ return nil
}
func (c *configuration) BindStruct(dst any) error {
From 12c95c327bf2ffd31969d7a4b8cbcf950731a36e Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 09:52:33 +0000
Subject: [PATCH 10/35] fix: disable log http cache
---
internal/task/task.go | 1 +
web/router.go | 2 ++
2 files changed, 3 insertions(+)
diff --git a/internal/task/task.go b/internal/task/task.go
index cc5a0b4..40c8839 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -180,6 +180,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
// return err
// }
+ // sideloader 会处理特殊字符"$",对于带有这特殊字符的,需要加单引号包括
cmd := exec.Command("sideloader", "install", "--quiet", "--nocolor", "--udid", v.UDID, "-a", v.Account, "-p", v.Password, v.IpaPath)
cmd.Dir = app.Config.Server.DataDir
cmd.Env = []string{"SIDELOADER_CONFIG_DIR=" + app.SideloaderDataDir()}
diff --git a/web/router.go b/web/router.go
index 2a58f67..078799c 100644
--- a/web/router.go
+++ b/web/router.go
@@ -65,6 +65,8 @@ func route(fi *fiber.App) {
id := utils.MustParseInt(c.Params("id"))
path := filepath.Join(app.Config.Server.DataDir, "log", fmt.Sprintf("task_%d.log", id))
+ c.Set("Cache-Control", "no-cache, no-store, must-revalidate;")
+ c.Set("pragma", "no-cache")
return c.Status(http.StatusOK).SendFile(path, false)
})
From 938fa0172a9716c99c4187c482506984fce98eea Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 10:17:54 +0000
Subject: [PATCH 11/35] fix: add more timeout to upload ipa
---
web/static/src/api/api.js | 2 +-
web/static/src/page/install/index.vue | 9 ++++-----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/web/static/src/api/api.js b/web/static/src/api/api.js
index 6bca2fd..77b35b6 100644
--- a/web/static/src/api/api.js
+++ b/web/static/src/api/api.js
@@ -55,7 +55,7 @@ export default {
return request({
url: "/api/upload",
method: "post",
- timeout: 30000,
+ timeout: 1200000,
headers: {
"Content-Type": "multipart/form-data",
},
diff --git a/web/static/src/page/install/index.vue b/web/static/src/page/install/index.vue
index a6905c6..b0b6b08 100644
--- a/web/static/src/page/install/index.vue
+++ b/web/static/src/page/install/index.vue
@@ -202,6 +202,9 @@ export default {
.catch((error) => {
console.log(error);
_this.log.output += error;
+ _this.loading = false;
+ toast.error(this.$t("install.toast.install_failed"));
+ return;
});
},
reset() {
@@ -294,11 +297,7 @@ export default {
// pairing error
- if (
- _this.cmd.output.indexOf("Could not install") !== -1 ||
- _this.cmd.output.indexOf("Error:") !== -1 ||
- _this.cmd.output.indexOf("command not found") !== -1
- ) {
+ if (_this.cmd.output.indexOf("ERROR") !== -1) {
_this.cmd.output = "";
_this.loading = false;
toast.error(this.$t("install.toast.install_failed"));
From ccf5796b3e771bac9c01454c7b164f7fd9d125d2 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 10:36:06 +0000
Subject: [PATCH 12/35] fix: send notify not error log
---
internal/task/task.go | 14 +++++++-------
web/static/src/api/api.js | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/internal/task/task.go b/internal/task/task.go
index 40c8839..5f21d74 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -201,6 +201,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
}
var output strings.Builder
+ var outputErr strings.Builder
reader := bufio.NewReader(stdout)
readerErr := bufio.NewReader(stderr)
go func(reader io.Reader) {
@@ -227,6 +228,9 @@ func (t *Task) runInternal(v model.InstalledApp) error {
_, _ = output.WriteString(lineText)
_, _ = output.WriteString("\n")
+ _, _ = outputErr.WriteString(lineText)
+ _, _ = outputErr.WriteString("\n")
+
// 处理中途需要输入才能继续的,如 Installing AltStore with Multiple AltServers Not Supported 消息
if strings.Contains(lineText, "Press any key to continue") {
_, _ = stdin.Write([]byte("\n"))
@@ -237,7 +241,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
data := []byte(output.String())
t.writeLog(v, data)
log.Err(err).Msg("执行安装脚本出错")
- return err
+ return fmt.Errorf(outputErr.String(), err)
}
err = cmd.Wait()
@@ -245,7 +249,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
data := []byte(output.String())
t.writeLog(v, data)
log.Err(err).Msg("执行安装脚本出错")
- return err
+ return fmt.Errorf(outputErr.String(), err)
}
data := []byte(output.String())
@@ -254,12 +258,8 @@ func (t *Task) runInternal(v model.InstalledApp) error {
log.Info("执行安装脚本成功")
return nil
} else {
- if len(data) > 200 {
- data = data[len(data)-200:]
- }
-
log.Info("执行安装脚本失败")
- return fmt.Errorf(string(data))
+ return fmt.Errorf(outputErr.String())
}
}
diff --git a/web/static/src/api/api.js b/web/static/src/api/api.js
index 77b35b6..09463ec 100644
--- a/web/static/src/api/api.js
+++ b/web/static/src/api/api.js
@@ -55,7 +55,7 @@ export default {
return request({
url: "/api/upload",
method: "post",
- timeout: 1200000,
+ timeout: 300000,
headers: {
"Content-Type": "multipart/form-data",
},
From cfece62fe07d7dcf5e7b1d00d650beaddaba059c Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 16:47:49 +0000
Subject: [PATCH 13/35] fix: install failed by usbmuxd error
---
internal/app/bootstrap.go | 8 ++++++-
internal/log/log.go | 2 ++
internal/manager/manager.go | 4 ++++
internal/task/task.go | 44 +++++++++++++++++++------------------
4 files changed, 36 insertions(+), 22 deletions(-)
diff --git a/internal/app/bootstrap.go b/internal/app/bootstrap.go
index 8038567..2457e0d 100644
--- a/internal/app/bootstrap.go
+++ b/internal/app/bootstrap.go
@@ -68,7 +68,13 @@ func InitSettings(conf *Configuration, debug bool) error {
}
func InitLogger(conf *Configuration) error {
- // set normal log
+ if conf.Log.LogFile == "" {
+ if conf.Server.DataDir != "" {
+ conf.Log.LogFile = filepath.Join(conf.Server.DataDir, "app.log")
+ } else {
+ conf.Log.LogFile = filepath.Join(cfg.DefaultConfigDir(), "app.log")
+ }
+ }
log.AddFileOutput(conf.Log.LogFile)
if conf.Log.Level == "debug" {
log.SetDebugLevel()
diff --git a/internal/log/log.go b/internal/log/log.go
index d32cc17..1c5171c 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -1,6 +1,7 @@
package log
import (
+ "fmt"
"io"
"os"
"path"
@@ -24,6 +25,7 @@ func AddFileOutput(logPath string) {
return
}
+ fmt.Printf("Log file path: %s\n", logPath)
consoleWriter := newConsoleWriter(os.Stderr)
// output log to file
logFileWriter := CreateRollingLogFile(logPath)
diff --git a/internal/manager/manager.go b/internal/manager/manager.go
index 1cbfeae..3ccff02 100644
--- a/internal/manager/manager.go
+++ b/internal/manager/manager.go
@@ -25,3 +25,7 @@ func ReloadDevices() {
func ScanDevices() {
deviceManager.Scan()
}
+
+func RestartUsbmuxd() error {
+ return deviceManager.RestartUsbmuxd()
+}
diff --git a/internal/task/task.go b/internal/task/task.go
index 5f21d74..35692f9 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -13,6 +13,7 @@ import (
"github.com/bitxeno/atvloadly/internal/app"
"github.com/bitxeno/atvloadly/internal/log"
+ "github.com/bitxeno/atvloadly/internal/manager"
"github.com/bitxeno/atvloadly/internal/model"
"github.com/bitxeno/atvloadly/internal/notify"
"github.com/bitxeno/atvloadly/internal/service"
@@ -81,29 +82,30 @@ func (t *Task) Run() {
}
log.Infof("开始执行安装ipa:%s", v.IpaName)
- tryTimes := 1
- for i := 0; i < tryTimes; i++ {
- err := t.runInternal(v)
- if err == nil {
- v.RefreshedDate = &now
- v.RefreshedResult = true
- _ = service.UpdateAppRefreshResult(v)
- break
- }
-
- if i == (tryTimes - 1) {
- now := time.Now()
- v.RefreshedDate = &now
- v.RefreshedResult = false
- _ = service.UpdateAppRefreshResult(v)
-
- failedList = append(failedList, v)
- failedMsg += fmt.Sprintf("app: %s\n 错误日志:%s\n\n", v.IpaName, err.Error())
- } else {
- log.Infof("1分钟后再次重新尝试执行")
- time.Sleep(1 * time.Minute)
+ if err := t.runInternal(v); err != nil {
+ // AppleTV system has reboot/lockdownd sleep, try restart usbmuxd to fix
+ if strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") {
+ log.Infof("尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. %s", v.IpaName)
+ if err = manager.RestartUsbmuxd(); err == nil {
+ log.Infof("usbmuxd 重启完成,再次尝试安装ipa:%s", v.IpaName)
+ time.Sleep(5 * time.Second)
+ err = t.runInternal(v)
+ }
}
}
+ if err != nil {
+ now := time.Now()
+ v.RefreshedDate = &now
+ v.RefreshedResult = false
+ _ = service.UpdateAppRefreshResult(v)
+
+ failedList = append(failedList, v)
+ failedMsg += fmt.Sprintf("app: %s\n 错误日志:%s\n\n", v.IpaName, err.Error())
+ } else {
+ v.RefreshedDate = &now
+ v.RefreshedResult = true
+ _ = service.UpdateAppRefreshResult(v)
+ }
log.Infof("安装ipa执行完成.任务:%s", v.IpaName)
// 下一个执行延迟10秒
From bdac8f877811bb0a401da2eb81ed02bab0612c58 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 16:51:18 +0000
Subject: [PATCH 14/35] fix: err not handle
---
internal/task/task.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/internal/task/task.go b/internal/task/task.go
index 35692f9..0170549 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -82,7 +82,8 @@ func (t *Task) Run() {
}
log.Infof("开始执行安装ipa:%s", v.IpaName)
- if err := t.runInternal(v); err != nil {
+ var err error
+ if err = t.runInternal(v); err != nil {
// AppleTV system has reboot/lockdownd sleep, try restart usbmuxd to fix
if strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") {
log.Infof("尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. %s", v.IpaName)
From 054df4344ab30408a74c5a86446af3f961791a90 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sat, 22 Jun 2024 17:15:21 +0000
Subject: [PATCH 15/35] fix: install failed by usbmuxd error
---
internal/task/task.go | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/internal/task/task.go b/internal/task/task.go
index 0170549..065c346 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -82,18 +82,7 @@ func (t *Task) Run() {
}
log.Infof("开始执行安装ipa:%s", v.IpaName)
- var err error
- if err = t.runInternal(v); err != nil {
- // AppleTV system has reboot/lockdownd sleep, try restart usbmuxd to fix
- if strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") {
- log.Infof("尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. %s", v.IpaName)
- if err = manager.RestartUsbmuxd(); err == nil {
- log.Infof("usbmuxd 重启完成,再次尝试安装ipa:%s", v.IpaName)
- time.Sleep(5 * time.Second)
- err = t.runInternal(v)
- }
- }
- }
+ err := t.runInternalRetry(v)
if err != nil {
now := time.Now()
v.RefreshedDate = &now
@@ -148,7 +137,7 @@ func (t *Task) RunImmediately(v model.InstalledApp) {
defer t.completedState()
now := time.Now()
- err := t.runInternal(v)
+ err := t.runInternalRetry(v)
if err == nil {
v.RefreshedDate = &now
v.RefreshedResult = true
@@ -163,6 +152,20 @@ func (t *Task) RunImmediately(v model.InstalledApp) {
}
}
+func (t *Task) runInternalRetry(v model.InstalledApp) error {
+ err := t.runInternal(v)
+ // AppleTV system has reboot/lockdownd sleep, try restart usbmuxd to fix
+ if err != nil && strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") {
+ log.Infof("尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. %s", v.IpaName)
+ if err = manager.RestartUsbmuxd(); err == nil {
+ log.Infof("usbmuxd 重启完成,再次尝试安装ipa:%s", v.IpaName)
+ time.Sleep(5 * time.Second)
+ err = t.runInternal(v)
+ }
+ }
+ return err
+}
+
func (t *Task) runInternal(v model.InstalledApp) error {
t.InstallingApp = &v
@@ -243,16 +246,16 @@ func (t *Task) runInternal(v model.InstalledApp) error {
if err := cmd.Start(); nil != err {
data := []byte(output.String())
t.writeLog(v, data)
- log.Err(err).Msg("执行安装脚本出错")
- return fmt.Errorf(outputErr.String(), err)
+ log.Err(err).Msgf("执行安装脚本出错. %s", outputErr.String())
+ return fmt.Errorf("%s %v", outputErr.String(), err)
}
err = cmd.Wait()
if err != nil {
data := []byte(output.String())
t.writeLog(v, data)
- log.Err(err).Msg("执行安装脚本出错")
- return fmt.Errorf(outputErr.String(), err)
+ log.Err(err).Msgf("执行安装脚本出错. %s", outputErr.String())
+ return fmt.Errorf("%s %v", outputErr.String(), err)
}
data := []byte(output.String())
From 5aaa8a7a2dc9682df92caa295689fa174f21eb82 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Sun, 23 Jun 2024 07:07:02 +0000
Subject: [PATCH 16/35] fix: install failed after reboot appletv
---
internal/task/task.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/internal/task/task.go b/internal/task/task.go
index 065c346..da54df2 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -155,7 +155,7 @@ func (t *Task) RunImmediately(v model.InstalledApp) {
func (t *Task) runInternalRetry(v model.InstalledApp) error {
err := t.runInternal(v)
// AppleTV system has reboot/lockdownd sleep, try restart usbmuxd to fix
- if err != nil && strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") {
+ if err != nil && (strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") || strings.Contains(err.Error(), "AFC_E_MUX_ERROR")) {
log.Infof("尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. %s", v.IpaName)
if err = manager.RestartUsbmuxd(); err == nil {
log.Infof("usbmuxd 重启完成,再次尝试安装ipa:%s", v.IpaName)
From a5cd45490f5769578218861b42a0ba065d1ed8aa Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Mon, 24 Jun 2024 09:58:28 +0800
Subject: [PATCH 17/35] feat: add afc check before install
---
internal/manager/device_manager.go | 20 ++++++++++++++++++++
internal/manager/manager.go | 4 ++++
internal/service/service.go | 14 ++++++++++++++
web/router.go | 10 ++++++++++
web/static/src/api/api.js | 15 +++++++++++++++
web/static/src/page/install/index.vue | 11 +++++++++++
6 files changed, 74 insertions(+)
diff --git a/internal/manager/device_manager.go b/internal/manager/device_manager.go
index 34b17a7..339da22 100644
--- a/internal/manager/device_manager.go
+++ b/internal/manager/device_manager.go
@@ -158,6 +158,26 @@ func (dm *DeviceManager) CheckHasMountImage(udid string) (bool, error) {
return strings.Contains(output, "ImageSignature") && !strings.Contains(output, "ImageSignature[0]"), nil
}
+func (dm *DeviceManager) CheckAfcServiceStatus(udid string) error {
+ cmd := exec.Command("sideloader", "check", "afc", "--nocolor", "--udid", udid)
+
+ data, err := cmd.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("%s%s", string(data), err.Error())
+ }
+
+ output := string(data)
+ if strings.Contains(output, "ERROR") {
+ return fmt.Errorf("%s", output)
+ }
+
+ if !strings.Contains(output, "SUCCESS") {
+ return fmt.Errorf("%s", output)
+ }
+
+ return nil
+}
+
func (dm *DeviceManager) RestartUsbmuxd() error {
cmd := exec.Command("/etc/init.d/usbmuxd", "restart")
data, err := cmd.CombinedOutput()
diff --git a/internal/manager/manager.go b/internal/manager/manager.go
index 3ccff02..2178b32 100644
--- a/internal/manager/manager.go
+++ b/internal/manager/manager.go
@@ -26,6 +26,10 @@ func ScanDevices() {
deviceManager.Scan()
}
+func CheckAfcServiceStatus(udid string) error {
+ return deviceManager.CheckAfcServiceStatus(udid)
+}
+
func RestartUsbmuxd() error {
return deviceManager.RestartUsbmuxd()
}
diff --git a/internal/service/service.go b/internal/service/service.go
index 83c09ae..742a292 100644
--- a/internal/service/service.go
+++ b/internal/service/service.go
@@ -9,6 +9,7 @@ import (
"regexp"
"runtime"
"strings"
+ "time"
"github.com/artdarek/go-unzip/pkg/unzip"
"github.com/bitxeno/atvloadly/internal/app"
@@ -95,6 +96,19 @@ func MountDeveloperDiskImage(ctx context.Context, id string) error {
return nil
}
+func CheckAfcService(ctx context.Context, id string) error {
+ var err error
+ if err = manager.CheckAfcServiceStatus(id); err != nil {
+ // try restart usbmuxd to fix afc connect issue
+ if err = manager.RestartUsbmuxd(); err == nil {
+ time.Sleep(5 * time.Second)
+ err = manager.CheckAfcServiceStatus(id)
+ }
+ }
+
+ return err
+}
+
func downloadDeveloperDiskImage(imageInfo *model.UsbmuxdImage) (dmg string, signature string, reterr error) {
// download current version DeveloperDiskImage
err := downloadDeveloperDiskImageByVersion(imageInfo.DeveloperDiskImageUrl, imageInfo.DeveloperDiskImageVersion)
diff --git a/web/router.go b/web/router.go
index 078799c..c8981ad 100644
--- a/web/router.go
+++ b/web/router.go
@@ -130,6 +130,16 @@ func route(fi *fiber.App) {
}
})
+ api.Post("/devices/:id/check/afc", func(c *fiber.Ctx) error {
+ id := c.Params("id")
+
+ if err := service.CheckAfcService(c.Context(), id); err != nil {
+ return c.Status(http.StatusOK).JSON(apiSuccess(err.Error()))
+ } else {
+ return c.Status(http.StatusOK).JSON(apiSuccess("success"))
+ }
+ })
+
api.Get("/scan", func(c *fiber.Ctx) error {
manager.ScanDevices()
diff --git a/web/static/src/api/api.js b/web/static/src/api/api.js
index 09463ec..5b56eb8 100644
--- a/web/static/src/api/api.js
+++ b/web/static/src/api/api.js
@@ -22,6 +22,21 @@ export default {
});
});
},
+ checkAfcService: (id) => {
+ return new Promise((resolve, reject) => {
+ request({
+ url: `/api/devices/${id}/check/afc`,
+ timeout: 60000,
+ method: "Post",
+ })
+ .then((res) => {
+ resolve(res.data);
+ })
+ .catch((err) => {
+ reject(err);
+ });
+ });
+ },
getDevices: (params) => {
return request({
url: "/api/devices",
diff --git a/web/static/src/page/install/index.vue b/web/static/src/page/install/index.vue
index b0b6b08..a8b99c0 100644
--- a/web/static/src/page/install/index.vue
+++ b/web/static/src/page/install/index.vue
@@ -183,6 +183,17 @@ export default {
_this.log.output = "";
_this.log.show = true;
+ _this.log.output += "Checking afc service status...\n";
+ let data = await api.checkAfcService(_this.id);
+ if (data != "success") {
+ _this.log.output += data;
+ _this.cmd.output = "";
+ _this.loading = false;
+ toast.error(this.$t("install.toast.install_failed"));
+ return;
+ }
+ _this.log.output += "afc service OK!\n";
+
let formData = new FormData();
for (let i = 0; i < _this.files.length; i++) {
From 06d8798da40fe0931b995a1e2a703b13421b8197 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Mon, 24 Jun 2024 10:26:44 +0800
Subject: [PATCH 18/35] ci: update github action
---
.github/workflows/clean_package.yml | 10 ++++------
.github/workflows/release-nightly.yml | 2 +-
.github/workflows/release.yml | 2 +-
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/clean_package.yml b/.github/workflows/clean_package.yml
index 509dba6..dcea1a0 100644
--- a/.github/workflows/clean_package.yml
+++ b/.github/workflows/clean_package.yml
@@ -25,11 +25,9 @@ jobs:
run: |
echo "APP_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT
- name: Delete old images
- uses: snok/container-retention-policy@v2
+ uses: dataaxiom/ghcr-cleanup-action@v1
with:
- image-names: ${{steps.vars.outputs.APP_NAME}}
- cut-off: A month ago UTC
- keep-at-least: 10
- skip-tags: latest, beta, alpha, main, master
- account-type: personal
+ exclude-tags: 'v*,dev,latest,main,master'
+ keep-n-tagged: 10
+ package: ${{steps.vars.outputs.APP_NAME}}
token: ${{ secrets.PAT }}
diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml
index 7a7630c..98d68c1 100644
--- a/.github/workflows/release-nightly.yml
+++ b/.github/workflows/release-nightly.yml
@@ -90,7 +90,7 @@ jobs:
go_version: ${{ matrix.go_version }}
dest: build
prefix: ${{steps.vars.outputs.APP_NAME}}
- targets: windows/386,windows/amd64,linux/386,linux/amd64,darwin/386,darwin/amd64,linux/386,linux/arm64
+ targets: windows/amd64,linux/amd64,darwin/amd64,linux/arm64
v: true
x: false
ldflags: -w -s -X ${{steps.vars.outputs.REPO}}/internal/app/build.Version=${{steps.vars.outputs.VERSION}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.BuildDate=${{steps.vars.outputs.BUILDDATE}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Commit=${{steps.vars.outputs.COMMIT}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Mode=production
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e7a03e9..9bfd6de 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -69,7 +69,7 @@ jobs:
go_version: ${{ matrix.go_version }}
dest: build
prefix: ${{steps.vars.outputs.APP_NAME}}
- targets: windows/386,windows/amd64,linux/386,linux/amd64,darwin/386,darwin/amd64,linux/386,linux/arm64
+ targets: windows/amd64,linux/amd64,darwin/amd64,linux/arm64
v: true
x: false
ldflags: -w -s -X ${{steps.vars.outputs.REPO}}/internal/app/build.Version=${{steps.vars.outputs.VERSION}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.BuildDate=${{steps.vars.outputs.BUILDDATE}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Commit=${{steps.vars.outputs.COMMIT}} -X ${{steps.vars.outputs.REPO}}/internal/app/build.Mode=production
From c578146ae3423dfbbd71621192502487cec71cf2 Mon Sep 17 00:00:00 2001
From: bitxeno <137328844+bitxeno@users.noreply.github.com>
Date: Mon, 24 Jun 2024 15:25:30 +0800
Subject: [PATCH 19/35] feat: task add i18n support
---
.air.toml | 2 +-
go.mod | 2 +
go.sum | 7 +++-
internal/i18n/i18n.go | 56 +++++++++++++++++++++++++++
internal/i18n/locales/en.json | 23 +++++++++++
internal/i18n/locales/zh_cn.json | 23 +++++++++++
internal/service/db.go | 2 +-
internal/task/task.go | 66 ++++++++++++++------------------
web/fs_dev.go | 2 +-
web/router.go | 13 ++++++-
web/static/src/api/api.js | 7 ++++
web/static/src/page/layout.vue | 3 ++
12 files changed, 162 insertions(+), 44 deletions(-)
create mode 100644 internal/i18n/i18n.go
create mode 100644 internal/i18n/locales/en.json
create mode 100644 internal/i18n/locales/zh_cn.json
diff --git a/.air.toml b/.air.toml
index 2154641..9e2161c 100644
--- a/.air.toml
+++ b/.air.toml
@@ -7,7 +7,7 @@ tmp_dir = "tmp"
[build]
# Just plain old shell command. You could use `make` as well.
-cmd = "go build -o ./tmp/main ."
+cmd = "go build -tags dev -o ./tmp/main ."
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary.
diff --git a/go.mod b/go.mod
index c6e3368..1ec6cb4 100644
--- a/go.mod
+++ b/go.mod
@@ -21,6 +21,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/knadh/koanf v1.5.0
github.com/mitchellh/go-ps v1.0.0
+ github.com/nicksnyder/go-i18n/v2 v2.4.0
github.com/nikoksr/notify v0.41.0
github.com/pkg/errors v0.9.1
github.com/robfig/cron/v3 v3.0.1
@@ -28,6 +29,7 @@ require (
github.com/runletapp/go-console v0.0.0-20211204140000-27323a28410a
github.com/silenceper/wechat/v2 v2.1.5
github.com/urfave/cli/v2 v2.3.0
+ golang.org/x/text v0.14.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gorm.io/gorm v1.25.7
howett.net/plist v1.0.0
diff --git a/go.sum b/go.sum
index 190ad24..7df8af9 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@@ -393,6 +393,8 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
+github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
+github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
github.com/nikoksr/notify v0.41.0 h1:4LGE41GpWdHX5M3Xo6DlWRwS2WLDbOq1Rk7IzY4vjmQ=
github.com/nikoksr/notify v0.41.0/go.mod h1:FoE0UVPeopz1Vy5nm9vQZ+JVmYjEIjQgbFstbkw+cRE=
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
@@ -725,7 +727,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go
new file mode 100644
index 0000000..0a74daa
--- /dev/null
+++ b/internal/i18n/i18n.go
@@ -0,0 +1,56 @@
+package i18n
+
+import (
+ "embed"
+ "encoding/json"
+ "path/filepath"
+
+ "github.com/nicksnyder/go-i18n/v2/i18n"
+ "golang.org/x/text/language"
+)
+
+//go:embed all:locales/*
+var localesFs embed.FS
+var i18nBundle *i18n.Bundle
+var i18nLocalizer *i18n.Localizer
+var currentLang = "en"
+
+func init() {
+ i18nBundle = i18n.NewBundle(language.English)
+ i18nBundle.RegisterUnmarshalFunc("json", json.Unmarshal)
+
+ root := "locales"
+ files, err := localesFs.ReadDir(root)
+ if err != nil {
+ panic(err)
+ }
+ for _, v := range files {
+ path := filepath.Join(root, v.Name())
+ i18nBundle.LoadMessageFileFS(localesFs, path)
+ }
+
+ i18nLocalizer = i18n.NewLocalizer(i18nBundle, currentLang)
+}
+
+func SetLanguage(lang string) {
+ if lang == "" {
+ return
+ }
+ if currentLang != lang {
+ currentLang = lang
+ i18nLocalizer = i18n.NewLocalizer(i18nBundle, currentLang)
+ }
+}
+
+func Localize(key string) string {
+ return i18nLocalizer.MustLocalize(&i18n.LocalizeConfig{
+ MessageID: key,
+ })
+}
+
+func LocalizeF(key string, data map[string]interface{}) string {
+ return i18nLocalizer.MustLocalize(&i18n.LocalizeConfig{
+ MessageID: key,
+ TemplateData: data,
+ })
+}
diff --git a/internal/i18n/locales/en.json b/internal/i18n/locales/en.json
new file mode 100644
index 0000000..5f9f6fc
--- /dev/null
+++ b/internal/i18n/locales/en.json
@@ -0,0 +1,23 @@
+{
+ "language": "en",
+ "notify": {
+ "title": "[{{.name}}] Refresh task execution failed.",
+ "content": "Account: {{.account}}\nError log: {{.error}}",
+ "batch_title": "atvloadly Refresh Task Execution Failed",
+ "batch_content": "app: {{.name}}\n Error Log: {{.error}}\n\n"
+ },
+ "task": {
+ "started": "Start executing installation task...",
+ "completed": "Installation task completed.",
+ "app_install_started": "Start installing ipa: {{.name}}",
+ "app_install_completed": "Ipa installation completed.{{.name}}",
+ "task_disabled": "App refresh scheduled task is not enabled",
+ "task_started": "App refresh scheduled task has started, time: {{.time}}",
+ "install_failed": "Error executing installation script.{{.error}}",
+ "error_get_app_list": "Failed to get the installation list",
+ "error_invalid_arguments": "Task account, password, UDID are empty",
+ "error_invalid_crod_time_format": "Failed to start app refresh scheduled task due to incorrect timing format: {{.time}}",
+ "try_restart_usbmuxd": "Try restarting usbmuxd to fix LOCKDOWN_E_MUX_ERROR error. {{.error}}",
+ "try_restart_usbmuxd_success": "usbmuxd restart complete, try installing ipa again: {{.name}}"
+ }
+}
\ No newline at end of file
diff --git a/internal/i18n/locales/zh_cn.json b/internal/i18n/locales/zh_cn.json
new file mode 100644
index 0000000..7bd33dd
--- /dev/null
+++ b/internal/i18n/locales/zh_cn.json
@@ -0,0 +1,23 @@
+{
+ "language": "zh_cn",
+ "notify": {
+ "title": "[{{.name}}]刷新任务执行失败",
+ "content": "帐号:{{.account}}\n错误日志:{{.error}}",
+ "batch_title": "atvloadly 刷新任务执行失败",
+ "batch_content": "app: {{.name}}\n 错误日志:{{.error}}\n\n"
+ },
+ "task": {
+ "started": "开始执行安装任务...",
+ "completed": "安装任务执行完成。",
+ "app_install_started": "开始执行安装ipa:{{.name}}",
+ "app_install_completed": "安装ipa执行完成.{{.name}}",
+ "task_disabled": "app刷新定时任务未启用",
+ "task_started": "app刷新定时任务已启动,时间: {{.time}}",
+ "install_failed": "执行安装脚本出错。{{.error}}",
+ "error_get_app_list": "获取安装列表失败",
+ "error_invalid_arguments": "任务帐号,密码,UDID 为空",
+ "error_invalid_crod_time_format": "app刷新定时任务启动失败,定时格式错误:{{.time}}",
+ "try_restart_usbmuxd": "尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. {{.error}}",
+ "try_restart_usbmuxd_success": "usbmuxd 重启完成,再次尝试安装ipa:{{.name}}"
+ }
+}
\ No newline at end of file
diff --git a/internal/service/db.go b/internal/service/db.go
index de8b439..7dac986 100644
--- a/internal/service/db.go
+++ b/internal/service/db.go
@@ -45,7 +45,7 @@ func SaveApp(app model.InstalledApp) (*model.InstalledApp, error) {
var cur model.InstalledApp
result := db.Store().Where("udid=? and bundle_identifier=? and account=?", app.UDID, app.BundleIdentifier, app.Account).First(&cur)
if result.Error != nil && result.Error != gorm.ErrRecordNotFound {
- log.Err(result.Error).Msg("保存安装记录时出错.")
+ log.Err(result.Error).Msg("SaveApp error.")
return nil, result.Error
}
diff --git a/internal/task/task.go b/internal/task/task.go
index da54df2..495e56b 100644
--- a/internal/task/task.go
+++ b/internal/task/task.go
@@ -12,6 +12,7 @@ import (
"time"
"github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/i18n"
"github.com/bitxeno/atvloadly/internal/log"
"github.com/bitxeno/atvloadly/internal/manager"
"github.com/bitxeno/atvloadly/internal/model"
@@ -39,18 +40,18 @@ func (t *Task) RunSchedule() error {
}
if !app.Settings.Task.Enabled {
- log.Info("app刷新定时任务未启用")
+ log.Info(i18n.Localize("task.task_disabled"))
return nil
}
t.c = cron.New()
if _, err := t.c.AddFunc(app.Settings.Task.CrodTime, t.Run); err != nil {
- log.Err(err).Msgf("app刷新定时任务启动失败,定时格式错误:%s", app.Settings.Task.CrodTime)
+ log.Err(err).Msg(i18n.LocalizeF("task.error_invalid_crod_time_format", map[string]interface{}{"time": app.Settings.Task.CrodTime}))
t.c = nil
return err
}
- log.Infof("app刷新定时任务已启动,时间: %s", app.Settings.Task.CrodTime)
+ log.Info(i18n.LocalizeF("task.task_started", map[string]interface{}{"time": app.Settings.Task.CrodTime}))
t.c.Start()
return nil
@@ -69,7 +70,7 @@ func (t *Task) Run() {
installedApps, err := service.GetEnableAppList()
if err != nil {
- log.Err(err).Msg("获取安装列表失败")
+ log.Err(err).Msg(i18n.Localize("task.error_get_app_list"))
return
}
@@ -81,7 +82,7 @@ func (t *Task) Run() {
continue
}
- log.Infof("开始执行安装ipa:%s", v.IpaName)
+ log.Info(i18n.LocalizeF("task.app_install_started", map[string]interface{}{"name": v.IpaName}))
err := t.runInternalRetry(v)
if err != nil {
now := time.Now()
@@ -90,21 +91,22 @@ func (t *Task) Run() {
_ = service.UpdateAppRefreshResult(v)
failedList = append(failedList, v)
- failedMsg += fmt.Sprintf("app: %s\n 错误日志:%s\n\n", v.IpaName, err.Error())
+ failedMsg += i18n.LocalizeF("notify.batch_content", map[string]interface{}{"name": v.IpaName, "error": err.Error()})
} else {
v.RefreshedDate = &now
v.RefreshedResult = true
_ = service.UpdateAppRefreshResult(v)
}
- log.Infof("安装ipa执行完成.任务:%s", v.IpaName)
+ log.Info(i18n.LocalizeF("task.app_install_completed", map[string]interface{}{"name": v.IpaName}))
- // 下一个执行延迟10秒
+ // Next execution delayed by 10 seconds.
time.Sleep(10 * time.Second)
}
- // 发送安装失败通知
+ // Send installation failure notification.
if len(failedList) > 0 {
- _ = notify.Send("atvloadly 自动刷新任务执行失败", failedMsg)
+ title := i18n.LocalizeF("notify.title", map[string]interface{}{"name": "atvloadly"})
+ _ = notify.Send(title, failedMsg)
}
}
@@ -147,8 +149,10 @@ func (t *Task) RunImmediately(v model.InstalledApp) {
v.RefreshedResult = false
_ = service.UpdateAppRefreshResult(v)
- // 发送安装失败通知
- _ = notify.Send(fmt.Sprintf("[%s]刷新任务执行失败", v.IpaName), fmt.Sprintf("帐号:%s\n错误日志:%s", v.Account, err.Error()))
+ // Send installation failure notification
+ title := i18n.LocalizeF("notify.title", map[string]interface{}{"name": v.IpaName})
+ message := i18n.LocalizeF("notify.content", map[string]interface{}{"account": v.Account, "error": err.Error()})
+ _ = notify.Send(title, message)
}
}
@@ -156,9 +160,9 @@ func (t *Task) runInternalRetry(v model.InstalledApp) error {
err := t.runInternal(v)
// AppleTV system has reboot/lockdownd sleep, try restart usbmuxd to fix
if err != nil && (strings.Contains(err.Error(), "LOCKDOWN_E_MUX_ERROR") || strings.Contains(err.Error(), "AFC_E_MUX_ERROR")) {
- log.Infof("尝试重启 usbmuxd 修复 LOCKDOWN_E_MUX_ERROR 错误. %s", v.IpaName)
+ log.Info(i18n.LocalizeF("task.try_restart_usbmuxd", map[string]interface{}{"name": v.IpaName}))
if err = manager.RestartUsbmuxd(); err == nil {
- log.Infof("usbmuxd 重启完成,再次尝试安装ipa:%s", v.IpaName)
+ log.Info(i18n.LocalizeF("task.try_restart_usbmuxd_success", map[string]interface{}{"name": v.IpaName}))
time.Sleep(5 * time.Second)
err = t.runInternal(v)
}
@@ -170,23 +174,11 @@ func (t *Task) runInternal(v model.InstalledApp) error {
t.InstallingApp = &v
if v.Account == "" || v.Password == "" || v.UDID == "" {
- log.Info("任务帐号,密码,UDID为空")
- return fmt.Errorf("任务帐号,密码,UDID为空")
+ log.Info(i18n.Localize("task.error_invalid_arguments"))
+ return fmt.Errorf(i18n.Localize("task.error_invalid_arguments"))
}
- // 检查developer disk image是否已mounted
- // imageInfo, err := manager.GetDeviceMountImageInfo(v.UDID)
- // if err != nil {
- // log.Err(err).Msg("Check DeveloperDiskImage mounted error: ")
- // return err
- // }
-
- // if !imageInfo.ImageMounted {
- // log.Error("DeveloperDiskImage not mounted.")
- // return err
- // }
-
- // sideloader 会处理特殊字符"$",对于带有这特殊字符的,需要加单引号包括
+ // The sideloader will handle special character "$". For those with this special character, it needs to be enclosed in single quotation marks.
cmd := exec.Command("sideloader", "install", "--quiet", "--nocolor", "--udid", v.UDID, "-a", v.Account, "-p", v.Password, v.IpaPath)
cmd.Dir = app.Config.Server.DataDir
cmd.Env = []string{"SIDELOADER_CONFIG_DIR=" + app.SideloaderDataDir()}
@@ -219,7 +211,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
_, _ = output.WriteString(lineText)
_, _ = output.WriteString("\n")
- // 处理中途需要输入才能继续的,如 Installing AltStore with Multiple AltServers Not Supported 消息
+ // Processing interaction to continue, such as [the Installing AltStore with Multiple AltServers the Not Supported] message.
if strings.Contains(lineText, "Press any key to continue") {
_, _ = stdin.Write([]byte("\n"))
}
@@ -237,7 +229,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
_, _ = outputErr.WriteString(lineText)
_, _ = outputErr.WriteString("\n")
- // 处理中途需要输入才能继续的,如 Installing AltStore with Multiple AltServers Not Supported 消息
+ // Processing interaction to continue, such as [the Installing AltStore with Multiple AltServers the Not Supported] message.
if strings.Contains(lineText, "Press any key to continue") {
_, _ = stdin.Write([]byte("\n"))
}
@@ -246,7 +238,7 @@ func (t *Task) runInternal(v model.InstalledApp) error {
if err := cmd.Start(); nil != err {
data := []byte(output.String())
t.writeLog(v, data)
- log.Err(err).Msgf("执行安装脚本出错. %s", outputErr.String())
+ log.Err(err).Msg(i18n.LocalizeF("install_failed", map[string]interface{}{"error": outputErr.String()}))
return fmt.Errorf("%s %v", outputErr.String(), err)
}
@@ -254,23 +246,21 @@ func (t *Task) runInternal(v model.InstalledApp) error {
if err != nil {
data := []byte(output.String())
t.writeLog(v, data)
- log.Err(err).Msgf("执行安装脚本出错. %s", outputErr.String())
+ log.Err(err).Msg(i18n.LocalizeF("install_failed", map[string]interface{}{"error": outputErr.String()}))
return fmt.Errorf("%s %v", outputErr.String(), err)
}
data := []byte(output.String())
t.writeLog(v, data)
if strings.Contains(string(data), "Installation Succeeded") {
- log.Info("执行安装脚本成功")
return nil
} else {
- log.Info("执行安装脚本失败")
return fmt.Errorf(outputErr.String())
}
}
func (t *Task) writeLog(v model.InstalledApp, data []byte) {
- // 打码密码字符串
+ // Hide log password string
data = bytes.Replace(data, []byte(v.Password), []byte("******"), -1)
saveDir := filepath.Join(app.Config.Server.DataDir, "log")
@@ -288,13 +278,13 @@ func (t *Task) writeLog(v model.InstalledApp, data []byte) {
func (t *Task) startedState() {
t.Running = true
- log.Info("开始执行定时任务...")
+ log.Info(i18n.Localize("task.started"))
}
func (t *Task) completedState() {
t.Running = false
t.InstallingApp = nil
- log.Warn("定时任务执行完成")
+ log.Info(i18n.Localize("task.completed"))
}
func ScheduleRefreshApps() error {
diff --git a/web/fs_dev.go b/web/fs_dev.go
index 5c13a2a..3ba532c 100644
--- a/web/fs_dev.go
+++ b/web/fs_dev.go
@@ -8,5 +8,5 @@ import (
)
func StaticAssets() fs.FS {
- return os.DirFS("static/dist")
+ return os.DirFS("web/static/dist")
}
diff --git a/web/router.go b/web/router.go
index c8981ad..2ac774b 100644
--- a/web/router.go
+++ b/web/router.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/bitxeno/atvloadly/internal/app"
+ "github.com/bitxeno/atvloadly/internal/i18n"
"github.com/bitxeno/atvloadly/internal/ipa"
"github.com/bitxeno/atvloadly/internal/manager"
"github.com/bitxeno/atvloadly/internal/model"
@@ -71,11 +72,21 @@ func route(fi *fiber.App) {
})
- // api路由
+ // API route
api := fi.Group("/api")
api.Get("/hello", func(c *fiber.Ctx) error {
return c.SendString("hello world.")
})
+ api.Post("/lang/sync", func(c *fiber.Ctx) error {
+ lang := c.Params("lang")
+ accept := c.Get("Accept-Language")
+ if lang != "" {
+ i18n.SetLanguage(lang)
+ } else {
+ i18n.SetLanguage(accept)
+ }
+ return c.Status(http.StatusOK).JSON(apiSuccess(i18n.Localize("language")))
+ })
api.Get("/settings", func(c *fiber.Ctx) error {
return c.Status(http.StatusOK).JSON(apiSuccess(app.Settings))
})
diff --git a/web/static/src/api/api.js b/web/static/src/api/api.js
index 5b56eb8..75a0b87 100644
--- a/web/static/src/api/api.js
+++ b/web/static/src/api/api.js
@@ -1,6 +1,13 @@
import request from "@/utils/request";
export default {
+ syncLang: (params) => {
+ return request({
+ url: '/api/lang/sync',
+ method: "post",
+ params
+ });
+ },
getDevice: (id) => {
return request({
url: `/api/devices/${id}`,
diff --git a/web/static/src/page/layout.vue b/web/static/src/page/layout.vue
index 3d578c1..045d58b 100644
--- a/web/static/src/page/layout.vue
+++ b/web/static/src/page/layout.vue
@@ -57,6 +57,7 @@