add user to nerwork

This commit is contained in:
daniel.w 2024-09-02 21:43:03 +08:00
parent f135327805
commit 5599f88787
17 changed files with 317 additions and 12 deletions

View File

@ -20,3 +20,12 @@ TimelineSetting:
RedisCluster: RedisCluster:
Host: 127.0.0.1:7001 Host: 127.0.0.1:7001
Type: cluster Type: cluster
Neo4J:
URI: neo4j://localhost:7687
Username: neo4j
Password: yyyytttt
MaxConnectionPoolSize: 20
MaxConnectionLifetime: 200s
ConnectionTimeout : 200s
LogLevel : debug

View File

@ -0,0 +1,5 @@
// 企業版才能用,社群版只能用預設的
CREATE DATABASE relation;
// 創建 User 節點 UID 是唯一鍵
CREATE CONSTRAINT FOR (u:User) REQUIRE u.UID IS UNIQUE

View File

@ -242,4 +242,16 @@ service TimelineService
rpc HasNoMoreData(DoNoMoreDataReq) returns (HasNoMoreDataResp); rpc HasNoMoreData(DoNoMoreDataReq) returns (HasNoMoreDataResp);
// ClearNoMoreDataFlag "NoMoreData" // ClearNoMoreDataFlag "NoMoreData"
rpc ClearNoMoreDataFlag(DoNoMoreDataReq) returns (OKResp); rpc ClearNoMoreDataFlag(DoNoMoreDataReq) returns (OKResp);
}
// ========== Social Network () ==========
message AddUserToNetworkReq
{
string uid = 1;
}
service SocialNetworkService
{
rpc AddUserToNetwork(AddUserToNetworkReq) returns (OKResp);
} }

1
go.mod
View File

@ -6,6 +6,7 @@ require (
code.30cm.net/digimon/library-go/errs v1.2.4 code.30cm.net/digimon/library-go/errs v1.2.4
code.30cm.net/digimon/library-go/validator v1.0.0 code.30cm.net/digimon/library-go/validator v1.0.0
github.com/alicebob/miniredis/v2 v2.33.0 github.com/alicebob/miniredis/v2 v2.33.0
github.com/neo4j/neo4j-go-driver/v5 v5.24.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/zeromicro/go-zero v1.7.0 github.com/zeromicro/go-zero v1.7.0
go.mongodb.org/mongo-driver v1.16.0 go.mongodb.org/mongo-driver v1.16.0

View File

@ -1,6 +1,8 @@
package config package config
import ( import (
"time"
"github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/zrpc" "github.com/zeromicro/go-zero/zrpc"
) )
@ -24,4 +26,15 @@ type Config struct {
// Redis Cluster // Redis Cluster
RedisCluster redis.RedisConf RedisCluster redis.RedisConf
// 圖形話資料庫
Neo4J struct {
URI string
Username string
Password string
MaxConnectionPoolSize int
MaxConnectionLifetime time.Duration
ConnectionTimeout time.Duration
LogLevel string
}
} }

View File

@ -0,0 +1,7 @@
package repository
import "context"
type SocialNetworkRepository interface {
CreateUserNode(ctx context.Context, uid string) error
}

View File

@ -0,0 +1,14 @@
package neo4j
import "time"
// Config holds the configuration for Neo4j connection.
type Config struct {
URI string
Username string
Password string
MaxConnectionPoolSize int
MaxConnectionLifetime time.Duration
ConnectionTimeout time.Duration
LogLevel string
}

View File

@ -0,0 +1,54 @@
package neo4j
import (
"context"
"fmt"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
n4Cfg "github.com/neo4j/neo4j-go-driver/v5/neo4j/config"
)
// NewNeo4J initializes a Neo4jInit using the provided Config and options.
// If opts is not provided, it will initialize Neo4jInit with default configuration.
func NewNeo4J(conf *Config, opts ...Option) *Client {
driverConfig := &n4Cfg.Config{
MaxConnectionLifetime: conf.MaxConnectionLifetime,
MaxConnectionPoolSize: conf.MaxConnectionPoolSize,
ConnectionAcquisitionTimeout: conf.ConnectionTimeout,
}
neo4ji := &Client{
neo4jConf: driverConfig,
}
for _, opt := range opts {
opt(neo4ji)
}
return neo4ji
}
// Conn initiates connection to the database and returns a Neo4j driver instance.
func (c *Client) Conn() (neo4j.DriverWithContext, error) {
auth := neo4j.BasicAuth(c.serviceConf.Username, c.serviceConf.Password, "")
driver, err := neo4j.NewDriverWithContext(c.serviceConf.URI, auth, func(c *n4Cfg.Config) {})
if err != nil {
return nil, fmt.Errorf("neo4j driver initialization error: %w", err)
}
defer func(driver neo4j.DriverWithContext, ctx context.Context) {
err := driver.Close(ctx)
if err != nil {
// fmt
}
}(driver, context.Background())
ctx := context.Background()
// Verify the connection to Neo4j.
err = driver.VerifyConnectivity(ctx)
if err != nil {
return nil, fmt.Errorf("neo4j connectivity verification error: %w", err)
}
return driver, nil
}

View File

@ -0,0 +1,60 @@
package neo4j
import (
"strings"
"time"
n4Cfg "github.com/neo4j/neo4j-go-driver/v5/neo4j/config"
"github.com/neo4j/neo4j-go-driver/v5/neo4j/log"
)
const (
defaultMaxConnectionLifetime = 5 * time.Minute
defaultMaxConnectionPoolSize = 25
defaultConnectionTimeout = 5 * time.Second
)
// Option configures Neo4jInit behaviour.
type Option func(*Client)
type Client struct {
neo4jConf *n4Cfg.Config
serviceConf Config
}
// WithLogLevel sets the log level for the Neo4j driver.
func WithLogLevel(level string) Option {
return func(neo4ji *Client) {
var logger log.Logger
switch strings.ToLower(level) {
case "panic", "fatal", "error":
logger = log.ToConsole(log.ERROR)
case "warn", "warning":
logger = log.ToConsole(log.WARNING)
case "info", "debug", "trace":
logger = log.ToConsole(log.INFO)
default:
logger = log.ToConsole(log.ERROR)
}
neo4ji.neo4jConf.Log = logger
}
}
// WithPerformance configures the Neo4j driver for performance by setting connection pool size and lifetime.
func WithPerformance() Option {
return func(neo4ji *Client) {
if neo4ji.serviceConf.MaxConnectionPoolSize > 0 {
neo4ji.neo4jConf.MaxConnectionPoolSize = neo4ji.serviceConf.MaxConnectionPoolSize
} else {
neo4ji.neo4jConf.MaxConnectionPoolSize = defaultMaxConnectionPoolSize
}
if neo4ji.serviceConf.MaxConnectionLifetime > 0 {
neo4ji.neo4jConf.MaxConnectionLifetime = neo4ji.serviceConf.MaxConnectionLifetime
} else {
neo4ji.neo4jConf.MaxConnectionLifetime = defaultMaxConnectionLifetime
}
}
}

View File

@ -0,0 +1,36 @@
package socialnetworkservicelogic
import (
"context"
"fmt"
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
"app-cloudep-tweeting-service/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type AddUserToNetworkLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewAddUserToNetworkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddUserToNetworkLogic {
return &AddUserToNetworkLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *AddUserToNetworkLogic) AddUserToNetwork(in *tweeting.AddUserToNetworkReq) (*tweeting.OKResp, error) {
// todo: add your logic here and delete this line
err := l.svcCtx.SocialNetworkRepository.CreateUserNode(l.ctx, in.GetUid())
if err != nil {
return nil, err
}
fmt.Println(err)
return &tweeting.OKResp{}, nil
}

View File

@ -0,0 +1,53 @@
package repository
import (
"app-cloudep-tweeting-service/internal/config"
"app-cloudep-tweeting-service/internal/domain/repository"
client4J "app-cloudep-tweeting-service/internal/lib/neo4j"
"context"
"fmt"
ers "code.30cm.net/digimon/library-go/errs"
n4 "github.com/neo4j/neo4j-go-driver/v5/neo4j"
)
type SocialNetworkParam struct {
Config config.Config
Neo4jClient *client4J.Client
}
type SocialNetworkRepository struct {
cfg config.Config
neo4jClient *client4J.Client
}
func MustSocialNetworkRepository(param SocialNetworkParam) repository.SocialNetworkRepository {
return &SocialNetworkRepository{
cfg: param.Config,
neo4jClient: param.Neo4jClient,
}
}
func (s SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string) error {
// 執行 Cypher
conn, err := s.neo4jClient.Conn()
if err != nil {
return ers.DBError("failed to connect to node4j", err.Error())
}
insert := map[string]any{
"uid": uid,
}
result, err := conn.NewSession(ctx, n4.SessionConfig{
AccessMode: n4.AccessModeWrite,
}).Run(ctx, "CREATE (n:Person {name: $name}) RETURN n", insert)
if err != nil {
return err
}
fmt.Println(result.Keys())
return nil
}

View File

@ -24,7 +24,7 @@ type TimelineRepository struct {
redis redis.Redis redis redis.Redis
} }
func MustGenerateUseCase(param TimelineRepositoryParam) repository.TimelineRepository { func MustGenerateRepository(param TimelineRepositoryParam) repository.TimelineRepository {
return &TimelineRepository{ return &TimelineRepository{
cfg: param.Config, cfg: param.Config,
redis: param.Redis, redis: param.Redis,

View File

@ -7,7 +7,7 @@ import (
"context" "context"
"app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/gen_result/pb/tweeting"
commentservicelogic "app-cloudep-tweeting-service/internal/logic/commentservice" "app-cloudep-tweeting-service/internal/logic/commentservice"
"app-cloudep-tweeting-service/internal/svc" "app-cloudep-tweeting-service/internal/svc"
) )

View File

@ -7,7 +7,7 @@ import (
"context" "context"
"app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/gen_result/pb/tweeting"
postservicelogic "app-cloudep-tweeting-service/internal/logic/postservice" "app-cloudep-tweeting-service/internal/logic/postservice"
"app-cloudep-tweeting-service/internal/svc" "app-cloudep-tweeting-service/internal/svc"
) )

View File

@ -0,0 +1,28 @@
// Code generated by goctl. DO NOT EDIT.
// Source: tweeting.proto
package server
import (
"context"
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
"app-cloudep-tweeting-service/internal/logic/socialnetworkservice"
"app-cloudep-tweeting-service/internal/svc"
)
type SocialNetworkServiceServer struct {
svcCtx *svc.ServiceContext
tweeting.UnimplementedSocialNetworkServiceServer
}
func NewSocialNetworkServiceServer(svcCtx *svc.ServiceContext) *SocialNetworkServiceServer {
return &SocialNetworkServiceServer{
svcCtx: svcCtx,
}
}
func (s *SocialNetworkServiceServer) AddUserToNetwork(ctx context.Context, in *tweeting.AddUserToNetworkReq) (*tweeting.OKResp, error) {
l := socialnetworkservicelogic.NewAddUserToNetworkLogic(ctx, s.svcCtx)
return l.AddUserToNetwork(in)
}

View File

@ -7,7 +7,7 @@ import (
"context" "context"
"app-cloudep-tweeting-service/gen_result/pb/tweeting" "app-cloudep-tweeting-service/gen_result/pb/tweeting"
timelineservicelogic "app-cloudep-tweeting-service/internal/logic/timelineservice" "app-cloudep-tweeting-service/internal/logic/timelineservice"
"app-cloudep-tweeting-service/internal/svc" "app-cloudep-tweeting-service/internal/svc"
) )

View File

@ -3,6 +3,7 @@ package svc
import ( import (
"app-cloudep-tweeting-service/internal/config" "app-cloudep-tweeting-service/internal/config"
domainRepo "app-cloudep-tweeting-service/internal/domain/repository" domainRepo "app-cloudep-tweeting-service/internal/domain/repository"
"app-cloudep-tweeting-service/internal/lib/neo4j"
model "app-cloudep-tweeting-service/internal/model/mongo" model "app-cloudep-tweeting-service/internal/model/mongo"
"app-cloudep-tweeting-service/internal/repository" "app-cloudep-tweeting-service/internal/repository"
@ -12,13 +13,12 @@ import (
) )
type ServiceContext struct { type ServiceContext struct {
Config config.Config Config config.Config
Validate vi.Validate Validate vi.Validate
PostModel model.PostModel
PostModel model.PostModel CommentModel model.CommentModel
CommentModel model.CommentModel TimelineRepo domainRepo.TimelineRepository
SocialNetworkRepository domainRepo.SocialNetworkRepository
TimelineRepo domainRepo.TimelineRepository
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -27,14 +27,27 @@ func NewServiceContext(c config.Config) *ServiceContext {
panic(err) panic(err)
} }
neoClient := neo4j.NewNeo4J(&neo4j.Config{
URI: c.Neo4J.URI,
Username: c.Neo4J.Username,
Password: c.Neo4J.Password,
MaxConnectionPoolSize: c.Neo4J.MaxConnectionPoolSize,
MaxConnectionLifetime: c.Neo4J.MaxConnectionLifetime,
ConnectionTimeout: c.Neo4J.ConnectionTimeout,
}, neo4j.WithPerformance(), neo4j.WithLogLevel(c.Neo4J.LogLevel))
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
Validate: vi.MustValidator(), Validate: vi.MustValidator(),
PostModel: MustPostModel(c), PostModel: MustPostModel(c),
CommentModel: MustCommentModel(c), CommentModel: MustCommentModel(c),
TimelineRepo: repository.MustGenerateUseCase(repository.TimelineRepositoryParam{ TimelineRepo: repository.MustGenerateRepository(repository.TimelineRepositoryParam{
Config: c, Config: c,
Redis: *newRedis, Redis: *newRedis,
}), }),
SocialNetworkRepository: repository.MustSocialNetworkRepository(repository.SocialNetworkParam{
Config: c,
Neo4jClient: neoClient,
}),
} }
} }