288 lines
6.6 KiB
Go
288 lines
6.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"spektr/internal/config"
|
|
"spektr/internal/discovery"
|
|
grpcclient "spektr/internal/grpc"
|
|
pb "spektr/internal/grpc/pb"
|
|
|
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
)
|
|
|
|
const HardAddr = "192.168.1.10:50051"
|
|
|
|
type App struct {
|
|
ctx context.Context
|
|
mu sync.Mutex
|
|
client *grpcclient.Client
|
|
currentFrequency string
|
|
connectionStatus string
|
|
}
|
|
|
|
func NewApp() *App {
|
|
return &App{
|
|
currentFrequency: "145",
|
|
connectionStatus: "модуль не подключен",
|
|
}
|
|
}
|
|
|
|
func (a *App) startup(ctx context.Context) {
|
|
a.ctx = ctx
|
|
|
|
go func() {
|
|
client, status := connectClient(ctx)
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
a.client = client
|
|
a.connectionStatus = status
|
|
}()
|
|
}
|
|
|
|
func (a *App) Quit() {
|
|
a.mu.Lock()
|
|
client := a.client
|
|
a.client = nil
|
|
a.mu.Unlock()
|
|
|
|
if client != nil {
|
|
_ = client.Close()
|
|
}
|
|
runtime.Quit(a.ctx)
|
|
}
|
|
|
|
type DeviceResponse struct {
|
|
Status string `json:"status"`
|
|
Frequency string `json:"frequency"`
|
|
}
|
|
|
|
func (a *App) CheckConnection() (DeviceResponse, error) {
|
|
log.Println("CheckConnection called")
|
|
start := time.Now()
|
|
log.Println("[TIMING] CheckConnection START")
|
|
resp := DeviceResponse{
|
|
Status: "модуль не подключен",
|
|
Frequency: a.getFrequency(),
|
|
}
|
|
|
|
//клиента вызываю в другом месте теперь
|
|
//client, err := a.getClientOrConnect()
|
|
//if err != nil {
|
|
// return resp, err
|
|
//}
|
|
|
|
//avMsg, err := client.Send(&pb.ClientMessage{
|
|
// RequestId: requestID(),
|
|
// Payload: &pb.ClientMessage_Av{Av: &pb.AvCommand{}},
|
|
//})
|
|
t1 := time.Now()
|
|
avMsg, err := a.sendWithReconnect(func() *pb.ClientMessage {
|
|
return &pb.ClientMessage{
|
|
RequestId: requestID(),
|
|
Payload: &pb.ClientMessage_Av{Av: &pb.AvCommand{}},
|
|
}
|
|
})
|
|
log.Printf("[TIMING] AV request took: %v", time.Since(t1))
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
if errMsg := avMsg.GetError(); errMsg != nil {
|
|
return resp, errors.New(errMsg.GetMessage())
|
|
}
|
|
if av := avMsg.GetAv(); av != nil {
|
|
resp.Status = fmt.Sprintf("HW: %s FW: %s", av.GetHw(), av.GetSw())
|
|
}
|
|
|
|
//freqMsg, err := client.Send(&pb.ClientMessage{
|
|
// RequestId: requestID(),
|
|
// Payload: &pb.ClientMessage_GetFrequency{GetFrequency: &pb.GetFrequencyCommand{}},
|
|
//})
|
|
t2 := time.Now()
|
|
freqMsg, err := a.sendWithReconnect(func() *pb.ClientMessage {
|
|
return &pb.ClientMessage{
|
|
RequestId: requestID(),
|
|
Payload: &pb.ClientMessage_GetFrequency{GetFrequency: &pb.GetFrequencyCommand{}},
|
|
}
|
|
})
|
|
log.Printf("[TIMING] GetFreq request took: %v", time.Since(t2))
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
if errMsg := freqMsg.GetError(); errMsg != nil {
|
|
return resp, errors.New(errMsg.GetMessage())
|
|
}
|
|
if freq := freqMsg.GetGetFrequency(); freq != nil {
|
|
resp.Frequency = strconv.FormatUint(uint64(freq.GetFrequency()), 10)
|
|
a.setFrequency(resp.Frequency)
|
|
}
|
|
|
|
a.mu.Lock()
|
|
a.connectionStatus = resp.Status
|
|
a.mu.Unlock()
|
|
log.Printf("[TIMING] CheckConnection TOTAL: %v", time.Since(start))
|
|
return resp, nil
|
|
}
|
|
|
|
func (a *App) SetFrequency(freq string) (string, error) {
|
|
val, err := strconv.Atoi(freq)
|
|
if err != nil || val < 70 || val > 8545 {
|
|
//return "", errors.New("вводимое значение должно быть целым положительным числом")
|
|
return "", errors.New(`
|
|
- значение может быть только числом
|
|
- диапазон от 70 до 8545
|
|
`)
|
|
}
|
|
|
|
//клиента я вызываю теперь в другом месте
|
|
//client, err := a.getClientOrConnect()
|
|
//if err != nil {
|
|
// return "", err
|
|
//}
|
|
|
|
//resp, err := client.Send(&pb.ClientMessage{
|
|
// RequestId: requestID(),
|
|
// Payload: &pb.ClientMessage_SetFrequency{
|
|
// SetFrequency: &pb.SetFrequencyCommand{Frequency: uint32(val)},
|
|
// },
|
|
//})
|
|
resp, err := a.sendWithReconnect(func() *pb.ClientMessage {
|
|
return &pb.ClientMessage{
|
|
RequestId: requestID(),
|
|
Payload: &pb.ClientMessage_SetFrequency{
|
|
SetFrequency: &pb.SetFrequencyCommand{Frequency: uint32(val)},
|
|
},
|
|
}
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if errMsg := resp.GetError(); errMsg != nil {
|
|
return "", errors.New(errMsg.GetMessage())
|
|
}
|
|
if ack := resp.GetSetFrequency(); ack != nil && !ack.GetOk() {
|
|
return "", errors.New("не удалось установить частоту")
|
|
}
|
|
|
|
freqStr := strconv.Itoa(val)
|
|
a.setFrequency(freqStr)
|
|
return freqStr, nil
|
|
}
|
|
|
|
func (a *App) getClient() *grpcclient.Client {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
return a.client
|
|
}
|
|
|
|
func (a *App) getClientOrConnect() (*grpcclient.Client, error) {
|
|
client := a.getClient()
|
|
if client != nil {
|
|
return client, nil
|
|
}
|
|
|
|
ctx := a.ctx
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
}
|
|
|
|
client, status := connectClient(ctx)
|
|
if client == nil {
|
|
return nil, errors.New(status)
|
|
}
|
|
|
|
a.mu.Lock()
|
|
if a.client == nil {
|
|
a.client = client
|
|
a.connectionStatus = status
|
|
a.mu.Unlock()
|
|
return client, nil
|
|
}
|
|
existing := a.client
|
|
a.mu.Unlock()
|
|
|
|
_ = client.Close()
|
|
return existing, nil
|
|
}
|
|
|
|
func (a *App) dropClient(client *grpcclient.Client) {
|
|
a.mu.Lock()
|
|
if a.client == client {
|
|
a.client = nil
|
|
a.connectionStatus = "модуль не подключен"
|
|
}
|
|
a.mu.Unlock()
|
|
|
|
if client != nil {
|
|
_ = client.Close()
|
|
}
|
|
}
|
|
|
|
func (a *App) sendWithReconnect(build func() *pb.ClientMessage) (*pb.ServerMessage, error) {
|
|
client, err := a.getClientOrConnect()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resp, err := client.Send(build())
|
|
if err == nil {
|
|
return resp, nil
|
|
}
|
|
|
|
// stream умер (часто после рестарта демона) — сбрасываем и пробуем 1 раз заново
|
|
a.dropClient(client)
|
|
|
|
client, err = a.getClientOrConnect()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return client.Send(build())
|
|
}
|
|
|
|
func (a *App) getFrequency() string {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
return a.currentFrequency
|
|
}
|
|
|
|
func (a *App) setFrequency(freq string) {
|
|
a.mu.Lock()
|
|
a.currentFrequency = freq
|
|
a.mu.Unlock()
|
|
}
|
|
|
|
func connectClient(ctx context.Context) (*grpcclient.Client, string) {
|
|
cfg := config.Default()
|
|
addr := cfg.GRPCAdvertiseAddr
|
|
|
|
discoveryCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
|
if discovered, err := discovery.Discover(discoveryCtx, cfg.DiscoveryPort); err == nil && discovered != "" {
|
|
addr = discovered
|
|
}
|
|
cancel()
|
|
|
|
dialCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
defer cancel()
|
|
|
|
//client, err := grpcclient.Dial(dialCtx, addr)
|
|
client, err := grpcclient.Dial(dialCtx, HardAddr)
|
|
if err != nil {
|
|
log.Printf("gRPC connect failed: %v", err)
|
|
return nil, "gRPC-клиент недоступен"
|
|
}
|
|
|
|
log.Printf("connected to gRPC at %s", addr)
|
|
return client, "модуль подключен"
|
|
}
|
|
|
|
func requestID() string {
|
|
return strconv.FormatInt(time.Now().UnixNano(), 10)
|
|
}
|