merge from r/paopao-ce-pro branch

r/paopao-ce-xtra
Michael Li 2 years ago
commit 781aba41ad
No known key found for this signature in database

@ -30,52 +30,124 @@ All notable changes to paopao-ce are documented in this file.
# 模块开启 # 模块开启
VITE_ENABLE_FRIENDS_BAR=true VITE_ENABLE_FRIENDS_BAR=true
``` ```
- add Newest/Hots/Following tweets support in friend bar feature. - add Newest/Hots/Following tweets support in friend bar feature.
mirgration database first(sql ddl file in `scripts/migration/**/*_home_timeline.up.sql`): mirgration database first(sql ddl file in `scripts/migration/**/*_home_timeline.up.sql`):
```sql ```sql
CREATE TABLE `p_post_metric` ( CREATE TABLE `p_post_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT, `id` bigint unsigned NOT NULL AUTO_INCREMENT,
`post_id` bigint unsigned NOT NULL, `post_id` bigint unsigned NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0, `rank_score` bigint unsigned NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0, `incentive_score` int unsigned NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0, `decay_factor` int unsigned NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0, `motivation_factor` int unsigned NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是 `is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0', `created_on` bigint unsigned NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0', `modified_on` bigint unsigned NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0', `deleted_on` bigint unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE KEY `idx_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_post_metric (post_id, rank_score, created_on) INSERT INTO p_post_metric (post_id, rank_score, created_on)
SELECT id AS post_id, SELECT id AS post_id,
comment_count + upvote_count*2 + collection_count*4 AS rank_score, comment_count + upvote_count*2 + collection_count*4 AS rank_score,
created_on created_on
FROM p_post FROM p_post
WHERE is_del=0; WHERE is_del=0;
-- 原来的可见性: 0公开 1私密 2好友可见 3关注可见 -- 原来的可见性: 0公开 1私密 2好友可见 3关注可见
-- 现在的可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开 -- 现在的可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开
UPDATE p_post a UPDATE p_post a, p_post b
SET visibility = ( SET a.visibility = (
SELECT CASE b.visibility
CASE visibility WHEN 0 THEN 90
WHEN 0 THEN 90 WHEN 1 THEN 0
WHEN 1 THEN 0 WHEN 2 THEN 50
WHEN 2 THEN 50 WHEN 3 THEN 60
WHEN 3 THEN 60 ELSE 0
ELSE 0 END
END )
FROM WHERE a.ID = b.ID;
p_post b ```
WHERE - add cache support for index/home etc. page.
a.ID = b.ID - add hots comments support for post detail page.
); - add highlight comments support for post detail page.
```sql mirgration database first(sql ddl file in `scripts/migration/**/*_comment_esence.up.sql`):
- add cache support for index/home etc. page. ```sql
- add hots comments support for post detail page. ALTER TABLE `p_comment` ADD COLUMN `is_essence` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否精选';
```
- add follow/unfollow user support in index/home/collecion/message/post page.
- add simple prometheus metrics support.
add `Metrics` to `conf.yaml` 's `Features` section to enable this feature like below:
```yaml
# file config.yaml
...
Features:
Default: ["Base", "Postgres", "Meili", "LocalOSS", "Metrics", "web"]
JobManager: # Cron Job理器的配置参数
MaxOnlineInterval: "@every 5m" # 更新最大在线人数默认每5分钟更新一次
UpdateMetricsInterval: "@every 5m" # 更新Prometheus指标默认每5分钟更新一次
MetricsServer: # Prometheus Metrics服务
RunMode: debug
HttpIp: 0.0.0.0
HttpPort: 6080
ReadTimeout: 60
WriteTimeout: 60
...
```
- add full support for tweet hots comment logic and add cache support for tweet comments.
mirgration database first(sql ddl file in `scripts/migration/**/*_rank_metrics.up.sql`):
```sql
ALTER TABLE `p_comment` ADD COLUMN `reply_count` int unsigned NOT NULL DEFAULT 0 COMMENT '回复数';
UPDATE p_comment comment
SET reply_count = (
SELECT count(*) FROM p_comment_reply reply WHERE reply.comment_id=comment.id AND reply.is_del=0
)
WHERE is_del=0;
CREATE TABLE `p_comment_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`comment_id` bigint unsigned NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_metric_comment_id_rank_score` (`comment_id`, `rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE `p_user_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`tweets_count` int unsigned NOT NULL DEFAULT 0,
`latest_trends_on` bigint unsigned NOT NULL DEFAULT 0 COMMENT '最新动态时间',
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user_metric_user_id_tweets_count_trends` (`user_id`, `tweets_count`, `latest_trends_on`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;
```
## 0.4.2 ## 0.4.2
### Fixed ### Fixed
- fixed remove multi-objects no effects and occurs resource leak error when use Minio as OSS(Object Storage System).[#371](https://github.com/rocboss/paopao-ce/pull/371) [#372](https://github.com/rocboss/paopao-ce/pull/372) - fixed remove multi-objects no effects and occurs resource leak error when use Minio as OSS(Object Storage System).[#371](https://github.com/rocboss/paopao-ce/pull/371) [#372](https://github.com/rocboss/paopao-ce/pull/372)

@ -18,6 +18,7 @@ type Loose interface {
// Chain provide handlers chain for gin // Chain provide handlers chain for gin
Chain() gin.HandlersChain Chain() gin.HandlersChain
TweetDetail(*web.TweetDetailReq) (*web.TweetDetailResp, mir.Error)
TweetComments(*web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) TweetComments(*web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error)
TopicList(*web.TopicListReq) (*web.TopicListResp, mir.Error) TopicList(*web.TopicListReq) (*web.TopicListResp, mir.Error)
GetUserProfile(*web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error) GetUserProfile(*web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error)
@ -35,6 +36,20 @@ func RegisterLooseServant(e *gin.Engine, s Loose) {
router.Use(middlewares...) router.Use(middlewares...)
// register routes info to router // register routes info to router
router.Handle("GET", "/post", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.TweetDetailReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.TweetDetail(req)
s.Render(c, resp, err)
})
router.Handle("GET", "/post/comments", func(c *gin.Context) { router.Handle("GET", "/post/comments", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -47,7 +62,12 @@ func RegisterLooseServant(e *gin.Engine, s Loose) {
return return
} }
resp, err := s.TweetComments(req) resp, err := s.TweetComments(req)
s.Render(c, resp, err) if err != nil {
s.Render(c, nil, err)
return
}
var rv _render_ = resp
rv.Render(c)
}) })
router.Handle("GET", "/tags", func(c *gin.Context) { router.Handle("GET", "/tags", func(c *gin.Context) {
select { select {
@ -125,6 +145,10 @@ func (UnimplementedLooseServant) Chain() gin.HandlersChain {
return nil return nil
} }
func (UnimplementedLooseServant) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedLooseServant) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) { func (UnimplementedLooseServant) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -27,6 +27,7 @@ type Priv interface {
ThumbsUpTweetComment(*web.TweetCommentThumbsReq) mir.Error ThumbsUpTweetComment(*web.TweetCommentThumbsReq) mir.Error
DeleteCommentReply(*web.DeleteCommentReplyReq) mir.Error DeleteCommentReply(*web.DeleteCommentReplyReq) mir.Error
CreateCommentReply(*web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error) CreateCommentReply(*web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error)
HighlightComment(*web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error)
DeleteComment(*web.DeleteCommentReq) mir.Error DeleteComment(*web.DeleteCommentReq) mir.Error
CreateComment(*web.CreateCommentReq) (*web.CreateCommentResp, mir.Error) CreateComment(*web.CreateCommentReq) (*web.CreateCommentResp, mir.Error)
VisibleTweet(*web.VisibleTweetReq) (*web.VisibleTweetResp, mir.Error) VisibleTweet(*web.VisibleTweetReq) (*web.VisibleTweetResp, mir.Error)
@ -184,6 +185,20 @@ func RegisterPrivServant(e *gin.Engine, s Priv, m ...PrivChain) {
resp, err := s.CreateCommentReply(req) resp, err := s.CreateCommentReply(req)
s.Render(c, resp, err) s.Render(c, resp, err)
}) })
router.Handle("POST", "/post/comment/highlight", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.HighlightCommentReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.HighlightComment(req)
s.Render(c, resp, err)
})
router.Handle("DELETE", "/post/comment", func(c *gin.Context) { router.Handle("DELETE", "/post/comment", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -419,6 +434,10 @@ func (UnimplementedPrivServant) CreateCommentReply(req *web.CreateCommentReplyRe
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedPrivServant) HighlightComment(req *web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) DeleteComment(req *web.DeleteCommentReq) mir.Error { func (UnimplementedPrivServant) DeleteComment(req *web.DeleteCommentReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -15,7 +15,6 @@ import (
type Pub interface { type Pub interface {
_default_ _default_
TweetDetail(*web.TweetDetailReq) (*web.TweetDetailResp, mir.Error)
SendCaptcha(*web.SendCaptchaReq) mir.Error SendCaptcha(*web.SendCaptchaReq) mir.Error
GetCaptcha() (*web.GetCaptchaResp, mir.Error) GetCaptcha() (*web.GetCaptchaResp, mir.Error)
Register(*web.RegisterReq) (*web.RegisterResp, mir.Error) Register(*web.RegisterReq) (*web.RegisterResp, mir.Error)
@ -30,20 +29,6 @@ func RegisterPubServant(e *gin.Engine, s Pub) {
router := e.Group("v1") router := e.Group("v1")
// register routes info to router // register routes info to router
router.Handle("GET", "/post", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.TweetDetailReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.TweetDetail(req)
s.Render(c, resp, err)
})
router.Handle("POST", "/captcha", func(c *gin.Context) { router.Handle("POST", "/captcha", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -110,10 +95,6 @@ func RegisterPubServant(e *gin.Engine, s Pub) {
// UnimplementedPubServant can be embedded to have forward compatible implementations. // UnimplementedPubServant can be embedded to have forward compatible implementations.
type UnimplementedPubServant struct{} type UnimplementedPubServant struct{}
func (UnimplementedPubServant) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPubServant) SendCaptcha(req *web.SendCaptchaReq) mir.Error { func (UnimplementedPubServant) SendCaptcha(req *web.SendCaptchaReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -2,8 +2,11 @@ module github.com/rocboss/paopao-ce
go 1.21 go 1.21
toolchain go1.21.1
require ( require (
github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/semver/v3 v3.2.1
github.com/RoaringBitmap/roaring v1.5.0
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868
github.com/alimy/mir/v4 v4.0.0 github.com/alimy/mir/v4 v4.0.0
github.com/alimy/tryst v0.8.3 github.com/alimy/tryst v0.8.3
@ -29,8 +32,9 @@ require (
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/meilisearch/meilisearch-go v0.25.1 github.com/meilisearch/meilisearch-go v0.25.1
github.com/minio/minio-go/v7 v7.0.63 github.com/minio/minio-go/v7 v7.0.63
github.com/onsi/ginkgo/v2 v2.12.0 github.com/onsi/ginkgo/v2 v2.12.1
github.com/onsi/gomega v1.27.10 github.com/onsi/gomega v1.27.10
github.com/prometheus/client_golang v1.16.0
github.com/pyroscope-io/client v0.7.2 github.com/pyroscope-io/client v0.7.2
github.com/redis/rueidis v1.0.18 github.com/redis/rueidis v1.0.18
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
@ -39,11 +43,11 @@ require (
github.com/sourcegraph/conc v0.3.0 github.com/sourcegraph/conc v0.3.0
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0 github.com/spf13/viper v1.16.0
github.com/sqlc-dev/sqlc v1.20.0 github.com/sqlc-dev/sqlc v1.21.0
github.com/tencentyun/cos-go-sdk-v5 v0.7.43 github.com/tencentyun/cos-go-sdk-v5 v0.7.43
github.com/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc github.com/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc
go.uber.org/automaxprocs v1.5.3 go.uber.org/automaxprocs v1.5.3
google.golang.org/grpc v1.58.1 google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/resty.v1 v1.12.0 gopkg.in/resty.v1 v1.12.0
@ -59,8 +63,11 @@ require (
require ( require (
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 // indirect
github.com/benbjohnson/clock v1.1.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect
github.com/bytecodealliance/wasmtime-go/v8 v8.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/clbanning/mxj v1.8.4 // indirect github.com/clbanning/mxj v1.8.4 // indirect
@ -70,6 +77,7 @@ require (
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
@ -83,7 +91,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/google/cel-go v0.17.1 // indirect github.com/google/cel-go v0.18.0 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
@ -110,18 +118,24 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mozillazg/go-httpheader v0.2.1 // indirect github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pganalyze/pg_query_go/v4 v4.2.1 // indirect github.com/pganalyze/pg_query_go/v4 v4.2.3 // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 // indirect github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c // indirect
github.com/pingcap/tidb/parser v0.0.0-20220725134311-c80026e61f00 // indirect github.com/pingcap/log v1.1.0 // indirect
github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/pyroscope-io/godeltaprof v0.1.2 // indirect github.com/pyroscope-io/godeltaprof v0.1.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/riza-io/grpc-go v0.2.0 // indirect github.com/riza-io/grpc-go v0.2.0 // indirect
@ -140,12 +154,12 @@ require (
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.40.0 // indirect github.com/valyala/fasthttp v1.40.0 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.21.0 // indirect go.uber.org/zap v1.25.0 // indirect
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.13.0 // indirect golang.org/x/crypto v0.13.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp v0.0.0-20230724220655-d98519c11495 // indirect
golang.org/x/image v0.0.0-20210216034530-4410531fe030 // indirect golang.org/x/image v0.0.0-20210216034530-4410531fe030 // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.15.0 // indirect golang.org/x/net v0.15.0 // indirect
@ -154,8 +168,8 @@ require (
golang.org/x/text v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.12.0 // indirect golang.org/x/tools v0.12.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect

@ -112,6 +112,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/RoaringBitmap/roaring v1.5.0 h1:V0VCSiHjroItEYCM3guC8T83ehi5QMt3oM9EefTTOms=
github.com/RoaringBitmap/roaring v1.5.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 h1:uFrPOl1VBt/Abfl2z+A/DFc+AwmFLxEHR1+Yq6cXvww= github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 h1:uFrPOl1VBt/Abfl2z+A/DFc+AwmFLxEHR1+Yq6cXvww=
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868/go.mod h1:srphKZ1i+yGXxl/LpBS7ZIECTjCTPzZzAMtJWoG3sLo= github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868/go.mod h1:srphKZ1i+yGXxl/LpBS7ZIECTjCTPzZzAMtJWoG3sLo=
@ -175,17 +177,20 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21
github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitbus/sqlx v1.8.0 h1:2mhQscUW9Qc95gUONNswkuDaJiluVUfmBP4yw2cSK7M= github.com/bitbus/sqlx v1.8.0 h1:2mhQscUW9Qc95gUONNswkuDaJiluVUfmBP4yw2cSK7M=
github.com/bitbus/sqlx v1.8.0/go.mod h1:MemKLfQ600g6PxUVsIDe48PlY3wOquyW2ApeiXoynFo= github.com/bitbus/sqlx v1.8.0/go.mod h1:MemKLfQ600g6PxUVsIDe48PlY3wOquyW2ApeiXoynFo=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
@ -201,8 +206,8 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bytecodealliance/wasmtime-go/v8 v8.0.0 h1:jP4sqm2PHgm3+eQ50zCoCdIyQFkIL/Rtkw6TT8OYPFI= github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 h1:Wga02UaZXYF3p0LIeL5xFp09/RI7UhjfT2uB0mLrwlw=
github.com/bytecodealliance/wasmtime-go/v8 v8.0.0/go.mod h1:tgazNLU7xSC2gfRAM8L4WyE+dgs5yp9FF5/tGebEQyM= github.com/bytecodealliance/wasmtime-go/v12 v12.0.0/go.mod h1:a3PRoftJxxUzkQvgjC6sv7pKyJJK0ZsFVmH+eeEKQC4=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc=
@ -216,6 +221,8 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
@ -450,6 +457,8 @@ github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
@ -649,8 +658,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/cel-go v0.17.1 h1:s2151PDGy/eqpCI80/8dl4VL3xTkqI/YubXLXCFw0mw= github.com/google/cel-go v0.18.0 h1:u74MPiEC8mejBrkXqrTWT102g5IFEUjxOngzQIijMzU=
github.com/google/cel-go v0.17.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/cel-go v0.18.0/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4=
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -957,6 +966,8 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/meilisearch/meilisearch-go v0.25.1 h1:D5wY22sn5kkpRH3uYMGlwltdUEq5regIFmO7awHz3Vo= github.com/meilisearch/meilisearch-go v0.25.1 h1:D5wY22sn5kkpRH3uYMGlwltdUEq5regIFmO7awHz3Vo=
github.com/meilisearch/meilisearch-go v0.25.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= github.com/meilisearch/meilisearch-go v0.25.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
@ -1007,6 +1018,8 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
@ -1033,8 +1046,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -1085,19 +1098,22 @@ github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZO
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pganalyze/pg_query_go/v4 v4.2.1 h1:id/vuyIQccb9f6Yx3pzH5l4QYrxE3v6/m8RPlgMrprc= github.com/pganalyze/pg_query_go/v4 v4.2.3 h1:cNLqyiVMasV7YGWyYV+fkXyHp32gDfXVNCqoHztEGNk=
github.com/pganalyze/pg_query_go/v4 v4.2.1/go.mod h1:aEkDNOXNM5j0YGzaAapwJ7LB3dLNj+bvbWcLv1hOVqA= github.com/pganalyze/pg_query_go/v4 v4.2.3/go.mod h1:aEkDNOXNM5j0YGzaAapwJ7LB3dLNj+bvbWcLv1hOVqA=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM= github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 h1:SvWCbCPh1YeHd9yQLksvJYAgft6wLTY1aNG81tpyscQ= github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c h1:CgbKAHto5CQgWM9fSBIvaxsJHuGP0uM74HXtv3MyyGQ=
github.com/pingcap/log v0.0.0-20210906054005-afc726e70354/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c/go.mod h1:4qGtCB0QK0wBzKtFEGDhxXnSnbQApw1gc9siScUl8ew=
github.com/pingcap/tidb/parser v0.0.0-20220725134311-c80026e61f00 h1:aDC/yAGx/jPEyrX+UPKV3GWg+4A4yG8ifuP6jBEhDi0= github.com/pingcap/log v1.1.0 h1:ELiPxACz7vdo1qAvvaWJg1NrYFoY6gqAh/+Uo6aXdD8=
github.com/pingcap/tidb/parser v0.0.0-20220725134311-c80026e61f00/go.mod h1:wjvp+T3/T9XYt0nKqGX3Kc1AKuyUcfno6LTc6b2A6ew= github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4=
github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1 h1:FvX5fDJ32eblK9f6KJIOVujjtu3FDEfcRGHsEDfJ4kI=
github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1/go.mod h1:pWA6mNa/o7UTDKrg+4H75NdpRgpWRTox/cqQjaQ4ZBU=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@ -1121,11 +1137,15 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@ -1134,6 +1154,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -1146,6 +1168,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pyroscope-io/client v0.7.2 h1:OX2qdUQsS8RSkn/3C8isD7f/P0YiZQlRbAlecAaj/R8= github.com/pyroscope-io/client v0.7.2 h1:OX2qdUQsS8RSkn/3C8isD7f/P0YiZQlRbAlecAaj/R8=
github.com/pyroscope-io/client v0.7.2/go.mod h1:FEocnjn+Ngzxy6EtU9ZxXWRvQ0+pffkrBxHLnPpxwi8= github.com/pyroscope-io/client v0.7.2/go.mod h1:FEocnjn+Ngzxy6EtU9ZxXWRvQ0+pffkrBxHLnPpxwi8=
@ -1188,6 +1212,7 @@ github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@ -1248,8 +1273,8 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
github.com/sqlc-dev/sqlc v1.20.0 h1:teJJBBN9PTKLhO6IFsyhsP6JD4mD0/Db73eLOyfgrgw= github.com/sqlc-dev/sqlc v1.21.0 h1:Shtux/GLJUSMtoJupSJNoFIQgfFRQHI0LIDkwvXIQp0=
github.com/sqlc-dev/sqlc v1.20.0/go.mod h1:txy7rfJ+rgUwThYp+d1+/vONbPgR34OgVCRdRYJcoWI= github.com/sqlc-dev/sqlc v1.21.0/go.mod h1:fHPNlsaUckfRQaHNl/hat4VwsPN3ZJZe+V1fAQoGf/Y=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
@ -1270,8 +1295,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
@ -1384,27 +1410,28 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@ -1452,8 +1479,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20230724220655-d98519c11495 h1:zKGKw2WlGb8oPoRGqQ2PT8g2YoCN1w/YbbQjHXCdUWE=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp v0.0.0-20230724220655-d98519c11495/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -1972,10 +1999,10 @@ google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@ -2009,8 +2036,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -2064,7 +2091,6 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -21,16 +21,16 @@ func MustAlipayClient() *alipay.Client {
logrus.Fatalf("alipay.New err: %s", err) logrus.Fatalf("alipay.New err: %s", err)
} }
// 加载应用公钥证书 // 加载应用公钥证书
if err = client.LoadAppPublicCertFromFile(s.AppPublicCertFile); err != nil { if err = client.LoadAppCertPublicKeyFromFile(s.AppPublicCertFile); err != nil {
logrus.Fatalf("client.LoadAppPublicCertFromFile err: %s\n", err) logrus.Fatalf("client.LoadAppCertPublicKeyFromFile err: %s\n", err)
} }
// 加载支付宝根证书 // 加载支付宝根证书
if err = client.LoadAliPayRootCertFromFile(s.RootCertFile); err != nil { if err = client.LoadAliPayRootCertFromFile(s.RootCertFile); err != nil {
logrus.Fatalf("client.LoadAliPayRootCertFromFile err: %s\n", err) logrus.Fatalf("client.LoadAliPayRootCertFromFile err: %s\n", err)
} }
// 加载支付宝公钥证书 // 加载支付宝公钥证书
if err = client.LoadAliPayPublicCertFromFile(s.PublicCertFile); err != nil { if err = client.LoadAlipayCertPublicKeyFromFile(s.PublicCertFile); err != nil {
logrus.Fatalf("client.LoadAliPayPublicCertFromFile err: %s\n", err) logrus.Fatalf("client.LoadAlipayCertPublicKeyFromFile err: %s\n", err)
} }
_alipayClient = client _alipayClient = client
}) })

@ -17,6 +17,9 @@ const (
// 以下包含一些在cache中会用到的key的前缀 // 以下包含一些在cache中会用到的key的前缀
const ( const (
InfixCommentDefault = "default"
InfixCommentHots = "hots"
InfixCommentNewest = "newest"
PrefixNewestTweets = "paopao:newesttweets:" PrefixNewestTweets = "paopao:newesttweets:"
PrefixHotsTweets = "paopao:hotstweets:" PrefixHotsTweets = "paopao:hotstweets:"
PrefixFollowingTweets = "paopao:followingtweets:" PrefixFollowingTweets = "paopao:followingtweets:"
@ -29,6 +32,9 @@ const (
PrefixUserInfo = "paopao:userinfo:" PrefixUserInfo = "paopao:userinfo:"
PrefixUserInfoById = "paopao:userinfo:id:" PrefixUserInfoById = "paopao:userinfo:id:"
PrefixUserInfoByName = "paopao:userinfo:name:" PrefixUserInfoByName = "paopao:userinfo:name:"
PrefixMyFriendIds = "paopao:myfriendids:"
PrefixMyFollowIds = "paopao:myfollowids:"
PrefixTweetComment = "paopao:comment:"
KeySiteStatus = "paopao:sitestatus" KeySiteStatus = "paopao:sitestatus"
KeyHistoryMaxOnline = "history.max.online" KeyHistoryMaxOnline = "history.max.online"
) )
@ -42,6 +48,8 @@ var (
KeyOnlineUser cache.KeyPool[int64] KeyOnlineUser cache.KeyPool[int64]
KeyUserInfoById cache.KeyPool[int64] KeyUserInfoById cache.KeyPool[int64]
KeyUserInfoByName cache.KeyPool[string] KeyUserInfoByName cache.KeyPool[string]
KeyMyFriendIds cache.KeyPool[int64]
KeyMyFollowIds cache.KeyPool[int64]
) )
func initCacheKeyPool() { func initCacheKeyPool() {
@ -56,6 +64,8 @@ func initCacheKeyPool() {
KeyOnlineUser = intKeyPool[int64](poolSize, PrefixOnlineUser) KeyOnlineUser = intKeyPool[int64](poolSize, PrefixOnlineUser)
KeyUserInfoById = intKeyPool[int64](poolSize, PrefixUserInfoById) KeyUserInfoById = intKeyPool[int64](poolSize, PrefixUserInfoById)
KeyUserInfoByName = strKeyPool(poolSize, PrefixUserInfoById) KeyUserInfoByName = strKeyPool(poolSize, PrefixUserInfoById)
KeyMyFriendIds = intKeyPool[int64](poolSize, PrefixMyFriendIds)
KeyMyFollowIds = intKeyPool[int64](poolSize, PrefixMyFollowIds)
} }
func strKeyPool(size int, prefix string) cache.KeyPool[string] { func strKeyPool(size int, prefix string) cache.KeyPool[string] {

@ -26,6 +26,7 @@ var (
PostgresSetting *postgresConf PostgresSetting *postgresConf
Sqlite3Setting *sqlite3Conf Sqlite3Setting *sqlite3Conf
PprofServerSetting *httpServerConf PprofServerSetting *httpServerConf
MetricsServerSetting *httpServerConf
WebServerSetting *httpServerConf WebServerSetting *httpServerConf
AdminServerSetting *httpServerConf AdminServerSetting *httpServerConf
SpaceXServerSetting *httpServerConf SpaceXServerSetting *httpServerConf
@ -78,6 +79,7 @@ func setupSetting(suite []string, noDefault bool) error {
"MetricManager": &MetricManagerSetting, "MetricManager": &MetricManagerSetting,
"JobManager": &JobManagerSetting, "JobManager": &JobManagerSetting,
"PprofServer": &PprofServerSetting, "PprofServer": &PprofServerSetting,
"MetricsServer": &MetricsServerSetting,
"WebServer": &WebServerSetting, "WebServer": &WebServerSetting,
"AdminServer": &AdminServerSetting, "AdminServer": &AdminServerSetting,
"SpaceXServer": &SpaceXServerSetting, "SpaceXServer": &SpaceXServerSetting,

@ -11,8 +11,10 @@ Cache:
UnreadMsgExpire: 60 # 未读消息过期时间,单位秒, 默认60s UnreadMsgExpire: 60 # 未读消息过期时间,单位秒, 默认60s
UserTweetsExpire: 60 # 获取用户推文列表过期时间,单位秒, 默认60s UserTweetsExpire: 60 # 获取用户推文列表过期时间,单位秒, 默认60s
IndexTweetsExpire: 120 # 获取广场推文列表过期时间,单位秒, 默认120s IndexTweetsExpire: 120 # 获取广场推文列表过期时间,单位秒, 默认120s
TweetCommentsExpire: 180 # 获取推文评论过期时间,单位秒, 默认180s
OnlineUserExpire: 300 # 标记在线用户 过期时间,单位秒, 默认300s OnlineUserExpire: 300 # 标记在线用户 过期时间,单位秒, 默认300s
UserInfoExpire: 300 # 获取用户信息过期时间,单位秒, 默认300s UserInfoExpire: 300 # 获取用户信息过期时间,单位秒, 默认300s
UserRelationExpire: 600 # 用户关系信息过期时间,单位秒, 默认600s
EventManager: # 事件管理器的配置参数 EventManager: # 事件管理器的配置参数
MinWorker: 64 # 最小后台工作者, 设置范围[5, ++], 默认64 MinWorker: 64 # 最小后台工作者, 设置范围[5, ++], 默认64
MaxEventBuf: 128 # 最大log缓存条数, 设置范围[10, ++], 默认128 MaxEventBuf: 128 # 最大log缓存条数, 设置范围[10, ++], 默认128
@ -26,7 +28,8 @@ MetricManager: # 指标监控管理器的配置参数
MaxTickCount: 60 # 最大的循环周期, 设置范围[60, ++], 默认60 MaxTickCount: 60 # 最大的循环周期, 设置范围[60, ++], 默认60
TickWaitTime: 1 # 一个周期的等待时间,单位:秒 默认1s TickWaitTime: 1 # 一个周期的等待时间,单位:秒 默认1s
JobManager: # Cron Job理器的配置参数 JobManager: # Cron Job理器的配置参数
MaxOnlineInterval: "@every 5m" # 更新最大在线人数默认每5分钟更新一次 MaxOnlineInterval: "@every 5m" # 更新最大在线人数默认每5分钟更新一次
UpdateMetricsInterval: "@every 5m" # 更新Prometheus指标默认每5分钟更新一次
Features: Features:
Default: [] Default: []
WebServer: # Web服务 WebServer: # Web服务
@ -65,6 +68,12 @@ PprofServer: # Pprof服务
HttpPort: 6060 HttpPort: 6060
ReadTimeout: 60 ReadTimeout: 60
WriteTimeout: 60 WriteTimeout: 60
MetricsServer: # Prometheus Metrics服务
RunMode: debug
HttpIp: 0.0.0.0
HttpPort: 6080
ReadTimeout: 60
WriteTimeout: 60
FrontendWebServer: # Web前端静态资源服务 FrontendWebServer: # Web前端静态资源服务
RunMode: debug RunMode: debug
HttpIp: 0.0.0.0 HttpIp: 0.0.0.0

@ -23,6 +23,7 @@ const (
TableAttachment = "attachment" TableAttachment = "attachment"
TableCaptcha = "captcha" TableCaptcha = "captcha"
TableComment = "comment" TableComment = "comment"
TableCommentMetric = "comment_metric"
TableCommentContent = "comment_content" TableCommentContent = "comment_content"
TableCommentReply = "comment_reply" TableCommentReply = "comment_reply"
TableFollowing = "following" TableFollowing = "following"
@ -39,6 +40,7 @@ const (
TablePostStar = "post_star" TablePostStar = "post_star"
TableTag = "tag" TableTag = "tag"
TableUser = "user" TableUser = "user"
TableUserMetric = "user_metric"
TableWalletRecharge = "wallet_recharge" TableWalletRecharge = "wallet_recharge"
TableWalletStatement = "wallet_statement" TableWalletStatement = "wallet_statement"
) )

@ -102,8 +102,10 @@ type cacheConf struct {
UnreadMsgExpire int64 UnreadMsgExpire int64
UserTweetsExpire int64 UserTweetsExpire int64
IndexTweetsExpire int64 IndexTweetsExpire int64
TweetCommentsExpire int64
OnlineUserExpire int64 OnlineUserExpire int64
UserInfoExpire int64 UserInfoExpire int64
UserRelationExpire int64
} }
type eventManagerConf struct { type eventManagerConf struct {
@ -123,7 +125,8 @@ type metricManagerConf struct {
} }
type jobManagerConf struct { type jobManagerConf struct {
MaxOnlineInterval string MaxOnlineInterval string
UpdateMetricsInterval string
} }
type cacheIndexConf struct { type cacheIndexConf struct {
@ -344,6 +347,7 @@ func (s *databaseConf) TableNames() (res TableNameMap) {
TableAttachment, TableAttachment,
TableCaptcha, TableCaptcha,
TableComment, TableComment,
TableCommentMetric,
TableCommentContent, TableCommentContent,
TableCommentReply, TableCommentReply,
TableFollowing, TableFollowing,
@ -360,6 +364,7 @@ func (s *databaseConf) TableNames() (res TableNameMap) {
TablePostStar, TablePostStar,
TableTag, TableTag,
TableUser, TableUser,
TableUserMetric,
TableWalletRecharge, TableWalletRecharge,
TableWalletStatement, TableWalletStatement,
} }

@ -21,6 +21,7 @@ type CommentService interface {
// CommentManageService 评论管理服务 // CommentManageService 评论管理服务
type CommentManageService interface { type CommentManageService interface {
HighlightComment(userId, commentId int64) (int8, error)
DeleteComment(comment *ms.Comment) error DeleteComment(comment *ms.Comment) error
CreateComment(comment *ms.Comment) (*ms.Comment, error) CreateComment(comment *ms.Comment) (*ms.Comment, error)
CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error) CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error)

@ -15,9 +15,6 @@ type DataService interface {
// 话题服务 // 话题服务
TopicService TopicService
// 广场泡泡服务
// IndexPostsService
// 推文服务 // 推文服务
TweetService TweetService
TweetManageService TweetManageService
@ -25,6 +22,7 @@ type DataService interface {
// 推文指标服务 // 推文指标服务
TweetMetricServantA TweetMetricServantA
CommentMetricServantA
// 评论服务 // 评论服务
CommentService CommentService
@ -34,6 +32,7 @@ type DataService interface {
UserManageService UserManageService
ContactManageService ContactManageService
FollowingManageService FollowingManageService
UserRelationService
// 安全服务 // 安全服务
SecurityService SecurityService

@ -13,8 +13,15 @@ type TweetMetric struct {
UpvoteCount int64 UpvoteCount int64
CollectionCount int64 CollectionCount int64
ShareCount int64 ShareCount int64
ThumbdownCount int64 ThumbsUpCount int64
ThumbupCount int64 ThumbsDownCount int64
}
type CommentMetric struct {
CommentId int64
ReplyCount int32
ThumbsUpCount int32
ThumbsDownCount int32
} }
func (m *TweetMetric) RankScore(motivationFactor int) int64 { func (m *TweetMetric) RankScore(motivationFactor int) int64 {
@ -23,3 +30,10 @@ func (m *TweetMetric) RankScore(motivationFactor int) int64 {
} }
return (m.CommentCount + m.UpvoteCount*2 + m.CollectionCount*4 + m.ShareCount*8) * int64(motivationFactor) return (m.CommentCount + m.UpvoteCount*2 + m.CollectionCount*4 + m.ShareCount*8) * int64(motivationFactor)
} }
func (m *CommentMetric) RankScore(motivationFactor int) int64 {
if motivationFactor == 0 {
motivationFactor = 1
}
return int64(m.ReplyCount*2+m.ThumbsUpCount*4-m.ThumbsDownCount) * int64(motivationFactor)
}

@ -9,7 +9,19 @@ import (
) )
type TweetMetricServantA interface { type TweetMetricServantA interface {
UpdateRankScore(metric *cs.TweetMetric) error UpdateTweetMetric(metric *cs.TweetMetric) error
AddTweetMetric(postId int64) error AddTweetMetric(postId int64) error
DeleteTweetMetric(postId int64) error DeleteTweetMetric(postId int64) error
} }
type CommentMetricServantA interface {
UpdateCommentMetric(metric *cs.CommentMetric) error
AddCommentMetric(commentId int64) error
DeleteCommentMetric(commentId int64) error
}
type UserMetricServantA interface {
UpdateUserMetric(userId int64, action uint8) error
AddUserMetric(userId int64) error
DeleteUserMetric(userId int64) error
}

@ -37,3 +37,11 @@ type FollowingManageService interface {
GetFollowCount(userId int64) (int64, int64, error) GetFollowCount(userId int64) (int64, int64, error)
IsFollow(userId int64, followId int64) bool IsFollow(userId int64, followId int64) bool
} }
// UserRelationService 用户关系服务
type UserRelationService interface {
MyFriendIds(userId int64) ([]int64, error)
MyFollowIds(userId int64) ([]int64, error)
IsMyFriend(userId int64, friendIds ...int64) (map[int64]bool, error)
IsMyFollow(userId int64, followIds ...int64) (map[int64]bool, error)
}

@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"github.com/RoaringBitmap/roaring/roaring64"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
@ -59,3 +60,47 @@ func (s *cacheDataService) GetUserByUsername(username string) (res *ms.User, err
} }
return return
} }
func (s *cacheDataService) IsMyFriend(userId int64, friendIds ...int64) (res map[int64]bool, err error) {
size := len(friendIds)
res = make(map[int64]bool, size)
if size == 0 {
return
}
// 从缓存中获取
key := conf.KeyMyFriendIds.Get(userId)
if data, xerr := s.ac.Get(key); xerr == nil {
bitmap := roaring64.New()
if err = bitmap.UnmarshalBinary(data); err == nil {
for _, friendId := range friendIds {
res[friendId] = bitmap.Contains(uint64(friendId))
}
return
}
}
// 直接查库并触发缓存更新事件
OnCacheMyFriendIdsEvent(s.DataService, userId)
return s.DataService.IsMyFriend(userId, friendIds...)
}
func (s *cacheDataService) IsMyFollow(userId int64, followIds ...int64) (res map[int64]bool, err error) {
size := len(followIds)
res = make(map[int64]bool, size)
if size == 0 {
return
}
// 从缓存中获取
key := conf.KeyMyFollowIds.Get(userId)
if data, xerr := s.ac.Get(key); xerr == nil {
bitmap := roaring64.New()
if err = bitmap.UnmarshalBinary(data); err == nil {
for _, followId := range followIds {
res[followId] = bitmap.Contains(uint64(followId))
}
return
}
}
// 直接查库并触发缓存更新事件
OnCacheMyFollowIdsEvent(s.DataService, userId, key)
return s.DataService.IsMyFollow(userId, followIds...)
}

@ -9,23 +9,23 @@ import (
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"github.com/RoaringBitmap/roaring/roaring64"
"github.com/alimy/tryst/event" "github.com/alimy/tryst/event"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/events" "github.com/rocboss/paopao-ce/internal/events"
"github.com/sirupsen/logrus"
) )
type expireIndexTweetsEvent struct { type expireIndexTweetsEvent struct {
event.UnimplementedEvent event.UnimplementedEvent
tweet *ms.Post
ac core.AppCache ac core.AppCache
keysPattern []string keysPattern []string
} }
type expireHotsTweetsEvent struct { type expireHotsTweetsEvent struct {
event.UnimplementedEvent event.UnimplementedEvent
tweet *ms.Post
ac core.AppCache ac core.AppCache
keyPattern string keyPattern string
} }
@ -46,21 +46,38 @@ type cacheUserInfoEvent struct {
expire int64 expire int64
} }
func onExpireIndexTweetEvent(tweet *ms.Post) { type cacheMyFriendIdsEvent struct {
event.UnimplementedEvent
ac core.AppCache
urs core.UserRelationService
userIds []int64
expire int64
}
type cacheMyFollowIdsEvent struct {
event.UnimplementedEvent
ac core.AppCache
urs core.UserRelationService
userId int64
key string
expire int64
}
func OnExpireIndexTweetEvent(userId int64) {
// TODO: 这里暴躁的将所有 最新/热门/关注 的推文列表缓存都过期掉,后续需要更精细话处理
events.OnEvent(&expireIndexTweetsEvent{ events.OnEvent(&expireIndexTweetsEvent{
tweet: tweet, ac: _appCache,
ac: _appCache,
keysPattern: []string{ keysPattern: []string{
conf.PrefixIdxTweetsNewest + "*", conf.PrefixIdxTweetsNewest + "*",
conf.PrefixIdxTweetsHots + "*", conf.PrefixIdxTweetsHots + "*",
fmt.Sprintf("%s%d:*", conf.PrefixUserTweets, tweet.UserID), conf.PrefixIdxTweetsFollowing + "*",
fmt.Sprintf("%s%d:*", conf.PrefixUserTweets, userId),
}, },
}) })
} }
func onExpireHotsTweetEvent(tweet *ms.Post) { func OnExpireHotsTweetEvent() {
events.OnEvent(&expireHotsTweetsEvent{ events.OnEvent(&expireHotsTweetsEvent{
tweet: tweet,
ac: _appCache, ac: _appCache,
keyPattern: conf.PrefixHotsTweets + "*", keyPattern: conf.PrefixHotsTweets + "*",
}) })
@ -83,6 +100,34 @@ func onCacheUserInfoEvent(key string, data *ms.User) {
}) })
} }
func OnCacheMyFriendIdsEvent(urs core.UserRelationService, userIds ...int64) {
if len(userIds) == 0 {
return
}
events.OnEvent(&cacheMyFriendIdsEvent{
userIds: userIds,
urs: urs,
ac: _appCache,
expire: conf.CacheSetting.UserRelationExpire,
})
}
func OnCacheMyFollowIdsEvent(urs core.UserRelationService, userId int64, key ...string) {
cacheKey := ""
if len(key) > 0 {
cacheKey = key[0]
} else {
cacheKey = conf.KeyMyFollowIds.Get(userId)
}
events.OnEvent(&cacheMyFollowIdsEvent{
userId: userId,
urs: urs,
key: cacheKey,
ac: _appCache,
expire: conf.CacheSetting.UserRelationExpire,
})
}
func (e *expireIndexTweetsEvent) Name() string { func (e *expireIndexTweetsEvent) Name() string {
return "expireIndexTweetsEvent" return "expireIndexTweetsEvent"
} }
@ -127,3 +172,49 @@ func (e *cacheUserInfoEvent) Action() (err error) {
} }
return return
} }
func (e *cacheMyFriendIdsEvent) Name() string {
return "cacheMyFriendIdsEvent"
}
func (e *cacheMyFriendIdsEvent) Action() error {
logrus.Debug("cacheMyFriendIdsEvent action runnging")
for _, userId := range e.userIds {
myFriendIds, err := e.urs.MyFriendIds(userId)
if err != nil {
return err
}
bitmap := roaring64.New()
for _, friendId := range myFriendIds {
bitmap.Add(uint64(friendId))
}
data, err := bitmap.MarshalBinary()
if err != nil {
return err
}
e.ac.Set(conf.KeyMyFriendIds.Get(userId), data, e.expire)
}
return nil
}
func (e *cacheMyFollowIdsEvent) Name() string {
return "cacheMyFollowIdsEvent"
}
func (e *cacheMyFollowIdsEvent) Action() (err error) {
logrus.Debug("cacheMyFollowIdsEvent action runnging")
myFollowIds, err := e.urs.MyFollowIds(e.userId)
if err != nil {
return err
}
bitmap := roaring64.New()
for _, followId := range myFollowIds {
bitmap.Add(uint64(followId))
}
data, err := bitmap.MarshalBinary()
if err != nil {
return err
}
e.ac.Set(e.key, data, e.expire)
return nil
}

@ -19,22 +19,22 @@ func (s *eventCacheIndexSrv) SendAction(act core.IdxAct, post *ms.Post) {
err := error(nil) err := error(nil)
switch act { switch act {
case core.IdxActUpdatePost: case core.IdxActUpdatePost:
err = s.tms.UpdateRankScore(&cs.TweetMetric{ err = s.tms.UpdateTweetMetric(&cs.TweetMetric{
PostId: post.ID, PostId: post.ID,
CommentCount: post.CommentCount, CommentCount: post.CommentCount,
UpvoteCount: post.UpvoteCount, UpvoteCount: post.UpvoteCount,
CollectionCount: post.CollectionCount, CollectionCount: post.CollectionCount,
ShareCount: post.ShareCount, ShareCount: post.ShareCount,
}) })
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
case core.IdxActCreatePost: case core.IdxActCreatePost:
err = s.tms.AddTweetMetric(post.ID) err = s.tms.AddTweetMetric(post.ID)
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
case core.IdxActDeletePost: case core.IdxActDeletePost:
err = s.tms.DeleteTweetMetric(post.ID) err = s.tms.DeleteTweetMetric(post.ID)
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
case core.IdxActStickPost, core.IdxActVisiblePost: case core.IdxActStickPost, core.IdxActVisiblePost:
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
} }
if err != nil { if err != nil {
logrus.Errorf("eventCacheIndexSrv.SendAction(%s) occurs error: %s", act, err) logrus.Errorf("eventCacheIndexSrv.SendAction(%s) occurs error: %s", act, err)

@ -5,6 +5,7 @@
package jinzhu package jinzhu
import ( import (
"fmt"
"time" "time"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
@ -61,20 +62,21 @@ func (s *commentSrv) GetCommentThumbsMap(userId int64, tweetId int64) (cs.Commen
} }
func (s *commentSrv) GetComments(tweetId int64, style cs.StyleCommentType, limit int, offset int) (res []*ms.Comment, total int64, err error) { func (s *commentSrv) GetComments(tweetId int64, style cs.StyleCommentType, limit int, offset int) (res []*ms.Comment, total int64, err error) {
// TODO: 需要优化一下,更精细的调整评论排序策略 db := s.db.Table(_comment_)
sort := "id ASC" sort := "is_essence DESC, id ASC"
switch style { switch style {
case cs.StyleCommentHots: case cs.StyleCommentHots:
// TOOD: 暂时简单排序,后续需要根据 rank_score=评论回复数*2+点赞*4-点踩, order byrank_score DESC // rank_score=评论回复数*2+点赞*4-点踩, order byrank_score DESC
sort = "thumbs_up_count DESC, id DESC" db = db.Joins(fmt.Sprintf("LEFT JOIN %s m ON %s.id=m.comment_id AND m.is_del=0", _commentMetric_, _comment_))
sort = fmt.Sprintf("is_essence DESC, m.rank_score DESC, %s.id DESC", _comment_)
case cs.StyleCommentNewest: case cs.StyleCommentNewest:
sort = "id DESC" sort = "is_essence DESC, id DESC"
case cs.StyleCommentDefault: case cs.StyleCommentDefault:
fallthrough fallthrough
default: default:
// sort = "id ASC" // nothing
} }
db := s.db.Table(_comment_).Where("post_id=?", tweetId) db = db.Where("post_id=?", tweetId)
if err = db.Count(&total).Error; err != nil { if err = db.Count(&total).Error; err != nil {
return return
} }
@ -117,11 +119,9 @@ func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyForma
"comment_id IN ?": ids, "comment_id IN ?": ids,
"ORDER": "id ASC", "ORDER": "id ASC",
}, 0, 0) }, 0, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
userIds := []int64{} userIds := []int64{}
for _, reply := range replies { for _, reply := range replies {
userIds = append(userIds, reply.UserID, reply.AtUserID) userIds = append(userIds, reply.UserID, reply.AtUserID)
@ -142,44 +142,61 @@ func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyForma
replyFormated.AtUser = user.Format() replyFormated.AtUser = user.Format()
} }
} }
repliesFormated = append(repliesFormated, replyFormated) repliesFormated = append(repliesFormated, replyFormated)
} }
return repliesFormated, nil return repliesFormated, nil
} }
func (s *commentManageSrv) DeleteComment(comment *ms.Comment) error { func (s *commentManageSrv) HighlightComment(userId, commentId int64) (res int8, err error) {
post := &dbr.Post{}
comment := &dbr.Comment{}
db := s.db.Model(comment)
if err = db.Where("id=?", commentId).First(comment).Error; err != nil {
return
}
if err = s.db.Table(_post_).Where("id=?", comment.PostID).First(post).Error; err != nil {
return
}
if post.UserID != userId {
return 0, cs.ErrNoPermission
}
comment.IsEssence = 1 - comment.IsEssence
return comment.IsEssence, db.Save(comment).Error
}
func (s *commentManageSrv) DeleteComment(comment *ms.Comment) (err error) {
db := s.db.Begin() db := s.db.Begin()
defer db.Rollback() defer db.Rollback()
if err = comment.Delete(db); err != nil {
err := comment.Delete(s.db) return
if err != nil {
return err
} }
err = db.Model(&dbr.TweetCommentThumbs{}).Where("user_id=? AND tweet_id=? AND comment_id=?", comment.UserID, comment.PostID, comment.ID).Updates(map[string]any{ err = db.Model(&dbr.TweetCommentThumbs{}).Where("user_id=? AND tweet_id=? AND comment_id=?", comment.UserID, comment.PostID, comment.ID).Updates(map[string]any{
"deleted_on": time.Now().Unix(), "deleted_on": time.Now().Unix(),
"is_del": 1, "is_del": 1,
}).Error }).Error
if err != nil { if err != nil {
return err return
} }
db.Commit() db.Commit()
return nil return
} }
func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) { func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) {
return comment.Create(s.db) return comment.Create(s.db)
} }
func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error) { func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (res *ms.CommentReply, err error) {
return reply.Create(s.db) if res, err = reply.Create(s.db); err == nil {
// 宽松处理错误
s.db.Table(_comment_).Where("id=?", reply.CommentID).Update("reply_count", gorm.Expr("reply_count+1"))
}
return
} }
func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error) { func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error) {
db := s.db.Begin() db := s.db.Begin()
defer db.Rollback() defer db.Rollback()
err = reply.Delete(s.db) err = reply.Delete(s.db)
if err != nil { if err != nil {
return return
@ -192,6 +209,8 @@ func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error
if err != nil { if err != nil {
return return
} }
// 宽松处理错误
db.Table(_comment_).Where("id=?", reply.CommentID).Update("reply_count", gorm.Expr("reply_count-1"))
db.Commit() db.Commit()
return return
} }

@ -17,6 +17,8 @@ type Comment struct {
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
IP string `json:"ip"` IP string `json:"ip"`
IPLoc string `json:"ip_loc"` IPLoc string `json:"ip_loc"`
IsEssence int8 `json:"is_essense"`
ReplyCount int32 `json:"reply_count"`
ThumbsUpCount int32 `json:"thumbs_up_count"` ThumbsUpCount int32 `json:"thumbs_up_count"`
ThumbsDownCount int32 `json:"-"` ThumbsDownCount int32 `json:"-"`
} }
@ -29,7 +31,9 @@ type CommentFormated struct {
Contents []*CommentContent `json:"contents"` Contents []*CommentContent `json:"contents"`
Replies []*CommentReplyFormated `json:"replies"` Replies []*CommentReplyFormated `json:"replies"`
IPLoc string `json:"ip_loc"` IPLoc string `json:"ip_loc"`
ReplyCount int32 `json:"reply_count"`
ThumbsUpCount int32 `json:"thumbs_up_count"` ThumbsUpCount int32 `json:"thumbs_up_count"`
IsEssence int8 `json:"is_essence"`
IsThumbsUp int8 `json:"is_thumbs_up"` IsThumbsUp int8 `json:"is_thumbs_up"`
IsThumbsDown int8 `json:"is_thumbs_down"` IsThumbsDown int8 `json:"is_thumbs_down"`
CreatedOn int64 `json:"created_on"` CreatedOn int64 `json:"created_on"`
@ -48,7 +52,9 @@ func (c *Comment) Format() *CommentFormated {
Contents: []*CommentContent{}, Contents: []*CommentContent{},
Replies: []*CommentReplyFormated{}, Replies: []*CommentReplyFormated{},
IPLoc: c.IPLoc, IPLoc: c.IPLoc,
ReplyCount: c.ReplyCount,
ThumbsUpCount: c.ThumbsUpCount, ThumbsUpCount: c.ThumbsUpCount,
IsEssence: c.IsEssence,
IsThumbsUp: types.No, IsThumbsUp: types.No,
IsThumbsDown: types.No, IsThumbsDown: types.No,
CreatedOn: c.CreatedOn, CreatedOn: c.CreatedOn,
@ -116,7 +122,6 @@ func (c *Comment) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) {
func (c *Comment) Create(db *gorm.DB) (*Comment, error) { func (c *Comment) Create(db *gorm.DB) (*Comment, error) {
err := db.Create(&c).Error err := db.Create(&c).Error
return c, err return c, err
} }

@ -19,13 +19,53 @@ type PostMetric struct {
MotivationFactor int MotivationFactor int
} }
func (p *PostMetric) Create(db *gorm.DB) (*PostMetric, error) { type CommentMetric struct {
err := db.Create(&p).Error *Model
return p, err CommentId int64
RankScore int64
IncentiveScore int
DecayFactor int
MotivationFactor int
}
type UserMetric struct {
*Model
UserId int64
TweetsCount int
LatestTrendsOn int64
}
func (m *PostMetric) Create(db *gorm.DB) (*PostMetric, error) {
err := db.Create(&m).Error
return m, err
}
func (m *PostMetric) Delete(db *gorm.DB) error {
return db.Model(m).Where("post_id", m.PostId).Updates(map[string]any{
"deleted_on": time.Now().Unix(),
"is_del": 1,
}).Error
}
func (m *CommentMetric) Create(db *gorm.DB) (*CommentMetric, error) {
err := db.Create(&m).Error
return m, err
}
func (m *CommentMetric) Delete(db *gorm.DB) error {
return db.Model(m).Where("comment_id", m.CommentId).Updates(map[string]any{
"deleted_on": time.Now().Unix(),
"is_del": 1,
}).Error
}
func (m *UserMetric) Create(db *gorm.DB) (*UserMetric, error) {
err := db.Create(&m).Error
return m, err
} }
func (p *PostMetric) Delete(db *gorm.DB) error { func (m *UserMetric) Delete(db *gorm.DB) error {
return db.Model(p).Where("post_id", p.PostId).Updates(map[string]any{ return db.Model(m).Where("user_id", m.UserId).Updates(map[string]any{
"deleted_on": time.Now().Unix(), "deleted_on": time.Now().Unix(),
"is_del": 1, "is_del": 1,
}).Error }).Error

@ -28,12 +28,14 @@ type User struct {
} }
type UserFormated struct { type UserFormated struct {
ID int64 `db:"id" json:"id"` ID int64 `db:"id" json:"id"`
Nickname string `json:"nickname"` Nickname string `json:"nickname"`
Username string `json:"username"` Username string `json:"username"`
Status int `json:"status"` Status int `json:"status"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
IsFriend bool `json:"is_friend"`
IsFollowing bool `json:"is_following"`
} }
func (u *User) Format() *UserFormated { func (u *User) Format() *UserFormated {

@ -15,6 +15,7 @@ var (
_attachment_ string _attachment_ string
_captcha_ string _captcha_ string
_comment_ string _comment_ string
_commentMetric_ string
_commentContent_ string _commentContent_ string
_commentReply_ string _commentReply_ string
_following_ string _following_ string
@ -31,6 +32,7 @@ var (
_postStar_ string _postStar_ string
_tag_ string _tag_ string
_user_ string _user_ string
_userMetric_ string
_walletRecharge_ string _walletRecharge_ string
_walletStatement_ string _walletStatement_ string
) )
@ -42,6 +44,7 @@ func initTableName() {
_attachment_ = m[conf.TableAttachment] _attachment_ = m[conf.TableAttachment]
_captcha_ = m[conf.TableCaptcha] _captcha_ = m[conf.TableCaptcha]
_comment_ = m[conf.TableComment] _comment_ = m[conf.TableComment]
_commentMetric_ = m[conf.TableCommentMetric]
_commentContent_ = m[conf.TableCommentContent] _commentContent_ = m[conf.TableCommentContent]
_commentReply_ = m[conf.TableCommentReply] _commentReply_ = m[conf.TableCommentReply]
_following_ = m[conf.TableFollowing] _following_ = m[conf.TableFollowing]
@ -58,6 +61,7 @@ func initTableName() {
_postStar_ = m[conf.TablePostStar] _postStar_ = m[conf.TablePostStar]
_tag_ = m[conf.TableTag] _tag_ = m[conf.TableTag]
_user_ = m[conf.TableUser] _user_ = m[conf.TableUser]
_userMetric_ = m[conf.TableUserMetric]
_walletRecharge_ = m[conf.TableWalletRecharge] _walletRecharge_ = m[conf.TableWalletRecharge]
_walletStatement_ = m[conf.TableWalletStatement] _walletStatement_ = m[conf.TableWalletStatement]
} }

@ -38,9 +38,11 @@ type dataSrv struct {
core.TweetMetricServantA core.TweetMetricServantA
core.CommentService core.CommentService
core.CommentManageService core.CommentManageService
core.CommentMetricServantA
core.UserManageService core.UserManageService
core.ContactManageService core.ContactManageService
core.FollowingManageService core.FollowingManageService
core.UserRelationService
core.SecurityService core.SecurityService
core.AttachmentCheckService core.AttachmentCheckService
} }
@ -56,10 +58,12 @@ func NewDataService() (core.DataService, core.VersionInfo) {
lazyInitial() lazyInitial()
db := conf.MustGormDB() db := conf.MustGormDB()
pvs := security.NewPhoneVerifyService() pvs := security.NewPhoneVerifyService()
tms := NewTweetMetricServentA(db) tms := newTweetMetricServentA(db)
cms := newCommentMetricServentA(db)
cis := cache.NewEventCacheIndexSrv(tms) cis := cache.NewEventCacheIndexSrv(tms)
ds := &dataSrv{ ds := &dataSrv{
TweetMetricServantA: tms, TweetMetricServantA: tms,
CommentMetricServantA: cms,
WalletService: newWalletService(db), WalletService: newWalletService(db),
MessageService: newMessageService(db), MessageService: newMessageService(db),
TopicService: newTopicService(db), TopicService: newTopicService(db),
@ -71,6 +75,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
UserManageService: newUserManageService(db), UserManageService: newUserManageService(db),
ContactManageService: newContactManageService(db), ContactManageService: newContactManageService(db),
FollowingManageService: newFollowingManageService(db), FollowingManageService: newFollowingManageService(db),
UserRelationService: newUserRelationService(db),
SecurityService: newSecurityService(db, pvs), SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(), AttachmentCheckService: security.NewAttachmentCheckService(),
} }

@ -15,7 +15,15 @@ type tweetMetricSrvA struct {
db *gorm.DB db *gorm.DB
} }
func (s *tweetMetricSrvA) UpdateRankScore(metric *cs.TweetMetric) error { type commentMetricSrvA struct {
db *gorm.DB
}
type userMetricSrvA struct {
db *gorm.DB
}
func (s *tweetMetricSrvA) UpdateTweetMetric(metric *cs.TweetMetric) error {
return s.db.Transaction(func(tx *gorm.DB) (err error) { return s.db.Transaction(func(tx *gorm.DB) (err error) {
postMetric := &dbr.PostMetric{PostId: metric.PostId} postMetric := &dbr.PostMetric{PostId: metric.PostId}
db := s.db.Model(postMetric).Where("post_id=?", metric.PostId) db := s.db.Model(postMetric).Where("post_id=?", metric.PostId)
@ -35,8 +43,54 @@ func (s *tweetMetricSrvA) DeleteTweetMetric(postId int64) (err error) {
return (&dbr.PostMetric{PostId: postId}).Delete(s.db) return (&dbr.PostMetric{PostId: postId}).Delete(s.db)
} }
func NewTweetMetricServentA(db *gorm.DB) core.TweetMetricServantA { func (s *commentMetricSrvA) UpdateCommentMetric(metric *cs.CommentMetric) error {
return s.db.Transaction(func(tx *gorm.DB) (err error) {
commentMetric := &dbr.CommentMetric{CommentId: metric.CommentId}
db := s.db.Model(commentMetric).Where("comment_id=?", metric.CommentId)
db.First(commentMetric)
commentMetric.RankScore = metric.RankScore(commentMetric.MotivationFactor)
err = db.Save(commentMetric).Error
return
})
}
func (s *commentMetricSrvA) AddCommentMetric(commentId int64) (err error) {
_, err = (&dbr.CommentMetric{CommentId: commentId}).Create(s.db)
return
}
func (s *commentMetricSrvA) DeleteCommentMetric(commentId int64) (err error) {
return (&dbr.CommentMetric{CommentId: commentId}).Delete(s.db)
}
func (s *userMetricSrvA) UpdateUserMetric(userId int64, action uint8) error {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) AddUserMetric(userId int64) (err error) {
_, err = (&dbr.UserMetric{UserId: userId}).Create(s.db)
return
}
func (s *userMetricSrvA) DeleteUserMetric(userId int64) (err error) {
return (&dbr.UserMetric{UserId: userId}).Delete(s.db)
}
func newTweetMetricServentA(db *gorm.DB) core.TweetMetricServantA {
return &tweetMetricSrvA{ return &tweetMetricSrvA{
db: db, db: db,
} }
} }
func newCommentMetricServentA(db *gorm.DB) core.CommentMetricServantA {
return &commentMetricSrvA{
db: db,
}
}
func newUserMetricServentA(db *gorm.DB) core.UserMetricServantA {
return &userMetricSrvA{
db: db,
}
}

@ -21,12 +21,22 @@ type userManageSrv struct {
db *gorm.DB db *gorm.DB
} }
type userRelationSrv struct {
db *gorm.DB
}
func newUserManageService(db *gorm.DB) core.UserManageService { func newUserManageService(db *gorm.DB) core.UserManageService {
return &userManageSrv{ return &userManageSrv{
db: db, db: db,
} }
} }
func newUserRelationService(db *gorm.DB) core.UserRelationService {
return &userRelationSrv{
db: db,
}
}
func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) { func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) {
user := &dbr.User{ user := &dbr.User{
Model: &dbr.Model{ Model: &dbr.Model{
@ -83,3 +93,57 @@ func (s *userManageSrv) GetRegisterUserCount() (res int64, err error) {
err = s.db.Model(&dbr.User{}).Count(&res).Error err = s.db.Model(&dbr.User{}).Count(&res).Error
return return
} }
func (s *userRelationSrv) MyFriendIds(userId int64) (res []int64, err error) {
err = s.db.Table(_contact_).Where("user_id=?", userId).Select("friend_id").Find(&res).Error
return
}
func (s *userRelationSrv) MyFollowIds(userId int64) (res []int64, err error) {
err = s.db.Table(_following_).Where("user_id=?", userId).Select("follow_id").Find(&res).Error
return
}
func (s *userRelationSrv) IsMyFriend(userId int64, friendIds ...int64) (map[int64]bool, error) {
size := len(friendIds)
res := make(map[int64]bool, size)
if size == 0 {
return res, nil
}
myFriendIds, err := s.MyFriendIds(userId)
if err != nil {
return nil, err
}
for _, friendId := range friendIds {
res[friendId] = false
for _, myFriendId := range myFriendIds {
if friendId == myFriendId {
res[friendId] = true
break
}
}
}
return res, nil
}
func (s *userRelationSrv) IsMyFollow(userId int64, followIds ...int64) (map[int64]bool, error) {
size := len(followIds)
res := make(map[int64]bool, size)
if size == 0 {
return res, nil
}
myFollowIds, err := s.MyFollowIds(userId)
if err != nil {
return nil, err
}
for _, followId := range followIds {
res[followId] = false
for _, myFollowId := range myFollowIds {
if followId == myFollowId {
res[followId] = true
break
}
}
}
return res, nil
}

@ -65,6 +65,11 @@ func (s *commentManageSrv) DeleteComment(comment *ms.Comment) error {
return nil return nil
} }
func (s *commentManageSrv) HighlightComment(userId, commentId int64) (res int8, err error) {
// TODO
return 0, cs.ErrNotImplemented
}
func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) { func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) {
// TODO // TODO
debug.NotImplemented() debug.NotImplemented()

@ -14,7 +14,15 @@ type tweetMetricSrvA struct {
*pgxSrv *pgxSrv
} }
func (s *tweetMetricSrvA) UpdateRankScore(metric *cs.TweetMetric) error { type commentMetricSrvA struct {
*pgxSrv
}
type userMetricSrvA struct {
*pgxSrv
}
func (s *tweetMetricSrvA) UpdateTweetMetric(metric *cs.TweetMetric) error {
// TODO // TODO
return cs.ErrNotImplemented return cs.ErrNotImplemented
} }
@ -29,8 +37,50 @@ func (s *tweetMetricSrvA) DeleteTweetMetric(postId int64) (err error) {
return cs.ErrNotImplemented return cs.ErrNotImplemented
} }
func NewTweetMetricServentA(db *pgx.Conn) core.TweetMetricServantA { func (s *commentMetricSrvA) UpdateCommentMetric(metric *cs.CommentMetric) error {
// TODO
return cs.ErrNotImplemented
}
func (s *commentMetricSrvA) AddCommentMetric(commentId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func (s *commentMetricSrvA) DeleteCommentMetric(commentId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) UpdateUserMetric(userId int64, action uint8) error {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) AddUserMetric(userId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) DeleteUserMetric(userId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func newTweetMetricServentA(db *pgx.Conn) core.TweetMetricServantA {
return &tweetMetricSrvA{ return &tweetMetricSrvA{
pgxSrv: newPgxSrv(db), pgxSrv: newPgxSrv(db),
} }
} }
func newCommentMetricServentA(db *pgx.Conn) core.CommentMetricServantA {
return &commentMetricSrvA{
pgxSrv: newPgxSrv(db),
}
}
func newUserMetricServentA(db *pgx.Conn) core.UserMetricServantA {
return &userMetricSrvA{
pgxSrv: newPgxSrv(db),
}
}

@ -32,9 +32,11 @@ type dataSrv struct {
core.UserManageService core.UserManageService
core.ContactManageService core.ContactManageService
core.FollowingManageService core.FollowingManageService
core.UserRelationService
core.SecurityService core.SecurityService
core.AttachmentCheckService core.AttachmentCheckService
core.TweetMetricServantA core.TweetMetricServantA
core.CommentMetricServantA
} }
type webDataSrvA struct { type webDataSrvA struct {
@ -47,10 +49,12 @@ type webDataSrvA struct {
func NewDataService() (core.DataService, core.VersionInfo) { func NewDataService() (core.DataService, core.VersionInfo) {
db := pgxDB() db := pgxDB()
pvs := security.NewPhoneVerifyService() pvs := security.NewPhoneVerifyService()
tms := NewTweetMetricServentA(db) cms := newCommentMetricServentA(db)
tms := newTweetMetricServentA(db)
cis := cache.NewEventCacheIndexSrv(tms) cis := cache.NewEventCacheIndexSrv(tms)
ds := &dataSrv{ ds := &dataSrv{
TweetMetricServantA: tms, TweetMetricServantA: tms,
CommentMetricServantA: cms,
WalletService: newWalletService(db), WalletService: newWalletService(db),
MessageService: newMessageService(db), MessageService: newMessageService(db),
TopicService: newTopicService(db), TopicService: newTopicService(db),
@ -62,6 +66,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
UserManageService: newUserManageService(db), UserManageService: newUserManageService(db),
ContactManageService: newContactManageService(db), ContactManageService: newContactManageService(db),
FollowingManageService: newFollowingManageService(db), FollowingManageService: newFollowingManageService(db),
UserRelationService: newUserRelationService(db),
SecurityService: newSecurityService(db, pvs), SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(), AttachmentCheckService: security.NewAttachmentCheckService(),
} }

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: core.sql // source: core.sql
package pg package pg

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pg package pg

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pg package pg

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: authrity.sql // source: authrity.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: comments.sql // source: comments.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: contacts.sql // source: contacts.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: following.sql // source: following.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: messages.sql // source: messages.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: security.sql // source: security.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: timeline.sql // source: timeline.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: topics.sql // source: topics.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: tweets.sql // source: tweets.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: user.sql // source: user.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: wallet.sql // source: wallet.sql
package pga package pga

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: authrity.sql // source: authrity.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: comments.sql // source: comments.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: contacts.sql // source: contacts.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: following.sql // source: following.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: messages.sql // source: messages.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: security.sql // source: security.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: timeline.sql // source: timeline.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: topics.sql // source: topics.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: tweets.sql // source: tweets.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: user.sql // source: user.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
// source: wallet.sql // source: wallet.sql
package pgc package pgc

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.20.0 // sqlc v1.21.0
package pg package pg

@ -7,6 +7,7 @@ package slonik
import ( import (
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/pkg/debug" "github.com/rocboss/paopao-ce/pkg/debug"
) )
@ -19,6 +20,10 @@ type userManageSrv struct {
*pgxSrv *pgxSrv
} }
type userRelationSrv struct {
*pgxSrv
}
func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) { func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) {
// TODO // TODO
debug.NotImplemented() debug.NotImplemented()
@ -67,8 +72,34 @@ func (s *userManageSrv) UpdateUser(user *ms.User) error {
return nil return nil
} }
func (s *userRelationSrv) MyFriendIds(userId int64) (res []int64, err error) {
// TODO
return nil, cs.ErrNotImplemented
}
func (s *userRelationSrv) MyFollowIds(userId int64) (res []int64, err error) {
// TODO
return nil, cs.ErrNotImplemented
}
func (s *userRelationSrv) IsMyFriend(userId int64, friendIds ...int64) (map[int64]bool, error) {
// TODO
return nil, cs.ErrNotImplemented
}
func (s *userRelationSrv) IsMyFollow(userId int64, followIds ...int64) (map[int64]bool, error) {
// TODO
return nil, cs.ErrNotImplemented
}
func newUserManageService(db *pgx.Conn) core.UserManageService { func newUserManageService(db *pgx.Conn) core.UserManageService {
return &userManageSrv{ return &userManageSrv{
pgxSrv: newPgxSrv(db), pgxSrv: newPgxSrv(db),
} }
} }
func newUserRelationService(db *pgx.Conn) core.UserRelationService {
return &userRelationSrv{
pgxSrv: newPgxSrv(db),
}
}

@ -16,7 +16,7 @@ import (
var ( var (
_defaultEventManager EventManager _defaultEventManager EventManager
_defaultJobManager JobManager _defaultJobManager JobManager = emptyJobManager{}
_onceInitial sync.Once _onceInitial sync.Once
) )

@ -6,6 +6,7 @@ package events
import ( import (
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/rocboss/paopao-ce/pkg/types"
) )
type ( type (
@ -38,31 +39,49 @@ type JobManager interface {
Schedule(Job) EntryID Schedule(Job) EntryID
} }
type jobManager struct { type emptyJobManager types.Empty
type simpleJobManager struct {
m *cron.Cron m *cron.Cron
} }
func (j *jobManager) Start() { func (emptyJobManager) Start() {
// nothing
}
func (emptyJobManager) Stop() {
// nothing
}
func (emptyJobManager) Remove(id EntryID) {
// nothing
}
func (emptyJobManager) Schedule(job Job) EntryID {
return 0
}
func (j *simpleJobManager) Start() {
j.m.Start() j.m.Start()
} }
func (j *jobManager) Stop() { func (j *simpleJobManager) Stop() {
j.m.Stop() j.m.Stop()
} }
// Remove an entry from being run in the future. // Remove an entry from being run in the future.
func (j *jobManager) Remove(id EntryID) { func (j *simpleJobManager) Remove(id EntryID) {
j.m.Remove(id) j.m.Remove(id)
} }
// Schedule adds a Job to the Cron to be run on the given schedule. // Schedule adds a Job to the Cron to be run on the given schedule.
// The job is wrapped with the configured Chain. // The job is wrapped with the configured Chain.
func (j *jobManager) Schedule(job Job) EntryID { func (j *simpleJobManager) Schedule(job Job) EntryID {
return j.m.Schedule(job, job) return j.m.Schedule(job, job)
} }
func NewJobManager() JobManager { func NewJobManager() JobManager {
return &jobManager{ return &simpleJobManager{
m: cron.New(), m: cron.New(),
} }
} }

@ -0,0 +1,57 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package prometheus
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/sirupsen/logrus"
)
type metrics struct {
siteInfo *prometheus.GaugeVec
ds core.DataService
wc core.WebCache
}
func (m *metrics) updateSiteInfo() {
if onlineUserKeys, err := m.wc.Keys(conf.PrefixOnlineUser + "*"); err == nil {
maxOnline := len(onlineUserKeys)
m.siteInfo.With(prometheus.Labels{"name": "max_online"}).Set(float64(maxOnline))
} else {
logrus.Warnf("update promethues metrics[site_info_max_online] occurs error: %s", err)
}
if registerUserCount, err := m.ds.GetRegisterUserCount(); err == nil {
m.siteInfo.With(prometheus.Labels{"name": "register_user_count"}).Set(float64(registerUserCount))
} else {
logrus.Warnf("update promethues metrics[site_info_register_user_count] occurs error: %s", err)
}
}
func (m *metrics) onUpdate() {
logrus.Debugf("update promethues metrics job running")
m.updateSiteInfo()
}
func newMetrics(reg prometheus.Registerer, ds core.DataService, wc core.WebCache) *metrics {
m := &metrics{
siteInfo: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "paopao",
Subsystem: "site",
Name: "simple_info",
Help: "paopao-ce site simple information.",
},
[]string{
// metric name
"name",
}),
ds: ds,
wc: wc,
}
reg.MustRegister(m.siteInfo)
return m
}

@ -0,0 +1,41 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package prometheus
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/robfig/cron/v3"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/events"
"github.com/sirupsen/logrus"
)
func scheduleJobs(metrics *metrics) {
spec := conf.JobManagerSetting.UpdateMetricsInterval
schedule, err := cron.ParseStandard(spec)
if err != nil {
panic(err)
}
events.OnTask(schedule, metrics.onUpdate)
logrus.Debug("shedule prometheus metrics update jobs complete")
}
func NewHandler(ds core.DataService, wc core.WebCache) http.Handler {
// Create non-global registry.
registry := prometheus.NewRegistry()
// Add go runtime metrics and process collectors.
registry.MustRegister(
collectors.NewGoCollector(),
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
)
metrics := newMetrics(registry, ds, wc)
scheduleJobs(metrics)
return promhttp.HandlerFor(registry, promhttp.HandlerOpts{EnableOpenMetrics: true})
}

@ -7,8 +7,10 @@ package web
import ( import (
"github.com/alimy/mir/v4" "github.com/alimy/mir/v4"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/cs" "github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/pkg/app" "github.com/rocboss/paopao-ce/pkg/app"
@ -45,7 +47,9 @@ type TweetCommentsReq struct {
PageSize int `form:"-" binding:"-"` PageSize int `form:"-" binding:"-"`
} }
type TweetCommentsResp base.PageResp type TweetCommentsResp struct {
joint.CachePageResp
}
type TimelineReq struct { type TimelineReq struct {
BaseInfo `form:"-" binding:"-"` BaseInfo `form:"-" binding:"-"`
@ -106,6 +110,13 @@ type TopicListResp struct {
ExtralTopics cs.TagList `json:"extral_topics,omitempty"` ExtralTopics cs.TagList `json:"extral_topics,omitempty"`
} }
type TweetDetailReq struct {
SimpleInfo `form:"-" binding:"-"`
TweetId int64 `form:"id"`
}
type TweetDetailResp ms.PostFormated
func (r *GetUserTweetsReq) SetPageInfo(page int, pageSize int) { func (r *GetUserTweetsReq) SetPageInfo(page int, pageSize int) {
r.Page, r.PageSize = page, pageSize r.Page, r.PageSize = page, pageSize
} }
@ -137,3 +148,17 @@ func (s CommentStyleType) ToInnerValue() (res cs.StyleCommentType) {
} }
return return
} }
func (s CommentStyleType) String() (res string) {
switch s {
case "default":
res = conf.InfixCommentDefault
case "hots":
res = conf.InfixCommentHots
case "newest":
res = conf.InfixCommentNewest
default:
res = "_"
}
return
}

@ -147,6 +147,16 @@ type DeleteCommentReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"` ID int64 `json:"id" binding:"required"`
} }
type HighlightCommentReq struct {
SimpleInfo `json:"-" binding:"-"`
CommentId int64 `json:"id" binding:"required"`
}
type HighlightCommentResp struct {
HighlightStatus int8 `json:"highlight_status"`
}
type DeleteCommentReplyReq struct { type DeleteCommentReplyReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"` ID int64 `json:"id" binding:"required"`

@ -5,16 +5,9 @@
package web package web
import ( import (
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/pkg/version" "github.com/rocboss/paopao-ce/pkg/version"
) )
type TweetDetailReq struct {
TweetId int64 `form:"id"`
}
type TweetDetailResp ms.PostFormated
type GetCaptchaResp struct { type GetCaptchaResp struct {
Id string `json:"id"` Id string `json:"id"`
Content string `json:"b64s"` Content string `json:"b64s"`

@ -50,14 +50,15 @@ var (
ErrGetPostsUnknowStyle = xerror.NewError(30014, "使用未知样式参数获取动态列表") ErrGetPostsUnknowStyle = xerror.NewError(30014, "使用未知样式参数获取动态列表")
ErrGetPostsNilUser = xerror.NewError(30015, "使用游客账户获取动态详情失败") ErrGetPostsNilUser = xerror.NewError(30015, "使用游客账户获取动态详情失败")
ErrGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败") ErrGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败")
ErrCreateCommentFailed = xerror.NewError(40002, "评论发布失败") ErrCreateCommentFailed = xerror.NewError(40002, "评论发布失败")
ErrGetCommentFailed = xerror.NewError(40003, "获取评论详情失败") ErrGetCommentFailed = xerror.NewError(40003, "获取评论详情失败")
ErrDeleteCommentFailed = xerror.NewError(40004, "评论删除失败") ErrDeleteCommentFailed = xerror.NewError(40004, "评论删除失败")
ErrCreateReplyFailed = xerror.NewError(40005, "评论回复失败") ErrCreateReplyFailed = xerror.NewError(40005, "评论回复失败")
ErrGetReplyFailed = xerror.NewError(40006, "获取评论详情失败") ErrGetReplyFailed = xerror.NewError(40006, "获取评论详情失败")
ErrMaxCommentCount = xerror.NewError(40007, "评论数已达最大限制") ErrMaxCommentCount = xerror.NewError(40007, "评论数已达最大限制")
ErrGetCommentThumbs = xerror.NewError(40008, "获取评论点赞信息失败") ErrGetCommentThumbs = xerror.NewError(40008, "获取评论点赞信息失败")
ErrHighlightCommentFailed = xerror.NewError(40009, "设置精选评论失败")
ErrGetMessagesFailed = xerror.NewError(50001, "获取消息列表失败") ErrGetMessagesFailed = xerror.NewError(50001, "获取消息列表失败")
ErrReadMessageFailed = xerror.NewError(50002, "标记消息已读失败") ErrReadMessageFailed = xerror.NewError(50002, "标记消息已读失败")

@ -24,6 +24,7 @@ import (
"github.com/rocboss/paopao-ce/internal/events" "github.com/rocboss/paopao-ce/internal/events"
"github.com/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/pkg/app" "github.com/rocboss/paopao-ce/pkg/app"
"github.com/rocboss/paopao-ce/pkg/types"
"github.com/rocboss/paopao-ce/pkg/xerror" "github.com/rocboss/paopao-ce/pkg/xerror"
) )
@ -172,6 +173,109 @@ func (s *BaseServant) Render(c *gin.Context, data any, err mir.Error) {
} }
} }
func (s *DaoServant) PrepareUser(userId int64, user *ms.UserFormated) error {
// guest用户的userId<0
if userId < 0 {
return nil
}
// friendMap, err := s.Ds.IsMyFriend(userId, user.ID)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, user.ID)
if err != nil {
return err
}
// user.IsFriend, user.IsFollowing = friendMap[user.ID], followMap[user.ID]
user.IsFollowing = followMap[user.ID]
return nil
}
func (s *DaoServant) PrepareMessages(userId int64, messages []*ms.MessageFormated) error {
// guest用户的userId<0
if userId < 0 {
return nil
}
userIds := make([]int64, 0, len(messages))
for _, msg := range messages {
if msg.SenderUser != nil {
userIds = append(userIds, msg.SenderUserID)
}
if msg.ReceiverUser != nil {
userIds = append(userIds, msg.ReceiverUserID)
}
}
// friendMap, err := s.Ds.IsMyFriend(userId, userIds...)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, userIds...)
if err != nil {
return err
}
for _, msg := range messages {
if msg.SenderUser != nil {
// msg.SenderUser.IsFriend, msg.SenderUser.IsFollowing = friendMap[msg.SenderUserID], followMap[msg.SenderUserID]
msg.SenderUser.IsFollowing = followMap[msg.SenderUserID]
}
if msg.ReceiverUser != nil {
// msg.ReceiverUser.IsFriend, msg.ReceiverUser.IsFollowing = friendMap[msg.ReceiverUserID], followMap[msg.ReceiverUserID]
msg.ReceiverUser.IsFollowing = followMap[msg.ReceiverUserID]
}
}
return nil
}
func (s *DaoServant) PrepareTweet(userId int64, tweet *ms.PostFormated) error {
// 转换一下可见性的值
tweet.Visibility = ms.PostVisibleT(tweet.Visibility.ToOutValue())
// guest用户的userId<0
if userId < 0 {
return nil
}
// friendMap, err := s.Ds.IsMyFriend(userId, userIds)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, tweet.UserID)
if err != nil {
return err
}
// tweet.User.IsFriend, tweet.User.IsFollowing = friendMap[tweet.UserID], followMap[tweet.UserID]
tweet.User.IsFollowing = followMap[tweet.UserID]
return nil
}
func (s *DaoServant) PrepareTweets(userId int64, tweets []*ms.PostFormated) error {
userIdSet := make(map[int64]types.Empty, len(tweets))
for _, tweet := range tweets {
userIdSet[tweet.UserID] = types.Empty{}
// 顺便转换一下可见性的值
tweet.Visibility = ms.PostVisibleT(tweet.Visibility.ToOutValue())
}
// guest用户的userId<0
if userId < 0 {
return nil
}
userIds := make([]int64, 0, len(userIdSet))
for id := range userIdSet {
userIds = append(userIds, id)
}
// friendMap, err := s.Ds.IsMyFriend(userId, userIds...)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, userIds...)
if err != nil {
return err
}
for _, tweet := range tweets {
// tweet.User.IsFriend, tweet.User.IsFollowing = friendMap[tweet.UserID], followMap[tweet.UserID]
tweet.User.IsFollowing = followMap[tweet.UserID]
}
return nil
}
func (s *DaoServant) GetTweetBy(id int64) (*ms.PostFormated, error) { func (s *DaoServant) GetTweetBy(id int64) (*ms.PostFormated, error) {
post, err := s.Ds.GetPostByID(id) post, err := s.Ds.GetPostByID(id)
if err != nil { if err != nil {
@ -278,15 +382,6 @@ func (s *DaoServant) DeleteSearchPost(post *ms.Post) error {
return s.Ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)}) return s.Ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)})
} }
func (s *DaoServant) GetTweetList(conditions ms.ConditionsT, offset, limit int) ([]*ms.Post, []*ms.PostFormated, error) {
posts, err := s.Ds.GetPosts(conditions, offset, limit)
if err != nil {
return nil, nil, err
}
postFormated, err := s.Ds.MergePosts(posts)
return posts, postFormated, err
}
func (s *DaoServant) RelationTypFrom(me *ms.User, username string) (res *cs.VistUser, err error) { func (s *DaoServant) RelationTypFrom(me *ms.User, username string) (res *cs.VistUser, err error) {
res = &cs.VistUser{ res = &cs.VistUser{
RelTyp: cs.RelationSelf, RelTyp: cs.RelationSelf,

@ -125,6 +125,10 @@ func (s *coreSrv) GetMessages(req *web.GetMessagesReq) (*web.GetMessagesResp, mi
logrus.Errorf("Ds.GetMessages err: %v\n", err) logrus.Errorf("Ds.GetMessages err: %v\n", err)
return nil, web.ErrGetMessagesFailed return nil, web.ErrGetMessagesFailed
} }
if err = s.PrepareMessages(req.UserId, messages); err != nil {
logrus.Errorf("get messages err[2]: %v\n", err)
return nil, web.ErrGetMessagesFailed
}
totalRows, _ := s.Ds.GetMessageCount(req.UserId) totalRows, _ := s.Ds.GetMessageCount(req.UserId)
resp := base.PageRespFrom(messages, req.Page, req.PageSize, totalRows) resp := base.PageRespFrom(messages, req.Page, req.PageSize, totalRows)
return (*web.GetMessagesResp)(resp), nil return (*web.GetMessagesResp)(resp), nil
@ -192,7 +196,6 @@ func (s *coreSrv) GetCollections(req *web.GetCollectionsReq) (*web.GetCollection
logrus.Errorf("Ds.GetUserPostCollectionCount err: %s", err) logrus.Errorf("Ds.GetUserPostCollectionCount err: %s", err)
return nil, web.ErrGetCollectionsFailed return nil, web.ErrGetCollectionsFailed
} }
var posts []*ms.Post var posts []*ms.Post
for _, collection := range collections { for _, collection := range collections {
posts = append(posts, collection.Post) posts = append(posts, collection.Post)
@ -202,8 +205,11 @@ func (s *coreSrv) GetCollections(req *web.GetCollectionsReq) (*web.GetCollection
logrus.Errorf("Ds.MergePosts err: %s", err) logrus.Errorf("Ds.MergePosts err: %s", err)
return nil, web.ErrGetCollectionsFailed return nil, web.ErrGetCollectionsFailed
} }
if err = s.PrepareTweets(req.UserId, postsFormated); err != nil {
logrus.Errorf("get collections prepare tweets err: %s", err)
return nil, web.ErrGetCollectionsFailed
}
resp := base.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows) resp := base.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows)
return (*web.GetCollectionsResp)(resp), nil return (*web.GetCollectionsResp)(resp), nil
} }

@ -9,13 +9,26 @@ import (
"fmt" "fmt"
"github.com/alimy/tryst/event" "github.com/alimy/tryst/event"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/events" "github.com/rocboss/paopao-ce/internal/events"
"github.com/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/model/web" "github.com/rocboss/paopao-ce/internal/model/web"
) )
const (
_commentActionCreate uint8 = iota
_commentActionDelete
_commentActionThumbsUp
_commentActionThumbsDown
_commentActionReplyCreate
_commentActionReplyDelete
_commentActionReplyThumbsUp
_commentActionReplyThumbsDown
)
type cacheUnreadMsgEvent struct { type cacheUnreadMsgEvent struct {
event.UnimplementedEvent event.UnimplementedEvent
ds core.DataService ds core.DataService
@ -30,6 +43,25 @@ type createMessageEvent struct {
message *ms.Message message *ms.Message
} }
type commentActionEvent struct {
event.UnimplementedEvent
ds core.DataService
ac core.AppCache
tweetId int64
commentId int64
action uint8
}
func onCommentActionEvent(tweetId int64, commentId int64, action uint8) {
events.OnEvent(&commentActionEvent{
ds: _ds,
ac: _ac,
tweetId: tweetId,
commentId: commentId,
action: action,
})
}
func onCacheUnreadMsgEvent(uid int64) { func onCacheUnreadMsgEvent(uid int64) {
events.OnEvent(&cacheUnreadMsgEvent{ events.OnEvent(&cacheUnreadMsgEvent{
ds: _ds, ds: _ds,
@ -86,3 +118,51 @@ func (e *createMessageEvent) Action() (err error) {
} }
return return
} }
func (e *commentActionEvent) Name() string {
return "updateCommentMetricEvent"
}
func (e *commentActionEvent) Action() (err error) {
// logrus.Debugf("trigger commentActionEvent action commentId[%d]", e.commentId)
switch e.action {
case _commentActionCreate:
err = e.ds.AddCommentMetric(e.commentId)
e.expireAllStyleComments()
case _commentActionDelete:
err = e.ds.DeleteCommentMetric(e.commentId)
e.expireAllStyleComments()
case _commentActionReplyCreate, _commentActionReplyDelete:
err = e.updateCommentMetric()
e.expireAllStyleComments()
case _commentActionThumbsUp, _commentActionThumbsDown:
err = e.updateCommentMetric()
e.expireHotsComments()
default:
// nothing
}
return
}
func (e *commentActionEvent) expireHotsComments() {
e.ac.DelAny(fmt.Sprintf("%s%d:%s:*", conf.PrefixTweetComment, e.tweetId, conf.InfixCommentHots))
}
func (e *commentActionEvent) expireAllStyleComments() {
e.ac.DelAny(fmt.Sprintf("%s%d:*", conf.PrefixTweetComment, e.tweetId))
}
func (e *commentActionEvent) updateCommentMetric() error {
// logrus.Debug("trigger commentActionEvent action[updateCommentMetric]")
comment, err := e.ds.GetCommentByID(e.commentId)
if err != nil {
return err
}
e.ds.UpdateCommentMetric(&cs.CommentMetric{
CommentId: e.commentId,
ReplyCount: comment.ReplyCount,
ThumbsUpCount: comment.ThumbsUpCount,
ThumbsDownCount: comment.ThumbsDownCount,
})
return nil
}

@ -8,6 +8,7 @@ import (
"github.com/alimy/mir/v4" "github.com/alimy/mir/v4"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
api "github.com/rocboss/paopao-ce/auto/api/v1" api "github.com/rocboss/paopao-ce/auto/api/v1"
"github.com/rocboss/paopao-ce/internal/dao/cache"
"github.com/rocboss/paopao-ce/internal/model/web" "github.com/rocboss/paopao-ce/internal/model/web"
"github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/internal/servants/chain" "github.com/rocboss/paopao-ce/internal/servants/chain"
@ -84,6 +85,9 @@ func (s *followshipSrv) UnfollowUser(r *web.UnfollowUserReq) mir.Error {
logrus.Errorf("Ds.UnfollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId) logrus.Errorf("Ds.UnfollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId)
return web.ErrUnfollowUserFailed return web.ErrUnfollowUserFailed
} }
// 触发缓存更新事件
cache.OnCacheMyFollowIdsEvent(s.Ds, r.User.ID)
cache.OnExpireIndexTweetEvent(r.User.ID)
return nil return nil
} }
@ -97,6 +101,9 @@ func (s *followshipSrv) FollowUser(r *web.FollowUserReq) mir.Error {
logrus.Errorf("Ds.FollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId) logrus.Errorf("Ds.FollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId)
return web.ErrUnfollowUserFailed return web.ErrUnfollowUserFailed
} }
// 触发缓存更新事件
cache.OnCacheMyFollowIdsEvent(s.Ds, r.User.ID)
cache.OnExpireIndexTweetEvent(r.User.ID)
return nil return nil
} }

@ -55,6 +55,8 @@ func (s *friendshipSrv) DeleteFriend(req *web.DeleteFriendReq) mir.Error {
logrus.Errorf("Ds.DeleteFriend err: %s", err) logrus.Errorf("Ds.DeleteFriend err: %s", err)
return web.ErrDeleteFriendFailed return web.ErrDeleteFriendFailed
} }
// 触发用户关系缓存更新事件
// cache.OnCacheMyFriendIdsEvent(s.Ds, req.User.ID, req.UserId)
return nil return nil
} }
@ -89,6 +91,8 @@ func (s *friendshipSrv) AddFriend(req *web.AddFriendReq) mir.Error {
logrus.Errorf("Ds.AddFriend err: %s", err) logrus.Errorf("Ds.AddFriend err: %s", err)
return web.ErrAddFriendFailed return web.ErrAddFriendFailed
} }
// 触发用户关系缓存更新事件
// cache.OnCacheMyFriendIdsEvent(s.Ds, req.User.ID, req.UserId)
return nil return nil
} }

@ -32,10 +32,12 @@ type looseSrv struct {
ac core.AppCache ac core.AppCache
userTweetsExpire int64 userTweetsExpire int64
idxTweetsExpire int64 idxTweetsExpire int64
tweetCommentsExpire int64
prefixUserTweets string prefixUserTweets string
prefixIdxTweetsNewest string prefixIdxTweetsNewest string
prefixIdxTweetsHots string prefixIdxTweetsHots string
prefixIdxTweetsFollowing string prefixIdxTweetsFollowing string
prefixTweetComment string
} }
func (s *looseSrv) Chain() gin.HandlersChain { func (s *looseSrv) Chain() gin.HandlersChain {
@ -61,8 +63,14 @@ func (s *looseSrv) Timeline(req *web.TimelineReq) (*web.TimelineResp, mir.Error)
logrus.Errorf("Ds.RevampPosts err: %s", err) logrus.Errorf("Ds.RevampPosts err: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(posts) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, posts); err != nil {
logrus.Errorf("timeline occurs error[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(posts, req.Page, req.PageSize, res.Total) resp := joint.PageRespFrom(posts, req.Page, req.PageSize, res.Total)
return &web.TimelineResp{ return &web.TimelineResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
@ -98,7 +106,7 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
return nil, web.ErrGetPostsUnknowStyle return nil, web.ErrGetPostsUnknowStyle
} }
if xerr != nil { if xerr != nil {
logrus.Errorf("getIndexTweets occurs error: %s", xerr) logrus.Errorf("getIndexTweets occurs error[1]: %s", xerr)
return nil, web.ErrGetPostFailed return nil, web.ErrGetPostFailed
} }
postsFormated, verr := s.Ds.MergePosts(posts) postsFormated, verr := s.Ds.MergePosts(posts)
@ -106,8 +114,14 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
logrus.Errorf("getIndexTweets in merge posts occurs error: %s", verr) logrus.Errorf("getIndexTweets in merge posts occurs error: %s", verr)
return nil, web.ErrGetPostFailed return nil, web.ErrGetPostFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postsFormated) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("getIndexTweets occurs error[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total) resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
// 缓存处理 // 缓存处理
base.OnCacheRespEvent(s.ac, key, resp, s.idxTweetsExpire) base.OnCacheRespEvent(s.ac, key, resp, s.idxTweetsExpire)
@ -119,17 +133,17 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
} }
func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset int) (res *web.TimelineResp, key string, ok bool) { func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset int) (res *web.TimelineResp, key string, ok bool) {
username := "_"
if req.User != nil {
username = req.User.Username
}
switch req.Style { switch req.Style {
case web.StyleTweetsFollowing: case web.StyleTweetsFollowing:
username := "_"
if req.User != nil {
username = req.User.Username
}
key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsFollowing, username, offset, limit) key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsFollowing, username, offset, limit)
case web.StyleTweetsNewest: case web.StyleTweetsNewest:
key = fmt.Sprintf("%s%d:%d", s.prefixIdxTweetsNewest, offset, limit) key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsNewest, username, offset, limit)
case web.StyleTweetsHots: case web.StyleTweetsHots:
key = fmt.Sprintf("%s%d:%d", s.prefixIdxTweetsHots, offset, limit) key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsHots, username, offset, limit)
default: default:
return return
} }
@ -143,6 +157,18 @@ func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset
return return
} }
func (s *looseSrv) tweetCommentsFromCache(req *web.TweetCommentsReq, limit int, offset int) (res *web.TweetCommentsResp, key string, ok bool) {
key = fmt.Sprintf("%s%d:%s:%d:%d", s.prefixTweetComment, req.TweetId, req.Style, limit, offset)
if data, err := s.ac.Get(key); err == nil {
ok, res = true, &web.TweetCommentsResp{
CachePageResp: joint.CachePageResp{
JsonResp: data,
},
}
}
return
}
func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (res *web.GetUserTweetsResp, err mir.Error) { func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (res *web.GetUserTweetsResp, err mir.Error) {
user, xerr := s.RelationTypFrom(req.User, req.Username) user, xerr := s.RelationTypFrom(req.User, req.Username)
if xerr != nil { if xerr != nil {
@ -198,7 +224,7 @@ func (s *looseSrv) userTweetsFromCache(req *web.GetUserTweetsReq, user *cs.VistU
func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUser) (*web.GetUserTweetsResp, mir.Error) { func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUser) (*web.GetUserTweetsResp, mir.Error) {
stars, totalRows, err := s.Ds.ListUserStarTweets(user, req.PageSize, (req.Page-1)*req.PageSize) stars, totalRows, err := s.Ds.ListUserStarTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
if err != nil { if err != nil {
logrus.Errorf("Ds.GetUserPostStars err: %s", err) logrus.Errorf("getUserStarTweets err[1]: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
var posts []*ms.Post var posts []*ms.Post
@ -212,8 +238,14 @@ func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUse
logrus.Errorf("Ds.MergePosts err: %s", err) logrus.Errorf("Ds.MergePosts err: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postsFormated) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("getUserStarTweets err[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows) resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
@ -233,21 +265,27 @@ func (s *looseSrv) listUserTweets(req *web.GetUserTweetsReq, user *cs.VistUser)
} else if req.Style == web.UserPostsStyleMedia { } else if req.Style == web.UserPostsStyleMedia {
tweets, total, err = s.Ds.ListUserMediaTweets(user, req.PageSize, (req.Page-1)*req.PageSize) tweets, total, err = s.Ds.ListUserMediaTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
} else { } else {
logrus.Errorf("s.listUserTweets unknow style: %s", req.Style) logrus.Errorf("s.listUserTweets unknow style[1]: %s", req.Style)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
if err != nil { if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err) logrus.Errorf("s.listUserTweets err[2]: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
postFormated, err := s.Ds.MergePosts(tweets) postsFormated, err := s.Ds.MergePosts(tweets)
if err != nil { if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err) logrus.Errorf("s.listUserTweets err[3]: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postFormated) if req.User != nil {
resp := joint.PageRespFrom(postFormated, req.Page, req.PageSize, total) userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("s.listUserTweets err[4]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
Data: resp, Data: resp,
@ -281,8 +319,14 @@ func (s *looseSrv) getUserPostTweets(req *web.GetUserTweetsReq, user *cs.VistUse
logrus.Errorf("s.GetTweetList error[2]: %s", err) logrus.Errorf("s.GetTweetList error[2]: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postsFormated) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("s.GetTweetList error[3]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total) resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
@ -364,10 +408,18 @@ func (s *looseSrv) TopicList(req *web.TopicListReq) (*web.TopicListResp, mir.Err
}, nil }, nil
} }
func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) { func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (res *web.TweetCommentsResp, err mir.Error) {
comments, totalRows, err := s.Ds.GetComments(req.TweetId, req.Style.ToInnerValue(), req.PageSize, (req.Page-1)*req.PageSize) limit, offset := req.PageSize, (req.Page-1)*req.PageSize
if err != nil { // 尝试直接从缓存中获取数据
logrus.Errorf("get tweet comments error[1]: %s", err) key, ok := "", false
if res, key, ok = s.tweetCommentsFromCache(req, limit, offset); ok {
logrus.Debugf("looseSrv.TweetComments from cache key:%s", key)
return
}
comments, totalRows, xerr := s.Ds.GetComments(req.TweetId, req.Style.ToInnerValue(), limit, offset)
if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[1]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
@ -378,29 +430,29 @@ func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsR
commentIDs = append(commentIDs, comment.ID) commentIDs = append(commentIDs, comment.ID)
} }
users, err := s.Ds.GetUsersByIDs(userIDs) users, xerr := s.Ds.GetUsersByIDs(userIDs)
if err != nil { if xerr != nil {
logrus.Errorf("get tweet comments error[2]: %s", err) logrus.Errorf("looseSrv.TweetComments occurs error[2]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
contents, err := s.Ds.GetCommentContentsByIDs(commentIDs) contents, xerr := s.Ds.GetCommentContentsByIDs(commentIDs)
if err != nil { if xerr != nil {
logrus.Errorf("get tweet comments error[3]: %s", err) logrus.Errorf("looseSrv.TweetComments occurs error[3]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
replies, err := s.Ds.GetCommentRepliesByID(commentIDs) replies, xerr := s.Ds.GetCommentRepliesByID(commentIDs)
if err != nil { if xerr != nil {
logrus.Errorf("get tweet comments error[4]: %s", err) logrus.Errorf("looseSrv.TweetComments occurs error[4]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
var commentThumbs, replyThumbs cs.CommentThumbsMap var commentThumbs, replyThumbs cs.CommentThumbsMap
if req.Uid > 0 { if req.Uid > 0 {
commentThumbs, replyThumbs, err = s.Ds.GetCommentThumbsMap(req.Uid, req.TweetId) commentThumbs, replyThumbs, xerr = s.Ds.GetCommentThumbsMap(req.Uid, req.TweetId)
if err != nil { if xerr != nil {
logrus.Errorf("get tweet comments error[5]: %s", err) logrus.Errorf("looseSrv.TweetComments occurs error[5]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
} }
@ -440,8 +492,41 @@ func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsR
} }
commentsFormated = append(commentsFormated, commentFormated) commentsFormated = append(commentsFormated, commentFormated)
} }
resp := base.PageRespFrom(commentsFormated, req.Page, req.PageSize, totalRows) resp := joint.PageRespFrom(commentsFormated, req.Page, req.PageSize, totalRows)
return (*web.TweetCommentsResp)(resp), nil // 缓存处理
base.OnCacheRespEvent(s.ac, key, resp, s.tweetCommentsExpire)
return &web.TweetCommentsResp{
CachePageResp: joint.CachePageResp{
Data: resp,
},
}, nil
}
func (s *looseSrv) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
post, err := s.Ds.GetPostByID(req.TweetId)
if err != nil {
return nil, web.ErrGetPostFailed
}
postContents, err := s.Ds.GetPostContentsByIDs([]int64{post.ID})
if err != nil {
return nil, web.ErrGetPostFailed
}
users, err := s.Ds.GetUsersByIDs([]int64{post.UserID})
if err != nil {
return nil, web.ErrGetPostFailed
}
// 数据整合
postFormated := post.Format()
for _, user := range users {
postFormated.User = user.Format()
}
for _, content := range postContents {
if content.PostID == post.ID {
postFormated.Contents = append(postFormated.Contents, content.Format())
}
}
s.PrepareTweet(req.Uid, postFormated)
return (*web.TweetDetailResp)(postFormated), nil
} }
func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose { func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose {
@ -451,9 +536,11 @@ func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose {
ac: ac, ac: ac,
userTweetsExpire: cs.UserTweetsExpire, userTweetsExpire: cs.UserTweetsExpire,
idxTweetsExpire: cs.IndexTweetsExpire, idxTweetsExpire: cs.IndexTweetsExpire,
tweetCommentsExpire: cs.TweetCommentsExpire,
prefixUserTweets: conf.PrefixUserTweets, prefixUserTweets: conf.PrefixUserTweets,
prefixIdxTweetsNewest: conf.PrefixIdxTweetsNewest, prefixIdxTweetsNewest: conf.PrefixIdxTweetsNewest,
prefixIdxTweetsHots: conf.PrefixIdxTweetsHots, prefixIdxTweetsHots: conf.PrefixIdxTweetsHots,
prefixIdxTweetsFollowing: conf.PrefixIdxTweetsFollowing, prefixIdxTweetsFollowing: conf.PrefixIdxTweetsFollowing,
prefixTweetComment: conf.PrefixTweetComment,
} }
} }

@ -82,6 +82,8 @@ func (s *privSrv) ThumbsDownTweetComment(req *web.TweetCommentThumbsReq) mir.Err
logrus.Errorf("thumbs down tweet comment error: %s req:%v", err, req) logrus.Errorf("thumbs down tweet comment error: %s req:%v", err, req)
return web.ErrThumbsDownTweetComment return web.ErrThumbsDownTweetComment
} }
// 缓存处理
onCommentActionEvent(req.TweetId, req.CommentId, _commentActionThumbsDown)
return nil return nil
} }
@ -90,6 +92,8 @@ func (s *privSrv) ThumbsUpTweetComment(req *web.TweetCommentThumbsReq) mir.Error
logrus.Errorf("thumbs up tweet comment error: %s req:%v", err, req) logrus.Errorf("thumbs up tweet comment error: %s req:%v", err, req)
return web.ErrThumbsUpTweetComment return web.ErrThumbsUpTweetComment
} }
// 缓存处理
onCommentActionEvent(req.TweetId, req.CommentId, _commentActionThumbsUp)
return nil return nil
} }
@ -355,10 +359,14 @@ func (s *privSrv) DeleteCommentReply(req *web.DeleteCommentReplyReq) mir.Error {
logrus.Errorf("s.deletePostCommentReply err: %s", err) logrus.Errorf("s.deletePostCommentReply err: %s", err)
return web.ErrDeleteCommentFailed return web.ErrDeleteCommentFailed
} }
// 缓存处理, 宽松处理错误
if comment, err := s.Ds.GetCommentByID(reply.CommentID); err == nil {
onCommentActionEvent(comment.PostID, comment.ID, _commentActionReplyDelete)
}
return nil return nil
} }
func (s *privSrv) CreateCommentReply(req *web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error) { func (s *privSrv) CreateCommentReply(req *web.CreateCommentReplyReq) (_ *web.CreateCommentReplyResp, xerr mir.Error) {
var ( var (
post *ms.Post post *ms.Post
comment *ms.Comment comment *ms.Comment
@ -435,6 +443,8 @@ func (s *privSrv) CreateCommentReply(req *web.CreateCommentReplyReq) (*web.Creat
}) })
} }
} }
// 缓存处理
onCommentActionEvent(comment.PostID, comment.ID, _commentActionReplyCreate)
return (*web.CreateCommentReplyResp)(reply), nil return (*web.CreateCommentReplyResp)(reply), nil
} }
@ -463,9 +473,22 @@ func (s *privSrv) DeleteComment(req *web.DeleteCommentReq) mir.Error {
logrus.Errorf("Ds.DeleteComment err: %s", err) logrus.Errorf("Ds.DeleteComment err: %s", err)
return web.ErrDeleteCommentFailed return web.ErrDeleteCommentFailed
} }
onCommentActionEvent(comment.PostID, comment.ID, _commentActionDelete)
return nil return nil
} }
func (s *privSrv) HighlightComment(req *web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error) {
status, err := s.Ds.HighlightComment(req.Uid, req.CommentId)
if err == cs.ErrNoPermission {
return nil, web.ErrNoPermission
} else if err != nil {
return nil, web.ErrHighlightCommentFailed
}
return &web.HighlightCommentResp{
HighlightStatus: status,
}, nil
}
func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateCommentResp, xerr mir.Error) { func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateCommentResp, xerr mir.Error) {
var ( var (
mediaContents []string mediaContents []string
@ -555,7 +578,8 @@ func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateComment
CommentID: comment.ID, CommentID: comment.ID,
}) })
} }
// 缓存处理
onCommentActionEvent(comment.PostID, comment.ID, _commentActionCreate)
return (*web.CreateCommentResp)(comment), nil return (*web.CreateCommentResp)(comment), nil
} }

@ -42,37 +42,6 @@ type pubSrv struct {
*base.DaoServant *base.DaoServant
} }
func (s *pubSrv) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
post, err := s.Ds.GetPostByID(req.TweetId)
if err != nil {
logrus.Errorf("get tweet detail error[1]: %s", err)
return nil, web.ErrGetPostFailed
}
postContents, err := s.Ds.GetPostContentsByIDs([]int64{post.ID})
if err != nil {
logrus.Errorf("get tweet detail error[2]: %s", err)
return nil, web.ErrGetPostFailed
}
users, err := s.Ds.GetUsersByIDs([]int64{post.UserID})
if err != nil {
logrus.Errorf("get tweet detail error[3]: %s", err)
return nil, web.ErrGetPostFailed
}
// 数据整合
postFormated := post.Format()
for _, user := range users {
postFormated.User = user.Format()
}
for _, content := range postContents {
if content.PostID == post.ID {
postFormated.Contents = append(postFormated.Contents, content.Format())
}
}
// TODO: 暂时处理办法,后续需要优化去掉这个步骤
postFormated.Visibility = ms.PostVisibleT(postFormated.Visibility.ToOutValue())
return (*web.TweetDetailResp)(postFormated), nil
}
func (s *pubSrv) SendCaptcha(req *web.SendCaptchaReq) mir.Error { func (s *pubSrv) SendCaptcha(req *web.SendCaptchaReq) mir.Error {
ctx := context.Background() ctx := context.Background()

@ -207,10 +207,3 @@ func checkPermision(user *ms.User, targetUserId int64) mir.Error {
} }
return nil return nil
} }
// visbleTansform 可见性等价转换,暂时处理方式,后续需要去掉这个步骤
func visbleTansform(list []*ms.PostFormated) {
for _, post := range list {
post.Visibility = ms.PostVisibleT(post.Visibility.ToOutValue())
}
}

@ -15,7 +15,9 @@ type baseHttpService struct {
} }
func (s *baseHttpService) registerRoute(srv Service, h func(e *gin.Engine)) { func (s *baseHttpService) registerRoute(srv Service, h func(e *gin.Engine)) {
h(s.server.e) if h != nil {
h(s.server.e)
}
s.server.addService(srv) s.server.addService(srv)
} }

@ -0,0 +1,63 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package service
import (
"fmt"
"net/http"
"github.com/Masterminds/semver/v3"
"github.com/fatih/color"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/dao"
"github.com/rocboss/paopao-ce/internal/dao/cache"
"github.com/rocboss/paopao-ce/internal/metrics/prometheus"
)
var (
_ Service = (*metricsService)(nil)
)
type metricsService struct {
*baseHttpService
}
func (s *metricsService) Name() string {
return "MetricsService"
}
func (s *metricsService) Version() *semver.Version {
return semver.MustParse("v0.1.0")
}
func (s *metricsService) OnInit() error {
s.registerRoute(s, nil)
return nil
}
func (s *metricsService) String() string {
return fmt.Sprintf("listen on %s\n", color.GreenString("http://%s:%s", conf.MetricsServerSetting.HttpIp, conf.MetricsServerSetting.HttpPort))
}
func newMetricsService() Service {
addr := conf.MetricsServerSetting.HttpIp + ":" + conf.MetricsServerSetting.HttpPort
server := httpServers.from(addr, func() *httpServer {
ds, wc := dao.DataService(), cache.NewWebCache()
mux := http.NewServeMux()
mux.Handle("/metrics", prometheus.NewHandler(ds, wc))
return &httpServer{
baseServer: newBaseServe(),
server: &http.Server{
Addr: addr,
Handler: mux,
},
}
})
return &metricsService{
baseHttpService: &baseHttpService{
server: server,
},
}
}

@ -10,7 +10,6 @@ import (
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/gin-gonic/gin"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
) )
@ -31,7 +30,7 @@ func (s *pprofService) Version() *semver.Version {
} }
func (s *pprofService) OnInit() error { func (s *pprofService) OnInit() error {
s.registerRoute(s, func(*gin.Engine) {}) s.registerRoute(s, nil)
return nil return nil
} }
@ -43,10 +42,8 @@ func newPprofService() Service {
addr := conf.PprofServerSetting.HttpIp + ":" + conf.PprofServerSetting.HttpPort addr := conf.PprofServerSetting.HttpIp + ":" + conf.PprofServerSetting.HttpPort
// notice this step just to register pprof server to start. don't share server with pprof. // notice this step just to register pprof server to start. don't share server with pprof.
server := httpServers.from(addr, func() *httpServer { server := httpServers.from(addr, func() *httpServer {
engine := newWebEngine()
return &httpServer{ return &httpServer{
baseServer: newBaseServe(), baseServer: newBaseServe(),
e: engine,
server: &http.Server{ server: &http.Server{
Addr: addr, Addr: addr,
Handler: http.DefaultServeMux, Handler: http.DefaultServeMux,

@ -75,6 +75,9 @@ func newService() (ss []Service) {
"Pprof": func() { "Pprof": func() {
ss = append(ss, newPprofService()) ss = append(ss, newPprofService())
}, },
"Metrics": func() {
ss = append(ss, newMetricsService())
},
}) })
return return
} }

@ -30,7 +30,7 @@ func (s *webService) Name() string {
} }
func (s *webService) Version() *semver.Version { func (s *webService) Version() *semver.Version {
return semver.MustParse("v0.1.0") return semver.MustParse("v0.5.0")
} }
func (s *webService) OnInit() error { func (s *webService) OnInit() error {

@ -29,4 +29,7 @@ type Loose struct {
// TweetComments 获取动态评论 // TweetComments 获取动态评论
TweetComments func(Get, web.TweetCommentsReq) web.TweetCommentsResp `mir:"/post/comments"` TweetComments func(Get, web.TweetCommentsReq) web.TweetCommentsResp `mir:"/post/comments"`
// TweetDetail 获取动态详情
TweetDetail func(Get, web.TweetDetailReq) web.TweetDetailResp `mir:"/post"`
} }

@ -54,6 +54,9 @@ type Priv struct {
// DeletePostComment 删除动态评论 // DeletePostComment 删除动态评论
DeleteComment func(Delete, web.DeleteCommentReq) `mir:"/post/comment"` DeleteComment func(Delete, web.DeleteCommentReq) `mir:"/post/comment"`
// HighlightComment 精选动态评论
HighlightComment func(Post, web.HighlightCommentReq) web.HighlightCommentResp `mir:"/post/comment/highlight"`
// CreateCommentReply 发布评论回复 // CreateCommentReply 发布评论回复
CreateCommentReply func(Post, web.CreateCommentReplyReq) web.CreateCommentReplyResp `mir:"/post/comment/reply"` CreateCommentReply func(Post, web.CreateCommentReplyReq) web.CreateCommentReplyResp `mir:"/post/comment/reply"`
@ -66,7 +69,7 @@ type Priv struct {
// ThumbsDownTweetComment 点踩评论 // ThumbsDownTweetComment 点踩评论
ThumbsDownTweetComment func(Post, web.TweetCommentThumbsReq) `mir:"/tweet/comment/thumbsdown"` ThumbsDownTweetComment func(Post, web.TweetCommentThumbsReq) `mir:"/tweet/comment/thumbsdown"`
// ThumbsUpTweetReply 点赞评论回复 // ThumbsUpTweetReply 点赞评论回复·
ThumbsUpTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsup"` ThumbsUpTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsup"`
// ThumbsDownTweetReply 点踩评论回复 // ThumbsDownTweetReply 点踩评论回复

@ -28,7 +28,4 @@ type Pub struct {
// SendCaptcha 发送验证码 // SendCaptcha 发送验证码
SendCaptcha func(Post, web.SendCaptchaReq) `mir:"/captcha"` SendCaptcha func(Post, web.SendCaptchaReq) `mir:"/captcha"`
// TweetDetail 获取动态详情
TweetDetail func(Get, web.TweetDetailReq) web.TweetDetailResp `mir:"/post"`
} }

@ -0,0 +1 @@
ALTER TABLE `p_comment` DROP COLUMN `is_essence`;

@ -0,0 +1 @@
ALTER TABLE `p_comment` ADD COLUMN `is_essence` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否精选';

@ -0,0 +1,3 @@
ALTER TABLE `p_comment` DROP COLUMN `reply_count`;
DROP TABLE IF EXISTS `p_comment_metric`;
DROP TABLE IF EXISTS `p_user_metric`;

@ -0,0 +1,48 @@
ALTER TABLE `p_comment` ADD COLUMN `reply_count` int unsigned NOT NULL DEFAULT 0 COMMENT '回复数';
UPDATE p_comment comment
SET reply_count = (
SELECT count(*) FROM p_comment_reply reply WHERE reply.comment_id=comment.id AND reply.is_del=0
)
WHERE is_del=0;
CREATE TABLE `p_comment_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`comment_id` bigint unsigned NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_metric_comment_id_rank_score` (`comment_id`, `rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE `p_user_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`tweets_count` int unsigned NOT NULL DEFAULT 0,
`latest_trends_on` bigint unsigned NOT NULL DEFAULT 0 COMMENT '最新动态时间',
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user_metric_user_id_tweets_count_trends` (`user_id`, `tweets_count`, `latest_trends_on`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;

@ -0,0 +1 @@
ALTER TABLE p_comment DROP COLUMN is_essence;

@ -0,0 +1 @@
ALTER TABLE p_comment ADD COLUMN is_essence SMALLINT NOT NULL DEFAULT 0;

@ -0,0 +1,3 @@
ALTER TABLE p_comment DROP COLUMN IF EXISTS reply_count;
DROP TABLE IF EXISTS p_comment_metric;
DROP TABLE IF EXISTS p_user_metric;

@ -0,0 +1,51 @@
ALTER TABLE p_comment ADD COLUMN reply_count INT NOT NULL DEFAULT 0;
WITH comment_reply AS (
SELECT comment_id, count(*) AS count
FROM p_comment_reply
WHERE is_del=0
GROUP By comment_id
)
UPDATE p_comment comment
SET reply_count = reply.count
FROM comment_reply reply
WHERE comment.id = reply.comment_id;
CREATE TABLE p_comment_metric (
id BIGSERIAL PRIMARY KEY,
comment_id BIGINT NOT NULL,
rank_score BIGINT NOT NULL DEFAULT 0,
incentive_score INT NOT NULL DEFAULT 0,
decay_factor INT NOT NULL DEFAULT 0,
motivation_factor INT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_comment_metric_comment_id_rank_score ON p_comment_metric USING btree (comment_id, rank_score);
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE p_user_metric (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
tweets_count INT NOT NULL DEFAULT 0,
latest_trends_on BIGINT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_user_metric_user_id_tweets_count_trends ON p_user_metric USING btree (user_id, tweets_count, latest_trends_on);
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;

@ -0,0 +1 @@
ALTER TABLE "p_comment" DROP COLUMN "is_essence";

@ -0,0 +1 @@
ALTER TABLE "p_comment" ADD COLUMN "is_essence" integer NOT NULL DEFAULT 0;

@ -0,0 +1,3 @@
ALTER TABLE "p_comment" DROP COLUMN "reply_count";
DROP TABLE IF EXISTS "p_comment_metric";
DROP TABLE IF EXISTS "p_user_metric";

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save