Merge pull request 'up some deprecated fixes' (#2) from develop into main
Build / Build (push) Successful in 11s

Reviewed-on: TolaMironcenko/up_go#2
This commit was merged in pull request #2.
This commit is contained in:
wt
2026-03-19 14:55:54 +07:00
8 changed files with 21 additions and 105 deletions
+2 -2
View File
@@ -2,6 +2,7 @@ package api
import (
"encoding/json"
"fmt"
"net/http"
"os"
"up/utils"
@@ -26,7 +27,6 @@ func ExtlinuxRead(w http.ResponseWriter, req *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
// В случае ошибки кодирования уже ничего не сделать,
// можно только залогировать (здесь опущено для краткости)
fmt.Errorf("Encoding error: %v", err)
}
}
-11
View File
@@ -16,7 +16,6 @@ import (
func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
var MOUNT_POINT = os.Getenv("MOUNT_POINT")
var EXTLINUX_FILE = os.Getenv("EXTLINUX_FILE")
// Ограничиваем размер тела, чтобы избежать слишком больших запросов (аналог 4096 в C)
r.Body = http.MaxBytesReader(w, r.Body, 4096)
body, err := io.ReadAll(r.Body)
if err != nil {
@@ -24,7 +23,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
return
}
// Парсим JSON
var requestData struct {
Content string `json:"content"`
}
@@ -35,7 +33,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
return
}
// Проверяем наличие поля content
if requestData.Content == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
@@ -45,14 +42,12 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
timestamp := r.URL.Query().Get("timestamp")
if timestamp != "" {
// Полное URL-декодирование (в C декодировался только %3A, но здесь используем стандартный способ)
decoded, err := url.QueryUnescape(timestamp)
if err == nil {
timestamp = decoded
}
}
// Монтируем устройство
if utils.MountDevice() < 0 {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
@@ -60,11 +55,9 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
return
}
// Формируем полный путь к файлу
filePath := filepath.Join(MOUNT_POINT, EXTLINUX_FILE)
fmt.Println(filePath)
// Открываем файл на запись (создаём/перезаписываем)
f, err := os.Create(filePath)
if err != nil {
w.Header().Set("Content-Type", "application/json")
@@ -74,7 +67,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
}
defer f.Close()
// Записываем содержимое
if _, err := f.WriteString(requestData.Content); err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
@@ -86,7 +78,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
versionPath := filepath.Join(MOUNT_POINT, EXTLINUX_FILE+".version")
vf, err := os.Create(versionPath)
if err == nil {
// Форматируем ISO 8601 в человекочитаемый вид (как в C)
var readableDate string
if len(timestamp) >= 19 {
readableDate = timestamp[:10] + " " + timestamp[11:19] // "YYYY-MM-DD HH:MM:SS"
@@ -99,10 +90,8 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
}
}
// Принудительно сбрасываем файловые буферы на диск (аналог sync())
syscall.Sync()
// Успешный ответ
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"success","message":"extlinux.conf updated"}`))
+1 -8
View File
@@ -8,33 +8,26 @@ import (
"path/filepath"
)
// handleFiledate обрабатывает HTTP-запрос для получения даты файла (версии)
func FileDate(w http.ResponseWriter, r *http.Request) {
var MOUNT_POINT = os.Getenv("MOUNT_POINT")
// Получаем параметр "file" из строки запроса
filename := r.URL.Query().Get("file")
if filename == "" {
http.Error(w, `{"error":"Missing file parameter"}`, http.StatusBadRequest)
return
}
// Формируем путь к файлу версии: <mount_point>/<filename>.version
versionPath := filepath.Join(MOUNT_POINT, filename+".version")
// Пытаемся прочитать первую строку из файла версии
dateStr := ""
f, err := os.Open(versionPath)
if err == nil {
defer f.Close()
scanner := bufio.NewScanner(f)
if scanner.Scan() {
dateStr = scanner.Text() // считываем строку без символа новой строки
dateStr = scanner.Text()
}
// Ошибки сканера игнорируем (как в C)
}
// Если файл не существует или другая ошибка — оставляем dateStr пустой
// Формируем JSON-ответ
response := map[string]interface{}{
"status": "success",
"date": dateStr,
+1 -13
View File
@@ -10,13 +10,8 @@ import (
"time"
)
// MOUNT_POINT должен быть определён (например, как глобальная константа)
// const MOUNT_POINT = "/mnt/mydevice"
// handleReboot обрабатывает HTTP-запрос на перезагрузку системы
func HandleReboot(w http.ResponseWriter, r *http.Request) {
MOUNT_POINT := os.Getenv("MOUNT_POINT")
// Отправляем JSON-ответ (как в C: mg_http_reply)
response := map[string]string{
"status": "success",
"message": "System rebooting...",
@@ -27,26 +22,19 @@ func HandleReboot(w http.ResponseWriter, r *http.Request) {
return
}
// Синхронизируем все файловые системы (аналог sync())
syscall.Sync()
// Размонтируем точку монтирования, если она смонтирована
fmt.Printf("Unmounting %s...\n", MOUNT_POINT)
if err := syscall.Unmount(MOUNT_POINT, 0); err != nil {
// Ошибку не фатализируем, просто логируем
fmt.Printf("Unmount error: %v\n", err)
}
// Повторная синхронизация
syscall.Sync()
// Инициируем мягкую перезагрузку через команду shutdown
fmt.Println("Initiating soft reboot via shutdown...")
// Запускаем shutdown в отдельной горутине с небольшой задержкой,
// чтобы ответ гарантированно ушёл клиенту до завершения сервера
go func() {
time.Sleep(500 * time.Millisecond) // ждём 0.5 секунды
time.Sleep(500 * time.Millisecond)
cmd := exec.Command("shutdown", "-r", "now")
if err := cmd.Run(); err != nil {
fmt.Printf("Reboot failed: %v\n", err)
+7 -15
View File
@@ -3,8 +3,8 @@ package api
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
)
@@ -15,44 +15,38 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
// Thermal zones 0–3
for i := 0; i < 4 && !success; i++ {
tempPath := fmt.Sprintf("/sys/class/thermal/thermal_zone%d/temp", i)
data, err := ioutil.ReadFile(tempPath)
data, err := os.ReadFile(tempPath)
if err != nil {
continue
}
// Читаем тип зоны, если доступен
typePath := fmt.Sprintf("/sys/class/thermal/thermal_zone%d/type", i)
typeData, _ := ioutil.ReadFile(typePath) // ошибку игнорируем
typeData, _ := os.ReadFile(typePath)
zoneType := strings.TrimSpace(string(typeData))
// Парсим температуру
var tempRaw int
if _, err := fmt.Sscanf(string(data), "%d", &tempRaw); err != nil {
continue
}
temp := float64(tempRaw) / 1000.0
// Проверяем, является ли зона CPU/SOC
isCPU := strings.Contains(strings.ToLower(zoneType), "cpu") ||
strings.Contains(strings.ToLower(zoneType), "soc")
temperature = temp
success = true
if isCPU {
break // предпочитаем CPU
break
}
// иначе продолжаем искать CPU
}
// Если thermal не дал результата, пробуем hwmon 0–3
for i := 0; i < 4 && !success; i++ {
tempPath := fmt.Sprintf("/sys/class/hwmon/hwmon%d/temp1_input", i)
data, err := ioutil.ReadFile(tempPath)
data, err := os.ReadFile(tempPath)
if err != nil {
continue
}
// Читаем имя сенсора
namePath := fmt.Sprintf("/sys/class/hwmon/hwmon%d/name", i)
nameData, _ := ioutil.ReadFile(namePath)
nameData, _ := os.ReadFile(namePath)
sensorName := strings.TrimSpace(string(nameData))
var tempRaw int
@@ -72,7 +66,6 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
}
}
// Финальный fallback – просто temp1_input для первых 4 hwmon
if !success {
fallbackPaths := []string{
"/sys/class/hwmon/hwmon0/temp1_input",
@@ -81,7 +74,7 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
"/sys/class/hwmon/hwmon3/temp1_input",
}
for _, path := range fallbackPaths {
data, err := ioutil.ReadFile(path)
data, err := os.ReadFile(path)
if err != nil {
continue
}
@@ -95,7 +88,6 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
}
}
// Формируем JSON-ответ
response := map[string]interface{}{
"success": success,
"temperature": temperature,
+4 -20
View File
@@ -14,7 +14,6 @@ import (
"up/utils"
)
// Глобальное состояние загрузки (аналог g_upload в C)
type UploadState struct {
mu sync.RWMutex
Type string
@@ -25,7 +24,7 @@ type UploadState struct {
var uploadState UploadState
// handleUpload обрабатывает POST /api/upload
// POST /api/upload
func HandleUpload(w http.ResponseWriter, r *http.Request) {
uboot_max_size_int, err := strconv.Atoi(os.Getenv("UBOOT_MAX_SIZE"))
if err != nil {
@@ -40,15 +39,13 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
UBOOT_MAX_SIZE := uboot_max_size_int * 1024 * 1024
MAX_FILE_SIZE := max_file_size_int * 1024 * 1024
MOUNT_POINT := os.Getenv("MOUNT_POINT")
// Ограничиваем размер запроса (максимум UBOOT_MAX_SIZE + запас)
r.Body = http.MaxBytesReader(w, r.Body, int64(MAX_FILE_SIZE)+1024)
if err := r.ParseMultipartForm(32 << 20); err != nil { // 32 MB в памяти
http.Error(w, `{"error":"Failed to parse multipart form"}`, http.StatusBadRequest)
return
}
defer r.MultipartForm.RemoveAll() // очищаем временные файлы
defer r.MultipartForm.RemoveAll()
// Получаем поле "type"
typeVals := r.MultipartForm.Value["type"]
if len(typeVals) == 0 {
http.Error(w, `{"error":"Missing type field"}`, http.StatusBadRequest)
@@ -56,7 +53,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
typ := typeVals[0]
// Получаем файл из поля "file"
files := r.MultipartForm.File["file"]
if len(files) == 0 {
http.Error(w, `{"error":"Missing file field"}`, http.StatusBadRequest)
@@ -64,7 +60,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
fileHeader := files[0]
// Проверка размера файла
maxSize := int64(MAX_FILE_SIZE)
if typ == "uboot_bin" {
maxSize = int64(UBOOT_MAX_SIZE)
@@ -74,7 +69,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
return
}
// Открываем загруженный файл
srcFile, err := fileHeader.Open()
if err != nil {
http.Error(w, `{"error":"Failed to open uploaded file"}`, http.StatusInternalServerError)
@@ -82,13 +76,11 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
defer srcFile.Close()
// Монтируем устройство
if utils.MountDevice() < 0 {
http.Error(w, `{"error":"Failed to mount device"}`, http.StatusInternalServerError)
return
}
// Определяем имя файла назначения
filename := utils.GetTargetFilename(typ)
if filename == "" {
http.Error(w, `{"error":"Invalid upload type"}`, http.StatusBadRequest)
@@ -96,7 +88,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
destPath := filepath.Join(MOUNT_POINT, filename)
// Обновляем состояние загрузки
uploadState.mu.Lock()
uploadState.Type = typ
uploadState.Received = 0
@@ -106,7 +97,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Upload: %s (%d bytes) -> %s\n", typ, fileHeader.Size, destPath)
// Получаем timestamp из query и декодируем
timestamp := r.URL.Query().Get("timestamp")
if timestamp != "" {
decoded, err := url.QueryUnescape(timestamp)
@@ -115,7 +105,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
}
// Специальная обработка для U-Boot
if typ == "uboot_bin" {
data, err := io.ReadAll(srcFile)
if err != nil {
@@ -139,7 +128,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
uploadState.Status = "Complete"
uploadState.mu.Unlock()
} else {
// Обычная запись файла чанками с обновлением прогресса
destFile, err := os.Create(destPath)
if err != nil {
uploadState.mu.Lock()
@@ -150,7 +138,7 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
defer destFile.Close()
buf := make([]byte, 65536) // 64 KB чанки
buf := make([]byte, 65536) // 64 KB chunks
var written int64
for {
n, err := srcFile.Read(buf)
@@ -163,7 +151,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
return
}
written += int64(n)
// Обновляем прогресс
uploadState.mu.Lock()
uploadState.Received = written
uploadState.Progress = int(written * 100 / fileHeader.Size)
@@ -181,19 +168,17 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
}
}
destFile.Sync()
syscall.Sync() // глобальная синхронизация
syscall.Sync()
uploadState.mu.Lock()
uploadState.Progress = 100
uploadState.Status = "Complete"
uploadState.mu.Unlock()
}
// Запись файла версии с timestamp
if timestamp != "" {
versionPath := filepath.Join(MOUNT_POINT, filename+".version")
vf, err := os.Create(versionPath)
if err == nil {
// Форматируем ISO 8601 в читаемый вид (как в C)
var readableDate string
if len(timestamp) >= 19 {
readableDate = timestamp[:10] + " " + timestamp[11:19] // "YYYY-MM-DD HH:MM:SS"
@@ -208,7 +193,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Upload complete: %s\n", destPath)
// Формируем JSON-ответ
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
+2 -7
View File
@@ -3,6 +3,7 @@ package api
import (
"bufio"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
@@ -13,7 +14,6 @@ func MountStatus(w http.ResponseWriter, req *http.Request) {
var DEVICE = os.Getenv("DEVICE")
mounted := false
// Проверяем, смонтировано ли устройство, читая /proc/mounts
f, err := os.Open("/proc/mounts")
if err == nil {
defer f.Close()
@@ -25,10 +25,8 @@ func MountStatus(w http.ResponseWriter, req *http.Request) {
break
}
}
// Ошибки сканера игнорируем (аналогично C‑версии)
}
// Формируем JSON‑ответ
response := map[string]interface{}{
"mounted": mounted,
"mount_point": MOUNT_POINT,
@@ -36,10 +34,7 @@ func MountStatus(w http.ResponseWriter, req *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
// json.NewEncoder автоматически добавляет символ новой строки в конце,
// что соответствует формату "%s\n" в C.
if err := json.NewEncoder(w).Encode(response); err != nil {
// В случае ошибки кодирования уже ничего не сделать,
// можно только залогировать (здесь опущено для краткости)
fmt.Errorf("Encoding error: %v", err)
}
}
+4 -29
View File
@@ -10,15 +10,11 @@ import (
"up/utils/mtd"
)
// Глобальное состояние загрузки (используется для обновления прогресса)
var uploadState struct {
sync.RWMutex
Progress int
// другие поля могут быть здесь
}
// writeUbootToDevices записывает U-Boot в файл, SPI NOR и SD-карту.
// Принимает данные, их длину и путь для сохранения копии в файловой системе.
func WriteUbootToDevices(data []byte, filepath string) error {
UBOOT_MAX_SIZE, err := strconv.Atoi(os.Getenv("UBOOT_MAX_SIZE"))
if err != nil {
@@ -35,12 +31,10 @@ func WriteUbootToDevices(data []byte, filepath string) error {
fmt.Printf("Writing U-Boot to devices (%d bytes)...\n", dataLen)
// Проверка лимита размера
if dataLen > int64(UBOOT_MAX_SIZE*1024*1024) {
return fmt.Errorf("U-Boot image too large for SPI NOR (%d > %d bytes)", dataLen, UBOOT_MAX_SIZE)
}
// --- 1. Сохраняем в файл (копия) ---
f, err := os.Create(filepath)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", filepath, err)
@@ -48,36 +42,29 @@ func WriteUbootToDevices(data []byte, filepath string) error {
var written int64
for written < dataLen {
toWrite := dataLen - written
if toWrite > chunkSize {
toWrite = chunkSize
}
toWrite := min(dataLen-written, chunkSize)
n, err := f.Write(data[written : written+toWrite])
if err != nil {
f.Close()
return fmt.Errorf("failed to write to file: %w", err)
}
written += int64(n)
// Прогресс: 30% за запись в файл
uploadState.Lock()
uploadState.Progress = int(written * 30 / dataLen)
uploadState.Unlock()
}
f.Close()
syscall.Sync() // синхронизация после записи файла
syscall.Sync()
// --- 2. Запись в SPI NOR (/dev/mtd0) ---
fmt.Println("Writing to /dev/mtd0 (SPI NOR)...")
mtdFd, err := os.OpenFile("/dev/mtd0", os.O_RDWR|os.O_SYNC, 0660)
if err == nil {
defer mtdFd.Close()
// Получаем размер MTD-устройства из sysfs
mtdSize, err := mtd.ReadMTDSize(0)
if err != nil {
fmt.Printf("Cannot get MTD size from sysfs, proceeding without erase: %v\n", err)
} else {
// Стираем весь чип
fmt.Printf("Erasing SPI NOR (size %d bytes)...\n", mtdSize)
if err := mtd.EraseMTD(mtdFd, 0, mtdSize); err != nil {
fmt.Printf("Warning: erase failed (continuing anyway): %v\n", err)
@@ -86,20 +73,15 @@ func WriteUbootToDevices(data []byte, filepath string) error {
}
}
// Запись в MTD
written = 0
for written < dataLen {
toWrite := dataLen - written
if toWrite > chunkSize {
toWrite = chunkSize
}
toWrite := min(dataLen-written, chunkSize)
n, err := mtdFd.Write(data[written : written+toWrite])
if err != nil {
fmt.Printf("Error writing to /dev/mtd0: %v\n", err)
break
}
written += int64(n)
// Прогресс: 30–65% за SPI NOR
uploadState.Lock()
uploadState.Progress = 30 + int(written*35/dataLen)
uploadState.Unlock()
@@ -109,29 +91,23 @@ func WriteUbootToDevices(data []byte, filepath string) error {
fmt.Printf("/dev/mtd0 not available: %v (skipping SPI NOR)\n", err)
}
// --- 3. Запись в SD-карту (/dev/mmcblk1) со смещением 8 КБ ---
fmt.Printf("Writing to /dev/mmcblk1 at offset %d (SD card boot area)...\n", MMC_BOOT_OFFSET)
mmcFd, err := os.OpenFile("/dev/mmcblk1", os.O_RDWR|os.O_SYNC, 0660)
if err == nil {
defer mmcFd.Close()
// Устанавливаем смещение
if _, err := mmcFd.Seek(int64(MMC_BOOT_OFFSET), io.SeekStart); err != nil {
fmt.Printf("Failed to seek on /dev/mmcblk1: %v\n", err)
} else {
written = 0
for written < dataLen {
toWrite := dataLen - written
if toWrite > chunkSize {
toWrite = chunkSize
}
toWrite := min(dataLen-written, chunkSize)
n, err := mmcFd.Write(data[written : written+toWrite])
if err != nil {
fmt.Printf("Error writing to /dev/mmcblk1: %v\n", err)
break
}
written += int64(n)
// Прогресс: 65–100% за MMC
uploadState.Lock()
uploadState.Progress = 65 + int(written*35/dataLen)
uploadState.Unlock()
@@ -142,7 +118,6 @@ func WriteUbootToDevices(data []byte, filepath string) error {
fmt.Printf("/dev/mmcblk1 not available: %v (skipping SD card)\n", err)
}
// Финальная синхронизация
syscall.Sync()
uploadState.Lock()