2025-03-07 11:02:43 +08:00

229 lines
6.1 KiB
Go

package tstorage
import (
"context"
tstorage "github.com/nakabonne/tstorage"
"github.com/winc-link/hummingbird/internal/dtos"
interfaces "github.com/winc-link/hummingbird/internal/hummingbird/core/interface"
"github.com/winc-link/hummingbird/internal/models"
"github.com/winc-link/hummingbird/internal/pkg/constants"
"github.com/winc-link/hummingbird/internal/pkg/logger"
"github.com/winc-link/hummingbird/internal/pkg/utils"
"os"
"path/filepath"
"time"
)
type Client struct {
client tstorage.Storage
loggingClient logger.LoggingClient
}
func (c *Client) GetDataDBType() constants.DataType {
return constants.Tstorage
}
func (c *Client) CloseSession() {
c.client.Close()
}
func (c *Client) Insert(ctx context.Context, table string, data map[string]interface{}) (err error) {
metric := table
var rows []tstorage.Row
timestamp := time.Now().UnixMilli()
for code, value := range data {
var labels []tstorage.Label
labels = append(labels, tstorage.Label{
Name: "code", Value: code,
})
rows = append(rows, tstorage.Row{
Metric: metric,
Labels: labels,
DataPoint: tstorage.DataPoint{
Timestamp: timestamp,
Value: utils.ConvertToFloat64(value),
},
})
}
return c.client.InsertRows(rows)
}
func paginate(arr []*tstorage.DataPoint, page, pageSize int) []*tstorage.DataPoint {
arr = reverseArray(arr)
// 计算起始索引
start := (page - 1) * pageSize
end := start + pageSize
// 边界检查
if start >= len(arr) {
return []*tstorage.DataPoint{}
}
if end > len(arr) {
end = len(arr) // 不能超出数组范围
}
return arr[start:end]
}
// reverseArray 翻转数组
func reverseArray(arr []*tstorage.DataPoint) []*tstorage.DataPoint {
n := len(arr)
reversed := make([]*tstorage.DataPoint, n)
for i, v := range arr {
reversed[n-1-i] = v
}
return reversed
}
func (c *Client) GetDeviceProperty(req dtos.ThingModelPropertyDataRequest, device models.Device) ([]dtos.ReportData, int, error) {
var response []dtos.ReportData
var count int
if len(req.Range) == 2 {
var startTime, endTime int64
if req.Range[0] < req.Range[1] {
startTime = req.Range[0]
endTime = req.Range[1]
} else {
startTime = req.Range[1]
endTime = req.Range[0]
}
var labels []tstorage.Label
labels = append(labels, tstorage.Label{
Name: "code", Value: req.Code,
})
points, err := c.client.Select(constants.DB_PREFIX+device.Id, labels, startTime, endTime)
if err != nil {
c.loggingClient.Error("tstorage query data:", err)
return []dtos.ReportData{}, count, err
}
count = len(points)
paginateRes := paginate(points, req.Page, req.PageSize)
for _, re := range paginateRes {
response = append(response, dtos.ReportData{
Value: re.Value,
Time: re.Timestamp,
})
}
} else if req.Last {
var labels []tstorage.Label
labels = append(labels, tstorage.Label{
Name: "code", Value: req.Code,
})
var startTime, endTime int64
// 获取当前时间
now := time.Now()
// 计算半小时前的时间
past := now.Add(-30 * time.Minute)
// 转换为毫秒时间戳
endTime = now.UnixMilli()
startTime = past.UnixMilli()
points, err := c.client.Select(constants.DB_PREFIX+device.Id, labels, startTime, endTime)
if err != nil {
c.loggingClient.Error("tstorage query data:", err)
return []dtos.ReportData{}, count, nil
}
dataPoint := points[len(points)-1]
var reportData dtos.ReportData
reportData.Time = dataPoint.Timestamp
reportData.Value = dataPoint.Value
response = append(response, reportData)
}
return response, count, nil
}
func (c *Client) GetDeviceService(req dtos.ThingModelServiceDataRequest, device models.Device, product models.Product) ([]dtos.SaveServiceIssueData, int, error) {
// tstorage 不支持服务查询
var response []dtos.SaveServiceIssueData
var count int
return response, count, nil
}
func (c *Client) GetDeviceEvent(req dtos.ThingModelEventDataRequest, device models.Device, product models.Product) ([]dtos.EventData, int, error) {
// tstorage 不支持事件查询
var response []dtos.EventData
var count int
return response, count, nil
}
func (c *Client) CreateTable(ctx context.Context, stable, table string) (err error) {
return nil
}
func (c *Client) DropTable(ctx context.Context, table string) (err error) {
return nil
}
func (c *Client) CreateStable(ctx context.Context, product models.Product) (err error) {
return nil
}
func (c *Client) DropStable(ctx context.Context, table string) (err error) {
return nil
}
func (c *Client) AddDatabaseField(ctx context.Context, tableName string, specsType constants.SpecsType, code string, name string) (err error) {
return nil
}
func (c *Client) DelDatabaseField(ctx context.Context, tableName, code string) (err error) {
return nil
}
func (c *Client) ModifyDatabaseField(ctx context.Context, tableName string, specsType constants.SpecsType, code string, name string) (err error) {
return nil
}
func (c *Client) GetDevicePropertyCount(request dtos.ThingModelPropertyDataRequest) (int, error) {
//TODO implement me
panic("implement me")
}
func (c *Client) GetDeviceEventCount(req dtos.ThingModelEventDataRequest) (int, error) {
//TODO implement me
panic("implement me")
}
func (c *Client) GetDeviceMsgCountByGiveTime(deviceId string, startTime, endTime int64) (int, error) {
var labels []tstorage.Label
var count int
labels = append(labels, tstorage.Label{})
points, err := c.client.Select(constants.DB_PREFIX+deviceId, labels, startTime, endTime)
if err != nil {
c.loggingClient.Error("tstorage query data:", err)
return count, err
}
count = len(points)
return count, nil
}
func NewClient(config dtos.Configuration, lc logger.LoggingClient) (c interfaces.DataDBClient, errEdgeX error) {
dataSourceDir := filepath.Dir(config.DataSource)
_, fileErr := os.Stat(dataSourceDir)
if fileErr != nil || !os.IsExist(fileErr) {
_ = os.MkdirAll(dataSourceDir, os.ModePerm)
}
storage, err := tstorage.NewStorage(
tstorage.WithTimestampPrecision(tstorage.Milliseconds),
tstorage.WithDataPath(dataSourceDir),
//tstorage.WithRetention(365*24*time.Hour),
)
if err != nil {
return nil, err
}
return &Client{
client: storage,
loggingClient: lc,
}, nil
}