spark-server/internal/module/friend/logic/service.go
DESKTOP-L8OUL9F\gfl0034 ce9c7a13aa feat: 互相关注后自动成为好友
一方关注只记关注。双方互关时写入已有双向好友边;取消关注若不再互关只删好友边,不删消息。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 21:51:18 +08:00

79 lines
3.1 KiB
Go

package logic
import (
"context"
"spark-server/internal/module/friend/entity"
msgentity "spark-server/internal/module/message/entity"
userentity "spark-server/internal/module/user/entity"
)
// Repository is friend persistence. Model implements it; do not split this by table.
type Repository interface {
GetRelation(ctx context.Context, userID, friendID int64) (*entity.Relation, error)
ListFriends(ctx context.Context, userID int64, limit int) ([]*entity.Relation, error)
ListFriendIDs(ctx context.Context, userID int64) ([]int64, error)
ListBlockedPeerIDs(ctx context.Context, userID int64) ([]int64, error)
GetRequest(ctx context.Context, id int64) (*entity.Request, error)
GetRequestByPair(ctx context.Context, from, to int64) (*entity.Request, error)
UpsertRequest(ctx context.Context, req *entity.Request) error
ListIncoming(ctx context.Context, toUserID int64, status entity.RequestStatus, limit int) ([]*entity.Request, error)
SetRemark(ctx context.Context, userID, friendID int64, remark string) error
SetPinned(ctx context.Context, userID, friendID int64, pinned bool) error
SetBlocked(ctx context.Context, userID, friendID int64, blocked bool) error
IsBlocked(ctx context.Context, userID, targetID int64) (bool, error)
BlockedEither(ctx context.Context, a, b int64) (bool, error)
CreateReport(ctx context.Context, r *entity.Report) error
AcceptFriend(ctx context.Context, in entity.AcceptParams) error
DeleteFriend(ctx context.Context, a, b int64) error
PutFollow(ctx context.Context, userID, targetID int64) error
DeleteFollow(ctx context.Context, userID, targetID int64) error
HasFollow(ctx context.Context, userID, targetID int64) (bool, error)
PurgeUser(ctx context.Context, userID int64) error
}
// UserFinder resolves accounts by uid / email / spark_id / qrcode ticket.
type UserFinder interface {
Get(ctx context.Context, id int64) (*userentity.User, error)
GetByEmail(ctx context.Context, email string) (*userentity.User, error)
GetBySparkID(ctx context.Context, sparkID string) (*userentity.User, error)
GetByQRCode(ctx context.Context, qrcode string) (*userentity.User, error)
}
// IDGen issues Snowflake ids for requests, reports, and system messages.
type IDGen interface {
NextID() (int64, error)
}
// Greeter writes the "became friends" system message. Nil skips greeting.
type Greeter interface {
BecameFriends(ctx context.Context, userA, userB int64) error
}
// P2PChats opens (or reuses) the 1:1 conversation for a pair.
type P2PChats interface {
EnsureP2P(ctx context.Context, userA, userB int64) (int64, error)
UpdateLastMsg(ctx context.Context, conversationID, msgID, atMS int64) error
}
// Messages persists a row in messages.
type Messages interface {
Create(ctx context.Context, m *msgentity.Message) error
}
// Service is the friend use-case layer (HTTP and TCP share it).
type Service struct {
repo Repository
users UserFinder
ids IDGen
greeter Greeter
}
func NewService(repo Repository, users UserFinder, ids IDGen, greeter Greeter) *Service {
return &Service{repo: repo, users: users, ids: ids, greeter: greeter}
}
func (s *Service) ready() bool {
return s != nil && s.repo != nil && s.users != nil && s.ids != nil
}