mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-17 23:20:13 +01:00
🎨 桌面端自动下载更新安装包 https://github.com/siyuan-note/siyuan/issues/5837
This commit is contained in:
parent
9531bdd01c
commit
e2a6780cec
14 changed files with 155 additions and 16 deletions
|
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"autoDownloadUpdatePkg": "Automatically download update installation package",
|
||||||
|
"autoDownloadUpdatePkgTip": "After enabling, it will automatically check the version update every two hours. If there is an updated version, it will automatically download the installation package and prompt for installation",
|
||||||
"downloaded": "Downloaded",
|
"downloaded": "Downloaded",
|
||||||
"allOp": "All operations",
|
"allOp": "All operations",
|
||||||
"htmlBlockError": "The execution of the following script will affect the interface display, and the script has stopped running",
|
"htmlBlockError": "The execution of the following script will affect the interface display, and the script has stopped running",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"autoDownloadUpdatePkg": "Descargar automáticamente el paquete de instalación de actualizaciones",
|
||||||
|
"autoDownloadUpdatePkgTip": "Después de abrir, verificará automáticamente la actualización de la versión cada dos horas. Si hay una versión actualizada, descargará automáticamente el paquete de instalación y solicitará la instalación",
|
||||||
"downloaded": "Descargado",
|
"downloaded": "Descargado",
|
||||||
"allOp": "Todas las operaciones",
|
"allOp": "Todas las operaciones",
|
||||||
"htmlBlockError": "La ejecución del siguiente script afectará la visualización de la interfaz y el script ha dejado de ejecutarse",
|
"htmlBlockError": "La ejecución del siguiente script afectará la visualización de la interfaz y el script ha dejado de ejecutarse",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"autoDownloadUpdatePkg": "Télécharger automatiquement le package d'installation de la mise à jour",
|
||||||
|
"autoDownloadUpdatePkgTip": "Après l'ouverture, il vérifiera automatiquement la mise à jour de la version toutes les deux heures. S'il existe une version mise à jour, il téléchargera automatiquement le package d'installation et demandera l'installation",
|
||||||
"downloaded": "Téléchargé",
|
"downloaded": "Téléchargé",
|
||||||
"allOp": "Toutes les opérations",
|
"allOp": "Toutes les opérations",
|
||||||
"htmlBlockError": "L'exécution du script suivant affectera l'affichage de l'interface et le script a cessé de s'exécuter",
|
"htmlBlockError": "L'exécution du script suivant affectera l'affichage de l'interface et le script a cessé de s'exécuter",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"autoDownloadUpdatePkg": "自動下載更新安裝包",
|
||||||
|
"autoDownloadUpdatePkgTip": "開啟後會每隔兩小時自動檢查版本更新,如果有更新版本則自動下載安裝包並提示安裝",
|
||||||
"downloaded": "已下載",
|
"downloaded": "已下載",
|
||||||
"allOp": "所有操作",
|
"allOp": "所有操作",
|
||||||
"htmlBlockError": "以下 script 執行會影響界面顯示,已經停止運行該腳本",
|
"htmlBlockError": "以下 script 執行會影響界面顯示,已經停止運行該腳本",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"autoDownloadUpdatePkg": "自动下载更新安装包",
|
||||||
|
"autoDownloadUpdatePkgTip": "开启后会每隔两小时自动检查版本更新,如果有更新版本则自动下载安装包并提示安装",
|
||||||
"downloaded": "已下载",
|
"downloaded": "已下载",
|
||||||
"allOp": "所有操作",
|
"allOp": "所有操作",
|
||||||
"htmlBlockError": "以下 script 执行会影响界面显示,已经停止运行该脚本",
|
"htmlBlockError": "以下 script 执行会影响界面显示,已经停止运行该脚本",
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,14 @@ export const about = {
|
||||||
<svg><use xlink:href="#iconRefresh"></use></svg>${window.siyuan.languages.checkUpdate}
|
<svg><use xlink:href="#iconRefresh"></use></svg>${window.siyuan.languages.checkUpdate}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="fn__flex b3-label${isBrowser() ? " fn__none" : ""}">
|
||||||
|
<div class="fn__flex-1">
|
||||||
|
${window.siyuan.languages.autoDownloadUpdatePkg}
|
||||||
|
<div class="b3-label__text">${window.siyuan.languages.autoDownloadUpdatePkgTip}</div>
|
||||||
|
</div>
|
||||||
|
<div class="fn__space"></div>
|
||||||
|
<input class="b3-switch fn__flex-center" id="downloadInstallPkg" type="checkbox"${window.siyuan.config.system.downloadInstallPkg ? " checked" : ""}>
|
||||||
|
</div>
|
||||||
<div class="fn__flex b3-label">
|
<div class="fn__flex b3-label">
|
||||||
<div class="fn__flex-1">
|
<div class="fn__flex-1">
|
||||||
${window.siyuan.languages.systemLog}
|
${window.siyuan.languages.systemLog}
|
||||||
|
|
@ -339,6 +347,12 @@ export const about = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const downloadInstallPkgElement = about.element.querySelector("#downloadInstallPkg") as HTMLInputElement;
|
||||||
|
downloadInstallPkgElement.addEventListener("change", () => {
|
||||||
|
fetchPost("/api/system/setDownloadInstallPkg", {downloadInstallPkg: downloadInstallPkgElement.checked}, () => {
|
||||||
|
window.siyuan.config.system.downloadInstallPkg = downloadInstallPkgElement.checked
|
||||||
|
});
|
||||||
|
});
|
||||||
about.element.querySelector("#aboutConfim").addEventListener("click", () => {
|
about.element.querySelector("#aboutConfim").addEventListener("click", () => {
|
||||||
fetchPost("/api/system/setNetworkProxy", {
|
fetchPost("/api/system/setNetworkProxy", {
|
||||||
scheme: (about.element.querySelector("#aboutScheme") as HTMLInputElement).value,
|
scheme: (about.element.querySelector("#aboutScheme") as HTMLInputElement).value,
|
||||||
|
|
|
||||||
1
app/src/types/index.d.ts
vendored
1
app/src/types/index.d.ts
vendored
|
|
@ -304,6 +304,7 @@ declare interface IConfig {
|
||||||
xanadu: boolean
|
xanadu: boolean
|
||||||
udanax: boolean
|
udanax: boolean
|
||||||
uploadErrLog: boolean
|
uploadErrLog: boolean
|
||||||
|
downloadInstallPkg: boolean
|
||||||
networkServe: boolean
|
networkServe: boolean
|
||||||
useExistingDB: boolean
|
useExistingDB: boolean
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ func ServeAPI(ginServer *gin.Engine) {
|
||||||
ginServer.Handle("POST", "/api/system/setAccessAuthCode", model.CheckAuth, setAccessAuthCode)
|
ginServer.Handle("POST", "/api/system/setAccessAuthCode", model.CheckAuth, setAccessAuthCode)
|
||||||
ginServer.Handle("POST", "/api/system/setNetworkServe", model.CheckAuth, setNetworkServe)
|
ginServer.Handle("POST", "/api/system/setNetworkServe", model.CheckAuth, setNetworkServe)
|
||||||
ginServer.Handle("POST", "/api/system/setUploadErrLog", model.CheckAuth, setUploadErrLog)
|
ginServer.Handle("POST", "/api/system/setUploadErrLog", model.CheckAuth, setUploadErrLog)
|
||||||
|
ginServer.Handle("POST", "/api/system/setDownloadInstallPkg", model.CheckAuth, setDownloadInstallPkg)
|
||||||
ginServer.Handle("POST", "/api/system/setNetworkProxy", model.CheckAuth, setNetworkProxy)
|
ginServer.Handle("POST", "/api/system/setNetworkProxy", model.CheckAuth, setNetworkProxy)
|
||||||
ginServer.Handle("POST", "/api/system/setWorkspaceDir", model.CheckAuth, setWorkspaceDir)
|
ginServer.Handle("POST", "/api/system/setWorkspaceDir", model.CheckAuth, setWorkspaceDir)
|
||||||
ginServer.Handle("POST", "/api/system/listWorkspaceDirs", model.CheckAuth, listWorkspaceDirs)
|
ginServer.Handle("POST", "/api/system/listWorkspaceDirs", model.CheckAuth, listWorkspaceDirs)
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,20 @@ func setUploadErrLog(c *gin.Context) {
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setDownloadInstallPkg(c *gin.Context) {
|
||||||
|
ret := gulu.Ret.NewResult()
|
||||||
|
defer c.JSON(http.StatusOK, ret)
|
||||||
|
|
||||||
|
arg, ok := util.JsonArg(c, ret)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadInstallPkg := arg["downloadInstallPkg"].(bool)
|
||||||
|
model.Conf.System.DownloadInstallPkg = downloadInstallPkg
|
||||||
|
model.Conf.Save()
|
||||||
|
}
|
||||||
|
|
||||||
func setNetworkProxy(c *gin.Context) {
|
func setNetworkProxy(c *gin.Context) {
|
||||||
ret := gulu.Ret.NewResult()
|
ret := gulu.Ret.NewResult()
|
||||||
defer c.JSON(http.StatusOK, ret)
|
defer c.JSON(http.StatusOK, ret)
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,16 @@ type System struct {
|
||||||
NetworkServe bool `json:"networkServe"`
|
NetworkServe bool `json:"networkServe"`
|
||||||
NetworkProxy *NetworkProxy `json:"networkProxy"`
|
NetworkProxy *NetworkProxy `json:"networkProxy"`
|
||||||
|
|
||||||
UploadErrLog bool `json:"uploadErrLog"`
|
UploadErrLog bool `json:"uploadErrLog"`
|
||||||
|
DownloadInstallPkg bool `json:"downloadInstallPkg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSystem() *System {
|
func NewSystem() *System {
|
||||||
return &System{
|
return &System{
|
||||||
ID: util.GetDeviceID(),
|
ID: util.GetDeviceID(),
|
||||||
KernelVersion: util.Ver,
|
KernelVersion: util.Ver,
|
||||||
NetworkProxy: &NetworkProxy{},
|
NetworkProxy: &NetworkProxy{},
|
||||||
|
DownloadInstallPkg: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func main() {
|
||||||
go model.HookResident()
|
go model.HookResident()
|
||||||
util.SetBooted()
|
util.SetBooted()
|
||||||
util.ClearPushProgress(100)
|
util.ClearPushProgress(100)
|
||||||
go model.AutoRefreshUser()
|
go model.AutoRefreshCheck()
|
||||||
go model.AutoFlushTx()
|
go model.AutoFlushTx()
|
||||||
go sql.AutoFlushTreeQueue()
|
go sql.AutoFlushTreeQueue()
|
||||||
go treenode.AutoFlushBlockTree()
|
go treenode.AutoFlushBlockTree()
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func StartKernel(container, appDir, workspaceDir, nativeLibDir, privateDataDir,
|
||||||
go model.AutoStat()
|
go model.AutoStat()
|
||||||
util.SetBooted()
|
util.SetBooted()
|
||||||
util.ClearPushProgress(100)
|
util.ClearPushProgress(100)
|
||||||
go model.AutoRefreshUser()
|
go model.AutoRefreshCheck()
|
||||||
go model.AutoFlushTx()
|
go model.AutoFlushTx()
|
||||||
go sql.AutoFlushTreeQueue()
|
go sql.AutoFlushTreeQueue()
|
||||||
go treenode.AutoFlushBlockTree()
|
go treenode.AutoFlushBlockTree()
|
||||||
|
|
|
||||||
|
|
@ -144,11 +144,11 @@ func LoadUploadToken() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
refreshUserTicker = time.NewTicker(2 * time.Hour)
|
refreshCheckTicker = time.NewTicker(2 * time.Hour)
|
||||||
subscriptionExpirationReminded bool
|
subscriptionExpirationReminded bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func AutoRefreshUser() {
|
func AutoRefreshCheck() {
|
||||||
for {
|
for {
|
||||||
if !subscriptionExpirationReminded {
|
if !subscriptionExpirationReminded {
|
||||||
subscriptionExpirationReminded = true
|
subscriptionExpirationReminded = true
|
||||||
|
|
@ -235,7 +235,12 @@ func AutoRefreshUser() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-refreshUserTicker.C
|
go func() {
|
||||||
|
defer logging.Recover()
|
||||||
|
checkDownloadInstallPkg()
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-refreshCheckTicker.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,111 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/88250/gulu"
|
||||||
|
"github.com/imroc/req/v3"
|
||||||
"github.com/siyuan-note/logging"
|
"github.com/siyuan-note/logging"
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func checkDownloadInstallPkg() {
|
||||||
checkUpdateLock = &sync.Mutex{}
|
if !Conf.System.DownloadInstallPkg {
|
||||||
)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := util.GetRhyResult(false)
|
||||||
|
if nil != err {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
installPkgSite := result["installPkg"].(string)
|
||||||
|
ver := result["ver"].(string)
|
||||||
|
if ver == util.Ver {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var suffix string
|
||||||
|
if gulu.OS.IsWindows() {
|
||||||
|
if "386" == runtime.GOARCH {
|
||||||
|
suffix = "win32.exe"
|
||||||
|
} else {
|
||||||
|
suffix = "win.exe"
|
||||||
|
}
|
||||||
|
} else if gulu.OS.IsDarwin() {
|
||||||
|
if "arm64" == runtime.GOARCH {
|
||||||
|
suffix = "mac-arm64.dmg"
|
||||||
|
} else {
|
||||||
|
suffix = "mac.dmg"
|
||||||
|
}
|
||||||
|
} else if gulu.OS.IsLinux() {
|
||||||
|
suffix = "linux.AppImage"
|
||||||
|
}
|
||||||
|
pkg := "siyuan-" + ver + "-" + suffix
|
||||||
|
installPkg := "siyuan/" + pkg
|
||||||
|
downloadPkgURL := installPkgSite + installPkg
|
||||||
|
localPkgPath := filepath.Join(util.TempDir, "install", pkg)
|
||||||
|
checksums := result["checksums"].(map[string]interface{})
|
||||||
|
checksum := checksums[pkg].(string)
|
||||||
|
|
||||||
|
downloadInstallPkg(downloadPkgURL, checksum, localPkgPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadInstallPkg(pkgURL, checksum, savePath string) {
|
||||||
|
if gulu.File.IsExist(savePath) {
|
||||||
|
localChecksum, _ := sha256Hash(savePath)
|
||||||
|
if localChecksum == checksum {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client := req.C()
|
||||||
|
callback := func(info req.DownloadInfo) {
|
||||||
|
logging.LogInfof("downloading install package from [%s] %.2f%%", pkgURL, float64(info.DownloadedSize)/float64(info.Response.ContentLength)*100.0)
|
||||||
|
}
|
||||||
|
resp, err := client.R().SetOutputFile(savePath).SetDownloadCallback(callback).Get(pkgURL)
|
||||||
|
if nil != err {
|
||||||
|
logging.LogErrorf("download install package failed: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if 200 != resp.StatusCode {
|
||||||
|
logging.LogErrorf("download install package [%s] failed [sc=%d]", pkgURL, resp.StatusCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logging.LogInfof("downloaded install package [%s] to [%s]", pkgURL, savePath)
|
||||||
|
localChecksum, _ := sha256Hash(savePath)
|
||||||
|
if checksum != localChecksum {
|
||||||
|
logging.LogErrorf("verify checksum failed, download install package [%s] checksum [%s] not equal to downloaded [%s] checksum [%s]", pkgURL, checksum, savePath, localChecksum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sha256Hash(filename string) (ret string, err error) {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if nil != err {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
hash := sha256.New()
|
||||||
|
reader := bufio.NewReader(file)
|
||||||
|
buf := make([]byte, 1024*1024*4)
|
||||||
|
for {
|
||||||
|
switch n, readErr := reader.Read(buf); readErr {
|
||||||
|
case nil:
|
||||||
|
hash.Write(buf[:n])
|
||||||
|
case io.EOF:
|
||||||
|
return fmt.Sprintf("%x", hash.Sum(nil)), nil
|
||||||
|
default:
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Announcement struct {
|
type Announcement struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
|
@ -58,9 +153,6 @@ func CheckUpdate(showMsg bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
checkUpdateLock.Lock()
|
|
||||||
defer checkUpdateLock.Unlock()
|
|
||||||
|
|
||||||
result, err := util.GetRhyResult(showMsg)
|
result, err := util.GetRhyResult(showMsg)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue