Генератор случаных чисел с отправкой на сервер
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("Программа завершена корректно")
}