1. Создай папку `bin` в корне проекта. 2. Напиши логику на Go, которая проверяет наличие `bin/sing-box.exe`. 3. Напиши функцию `runSingBox(configPath string)`, которая запускает `sing-box.exe` как скрытый фоновый процесс (`os/exec`). 4. Реализуй корректное завершение процесса (Kill) при нажатии кнопки "Отключить".
115 lines
2.4 KiB
Go
115 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"fyne.io/fyne/v2/app"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/widget"
|
|
"fyne.io/fyne/v2"
|
|
)
|
|
|
|
var currentProcess *exec.Cmd
|
|
|
|
// checkSingBox checks if sing-box.exe exists in the bin folder
|
|
func checkSingBox() bool {
|
|
singBoxPath := filepath.Join("bin", "sing-box.exe")
|
|
if _, err := os.Stat(singBoxPath); os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// runSingBox starts the sing-box process with the given config path
|
|
func runSingBox(configPath string) error {
|
|
singBoxPath := filepath.Join("bin", "sing-box.exe")
|
|
|
|
if !checkSingBox() {
|
|
return nil
|
|
}
|
|
|
|
cmd := exec.Command(singBoxPath, "run", "-c", configPath)
|
|
|
|
// Make the process run as hidden
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
HideWindow: true,
|
|
}
|
|
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
currentProcess = cmd
|
|
return nil
|
|
}
|
|
|
|
// killCurrentProcess terminates the current sing-box process if running
|
|
func killCurrentProcess() {
|
|
if currentProcess != nil && currentProcess.Process != nil {
|
|
currentProcess.Process.Kill()
|
|
currentProcess = nil
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
myApp := app.New()
|
|
myWindow := myApp.NewWindow("Hamy VPN Client")
|
|
myWindow.Resize(fyne.NewSize(200, 300))
|
|
|
|
var connectButton *widget.Button
|
|
var disconnectButton *widget.Button
|
|
|
|
disconnectButton = widget.NewButton("Отключить", func() {
|
|
killCurrentProcess()
|
|
|
|
statusLabel := widget.NewLabel("Отключено")
|
|
myWindow.SetContent(container.NewVBox(
|
|
connectButton,
|
|
disconnectButton,
|
|
statusLabel,
|
|
))
|
|
})
|
|
|
|
connectButton = widget.NewButton("Подключить", func() {
|
|
// Check if sing-box exists
|
|
if !checkSingBox() {
|
|
errorLabel := widget.NewLabel("Файл bin/sing-box.exe не найден")
|
|
myWindow.SetContent(container.NewVBox(
|
|
connectButton,
|
|
disconnectButton,
|
|
errorLabel,
|
|
))
|
|
return
|
|
}
|
|
|
|
// Run sing-box with a sample config file
|
|
err := runSingBox("config.json") // Replace with actual config path
|
|
if err != nil {
|
|
errorLabel := widget.NewLabel("Ошибка подключения: " + err.Error())
|
|
myWindow.SetContent(container.NewVBox(
|
|
connectButton,
|
|
disconnectButton,
|
|
errorLabel,
|
|
))
|
|
return
|
|
}
|
|
|
|
connectLabel := widget.NewLabel("Подключено")
|
|
myWindow.SetContent(container.NewVBox(
|
|
connectButton,
|
|
disconnectButton,
|
|
connectLabel,
|
|
))
|
|
})
|
|
|
|
myWindow.SetContent(container.NewVBox(
|
|
connectButton,
|
|
disconnectButton,
|
|
))
|
|
|
|
myWindow.ShowAndRun()
|
|
} |