feat(call): integrate call handling and WebSocket support
All checks were successful
Build Backend / build (push) Successful in 13m26s
Build Backend / build-docker (push) Successful in 1m22s

- Added CallHandler and related services for managing call sessions and participants.
- Enhanced WSHandler to support call signaling, including invite, answer, reject, and end functionalities.
- Updated router to include call-related routes for history and ICE server retrieval.
- Introduced WebRTC configuration in the application settings for call management.
- Refactored wire generation to include CallService and CallRepository for improved dependency injection.
This commit is contained in:
lafay
2026-03-27 01:54:34 +08:00
parent 9ecb29225a
commit 7e6a65d29d
16 changed files with 1002 additions and 7 deletions

View File

@@ -0,0 +1,156 @@
package repository
import (
"context"
"carrot_bbs/internal/model"
"gorm.io/gorm"
)
// CallRepository 通话仓库接口
type CallRepository interface {
// 通话会话操作
CreateCall(call *model.CallSession) error
GetCallByID(id string) (*model.CallSession, error)
GetCallByIDWithParticipants(id string) (*model.CallSession, error)
UpdateCall(call *model.CallSession) error
GetActiveCallByConversationID(conversationID string) (*model.CallSession, error)
// 通话参与者操作
CreateCallParticipant(participant *model.CallParticipant) error
GetCallParticipant(callID, userID string) (*model.CallParticipant, error)
GetCallParticipants(callID string) ([]model.CallParticipant, error)
UpdateCallParticipant(participant *model.CallParticipant) error
// 通话历史
GetCallHistory(userID string, page, pageSize int) ([]model.CallSession, int64, error)
// 事务操作
CreateCallWithParticipants(ctx context.Context, call *model.CallSession, participants []*model.CallParticipant) error
}
// callRepository 通话仓库实现
type callRepository struct {
db *gorm.DB
}
// NewCallRepository 创建通话仓库
func NewCallRepository(db *gorm.DB) CallRepository {
return &callRepository{db: db}
}
// CreateCall 创建通话会话
func (r *callRepository) CreateCall(call *model.CallSession) error {
return r.db.Create(call).Error
}
// GetCallByID 根据ID获取通话会话
func (r *callRepository) GetCallByID(id string) (*model.CallSession, error) {
var call model.CallSession
err := r.db.First(&call, "id = ?", id).Error
if err != nil {
return nil, err
}
return &call, nil
}
// GetCallByIDWithParticipants 根据ID获取通话会话包含参与者
func (r *callRepository) GetCallByIDWithParticipants(id string) (*model.CallSession, error) {
var call model.CallSession
err := r.db.Preload("Participants").First(&call, "id = ?", id).Error
if err != nil {
return nil, err
}
return &call, nil
}
// UpdateCall 更新通话会话
func (r *callRepository) UpdateCall(call *model.CallSession) error {
return r.db.Save(call).Error
}
// GetActiveCallByConversationID 获取会话中的活跃通话
func (r *callRepository) GetActiveCallByConversationID(conversationID string) (*model.CallSession, error) {
var call model.CallSession
err := r.db.Where("conversation_id = ? AND status IN ?", conversationID, []model.CallStatus{
model.CallStatusCalling,
model.CallStatusConnected,
}).First(&call).Error
if err != nil {
return nil, err
}
return &call, nil
}
// CreateCallParticipant 创建通话参与者
func (r *callRepository) CreateCallParticipant(participant *model.CallParticipant) error {
return r.db.Create(participant).Error
}
// GetCallParticipant 获取通话参与者
func (r *callRepository) GetCallParticipant(callID, userID string) (*model.CallParticipant, error) {
var participant model.CallParticipant
err := r.db.Where("call_id = ? AND user_id = ?", callID, userID).First(&participant).Error
if err != nil {
return nil, err
}
return &participant, nil
}
// GetCallParticipants 获取通话参与者列表
func (r *callRepository) GetCallParticipants(callID string) ([]model.CallParticipant, error) {
var participants []model.CallParticipant
err := r.db.Where("call_id = ?", callID).Find(&participants).Error
if err != nil {
return nil, err
}
return participants, nil
}
// UpdateCallParticipant 更新通话参与者
func (r *callRepository) UpdateCallParticipant(participant *model.CallParticipant) error {
return r.db.Save(participant).Error
}
// GetCallHistory 获取用户通话历史
func (r *callRepository) GetCallHistory(userID string, page, pageSize int) ([]model.CallSession, int64, error) {
var calls []model.CallSession
var total int64
// 子查询获取用户参与的通话ID
subQuery := r.db.Model(&model.CallParticipant{}).
Select("DISTINCT call_id").
Where("user_id = ?", userID)
query := r.db.Model(&model.CallSession{}).
Where("id IN (?)", subQuery).
Order("created_at DESC")
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
if err := query.Preload("Participants").Offset(offset).Limit(pageSize).Find(&calls).Error; err != nil {
return nil, 0, err
}
return calls, total, nil
}
// CreateCallWithParticipants 创建通话会话和参与者(事务)
func (r *callRepository) CreateCallWithParticipants(ctx context.Context, call *model.CallSession, participants []*model.CallParticipant) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Create(call).Error; err != nil {
return err
}
for _, p := range participants {
p.CallID = call.ID
if err := tx.Create(p).Error; err != nil {
return err
}
}
return nil
})
}