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

Стабильный рабочий проект.
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

View File

@@ -0,0 +1,46 @@
package admin
import (
"net/http"
command "vServer/Backend/admin/go/command"
config "vServer/Backend/config"
tools "vServer/Backend/tools"
)
var adminServer *http.Server
// Запуск Admin сервера
func StartAdmin() {
// Получаем значения из конфига во время выполнения
port_admin := config.ConfigData.Soft_Settings.Admin_port
host_admin := config.ConfigData.Soft_Settings.Admin_host
if tools.Port_check("ADMIN", host_admin, port_admin) {
return
}
// Создаем оптимизированный мультиплексор для админ сервера
mux := http.NewServeMux()
// Регистрируем специализированные обработчики (быстрая маршрутизация)
mux.HandleFunc("/api/", command.ApiHandler) // API эндпоинты
mux.HandleFunc("/json/", command.JsonHandler) // JSON данные
mux.HandleFunc("/service/", command.ServiceHandler) // Сервисные команды POST
mux.HandleFunc("/", command.StaticHandler) // Статические файлы
// Создаем Admin сервер (только localhost для безопасности)
adminServer = &http.Server{
Addr: host_admin + ":" + port_admin,
Handler: mux,
}
tools.Logs_file(0, "ADMIN", "🛠️ Admin панель запущена на порту "+port_admin, "logs_http.log", true)
if err := adminServer.ListenAndServe(); err != nil {
// Игнорируем нормальную ошибку при остановке сервера
if err.Error() != "http: Server closed" {
tools.Logs_file(1, "ADMIN", "❌ Ошибка запуска админ сервера: "+err.Error(), "logs_http.log", true)
}
}
}

View File

@@ -0,0 +1,122 @@
package command
import (
"io/fs"
"net/http"
"path/filepath"
"strings"
webserver "vServer/Backend/WebServer"
admin "vServer/Backend/admin"
json "vServer/Backend/admin/go/json"
)
func SecurePost(w http.ResponseWriter, r *http.Request) bool {
// Проверяем, что запрос POST (не GET из браузера)
if webserver.Secure_post {
if r.Method != "POST" {
http.Error(w, "Метод не разрешен. Используйте POST", http.StatusMethodNotAllowed)
return false
}
}
return true
}
// API обработчик для /api/*
func ApiHandler(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
switch path {
case "/api/metrics":
json.GetAllMetrics(w)
default:
http.NotFound(w, r)
}
}
// JSON обработчик для /json/*
func JsonHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
path := r.URL.Path
switch path {
case "/json/server_status.json":
w.Write(json.GetServerStatusJSON())
case "/json/menu.json":
w.Write(json.GetMenuJSON())
default:
http.NotFound(w, r)
}
}
// Обработчик сервисных команд для /service/*
func ServiceHandler(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if !SecurePost(w, r) {
return
}
if SiteList(w, r, path) {
return
}
if site_add(w, path) {
return
}
if Service_Run(w, r, path) {
return
}
http.NotFound(w, r)
}
// Обработчик статических файлов из embed
func StaticHandler(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
// Убираем ведущий слэш
path = strings.TrimPrefix(path, "/")
// Если пустой путь, показываем index.html
if path == "" {
path = "html/index.html"
} else {
path = "html/" + path
}
// Читаем файл из файловой системы (embed или диск)
fileSystem := admin.GetFileSystem()
content, err := fs.ReadFile(fileSystem, path)
if err != nil {
http.NotFound(w, r)
return
}
// Устанавливаем правильный Content-Type
ext := filepath.Ext(path)
switch ext {
case ".css":
w.Header().Set("Content-Type", "text/css")
case ".js":
w.Header().Set("Content-Type", "application/javascript")
case ".json":
w.Header().Set("Content-Type", "application/json")
case ".html":
w.Header().Set("Content-Type", "text/html")
}
// Предотвращаем кеширование в режиме разработки (когда UseEmbedded = false)
if !admin.UseEmbedded {
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
}
// Отдаем файл
w.Write(content)
}

View File

@@ -0,0 +1,57 @@
package command
import (
"net/http"
webserver "vServer/Backend/WebServer"
json "vServer/Backend/admin/go/json"
)
// Обработчик команд управления серверами
func Service_Run(w http.ResponseWriter, r *http.Request, path string) bool {
switch path {
case "/service/MySql_Stop":
webserver.StopMySQLServer()
json.UpdateServerStatus("MySQL Server", "stopped")
return true
case "/service/MySql_Start":
webserver.StartMySQLServer(false)
json.UpdateServerStatus("MySQL Server", "running")
return true
case "/service/Http_Stop":
webserver.StopHTTPServer()
json.UpdateServerStatus("HTTP Server", "stopped")
return true
case "/service/Http_Start":
go webserver.StartHTTP()
json.UpdateServerStatus("HTTP Server", "running")
return true
case "/service/Https_Stop":
webserver.StopHTTPSServer()
json.UpdateServerStatus("HTTPS Server", "stopped")
return true
case "/service/Https_Start":
go webserver.StartHTTPS()
json.UpdateServerStatus("HTTPS Server", "running")
return true
case "/service/Php_Start":
webserver.PHP_Start()
json.UpdateServerStatus("PHP Server", "running")
return true
case "/service/Php_Stop":
webserver.PHP_Stop()
json.UpdateServerStatus("PHP Server", "stopped")
return true
default:
http.NotFound(w, r)
return false // Команда не найдена
}
}

View File

@@ -0,0 +1,269 @@
package command
import (
"encoding/json"
"net/http"
"os"
"regexp"
"strings"
"vServer/Backend/config"
"vServer/Backend/tools"
)
var entries []os.DirEntry
func path_www() {
wwwPath, err := tools.AbsPath("WebServer/www")
tools.Error_check(err, "Ошибка получения пути")
entries, err = os.ReadDir(wwwPath)
tools.Error_check(err, "Ошибка чтения директории")
}
func site_type(entry os.DirEntry) string {
certPath, err := tools.AbsPath("WebServer/cert/" + entry.Name())
if err == nil {
if _, err := os.Stat(certPath); err == nil {
return "https"
}
}
return "http"
}
func site_alliace(siteName string) []string {
// Получаем абсолютный путь к config.json
configPath, err := tools.AbsPath("WebServer/config.json")
tools.Error_check(err, "Ошибка получения пути к config.json")
// Читаем содержимое config.json
configData, err := os.ReadFile(configPath)
tools.Error_check(err, "Ошибка чтения config.json")
// Структура для парсинга Site_www
type SiteConfig struct {
Name string `json:"name"`
Host string `json:"host"`
Alias []string `json:"alias"`
Status string `json:"status"`
}
type Config struct {
SiteWWW []SiteConfig `json:"Site_www"`
}
var config Config
err = json.Unmarshal(configData, &config)
tools.Error_check(err, "Ошибка парсинга config.json")
// Ищем алиасы для конкретного сайта
for _, site := range config.SiteWWW {
if site.Host == siteName {
return site.Alias
}
}
// Возвращаем пустой массив если сайт не найден
return []string{}
}
func site_status(siteName string) string {
configPath := "WebServer/config.json"
// Читаем конфигурационный файл
data, err := os.ReadFile(configPath)
if err != nil {
return "error"
}
// Парсим JSON
var config map[string]interface{}
if err := json.Unmarshal(data, &config); err != nil {
return "error"
}
// Получаем список сайтов
siteWww, ok := config["Site_www"].([]interface{})
if !ok {
return "error"
}
// Ищем сайт по host
for _, siteInterface := range siteWww {
site, ok := siteInterface.(map[string]interface{})
if !ok {
continue
}
// Проверяем только по host (имя папки)
if host, ok := site["host"].(string); ok && host == siteName {
if status, ok := site["status"].(string); ok {
return status
}
}
}
return "inactive"
}
func SiteList(w http.ResponseWriter, r *http.Request, path string) bool {
switch path {
case "/service/Site_List":
sites := []map[string]interface{}{}
path_www()
for _, entry := range entries {
if entry.IsDir() {
site := map[string]interface{}{
"host": entry.Name(),
"type": site_type(entry),
"aliases": site_alliace(entry.Name()),
"status": site_status(entry.Name()),
}
sites = append(sites, site)
}
}
metrics := map[string]interface{}{
"sites": sites,
}
data, _ := json.MarshalIndent(metrics, "", " ")
w.Write(data)
return true
}
return false
}
func addSiteToConfig(siteName string) error {
// Получаем абсолютный путь к config.json
configPath, err := tools.AbsPath("WebServer/config.json")
if err != nil {
return err
}
// Читаем содержимое config.json
configData, err := os.ReadFile(configPath)
if err != nil {
return err
}
// Парсим как общий JSON объект
var config map[string]interface{}
err = json.Unmarshal(configData, &config)
if err != nil {
return err
}
// Получаем массив сайтов
siteWWW, ok := config["Site_www"].([]interface{})
if !ok {
siteWWW = []interface{}{}
}
// Создаем новый сайт в том же формате что уже есть
newSite := map[string]interface{}{
"name": siteName,
"host": siteName,
"alias": []string{""},
"status": "active",
}
// Добавляем новый сайт в массив
config["Site_www"] = append(siteWWW, newSite)
// Сохраняем обновленный конфиг
updatedData, err := json.MarshalIndent(config, "", " ")
if err != nil {
return err
}
// Делаем массивы алиасов в одну строку
re := regexp.MustCompile(`"alias": \[\s+"([^"]*?)"\s+\]`)
compactData := re.ReplaceAll(updatedData, []byte(`"alias": ["$1"]`))
// Исправляем отступы после Site_www
dataStr := string(compactData)
dataStr = strings.ReplaceAll(dataStr, ` ],
"Soft_Settings"`, ` ],
"Soft_Settings"`)
compactData = []byte(dataStr)
err = os.WriteFile(configPath, compactData, 0644)
if err != nil {
return err
}
return nil
}
func site_add(w http.ResponseWriter, path string) bool {
// URL параметры: /service/Site_Add/sitename
if strings.HasPrefix(path, "/service/Site_Add/") {
siteName := strings.TrimPrefix(path, "/service/Site_Add/")
if siteName == "" {
w.WriteHeader(400)
w.Write([]byte(`{"status":"error","message":"Не указано имя сайта в URL"}`))
return true
}
wwwPath := "WebServer/www/" + siteName
// Проверяем существует ли уже такой сайт
if _, err := os.Stat(wwwPath); err == nil {
w.WriteHeader(409) // Conflict
w.Write([]byte(`{"status":"error","message":"Сайт ` + siteName + ` уже существует"}`))
return true
}
err := os.MkdirAll(wwwPath, 0755)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(`{"status":"error","message":"Ошибка создания папки сайта"}`))
return true
}
// Добавляем сайт в config.json
err = addSiteToConfig(siteName)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(`{"status":"error","message":"Ошибка добавления в конфигурацию: ` + err.Error() + `"}`))
return true
}
// Создаем папку public_www
publicWwwPath := wwwPath + "/public_www"
err = os.MkdirAll(publicWwwPath, 0755)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(`{"status":"error","message":"Ошибка создания папки public_www"}`))
return true
}
indexFilePath := wwwPath + "/public_www/index.html"
indexContent := "Привет друг! Твой сайт создан!"
err = os.WriteFile(indexFilePath, []byte(indexContent), 0644)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(`{"status":"error","message":"Ошибка создания index.html: ` + err.Error() + `"}`))
return true
}
w.Write([]byte(`{"status":"ok","message":"Сайт ` + siteName + ` успешно создан и добавлен в конфигурацию"}`))
config.LoadConfig()
return true
}
return false
}

View File

@@ -0,0 +1,45 @@
package json
import "encoding/json"
// Данные серверов
var ServerStatus = []map[string]interface{}{
{"NameService": "HTTP Server", "Port": 80, "Status": "stopped"},
{"NameService": "HTTPS Server", "Port": 443, "Status": "stopped"},
{"NameService": "PHP Server", "Port": 9000, "Status": "stopped"},
{"NameService": "MySQL Server", "Port": 3306, "Status": "stopped"},
}
// Данные меню
var MenuData = []map[string]interface{}{
{"name": "Dashboard", "icon": "🏠", "url": "#dashboard", "active": true},
{"name": "Серверы", "icon": "🖥️", "url": "#servers", "active": false},
{"name": "Сайты", "icon": "🌐", "url": "#sites", "active": false},
{"name": "SSL Сертификаты", "icon": "🔒", "url": "#certificates", "active": false},
{"name": "Файловый менеджер", "icon": "📁", "url": "#files", "active": false},
{"name": "Базы данных", "icon": "🗄️", "url": "#databases", "active": false},
{"name": "Логи", "icon": "📋", "url": "#logs", "active": false},
{"name": "Настройки", "icon": "⚙️", "url": "#settings", "active": false},
}
// Функция обновления статуса сервера
func UpdateServerStatus(serviceName, status string) {
for i := range ServerStatus {
if ServerStatus[i]["NameService"] == serviceName {
ServerStatus[i]["Status"] = status
break
}
}
}
// Получить JSON серверов
func GetServerStatusJSON() []byte {
data, _ := json.Marshal(ServerStatus)
return data
}
// Получить JSON меню
func GetMenuJSON() []byte {
data, _ := json.Marshal(MenuData)
return data
}

View File

@@ -0,0 +1,130 @@
package json
import (
"encoding/json"
"net/http"
"strings"
"time"
"vServer/Backend/tools"
)
var CPU_NAME string
var CPU_GHz string
var CPU_Cores string
var CPU_Using string
var Disk_Size string
var Disk_Free string
var Disk_Used string
var Disk_Name string
var RAM_Using string
var RAM_Total string
// Инициализация при запуске пакета
func init() {
// Загружаем статичные данные один раз при старте
UpdateMetrics()
// Загружаем динамические данные в фоне
go updateMetricsBackground()
}
func UpdateMetrics() {
commands := []string{
`$name = (Get-WmiObject Win32_DiskDrive | Where-Object { $_.Index -eq (Get-WmiObject Win32_DiskPartition | Where-Object { $_.DeviceID -eq ((Get-WmiObject Win32_LogicalDiskToPartition | Where-Object { $_.Dependent -match "C:" }).Antecedent -split '"')[1] }).DiskIndex }).Model`,
`$size = "{0} GB" -f [math]::Round(((Get-PSDrive -Name C).Used + (Get-PSDrive -Name C).Free) / 1GB)`,
"$cpuInfo = Get-CimInstance Win32_Processor",
"$cpuCores = $cpuInfo.NumberOfCores",
"$cpuName = $cpuInfo.Name",
`$ram_total = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)`,
"Write-Output \"$cpuName|$cpuCores|$name|$size|$ram_total\"",
}
// Выполняем команды и получаем результат
result := tools.RunPersistentScript(commands)
// Парсим результат для статичных данных
parts := strings.Split(result, "|")
if len(parts) >= 4 {
cpuName := strings.TrimSpace(parts[0])
cpuCores := strings.TrimSpace(parts[1])
diskName := strings.TrimSpace(parts[2])
diskSize := strings.TrimSpace(parts[3])
ramTotal := strings.TrimSpace(parts[4])
// Обновляем глобальные переменные
CPU_NAME = cpuName
CPU_Cores = cpuCores
Disk_Name = diskName
Disk_Size = diskSize
RAM_Total = ramTotal
}
}
// Фоновое обновление динамических метрик (внутреннее)
func updateMetricsBackground() {
updateDynamicMetrics := func() {
commands := []string{
"$cpuInfo = Get-CimInstance Win32_Processor",
"$cpuGHz = $cpuInfo.MaxClockSpeed",
"$cpuUsage = $cpuInfo.LoadPercentage",
`$used = "{0} GB" -f [math]::Round(((Get-PSDrive -Name C).Used / 1GB))`,
`$free = "{0} GB" -f [math]::Round(((Get-PSDrive -Name C).Free / 1GB))`,
`$ram_using = [math]::Round((Get-CimInstance Win32_OperatingSystem | % {($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) / 1MB}), 2)`,
"Write-Output \"$cpuGHz|$cpuUsage|$used|$free|$ram_using\"",
}
// Один запуск PowerShell для динамических команд!
result := tools.RunPersistentScript(commands)
// Парсим результат для динамических данных
parts := strings.Split(result, "|")
if len(parts) >= 4 {
cpuGHz := strings.TrimSpace(parts[0])
cpuUsage := strings.TrimSpace(parts[1])
diskUsed := strings.TrimSpace(parts[2])
diskFree := strings.TrimSpace(parts[3])
ramUsing := strings.TrimSpace(parts[4])
// Обновляем глобальные переменные
CPU_GHz = cpuGHz
CPU_Using = cpuUsage
Disk_Used = diskUsed
Disk_Free = diskFree
RAM_Using = ramUsing
}
}
// Выполняем сразу при запуске
updateDynamicMetrics()
// Затем каждые 5 секунд
for range time.NewTicker(5 * time.Second).C {
updateDynamicMetrics()
}
}
// Получить JSON системных метрик
func GetAllMetrics(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json")
w.Write(GetMetricsJSON())
}
// Получить JSON метрик
func GetMetricsJSON() []byte {
metrics := map[string]interface{}{
"cpu_name": CPU_NAME,
"cpu_ghz": CPU_GHz,
"cpu_cores": CPU_Cores,
"cpu_usage": CPU_Using,
"disk_name": Disk_Name,
"disk_size": Disk_Size,
"disk_used": Disk_Used,
"disk_free": Disk_Free,
"ram_using": RAM_Using,
"ram_total": RAM_Total,
"server_uptime": tools.ServerUptime("get"),
}
data, _ := json.Marshal(metrics)
return data
}