Files
backend/internal/model/call.go
lan 60654bc0f4
All checks were successful
Build Backend / build (push) Successful in 2m14s
Build Backend / build-docker (push) Successful in 1m15s
feat(call): implement group calling and enhance call management
Introduces group calling capabilities, including group invites and participant
lifecycle management. Enhances the existing call system with support for
media types (voice/video) and improved participant tracking.

- Add `GroupInvite` and `ParticipantJoin/Leave` to `CallService`.
- Implement WebSocket handlers for `call_group_invite` and
  `call_participant_join`.
- Update `CallSession` model to support group IDs, media types, and
  tracking who ended the call.
- Integrate `GroupService` into `CallService` via dependency injection.
- Add error constants for group call limitations and participant capacity.
- Update LiveKit webhook handling to process participant leave events.

Refactor grade synchronization to remove semester-based filtering in favor
of a more flexible user-based approach and improve GPA summary updates.
2026-06-07 00:11:47 +08:00

106 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"time"
"gorm.io/gorm"
)
// CallType 通话类型
type CallType string
const (
CallTypePrivate CallType = "private" // 私聊通话
CallTypeGroup CallType = "group" // 群聊通话
)
// CallStatus 通话状态
type CallStatus string
const (
CallStatusCalling CallStatus = "calling" // 呼叫中
CallStatusConnected CallStatus = "connected" // 已接通
CallStatusEnded CallStatus = "ended" // 已结束
CallStatusRejected CallStatus = "rejected" // 已拒绝
CallStatusMissed CallStatus = "missed" // 未接听
CallStatusCancelled CallStatus = "cancelled" // 已取消
)
// ParticipantStatus 参与者状态
type ParticipantStatus string
const (
ParticipantStatusInvited ParticipantStatus = "invited" // 已邀请
ParticipantStatusJoined ParticipantStatus = "joined" // 已加入
ParticipantStatusLeft ParticipantStatus = "left" // 已离开
ParticipantStatusRejected ParticipantStatus = "rejected" // 已拒绝
)
// CallSession 通话会话
type CallSession struct {
ID string `gorm:"primaryKey;size:20" json:"id"` // 雪花算法ID
ConversationID string `gorm:"not null;size:20;index" json:"conversation_id"` // 会话ID
GroupID *string `gorm:"index" json:"group_id,omitempty"` // 群组ID群聊时使用
CallerID string `gorm:"column:caller_id;type:varchar(50);index;not null" json:"caller_id"` // 发起者ID
CallType CallType `gorm:"type:varchar(20);not null" json:"call_type"` // 通话类型
MediaType string `gorm:"type:varchar(20);default:'voice'" json:"media_type"` // 媒体类型: voice/video
Status CallStatus `gorm:"type:varchar(20);default:'calling'" json:"status"` // 通话状态
EndedBy *string `gorm:"type:varchar(50)" json:"ended_by,omitempty"` // 结束通话的用户ID
StartedAt *time.Time `json:"started_at,omitempty"` // 接通时间
EndedAt *time.Time `json:"ended_at,omitempty"` // 结束时间
Duration int64 `gorm:"default:0" json:"duration"` // 通话时长(秒)
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
// 关联
Participants []CallParticipant `gorm:"foreignKey:CallID" json:"participants,omitempty"`
}
// BeforeCreate 创建前生成雪花算法ID
func (c *CallSession) BeforeCreate(tx *gorm.DB) error {
return SetSnowflakeStringID(&c.ID)
}
func (CallSession) TableName() string {
return "call_sessions"
}
// CallParticipant 通话参与者
type CallParticipant struct {
ID uint `gorm:"primaryKey" json:"id"`
CallID string `gorm:"not null;size:20;index" json:"call_id"` // 通话ID
UserID string `gorm:"column:user_id;type:varchar(50);index;not null" json:"user_id"` // 用户ID
Status ParticipantStatus `gorm:"type:varchar(20);default:'invited'" json:"status"` // 参与状态
JoinedAt *time.Time `json:"joined_at,omitempty"` // 加入时间
LeftAt *time.Time `json:"left_at,omitempty"` // 离开时间
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}
func (CallParticipant) TableName() string {
return "call_participants"
}
// IsPrivate 是否私聊通话
func (c *CallSession) IsPrivate() bool {
return c.CallType == CallTypePrivate
}
// IsGroup 是否群聊通话
func (c *CallSession) IsGroup() bool {
return c.CallType == CallTypeGroup
}
// IsActive 是否活跃通话
func (c *CallSession) IsActive() bool {
return c.Status == CallStatusCalling || c.Status == CallStatusConnected
}
// CalculateDuration 计算通话时长
func (c *CallSession) CalculateDuration() {
if c.StartedAt != nil && c.EndedAt != nil {
c.Duration = int64(c.EndedAt.Sub(*c.StartedAt).Seconds())
}
}