From 0b9ac4bd873049ab6cbe73b66dfdef137a13c7f4 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Thu, 27 Jul 2023 16:44:02 +0800 Subject: [PATCH 1/8] Feat/develop test (#687) * docs: add readme docs Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * Update config.yaml * Update config.yaml --------- Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> --- .github/workflows/build-docker-image.yml | 38 ++++++-- .github/workflows/deploy.yml | 86 +++++++++-------- .goreleaser.yaml | 118 +++++++++++------------ config/config.yaml | 6 +- 4 files changed, 138 insertions(+), 110 deletions(-) diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index ff58d8d8f..ef2659724 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -29,30 +29,31 @@ jobs: - name: Check out the repo uses: actions/checkout@v3 +# docker.io/openim/openim-server:latest - name: Log in to Docker Hub - uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + uses: docker/metadata-action@v4.6.0 with: images: openim/openim-server tags: latest - name: Build and push Docker image - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + uses: docker/build-push-action@v4 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - +# registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server:latest - name: Log in to AliYun Docker Hub - uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + uses: docker/login-action@v2 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} @@ -60,19 +61,42 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta2 - uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + uses: docker/metadata-action@v4.6.0 with: images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server tags: latest - name: Build and push Docker image - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + uses: docker/build-push-action@v4 with: context: . push: true tags: ${{ steps.meta2.outputs.tags }} labels: ${{ steps.meta2.outputs.labels }} +# ghcr.io/openim/openim-server:latest + - name: Log in to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta3 + uses: docker/metadata-action@v4.6.0 + with: + images: openim/openim-server + tags: latest + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ steps.meta3.outputs.tags }} + labels: ${{ steps.meta3.outputs.labels }} + # name: OpenIM Build Docker Images # on: # push: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ef50743a1..2d7798916 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,48 +12,52 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: deploy for dev +name: OpenIM Deploy for dev on: - push: - branches: - - 'devops' # Only for the dev branch - paths: - - '.github/workflows/*' - # - '__test__/**' # dev No immediate testing is required - - 'src/**' - - 'Dockerfile' - - 'docker-compose.yml' - - 'bin/*' + push: + branches: + - 'devops' # Only for the dev branch + paths: + - '.github/workflows/*' + # - '__test__/**' # dev No immediate testing is required + - 'src/**' + - 'Dockerfile' + - 'docker-compose.yml' + - 'bin/*' + +env: + SERVER_PRIVATE_KEY: ${{ secrets.SERVER_PRIVATE_KEY }} # server private key + SERVER_HOST: ${{ secrets.SERVER_HOST }} # server ip address + USER_NAME: ${{ secrets.USER_NAME }} # server username + cache-name: note jobs: - deploy-dev: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: set ssh key # Temporarily set up ssh key - run: | - mkdir -p ~/.ssh/ - # secrets.WFP_ID_RSA set in GitHub - echo "${{secrets.WFP_ID_RSA}}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan "182.92.xxx.xxx" >> ~/.ssh/known_hosts - - name: deploy # Deployment - run: | - ssh work@182.92.xxx.xxx " - # 【Attention】Log in with the 'work' account, manually create /home/work/imooc-lego directory - # Then git clone https://username:password@github.com/imooc-lego/biz-editor-server.git -b dev (private repository, use GitHub username and password) - # Remember to delete origin to avoid exposing GitHub password - - cd /home/work/imooc-lego/biz-editor-server; - git remote add origin https://openimbot:${{secrets.WFP_PASSWORD}}@github.com/OpenIMSDK/open-im-server.git; - git checkout dev; - git pull origin dev; # Download the latest code again - git remote remove origin; # Remove origin to avoid exposing GitHub password - # Start docker - docker-compose build editor-server; # Same as the service name in docker-compose.yml - docker-compose up -d; - " - - name: delete ssh key # Delete ssh key - run: rm -rf ~/.ssh/id_rsa + deploy-dev: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: set ssh key # Temporarily set up ssh key + run: | + mkdir -p ~/.ssh/ + # secrets.WFP_ID_RSA set in GitHub + echo "${{secrets.WFP_ID_RSA}}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan "182.92.xxx.xxx" >> ~/.ssh/known_hosts + - name: deploy # Deployment + run: | + ssh work@182.92.xxx.xxx " + # 【Attention】Log in with the 'work' account, manually create /home/work/imooc-lego directory + # Then git clone https://username:password@github.com/imooc-lego/biz-editor-server.git -b dev (private repository, use GitHub username and password) + # Remember to delete origin to avoid exposing GitHub password + cd /home/work/imooc-lego/biz-editor-server; + git remote add origin https://openimbot:${{secrets.WFP_PASSWORD}}@github.com/OpenIMSDK/open-im-server.git; + git checkout dev; + git pull origin dev; # Download the latest code again + git remote remove origin; # Remove origin to avoid exposing GitHub password + # Start docker + docker-compose build editor-server; # Same as the service name in docker-compose.yml + docker-compose up -d; + " + - name: delete ssh key # Delete ssh key + run: rm -rf ~/.ssh/id_rsa \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 996a53745..e9eb44c94 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -335,66 +335,66 @@ changelog: - title: Other work order: 9999 -dockers: - - image_templates: - - "openimsdk/open-im-server:{{ .Tag }}-amd64" - - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-amd64" - dockerfile: Dockerfile - use: buildx - build_flag_templates: - - "--pull" - - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/Open-IM-Server/main/README.md" - - "--label=io.artifacthub.package.logo-url=hhttps://github.com/OpenIMSDK/Open-IM-Server/blob/main/assets/logo/openim-logo-green.png" - - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' - - "--label=io.artifacthub.package.license=Apace-2.0" - - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.name={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - "--label=org.opencontainers.image.source={{.GitURL}}" - - "--platform=linux/amd64" - extra_files: - - scripts/entrypoint.sh - - image_templates: - - "goreleaser/goreleaser:{{ .Tag }}-arm64" - - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-arm64" - dockerfile: Dockerfile - use: buildx - build_flag_templates: - - "--pull" - - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/Open-IM-Server/main/README.md" - - "--label=io.artifacthub.package.logo-url=hhttps://github.com/OpenIMSDK/Open-IM-Server/blob/main/assets/logo/openim-logo-green.png" - - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' - - "--label=io.artifacthub.package.license=Apace-2.0" - - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.name={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - "--label=org.opencontainers.image.source={{.GitURL}}" - - "--platform=linux/arm64" - goarch: arm64 - extra_files: - - scripts/entrypoint.sh +# dockers: +# - image_templates: +# - "openimsdk/open-im-server:{{ .Tag }}-amd64" +# - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-amd64" +# dockerfile: Dockerfile +# use: buildx +# build_flag_templates: +# - "--pull" +# - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/Open-IM-Server/main/README.md" +# - "--label=io.artifacthub.package.logo-url=hhttps://github.com/OpenIMSDK/Open-IM-Server/blob/main/assets/logo/openim-logo-green.png" +# - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' +# - "--label=io.artifacthub.package.license=Apace-2.0" +# - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" +# - "--label=org.opencontainers.image.created={{.Date}}" +# - "--label=org.opencontainers.image.name={{.ProjectName}}" +# - "--label=org.opencontainers.image.revision={{.FullCommit}}" +# - "--label=org.opencontainers.image.version={{.Version}}" +# - "--label=org.opencontainers.image.source={{.GitURL}}" +# - "--platform=linux/amd64" +# extra_files: +# - scripts/entrypoint.sh +# - image_templates: +# - "goreleaser/goreleaser:{{ .Tag }}-arm64" +# - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-arm64" +# dockerfile: Dockerfile +# use: buildx +# build_flag_templates: +# - "--pull" +# - "--label=io.artifacthub.package.readme-url=https://raw.githubusercontent.com/OpenIMSDK/Open-IM-Server/main/README.md" +# - "--label=io.artifacthub.package.logo-url=hhttps://github.com/OpenIMSDK/Open-IM-Server/blob/main/assets/logo/openim-logo-green.png" +# - '--label=io.artifacthub.package.maintainers=[{"name":"Xinwei Xiong","email":"3293172751nss@gmail.com"}]' +# - "--label=io.artifacthub.package.license=Apace-2.0" +# - "--label=org.opencontainers.image.description=OpenIM Open source top instant messaging system" +# - "--label=org.opencontainers.image.created={{.Date}}" +# - "--label=org.opencontainers.image.name={{.ProjectName}}" +# - "--label=org.opencontainers.image.revision={{.FullCommit}}" +# - "--label=org.opencontainers.image.version={{.Version}}" +# - "--label=org.opencontainers.image.source={{.GitURL}}" +# - "--platform=linux/arm64" +# goarch: arm64 +# extra_files: +# - scripts/entrypoint.sh -docker_manifests: - - name_template: "goreleaser/goreleaser:{{ .Tag }}" - image_templates: - - "goreleaser/goreleaser:{{ .Tag }}-amd64" - - "goreleaser/goreleaser:{{ .Tag }}-arm64" - - name_template: "ghcr.io/goreleaser/goreleaser:{{ .Tag }}" - image_templates: - - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-amd64" - - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-arm64" - - name_template: "goreleaser/goreleaser:latest" - image_templates: - - "goreleaser/goreleaser:{{ .Tag }}-amd64" - - "goreleaser/goreleaser:{{ .Tag }}-arm64" - - name_template: "ghcr.io/goreleaser/goreleaser:latest" - image_templates: - - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-amd64" - - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-arm64" +# docker_manifests: +# - name_template: "goreleaser/goreleaser:{{ .Tag }}" +# image_templates: +# - "goreleaser/goreleaser:{{ .Tag }}-amd64" +# - "goreleaser/goreleaser:{{ .Tag }}-arm64" +# - name_template: "ghcr.io/goreleaser/goreleaser:{{ .Tag }}" +# image_templates: +# - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-amd64" +# - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-arm64" +# - name_template: "goreleaser/goreleaser:latest" +# image_templates: +# - "goreleaser/goreleaser:{{ .Tag }}-amd64" +# - "goreleaser/goreleaser:{{ .Tag }}-arm64" +# - name_template: "ghcr.io/goreleaser/goreleaser:latest" +# image_templates: +# - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-amd64" +# - "ghcr.io/goreleaser/goreleaser:{{ .Tag }}-arm64" nfpms: - id: packages diff --git a/config/config.yaml b/config/config.yaml index 6bf3cf06e..348aa2e93 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -126,10 +126,10 @@ api: # Configuration for Aliyun OSS object: enable: "minio" - apiURL: "http://127.0.0.1:10002/object/" + apiURL: http://127.0.0.1:10002/object/ minio: bucket: "openim" - endpoint: http://127.0.0.1:10005 + endpoint: http://127.0.0.1:10005 accessKeyID: root secretAccessKey: openIM123 sessionToken: "" @@ -371,4 +371,4 @@ prometheus: conversationPrometheusPort: [ 20230 ] rtcPrometheusPort: [ 21300 ] thirdPrometheusPort: [ 21301 ] - messageTransferPrometheusPort: [ 21400, 21401, 21402, 21403 ] \ No newline at end of file + messageTransferPrometheusPort: [ 21400, 21401, 21402, 21403 ] From 4d816978ec8f03eb7d6652599ebd5a72d35ed06e Mon Sep 17 00:00:00 2001 From: pluto <83957921+plutoyty@users.noreply.github.com> Date: Thu, 27 Jul 2023 19:46:44 +0800 Subject: [PATCH 2/8] Resolving code conflicts after project directory changes and Add user subscription to the operation from rpc to db layer (#684) * Resolving code conflicts after project directory changes and Add subscribe and unsubscribe mongodb operations * Organize and update module dependencies --- go.mod | 2 +- go.sum | 4 +- internal/api/route.go | 3 + internal/api/user.go | 18 +++- internal/rpc/user/user.go | 33 +++++- internal/tools/msg.go | 2 + pkg/common/db/controller/user.go | 89 +++++++++++----- pkg/common/db/table/unrelation/user.go | 42 ++++++++ pkg/common/db/unrelation/user.go | 141 +++++++++++++++++++++++++ 9 files changed, 295 insertions(+), 39 deletions(-) create mode 100644 pkg/common/db/table/unrelation/user.go create mode 100644 pkg/common/db/unrelation/user.go diff --git a/go.mod b/go.mod index e4bc8edc6..c18eabd08 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( require github.com/google/uuid v1.3.0 require ( - github.com/OpenIMSDK/protocol v0.0.1 + github.com/OpenIMSDK/protocol v0.0.2 github.com/OpenIMSDK/tools v0.0.5 github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible github.com/go-redis/redis v6.15.9+incompatible diff --git a/go.sum b/go.sum index 0089e1924..a93a1687a 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5og firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OpenIMSDK/protocol v0.0.1 h1:Q6J1jCU00dfqmguxw2XI+IGcVfBAkb5Tz8LgvyeNkk0= -github.com/OpenIMSDK/protocol v0.0.1/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= +github.com/OpenIMSDK/protocol v0.0.2 h1:O53/WiqLCHF9aWPLI32GPF82hn7suM8PkhrtL89Klrw= +github.com/OpenIMSDK/protocol v0.0.2/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= github.com/OpenIMSDK/tools v0.0.5 h1:yBVHJ3EpIDcp8VFKPjuGr6MQvFa3t4JByZ+vmeC06/Q= github.com/OpenIMSDK/tools v0.0.5/go.mod h1:eg+q4A34Qmu73xkY0mt37FHGMCMfC6CtmOnm0kFEGFI= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= diff --git a/internal/api/route.go b/internal/api/route.go index 4a4f92cc0..0f46f0f0c 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -79,6 +79,9 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive userRouterGroup.POST("/get_users", ParseToken, u.GetUsers) userRouterGroup.POST("/get_users_online_status", ParseToken, u.GetUsersOnlineStatus) userRouterGroup.POST("/get_users_online_token_detail", ParseToken, u.GetUsersOnlineTokenDetail) + userRouterGroup.POST("/subscribe_users_status", ParseToken, u.UnSubscriberStatus) + userRouterGroup.POST("/unsubscribe_users_status", ParseToken, u.UnSubscriberStatus) + } // friend routing group friendRouterGroup := r.Group("/friend", ParseToken) diff --git a/internal/api/user.go b/internal/api/user.go index 8595b3501..108ccac69 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -62,6 +62,7 @@ func (u *UserApi) GetUsers(c *gin.Context) { a2r.Call(user.UserClient.GetPaginationUsers, u.Client, c) } +// GetUsersOnlineStatus Get user online status. func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) { var req msggateway.GetUsersOnlineStatusReq if err := c.BindJSON(&req); err != nil { @@ -95,13 +96,13 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) { wsResult = append(wsResult, reply.SuccessResult...) } } - // 遍历 api 请求体中的 userIDs + // Traversing the userIDs in the api request body for _, v1 := range req.UserIDs { flag = false res := new(msggateway.GetUsersOnlineStatusResp_SuccessResult) - // 遍历从各个网关中获取的在线结果 + // Iterate through the online results fetched from various gateways for _, v2 := range wsResult { - // 如果匹配上说明在线,反之 + // If matches the above description on the line, and vice versa if v2.UserID == v1 { flag = true res.UserID = v1 @@ -123,6 +124,7 @@ func (u *UserApi) UserRegisterCount(c *gin.Context) { a2r.Call(user.UserClient.UserRegisterCount, u.Client, c) } +// GetUsersOnlineTokenDetail Get user online token details. func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) { var wsResult []*msggateway.GetUsersOnlineStatusResp_SuccessResult var respResult []*msggateway.SingleDetail @@ -182,3 +184,13 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) { apiresp.GinSuccess(c, respResult) } + +// SubscriberStatus Presence status of subscribed users. +func (u *UserApi) SubscriberStatus(c *gin.Context) { + a2r.Call(user.UserClient.SubscribeOrCancelUsersStatus, u.Client, c) +} + +// UnSubscriberStatus Unsubscribe a user's presence. +func (u *UserApi) UnSubscriberStatus(c *gin.Context) { + a2r.Call(user.UserClient.SubscribeOrCancelUsersStatus, u.Client, c) +} diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index fb6518a7e..576492566 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -17,13 +17,12 @@ package user import ( "context" "errors" + "github.com/OpenIMSDK/Open-IM-Server/pkg/authverify" + "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/unrelation" + "github.com/OpenIMSDK/tools/log" "strings" "time" - "github.com/OpenIMSDK/Open-IM-Server/pkg/authverify" - - "github.com/OpenIMSDK/tools/log" - "github.com/OpenIMSDK/Open-IM-Server/pkg/common/config" "github.com/OpenIMSDK/Open-IM-Server/pkg/common/convert" "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache" @@ -60,6 +59,10 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { if err != nil { return err } + mongo, err := unrelation.NewMongo() + if err != nil { + return err + } if err := db.AutoMigrate(&tablerelation.UserModel{}); err != nil { return err } @@ -72,7 +75,8 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { } userDB := relation.NewUserGorm(db) cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) - database := controller.NewUserDatabase(userDB, cache, tx.NewGorm(db)) + userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) + database := controller.NewUserDatabase(userDB, cache, tx.NewGorm(db), userMongoDB) friendRpcClient := rpcclient.NewFriendRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client) u := &userServer{ @@ -235,6 +239,7 @@ func (s *userServer) GetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Ge return &pbuser.GetGlobalRecvMessageOptResp{GlobalRecvMsgOpt: user[0].GlobalRecvMsgOpt}, nil } +// GetAllUserID Get user account by page. func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDReq) (resp *pbuser.GetAllUserIDResp, err error) { userIDs, err := s.UserDatabase.GetAllUserID(ctx, req.Pagination.PageNumber, req.Pagination.ShowNumber) if err != nil { @@ -243,6 +248,24 @@ func (s *userServer) GetAllUserID(ctx context.Context, req *pbuser.GetAllUserIDR return &pbuser.GetAllUserIDResp{UserIDs: userIDs}, nil } +// SubscribeOrCancelUsersStatus Subscribe online or cancel online users. func (s *userServer) SubscribeOrCancelUsersStatus(ctx context.Context, req *pbuser.SubscribeOrCancelUsersStatusReq) (resp *pbuser.SubscribeOrCancelUsersStatusResp, err error) { + err = s.UserDatabase.SubscribeOrCancelUsersStatus(ctx, req.UserID, req.UserIDs, req.Genre) + if err != nil { + return nil, err + } + //var status map[string][]string + //TODO 获取用户在线列表,返回订阅的用户的在线列表 + + return &pbuser.SubscribeOrCancelUsersStatusResp{}, nil +} + +func (s *userServer) GetUserStatus(ctx context.Context, req *pbuser.GetUserStatusReq) (resp *pbuser.GetUserStatusResp, err error) { + //TODO implement me + panic("implement me") +} + +func (s *userServer) SetUserStatus(ctx context.Context, req *pbuser.SetUserStatusReq) (resp *pbuser.SetUserStatusResp, err error) { + //TODO implement me panic("implement me") } diff --git a/internal/tools/msg.go b/internal/tools/msg.go index 972877516..d13f4597a 100644 --- a/internal/tools/msg.go +++ b/internal/tools/msg.go @@ -82,10 +82,12 @@ func InitMsgTool() (*MsgTool, error) { discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials())) userDB := relation.NewUserGorm(db) msgDatabase := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) + userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userDatabase := controller.NewUserDatabase( userDB, cache.NewUserCacheRedis(rdb, relation.NewUserGorm(db), cache.GetDefaultOpt()), tx.NewGorm(db), + userMongoDB, ) groupDatabase := controller.InitGroupDatabase(db, rdb, mongo.GetDatabase()) conversationDatabase := controller.NewConversationDatabase( diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index 4f9383b09..83942ce22 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -16,6 +16,8 @@ package controller import ( "context" + unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation" + "github.com/OpenIMSDK/protocol/constant" "time" "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache" @@ -26,38 +28,45 @@ import ( ) type UserDatabase interface { - // 获取指定用户的信息 如有userID未找到 也返回错误 + // FindWithError Get the information of the specified user. If the userID is not found, it will also return an error FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) - // 获取指定用户的信息 如有userID未找到 不返回错误 + // Find Get the information of the specified user If the userID is not found, no error will be returned Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) - // 插入多条 外部保证userID 不重复 且在db中不存在 + // Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db Create(ctx context.Context, users []*relation.UserModel) (err error) - // 更新(非零值) 外部保证userID存在 + // Update update (non-zero value) external guarantee userID exists Update(ctx context.Context, user *relation.UserModel) (err error) - // 更新(零值) 外部保证userID存在 + // UpdateByMap update (zero value) external guarantee userID exists UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) - // 如果没找到,不返回错误 + // Page If not found, no error is returned Page(ctx context.Context, pageNumber, showNumber int32) (users []*relation.UserModel, count int64, err error) - // 只要有一个存在就为true + // IsExist true as long as one exists IsExist(ctx context.Context, userIDs []string) (exist bool, err error) - // 获取所有用户ID + // GetAllUserID Get all user IDs GetAllUserID(ctx context.Context, pageNumber, showNumber int32) ([]string, error) - // 函数内部先查询db中是否存在,存在则什么都不做;不存在则插入 + // InitOnce Inside the function, first query whether it exists in the db, if it exists, do nothing; if it does not exist, insert it InitOnce(ctx context.Context, users []*relation.UserModel) (err error) - // 获取用户总数 + // CountTotal Get the total number of users CountTotal(ctx context.Context, before *time.Time) (int64, error) - // 获取范围内用户增量 + // CountRangeEverydayTotal Get the user increment in the range CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) + //SubscribeOrCancelUsersStatus Subscribe or unsubscribe a user's presence status + SubscribeOrCancelUsersStatus(ctx context.Context, userID string, userIDs []string, genre int32) error + // GetAllSubscribeList Get a list of all subscriptions + GetAllSubscribeList(ctx context.Context, userID string) ([]string, error) + // GetSubscribedList Get all subscribed lists + GetSubscribedList(ctx context.Context, userID string) ([]string, error) } type userDatabase struct { - userDB relation.UserModelInterface - cache cache.UserCache - tx tx.Tx + userDB relation.UserModelInterface + cache cache.UserCache + tx tx.Tx + mongoDB unRelationTb.UserModelInterface } -func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx) UserDatabase { - return &userDatabase{userDB: userDB, cache: cache, tx: tx} +func NewUserDatabase(userDB relation.UserModelInterface, cache cache.UserCache, tx tx.Tx, mongoDB unRelationTb.UserModelInterface) UserDatabase { + return &userDatabase{userDB: userDB, cache: cache, tx: tx, mongoDB: mongoDB} } func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel) (err error) { @@ -75,7 +84,7 @@ func (u *userDatabase) InitOnce(ctx context.Context, users []*relation.UserModel return nil } -// 获取指定用户的信息 如有userID未找到 也返回错误. +// FindWithError Get the information of the specified user and return an error if the userID is not found. func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { users, err = u.cache.GetUsersInfo(ctx, userIDs) if err != nil { @@ -87,13 +96,13 @@ func (u *userDatabase) FindWithError(ctx context.Context, userIDs []string) (use return } -// 获取指定用户的信息 如有userID未找到 不返回错误. +// Find Get the information of the specified user. If the userID is not found, no error will be returned. func (u *userDatabase) Find(ctx context.Context, userIDs []string) (users []*relation.UserModel, err error) { users, err = u.cache.GetUsersInfo(ctx, userIDs) return } -// 插入多条 外部保证userID 不重复 且在db中不存在. +// Create Insert multiple external guarantees that the userID is not repeated and does not exist in the db. func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) (err error) { if err := u.tx.Transaction(func(tx any) error { err = u.userDB.Create(ctx, users) @@ -111,7 +120,7 @@ func (u *userDatabase) Create(ctx context.Context, users []*relation.UserModel) return u.cache.DelUsersInfo(userIDs...).ExecDel(ctx) } -// 更新(非零值) 外部保证userID存在. +// Update (non-zero value) externally guarantees that userID exists. func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (err error) { if err := u.userDB.Update(ctx, user); err != nil { return err @@ -119,7 +128,7 @@ func (u *userDatabase) Update(ctx context.Context, user *relation.UserModel) (er return u.cache.DelUsersInfo(user.UserID).ExecDel(ctx) } -// 更新(零值) 外部保证userID存在. +// UpdateByMap update (zero value) externally guarantees that userID exists. func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[string]interface{}) (err error) { if err := u.userDB.UpdateByMap(ctx, userID, args); err != nil { return err @@ -127,7 +136,7 @@ func (u *userDatabase) UpdateByMap(ctx context.Context, userID string, args map[ return u.cache.DelUsersInfo(userID).ExecDel(ctx) } -// 获取,如果没找到,不返回错误. +// Page Gets, returns no error if not found. func (u *userDatabase) Page( ctx context.Context, pageNumber, showNumber int32, @@ -135,7 +144,7 @@ func (u *userDatabase) Page( return u.userDB.Page(ctx, pageNumber, showNumber) } -// userIDs是否存在 只要有一个存在就为true. +// IsExist Does userIDs exist? As long as there is one, it will be true. func (u *userDatabase) IsExist(ctx context.Context, userIDs []string) (exist bool, err error) { users, err := u.userDB.Find(ctx, userIDs) if err != nil { @@ -147,18 +156,42 @@ func (u *userDatabase) IsExist(ctx context.Context, userIDs []string) (exist boo return false, nil } +// GetAllUserID Get all user IDs func (u *userDatabase) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) { return u.userDB.GetAllUserID(ctx, pageNumber, showNumber) } +// CountTotal Get the total number of users func (u *userDatabase) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) { return u.userDB.CountTotal(ctx, before) } -func (u *userDatabase) CountRangeEverydayTotal( - ctx context.Context, - start time.Time, - end time.Time, -) (map[string]int64, error) { +// CountRangeEverydayTotal Get the user increment in the range +func (u *userDatabase) CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error) { return u.userDB.CountRangeEverydayTotal(ctx, start, end) } + +//SubscribeOrCancelUsersStatus Subscribe or unsubscribe a user's presence status +func (u *userDatabase) SubscribeOrCancelUsersStatus(ctx context.Context, userID string, userIDs []string, genre int32) error { + var err error + if genre == constant.SubscriberUser { + err = u.mongoDB.AddSubscriptionList(ctx, userID, userIDs) + } else if genre == constant.Unsubscribe { + err = u.mongoDB.UnsubscriptionList(ctx, userID, userIDs) + } + return err +} + +// GetAllSubscribeList Get a list of all subscriptions. +func (u *userDatabase) GetAllSubscribeList(ctx context.Context, userID string) ([]string, error) { + + //TODO 获取所有订阅 + return nil, nil +} + +// GetSubscribedList Get all subscribed lists +func (u *userDatabase) GetSubscribedList(ctx context.Context, userID string) ([]string, error) { + + //TODO 获取所有被订阅 + return nil, nil +} diff --git a/pkg/common/db/table/unrelation/user.go b/pkg/common/db/table/unrelation/user.go new file mode 100644 index 000000000..d264da467 --- /dev/null +++ b/pkg/common/db/table/unrelation/user.go @@ -0,0 +1,42 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package unrelation + +import "context" + +// SubscribeUser collection constant. +const ( + SubscribeUser = "subscribe_user" +) + +// UserModel collection structure. +type UserModel struct { + UserID string `bson:"user_id" json:"userID"` + UserIDList []string `bson:"user_id_list" json:"userIDList"` +} + +func (UserModel) TableName() string { + return SubscribeUser +} + +// UserModelInterface Operation interface of user mongodb. +type UserModelInterface interface { + // AddSubscriptionList Subscriber's handling of thresholds. + AddSubscriptionList(ctx context.Context, userID string, userIDList []string) error + // UnsubscriptionList Handling of unsubscribe. + UnsubscriptionList(ctx context.Context, userID string, userIDList []string) error + // RemoveSubscribedListFromUser Among the unsubscribed users, delete the user from the subscribed list. + RemoveSubscribedListFromUser(ctx context.Context, userID string, userIDList []string) error +} diff --git a/pkg/common/db/unrelation/user.go b/pkg/common/db/unrelation/user.go new file mode 100644 index 000000000..feec8aa21 --- /dev/null +++ b/pkg/common/db/unrelation/user.go @@ -0,0 +1,141 @@ +// Copyright © 2023 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package unrelation + +import ( + "context" + "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation" + "github.com/OpenIMSDK/tools/utils" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "log" +) + +// prefixes and suffixes. +const ( + SubscriptionPrefix = "subscription_prefix" + SubscribedPrefix = "subscribed_prefix" +) + +// MaximumSubscription Maximum number of subscriptions. +const ( + MaximumSubscription = 3000 +) + +func NewUserMongoDriver(database *mongo.Database) unrelation.UserModelInterface { + return &UserMongoDriver{ + userCollection: database.Collection(unrelation.SubscribeUser), + } +} + +type UserMongoDriver struct { + userCollection *mongo.Collection +} + +// AddSubscriptionList Subscriber's handling of thresholds. +func (u *UserMongoDriver) AddSubscriptionList(ctx context.Context, userID string, userIDList []string) error { + // Check the number of lists in the key. + filter := bson.M{SubscriptionPrefix + userID: bson.M{"$size": 1}} + result, err := u.userCollection.Find(context.Background(), filter) + if err != nil { + return err + } + var newUserIDList []string + for result.Next(context.Background()) { + err := result.Decode(&newUserIDList) + if err != nil { + log.Fatal(err) + } + } + // If the threshold is exceeded, pop out the previous MaximumSubscription - len(userIDList) and insert it. + if len(newUserIDList)+len(userIDList) > MaximumSubscription { + newUserIDList = newUserIDList[MaximumSubscription-len(userIDList):] + _, err := u.userCollection.UpdateOne( + ctx, + bson.M{"user_id": SubscriptionPrefix + userID}, + bson.M{"$set": bson.M{"user_id_list": newUserIDList}}, + ) + if err != nil { + return err + } + //for i := 1; i <= MaximumSubscription-len(userIDList); i++ { + // _, err := u.userCollection.UpdateOne( + // ctx, + // bson.M{"user_id": SubscriptionPrefix + userID}, + // bson.M{SubscriptionPrefix + userID: bson.M{"$pop": -1}}, + // ) + // if err != nil { + // return err + // } + //} + } + upsert := true + opts := &options.UpdateOptions{ + Upsert: &upsert, + } + _, err = u.userCollection.UpdateOne( + ctx, + bson.M{"user_id": SubscriptionPrefix + userID}, + bson.M{"$addToSet": bson.M{"user_id_list": bson.M{"$each": userIDList}}}, + opts, + ) + if err != nil { + return err + } + for _, user := range userIDList { + _, err = u.userCollection.UpdateOne( + ctx, + bson.M{"user_id": SubscribedPrefix + user}, + bson.M{"$addToSet": bson.M{"user_id_list": userID}}, + opts, + ) + if err != nil { + return utils.Wrap(err, "transaction failed") + } + } + return nil +} + +// UnsubscriptionList Handling of unsubscribe. +func (u *UserMongoDriver) UnsubscriptionList(ctx context.Context, userID string, userIDList []string) error { + _, err := u.userCollection.UpdateOne( + ctx, + bson.M{"user_id": SubscriptionPrefix + userID}, + bson.M{"$pull": bson.M{"user_id_list": bson.M{"$in": userIDList}}}, + ) + if err != nil { + return err + } + err = u.RemoveSubscribedListFromUser(ctx, userID, userIDList) + if err != nil { + return err + } + return nil +} + +// RemoveSubscribedListFromUser Among the unsubscribed users, delete the user from the subscribed list. +func (u *UserMongoDriver) RemoveSubscribedListFromUser(ctx context.Context, userID string, userIDList []string) error { + var newUserIDList []string + for _, value := range userIDList { + newUserIDList = append(newUserIDList, SubscribedPrefix+value) + } + _, err := u.userCollection.UpdateOne( + ctx, + bson.M{"user_id": bson.M{"$in": newUserIDList}}, + bson.M{"$pull": bson.M{"user_id_list": userID}}, + ) + return utils.Wrap(err, "") +} From cf59084ddef1bed7a4e07b72329f02faa2ece3c9 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Fri, 28 Jul 2023 14:22:27 +0800 Subject: [PATCH 3/8] Fix/docker images (#689) * docs: add readme docs Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> --------- Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> From 114d77b9d86563d43039d6f7859867c2f5c92b10 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Fri, 28 Jul 2023 14:26:18 +0800 Subject: [PATCH 4/8] docs: add readme docs (#690) * docs: add readme docs Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> --------- Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> From e7040d3b26b3e77a55ae5121614171eea3e81841 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Fri, 28 Jul 2023 14:37:39 +0800 Subject: [PATCH 5/8] docs: add readme docs (#691) * docs: add readme docs Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add script yaml Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * fix bug: reject group req bug * feat: add go relase Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * feat: add test Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> * fix: config env command Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> --------- Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> Co-authored-by: wangchuxiao --- .github/workflows/build-docker-image.yml | 88 ++++++++---------------- .github/workflows/deploy.yml | 72 ++++++++++--------- .goreleaser.yaml | 3 + Dockerfile | 3 +- docs/conversions/images.md | 69 +++++++++++++++++++ docs/conversions/version.md | 6 +- internal/rpc/group/group.go | 11 +-- 7 files changed, 153 insertions(+), 99 deletions(-) create mode 100644 docs/conversions/images.md diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index ef2659724..3dd64c930 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -18,6 +18,7 @@ on: push: branches: - main + - release-* tags: - v* workflow_dispatch: @@ -29,29 +30,38 @@ jobs: - name: Check out the repo uses: actions/checkout@v3 + - name: Build OpenIM Server + run: | + sudo make build + # docker.io/openim/openim-server:latest + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4.6.0 + with: + images: openim/openim-server + - name: Log in to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4.6.0 - with: - images: openim/openim-server - tags: latest - - name: Build and push Docker image uses: docker/build-push-action@v4 with: context: . - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} # registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server:latest + - name: Extract metadata (tags, labels) for Docker + id: meta2 + uses: docker/metadata-action@v4.6.0 + with: + images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server + - name: Log in to AliYun Docker Hub uses: docker/login-action@v2 with: @@ -59,22 +69,21 @@ jobs: username: ${{ secrets.ALIREGISTRY_USERNAME }} password: ${{ secrets.ALIREGISTRY_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta2 - uses: docker/metadata-action@v4.6.0 - with: - images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server - tags: latest - - name: Build and push Docker image uses: docker/build-push-action@v4 with: context: . - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta2.outputs.tags }} labels: ${{ steps.meta2.outputs.labels }} -# ghcr.io/openim/openim-server:latest +# ghcr.io/openimsdk/openim-server:latest + - name: Extract metadata (tags, labels) for Docker + id: meta3 + uses: docker/metadata-action@v4.6.0 + with: + images: ghcr.io/openimsdk/openim-server + - name: Log in to GitHub Container Registry uses: docker/login-action@v2 with: @@ -82,53 +91,10 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta3 - uses: docker/metadata-action@v4.6.0 - with: - images: openim/openim-server - tags: latest - - name: Build and push Docker image uses: docker/build-push-action@v4 with: context: . - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta3.outputs.tags }} labels: ${{ steps.meta3.outputs.labels }} - -# name: OpenIM Build Docker Images -# on: -# push: -# tags: -# - v* -# jobs: -# build: -# runs-on: ubuntu-latest -# strategy: -# matrix: -# bin: -# - openim-server -# steps: -# - name: Checkout -# uses: actions/checkout@v3 -# - name: Setup Docker Buildx -# uses: docker/setup-buildx-action@v2 -# - name: Login to GitHub Container Registry -# uses: docker/login-action@v2 -# with: -# registry: ghcr.io -# username: ${{ github.repository_owner }} -# password: ${{ secrets.GITHUB_TOKEN }} -# - name: Docker metadata -# id: metadata -# uses: docker/metadata-action@v4 -# with: -# images: ghcr.io/${{ github.repository_owner }}/openim-${{ matrix.bin }} -# - name: Build and release Docker images -# uses: docker/build-push-action@v3 -# with: -# platforms: linux/386,linux/amd64,linux/arm64/v8 -# target: ${{ matrix.bin }} -# tags: ${{ steps.metadata.outputs.tags }} -# push: true \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2d7798916..ea28440e9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,6 +18,7 @@ on: push: branches: - 'devops' # Only for the dev branch + - 'main' paths: - '.github/workflows/*' # - '__test__/**' # dev No immediate testing is required @@ -26,38 +27,47 @@ on: - 'docker-compose.yml' - 'bin/*' -env: - SERVER_PRIVATE_KEY: ${{ secrets.SERVER_PRIVATE_KEY }} # server private key - SERVER_HOST: ${{ secrets.SERVER_HOST }} # server ip address - USER_NAME: ${{ secrets.USER_NAME }} # server username - cache-name: note - jobs: deploy-dev: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: set ssh key # Temporarily set up ssh key - run: | - mkdir -p ~/.ssh/ - # secrets.WFP_ID_RSA set in GitHub - echo "${{secrets.WFP_ID_RSA}}" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan "182.92.xxx.xxx" >> ~/.ssh/known_hosts - - name: deploy # Deployment - run: | - ssh work@182.92.xxx.xxx " - # 【Attention】Log in with the 'work' account, manually create /home/work/imooc-lego directory - # Then git clone https://username:password@github.com/imooc-lego/biz-editor-server.git -b dev (private repository, use GitHub username and password) - # Remember to delete origin to avoid exposing GitHub password - cd /home/work/imooc-lego/biz-editor-server; - git remote add origin https://openimbot:${{secrets.WFP_PASSWORD}}@github.com/OpenIMSDK/open-im-server.git; - git checkout dev; - git pull origin dev; # Download the latest code again - git remote remove origin; # Remove origin to avoid exposing GitHub password - # Start docker - docker-compose build editor-server; # Same as the service name in docker-compose.yml - docker-compose up -d; - " - - name: delete ssh key # Delete ssh key - run: rm -rf ~/.ssh/id_rsa \ No newline at end of file + - uses: actions/checkout@v3 + - name: executing remote ssh commands using password + uses: appleboy/ssh-action@v1.0.0 + env: + OWNER: ${{ github.repository_owner }} + REPO: ${{ github.event.repository.name }} + with: + host: "${{ secrets.SG_M1_HOST }}, ${{ secrets.SG_N1_HOST }}, ${{ secrets.SG_N2_HOST}}" + username: ${{ secrets.SG_USERNAME }} + password: ${{ secrets.SG_PASSWORD }} + port: ${{ secrets.SG_PORT }} + envs: OWNER,REPO + script_stop: true + script: | + mkdir -p /test/openim + cd /test/openim + pwd;ls -al + echo "OWNER: $OWNER" + echo "REPO: $REPO" + git clone -b develop https://github.com/${OWNER}/${REPO}.git; cd ${REPO} + docker compose up -d + + + # - name: deploy # Deployment + # run: | + # ssh work@182.92.xxx.xxx " + # # 【Attention】Log in with the 'work' account, manually create /home/work/imooc-lego directory + # # Then git clone https://username:password@github.com/imooc-lego/biz-editor-server.git -b dev (private repository, use GitHub username and password) + # # Remember to delete origin to avoid exposing GitHub password + # cd /home/work/imooc-lego/biz-editor-server; + # git remote add origin https://openimbot:${{secrets.WFP_PASSWORD}}@github.com/OpenIMSDK/open-im-server.git; + # git checkout dev; + # git pull origin dev; # Download the latest code again + # git remote remove origin; # Remove origin to avoid exposing GitHub password + # # Start docker + # docker-compose build editor-server; # Same as the service name in docker-compose.yml + # docker-compose up -d; + # " + # - name: delete ssh key # Delete ssh key + # run: rm -rf ~/.ssh/id_rsa \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e9eb44c94..fc7c0cd01 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -480,6 +480,9 @@ checksum: release: footer: | + + ## Welcome to the {{ .Tag }} release of [chat](https://github.com/OpenIMSDK/chat)!🎉🎉! + **Full Changelog**: https://github.com/OpenIMSDK/Open-IM-Server/compare/{{ .PreviousTag }}...{{ .Tag }} ## Helping out diff --git a/Dockerfile b/Dockerfile index 33c4651c9..290aa02c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,8 @@ RUN /bin/sh -c "make build" # Production Stage FROM alpine -RUN apk --no-cache add tzdata +RUN apk --no-cache add tzdata; \ + apt --no-cache add ca-certificates # Set directory to map logs, config files, scripts, and SDK VOLUME ["/Open-IM-Server/logs", "/Open-IM-Server/config", "/Open-IM-Server/scripts", "/Open-IM-Server/db/sdk"] diff --git a/docs/conversions/images.md b/docs/conversions/images.md new file mode 100644 index 000000000..ae85a5bab --- /dev/null +++ b/docs/conversions/images.md @@ -0,0 +1,69 @@ +# OpenIM Image Management Strategy and Pulling Guide + +OpenIM is an efficient, stable, and scalable instant messaging framework that provides convenient deployment methods through Docker images. OpenIM manages multiple image sources, hosted respectively on GitHub (ghcr), Alibaba Cloud, and Docker Hub. This document is aimed at detailing the image management strategy of OpenIM and providing the steps for pulling these images. + +## Image Management Strategy + +OpenIM's versions correspond to GitHub's tag versions. Each time we release a new version and tag it on GitHub, an automated process is triggered that pushes the new Docker image version to the following three platforms: + +1. **GitHub (ghcr.io):** We use GitHub Container Registry (ghcr.io) to host OpenIM's Docker images. This allows us to better integrate with the GitHub source code repository, providing better version control and continuous integration/deployment (CI/CD) features. You can view all GitHub images [here](https://github.com/orgs/OpenIMSDK/packages). +2. **Alibaba Cloud (registry.cn-hangzhou.aliyuncs.com):** For users in Mainland China, we also host OpenIM's Docker images on Alibaba Cloud to provide faster pull speeds. You can view all Alibaba Cloud images on this [page](https://cr.console.aliyun.com/cn-hangzhou/instances/repositories) of Alibaba Cloud Image Service (note that you need to log in to your Alibaba Cloud account first). +3. **Docker Hub (docker.io):** Docker Hub is the most commonly used Docker image hosting platform, and we also host OpenIM's images there to facilitate developers worldwide. You can view all Docker Hub images on the [OpenIM's Docker Hub page](https://hub.docker.com/r/openim). + +## Methods and Steps for Pulling Images + +When pulling OpenIM's Docker images, you can choose the most suitable source based on your geographic location and network conditions. Here are the steps to pull OpenIM images from each source: + +1. First, make sure Docker is installed on your machine. If not, you can refer to the [Docker official documentation](https://docs.docker.com/get-docker/) for installation. + +2. Open the terminal and run the following commands to pull the images: + + For OpenIM Server: + + - Pull from GitHub: + + ``` + bashCopy code + docker pull ghcr.io/openimsdk/openim-server:latest + ``` + + - Pull from Alibaba Cloud: + + ``` + bashCopy code + docker pull registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server:latest + ``` + + - Pull from Docker Hub: + + ``` + bashCopy code + docker pull docker.io/openim/openim-server:latest + ``` + + For OpenIM Chat: + + - Pull from GitHub: + + ``` + bashCopy code + docker pull ghcr.io/openimsdk/openim-chat:latest + ``` + + - Pull from Alibaba Cloud: + + ``` + bashCopy code + docker pull registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat:latest + ``` + + - Pull from Docker Hub: + + ``` + bashCopy code + docker pull docker.io/openim/openim-chat:latest + ``` + +3. Run the `docker images` command to confirm that the image has been successfully pulled. + +This concludes OpenIM's image management strategy and the steps for pulling images. If you have any questions, please feel free to ask. \ No newline at end of file diff --git a/docs/conversions/version.md b/docs/conversions/version.md index a421dd549..bf1062b77 100644 --- a/docs/conversions/version.md +++ b/docs/conversions/version.md @@ -54,4 +54,8 @@ git merge release-v3.1 git push origin main ``` -Remember, communication with your team is key throughout this process, keeping everyone up-to-date with the changes being made. \ No newline at end of file +Remember, communication with your team is key throughout this process, keeping everyone up-to-date with the changes being made. + + +## Docker images version management + diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 4ce3d4216..65beae37e 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -17,14 +17,15 @@ package group import ( "context" "fmt" - "github.com/OpenIMSDK/Open-IM-Server/pkg/authverify" - "github.com/OpenIMSDK/Open-IM-Server/pkg/msgprocessor" "math/big" "math/rand" "strconv" "strings" "time" + "github.com/OpenIMSDK/Open-IM-Server/pkg/authverify" + "github.com/OpenIMSDK/Open-IM-Server/pkg/msgprocessor" + pbConversation "github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/wrapperspb" @@ -718,11 +719,11 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup if err := s.GroupDatabase.HandlerGroupRequest(ctx, req.GroupID, req.FromUserID, req.HandledMsg, req.HandleResult, member); err != nil { return nil, err } - if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.FromUserID}); err != nil { - return nil, err - } switch req.HandleResult { case constant.GroupResponseAgree: + if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.FromUserID}); err != nil { + return nil, err + } s.Notification.GroupApplicationAcceptedNotification(ctx, req) case constant.GroupResponseRefuse: s.Notification.GroupApplicationRejectedNotification(ctx, req) From 8979b9dce19df9c58cdde4beed461aae7f7e9c73 Mon Sep 17 00:00:00 2001 From: Xinwei Xiong <3293172751@qq.com> Date: Fri, 28 Jul 2023 15:09:04 +0800 Subject: [PATCH 6/8] fix: docker file fix (#692) Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com> --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 290aa02c6..8a230a431 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,8 +22,8 @@ RUN /bin/sh -c "make build" # Production Stage FROM alpine -RUN apk --no-cache add tzdata; \ - apt --no-cache add ca-certificates +RUN echo "https://mirrors.aliyun.com/alpine/v3.4/main" > /etc/apk/repositories && \ + apk --no-cache add tzdata ca-certificates # Set directory to map logs, config files, scripts, and SDK VOLUME ["/Open-IM-Server/logs", "/Open-IM-Server/config", "/Open-IM-Server/scripts", "/Open-IM-Server/db/sdk"] From e24b0e21149ebd316d3ee5ad9baf1ea5d09e4468 Mon Sep 17 00:00:00 2001 From: pluto <83957921+plutoyty@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:54:29 +0800 Subject: [PATCH 7/8] Get user online status (#693) * Resolving code conflicts after project directory changes and Add subscribe and unsubscribe mongodb operations * Organize and update module dependencies * Get user online status * Get user online status * Get user online status --- internal/api/route.go | 1 + internal/api/user.go | 4 ++ internal/rpc/user/user.go | 15 ++++-- pkg/common/db/cache/user.go | 85 ++++++++++++++++++++++++++++++-- pkg/common/db/controller/user.go | 16 ++++++ 5 files changed, 114 insertions(+), 7 deletions(-) diff --git a/internal/api/route.go b/internal/api/route.go index 0f46f0f0c..1926b55f1 100644 --- a/internal/api/route.go +++ b/internal/api/route.go @@ -81,6 +81,7 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive userRouterGroup.POST("/get_users_online_token_detail", ParseToken, u.GetUsersOnlineTokenDetail) userRouterGroup.POST("/subscribe_users_status", ParseToken, u.UnSubscriberStatus) userRouterGroup.POST("/unsubscribe_users_status", ParseToken, u.UnSubscriberStatus) + userRouterGroup.POST("/get_users_status", ParseToken, u.GetUserStatus) } // friend routing group diff --git a/internal/api/user.go b/internal/api/user.go index 108ccac69..3eb136b3d 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -194,3 +194,7 @@ func (u *UserApi) SubscriberStatus(c *gin.Context) { func (u *UserApi) UnSubscriberStatus(c *gin.Context) { a2r.Call(user.UserClient.SubscribeOrCancelUsersStatus, u.Client, c) } + +func (u *UserApi) GetUserStatus(c *gin.Context) { + a2r.Call(user.UserClient.GetUserStatus, u.Client, c) +} diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go index 576492566..53598db0b 100644 --- a/internal/rpc/user/user.go +++ b/internal/rpc/user/user.go @@ -261,11 +261,18 @@ func (s *userServer) SubscribeOrCancelUsersStatus(ctx context.Context, req *pbus } func (s *userServer) GetUserStatus(ctx context.Context, req *pbuser.GetUserStatusReq) (resp *pbuser.GetUserStatusResp, err error) { - //TODO implement me - panic("implement me") + //TODO 是否加一个参数校验-判断req.userID的数量,每一个获取加一个限制,一次请求限制500? + onlineStatusList, err := s.UserDatabase.GetUserStatus(ctx, req.UserIDs) + if err != nil { + return nil, err + } + return &pbuser.GetUserStatusResp{StatusList: onlineStatusList}, nil } func (s *userServer) SetUserStatus(ctx context.Context, req *pbuser.SetUserStatusReq) (resp *pbuser.SetUserStatusResp, err error) { - //TODO implement me - panic("implement me") + err = s.UserDatabase.SetUserStatus(ctx, req.StatusList) + if err != nil { + return nil, err + } + return &pbuser.SetUserStatusResp{}, nil } diff --git a/pkg/common/db/cache/user.go b/pkg/common/db/cache/user.go index 455bc9ebe..5c76af22f 100644 --- a/pkg/common/db/cache/user.go +++ b/pkg/common/db/cache/user.go @@ -16,6 +16,9 @@ package cache import ( "context" + "encoding/json" + "github.com/OpenIMSDK/protocol/user" + "strconv" "time" "github.com/dtm-labs/rockscache" @@ -25,9 +28,12 @@ import ( ) const ( - userExpireTime = time.Second * 60 * 60 * 12 - userInfoKey = "USER_INFO:" - userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" + userExpireTime = time.Second * 60 * 60 * 12 + userInfoKey = "USER_INFO:" + userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:" + olineStatusKey = "ONLINE_STATUS:" + userOlineStatusExpireTime = time.Second * 60 * 60 * 24 + statusMod = 500 ) type UserCache interface { @@ -38,10 +44,13 @@ type UserCache interface { DelUsersInfo(userIDs ...string) UserCache GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache + GetUserStatus(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) + SetUserStatus(ctx context.Context, list []*user.OnlineStatus) error } type UserCacheRedis struct { metaCache + rdb redis.UniversalClient userDB relationTb.UserModelInterface expireTime time.Duration rcClient *rockscache.Client @@ -54,6 +63,7 @@ func NewUserCacheRedis( ) UserCache { rcClient := rockscache.NewClient(rdb, options) return &UserCacheRedis{ + rdb: rdb, metaCache: NewMetaCacheRedis(rcClient), userDB: userDB, expireTime: userExpireTime, @@ -63,6 +73,7 @@ func NewUserCacheRedis( func (u *UserCacheRedis) NewCache() UserCache { return &UserCacheRedis{ + rdb: u.rdb, metaCache: NewMetaCacheRedis(u.rcClient, u.metaCache.GetPreDelKeys()...), userDB: u.userDB, expireTime: u.expireTime, @@ -145,3 +156,71 @@ func (u *UserCacheRedis) DelUsersGlobalRecvMsgOpt(userIDs ...string) UserCache { cache.AddKeys(keys...) return cache } + +func (u *UserCacheRedis) getOnlineStatusKey(userID string) string { + return olineStatusKey + userID +} + +// GetUserStatus get user status +func (u *UserCacheRedis) GetUserStatus(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) { + var res []*user.OnlineStatus + for _, userID := range userIDs { + UserIDNum, err := strconv.Atoi(userID) + if err != nil { + return nil, err + } + var modKey = strconv.Itoa(UserIDNum % statusMod) + var onlineStatus user.OnlineStatus + key := olineStatusKey + modKey + result, err := u.rdb.HGet(ctx, key, userID).Result() + if err != nil { + if err == redis.Nil { + // key or field does not exist + res = append(res, &user.OnlineStatus{ + UserID: userID, + Status: 0, + PlatformID: -1, + }) + continue + } else { + return nil, err + } + } + err = json.Unmarshal([]byte(result), &onlineStatus) + if err != nil { + return nil, err + } + onlineStatus.UserID = userID + res = append(res, &onlineStatus) + } + return res, nil +} + +// SetUserStatus Set the user status and save it in redis +func (u *UserCacheRedis) SetUserStatus(ctx context.Context, list []*user.OnlineStatus) error { + for _, status := range list { + var isNewKey int64 + UserIDNum, err := strconv.Atoi(status.UserID) + if err != nil { + return err + } + var modKey = strconv.Itoa(UserIDNum % statusMod) + key := olineStatusKey + modKey + jsonData, err := json.Marshal(status) + if err != nil { + return err + } + isNewKey, err = u.rdb.Exists(ctx, key).Result() + if err != nil { + return err + } + _, err = u.rdb.HSet(ctx, key, status.UserID, string(jsonData)).Result() + if err != nil { + return err + } + if isNewKey > 0 { + u.rdb.Expire(ctx, key, userOlineStatusExpireTime) + } + } + return nil +} diff --git a/pkg/common/db/controller/user.go b/pkg/common/db/controller/user.go index 83942ce22..5b303ebd7 100644 --- a/pkg/common/db/controller/user.go +++ b/pkg/common/db/controller/user.go @@ -18,6 +18,7 @@ import ( "context" unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation" "github.com/OpenIMSDK/protocol/constant" + "github.com/OpenIMSDK/protocol/user" "time" "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache" @@ -56,6 +57,10 @@ type UserDatabase interface { GetAllSubscribeList(ctx context.Context, userID string) ([]string, error) // GetSubscribedList Get all subscribed lists GetSubscribedList(ctx context.Context, userID string) ([]string, error) + // GetUserStatus Get the online status of the user + GetUserStatus(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) + // SetUserStatus Set the user status and store the user status in redis + SetUserStatus(ctx context.Context, list []*user.OnlineStatus) error } type userDatabase struct { @@ -195,3 +200,14 @@ func (u *userDatabase) GetSubscribedList(ctx context.Context, userID string) ([] //TODO 获取所有被订阅 return nil, nil } + +// GetUserStatus get user status +func (u *userDatabase) GetUserStatus(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) { + onlineStatusList, err := u.cache.GetUserStatus(ctx, userIDs) + return onlineStatusList, err +} + +// SetUserStatus Set the user status and save it in redis +func (u *userDatabase) SetUserStatus(ctx context.Context, list []*user.OnlineStatus) error { + return u.cache.SetUserStatus(ctx, list) +} From c9c698551bc03c3ba74ae83220bf82c652b6d376 Mon Sep 17 00:00:00 2001 From: wangchuxiao Date: Fri, 28 Jul 2023 20:16:32 +0800 Subject: [PATCH 8/8] fix bug: join group failed --- internal/rpc/group/group.go | 2 +- pkg/common/db/controller/group.go | 5 +++++ pkg/common/db/relation/group_model.go | 4 ++++ pkg/common/db/table/relation/group.go | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 65beae37e..a7680dfaa 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -1040,7 +1040,7 @@ func (s *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbGrou groupIDs := utils.Distinct(utils.Slice(requests, func(e *relationTb.GroupRequestModel) string { return e.GroupID })) - groups, err := s.GroupDatabase.FindGroup(ctx, groupIDs) + groups, err := s.GroupDatabase.FindNotDismissedGroup(ctx, groupIDs) if err != nil { return nil, err } diff --git a/pkg/common/db/controller/group.go b/pkg/common/db/controller/group.go index e2b5f90b3..ba4ae18df 100644 --- a/pkg/common/db/controller/group.go +++ b/pkg/common/db/controller/group.go @@ -39,6 +39,7 @@ type GroupDatabase interface { CreateGroup(ctx context.Context, groups []*relationTb.GroupModel, groupMembers []*relationTb.GroupMemberModel) error TakeGroup(ctx context.Context, groupID string) (group *relationTb.GroupModel, err error) FindGroup(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error) + FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error) SearchGroup( ctx context.Context, keyword string, @@ -581,3 +582,7 @@ func (g *groupDatabase) CountRangeEverydayTotal(ctx context.Context, start time. func (g *groupDatabase) FindGroupRequests(ctx context.Context, groupID string, userIDs []string) (int64, []*relationTb.GroupRequestModel, error) { return g.groupRequestDB.FindGroupRequests(ctx, groupID, userIDs) } + +func (g *groupDatabase) FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*relationTb.GroupModel, err error) { + return g.groupDB.FindNotDismissedGroup(ctx, groupIDs) +} diff --git a/pkg/common/db/relation/group_model.go b/pkg/common/db/relation/group_model.go index 697427e04..853f5dccd 100644 --- a/pkg/common/db/relation/group_model.go +++ b/pkg/common/db/relation/group_model.go @@ -99,3 +99,7 @@ func (g *GroupGorm) CountRangeEverydayTotal(ctx context.Context, start time.Time } return v, nil } + +func (g *GroupGorm) FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*relation.GroupModel, err error) { + return groups, utils.Wrap(g.DB.Where("group_id in (?) and status != ?", groupIDs, constant.GroupStatusDismissed).Find(&groups).Error, "") +} diff --git a/pkg/common/db/table/relation/group.go b/pkg/common/db/table/relation/group.go index 2bafb53ec..6759e0d35 100644 --- a/pkg/common/db/table/relation/group.go +++ b/pkg/common/db/table/relation/group.go @@ -51,6 +51,7 @@ type GroupModelInterface interface { UpdateMap(ctx context.Context, groupID string, args map[string]interface{}) (err error) UpdateStatus(ctx context.Context, groupID string, status int32) (err error) Find(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) + FindNotDismissedGroup(ctx context.Context, groupIDs []string) (groups []*GroupModel, err error) Take(ctx context.Context, groupID string) (group *GroupModel, err error) Search( ctx context.Context,