- {{ currentTitle }}
+ {{ store.currentTitle }}
diff --git a/frontend/src/i18n/lang/en.json b/frontend/src/i18n/lang/en.json
index 06cadb0..ca72e32 100644
--- a/frontend/src/i18n/lang/en.json
+++ b/frontend/src/i18n/lang/en.json
@@ -2,6 +2,7 @@
"hello": "hello",
"startMenu.power": "Power",
"setting": "Setting",
+ "progressmanger": "Progress",
"startMenu.shutdown": "Shutdown",
"startMenu.recover": "Recover",
"windows.setting": "Windows Setting",
@@ -133,18 +134,34 @@
"cannot.create.shortcut": "Cannot Create Shortcut",
"shortcut.has.been.created": "Shortcut Has Been Created",
"system.message": "System Message",
- "store" : {
- "hots":"Popular",
+ "store": {
+ "hots": "Popular",
"work": "Work",
"development": "Development",
"games": "Games",
"education": "Education",
"news": "News",
- "shopping":"Shopping",
+ "shopping": "Shopping",
"social": "Social Networking",
"utilities": "Utilities",
"others": "Others",
- "add":"Add",
- "errorList":"Cannot get the list of applications"
-}
+ "add": "Add",
+ "errorList": "Cannot get the list of applications"
+ },
+ "process":{
+ "title":"Process Manager",
+ "port":"Port",
+ "pid":"PID",
+ "name":"Name",
+ "proto":"Protocol",
+ "action":"Actions"
+ },
+ "upgrade": {
+ "title": "New version",
+ "msg": "The new version is available, please update it now! Dont worry, the update is fast!",
+ "desc": "Prompt: Update will restore the default configuration",
+ "btnOne": "Cruel refusal",
+ "btnTwo": "Update now",
+ "btnTwoLoading": "Updating"
+ }
}
\ No newline at end of file
diff --git a/frontend/src/i18n/lang/zh.json b/frontend/src/i18n/lang/zh.json
index 74220ba..f4e4bd9 100644
--- a/frontend/src/i18n/lang/zh.json
+++ b/frontend/src/i18n/lang/zh.json
@@ -147,6 +147,29 @@
"utilities": "实用工具",
"others": "其他",
"add":"添加应用",
- "errorList":"获取列表失败!"
- }
+ "errorList":"获取列表失败!",
+ "urlEmpty":"网址为空",
+ "hasSameName":"存在相同名称的应用!",
+ "installError":"安装失败!",
+ "installSuccess":"安装成功!",
+ "uninstallSuccess":"卸载成功",
+ "downloadError":"下载失败!",
+ "cantStream":"暂不支持流下载!"
+ },
+ "process":{
+ "title":"进程管理",
+ "port":"端口",
+ "pid":"PID",
+ "name":"名称",
+ "proto":"类型",
+ "action":"操作"
+ },
+ "upgrade": {
+ "title": "新版本升级",
+ "msg": "新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!",
+ "desc": "提示:更新会还原默认配置",
+ "btnOne": "残忍拒绝",
+ "btnTwo": "马上更新",
+ "btnTwoLoading": "更新中"
+ }
}
\ No newline at end of file
diff --git a/frontend/src/stores/store.ts b/frontend/src/stores/store.ts
new file mode 100644
index 0000000..f813c77
--- /dev/null
+++ b/frontend/src/stores/store.ts
@@ -0,0 +1,108 @@
+import { defineStore } from 'pinia'
+import { ref } from "vue";
+import { t } from "@/i18n";
+// import storeInitList from "@/assets/store.json";
+import { getSystemKey } from "@/system/config";
+export const useStoreStore = defineStore('storeStore', () => {
+ const currentCateId = ref(0)
+ const currentTitle = ref(t("store.hots"))
+ const currentCate = ref('hots')
+ const categoryList = ['hots', 'work', 'development', 'games', 'education', 'news', 'shopping', 'social', 'utilities', 'others', 'add']
+ const categoryIcon = ['HomeFilled', 'Odometer', 'Postcard', 'TrendCharts', 'School', 'HelpFilled', 'ShoppingCart', 'ChatLineRound', 'MessageBox', 'Ticket', 'CirclePlusFilled']
+ const isready = ref(false);
+ const installed = getSystemKey("intstalledPlugins");
+ const apiUrl = getSystemKey("apiUrl");
+ const installedList: any = ref(installed);
+ const storeList: any = ref([])
+ const outList: any = ref([])
+ async function getList() {
+ if (currentCate.value == 'add') return;
+ //storeList.value = storeInitList
+ const storeUrl = apiUrl + '/store/storelist?cate=' + currentCate.value
+ const res = await fetch(storeUrl)
+ if (!res.ok) {
+ return []
+ }
+ let list:any = await res.json()
+ //console.log(data)
+ if (outList.value.length > 0 && currentCate.value == 'hots') {
+ const names = list.value.map((item : any) => item.name)
+ const adds:any = []
+ outList.value.forEach((item : any) => {
+ if (!names.includes(item.name)) {
+ adds.push(item)
+ }
+ })
+ list = adds.concat(list)
+ }
+ storeList.value = list
+ await checkProgress()
+ isready.value = true;
+ }
+ async function addOutList(item:any) {
+ const has = outList.value.find((i:any) => i.name === item.name)
+ if(!has) {
+ item.isOut = true
+ outList.value.push(item)
+ await getList()
+ return true
+ }else{
+ return false
+ }
+ }
+ async function changeCate(index: number, item: string) {
+ currentCateId.value = index
+ currentCate.value = item
+ currentTitle.value = t("store." + item)
+ await getList()
+ }
+ async function checkProgress() {
+ const completion: any = await fetch(apiUrl + '/store/listporgress')
+ if (!completion.ok) {
+ return
+ }
+ let res: any = await completion.json()
+ if (!res || res.length < 1) {
+ res = []
+ }
+ storeList.value.forEach((item: any, index: number) => {
+ const pitem: any = res.find((i: any) => i.name == item.name)
+ //console.log(pitem)
+ if (pitem) {
+ storeList.value[index].isRuning = pitem.running
+ } else {
+ storeList.value[index].isRuning = false
+ }
+ })
+ }
+
+
+ return {
+ currentCateId,
+ categoryIcon,
+ currentTitle,
+ currentCate,
+ categoryList,
+ isready,
+ installedList,
+ storeList,
+ outList,
+ apiUrl,
+ changeCate,
+ getList,
+ addOutList,
+ checkProgress
+ }
+}, {
+ persist: {
+ enabled: true,
+ strategies: [
+ {
+ storage: localStorage,
+ paths: [
+ "outList"
+ ]
+ }, // name 字段用localstorage存储
+ ],
+ }
+})
\ No newline at end of file
diff --git a/frontend/src/stores/upgrade.ts b/frontend/src/stores/upgrade.ts
new file mode 100644
index 0000000..46af8b3
--- /dev/null
+++ b/frontend/src/stores/upgrade.ts
@@ -0,0 +1,88 @@
+import { defineStore } from "pinia";
+import { ref } from "vue";
+import { getSystemKey, setSystemKey, parseJson, getSystemConfig } from '@/system/config'
+import { RestartApp } from '@/util/goutil';
+import { ElMessage } from 'element-plus'
+export const useUpgradeStore = defineStore('upgradeStore', () => {
+ const hasUpgrade = ref(false);
+ const hasNotice = ref(false);
+ const hasAd = ref(false);
+ const updateUrl = ref('');
+ const versionTag = ref(0)
+ const currentVersion = ref(0)
+ const progress = ref(0)
+ const noticeList:any = ref([])
+ const adList:any = ref([])
+ async function checkUpdate() {
+ const config = getSystemConfig();
+ currentVersion.value = config.version;
+ const releaseRes = await fetch(`${config.apiUrl}/system/updateInfo`)
+ if (!releaseRes.ok) return;
+ const releaseData = await releaseRes.json()
+ versionTag.value = releaseData.version
+ if(versionTag.value > config.version){
+ hasUpgrade.value = true
+ updateUrl.value = releaseData.url
+ }
+ if (releaseData.noticeList && releaseData.noticeList.length > 0) {
+ hasNotice.value = true
+ noticeList.value = releaseData.noticeList
+ }
+ if (!hasUpgrade.value && releaseData.adList && releaseData.adList.length > 0) {
+ hasAd.value = true
+ adList.value = releaseData.adList
+ }
+ }
+ async function update() {
+ const apiUrl = getSystemKey('apiUrl')
+ const upUrl = `${apiUrl}/system/update?url=${updateUrl.value}`
+ 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) {
+ progress.value = json.progress
+ }
+ if (json.updateCompleted) {
+ hasUpgrade.value = false
+ progress.value = 0
+ ElMessage({
+ type: 'success',
+ message: "update completed!"
+ })
+ setSystemKey('version', versionTag.value)
+ currentVersion.value = versionTag.value
+ RestartApp()
+ break;
+ }
+ }
+ }
+ }
+ return {
+ hasUpgrade,
+ hasNotice,
+ hasAd,
+ versionTag,
+ updateUrl,
+ noticeList,
+ adList,
+ progress,
+ checkUpdate,
+ update
+ }
+})
\ No newline at end of file
diff --git a/frontend/src/system/applist.ts b/frontend/src/system/applist.ts
index 7734f90..78703ad 100644
--- a/frontend/src/system/applist.ts
+++ b/frontend/src/system/applist.ts
@@ -57,6 +57,19 @@ export const appList = [
isMagnet: true,
isMenuList: true,
},
+ {
+ name: 'process.title',
+ appIcon: "progress",
+ content: "ProcessManager",
+ width: 800,
+ height: 600,
+ frame: true,
+ center: true,
+ resizable: false,
+ isDeskTop: false,
+ isMagnet: true,
+ isMenuList: true,
+ },
{
name: "create.shortcut",
diff --git a/frontend/src/system/index.ts b/frontend/src/system/index.ts
index c3e7d5a..4620f5d 100644
--- a/frontend/src/system/index.ts
+++ b/frontend/src/system/index.ts
@@ -25,7 +25,7 @@ import { Tray, TrayOptions } from './menu/Tary';
import { InitSystemFile, InitUserFile } from './core/SystemFileConfig';
import { createInitFile } from './core/createInitFile';
import { getSystemConfig, getSystemKey, setSystemKey, setSystemConfig, clearSystemConfig } from './config'
-import { checkUpdate } from '@/util/update';
+import { useUpgradeStore } from '@/stores/upgrade';
import { RestartApp } from '@/util/goutil';
export type OsPlugin = (system: System) => void;
@@ -115,7 +115,8 @@ export class System {
if (this._rootState.magnet?.length < 1) {
this.refershAppList()
}
- checkUpdate();
+ const upgradeStore = useUpgradeStore();
+ upgradeStore.checkUpdate()
setTimeout(() => {
if (this._rootState.magnet?.length < 1) {
this.recover()
diff --git a/frontend/src/util/update.ts b/frontend/src/util/update.ts
deleted file mode 100644
index bad3665..0000000
--- a/frontend/src/util/update.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { getSystemConfig,setSystemKey,parseJson } from '@/system/config'
-import { RestartApp } from './goutil';
-import { Dialog } from '@/system';
-import { ElMessage } from 'element-plus'
-export async function checkUpdate() {
- const config = getSystemConfig();
- const updateGiteeUrl = `${config.apiUrl}/system/updateInfo`
- const releaseRes = await fetch(updateGiteeUrl)
- if (!releaseRes.ok) return;
- const releaseData = await releaseRes.json()
- const versionTag = releaseData.version;
- if (!versionTag) return;
- if (versionTag <= config.version) return;
- const updateUrl = releaseData.url
- if (!updateUrl || updateUrl == '') return;
- const dialogRes: any = await Dialog.showMessageBox({
- title: '更新提示',
- message: `发现新版本:${versionTag},是否更新?`
- })
- //console.log(dialogRes)
- if (dialogRes.response !== -1) {
- return;
- }
- 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;
- }
- }
- }
-}
diff --git a/godo/cmd/main.go b/godo/cmd/main.go
index 3fc5307..d5b68f5 100644
--- a/godo/cmd/main.go
+++ b/godo/cmd/main.go
@@ -39,14 +39,16 @@ func OsStart() {
progressRouter.HandleFunc("/stopall", store.StopAll).Methods(http.MethodGet)
progressRouter.HandleFunc("/restart/{name}", store.ReStartProcess).Methods(http.MethodGet)
progressRouter.HandleFunc("/listporgress", store.Status).Methods(http.MethodGet)
- progressRouter.HandleFunc("/listport", store.ListPortsHandler).Methods(http.MethodGet)
- progressRouter.HandleFunc("/killport", store.KillPortHandler).Methods(http.MethodGet)
+ progressRouter.HandleFunc("/listport", store.ListAllProcessesHandler).Methods(http.MethodGet)
+ progressRouter.HandleFunc("/killport", store.KillProcessByNameHandler).Methods(http.MethodGet)
progressRouter.HandleFunc("/storelist", store.GetStoreListHandler).Methods(http.MethodGet)
progressRouter.HandleFunc("/download", store.DownloadHandler).Methods(http.MethodGet)
progressRouter.HandleFunc("/install", store.InstallHandler).Methods(http.MethodGet)
+ progressRouter.HandleFunc("/installInfo", store.GetInstallInfoHandler).Methods(http.MethodGet)
progressRouter.HandleFunc("/installOut", store.RunOutHandler).Methods(http.MethodGet)
progressRouter.HandleFunc("/uninstall", store.UnInstallHandler).Methods(http.MethodGet)
progressRouter.HandleFunc("/setting", store.StoreSettingHandler).Methods(http.MethodPost)
+ progressRouter.HandleFunc("/upload", store.UploadHandler).Methods(http.MethodPost)
router.HandleFunc("/system/updateInfo", sys.GetUpdateUrlHandler).Methods(http.MethodGet)
router.HandleFunc("/system/update", sys.UpdateAppHandler).Methods(http.MethodGet)
diff --git a/godo/libs/msg.go b/godo/libs/msg.go
index 7e19325..683c72b 100644
--- a/godo/libs/msg.go
+++ b/godo/libs/msg.go
@@ -12,7 +12,7 @@ type APIResponse struct {
Error string `json:"error,omitempty"`
}
-func writeJSONResponse(w http.ResponseWriter, res APIResponse, status int) {
+func WriteJSONResponse(w http.ResponseWriter, res APIResponse, status int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(res)
@@ -20,11 +20,11 @@ func writeJSONResponse(w http.ResponseWriter, res APIResponse, status int) {
// HTTPError 返回带有JSON错误消息的HTTP错误
func HTTPError(w http.ResponseWriter, status int, message string) {
- writeJSONResponse(w, APIResponse{Message: message, Code: -1}, status)
+ WriteJSONResponse(w, APIResponse{Message: message, Code: -1}, status)
}
func ErrorMsg(w http.ResponseWriter, message string) {
- writeJSONResponse(w, APIResponse{Message: message, Code: -1}, 200)
+ WriteJSONResponse(w, APIResponse{Message: message, Code: -1}, 200)
}
func SuccessMsg(w http.ResponseWriter, data any, message string) {
- writeJSONResponse(w, APIResponse{Message: message, Data: data, Code: 0}, 200)
+ WriteJSONResponse(w, APIResponse{Message: message, Data: data, Code: 0}, 200)
}
diff --git a/godo/store/install.go b/godo/store/install.go
index 758af35..063c111 100644
--- a/godo/store/install.go
+++ b/godo/store/install.go
@@ -29,6 +29,21 @@ func InstallHandler(w http.ResponseWriter, r *http.Request) {
libs.ErrorMsg(w, "the install.json is error:"+err.Error())
return
}
+ if len(installInfo.Dependencies) > 0 {
+ var needInstalls []Item
+ for _, item := range installInfo.Dependencies {
+ info, err := GetInstallInfo(item.Value.(string))
+ if err != nil {
+ needInstalls = append(needInstalls, item)
+ continue
+ }
+ if info.Version != installInfo.Version {
+ needInstalls = append(needInstalls, item)
+ }
+ }
+ libs.WriteJSONResponse(w, libs.APIResponse{Message: "you need install apps!", Data: needInstalls, Code: -1}, 200)
+ return
+ }
if pluginName != installInfo.Name {
libs.ErrorMsg(w, "the app name must equal the install.json!")
return
@@ -78,7 +93,6 @@ func InstallHandler(w http.ResponseWriter, r *http.Request) {
libs.ErrorMsg(w, "install the app is error!")
return
}
- var res string
//复制static目录
staticPath := filepath.Join(exePath, "static")
if libs.PathExists(staticPath) {
@@ -91,12 +105,12 @@ func InstallHandler(w http.ResponseWriter, r *http.Request) {
}
iconPath := filepath.Join(targetPath, storeInfo.Icon)
if libs.PathExists(iconPath) {
- res = "http://localhost:56780/static/" + pluginName + "/" + storeInfo.Icon
+ installInfo.Icon = "http://localhost:56780/static/" + pluginName + "/" + storeInfo.Icon
}
}
}
- libs.SuccessMsg(w, res, "install the app success!")
+ libs.SuccessMsg(w, installInfo, "install the app success!")
}
func UnInstallHandler(w http.ResponseWriter, r *http.Request) {
diff --git a/godo/store/port.go b/godo/store/port.go
index 565af98..82925c0 100644
--- a/godo/store/port.go
+++ b/godo/store/port.go
@@ -1,24 +1,34 @@
package store
import (
+ "bufio"
+ "bytes"
"encoding/json"
"fmt"
"log"
+ "net"
"net/http"
"os/exec"
+ "regexp"
"runtime"
"strconv"
"strings"
- "sync"
)
-type PortRangeResponse struct {
- Start int `json:"start"`
- End int `json:"end"`
- EnabledPorts []int `json:"enabled_ports"`
+type ProcessSystemInfo struct {
+ PID int `json:"pid"`
+ Port int `json:"port"`
+ Proto string `json:"proto"`
+ Name string `json:"name"`
}
-func getProcessIdsOnPort(port int) ([]string, error) {
+type AllProcessesResponse struct {
+ Processes []ProcessSystemInfo `json:"processes"`
+}
+
+var processInfoRegex = regexp.MustCompile(`(\d+)\s+.*:\s*(\d+)\s+.*LISTEN\s+.*:(\d+)`)
+
+func listAllProcesses() ([]ProcessSystemInfo, error) {
osType := runtime.GOOS
var cmd *exec.Cmd
@@ -27,55 +37,115 @@ func getProcessIdsOnPort(port int) ([]string, error) {
switch osType {
case "darwin", "linux":
- cmd = exec.Command("lsof", "-ti", fmt.Sprintf("tcp:%d", port))
+ cmd = exec.Command("lsof", "-i", "-n", "-P")
case "windows":
- cmd = exec.Command("powershell", "-Command", "Get-Process | Where-Object {$_.Id -eq "+strconv.Itoa(port)+"} | Select-Object -ExpandProperty Id")
+ cmd = exec.Command("netstat", "-ano")
default:
return nil, fmt.Errorf("unsupported operating system")
}
output, err = cmd.CombinedOutput()
if err != nil {
- if exitError, ok := err.(*exec.ExitError); ok {
- // 如果lsof或powershell命令找不到任何进程,它会返回非零退出代码,这是正常情况
- if exitError.ExitCode() != 1 {
- return nil, fmt.Errorf("failed to list processes on port %d: %v", port, err)
+ return nil, fmt.Errorf("failed to list all processes: %v", err)
+ }
+
+ processes := make([]ProcessSystemInfo, 0)
+
+ // 解析输出
+ switch osType {
+ case "darwin", "linux":
+ scanner := bufio.NewScanner(bytes.NewBuffer(output)) // 使用bufio.Scanner
+
+ for scanner.Scan() {
+ line := scanner.Text()
+ matches := processInfoRegex.FindStringSubmatch(line)
+ if matches != nil {
+ pid, _ := strconv.Atoi(matches[1])
+ port, _ := strconv.Atoi(matches[3])
+ processName, err := getProcessName(osType, pid)
+ if err != nil {
+ log.Printf("Failed to get process name for PID %d: %v", pid, err)
+ continue
+ }
+ processes = append(processes, ProcessSystemInfo{
+ PID: pid,
+ Port: port,
+ Proto: matches[2],
+ Name: processName,
+ })
+ }
+ }
+ case "windows":
+ scanner := bufio.NewScanner(bytes.NewBuffer(output))
+ for scanner.Scan() {
+ line := scanner.Text()
+ // 需要针对Windows的netstat输出格式进行解析
+ // 示例:TCP 0.0.0.0:80 0.0.0.0:* LISTENING 1234
+ fields := strings.Fields(line)
+ if len(fields) >= 4 && fields[3] == "LISTENING" {
+ _, port, err := net.SplitHostPort(fields[1])
+ if err != nil {
+ log.Printf("Failed to parse port: %v", err)
+ continue
+ }
+ pid, _ := strconv.Atoi(fields[4])
+ processName, err := getProcessName(osType, pid)
+ if err != nil {
+ log.Printf("Failed to get process name for PID %d: %v", pid, err)
+ continue
+ }
+ portInt, err := strconv.Atoi(port)
+ if err != nil {
+ log.Printf("Failed to convert port to integer: %v", err)
+ continue
+ }
+ processes = append(processes, ProcessSystemInfo{
+ PID: pid,
+ Port: portInt,
+ Proto: fields[0],
+ Name: processName,
+ })
}
- } else {
- return nil, fmt.Errorf("failed to list processes on port %d: %v", port, err)
}
}
- pids := strings.Fields(strings.TrimSpace(string(output)))
- return pids, nil
+ return processes, nil
}
-func listEnabledPorts(portRangeStart, portRangeEnd int) ([]int, error) {
- var usedPorts []int
- var wg sync.WaitGroup
-
- for i := portRangeStart; i <= portRangeEnd; i++ {
- currentPort := i // 创建一个新的变量来绑定当前的i值
- wg.Add(1)
- go func() { // 注意这里不再直接传入port,而是使用currentPort
- defer wg.Done()
-
- pids, err := getProcessIdsOnPort(currentPort)
- if err != nil {
- log.Printf("Error checking port %d: %v", currentPort, err)
- }
- if len(pids) > 0 {
- usedPorts = append(usedPorts, currentPort)
- }
- }()
+func getProcessName(osType string, pid int) (string, error) {
+ var cmd *exec.Cmd
+ var output []byte
+ var err error
+
+ switch osType {
+ case "darwin", "linux":
+ cmd = exec.Command("ps", "-p", strconv.Itoa(pid), "-o", "comm=")
+ case "windows":
+ cmd = exec.Command("tasklist", "/FI", fmt.Sprintf("PID eq %d", pid), "/NH")
+ default:
+ return "", fmt.Errorf("unsupported operating system")
}
- wg.Wait()
+ output, err = cmd.CombinedOutput()
+ if err != nil {
+ return "", fmt.Errorf("failed to get process name: %v", err)
+ }
+ // log.Printf("output: %s", output)
+ switch osType {
+ case "darwin", "linux":
+ return strings.TrimSpace(string(output)), nil
+ case "windows":
+ parts := strings.Fields(string(output))
+ if len(parts) >= 1 {
+ return parts[0], nil
+ }
+ return "", fmt.Errorf("no process name found in output")
+ }
- return usedPorts, nil
+ return "", fmt.Errorf("unknown error getting process name")
}
-func killProcess(pid int) error {
+func killProcessByName(name string) error {
osType := runtime.GOOS
var cmd *exec.Cmd
@@ -83,90 +153,42 @@ func killProcess(pid int) error {
switch osType {
case "darwin", "linux":
- cmd = exec.Command("kill", "-9", strconv.Itoa(pid))
+ cmd = exec.Command("pkill", name)
case "windows":
- cmd = exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid)) // /F 表示强制结束
+ cmd = exec.Command("taskkill", "/IM", name, "/F") // /F 表示强制结束
default:
return fmt.Errorf("unsupported operating system")
}
err = cmd.Run()
if err != nil {
- log.Printf("Failed to kill process with PID %d: %v", pid, err)
+ log.Printf("Failed to kill process with name %s: %v", name, err)
}
return err
}
-func killAllProcessesOnPort(port int, w http.ResponseWriter) {
- pids, err := getProcessIdsOnPort(port)
- if err != nil {
- http.Error(w, "Failed to list processes", http.StatusInternalServerError)
- return
- }
-
- for _, pidStr := range pids {
- if pidStr == "" {
- continue
- }
-
- pidInt, err := strconv.Atoi(pidStr)
- if err != nil {
- log.Printf("Failed to convert PID to integer: %v", err)
- continue
- }
-
- if err := killProcess(pidInt); err != nil {
- log.Printf("Failed to kill process with PID %d: %v", pidInt, err)
- continue
- }
- }
-
- fmt.Fprintf(w, "All processes on port %d have been killed", port)
-}
-func KillPortHandler(w http.ResponseWriter, r *http.Request) {
- portStr := r.URL.Query().Get("port")
- port, err := strconv.Atoi(portStr)
- if err != nil {
- http.Error(w, "Invalid port number", http.StatusBadRequest)
+func KillProcessByNameHandler(w http.ResponseWriter, r *http.Request) {
+ name := r.URL.Query().Get("name")
+ if err := killProcessByName(name); err != nil {
+ http.Error(w, fmt.Sprintf("Failed to kill process: %v", err), http.StatusInternalServerError)
return
}
- killAllProcessesOnPort(port, w)
+ fmt.Fprintf(w, "Process '%s' has been killed", name)
}
-func ListPortsHandler(w http.ResponseWriter, r *http.Request) {
- startStr := r.URL.Query().Get("start")
- endStr := r.URL.Query().Get("end")
- // 设置默认值
- start := 56711
- end := 56730
-
- // 如果参数存在,则尝试转换为整数,否则使用默认值
- if startStr != "" {
- start, _ = strconv.Atoi(startStr)
- }
-
- if endStr != "" {
- end, _ = strconv.Atoi(endStr)
- }
-
- ports, err := listEnabledPorts(start, end)
+func ListAllProcessesHandler(w http.ResponseWriter, r *http.Request) {
+ processes, err := listAllProcesses()
if err != nil {
- http.Error(w, "Failed to list ports", http.StatusInternalServerError)
+ http.Error(w, "Failed to list all processes", http.StatusInternalServerError)
return
}
- // 构造JSON响应结构体
- response := PortRangeResponse{
- Start: start,
- End: end,
- EnabledPorts: ports,
+ response := AllProcessesResponse{
+ Processes: processes,
}
- // 设置响应内容类型为JSON
w.Header().Set("Content-Type", "application/json")
-
- // 编码并写入响应体
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to encode response as JSON", http.StatusInternalServerError)
return
diff --git a/godo/store/store.go b/godo/store/store.go
index d5188c4..11dd50a 100644
--- a/godo/store/store.go
+++ b/godo/store/store.go
@@ -42,6 +42,19 @@ func GetStoreListHandler(w http.ResponseWriter, r *http.Request) {
}
}
+func GetInstallInfoHandler(w http.ResponseWriter, r *http.Request) {
+ name := r.URL.Query().Get("name")
+ if name == "" {
+ libs.ErrorMsg(w, "name is required")
+ return
+ }
+ info, err := GetInstallInfo(name)
+ if err != nil {
+ libs.ErrorMsg(w, err.Error())
+ return
+ }
+ libs.SuccessMsg(w, info, "")
+}
func StoreSettingHandler(w http.ResponseWriter, r *http.Request) {
var req map[string]any
err := json.NewDecoder(r.Body).Decode(&req)
diff --git a/godo/store/types.go b/godo/store/types.go
index bb05c31..604fa5a 100644
--- a/godo/store/types.go
+++ b/godo/store/types.go
@@ -15,6 +15,7 @@ type InstallInfo struct {
CheckProgress bool `json:"checkProgress"` // 标志位,表示是否显示启动和停止。
HasRestart bool `json:"hasRestart"` // 标志位,表示安装后是否需要重启。
Setting bool `json:"setting"` // 标志位,表示是否需要配置。
+ Dependencies []Item `json:"dependencies"` // 依赖项。
}
// StoreInfo 维护了应用程序商店的信息。
diff --git a/godo/store/upload.go b/godo/store/upload.go
new file mode 100644
index 0000000..91abdf9
--- /dev/null
+++ b/godo/store/upload.go
@@ -0,0 +1,66 @@
+package store
+
+import (
+ "godo/files"
+ "godo/libs"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// UploadHandler 处理上传的HTTP请求
+func UploadHandler(w http.ResponseWriter, r *http.Request) {
+
+ // 解析上传的文件
+ err := r.ParseMultipartForm(10000 << 20) // 限制最大上传大小为1000MB
+ if err != nil {
+ http.Error(w, "上传文件过大"+err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ file, header, err := r.FormFile("files") // 表单字段名为"files"
+ if err != nil {
+ http.Error(w, "没有找到文件", http.StatusBadRequest)
+ return
+ }
+ defer file.Close()
+
+ // 读取文件内容
+ fileBytes, err := io.ReadAll(file)
+ if err != nil {
+ log.Printf("读取文件内容出错: %v", err)
+ http.Error(w, "读取文件内容出错", http.StatusInternalServerError)
+ return
+ }
+ cachePath := libs.GetCacheDir()
+ baseName := filepath.Base(header.Filename)
+ filenameNoExt := strings.TrimSuffix(baseName, filepath.Ext(baseName))
+
+ savePath := filepath.Join(cachePath, baseName)
+
+ out, err := os.Create(savePath)
+ if err != nil {
+ log.Printf("创建文件出错: %v", err)
+ http.Error(w, "保存文件出错", http.StatusInternalServerError)
+ return
+ }
+ defer out.Close()
+
+ // 将文件内容写入到服务器上的文件
+ _, err = out.Write(fileBytes)
+ if err != nil {
+ log.Printf("写入文件出错: %v", err)
+ http.Error(w, "写入文件出错", http.StatusInternalServerError)
+ return
+ }
+ runDir := libs.GetRunDir()
+ err = files.HandlerFile(savePath, runDir)
+ if err != nil {
+ log.Printf("Error moving file: %v", err)
+ }
+
+ libs.SuccessMsg(w, filenameNoExt, "File already exists and is of correct size")
+}