Генератор случаных чисел с отправкой на сервер



    package main

    import (
        "bytes"
        "context"
        "encoding/json"
        "errors"
        "fmt"
        "io"
        "log"
        "math"
        "net/http"
        "os"
        "os/signal"
        "sync"
        "syscall"
        "time"
    )
    
    // Глобальная переменная для управления логами
    var enableLogging = false
    
    // Вспомогательная функция для записи лога
    func logMessage(format string, v ...interface{}) {
        if enableLogging {
            log.Printf(format, v...)
        }
    }
    
    type ChannelData struct {
        Code  int     `json:"code"`
        Value float64 `json:"value"`
    }
    
    type DeviceData struct {
        Channels []ChannelData `json:"channels"`
    }
    
    const (
        apiURL       = "http://welldatapro.ru/api" //
        bufferLimit  = 100                  // Максимальное количество записей в буфере
        sendInterval = 1 * time.Second      // Интервал для отправки данных
        tokenFile    = "token.txt"          // Файл для сохранения токена
        channelsFile = "channels.json"      // Файл для сохранения каналов
    )
    
    var (
        dataBuffer []map[string]interface{}
        bufMutex   sync.Mutex
        authToken  string
        client     = &http.Client{}
        channels   []ChannelData
    )
    
    // Функция для сохранения токена в файл
    func saveToken(token string) error {
        return os.WriteFile(tokenFile, []byte(token), 0644)
    }
    
    // Функция для загрузки токена из файла
    func loadToken() (string, error) {
        data, err := os.ReadFile(tokenFile)
        if err != nil {
            return "", err
        }
        return string(data), nil
    }
    
    // Функция для сохранения каналов в файл
    func saveChannels(channels []ChannelData) error {
        data, err := json.Marshal(channels)
        if err != nil {
            return err
        }
        return os.WriteFile(channelsFile, data, 0644)
    }
    
    // Функция для загрузки каналов из файла
    func loadChannels() ([]ChannelData, error) {
        data, err := os.ReadFile(channelsFile)
        if err != nil {
            return nil, err
        }
        var channels []ChannelData
        if err := json.Unmarshal(data, &channels); err != nil {
            return nil, err
        }
        return channels, nil
    }
    
    // Функция авторизации
    func login(username, password string) (string, error) {
        logMessage("Начинается процесс авторизации для пользователя: %s", username)
    
        payload := map[string]string{
            "login":    username,
            "password": password,
        }
        body, err := json.Marshal(payload)
        if err != nil {
            logMessage("Ошибка маршалинга данных для авторизации: %v", err)
            return "", fmt.Errorf("ошибка маршалинга данных: %w", err)
        }
    
        resp, err := client.Post(fmt.Sprintf("%s/login", apiURL), "application/json", bytes.NewBuffer(body))
        if err != nil {
            logMessage("Ошибка при выполнении запроса авторизации: %v", err)
            return "", fmt.Errorf("ошибка авторизации: %w", err)
        }
        defer resp.Body.Close()
    
        if resp.StatusCode != http.StatusOK {
            logMessage("Авторизация не удалась, код ошибки: %d", resp.StatusCode)
            return "", fmt.Errorf("авторизация не удалась, код ошибки: %d", resp.StatusCode)
        }
    
        var result struct {
            Msg   string `json:"msg"`
            Token string `json:"token"`
        }
        if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
            logMessage("Ошибка декодирования ответа при авторизации: %v", err)
            return "", fmt.Errorf("ошибка декодирования ответа: %w", err)
        }
        logMessage("Ответ сервера: %s", result.Msg)
    
        if result.Msg != "success" || result.Token == "" {
            logMessage("Не удалось получить токен авторизации")
            return "", errors.New("не удалось получить токен")
        }
        logMessage("Авторизация прошла успешно, токен получен: %s", result.Token)
        return result.Token, nil
    }
    
    // Генерация данных
    // Генерация данных
    func generateData(ctx context.Context, tableCode int) {
        logMessage("Запуск генерации данных")
        startTime := time.Now() // Запоминаем время начала генерации данных
    
        for {
            select {
            case <-ctx.Done():
                logMessage("Остановлена генерация данных")
                return
            default:
                // Вычисляем время с начала генерации в секундах
                elapsedTime := time.Since(startTime).Seconds()
    
                // Генерируем данные для каждого канала
                var channelValues []float64
                for _, channel := range channels {
                    // Используем код канала для генерации уникального значения
                    value := 10 * math.Sin(2*math.Pi*float64(channel.Code)*elapsedTime)
                    channelValues = append(channelValues, value)
                }
    
                // Преобразуем данные в нужный формат
                formattedData := map[string]interface{}{
                    "c":     tableCode,
                    "time":  time.Now().Format("02.01.2006 15:04:05"), // Форматируем текущее время
                    "value": channelValues,
                }
    
                bufMutex.Lock()
                if len(dataBuffer) < bufferLimit {
                    dataBuffer = append(dataBuffer, formattedData)
                } else {
                    logMessage("Буфер заполнен, запись отклонена")
                }
                bufMutex.Unlock()
    
                logMessage("Сгенерированы данные: %+v", formattedData)
                time.Sleep(sendInterval)
            }
        }
    }
    
    // Функция для вызова API func_umgd_add_time_params_settings
    func sendParamsSettings() (int, error) {
        logMessage("Начинается процесс отправки параметров")
    
        // Создаем список кодов параметров
        var codes []int
        for _, channel := range channels {
            codes = append(codes, channel.Code)
        }
    
        dataToSend := map[string][]int{
            "code": codes,
        }
    
        payload, err := json.Marshal(dataToSend)
        if err != nil {
            logMessage("Ошибка маршалинга данных для отправки: %v", err)
            return 0, fmt.Errorf("ошибка маршалинга данных: %w", err)
        }
    
        req, err := http.NewRequest("POST", fmt.Sprintf("%s/func_umgd_add_time_params_settings", apiURL), bytes.NewBuffer(payload))
        if err != nil {
            logMessage("Ошибка создания запроса для func_umgd_add_time_params_settings: %v", err)
            return 0, fmt.Errorf("ошибка создания запроса: %w", err)
        }
    
        // Добавляем cookies access_token
        if authToken != "" {
            cookie := &http.Cookie{
                Name:  "access_token",
                Value: authToken,
            }
            req.AddCookie(cookie)
        }
    
        resp, err := client.Do(req)
        if err != nil {
            logMessage("Ошибка выполнения запроса func_umgd_add_time_params_settings: %v", err)
            return 0, fmt.Errorf("ошибка выполнения запроса: %w", err)
        }
        defer resp.Body.Close()
    
        if resp.StatusCode != http.StatusOK {
            logMessage("Ошибка при вызове func_umgd_add_time_params_settings, статус: %d", resp.StatusCode)
            return 0, fmt.Errorf("ошибка при вызове func_umgd_add_time_params_settings, статус: %d", resp.StatusCode)
        }
    
        // Обрабатываем ответ от сервера
        var result struct {
            TableCode int `json:"tableCode"`
        }
        if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
            logMessage("Ошибка декодирования ответа от func_umgd_add_time_params_settings: %v", err)
            return 0, fmt.Errorf("ошибка декодирования ответа: %w", err)
        }
    
        if result.TableCode == 0 {
            logMessage("Не удалось получить tableCode")
            return 0, errors.New("не удалось получить tableCode")
        }
    
        logMessage("Функция func_umgd_add_time_params_settings успешно вызвана, tableCode: %d", result.TableCode)
        return result.TableCode, nil
    }
    
    func sendData(ctx context.Context) {
        logMessage("Запуск потока отправки данных")
    
        for {
            select {
            case <-ctx.Done():
                logMessage("Остановка потока отправки данных")
                return
            default:
                time.Sleep(sendInterval)
    
                bufMutex.Lock()
                if len(dataBuffer) == 0 {
                    logMessage("Буфер пуст, данные не отправлены")
                    bufMutex.Unlock()
                    continue
                }
    
                dataToSend := make([]map[string]interface{}, len(dataBuffer))
                copy(dataToSend, dataBuffer)
                dataBuffer = dataBuffer[:0] // Очищаем исходный буфер
                bufMutex.Unlock()
    
                payload, err := json.Marshal(dataToSend)
                if err != nil {
                    logMessage("Ошибка маршалинга данных для отправки: %v", err)
                    continue
                }
    
                // Логирование текста запроса
                logMessage("Текст запроса: %s", string(payload))
    
                req, err := http.NewRequest("POST", fmt.Sprintf("%s/func_umgd_add_time_data", apiURL), bytes.NewBuffer(payload))
                if err != nil {
                    logMessage("Ошибка создания запроса для отправки данных: %v", err)
                    continue
                }
    
                // Добавляем cookies access_token
                if authToken != "" {
                    cookie := &http.Cookie{
                        Name:  "access_token",
                        Value: authToken,
                    }
                    req.AddCookie(cookie)
                }
    
                req.Header.Set("Content-Type", "application/json")
    
                resp, err := client.Do(req)
                if err != nil {
                    logMessage("Ошибка отправки данных: %v", err)
                    continue
                }
                defer resp.Body.Close()
    
                // Логирование статуса ответа
                logMessage("Статус ответа сервера: %d", resp.StatusCode)
    
                // Чтение тела ответа
                body, err := io.ReadAll(resp.Body)
                if err != nil {
                    logMessage("Ошибка при чтении тела ответа: %v", err)
                    continue
                }
    
                // Логирование текста ответа
                logMessage("Текст ответа сервера: %s", string(body))
    
                // Декодирование ответа
                var result map[string]interface{}
                if err := json.Unmarshal(body, &result); err != nil {
                    logMessage("Ошибка при декодировании ответа сервера: %v", err)
                    continue
                }
    
                if resp.StatusCode != http.StatusOK {
                    logMessage("Ошибка при отправке данных, статус: %d", resp.StatusCode)
                    continue
                }
    
                if msg, ok := result["msg"].(string); ok && msg == "ok" {
                    logMessage("Данные успешно отправлены: %d записей", len(dataToSend))
                } else {
                    logMessage("Ошибка при отправке данных: %v", result)
                }
            }
        }
    }
    
    func main() {
        // Устанавливаем логгер для вывода в консоль
        log.SetOutput(os.Stdout)
    
        logMessage("Программа запущена")
    
        // Попытка загрузить токен из файла
        token, err := loadToken()
        if err == nil && token != "" {
            authToken = token
            logMessage("Токен загружен из файла: %s", authToken)
        } else {
            // Ввод логина и пароля
            var username, password string
            fmt.Print("Введите логин: ")
            fmt.Scanln(&username)
            fmt.Print("Введите пароль: ")
            fmt.Scanln(&password)
    
            // Авторизация
            token, err := login(username, password)
            if err != nil {
                log.Fatalf("Ошибка авторизации: %v", err)
                return
            }
            authToken = token
            logMessage("Успешная авторизация: %s", authToken)
    
            // Сохраняем токен в файл
            if err := saveToken(authToken); err != nil {
                logMessage("Ошибка сохранения токена: %v", err)
            }
        }
    
        // Попытка загрузить каналы из файла
        loadedChannels, err := loadChannels()
        if err == nil && len(loadedChannels) > 0 {
            channels = loadedChannels
            logMessage("Каналы загружены из файла: %+v", channels)
        } else {
            // Ввод количества каналов и их кодов
            var numChannels int
            fmt.Print("Введите количество каналов: ")
            fmt.Scanln(&numChannels)
    
            for i := 0; i < numChannels; i++ {
                var code int
                fmt.Printf("Введите код канала %d: ", i+1)
                fmt.Scanln(&code)
                channels = append(channels, ChannelData{Code: code})
            }
    
            // Сохраняем каналы в файл
            if err := saveChannels(channels); err != nil {
                logMessage("Ошибка сохранения каналов: %v", err)
            }
        }
    
        // Отправляем список "Кодов параметров" и получаем tableCode
        tableCode, err := sendParamsSettings()
        if err != nil {
            log.Fatalf("Ошибка при отправке параметров: %v", err)
        }
    
        ctx, cancel := context.WithCancel(context.Background())
        go generateData(ctx, tableCode)
        go sendData(ctx)
        defer cancel()
    
        // Ожидание завершения программы по сигналу
        signalChan := make(chan os.Signal, 1)
        signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
    
        logMessage("Ожидание сигнала завершения программы")
        <-signalChan
        logMessage("Получен сигнал завершения программы")
    
        logMessage("Программа завершена корректно")
    }