96 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package lora
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"time"
 | |
| 
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport/lora/chirp_stack_proto/client/device_service"
 | |
| 	"github.com/go-openapi/runtime"
 | |
| 	httptransport "github.com/go-openapi/runtime/client"
 | |
| 	"github.com/go-openapi/strfmt"
 | |
| 
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport/lora/chirp_stack_proto/client"
 | |
| )
 | |
| 
 | |
| // ChirpStackTransport 是一个客户端,用于封装与 ChirpStack REST API 的交互。
 | |
| type ChirpStackTransport struct {
 | |
| 	client   *client.ChirpStackRESTAPI
 | |
| 	authInfo runtime.ClientAuthInfoWriter
 | |
| 	config   config.ChirpStackConfig
 | |
| 	logger   *logs.Logger
 | |
| }
 | |
| 
 | |
| // NewChirpStackTransport 创建一个新的通信实例,用于与 ChirpStack 通信。
 | |
| func NewChirpStackTransport(
 | |
| 	config config.ChirpStackConfig,
 | |
| 	logger *logs.Logger,
 | |
| ) *ChirpStackTransport {
 | |
| 	// 使用配置中的服务器地址创建一个 HTTP transport。
 | |
| 	// 它会使用生成的客户端中定义的默认 base path 和 schemes。
 | |
| 	transport := httptransport.New(config.APIHost, client.DefaultBasePath, client.DefaultSchemes)
 | |
| 
 | |
| 	// 使用 transport 和默认的字符串格式化器,创建一个 API 主客户端。
 | |
| 	apiClient := client.New(transport, strfmt.Default)
 | |
| 
 | |
| 	// 使用 API Key 创建认证信息写入器。
 | |
| 	authInfo := httptransport.APIKeyAuth("grpc-metadata-authorization", "header", config.GenerateAPIKey())
 | |
| 
 | |
| 	return &ChirpStackTransport{
 | |
| 		client:   apiClient,
 | |
| 		authInfo: authInfo,
 | |
| 		config:   config,
 | |
| 		logger:   logger,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *ChirpStackTransport) Send(address string, payload []byte) (*transport.SendResult, error) {
 | |
| 	// 1. 构建 API 请求体。
 | |
| 	//    - Confirmed: true 表示确认消息, 设为false将不保证消息送达(但可以节约下行容量)。
 | |
| 	//    - Data: 经过 Base64 编码的数据。
 | |
| 	//    - FPort: LoRaWAN 端口。
 | |
| 	body := device_service.DeviceServiceEnqueueBody{
 | |
| 		QueueItem: &device_service.DeviceServiceEnqueueParamsBodyQueueItem{
 | |
| 			Confirmed: true,
 | |
| 			Data:      payload,
 | |
| 			FPort:     int64(c.config.FPort),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	// 2. 构建 API 请求参数。
 | |
| 	//    - WithTimeout 设置一个合理的请求超时。
 | |
| 	//    - WithQueueItemDevEui 指定目标设备的 EUI。
 | |
| 	//    - WithBody 设置请求体。
 | |
| 	params := device_service.NewDeviceServiceEnqueueParams().
 | |
| 		WithTimeout(time.Duration(c.config.APITimeout) * time.Second).
 | |
| 		WithQueueItemDevEui(address).
 | |
| 		WithBody(body)
 | |
| 
 | |
| 	// 3. 调用生成的客户端方法来发送请求。
 | |
| 	//    c.authInfo 是您在 NewChirpStackTransport 中创建的认证信息。
 | |
| 	resp, err := c.client.DeviceService.DeviceServiceEnqueue(params, c.authInfo)
 | |
| 	if err != nil {
 | |
| 		c.logger.Errorf("设备 %s 调用ChirpStack Enqueue失败: %v", address, err)
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if resp == nil || resp.Payload == nil || resp.Payload.ID == "" {
 | |
| 		// 这是一个需要明确处理的错误情况,因为调用方依赖 MessageID。
 | |
| 		errMsg := "ChirpStack Enqueue 响应未包含 MessageID (ID)"
 | |
| 		c.logger.Errorf(errMsg)
 | |
| 		return nil, errors.New(errMsg)
 | |
| 	}
 | |
| 
 | |
| 	c.logger.Infof("成功将 payload 发送到设备 %s 的队列 (MessageID: %s)", address, resp.Payload.ID)
 | |
| 
 | |
| 	// 将 MessageID 包装在 SendResult 中返回
 | |
| 	result := &transport.SendResult{
 | |
| 		MessageID: resp.Payload.ID,
 | |
| 	}
 | |
| 
 | |
| 	return result, nil
 | |
| 
 | |
| }
 |