♻️ All parts into nexus

This commit is contained in:
2024-10-27 00:06:23 +08:00
parent 4c44af74b5
commit 7a0756a5e8
22 changed files with 233 additions and 306 deletions

View File

@ -1,15 +0,0 @@
package gap
import "net"
func GetOutboundIP() (net.IP, error) {
conn, err := net.Dial("udp", "1.1.1.1:80")
if err != nil {
return nil, err
} else {
defer conn.Close()
}
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP, nil
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"git.solsynth.dev/hypernet/nexus/pkg/nex"
"git.solsynth.dev/hypernet/nexus/pkg/proto"
"git.solsynth.dev/hypernet/pusher/pkg/pushkit/pushcon"
"github.com/rs/zerolog/log"
"strings"
@ -11,18 +12,19 @@ import (
)
var Nx *nex.Conn
var Px *pushcon.Conn
func InitializeToNexus() error {
grpcBind := strings.SplitN(viper.GetString("grpc_bind"), ":", 2)
httpBind := strings.SplitN(viper.GetString("bind"), ":", 2)
outboundIp, _ := GetOutboundIP()
outboundIp, _ := nex.GetOutboundIP()
grpcOutbound := fmt.Sprintf("%s:%s", outboundIp, grpcBind[1])
httpOutbound := fmt.Sprintf("%s:%s", outboundIp, httpBind[1])
var err error
Nx, err = nex.NewNexusConn(viper.GetString("dealer.addr"), &proto.ServiceInfo{
Nx, err = nex.NewNexusConn(viper.GetString("nexus_addr"), &proto.ServiceInfo{
Id: viper.GetString("id"),
Type: nex.ServiceTypeAuth,
Label: "Passport",
@ -38,5 +40,10 @@ func InitializeToNexus() error {
}()
}
Px, err = pushcon.NewConn(Nx)
if err != nil {
return fmt.Errorf("error during initialize pushcon: %v", err)
}
return err
}

View File

@ -24,17 +24,15 @@ func (v *Server) NotifyUser(_ context.Context, in *proto.NotifyUserRequest) (*pr
metadata := nex.DecodeMap(in.GetNotify().GetMetadata())
notification := models.Notification{
Topic: in.GetNotify().GetTopic(),
Title: in.GetNotify().GetTitle(),
Subtitle: in.GetNotify().Subtitle,
Body: in.GetNotify().GetBody(),
Metadata: metadata,
Avatar: in.GetNotify().Avatar,
Picture: in.GetNotify().Picture,
IsRealtime: in.GetNotify().GetIsRealtime(),
IsForcePush: in.GetNotify().GetIsForcePush(),
Account: user,
AccountID: user.ID,
Topic: in.GetNotify().GetTopic(),
Title: in.GetNotify().GetTitle(),
Subtitle: in.GetNotify().GetSubtitle(),
Body: in.GetNotify().GetBody(),
Metadata: metadata,
Priority: int(in.GetNotify().GetPriority()),
IsRealtime: in.GetNotify().GetIsRealtime(),
Account: user,
AccountID: user.ID,
}
log.Debug().Str("topic", notification.Topic).Uint("uid", notification.AccountID).Msg("Notifying user...")
@ -73,17 +71,15 @@ func (v *Server) NotifyUserBatch(_ context.Context, in *proto.NotifyUserBatchReq
}
notification := models.Notification{
Topic: in.GetNotify().GetTopic(),
Title: in.GetNotify().GetTitle(),
Subtitle: in.GetNotify().Subtitle,
Body: in.GetNotify().GetBody(),
Metadata: metadata,
Avatar: in.GetNotify().Avatar,
Picture: in.GetNotify().Picture,
IsRealtime: in.GetNotify().GetIsRealtime(),
IsForcePush: in.GetNotify().GetIsForcePush(),
Account: user,
AccountID: user.ID,
Topic: in.GetNotify().GetTopic(),
Title: in.GetNotify().GetTitle(),
Subtitle: in.GetNotify().GetSubtitle(),
Body: in.GetNotify().GetBody(),
Metadata: metadata,
Priority: int(in.GetNotify().GetPriority()),
IsRealtime: in.GetNotify().GetIsRealtime(),
Account: user,
AccountID: user.ID,
}
checklist[user.ID] = true
@ -121,17 +117,15 @@ func (v *Server) NotifyAllUser(_ context.Context, in *proto.NotifyRequest) (*pro
}
notification := models.Notification{
Topic: in.GetTopic(),
Title: in.GetTitle(),
Subtitle: in.Subtitle,
Body: in.GetBody(),
Metadata: metadata,
Avatar: in.Avatar,
Picture: in.Picture,
IsRealtime: in.GetIsRealtime(),
IsForcePush: in.GetIsForcePush(),
Account: user,
AccountID: user.ID,
Topic: in.GetTopic(),
Title: in.GetTitle(),
Subtitle: in.GetSubtitle(),
Body: in.GetBody(),
Metadata: metadata,
Priority: int(in.GetPriority()),
IsRealtime: in.GetIsRealtime(),
Account: user,
AccountID: user.ID,
}
checklist[user.ID] = true

View File

@ -10,11 +10,10 @@ type Notification struct {
Topic string `json:"topic"`
Title string `json:"title"`
Subtitle *string `json:"subtitle"`
Subtitle string `json:"subtitle"`
Body string `json:"body"`
Metadata datatypes.JSONMap `json:"metadata"`
Avatar *string `json:"avatar"`
Picture *string `json:"picture"`
Priority int `json:"priority"`
SenderID *uint `json:"sender_id"`
Account Account `json:"account"`
@ -22,8 +21,7 @@ type Notification struct {
ReadAt *time.Time `json:"read_at"`
IsRealtime bool `json:"is_realtime" gorm:"-"`
IsForcePush bool `json:"is_force_push" gorm:"-"`
IsRealtime bool `json:"is_realtime" gorm:"-"`
}
const (

View File

@ -11,15 +11,13 @@ import (
func notifyAllUser(c *fiber.Ctx) error {
var data struct {
Topic string `json:"type" validate:"required"`
Title string `json:"subject" validate:"required,max=1024"`
Subtitle *string `json:"subtitle" validate:"max=1024"`
Body string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
Avatar *string `json:"avatar"`
Picture *string `json:"picture"`
IsForcePush bool `json:"is_force_push"`
IsRealtime bool `json:"is_realtime"`
Topic string `json:"type" validate:"required"`
Title string `json:"subject" validate:"required,max=1024"`
Subtitle string `json:"subtitle" validate:"max=1024"`
Body string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
Priority int `json:"priority"`
IsRealtime bool `json:"is_realtime"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
@ -43,17 +41,14 @@ func notifyAllUser(c *fiber.Ctx) error {
go func() {
for _, user := range users {
notification := models.Notification{
Topic: data.Topic,
Subtitle: data.Subtitle,
Title: data.Title,
Body: data.Body,
Metadata: data.Metadata,
Avatar: data.Avatar,
Picture: data.Picture,
IsRealtime: data.IsRealtime,
IsForcePush: data.IsForcePush,
Account: user,
AccountID: user.ID,
Topic: data.Topic,
Subtitle: data.Subtitle,
Title: data.Title,
Body: data.Body,
Metadata: data.Metadata,
Priority: data.Priority,
Account: user,
AccountID: user.ID,
}
if data.IsRealtime {
@ -73,14 +68,14 @@ func notifyAllUser(c *fiber.Ctx) error {
func notifyOneUser(c *fiber.Ctx) error {
var data struct {
Topic string `json:"type" validate:"required"`
Title string `json:"subject" validate:"required,max=1024"`
Subtitle *string `json:"subtitle" validate:"max=1024"`
Body string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
IsForcePush bool `json:"is_force_push"`
IsRealtime bool `json:"is_realtime"`
UserID uint `json:"user_id" validate:"required"`
Topic string `json:"type" validate:"required"`
Title string `json:"subject" validate:"required,max=1024"`
Subtitle string `json:"subtitle" validate:"max=1024"`
Body string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
Priority int `json:"priority"`
IsRealtime bool `json:"is_realtime"`
UserID uint `json:"user_id" validate:"required"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
@ -103,13 +98,12 @@ func notifyOneUser(c *fiber.Ctx) error {
}
notification := models.Notification{
Topic: data.Topic,
Subtitle: data.Subtitle,
Title: data.Title,
Body: data.Body,
IsRealtime: data.IsRealtime,
IsForcePush: data.IsForcePush,
AccountID: user.ID,
Topic: data.Topic,
Subtitle: data.Subtitle,
Title: data.Title,
Body: data.Body,
Priority: data.Priority,
AccountID: user.ID,
}
if data.IsRealtime {

View File

@ -16,17 +16,15 @@ func notifyUser(c *fiber.Ctx) error {
user := c.Locals("user").(models.Account)
var data struct {
ClientID string `json:"client_id" validate:"required"`
Topic string `json:"type" validate:"required"`
Title string `json:"subject" validate:"required,max=1024"`
Subtitle *string `json:"subtitle" validate:"max=1024"`
Body string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
Avatar *string `json:"avatar"`
Picture *string `json:"picture"`
IsForcePush bool `json:"is_force_push"`
IsRealtime bool `json:"is_realtime"`
UserID uint `json:"user_id" validate:"required"`
ClientID string `json:"client_id" validate:"required"`
Topic string `json:"type" validate:"required"`
Title string `json:"subject" validate:"required,max=1024"`
Subtitle string `json:"subtitle" validate:"max=1024"`
Body string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
Priority int `json:"priority"`
IsRealtime bool `json:"is_realtime"`
UserID uint `json:"user_id" validate:"required"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
@ -44,18 +42,15 @@ func notifyUser(c *fiber.Ctx) error {
}
notification := models.Notification{
Topic: data.Topic,
Subtitle: data.Subtitle,
Title: data.Title,
Body: data.Body,
Metadata: data.Metadata,
Avatar: data.Avatar,
Picture: data.Picture,
IsRealtime: data.IsRealtime,
IsForcePush: data.IsForcePush,
Account: target,
AccountID: target.ID,
SenderID: &client.ID,
Topic: data.Topic,
Subtitle: data.Subtitle,
Title: data.Title,
Body: data.Body,
Metadata: data.Metadata,
Priority: data.Priority,
Account: target,
AccountID: target.ID,
SenderID: &client.ID,
}
if data.IsRealtime {

View File

@ -25,8 +25,8 @@ func NewServer() *HTTPApp {
app := fiber.New(fiber.Config{
DisableStartupMessage: true,
EnableIPValidation: true,
ServerHeader: "Hydrogen.Passport",
AppName: "Hydrogen.Passport",
ServerHeader: "Hypernet.Passport",
AppName: "Hypernet.Passport",
ProxyHeader: fiber.HeaderXForwardedFor,
JSONEncoder: jsoniter.ConfigCompatibleWithStandardLibrary.Marshal,
JSONDecoder: jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal,

View File

@ -3,10 +3,11 @@ package services
import (
"context"
"fmt"
"git.solsynth.dev/hypernet/nexus/pkg/nex"
"git.solsynth.dev/hypernet/nexus/pkg/proto"
"time"
"unicode"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/gap"
"gorm.io/gorm/clause"
@ -312,9 +313,12 @@ func DeleteAccount(id uint) error {
return err
} else {
InvalidAuthCacheWithUser(id)
_, _ = proto.NewServiceDirectoryClient(gap.Nx.GetNexusGrpcConn()).BroadcastDeletion(context.Background(), &proto.DeletionRequest{
ResourceType: "account",
ResourceId: fmt.Sprintf("%d", id),
_, _ = proto.NewDirectoryServiceClient(gap.Nx.GetNexusGrpcConn()).BroadcastEvent(context.Background(), &proto.EventInfo{
Event: "deletion",
Data: nex.EncodeMap(map[string]any{
"type": "account",
"id": fmt.Sprintf("%d", id),
}),
})
}

View File

@ -1,19 +1,16 @@
package services
import (
"context"
"fmt"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/gap"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hypernet/pusher/pkg/pushkit"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
"github.com/samber/lo"
"strings"
"time"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"github.com/google/uuid"
"github.com/spf13/viper"
"strings"
)
const EmailPasswordTemplate = `Dear %s,
@ -86,13 +83,11 @@ func GetFactorCode(factor models.AuthFactor) (bool, error) {
subject := fmt.Sprintf("[%s] Login verification code", viper.GetString("name"))
content := fmt.Sprintf(EmailPasswordTemplate, user.Name, factor.Secret, viper.GetString("maintainer"))
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := proto.NewPostmanClient(gap.Nx.GetNexusGrpcConn()).DeliverEmail(ctx, &proto.DeliverEmailRequest{
err := gap.Px.PushEmail(pushkit.EmailDeliverRequest{
To: user.GetPrimaryEmail().Content,
Email: &proto.EmailRequest{
Subject: subject,
TextBody: &content,
Email: pushkit.EmailData{
Subject: subject,
Text: &content,
},
})
if err != nil {

View File

@ -4,22 +4,20 @@ import (
"context"
"fmt"
"git.solsynth.dev/hypernet/nexus/pkg/nex"
"git.solsynth.dev/hypernet/nexus/pkg/proto"
"git.solsynth.dev/hypernet/pusher/pkg/pushkit"
"reflect"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/rs/zerolog/log"
"github.com/samber/lo"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/gap"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
)
// TODO Awaiting for the new notification pusher
func AddNotifySubscriber(user models.Account, provider, id, tk, ua string) (models.NotificationSubscriber, error) {
var prev models.NotificationSubscriber
var subscriber models.NotificationSubscriber
@ -101,7 +99,7 @@ func PushNotification(notification models.Notification, skipNotifiableCheck ...b
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := proto.NewStreamControllerClient(gap.Nx.GetNexusGrpcConn()).PushStream(ctx, &proto.PushStreamRequest{
_, err := proto.NewStreamServiceClient(gap.Nx.GetNexusGrpcConn()).PushStream(ctx, &proto.PushStreamRequest{
UserId: lo.ToPtr(uint64(notification.AccountID)),
Body: nex.WebSocketPackage{
Action: "notifications.new",
@ -131,23 +129,17 @@ func PushNotification(notification models.Notification, skipNotifiableCheck ...b
tokens = append(tokens, subscriber.DeviceToken)
}
metadata, _ := jsoniter.Marshal(notification.Metadata)
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err = proto.NewPostmanClient(gap.Nx.GetNexusGrpcConn()).DeliverNotificationBatch(ctx, &proto.DeliverNotificationBatchRequest{
Providers: providers,
DeviceTokens: tokens,
Notify: &proto.NotifyRequest{
Topic: notification.Topic,
Title: notification.Title,
Subtitle: notification.Subtitle,
Body: notification.Body,
Metadata: metadata,
Avatar: notification.Avatar,
Picture: notification.Picture,
IsRealtime: notification.IsRealtime,
IsForcePush: notification.IsForcePush,
err = gap.Px.PushNotifyBatch(pushkit.NotificationPushBatchRequest{
Providers: providers,
Tokens: tokens,
Notification: pushkit.Notification{
Topic: notification.Topic,
Title: notification.Title,
Subtitle: notification.Subtitle,
Body: notification.Body,
Metadata: notification.Metadata,
},
})
@ -188,7 +180,7 @@ func PushNotificationBatch(notifications []models.Notification, skipNotifiableCh
var subscribers []models.NotificationSubscriber
database.C.Where("account_id IN ?", accountIdx).Find(&subscribers)
stream := proto.NewStreamControllerClient(gap.Nx.GetNexusGrpcConn())
stream := proto.NewStreamServiceClient(gap.Nx.GetNexusGrpcConn())
for _, notification := range notifications {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
_, _ = stream.PushStream(ctx, &proto.PushStreamRequest{
@ -214,22 +206,16 @@ func PushNotificationBatch(notifications []models.Notification, skipNotifiableCh
tokens = append(tokens, subscriber.DeviceToken)
}
metadata, _ := jsoniter.Marshal(notification.Metadata)
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
_, _ = proto.NewPostmanClient(gap.Nx.GetNexusGrpcConn()).DeliverNotificationBatch(ctx, &proto.DeliverNotificationBatchRequest{
Providers: providers,
DeviceTokens: tokens,
Notify: &proto.NotifyRequest{
Topic: notification.Topic,
Title: notification.Title,
Subtitle: notification.Subtitle,
Body: notification.Body,
Metadata: metadata,
Avatar: notification.Avatar,
Picture: notification.Picture,
IsRealtime: notification.IsRealtime,
IsForcePush: notification.IsForcePush,
_ = gap.Px.PushNotifyBatch(pushkit.NotificationPushBatchRequest{
Providers: providers,
Tokens: tokens,
Notification: pushkit.Notification{
Topic: notification.Topic,
Title: notification.Title,
Subtitle: notification.Subtitle,
Body: notification.Body,
Metadata: notification.Metadata,
},
})
cancel()

View File

@ -6,7 +6,6 @@ import (
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"github.com/samber/lo"
"gorm.io/gorm"
)
@ -131,7 +130,7 @@ func NewFriend(userA models.Account, userB models.Account, skipPending ...bool)
} else {
_ = NewNotification(models.Notification{
Title: "New Friend Request",
Subtitle: lo.ToPtr(fmt.Sprintf("New friend request from %s", userA.Name)),
Subtitle: fmt.Sprintf("New friend request from %s", userA.Name),
Body: fmt.Sprintf("You got a new friend request from %s. Go to your account page and decide how to deal it.", userA.Nick),
Account: userB,
AccountID: userB.ID,
@ -168,7 +167,7 @@ func HandleFriend(userA models.Account, userB models.Account, isAccept bool) err
_ = NewNotification(models.Notification{
Title: "Friend Request Processed",
Subtitle: lo.ToPtr(fmt.Sprintf("Your friend request to %s has been processsed.", userA.Name)),
Subtitle: fmt.Sprintf("Your friend request to %s has been processsed.", userA.Name),
Body: fmt.Sprintf("Your relationship status with %s has been updated, go check it out!", userA.Nick),
Account: userB,
AccountID: userB.ID,

View File

@ -5,7 +5,6 @@ import (
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"github.com/samber/lo"
)
func ListAbuseReport(account models.Account) ([]models.AbuseReport, error) {
@ -42,10 +41,10 @@ func UpdateAbuseReportStatus(id uint, status, message string) error {
return err
}
NewNotification(models.Notification{
_ = NewNotification(models.Notification{
Topic: "reports.feedback",
Title: "Abuse report status has been changed.",
Subtitle: lo.ToPtr(fmt.Sprintf("The report #%d's status updated", id)),
Subtitle: fmt.Sprintf("The report #%d's status updated", id),
Body: fmt.Sprintf("The report created by you with ID #%d's status has been changed to %s. Moderator message: %s", id, status, message),
Account: account,
AccountID: account.ID,

View File

@ -3,9 +3,9 @@ package services
import (
"context"
"fmt"
"git.solsynth.dev/hypernet/nexus/pkg/proto"
"time"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
localCache "git.solsynth.dev/hydrogen/passport/pkg/internal/cache"
"git.solsynth.dev/hydrogen/passport/pkg/internal/gap"
@ -60,7 +60,7 @@ func CacheUserStatus(uid uint, status models.Status) {
}
func GetUserOnline(uid uint) bool {
pc := proto.NewStreamControllerClient(gap.Nx.GetNexusGrpcConn())
pc := proto.NewStreamServiceClient(gap.Nx.GetNexusGrpcConn())
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := pc.CountStreamConnection(ctx, &proto.CountConnectionRequest{

View File

@ -129,15 +129,15 @@ func ActiveTicket(ticket models.AuthTicket) (models.AuthTicket, error) {
_ = NewNotification(models.Notification{
Topic: "passport.security.alert",
Title: "New sign in alert",
Subtitle: lo.ToPtr(fmt.Sprintf("New sign in from %s", ticket.IpAddress)),
Subtitle: fmt.Sprintf("New sign in from %s", ticket.IpAddress),
Body: fmt.Sprintf("Your account just got a new sign in from %s. Make sure you recongize this device, or sign out it immediately and reset password.", ticket.IpAddress),
Metadata: datatypes.JSONMap{
"ip_address": ticket.IpAddress,
"created_at": ticket.CreatedAt,
"available_at": ticket.AvailableAt,
},
AccountID: ticket.AccountID,
IsForcePush: true,
AccountID: ticket.AccountID,
Priority: 5,
})
}

View File

@ -1,10 +1,9 @@
package services
import (
"context"
"fmt"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/gap"
"git.solsynth.dev/hypernet/pusher/pkg/pushkit"
"strings"
"time"
@ -143,13 +142,11 @@ func NotifyMagicToken(token models.MagicToken) error {
return fmt.Errorf("unsupported magic token type to notify")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := proto.NewPostmanClient(gap.Nx.GetNexusGrpcConn()).DeliverEmail(ctx, &proto.DeliverEmailRequest{
err := gap.Px.PushEmail(pushkit.EmailDeliverRequest{
To: user.GetPrimaryEmail().Content,
Email: &proto.EmailRequest{
Subject: subject,
TextBody: &content,
Email: pushkit.EmailData{
Subject: subject,
Text: &content,
},
})
return err