Инициализация проекта

Стабильный рабочий проект.
This commit is contained in:
Falknat
2025-10-02 06:02:45 +07:00
commit 7a87617282
47 changed files with 6057 additions and 0 deletions

25
Backend/tools/AbsPatch.go Normal file
View File

@@ -0,0 +1,25 @@
package tools
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// getAbsPath получает абсолютный путь с автоматической проверкой существования для файлов
func AbsPath(path string) (string, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return "", fmt.Errorf("ошибка получения абсолютного пути: %v", err)
}
// Проверяем существование только для файлов (с расширением)
if strings.Contains(filepath.Base(absPath), ".") {
if _, err := os.Stat(absPath); os.IsNotExist(err) {
return "", fmt.Errorf("файл не найден: %s", absPath)
}
}
return absPath, nil
}

View File

@@ -0,0 +1,79 @@
package tools
import (
"fmt"
"net"
"time"
)
// Время запуска сервера
var ServerStartTime time.Time
// isPortInUse проверяет, занят ли указанный порт
func Port_check(service string, host string, port string) bool {
conn, err := net.DialTimeout("tcp", host+":"+port, time.Millisecond*300)
if err != nil {
return false // порт свободен
}
conn.Close()
Logs_file(1, service, "⚠️ Порт "+port+" уже занят, сервис не запущен", "logs_error.log", true)
return true // порт занят
}
// Управление временем работы сервера
func ServerUptime(action string, asSeconds ...bool) interface{} {
switch action {
case "start":
// Инициализация времени запуска
ServerStartTime = time.Now()
return nil
case "get":
// Получить время работы
if ServerStartTime.IsZero() {
if len(asSeconds) > 0 && asSeconds[0] {
return int64(0)
}
return "Сервер не запущен"
}
uptime := time.Since(ServerStartTime)
// Возвращаем секунды
if len(asSeconds) > 0 && asSeconds[0] {
return int64(uptime.Seconds())
}
// Возвращаем читаемый формат
days := int(uptime.Hours()) / 24
hours := int(uptime.Hours()) % 24
minutes := int(uptime.Minutes()) % 60
seconds := int(uptime.Seconds()) % 60
if days > 0 {
return fmt.Sprintf("%dд %dч %dм", days, hours, minutes)
} else if hours > 0 {
return fmt.Sprintf("%dч %dм", hours, minutes)
} else if minutes > 0 {
return fmt.Sprintf("%dм", minutes)
} else {
return fmt.Sprintf("%dс", seconds)
}
default:
return "Неизвестное действие"
}
}
func Error_check(err error, message string) bool {
if err != nil {
fmt.Printf("Ошибка: %v\n", message)
return false
}
return true
}

View File

@@ -0,0 +1,10 @@
package tools
func CheckError(err error) error {
if err != nil {
return err
} else {
return nil
}
}

131
Backend/tools/cmd_go.go Normal file
View File

@@ -0,0 +1,131 @@
//go:build windows
package tools
import (
"bufio"
"fmt"
"os"
"os/exec"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procCreateMutex = kernel32.NewProc("CreateMutexW")
procCloseHandle = kernel32.NewProc("CloseHandle")
)
const ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
var mutexHandle syscall.Handle
func init() {
enableVirtualTerminal()
}
func enableVirtualTerminal() {
handle := os.Stdout.Fd()
var mode uint32
// Получаем текущий режим консоли
_, _, _ = procGetConsoleMode.Call(uintptr(handle), uintptr(unsafe.Pointer(&mode)))
// Добавляем флаг поддержки ANSI
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
// Устанавливаем новый режим
_, _, _ = procSetConsoleMode.Call(uintptr(handle), uintptr(mode))
}
func RunBatScript(script string) (string, error) {
// Создание временного файла
tmpFile, err := os.CreateTemp("", "script-*.bat")
if err != nil {
return "", fmt.Errorf("ошибка создания temp-файла: %w", err)
}
defer os.Remove(tmpFile.Name())
// Запись скрипта в файл
if _, err := tmpFile.WriteString(script); err != nil {
return "", fmt.Errorf("ошибка записи в temp-файл: %w", err)
}
tmpFile.Close()
// Выполняем файл через cmd
cmd := exec.Command("cmd", "/C", tmpFile.Name())
output, err := cmd.CombinedOutput()
return string(output), err
}
// Функция для логирования вывода процесса в консоль
func Logs_console(process *exec.Cmd, check bool) error {
if check {
// Настраиваем pipes для захвата вывода
stdout, err := process.StdoutPipe()
CheckError(err)
stderr, err := process.StderrPipe()
CheckError(err)
// Запускаем процесс
process.Start()
// Захватываем stdout и stderr для вывода логов
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}()
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}()
} else {
// Просто запускаем процесс без логирования
return process.Start()
}
return nil
}
// CheckSingleInstance проверяет, не запущена ли программа уже через мьютекс
func CheckSingleInstance() bool {
mutexName, _ := syscall.UTF16PtrFromString("Global\\vServer_SingleInstance")
handle, _, err := procCreateMutex.Call(
0,
0,
uintptr(unsafe.Pointer(mutexName)),
)
if handle == 0 {
return false // не удалось создать мьютекс
}
mutexHandle = syscall.Handle(handle)
// Если GetLastError возвращает ERROR_ALREADY_EXISTS (183), значит мьютекс уже существует
if err.(syscall.Errno) == 183 {
return false // программа уже запущена
}
return true // успешно создали мьютекс, программа не запущена
}
// ReleaseMutex освобождает мьютекс при завершении программы
func ReleaseMutex() {
if mutexHandle != 0 {
procCloseHandle.Call(uintptr(mutexHandle))
mutexHandle = 0
}
}

88
Backend/tools/message.go Normal file
View File

@@ -0,0 +1,88 @@
package tools
import (
"fmt"
"log"
"os"
"regexp"
"time"
)
const (
Красный = "\033[31m"
Зелёный = "\033[32m"
Жёлтый = "\033[33m"
Синий = "\033[34m"
Голубой = "\033[36m"
Фиолетовый = "\033[35m"
Белый = "\033[37m"
Серый = "\033[90m"
Оранжевый = "\033[38;5;208m"
Сброс_Цвета = "\033[0m"
)
// Функция окрашивания текста
func Color(text, ansi string) string {
return ansi + text + Сброс_Цвета
}
// Функция для удаления ANSI-кодов из строки
func RemoveAnsiCodes(text string) string {
// Регулярное выражение для удаления ANSI escape sequences
ansiRegex := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
return ansiRegex.ReplaceAllString(text, "")
}
// Логирование в файл
/*
type_log:
0 - INFO
1 - ERROR
2 - WARNING
*/
func Logs_file(type_log int, service string, message string, log_file string, console bool) {
color_data := ""
service_str := Color(" ["+service+"] ", Жёлтый)
type_log_str := Color(" [INFO] ", Голубой)
log_files := log_file
switch type_log {
case 0:
type_log_str = Color(" [-INFOS-]", Голубой)
case 1:
type_log_str = Color(" [-ERROR-]", Красный)
case 2:
type_log_str = Color(" [WARNING]", Жёлтый)
}
if type_log == 1 {
color_data = Красный
} else {
color_data = Зелёный
}
if console {
// Очищаем текущую строку (стираем промпт >) и выводим лог с новой строки
fmt.Print("\r\033[K")
fmt.Println(Color(time.Now().Format("2006-01-02 15:04:05")+type_log_str+service_str+message, color_data))
}
// Создаем текст с цветами, затем удаляем ANSI-коды для файла
colored_text := time.Now().Format("2006-01-02 15:04:05") + type_log_str + service_str + message
text := RemoveAnsiCodes(colored_text) + "\n"
// Открываем файл для дозаписи, создаём если нет, права на запись.
file, err := os.OpenFile("WebServer/tools/logs/"+log_files, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Пишем строку в файл
if _, err := file.WriteString(text); err != nil {
log.Fatal(err)
}
}

View File

@@ -0,0 +1,72 @@
package tools
import (
"bufio"
"os/exec"
"strings"
"sync"
)
// Глобальная persistent PowerShell сессия
var (
psCmd *exec.Cmd
psStdin *bufio.Writer
psStdout *bufio.Scanner
psMutex sync.Mutex
)
// RunPersistentScript выполняет команды через постоянную PowerShell сессию
func RunPersistentScript(commands []string) string {
psMutex.Lock()
defer psMutex.Unlock()
// Инициализируем если еще не запущен
if psCmd == nil {
psCmd = exec.Command("powershell", "-NoExit", "-Command", "-")
stdin, _ := psCmd.StdinPipe()
stdout, _ := psCmd.StdoutPipe()
psStdin = bufio.NewWriter(stdin)
psStdout = bufio.NewScanner(stdout)
psCmd.Start()
}
// Выполняем команды
fullCommand := strings.Join(commands, "; ")
psStdin.WriteString(fullCommand + "; Write-Output '---END---'\n")
psStdin.Flush()
// Читаем результат - только последняя строка с данными
var lastLine string
for psStdout.Scan() {
line := psStdout.Text()
if line == "---END---" {
break
}
if strings.TrimSpace(line) != "" {
lastLine = line
}
}
return lastLine
}
// RunPowerShellCommand выполняет PowerShell команду и возвращает результат
// Если ошибка - возвращает текст ошибки в строке
func RunPScode(command string) string {
cmd := exec.Command("powershell", "-Command", command)
output, err := cmd.Output()
if err != nil {
return "ERROR: " + err.Error()
}
return strings.TrimSpace(string(output))
}
// RunPowerShellScript выполняет несколько команд PowerShell
func RunPowerShellScript(commands []string) string {
// Объединяем команды через точку с запятой
fullCommand := strings.Join(commands, "; ")
return RunPScode(fullCommand)
}