🎨 Update project structure

This commit is contained in:
2024-06-16 23:17:32 +08:00
parent 0695338fa1
commit 45048ea814
103 changed files with 138 additions and 40 deletions

70
pkg/internal/grpc/auth.go Normal file
View File

@ -0,0 +1,70 @@
package grpc
import (
"context"
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
"git.solsynth.dev/hydrogen/passport/pkg/services"
jsoniter "github.com/json-iterator/go"
"github.com/samber/lo"
)
func (v *Server) Authenticate(_ context.Context, in *proto.AuthRequest) (*proto.AuthReply, error) {
ctx, perms, atk, rtk, err := services.Authenticate(in.GetAccessToken(), in.GetRefreshToken(), 0)
if err != nil {
return &proto.AuthReply{
IsValid: false,
}, nil
} else {
user := ctx.Account
rawPerms, _ := jsoniter.Marshal(perms)
userinfo := &proto.Userinfo{
Id: uint64(user.ID),
Name: user.Name,
Nick: user.Nick,
Email: user.GetPrimaryEmail().Content,
Description: &user.Description,
}
if user.Avatar != nil {
userinfo.Avatar = *user.GetAvatar()
}
if user.Banner != nil {
userinfo.Banner = *user.GetBanner()
}
return &proto.AuthReply{
IsValid: true,
AccessToken: &atk,
RefreshToken: &rtk,
Permissions: rawPerms,
TicketId: lo.ToPtr(uint64(ctx.Ticket.ID)),
Userinfo: userinfo,
}, nil
}
}
func (v *Server) CheckPerm(_ context.Context, in *proto.CheckPermRequest) (*proto.CheckPermReply, error) {
claims, err := services.DecodeJwt(in.GetToken())
if err != nil {
return nil, err
}
ctx, err := services.GetAuthContext(claims.ID)
if err != nil {
return nil, err
}
var heldPerms map[string]any
rawHeldPerms, _ := jsoniter.Marshal(ctx.Account.PermNodes)
_ = jsoniter.Unmarshal(rawHeldPerms, &heldPerms)
var value any
_ = jsoniter.Unmarshal(in.GetValue(), &value)
perms := services.FilterPermNodes(heldPerms, ctx.Ticket.Claims)
valid := services.HasPermNode(perms, in.GetKey(), value)
return &proto.CheckPermReply{
IsValid: valid,
}, nil
}

View File

@ -0,0 +1,21 @@
package grpc
import (
pcpb "git.solsynth.dev/hydrogen/paperclip/pkg/grpc/proto"
"github.com/spf13/viper"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
var Attachments pcpb.AttachmentsClient
func ConnectPaperclip() error {
addr := viper.GetString("paperclip.grpc_endpoint")
if conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil {
return err
} else {
Attachments = pcpb.NewAttachmentsClient(conn)
}
return nil
}

View File

@ -0,0 +1,46 @@
package grpc
import (
"context"
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
"git.solsynth.dev/hydrogen/passport/pkg/models"
"git.solsynth.dev/hydrogen/passport/pkg/services"
"github.com/samber/lo"
)
func (v *Server) ListFriendship(_ context.Context, request *proto.FriendshipLookupRequest) (*proto.ListFriendshipResponse, error) {
account, err := services.GetAccount(uint(request.GetAccountId()))
if err != nil {
return nil, err
}
friends, err := services.ListFriend(account, models.FriendshipStatus(request.GetStatus()))
if err != nil {
return nil, err
}
return &proto.ListFriendshipResponse{
Data: lo.Map(friends, func(item models.AccountFriendship, index int) *proto.FriendshipResponse {
return &proto.FriendshipResponse{
AccountId: uint64(item.AccountID),
RelatedId: uint64(item.RelatedID),
Status: uint32(item.Status),
}
}),
}, nil
}
func (v *Server) GetFriendship(ctx context.Context, request *proto.FriendshipTwoSideLookupRequest) (*proto.FriendshipResponse, error) {
friend, err := services.GetFriendWithTwoSides(uint(request.GetAccountId()), uint(request.GetRelatedId()))
if err != nil {
return nil, err
} else if friend.Status != models.FriendshipStatus(request.GetStatus()) {
return nil, fmt.Errorf("status mismatch")
}
return &proto.FriendshipResponse{
AccountId: uint64(friend.AccountID),
RelatedId: uint64(friend.RelatedID),
Status: uint32(friend.Status),
}, nil
}

View File

@ -0,0 +1,57 @@
package grpc
import (
"context"
jsoniter "github.com/json-iterator/go"
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
"git.solsynth.dev/hydrogen/passport/pkg/models"
"git.solsynth.dev/hydrogen/passport/pkg/services"
"github.com/samber/lo"
)
func (v *Server) NotifyUser(_ context.Context, in *proto.NotifyRequest) (*proto.NotifyReply, error) {
client, err := services.GetThirdClientWithSecret(in.GetClientId(), in.GetClientSecret())
if err != nil {
return nil, err
}
var user models.Account
if user, err = services.GetAccount(uint(in.GetRecipientId())); err != nil {
return nil, err
}
var metadata map[string]any
_ = jsoniter.Unmarshal(in.GetMetadata(), &metadata)
links := lo.Map(in.GetLinks(), func(item *proto.NotifyLink, index int) models.NotificationLink {
return models.NotificationLink{
Label: item.Label,
Url: item.Url,
}
})
notification := models.Notification{
Type: lo.Ternary(len(in.GetType()) > 0, in.GetType(), "common"),
Subject: in.GetSubject(),
Content: in.GetContent(),
Metadata: metadata,
Links: links,
IsRealtime: in.GetIsRealtime(),
IsForcePush: in.GetIsForcePush(),
RecipientID: user.ID,
SenderID: &client.ID,
}
if in.GetIsRealtime() {
if err := services.PushNotification(notification); err != nil {
return nil, err
}
} else {
if err := services.NewNotification(notification); err != nil {
return nil, err
}
}
return &proto.NotifyReply{IsSent: true}, nil
}

151
pkg/internal/grpc/realms.go Normal file
View File

@ -0,0 +1,151 @@
package grpc
import (
"context"
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/database"
"git.solsynth.dev/hydrogen/passport/pkg/models"
"git.solsynth.dev/hydrogen/passport/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/services"
"github.com/samber/lo"
"google.golang.org/protobuf/types/known/emptypb"
)
func (v *Server) ListCommunityRealm(ctx context.Context, empty *emptypb.Empty) (*proto.ListRealmResponse, error) {
realms, err := services.ListCommunityRealm()
if err != nil {
return nil, err
}
return &proto.ListRealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
return &proto.RealmResponse{
Id: uint64(item.ID),
Alias: item.Alias,
Name: item.Name,
Description: item.Description,
IsPublic: item.IsPublic,
IsCommunity: item.IsCommunity,
}
}),
}, nil
}
func (v *Server) ListAvailableRealm(ctx context.Context, request *proto.RealmLookupWithUserRequest) (*proto.ListRealmResponse, error) {
account, err := services.GetAccount(uint(request.GetUserId()))
if err != nil {
return nil, fmt.Errorf("unable to find target account: %v", err)
}
realms, err := services.ListAvailableRealm(account)
if err != nil {
return nil, err
}
return &proto.ListRealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
return &proto.RealmResponse{
Id: uint64(item.ID),
Alias: item.Alias,
Name: item.Name,
Description: item.Description,
IsPublic: item.IsPublic,
IsCommunity: item.IsCommunity,
}
}),
}, nil
}
func (v *Server) ListOwnedRealm(ctx context.Context, request *proto.RealmLookupWithUserRequest) (*proto.ListRealmResponse, error) {
account, err := services.GetAccount(uint(request.GetUserId()))
if err != nil {
return nil, fmt.Errorf("unable to find target account: %v", err)
}
realms, err := services.ListOwnedRealm(account)
if err != nil {
return nil, err
}
return &proto.ListRealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
return &proto.RealmResponse{
Id: uint64(item.ID),
Alias: item.Alias,
Name: item.Name,
Description: item.Description,
IsPublic: item.IsPublic,
IsCommunity: item.IsCommunity,
}
}),
}, nil
}
func (v *Server) GetRealm(ctx context.Context, request *proto.RealmLookupRequest) (*proto.RealmResponse, error) {
var realm models.Realm
tx := database.C.Model(&models.Realm{})
if request.Id != nil {
tx = tx.Where("id = ?", request.GetId())
}
if request.Alias != nil {
tx = tx.Where("alias = ?", request.GetAlias())
}
if request.IsPublic != nil {
tx = tx.Where("is_public = ?", request.GetIsPublic())
}
if request.IsCommunity != nil {
tx = tx.Where("is_community = ?", request.GetIsCommunity())
}
if err := tx.First(&realm).Error; err != nil {
return nil, err
}
return &proto.RealmResponse{
Id: uint64(realm.ID),
Alias: realm.Alias,
Name: realm.Name,
Description: realm.Description,
IsPublic: realm.IsPublic,
IsCommunity: realm.IsCommunity,
}, nil
}
func (v *Server) ListRealmMember(ctx context.Context, request *proto.RealmMemberLookupRequest) (*proto.ListRealmMemberResponse, error) {
var members []models.RealmMember
tx := database.C.Where("realm_id = ?", request.GetRealmId())
if request.UserId != nil {
tx = tx.Where("account_id = ?", request.GetUserId())
}
if err := tx.Find(&members).Error; err != nil {
return nil, err
}
return &proto.ListRealmMemberResponse{
Data: lo.Map(members, func(item models.RealmMember, index int) *proto.RealmMemberResponse {
return &proto.RealmMemberResponse{
RealmId: uint64(item.RealmID),
UserId: uint64(item.AccountID),
PowerLevel: int32(item.PowerLevel),
}
}),
}, nil
}
func (v *Server) GetRealmMember(ctx context.Context, request *proto.RealmMemberLookupRequest) (*proto.RealmMemberResponse, error) {
var member models.RealmMember
tx := database.C.Where("realm_id = ?", request.GetRealmId())
if request.UserId != nil {
tx = tx.Where("account_id = ?", request.GetUserId())
}
if err := tx.First(&member).Error; err != nil {
return nil, err
}
return &proto.RealmMemberResponse{
RealmId: uint64(member.RealmID),
UserId: uint64(member.AccountID),
PowerLevel: int32(member.PowerLevel),
}, nil
}

View File

@ -0,0 +1,35 @@
package grpc
import (
"net"
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
"github.com/spf13/viper"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
type Server struct {
proto.UnimplementedAuthServer
proto.UnimplementedNotifyServer
proto.UnimplementedFriendshipsServer
proto.UnimplementedRealmsServer
}
func StartGrpc() error {
listen, err := net.Listen("tcp", viper.GetString("grpc_bind"))
if err != nil {
return err
}
server := grpc.NewServer()
proto.RegisterAuthServer(server, &Server{})
proto.RegisterNotifyServer(server, &Server{})
proto.RegisterFriendshipsServer(server, &Server{})
proto.RegisterRealmsServer(server, &Server{})
reflection.Register(server)
return server.Serve(listen)
}