mirror of
https://github.com/gl-inet/glkvm-cloud.git
synced 2026-09-11 21:38:55 +00:00
fix: sync with frontend and fix bugs
- Align API behavior with frontend integration - Fix issues found during joint debugging Signed-off-by: GL.iNet-Yongping.Xie <yongping.xie@gl-inet.com>
This commit is contained in:
@@ -9,13 +9,14 @@ const (
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
ID int64
|
||||
Ddns string
|
||||
Mac string
|
||||
Name string
|
||||
Description string
|
||||
IP string
|
||||
DeviceGroupID *int64 // nil means ungrouped (admin-only visibility)
|
||||
Status Status
|
||||
LastSeenAt *int64
|
||||
ID int64
|
||||
Ddns string
|
||||
Mac string
|
||||
Name string
|
||||
Description string
|
||||
IP string
|
||||
Client string
|
||||
DeviceGroupID *int64 // nil means ungrouped (admin-only visibility)
|
||||
Status Status
|
||||
LastSeenAt *int64
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package dto
|
||||
|
||||
type Device struct {
|
||||
ID int64 `json:"id"`
|
||||
Ddns string `json:"ddns"`
|
||||
ID int64 `json:"id"`
|
||||
Ddns string `json:"ddns"`
|
||||
Status string `json:"status"`
|
||||
ConnectedTime int64 `json:"connectedTime"`
|
||||
UpTime int64 `json:"upTime"`
|
||||
IP string `json:"ip"`
|
||||
Mac string `json:"mac"`
|
||||
Description string `json:"description"`
|
||||
DeviceGroupID *int64 `json:"deviceGroupId"`
|
||||
DeviceGroupName string `json:"deviceGroupName"`
|
||||
Mac string `json:"mac"`
|
||||
Description string `json:"description"`
|
||||
Client string `json:"client"`
|
||||
DeviceGroupID *int64 `json:"deviceGroupId"`
|
||||
DeviceGroupName string `json:"deviceGroupName"`
|
||||
}
|
||||
|
||||
type ListDevicesResp struct {
|
||||
|
||||
@@ -42,7 +42,6 @@ func (h *AuthHandler) Login(c *gin.Context) {
|
||||
if authMethod == "ldap" {
|
||||
ok, errorType := ldap.AuthenticateUserWithError(cfg, req.Username, req.Password, authMethod)
|
||||
if !ok {
|
||||
// Keep behavior consistent with /signin
|
||||
if errorType == "authorization" {
|
||||
dto.Write(c, dto.Err(traceID, dto.CodeForbidden, "User not authorized", nil))
|
||||
} else {
|
||||
@@ -55,8 +54,7 @@ func (h *AuthHandler) Login(c *gin.Context) {
|
||||
} else {
|
||||
u, err := h.userSvc.Authenticate(c.Request.Context(), req.Username, req.Password)
|
||||
if err != nil || u == nil {
|
||||
// do not leak details
|
||||
dto.Write(c, dto.Err(traceID, dto.CodeForbidden, "Permission denied", nil))
|
||||
dto.Write(c, dto.Err(traceID, dto.CodeForbidden, "Authentication failed", nil))
|
||||
return
|
||||
}
|
||||
userID = u.ID
|
||||
|
||||
@@ -3,9 +3,9 @@ package handler
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"rttys/internal/domain/device"
|
||||
"rttys/internal/domain/identity"
|
||||
@@ -118,7 +118,15 @@ func (h *DeviceHandler) ListDevices(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
sort.SliceStable(items, func(i, j int) bool {
|
||||
oi := items[i].Status == device.StatusOnline
|
||||
oj := items[j].Status == device.StatusOnline
|
||||
if oi != oj {
|
||||
return oi
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
out := make([]dto.Device, 0, len(items))
|
||||
for _, d := range items {
|
||||
var groupName string
|
||||
@@ -131,20 +139,15 @@ func (h *DeviceHandler) ListDevices(c *gin.Context) {
|
||||
connectedTime = *d.LastSeenAt
|
||||
}
|
||||
|
||||
var upTime int64
|
||||
if d.LastSeenAt != nil && d.Status == device.StatusOnline && now >= *d.LastSeenAt {
|
||||
upTime = now - *d.LastSeenAt
|
||||
}
|
||||
|
||||
out = append(out, dto.Device{
|
||||
ID: d.ID,
|
||||
Ddns: d.Ddns,
|
||||
Status: string(d.Status),
|
||||
ConnectedTime: connectedTime,
|
||||
UpTime: upTime,
|
||||
IP: d.IP,
|
||||
Mac: d.Mac,
|
||||
Description: d.Description,
|
||||
Client: d.Client,
|
||||
DeviceGroupID: d.DeviceGroupID,
|
||||
DeviceGroupName: groupName,
|
||||
})
|
||||
|
||||
@@ -11,6 +11,11 @@ func SaveOrUpdateDeviceMeta(deviceID, mac, description, ip string) error {
|
||||
return repo.SaveOrUpdate(context.Background(), deviceID, mac, description, ip)
|
||||
}
|
||||
|
||||
func UpdateDeviceClient(deviceID, client string) error {
|
||||
repo := sqlite.MustContainer().DeviceMeta
|
||||
return repo.UpdateClient(context.Background(), deviceID, client)
|
||||
}
|
||||
|
||||
func GetDeviceMetaByDeviceID(deviceID string) (*model.DeviceMeta, error) {
|
||||
repo := sqlite.MustContainer().DeviceMeta
|
||||
return repo.GetByDeviceID(context.Background(), deviceID)
|
||||
|
||||
@@ -489,13 +489,20 @@ func handleDeviceInfoMsg(dev *Device, data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var payload map[string]any
|
||||
var payload struct {
|
||||
Client string `json:"client"`
|
||||
}
|
||||
if err := jsoniter.Unmarshal(data, &payload); err != nil {
|
||||
log.Warn().Msgf("device '%s' client info invalid json: %v", dev.id, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
dev.setClientInfo(data)
|
||||
if payload.Client != "" {
|
||||
if err := legacy.UpdateDeviceClient(dev.id, payload.Client); err != nil {
|
||||
log.Warn().Err(err).Msgf("device '%s' update client info failed", dev.id)
|
||||
}
|
||||
}
|
||||
log.Info().Msgf("device '%s' client info: %s", dev.id, string(data))
|
||||
log.Debug().Msgf("device '%s' client info updated", dev.id)
|
||||
return nil
|
||||
|
||||
@@ -20,6 +20,7 @@ type deviceRow struct {
|
||||
Name string `gorm:"column:name"`
|
||||
Description string `gorm:"column:description"`
|
||||
IP string `gorm:"column:ip"`
|
||||
Client string `gorm:"column:client"`
|
||||
DeviceGroupID *int64 `gorm:"column:device_group_id"` // NULL => nil
|
||||
Status string `gorm:"column:status"`
|
||||
LastSeenAt *int64 `gorm:"column:last_seen_at"` // NULL => nil
|
||||
@@ -45,6 +46,7 @@ func (r *DeviceRepo) ListAll(ctx context.Context) ([]device.Device, error) {
|
||||
Name: row.Name,
|
||||
Description: row.Description,
|
||||
IP: row.IP,
|
||||
Client: row.Client,
|
||||
DeviceGroupID: row.DeviceGroupID,
|
||||
Status: device.Status(row.Status),
|
||||
LastSeenAt: row.LastSeenAt,
|
||||
@@ -76,6 +78,7 @@ func (r *DeviceRepo) ListByDeviceGroupIDs(ctx context.Context, groupIDs []int64)
|
||||
Name: row.Name,
|
||||
Description: row.Description,
|
||||
IP: row.IP,
|
||||
Client: row.Client,
|
||||
DeviceGroupID: row.DeviceGroupID,
|
||||
Status: device.Status(row.Status),
|
||||
LastSeenAt: row.LastSeenAt,
|
||||
|
||||
@@ -38,6 +38,16 @@ func (r *DeviceMetaRepo) SaveOrUpdate(ctx context.Context, deviceID, mac, descri
|
||||
).Error
|
||||
}
|
||||
|
||||
func (r *DeviceMetaRepo) UpdateClient(ctx context.Context, deviceID, client string) error {
|
||||
if r.db == nil {
|
||||
return fmt.Errorf("gorm db is nil")
|
||||
}
|
||||
return r.db.WithContext(ctx).Exec(
|
||||
`UPDATE devices SET client=? WHERE ddns=?`,
|
||||
client, deviceID,
|
||||
).Error
|
||||
}
|
||||
|
||||
func (r *DeviceMetaRepo) GetByDeviceID(ctx context.Context, deviceID string) (*model.DeviceMeta, error) {
|
||||
var meta model.DeviceMeta
|
||||
err := r.db.WithContext(ctx).Where("ddns = ?", deviceID).First(&meta).Error
|
||||
|
||||
@@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS devices (
|
||||
name TEXT NOT NULL DEFAULT '',
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
ip TEXT NOT NULL DEFAULT '',
|
||||
client TEXT NOT NULL DEFAULT '',
|
||||
device_group_id INTEGER NULL,
|
||||
status TEXT NOT NULL DEFAULT 'online' CHECK (status IN ('online','offline','disabled')),
|
||||
last_seen_at INTEGER NULL,
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
gormsqlite "github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
@@ -74,6 +75,22 @@ func InitSchema(ctx context.Context, db *sql.DB, schemaPath string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = db.ExecContext(ctx, string(b))
|
||||
if _, err = db.ExecContext(ctx, string(b)); err != nil {
|
||||
return err
|
||||
}
|
||||
return ensureDeviceClientColumn(ctx, db)
|
||||
}
|
||||
|
||||
func ensureDeviceClientColumn(ctx context.Context, db *sql.DB) error {
|
||||
if db == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := db.ExecContext(ctx, `ALTER TABLE devices ADD COLUMN client TEXT NOT NULL DEFAULT ''`)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(err.Error(), "duplicate column name") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ type DeviceMeta struct {
|
||||
Mac string `gorm:"column:mac"` // Mac is the unique and immutable MAC address of the device.
|
||||
IP string `gorm:"column:ip"` // IP is the current IP address of the device.
|
||||
Description string `gorm:"column:description"` // Description is a human-readable description of the device.
|
||||
Client string `gorm:"column:client"` // Client reported by device (e.g. "rtty-go").
|
||||
}
|
||||
|
||||
// TableName sets the name of the table in the database that this struct binds to.
|
||||
|
||||
Reference in New Issue
Block a user