Browse Source

add update

master
godo 11 months ago
parent
commit
382fca2364
  1. 3
      app/app.go
  2. 102
      app/update.go
  3. 2
      frontend/src/components/setting/SetSystem.vue
  4. 1
      frontend/src/system/config.ts
  5. 25
      frontend/src/system/index.ts
  6. 1
      frontend/src/system/window/Dialog.ts
  7. 14
      frontend/src/util/goutil.ts
  8. 172
      frontend/src/util/update.ts
  9. 2
      frontend/wailsjs/go/app/App.d.ts
  10. 4
      frontend/wailsjs/go/app/App.js
  11. 6
      go.mod
  12. 2
      godo/.gitignore
  13. 8
      godo/cmd/main.go
  14. 8
      godo/cmd/serve.go
  15. 5
      godo/go.mod
  16. 21
      godo/go.sum
  17. 2
      godo/sys/setting.go
  18. 41
      godo/sys/store.go
  19. 175
      godo/sys/update.go

3
app/app.go

@ -13,8 +13,7 @@ import (
// App struct // App struct
type App struct { type App struct {
ctx context.Context ctx context.Context
exDir string
} }
// NewApp creates a new App application struct // NewApp creates a new App application struct

102
app/update.go

@ -1,102 +0,0 @@
package app
import (
"archive/zip"
"bytes"
"io"
"net/http"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/minio/selfupdate"
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
)
type ProgressReader struct {
reader io.Reader
total int64
err error
}
type DownloadStatus struct {
Name string `json:"name"`
Path string `json:"path"`
Url string `json:"url"`
Transferred int64 `json:"transferred"`
Size int64 `json:"size"`
Speed float64 `json:"speed"`
Progress float64 `json:"progress"`
Downloading bool `json:"downloading"`
Done bool `json:"done"`
}
func (pr *ProgressReader) Read(p []byte) (n int, err error) {
n, err = pr.reader.Read(p)
pr.err = err
pr.total += int64(n)
return
}
func (a *App) UpdateApp(url string) (broken bool, err error) {
resp, err := http.Get(url)
if err != nil {
return false, err
}
defer resp.Body.Close()
pr := &ProgressReader{reader: resp.Body}
ticker := time.NewTicker(250 * time.Millisecond)
defer ticker.Stop()
// update progress
go func() {
for {
<-ticker.C
wruntime.EventsEmit(a.ctx, "updateApp", &DownloadStatus{
Name: filepath.Base(url),
Path: "",
Url: url,
Transferred: pr.total,
Size: resp.ContentLength,
Speed: 0,
Progress: 100 * (float64(pr.total) / float64(resp.ContentLength)),
Downloading: pr.err == nil && pr.total < resp.ContentLength,
Done: pr.total == resp.ContentLength,
})
if pr.err != nil || pr.total == resp.ContentLength {
break
}
}
}()
var updateFile io.Reader = pr
// extract macos binary from zip
if strings.HasSuffix(url, ".zip") && runtime.GOOS == "darwin" {
zipBytes, err := io.ReadAll(pr)
if err != nil {
return false, err
}
archive, err := zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes)))
if err != nil {
return false, err
}
file, err := archive.Open("godoos.app/Contents/MacOS/godoos")
if err != nil {
return false, err
}
defer file.Close()
updateFile = file
}
// apply update
err = selfupdate.Apply(updateFile, selfupdate.Options{})
if err != nil {
if rerr := selfupdate.RollbackError(err); rerr != nil {
return true, rerr
}
return false, err
}
// restart app
a.RestartApp()
return false, nil
}

2
frontend/src/components/setting/SetSystem.vue

@ -27,7 +27,7 @@
</div> </div>
<div class="setting-item" v-if="config.storeType === 'local'"> <div class="setting-item" v-if="config.storeType === 'local'">
<label>存储地址</label> <label>存储地址</label>
<el-input v-model="config.storePath" @click="selectFile" /> <el-input v-model="config.storePath" @click="selectFile()" />
</div> </div>
<template v-if="config.storeType === 'net'"> <template v-if="config.storeType === 'net'">
<div class="setting-item"> <div class="setting-item">

1
frontend/src/system/config.ts

@ -15,6 +15,7 @@ export const getSystemConfig = (ifset = false) => {
// 初始化配置对象的各项属性,若本地存储中已存在则不进行覆盖 // 初始化配置对象的各项属性,若本地存储中已存在则不进行覆盖
if (!config.version) { if (!config.version) {
config.version = '1.0.0'; config.version = '1.0.0';
//config.version = '0.0.9';
} }
if (!config.isFirstRun) { if (!config.isFirstRun) {
config.isFirstRun = false; config.isFirstRun = false;

25
frontend/src/system/index.ts

@ -25,7 +25,8 @@ import { Tray, TrayOptions } from './menu/Tary';
import { InitSystemFile, InitUserFile } from './core/SystemFileConfig'; import { InitSystemFile, InitUserFile } from './core/SystemFileConfig';
import { createInitFile } from './core/createInitFile'; import { createInitFile } from './core/createInitFile';
import { getSystemConfig, getSystemKey, setSystemKey, setSystemConfig, clearSystemConfig } from './config' import { getSystemConfig, getSystemKey, setSystemKey, setSystemConfig, clearSystemConfig } from './config'
import { checkUpdate } from '@/util/update';
import { RestartApp } from '@/util/goutil';
export type OsPlugin = (system: System) => void; export type OsPlugin = (system: System) => void;
export type FileOpener = { export type FileOpener = {
@ -71,8 +72,6 @@ export class System {
this._eventer = this.initEvent(); this._eventer = this.initEvent();
this.firstRun(); this.firstRun();
this.initSystem(); this.initSystem();
} }
/** /**
@ -112,11 +111,17 @@ export class System {
this.initBackground(); // 初始化壁纸 this.initBackground(); // 初始化壁纸
this.emit('start'); this.emit('start');
// setTimeout(() => { setTimeout(() => {
// if (this._rootState.magnet?.length < 1) { if (this._rootState.magnet?.length < 1) {
// this.refershAppList() this.refershAppList()
// } }
// }, 6000); checkUpdate();
setTimeout(() => {
if (this._rootState.magnet?.length < 1) {
this.recover()
}
}, 3000);
}, 6000);
} }
/** /**
@ -382,7 +387,7 @@ export class System {
} }
reboot() { reboot() {
this._rootState.state = SystemStateEnum.close; this._rootState.state = SystemStateEnum.close;
window.location.reload(); RestartApp();
} }
recover() { recover() {
clearSystemConfig() clearSystemConfig()
@ -390,7 +395,7 @@ export class System {
this.fs.removeFileSystem().then(() => { this.fs.removeFileSystem().then(() => {
window.indexedDB.deleteDatabase("GodoDatabase"); window.indexedDB.deleteDatabase("GodoDatabase");
window.location.reload(); RestartApp();
}) })
} }

1
frontend/src/system/window/Dialog.ts

@ -49,6 +49,7 @@ class Dialog {
return { return {
setProgress, setProgress,
dialogwin
}; };
} }
public static showMessageBox(option: { public static showMessageBox(option: {

14
frontend/src/util/goutil.ts

@ -1,8 +1,16 @@
export async function OpenDirDialog(){ export async function OpenDirDialog(){
if((window as any).go) { if((window as any).go) {
//(window as any).go.OpenDirDialog(); return (window as any)['go']['app']['App']['OpenDirDialog']();
return (window as any)['go']['main']['App']['OpenDirDialog']();
}else { }else {
return "" return ""
} }
} }
export function RestartApp(){
if(!(window as any).go){
window.location.reload();
}else{
return (window as any)['go']['app']['App']['RestartApp']();
}
}

172
frontend/src/util/update.ts

@ -1,114 +1,62 @@
//import { EventsOff, EventsOn } from '~/runtime'; import { getSystemConfig,setSystemKey,parseJson } from '@/system/config'
//import manifest from '../../package.json'; import { RestartApp } from './goutil';
import {isWindowsOS,getSystemConfig} from '@/system/config' import { Dialog } from '@/system';
import { ElMessage } from 'element-plus'
export async function checkUpdate() { export async function checkUpdate() {
if(!(window as any).go) return; const config = getSystemConfig();
const config = getSystemConfig(); const updateGiteeUrl = `${config.apiUrl}/system/updateInfo`
const updateGiteeUrl = `https://gitee.com/api/v5/repos/ruitao_admin/godoos/releases/` const releaseRes = await fetch(updateGiteeUrl)
const releaseRes = await fetch(updateGiteeUrl) if (!releaseRes.ok) return;
if(!releaseRes.ok) return; const releaseData = await releaseRes.json()
const releaseData = await releaseRes.json() const versionTag = releaseData.version;
const versionTag = releaseData.tag_name; if (!versionTag) return;
if(!versionTag) return; if (versionTag <= config.version) return;
if (versionTag.replace('v', '') <= config.version) return; const updateUrl = releaseData.url
const verifyUrl = `${updateGiteeUrl}tags/${versionTag}`; if (!updateUrl || updateUrl == '') return;
const verRes = await fetch(verifyUrl); const dialogRes: any = await Dialog.showMessageBox({
if(!verRes.ok) return; title: '更新提示',
const verData = await verRes.json() message: `发现新版本:${versionTag},是否更新?`
if(!verData.assets || verData.assets.length <= 0) return; })
const appName = "godoos"+ versionTag + (isWindowsOS() ? '.exe' : ''); //console.log(dialogRes)
const updateUrl = `${updateGiteeUrl}download/${versionTag}/${appName}`; if (dialogRes.response !== -1) {
console.log(updateUrl) return;
// fetch(`${updateGiteeUrl}latest`).then((r) => {
// if (r.ok) {
// r.json().then((data) => {
// if (data.tag_name) {
// const versionTag = data.tag_name;
// console.log(versionTag)
// if (versionTag.replace('v', '') > manifest.version) {
// const verifyUrl = `${updateGiteeUrl}tags/${versionTag}`;
// }
/*
if (versionTag.replace('v', '') > manifest.version) {
const verifyUrl = `${updateGiteeUrl}tags/${versionTag}`;
fetch(verifyUrl).then((r) => {
if (r.ok) {
r.json().then((data) => {
if (data.assets && data.assets.length > 0) {
const asset = data.assets.find((a: any) => a.name.toLowerCase().includes(commonStore.platform.toLowerCase().replace('darwin', 'macos')));
if (asset) {
const updateUrl = `${updateGiteeUrl}download/${versionTag}/${asset.name}`;
toastWithButton(t('New Version Available') + ': ' + versionTag, t('Update'), () => {
DeleteFile('cache.json');
const progressId = 'update_app';
const progressEvent = 'updateApp';
const updateProgress = (ds: DownloadStatus | null) => {
const content =
t('Downloading update, please wait. If it is not completed, please manually download the program from GitHub and replace the original program.')
+ (ds ? ` (${ds.progress.toFixed(2)}% ${bytesToReadable(ds.transferred)}/${bytesToReadable(ds.size)})` : '');
const options: ToastOptions = {
type: 'info',
position: 'bottom-left',
autoClose: false,
toastId: progressId,
hideProgressBar: false,
progress: ds ? ds.progress / 100 : 0
};
if (toast.isActive(progressId))
toast.update(progressId, {
render: content,
...options
});
else
toast(content, options);
};
updateProgress(null);
EventsOn(progressEvent, updateProgress);
UpdateApp(updateUrl).then(() => {
toast(t('Update completed, please restart the program.'), {
type: 'success',
position: 'bottom-left',
autoClose: false
}
);
}).catch((e) => {
toast(t('Update Error') + ' - ' + (e.message || e), {
type: 'error',
position: 'bottom-left',
autoClose: false
});
}).finally(() => {
toast.dismiss(progressId);
EventsOff(progressEvent);
});
}, {
autoClose: false,
position: 'bottom-left'
});
}
}
});
} else {
throw new Error('Verify response was not ok.');
}
});
} else {
if (notifyEvenLatest) {
toast(t('This is the latest version'), { type: 'success', position: 'bottom-left', autoClose: 2000 });
}
}
*/
// } else {
// throw new Error('Invalid response.');
// }
// });
// } else {
// throw new Error('Network response was not ok.');
// }
// }
// ).catch((e) => {
// //toast(t('Updates Check Error') + ' - ' + (e.message || e), { type: 'error', position: 'bottom-left' });
// });
} }
const { setProgress,dialogwin } = Dialog.showProcessDialog({
message: '正在更新',
});
const upUrl = `${config.apiUrl}/system/update?url=${updateUrl}`
const upRes = await fetch(upUrl)
if (!upRes.ok) return;
const reader: any = upRes.body?.getReader();
if (!reader) {
ElMessage({
type: 'error',
message: "the system has not stream!"
})
}
while (true) {
const { done, value } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
const rawjson = new TextDecoder().decode(value);
const json = parseJson(rawjson);
console.log(json)
if(json){
if(json.progress){
setProgress(json.progress)
}
if(json.updateCompleted){
dialogwin.close()
ElMessage({
type: 'success',
message: "update completed!"
})
setSystemKey('version',versionTag)
RestartApp()
break;
}
}
}
}

2
frontend/wailsjs/go/app/App.d.ts

@ -4,5 +4,3 @@
export function OpenDirDialog():Promise<string>; export function OpenDirDialog():Promise<string>;
export function RestartApp():Promise<void>; export function RestartApp():Promise<void>;
export function UpdateApp(arg1:string):Promise<boolean>;

4
frontend/wailsjs/go/app/App.js

@ -9,7 +9,3 @@ export function OpenDirDialog() {
export function RestartApp() { export function RestartApp() {
return window['go']['app']['App']['RestartApp'](); return window['go']['app']['App']['RestartApp']();
} }
export function UpdateApp(arg1) {
return window['go']['app']['App']['UpdateApp'](arg1);
}

6
go.mod

@ -2,15 +2,13 @@ module godoos
go 1.22.5 go 1.22.5
require ( require github.com/wailsapp/wails/v2 v2.9.1
github.com/minio/selfupdate v0.6.0
github.com/wailsapp/wails/v2 v2.9.1
)
require ( require (
aead.dev/minisign v0.2.0 // indirect aead.dev/minisign v0.2.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/mux v1.8.1 // indirect
github.com/minio/selfupdate v0.6.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect github.com/tklauser/numcpus v0.8.0 // indirect

2
godo/.gitignore

@ -0,0 +1,2 @@
tmp

8
godo/cmd/main.go

@ -6,6 +6,7 @@ import (
"godo/libs" "godo/libs"
"godo/localchat" "godo/localchat"
"godo/progress" "godo/progress"
"godo/sys"
"log" "log"
"net/http" "net/http"
"time" "time"
@ -38,8 +39,11 @@ func OsStart() {
progressRouter.HandleFunc("/app/{name}/{subpath:.*}", progress.ForwardRequest).Methods(http.MethodGet, http.MethodPost) progressRouter.HandleFunc("/app/{name}/{subpath:.*}", progress.ForwardRequest).Methods(http.MethodGet, http.MethodPost)
router.HandleFunc("/ping", progress.Ping).Methods(http.MethodGet) router.HandleFunc("/ping", progress.Ping).Methods(http.MethodGet)
router.HandleFunc("/", progress.Ping).Methods(http.MethodGet) router.HandleFunc("/", progress.Ping).Methods(http.MethodGet)
router.HandleFunc("/system/info", files.HandleSystemInfo).Methods(http.MethodGet) router.HandleFunc("/system/updateInfo", sys.GetUpdateUrlHandler).Methods(http.MethodGet)
router.HandleFunc("/system/setting", HandleSetConfig).Methods(http.MethodPost) router.HandleFunc("/system/update", sys.UpdateAppHandler).Methods(http.MethodGet)
router.HandleFunc("/system/storeList", sys.GetStoreInfoHandler).Methods(http.MethodGet)
router.HandleFunc("/system/setting", sys.HandleSetConfig).Methods(http.MethodPost)
router.HandleFunc("/files/info", files.HandleSystemInfo).Methods(http.MethodGet)
router.HandleFunc("/file/read", files.HandleReadDir).Methods(http.MethodGet) router.HandleFunc("/file/read", files.HandleReadDir).Methods(http.MethodGet)
router.HandleFunc("/file/stat", files.HandleStat).Methods(http.MethodGet) router.HandleFunc("/file/stat", files.HandleStat).Methods(http.MethodGet)
router.HandleFunc("/file/chmod", files.HandleChmod).Methods(http.MethodPost) router.HandleFunc("/file/chmod", files.HandleChmod).Methods(http.MethodPost)

8
godo/cmd/serve.go

@ -73,10 +73,10 @@ func corsMiddleware() mux.MiddlewareFunc {
w.Header().Set("Access-Control-Allow-Headers", allowHeaders) w.Header().Set("Access-Control-Allow-Headers", allowHeaders)
// 如果是预检请求(OPTIONS),直接返回 200 OK // 如果是预检请求(OPTIONS),直接返回 200 OK
// if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
// w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
// return return
// } }
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })

5
godo/go.mod

@ -3,18 +3,21 @@ module godo
go 1.22.5 go 1.22.5
require ( require (
github.com/cavaliergopher/grab/v3 v3.0.1
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.7.0
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
github.com/minio/selfupdate v0.6.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
) )
require ( require (
github.com/cavaliergopher/grab/v3 v3.0.1 // indirect aead.dev/minisign v0.2.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/stretchr/testify v1.9.0 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect github.com/tklauser/numcpus v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b // indirect
golang.org/x/sys v0.19.0 // indirect golang.org/x/sys v0.19.0 // indirect
) )

21
godo/go.sum

@ -1,3 +1,5 @@
aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -8,6 +10,8 @@ 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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/minio/selfupdate v0.6.0 h1:i76PgT0K5xO9+hjzKcacQtO7+MjJ4JKA8Ak8XQ9DDwU=
github.com/minio/selfupdate v0.6.0/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -22,8 +26,25 @@ github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYg
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b h1:QAqMVf3pSa6eeTsuklijukjXBlj7Es2QQplab+/RbQ4=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

2
godo/cmd/setting.go → godo/sys/setting.go

@ -1,4 +1,4 @@
package cmd package sys
import ( import (
"encoding/json" "encoding/json"

41
godo/sys/store.go

@ -0,0 +1,41 @@
package sys
import (
"encoding/json"
"fmt"
"godo/libs"
"io"
"net/http"
"runtime"
)
func GetStoreInfoHandler(w http.ResponseWriter, r *http.Request) {
cate := r.URL.Query().Get("cate")
os := runtime.GOOS
arch := runtime.GOARCH
if cate == "" {
libs.ErrorMsg(w, "cate is required")
return
}
pluginUrl := "https://gitee.com/ruitao_admin/godoos-image/raw/master/store/" + os + "/" + arch + "/" + cate + ".json"
res, err := http.Get(pluginUrl)
if err != nil {
libs.ErrorMsg(w, err.Error())
}
defer res.Body.Close()
if res.StatusCode == 200 {
body, err := io.ReadAll(res.Body)
if err != nil {
libs.ErrorMsg(w, err.Error())
return
}
var info interface{}
err = json.Unmarshal(body, &info)
if err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return
}
json.NewEncoder(w).Encode(info)
}
}

175
godo/sys/update.go

@ -0,0 +1,175 @@
package sys
import (
"encoding/json"
"fmt"
"godo/libs"
"io"
"log"
"net/http"
"path/filepath"
"runtime"
"time"
"github.com/minio/selfupdate"
)
type OSInfo struct {
Amd64 string `json:"amd64"`
Arm64 string `json:"arm64"`
}
type VersionInfo struct {
Version string `json:"version"`
Name string `json:"name"`
Description string `json:"description"`
Changelog string `json:"changelog"`
Windows OSInfo `json:"windows"`
Linux OSInfo `json:"linux"`
Darwin OSInfo `json:"darwin"`
}
type ProgressReader struct {
reader io.Reader
total int64
err error
}
type DownloadStatus struct {
Name string `json:"name"`
Path string `json:"path"`
Url string `json:"url"`
Current int64 `json:"current"`
Size int64 `json:"size"`
Speed float64 `json:"speed"`
Progress float64 `json:"progress"`
Downloading bool `json:"downloading"`
Done bool `json:"done"`
}
func (pr *ProgressReader) Read(p []byte) (n int, err error) {
n, err = pr.reader.Read(p)
pr.err = err
pr.total += int64(n)
return
}
func UpdateAppHandler(w http.ResponseWriter, r *http.Request) {
url := r.URL.Query().Get("url")
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
pr := &ProgressReader{reader: resp.Body}
ticker := time.NewTicker(250 * time.Millisecond)
defer ticker.Stop()
flusher, ok := w.(http.Flusher)
if !ok {
log.Printf("Streaming unsupported")
http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
return
}
// update progress
go func() {
for {
<-ticker.C
rp := &DownloadStatus{
Name: filepath.Base(url),
Path: "",
Url: url,
Current: pr.total,
Size: resp.ContentLength,
Speed: 0,
Progress: 100 * (float64(pr.total) / float64(resp.ContentLength)),
Downloading: pr.err == nil && pr.total < resp.ContentLength,
Done: pr.total == resp.ContentLength,
}
if pr.err != nil || pr.total == resp.ContentLength {
break
}
if w != nil {
jsonBytes, err := json.Marshal(rp)
if err != nil {
log.Printf("Error marshaling FileProgress to JSON: %v", err)
continue
}
io.WriteString(w, string(jsonBytes))
w.Write([]byte("\n"))
flusher.Flush()
} else {
log.Println("ResponseWriter is nil, cannot send progress")
}
}
}()
var updateFile io.Reader = pr
// apply update
err = selfupdate.Apply(updateFile, selfupdate.Options{})
if err != nil {
if rerr := selfupdate.RollbackError(err); rerr != nil {
http.Error(w, "update error:"+rerr.Error(), http.StatusInternalServerError)
return
}
return
}
// 更新完成后发送响应给前端
json.NewEncoder(w).Encode(map[string]bool{"updateCompleted": true})
}
func GetUpdateUrlHandler(w http.ResponseWriter, r *http.Request) {
updateUrl := "https://gitee.com/ruitao_admin/godoos-image/raw/master/version/version.json"
res, err := http.Get(updateUrl)
if err != nil {
libs.ErrorMsg(w, err.Error())
}
defer res.Body.Close()
if res.StatusCode == 200 {
body, err := io.ReadAll(res.Body)
if err != nil {
libs.ErrorMsg(w, err.Error())
return
}
var info VersionInfo
err = json.Unmarshal(body, &info)
if err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return
}
//log.Printf("info: %v", info)
// 根据操作系统和架构获取路径
path := getPathForOSAndArch(&info)
// 将结果以 JSON 格式返回给前端
response := map[string]string{"url": path, "version": info.Version}
json.NewEncoder(w).Encode(response)
}
}
// 根据操作系统和架构获取路径
func getPathForOSAndArch(info *VersionInfo) string {
os := runtime.GOOS
arch := runtime.GOARCH
switch os {
case "windows":
if arch == "amd64" {
return info.Windows.Amd64
} else if arch == "arm64" {
return info.Windows.Arm64
}
case "linux":
if arch == "amd64" {
return info.Linux.Amd64
} else if arch == "arm64" {
return info.Linux.Arm64
}
case "darwin":
if arch == "amd64" {
return info.Darwin.Amd64
} else if arch == "arm64" {
return info.Darwin.Arm64
}
default:
return ""
}
return ""
}
Loading…
Cancel
Save