mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-05-01 07:35:58 +08:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e6c90d4ea1 | |||
| 8530692a53 | |||
| 7f8ff8ff2e | |||
| a7e97d8905 | |||
| f0ca2e6fda | |||
| 57f6638b11 | |||
| 58fc7c0a80 | |||
| a816e76f16 | |||
| 59811ad196 | |||
| 59b7324d6c | |||
| a6a70dc22e | |||
| d948e6603c | |||
| 66dd9f6e09 | |||
| 0e61c3acef | |||
| e81803a53d | |||
| a338731fe9 | |||
| a64f6d108a | |||
| 825416bbba | |||
| 6e2132d217 | |||
| 27ad975359 | |||
| b1a7439516 | |||
| 24b9dca935 | |||
| 27e62c9cd0 | |||
| d6d151d8f5 | |||
| ae3dcacd79 | |||
| 1921e4416f | |||
| e85d699f5f | |||
| dd7e2e3a74 | |||
| 7730f60943 | |||
| a938e03def | |||
| 51fb4737cf | |||
| e5cf56bf0f | |||
| 3c24a9be15 | |||
| a6ac0b990e | |||
| fc94eed98b | |||
| ed45f6f860 | |||
| caed25252d | |||
| 54f13e74ff | |||
| 37947623e3 | |||
| 210936411d | |||
| a3fff86ed8 | |||
| 9f67a41189 | |||
| ae78ea479e | |||
| 87d8a1dbb7 | |||
| 34c7f22ba8 | |||
| eabe4d53da | |||
| a5341346e9 | |||
| 5282ab9f36 | |||
| bd31f6b49c | |||
| d4ed448d7d | |||
| 76d8253aeb | |||
| c2009ceff6 | |||
| 39a6141787 | |||
| 6a05e64f3f | |||
| d91cde90ef | |||
| 90370557e3 | |||
| d89c17bcf0 | |||
| 1964a4b3fd | |||
| c40de0b12e | |||
| 31f28a54ab | |||
| 86737c9004 | |||
| 86d3a668fd | |||
| 16a9dfba27 | |||
| 24a0479761 | |||
| b2ca1366f8 | |||
| 1a14191d66 | |||
| 9d313cb308 | |||
| 38e11dc678 | |||
| b940bcaafe | |||
| efa74a95a7 | |||
| 119a2c2247 | |||
| 4266fed44f | |||
| c81e199698 | |||
| 9660556f35 | |||
| c7067bc48a | |||
| 84f97a72f4 | |||
| 5a81a7a560 | |||
| 0ee68e57b9 | |||
| 59529718bb | |||
| e3d78de887 | |||
| e3ff304394 | |||
| 899f1f15a4 | |||
| 33094ec532 | |||
| e26a582836 | |||
| 77894b104e | |||
| c16f17582a | |||
| 445db67568 | |||
| 30ef247a59 | |||
| 025eb44113 | |||
| af5e191144 | |||
| 4a042489bf | |||
| 9e4a7d082d | |||
| 000f6ce595 | |||
| f53dd855aa | |||
| f1506e40c4 | |||
| b9eb642616 | |||
| 1c93f87e95 | |||
| b2eae0999c | |||
| 1afdd0bcf7 | |||
| 45859d9cab | |||
| d26a1b2090 | |||
| 1e81d29e86 | |||
| 6e1f96a720 | |||
| 656bfef069 | |||
| 1db6e3b389 | |||
| 32221da613 | |||
| ad5e4e1540 | |||
| c9193302a8 | |||
| 640c363eee | |||
| abbb701192 | |||
| b87e366d74 | |||
| 3e30e50a09 | |||
| 41d2c7be7a | |||
| 166d51ab23 | |||
| 749eb11830 | |||
| a81bc3fc23 | |||
| 9908e2c658 | |||
| 45064ae5ca | |||
| 1f1ab65375 | |||
| 48ff03f854 | |||
| a00d77a705 | |||
| ad979d493d | |||
| f5f2cf4746 | |||
| 4c3c4555a3 | |||
| 006e4a1e93 | |||
| 8ff8861603 | |||
| 2d21ab3aeb | |||
| a84ad774f7 | |||
| ee9c9eb97c | |||
| da2c0d11f5 | |||
| 7a67beb7a1 | |||
| 28292be37d | |||
| 1ea5fe04f1 | |||
| c16cd0bf7c | |||
| 03e15766ab | |||
| f0e5c587ad | |||
| b0ec48d35d | |||
| 8360c72300 | |||
| 18ad656087 | |||
| 22c00c411e | |||
| f0075265d5 | |||
| 86aebfc0bd | |||
| bbb5ef5ccc | |||
| 0248fbb47d | |||
| 938622b1fe | |||
| 3d77c1c8cf | |||
| 1ae523dcc2 | |||
| d9921248a7 |
@@ -0,0 +1,7 @@
|
|||||||
|
directory: ./
|
||||||
|
file_types:
|
||||||
|
- .go
|
||||||
|
- .yaml
|
||||||
|
- .yml
|
||||||
|
languages:
|
||||||
|
- Chinese
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
name: Language Check Workflow Test
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment-language-detector:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Code Language Detector
|
||||||
|
uses: kubecub/comment-lang-detector@v1.0.0
|
||||||
+2
-4
@@ -3,16 +3,14 @@ FROM golang:1.20 AS builder
|
|||||||
|
|
||||||
# Set go mod installation source and proxy
|
# Set go mod installation source and proxy
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
ENV GO111MODULE=$GO111MODULE
|
ENV GO111MODULE=$GO111MODULE
|
||||||
ENV GOPROXY=$GOPROXY
|
ENV GOPROXY=$GOPROXY
|
||||||
|
|
||||||
# Set up the working directory
|
# Set up the working directory
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
# Copy all files to the container
|
# Copy all files to the container
|
||||||
ADD . .
|
ADD . .
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
FROM golang:1.20 AS builder
|
FROM golang:1.20 AS builder
|
||||||
|
|
||||||
ARG GO111MODULE=on
|
ARG GO111MODULE=on
|
||||||
ARG GOPROXY=https://goproxy.cn,direct
|
ARG GOPROXY=https://goproxy.io,direct
|
||||||
|
|
||||||
WORKDIR /openim/openim-server
|
WORKDIR /openim/openim-server
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ MONGO_OPENIM_PASSWORD=openIM123
|
|||||||
# Default: MONGO_DATABASE=openim_v3
|
# Default: MONGO_DATABASE=openim_v3
|
||||||
MONGO_DATABASE=openim_v3
|
MONGO_DATABASE=openim_v3
|
||||||
|
|
||||||
|
MONGO_MAX_POOL_SIZE=100
|
||||||
# ----- Redis Configuration -----
|
# ----- Redis Configuration -----
|
||||||
|
|
||||||
# Port on which Redis in-memory data structure store is running.
|
# Port on which Redis in-memory data structure store is running.
|
||||||
|
|||||||
@@ -535,3 +535,39 @@ prometheus:
|
|||||||
rtcPrometheusPort: [ ${RTC_PROM_PORT} ]
|
rtcPrometheusPort: [ ${RTC_PROM_PORT} ]
|
||||||
thirdPrometheusPort: [ ${THIRD_PROM_PORT} ]
|
thirdPrometheusPort: [ ${THIRD_PROM_PORT} ]
|
||||||
messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports
|
messageTransferPrometheusPort: [ ${MSG_TRANSFER_PROM_PORT} ] # List of ports
|
||||||
|
|
||||||
|
###################### LocalCache configuration information ######################
|
||||||
|
# topic: redis subscriber channel
|
||||||
|
# slotNum: number of slots, multiple slots can prevent too many keys from competing for a lock
|
||||||
|
# slotSize: number of slots, the number of cached keys per slot, the overall cache quantity is slotNum * slotSize
|
||||||
|
# successExpire: successful cache time seconds
|
||||||
|
# failedExpire: failed cache time seconds
|
||||||
|
# disable local caching and annotate topic, slotNum, and slotSize
|
||||||
|
localCache:
|
||||||
|
user:
|
||||||
|
topic: DELETE_CACHE_USER
|
||||||
|
slotNum: 100
|
||||||
|
slotSize: 2000
|
||||||
|
successExpire: 300
|
||||||
|
failedExpire: 5
|
||||||
|
|
||||||
|
group:
|
||||||
|
topic: DELETE_CACHE_GROUP
|
||||||
|
slotNum: 100
|
||||||
|
slotSize: 2000
|
||||||
|
successExpire: 300
|
||||||
|
failedExpire: 5
|
||||||
|
|
||||||
|
friend:
|
||||||
|
topic: DELETE_CACHE_FRIEND
|
||||||
|
slotNum: 100
|
||||||
|
slotSize: 2000
|
||||||
|
successExpire: 300
|
||||||
|
failedExpire: 5
|
||||||
|
|
||||||
|
conversation:
|
||||||
|
topic: DELETE_CACHE_CONVERSATION
|
||||||
|
slotNum: 100
|
||||||
|
slotSize: 2000
|
||||||
|
successExpire: 300
|
||||||
|
failedExpire: 5
|
||||||
@@ -118,6 +118,7 @@ MONGO_OPENIM_PASSWORD=${MONGO_OPENIM_PASSWORD}
|
|||||||
# Default: MONGO_DATABASE=openim_v3
|
# Default: MONGO_DATABASE=openim_v3
|
||||||
MONGO_DATABASE=${MONGO_DATABASE}
|
MONGO_DATABASE=${MONGO_DATABASE}
|
||||||
|
|
||||||
|
MONGO_MAX_POOL_SIZE=${MONGO_MAX_POOL_SIZE}
|
||||||
# ----- Redis Configuration -----
|
# ----- Redis Configuration -----
|
||||||
|
|
||||||
# Port on which Redis in-memory data structure store is running.
|
# Port on which Redis in-memory data structure store is running.
|
||||||
@@ -142,7 +143,7 @@ KAFKA_LATESTMSG_REDIS_TOPIC=${KAFKA_LATESTMSG_REDIS_TOPIC}
|
|||||||
# MINIO_PORT
|
# MINIO_PORT
|
||||||
# ----------
|
# ----------
|
||||||
# MINIO_PORT sets the port for the MinIO object storage service.
|
# MINIO_PORT sets the port for the MinIO object storage service.
|
||||||
# Upon changing this port, the MinIO endpoint URLs in the `config/config.yaml` file must be updated
|
# Upon changing this port, the MinIO endpoint URLs in the config/config.yaml file must be updated
|
||||||
# to reflect this change. The endpoints include both the 'endpoint' and 'signEndpoint'
|
# to reflect this change. The endpoints include both the 'endpoint' and 'signEndpoint'
|
||||||
# under the MinIO configuration.
|
# under the MinIO configuration.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ require (
|
|||||||
github.com/minio/minio-go/v7 v7.0.67
|
github.com/minio/minio-go/v7 v7.0.67
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
|
github.com/openimsdk/localcache v0.0.1
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.18.0
|
github.com/prometheus/client_golang v1.18.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
@@ -84,6 +85,7 @@ require (
|
|||||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
||||||
@@ -162,3 +164,5 @@ require (
|
|||||||
golang.org/x/crypto v0.19.0 // indirect
|
golang.org/x/crypto v0.19.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace github.com/openimsdk/localcache => ./pkg/localcache
|
||||||
|
|||||||
@@ -178,6 +178,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
|
|||||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
|||||||
@@ -3,16 +3,13 @@ go 1.19
|
|||||||
use (
|
use (
|
||||||
.
|
.
|
||||||
./test/typecheck
|
./test/typecheck
|
||||||
./tools/codescan
|
|
||||||
./tools/changelog
|
./tools/changelog
|
||||||
./tools/component
|
./tools/component
|
||||||
./tools/data-conversion
|
|
||||||
./tools/formitychecker
|
./tools/formitychecker
|
||||||
./tools/imctl
|
./tools/imctl
|
||||||
./tools/infra
|
./tools/infra
|
||||||
./tools/ncpu
|
./tools/ncpu
|
||||||
./tools/openim-web
|
./tools/openim-web
|
||||||
./tools/up35
|
|
||||||
./tools/url2im
|
./tools/url2im
|
||||||
./tools/versionchecker
|
./tools/versionchecker
|
||||||
./tools/yamlfmt
|
./tools/yamlfmt
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig,
|
|||||||
// func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID
|
// func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID
|
||||||
// string) cbApi.CommonCallbackResp {
|
// string) cbApi.CommonCallbackResp {
|
||||||
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
||||||
// if !config.Config.Callback.CallbackUserOnline.Enable {
|
// if !config.Config.Callback.CallbackUserOnline.WithEnable {
|
||||||
// return callbackResp
|
// return callbackResp
|
||||||
// }
|
// }
|
||||||
// callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{
|
// callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{
|
||||||
@@ -129,7 +129,7 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig,
|
|||||||
//}
|
//}
|
||||||
//func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp {
|
//func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp {
|
||||||
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
||||||
// if !config.Config.Callback.CallbackUserOffline.Enable {
|
// if !config.Config.Callback.CallbackUserOffline.WithEnable {
|
||||||
// return callbackResp
|
// return callbackResp
|
||||||
// }
|
// }
|
||||||
// callbackOfflineReq := cbApi.CallbackUserOfflineReq{
|
// callbackOfflineReq := cbApi.CallbackUserOfflineReq{
|
||||||
@@ -156,7 +156,7 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig,
|
|||||||
//}
|
//}
|
||||||
//func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp {
|
//func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp {
|
||||||
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
||||||
// if !config.Config.Callback.CallbackUserKickOff.Enable {
|
// if !config.Config.Callback.CallbackUserKickOff.WithEnable {
|
||||||
// return callbackResp
|
// return callbackResp
|
||||||
// }
|
// }
|
||||||
// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{
|
// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/OpenIMSDK/tools/errs"
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
"github.com/OpenIMSDK/tools/log"
|
"github.com/OpenIMSDK/tools/log"
|
||||||
"github.com/OpenIMSDK/tools/mcontext"
|
"github.com/OpenIMSDK/tools/mcontext"
|
||||||
"github.com/OpenIMSDK/tools/utils"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||||
@@ -58,22 +57,25 @@ type Server struct {
|
|||||||
rpcPort int
|
rpcPort int
|
||||||
prometheusPort int
|
prometheusPort int
|
||||||
LongConnServer LongConnServer
|
LongConnServer LongConnServer
|
||||||
pushTerminal []int
|
|
||||||
config *config.GlobalConfig
|
config *config.GlobalConfig
|
||||||
|
pushTerminal map[int]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
||||||
s.LongConnServer = LongConnServer
|
s.LongConnServer = LongConnServer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, config *config.GlobalConfig) *Server {
|
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *config.GlobalConfig) *Server {
|
||||||
return &Server{
|
s := &Server{
|
||||||
rpcPort: rpcPort,
|
rpcPort: rpcPort,
|
||||||
prometheusPort: proPort,
|
prometheusPort: proPort,
|
||||||
LongConnServer: longConnServer,
|
LongConnServer: longConnServer,
|
||||||
pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID},
|
pushTerminal: make(map[int]struct{}),
|
||||||
config: config,
|
config: conf,
|
||||||
}
|
}
|
||||||
|
s.pushTerminal[constant.IOSPlatformID] = struct{}{}
|
||||||
|
s.pushTerminal[constant.AndroidPlatformID] = struct{}{}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) OnlinePushMsg(
|
func (s *Server) OnlinePushMsg(
|
||||||
@@ -127,13 +129,9 @@ func (s *Server) OnlineBatchPushOneMsg(
|
|||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SuperGroupOnlineBatchPushOneMsg(
|
func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq,
|
||||||
ctx context.Context,
|
|
||||||
req *msggateway.OnlineBatchPushOneMsgReq,
|
|
||||||
) (*msggateway.OnlineBatchPushOneMsgResp, error) {
|
) (*msggateway.OnlineBatchPushOneMsgResp, error) {
|
||||||
|
|
||||||
var singleUserResults []*msggateway.SingleMsgToUserResults
|
var singleUserResults []*msggateway.SingleMsgToUserResults
|
||||||
|
|
||||||
for _, v := range req.PushToUserIDs {
|
for _, v := range req.PushToUserIDs {
|
||||||
var resp []*msggateway.SingleMsgToUserPlatform
|
var resp []*msggateway.SingleMsgToUserPlatform
|
||||||
results := &msggateway.SingleMsgToUserResults{
|
results := &msggateway.SingleMsgToUserResults{
|
||||||
@@ -154,23 +152,22 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
userPlatform := &msggateway.SingleMsgToUserPlatform{
|
userPlatform := &msggateway.SingleMsgToUserPlatform{
|
||||||
RecvID: v,
|
|
||||||
RecvPlatFormID: int32(client.PlatformID),
|
RecvPlatFormID: int32(client.PlatformID),
|
||||||
}
|
}
|
||||||
if !client.IsBackground ||
|
if !client.IsBackground ||
|
||||||
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) {
|
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) {
|
||||||
err := client.PushMessage(ctx, req.MsgData)
|
err := client.PushMessage(ctx, req.MsgData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
userPlatform.ResultCode = -2
|
userPlatform.ResultCode = int64(errs.ErrPushMsgErr.Code())
|
||||||
resp = append(resp, userPlatform)
|
resp = append(resp, userPlatform)
|
||||||
} else {
|
} else {
|
||||||
if utils.IsContainInt(client.PlatformID, s.pushTerminal) {
|
if _, ok := s.pushTerminal[client.PlatformID]; ok {
|
||||||
results.OnlinePush = true
|
results.OnlinePush = true
|
||||||
resp = append(resp, userPlatform)
|
resp = append(resp, userPlatform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userPlatform.ResultCode = -3
|
userPlatform.ResultCode = int64(errs.ErrIOSBackgroundPushErr.Code())
|
||||||
resp = append(resp, userPlatform)
|
resp = append(resp, userPlatform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package push
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/constant"
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
pbpush "github.com/OpenIMSDK/protocol/push"
|
pbpush "github.com/OpenIMSDK/protocol/push"
|
||||||
@@ -25,7 +26,6 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
@@ -51,8 +51,8 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg
|
|||||||
client,
|
client,
|
||||||
offlinePusher,
|
offlinePusher,
|
||||||
database,
|
database,
|
||||||
localcache.NewGroupLocalCache(&groupRpcClient),
|
rpccache.NewGroupLocalCache(groupRpcClient, rdb),
|
||||||
localcache.NewConversationLocalCache(&conversationRpcClient),
|
rpccache.NewConversationLocalCache(conversationRpcClient, rdb),
|
||||||
&conversationRpcClient,
|
&conversationRpcClient,
|
||||||
&groupRpcClient,
|
&groupRpcClient,
|
||||||
&msgRpcClient,
|
&msgRpcClient,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/constant"
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
@@ -36,7 +37,6 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
@@ -49,8 +49,8 @@ type Pusher struct {
|
|||||||
database controller.PushDatabase
|
database controller.PushDatabase
|
||||||
discov discoveryregistry.SvcDiscoveryRegistry
|
discov discoveryregistry.SvcDiscoveryRegistry
|
||||||
offlinePusher offlinepush.OfflinePusher
|
offlinePusher offlinepush.OfflinePusher
|
||||||
groupLocalCache *localcache.GroupLocalCache
|
groupLocalCache *rpccache.GroupLocalCache
|
||||||
conversationLocalCache *localcache.ConversationLocalCache
|
conversationLocalCache *rpccache.ConversationLocalCache
|
||||||
msgRpcClient *rpcclient.MessageRpcClient
|
msgRpcClient *rpcclient.MessageRpcClient
|
||||||
conversationRpcClient *rpcclient.ConversationRpcClient
|
conversationRpcClient *rpcclient.ConversationRpcClient
|
||||||
groupRpcClient *rpcclient.GroupRpcClient
|
groupRpcClient *rpcclient.GroupRpcClient
|
||||||
@@ -59,7 +59,7 @@ type Pusher struct {
|
|||||||
var errNoOfflinePusher = errors.New("no offlinePusher is configured")
|
var errNoOfflinePusher = errors.New("no offlinePusher is configured")
|
||||||
|
|
||||||
func NewPusher(config *config.GlobalConfig, discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase,
|
func NewPusher(config *config.GlobalConfig, discov discoveryregistry.SvcDiscoveryRegistry, offlinePusher offlinepush.OfflinePusher, database controller.PushDatabase,
|
||||||
groupLocalCache *localcache.GroupLocalCache, conversationLocalCache *localcache.ConversationLocalCache,
|
groupLocalCache *rpccache.GroupLocalCache, conversationLocalCache *rpccache.ConversationLocalCache,
|
||||||
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient,
|
conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient, msgRpcClient *rpcclient.MessageRpcClient,
|
||||||
) *Pusher {
|
) *Pusher {
|
||||||
return &Pusher{
|
return &Pusher{
|
||||||
|
|||||||
@@ -48,14 +48,6 @@ type conversationServer struct {
|
|||||||
config *config.GlobalConfig
|
config *config.GlobalConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(
|
|
||||||
ctx context.Context,
|
|
||||||
req *pbconversation.GetConversationNotReceiveMessageUserIDsReq,
|
|
||||||
) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
|
func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
|
||||||
rdb, err := cache.NewRedis(config)
|
rdb, err := cache.NewRedis(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -96,11 +88,11 @@ func (c *conversationServer) GetConversation(ctx context.Context, req *pbconvers
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *conversationServer) GetSortedConversationList(ctx context.Context, req *pbconversation.GetSortedConversationListReq) (resp *pbconversation.GetSortedConversationListResp, err error) {
|
func (c *conversationServer) GetSortedConversationList(ctx context.Context, req *pbconversation.GetSortedConversationListReq) (resp *pbconversation.GetSortedConversationListResp, err error) {
|
||||||
log.ZDebug(ctx, "GetSortedConversationList", "seqs", req, "userID", req.UserID)
|
log.ZDebug(ctx, "GetSortedConversationList", "seqs", req, "userID", req.UserID)
|
||||||
var conversationIDs []string
|
var conversationIDs []string
|
||||||
if len(req.ConversationIDs) == 0 {
|
if len(req.ConversationIDs) == 0 {
|
||||||
conversationIDs, err = m.conversationDatabase.GetConversationIDs(ctx, req.UserID)
|
conversationIDs, err = c.conversationDatabase.GetConversationIDs(ctx, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -108,7 +100,7 @@ func (m *conversationServer) GetSortedConversationList(ctx context.Context, req
|
|||||||
conversationIDs = req.ConversationIDs
|
conversationIDs = req.ConversationIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
conversations, err := m.conversationDatabase.FindConversations(ctx, req.UserID, conversationIDs)
|
conversations, err := c.conversationDatabase.FindConversations(ctx, req.UserID, conversationIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -116,22 +108,22 @@ func (m *conversationServer) GetSortedConversationList(ctx context.Context, req
|
|||||||
return nil, errs.ErrRecordNotFound.Wrap()
|
return nil, errs.ErrRecordNotFound.Wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
maxSeqs, err := m.msgRpcClient.GetMaxSeqs(ctx, conversationIDs)
|
maxSeqs, err := c.msgRpcClient.GetMaxSeqs(ctx, conversationIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
chatLogs, err := m.msgRpcClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs)
|
chatLogs, err := c.msgRpcClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
conversationMsg, err := m.getConversationInfo(ctx, chatLogs, req.UserID)
|
conversationMsg, err := c.getConversationInfo(ctx, chatLogs, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
hasReadSeqs, err := m.msgRpcClient.GetHasReadSeqs(ctx, req.UserID, conversationIDs)
|
hasReadSeqs, err := c.msgRpcClient.GetHasReadSeqs(ctx, req.UserID, conversationIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -163,8 +155,8 @@ func (m *conversationServer) GetSortedConversationList(ctx context.Context, req
|
|||||||
UnreadTotal: unreadTotal,
|
UnreadTotal: unreadTotal,
|
||||||
}
|
}
|
||||||
|
|
||||||
m.conversationSort(conversation_isPinTime, resp, conversation_unreadCount, conversationMsg)
|
c.conversationSort(conversation_isPinTime, resp, conversation_unreadCount, conversationMsg)
|
||||||
m.conversationSort(conversation_notPinTime, resp, conversation_unreadCount, conversationMsg)
|
c.conversationSort(conversation_notPinTime, resp, conversation_unreadCount, conversationMsg)
|
||||||
|
|
||||||
resp.ConversationElems = utils.Paginate(resp.ConversationElems, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber()))
|
resp.ConversationElems = utils.Paginate(resp.ConversationElems, int(req.Pagination.GetPageNumber()), int(req.Pagination.GetShowNumber()))
|
||||||
return resp, nil
|
return resp, nil
|
||||||
@@ -514,19 +506,27 @@ func (c *conversationServer) getConversationInfo(
|
|||||||
switch chatLog.SessionType {
|
switch chatLog.SessionType {
|
||||||
case constant.SingleChatType:
|
case constant.SingleChatType:
|
||||||
if chatLog.SendID == userID {
|
if chatLog.SendID == userID {
|
||||||
msgInfo.FaceURL = sendMap[chatLog.RecvID].FaceURL
|
if recv, ok := sendMap[chatLog.RecvID]; ok {
|
||||||
msgInfo.SenderName = sendMap[chatLog.RecvID].Nickname
|
msgInfo.FaceURL = recv.FaceURL
|
||||||
|
msgInfo.SenderName = recv.Nickname
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
msgInfo.FaceURL = sendMap[chatLog.SendID].FaceURL
|
if send, ok := sendMap[chatLog.SendID]; ok {
|
||||||
msgInfo.SenderName = sendMap[chatLog.SendID].Nickname
|
msgInfo.FaceURL = send.FaceURL
|
||||||
|
msgInfo.SenderName = send.Nickname
|
||||||
|
}
|
||||||
case constant.GroupChatType, constant.SuperGroupChatType:
|
case constant.GroupChatType, constant.SuperGroupChatType:
|
||||||
msgInfo.GroupName = groupMap[chatLog.GroupID].GroupName
|
|
||||||
msgInfo.GroupFaceURL = groupMap[chatLog.GroupID].FaceURL
|
|
||||||
msgInfo.GroupMemberCount = groupMap[chatLog.GroupID].MemberCount
|
|
||||||
msgInfo.GroupID = chatLog.GroupID
|
msgInfo.GroupID = chatLog.GroupID
|
||||||
msgInfo.GroupType = groupMap[chatLog.GroupID].GroupType
|
if group, ok := groupMap[chatLog.GroupID]; ok {
|
||||||
msgInfo.SenderName = sendMap[chatLog.SendID].Nickname
|
msgInfo.GroupName = group.GroupName
|
||||||
|
msgInfo.GroupFaceURL = group.FaceURL
|
||||||
|
msgInfo.GroupMemberCount = group.MemberCount
|
||||||
|
msgInfo.GroupType = group.GroupType
|
||||||
|
}
|
||||||
|
if send, ok := sendMap[chatLog.SendID]; ok {
|
||||||
|
msgInfo.SenderName = send.Nickname
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pbchatLog.ConversationID = conversationID
|
pbchatLog.ConversationID = conversationID
|
||||||
msgInfo.LatestMsgRecvTime = chatLog.SendTime
|
msgInfo.LatestMsgRecvTime = chatLog.SendTime
|
||||||
@@ -535,3 +535,11 @@ func (c *conversationServer) getConversationInfo(
|
|||||||
}
|
}
|
||||||
return conversationMsg, nil
|
return conversationMsg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(ctx context.Context, req *pbconversation.GetConversationNotReceiveMessageUserIDsReq) (*pbconversation.GetConversationNotReceiveMessageUserIDsResp, error) {
|
||||||
|
userIDs, err := c.conversationDatabase.GetConversationNotReceiveMessageUserIDs(ctx, req.ConversationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pbconversation.GetConversationNotReceiveMessageUserIDsResp{UserIDs: userIDs}, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,26 +16,31 @@ package friend
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/tx"
|
||||||
|
|
||||||
|
"github.com/OpenIMSDK/protocol/sdkws"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||||
|
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/constant"
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
pbfriend "github.com/OpenIMSDK/protocol/friend"
|
pbfriend "github.com/OpenIMSDK/protocol/friend"
|
||||||
"github.com/OpenIMSDK/protocol/sdkws"
|
|
||||||
registry "github.com/OpenIMSDK/tools/discoveryregistry"
|
registry "github.com/OpenIMSDK/tools/discoveryregistry"
|
||||||
"github.com/OpenIMSDK/tools/errs"
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
"github.com/OpenIMSDK/tools/log"
|
|
||||||
"github.com/OpenIMSDK/tools/tx"
|
|
||||||
"github.com/OpenIMSDK/tools/utils"
|
"github.com/OpenIMSDK/tools/utils"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
|
||||||
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type friendServer struct {
|
type friendServer struct {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func (m *msgServer) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *m
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conversations, err := m.Conversation.GetConversations(ctx, req.UserID, conversationIDs)
|
conversations, err := m.ConversationLocalCache.GetConversations(ctx, req.UserID, conversationIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ func (m *msgServer) MarkMsgsAsRead(
|
|||||||
if hasReadSeq > maxSeq {
|
if hasReadSeq > maxSeq {
|
||||||
return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq")
|
return nil, errs.ErrArgs.Wrap("hasReadSeq must not be bigger than maxSeq")
|
||||||
}
|
}
|
||||||
conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID)
|
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func (m *msgServer) MarkConversationAsRead(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *msg.MarkConversationAsReadReq,
|
req *msg.MarkConversationAsReadReq,
|
||||||
) (resp *msg.MarkConversationAsReadResp, err error) {
|
) (resp *msg.MarkConversationAsReadResp, err error) {
|
||||||
conversation, err := m.Conversation.GetConversation(ctx, req.UserID, req.ConversationID)
|
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, req.ConversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,27 +156,27 @@ func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, m
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error {
|
func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error {
|
||||||
if !globalConfig.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text {
|
if !globalConfig.Callback.CallbackGroupMsgRead.Enable {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand
|
req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand
|
||||||
|
|
||||||
resp := &cbapi.CallbackGroupMsgReadResp{}
|
resp := &cbapi.CallbackGroupMsgReadResp{}
|
||||||
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil {
|
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackGroupMsgRead); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error {
|
func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error {
|
||||||
if !globalConfig.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text {
|
if !globalConfig.Callback.CallbackSingleMsgRead.Enable {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
req.CallbackCommand = cbapi.CallbackSingleMsgRead
|
req.CallbackCommand = cbapi.CallbackSingleMsgRead
|
||||||
|
|
||||||
resp := &cbapi.CallbackSingleMsgReadResp{}
|
resp := &cbapi.CallbackSingleMsgReadResp{}
|
||||||
|
|
||||||
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil {
|
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackSingleMsgRead); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
|
|||||||
if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
|
if err := authverify.CheckAccessV3(ctx, req.UserID, m.config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user, err := m.User.GetUserInfo(ctx, req.UserID)
|
user, err := m.UserLocalCache.GetUserInfo(ctx, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -70,12 +70,7 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
|
|||||||
}
|
}
|
||||||
role = user.AppMangerLevel
|
role = user.AppMangerLevel
|
||||||
case constant.SuperGroupChatType:
|
case constant.SuperGroupChatType:
|
||||||
members, err := m.Group.GetGroupMemberInfoMap(
|
members, err := m.GroupLocalCache.GetGroupMemberInfoMap(ctx, msgs[0].GroupID, utils.Distinct([]string{req.UserID, msgs[0].SendID}))
|
||||||
ctx,
|
|
||||||
msgs[0].GroupID,
|
|
||||||
utils.Distinct([]string{req.UserID, msgs[0].SendID}),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
|
|||||||
}
|
}
|
||||||
tagAll := utils.IsContain(constant.AtAllString, msg.AtUserIDList)
|
tagAll := utils.IsContain(constant.AtAllString, msg.AtUserIDList)
|
||||||
if tagAll {
|
if tagAll {
|
||||||
memberUserIDList, err := m.Group.GetGroupMemberIDs(ctx, msg.GroupID)
|
memberUserIDList, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, msg.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZWarn(ctx, "GetGroupMemberIDs", err)
|
log.ZWarn(ctx, "GetGroupMemberIDs", err)
|
||||||
return
|
return
|
||||||
@@ -143,6 +143,7 @@ func (m *msgServer) sendMsgNotification(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) {
|
func (m *msgServer) sendMsgSingleChat(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, err error) {
|
||||||
|
log.ZDebug(ctx, "sendMsgSingleChat return")
|
||||||
if err := m.messageVerification(ctx, req); err != nil {
|
if err := m.messageVerification(ctx, req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-11
@@ -15,6 +15,8 @@
|
|||||||
package msg
|
package msg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/constant"
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
"github.com/OpenIMSDK/protocol/conversation"
|
"github.com/OpenIMSDK/protocol/conversation"
|
||||||
"github.com/OpenIMSDK/protocol/msg"
|
"github.com/OpenIMSDK/protocol/msg"
|
||||||
@@ -22,7 +24,6 @@ import (
|
|||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -33,12 +34,11 @@ type (
|
|||||||
msgServer struct {
|
msgServer struct {
|
||||||
RegisterCenter discoveryregistry.SvcDiscoveryRegistry
|
RegisterCenter discoveryregistry.SvcDiscoveryRegistry
|
||||||
MsgDatabase controller.CommonMsgDatabase
|
MsgDatabase controller.CommonMsgDatabase
|
||||||
Group *rpcclient.GroupRpcClient
|
|
||||||
User *rpcclient.UserRpcClient
|
|
||||||
Conversation *rpcclient.ConversationRpcClient
|
Conversation *rpcclient.ConversationRpcClient
|
||||||
friend *rpcclient.FriendRpcClient
|
UserLocalCache *rpccache.UserLocalCache
|
||||||
GroupLocalCache *localcache.GroupLocalCache
|
FriendLocalCache *rpccache.FriendLocalCache
|
||||||
ConversationLocalCache *localcache.ConversationLocalCache
|
GroupLocalCache *rpccache.GroupLocalCache
|
||||||
|
ConversationLocalCache *rpccache.ConversationLocalCache
|
||||||
Handlers MessageInterceptorChain
|
Handlers MessageInterceptorChain
|
||||||
notificationSender *rpcclient.NotificationSender
|
notificationSender *rpcclient.NotificationSender
|
||||||
config *config.GlobalConfig
|
config *config.GlobalConfig
|
||||||
@@ -84,13 +84,12 @@ func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryReg
|
|||||||
}
|
}
|
||||||
s := &msgServer{
|
s := &msgServer{
|
||||||
Conversation: &conversationClient,
|
Conversation: &conversationClient,
|
||||||
User: &userRpcClient,
|
|
||||||
Group: &groupRpcClient,
|
|
||||||
MsgDatabase: msgDatabase,
|
MsgDatabase: msgDatabase,
|
||||||
RegisterCenter: client,
|
RegisterCenter: client,
|
||||||
GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient),
|
UserLocalCache: rpccache.NewUserLocalCache(userRpcClient, rdb),
|
||||||
ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient),
|
GroupLocalCache: rpccache.NewGroupLocalCache(groupRpcClient, rdb),
|
||||||
friend: &friendRpcClient,
|
ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, rdb),
|
||||||
|
FriendLocalCache: rpccache.NewFriendLocalCache(friendRpcClient, rdb),
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg))
|
s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg))
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (m *msgServer) GetActiveUser(ctx context.Context, req *msg.GetActiveUserReq
|
|||||||
var pbUsers []*msg.ActiveUser
|
var pbUsers []*msg.ActiveUser
|
||||||
if len(users) > 0 {
|
if len(users) > 0 {
|
||||||
userIDs := utils.Slice(users, func(e *unrelation.UserCount) string { return e.UserID })
|
userIDs := utils.Slice(users, func(e *unrelation.UserCount) string { return e.UserID })
|
||||||
userMap, err := m.User.GetUsersInfoMap(ctx, userIDs)
|
userMap, err := m.UserLocalCache.GetUsersInfoMap(ctx, userIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ func (m *msgServer) GetActiveGroup(ctx context.Context, req *msg.GetActiveGroupR
|
|||||||
var pbgroups []*msg.ActiveGroup
|
var pbgroups []*msg.ActiveGroup
|
||||||
if len(groups) > 0 {
|
if len(groups) > 0 {
|
||||||
groupIDs := utils.Slice(groups, func(e *unrelation.GroupCount) string { return e.GroupID })
|
groupIDs := utils.Slice(groups, func(e *unrelation.GroupCount) string { return e.GroupID })
|
||||||
resp, err := m.Group.GetGroupInfos(ctx, groupIDs, false)
|
resp, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func (m *msgServer) PullMessageBySeqs(
|
|||||||
resp.NotificationMsgs = make(map[string]*sdkws.PullMsgs)
|
resp.NotificationMsgs = make(map[string]*sdkws.PullMsgs)
|
||||||
for _, seq := range req.SeqRanges {
|
for _, seq := range req.SeqRanges {
|
||||||
if !msgprocessor.IsNotification(seq.ConversationID) {
|
if !msgprocessor.IsNotification(seq.ConversationID) {
|
||||||
conversation, err := m.Conversation.GetConversation(ctx, req.UserID, seq.ConversationID)
|
conversation, err := m.ConversationLocalCache.GetConversation(ctx, req.UserID, seq.ConversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID)
|
log.ZError(ctx, "GetConversation error", err, "conversationID", seq.ConversationID)
|
||||||
continue
|
continue
|
||||||
@@ -138,7 +138,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(sendIDs) != 0 {
|
if len(sendIDs) != 0 {
|
||||||
sendInfos, err := m.User.GetUsersInfo(ctx, sendIDs)
|
sendInfos, err := m.UserLocalCache.GetUsersInfo(ctx, sendIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(recvIDs) != 0 {
|
if len(recvIDs) != 0 {
|
||||||
recvInfos, err := m.User.GetUsersInfo(ctx, recvIDs)
|
recvInfos, err := m.UserLocalCache.GetUsersInfo(ctx, recvIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(groupIDs) != 0 {
|
if len(groupIDs) != 0 {
|
||||||
groupInfos, err := m.Group.GetGroupInfos(ctx, groupIDs, true)
|
groupInfos, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-16
@@ -16,6 +16,7 @@ package msg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -59,15 +60,15 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
|
|||||||
data.MsgData.ContentType >= constant.NotificationBegin {
|
data.MsgData.ContentType >= constant.NotificationBegin {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
black, err := m.friend.IsBlocked(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
black, err := m.FriendLocalCache.IsBlack(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if black {
|
if black {
|
||||||
return errs.ErrBlockedByPeer.Wrap()
|
return errs.ErrBlockedByPeer.Wrap()
|
||||||
}
|
}
|
||||||
if *m.config.MessageVerify.FriendVerify {
|
if m.config.MessageVerify.FriendVerify != nil && *m.config.MessageVerify.FriendVerify {
|
||||||
friend, err := m.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
friend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case constant.SuperGroupChatType:
|
case constant.SuperGroupChatType:
|
||||||
groupInfo, err := m.Group.GetGroupInfoCache(ctx, data.MsgData.GroupID)
|
groupInfo, err := m.GroupLocalCache.GetGroupInfo(ctx, data.MsgData.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -99,17 +100,17 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
|
|||||||
data.MsgData.ContentType >= constant.NotificationBegin {
|
data.MsgData.ContentType >= constant.NotificationBegin {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// memberIDs, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, data.MsgData.GroupID)
|
memberIDs, err := m.GroupLocalCache.GetGroupMemberIDMap(ctx, data.MsgData.GroupID)
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if !utils.IsContain(data.MsgData.SendID, memberIDs) {
|
|
||||||
// return errs.ErrNotInGroupYet.Wrap()
|
|
||||||
// }
|
|
||||||
|
|
||||||
groupMemberInfo, err := m.Group.GetGroupMemberCache(ctx, data.MsgData.GroupID, data.MsgData.SendID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errs.ErrRecordNotFound {
|
return err
|
||||||
|
}
|
||||||
|
if _, ok := memberIDs[data.MsgData.SendID]; !ok {
|
||||||
|
return errs.ErrNotInGroupYet.Wrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
groupMemberInfo, err := m.GroupLocalCache.GetGroupMember(ctx, data.MsgData.GroupID, data.MsgData.SendID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
return errs.ErrNotInGroupYet.Wrap(err.Error())
|
return errs.ErrNotInGroupYet.Wrap(err.Error())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -187,7 +188,8 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(
|
|||||||
sessionType int,
|
sessionType int,
|
||||||
pb *msg.SendMsgReq,
|
pb *msg.SendMsgReq,
|
||||||
) (bool, error) {
|
) (bool, error) {
|
||||||
opt, err := m.User.GetUserGlobalMsgRecvOpt(ctx, userID)
|
defer log.ZDebug(ctx, "modifyMessageByUserMessageReceiveOpt return")
|
||||||
|
opt, err := m.UserLocalCache.GetUserGlobalMsgRecvOpt(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -203,7 +205,7 @@ func (m *msgServer) modifyMessageByUserMessageReceiveOpt(
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
// conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType)
|
// conversationID := utils.GetConversationIDBySessionType(conversationID, sessionType)
|
||||||
singleOpt, err := m.Conversation.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID)
|
singleOpt, err := m.ConversationLocalCache.GetSingleConversationRecvMsgOpt(ctx, userID, conversationID)
|
||||||
if errs.ErrRecordNotFound.Is(err) {
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
return true, nil
|
return true, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cachekey
|
||||||
|
|
||||||
|
const (
|
||||||
|
BlackIDsKey = "BLACK_IDS:"
|
||||||
|
IsBlackKey = "IS_BLACK:" // local cache
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetBlackIDsKey(ownerUserID string) string {
|
||||||
|
return BlackIDsKey + ownerUserID
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIsBlackIDsKey(possibleBlackUserID, userID string) string {
|
||||||
|
return IsBlackKey + userID + "-" + possibleBlackUserID
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package cachekey
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConversationKey = "CONVERSATION:"
|
||||||
|
ConversationIDsKey = "CONVERSATION_IDS:"
|
||||||
|
ConversationIDsHashKey = "CONVERSATION_IDS_HASH:"
|
||||||
|
ConversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
|
||||||
|
RecvMsgOptKey = "RECV_MSG_OPT:"
|
||||||
|
SuperGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
|
||||||
|
SuperGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
|
||||||
|
ConversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetConversationKey(ownerUserID, conversationID string) string {
|
||||||
|
return ConversationKey + ownerUserID + ":" + conversationID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConversationIDsKey(ownerUserID string) string {
|
||||||
|
return ConversationIDsKey + ownerUserID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
|
||||||
|
return SuperGroupRecvMsgNotNotifyUserIDsKey + groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRecvMsgOptKey(ownerUserID, conversationID string) string {
|
||||||
|
return RecvMsgOptKey + ownerUserID + ":" + conversationID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
|
||||||
|
return SuperGroupRecvMsgNotNotifyUserIDsHashKey + groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConversationHasReadSeqKey(ownerUserID, conversationID string) string {
|
||||||
|
return ConversationHasReadSeqKey + ownerUserID + ":" + conversationID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConversationNotReceiveMessageUserIDsKey(conversationID string) string {
|
||||||
|
return ConversationNotReceiveMessageUserIDsKey + conversationID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserConversationIDsHashKey(ownerUserID string) string {
|
||||||
|
return ConversationIDsHashKey + ownerUserID
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package cachekey
|
||||||
|
|
||||||
|
const (
|
||||||
|
FriendIDsKey = "FRIEND_IDS:"
|
||||||
|
TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
|
||||||
|
FriendKey = "FRIEND_INFO:"
|
||||||
|
IsFriendKey = "IS_FRIEND:" // local cache key
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetFriendIDsKey(ownerUserID string) string {
|
||||||
|
return FriendIDsKey + ownerUserID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTwoWayFriendsIDsKey(ownerUserID string) string {
|
||||||
|
return TwoWayFriendsIDsKey + ownerUserID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFriendKey(ownerUserID, friendUserID string) string {
|
||||||
|
return FriendKey + ownerUserID + "-" + friendUserID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIsFriendKey(possibleFriendUserID, userID string) string {
|
||||||
|
return IsFriendKey + possibleFriendUserID + "-" + userID
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package cachekey
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
groupExpireTime = time.Second * 60 * 60 * 12
|
||||||
|
GroupInfoKey = "GROUP_INFO:"
|
||||||
|
GroupMemberIDsKey = "GROUP_MEMBER_IDS:"
|
||||||
|
GroupMembersHashKey = "GROUP_MEMBERS_HASH2:"
|
||||||
|
GroupMemberInfoKey = "GROUP_MEMBER_INFO:"
|
||||||
|
JoinedGroupsKey = "JOIN_GROUPS_KEY:"
|
||||||
|
GroupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
|
||||||
|
GroupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetGroupInfoKey(groupID string) string {
|
||||||
|
return GroupInfoKey + groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetJoinedGroupsKey(userID string) string {
|
||||||
|
return JoinedGroupsKey + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupMembersHashKey(groupID string) string {
|
||||||
|
return GroupMembersHashKey + groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupMemberIDsKey(groupID string) string {
|
||||||
|
return GroupMemberIDsKey + groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupMemberInfoKey(groupID, userID string) string {
|
||||||
|
return GroupMemberInfoKey + groupID + "-" + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupMemberNumKey(groupID string) string {
|
||||||
|
return GroupMemberNumKey + groupID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
|
||||||
|
return GroupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel))
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package cachekey
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserInfoKey = "USER_INFO:"
|
||||||
|
UserGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetUserInfoKey(userID string) string {
|
||||||
|
return UserInfoKey + userID
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserGlobalRecvMsgOptKey(userID string) string {
|
||||||
|
return UserGlobalRecvMsgOptKey + userID
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -266,6 +267,8 @@ type GlobalConfig struct {
|
|||||||
FriendVerify *bool `yaml:"friendVerify"`
|
FriendVerify *bool `yaml:"friendVerify"`
|
||||||
} `yaml:"messageVerify"`
|
} `yaml:"messageVerify"`
|
||||||
|
|
||||||
|
LocalCache localCache `yaml:"localCache"`
|
||||||
|
|
||||||
IOSPush struct {
|
IOSPush struct {
|
||||||
PushSound string `yaml:"pushSound"`
|
PushSound string `yaml:"pushSound"`
|
||||||
BadgeCount bool `yaml:"badgeCount"`
|
BadgeCount bool `yaml:"badgeCount"`
|
||||||
@@ -382,6 +385,33 @@ type notification struct {
|
|||||||
ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"`
|
ConversationSetPrivate NotificationConf `yaml:"conversationSetPrivate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalCache struct {
|
||||||
|
Topic string `yaml:"topic"`
|
||||||
|
SlotNum int `yaml:"slotNum"`
|
||||||
|
SlotSize int `yaml:"slotSize"`
|
||||||
|
SuccessExpire int `yaml:"successExpire"` // second
|
||||||
|
FailedExpire int `yaml:"failedExpire"` // second
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LocalCache) Failed() time.Duration {
|
||||||
|
return time.Second * time.Duration(l.FailedExpire)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LocalCache) Success() time.Duration {
|
||||||
|
return time.Second * time.Duration(l.SuccessExpire)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LocalCache) Enable() bool {
|
||||||
|
return l.Topic != "" && l.SlotNum > 0 && l.SlotSize > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type localCache struct {
|
||||||
|
User LocalCache `yaml:"user"`
|
||||||
|
Group LocalCache `yaml:"group"`
|
||||||
|
Friend LocalCache `yaml:"friend"`
|
||||||
|
Conversation LocalCache `yaml:"conversation"`
|
||||||
|
}
|
||||||
|
|
||||||
func (c *GlobalConfig) GetServiceNames() []string {
|
func (c *GlobalConfig) GetServiceNames() []string {
|
||||||
return []string{
|
return []string{
|
||||||
c.RpcRegisterName.OpenImUserName,
|
c.RpcRegisterName.OpenImUserName,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -116,3 +118,13 @@ func TestInitConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestName(t *testing.T) {
|
||||||
|
Config.LocalCache.Friend.Topic = "friend"
|
||||||
|
Config.LocalCache.Friend.SlotNum = 500
|
||||||
|
Config.LocalCache.Friend.SlotSize = 20000
|
||||||
|
|
||||||
|
data, _ := yaml.Marshal(&Config)
|
||||||
|
|
||||||
|
fmt.Println(string(data))
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+11
-4
@@ -16,6 +16,9 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dtm-labs/rockscache"
|
"github.com/dtm-labs/rockscache"
|
||||||
@@ -47,11 +50,15 @@ type BlackCacheRedis struct {
|
|||||||
|
|
||||||
func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache {
|
func NewBlackCacheRedis(rdb redis.UniversalClient, blackDB relationtb.BlackModelInterface, options rockscache.Options) BlackCache {
|
||||||
rcClient := rockscache.NewClient(rdb, options)
|
rcClient := rockscache.NewClient(rdb, options)
|
||||||
|
mc := NewMetaCacheRedis(rcClient)
|
||||||
|
b := config.Config.LocalCache.Friend
|
||||||
|
log.ZDebug(context.Background(), "black local cache init", "Topic", b.Topic, "SlotNum", b.SlotNum, "SlotSize", b.SlotSize, "enable", b.Enable())
|
||||||
|
mc.SetTopic(b.Topic)
|
||||||
|
mc.SetRawRedisClient(rdb)
|
||||||
return &BlackCacheRedis{
|
return &BlackCacheRedis{
|
||||||
expireTime: blackExpireTime,
|
expireTime: blackExpireTime,
|
||||||
rcClient: rcClient,
|
rcClient: rcClient,
|
||||||
metaCache: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
blackDB: blackDB,
|
blackDB: blackDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,12 +68,12 @@ func (b *BlackCacheRedis) NewCache() BlackCache {
|
|||||||
expireTime: b.expireTime,
|
expireTime: b.expireTime,
|
||||||
rcClient: b.rcClient,
|
rcClient: b.rcClient,
|
||||||
blackDB: b.blackDB,
|
blackDB: b.blackDB,
|
||||||
metaCache: NewMetaCacheRedis(b.rcClient, b.metaCache.GetPreDelKeys()...),
|
metaCache: b.Copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string {
|
func (b *BlackCacheRedis) getBlackIDsKey(ownerUserID string) string {
|
||||||
return blackIDsKey + ownerUserID
|
return cachekey.GetBlackIDsKey(ownerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) {
|
func (b *BlackCacheRedis) GetBlackIDs(ctx context.Context, userID string) (blackIDs []string, err error) {
|
||||||
|
|||||||
Vendored
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
subscribe map[string][]string
|
||||||
|
)
|
||||||
|
|
||||||
|
func getPublishKey(topic string, key []string) []string {
|
||||||
|
if topic == "" || len(key) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
once.Do(func() {
|
||||||
|
list := []struct {
|
||||||
|
Local config.LocalCache
|
||||||
|
Keys []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Local: config.Config.LocalCache.User,
|
||||||
|
Keys: []string{cachekey.UserInfoKey, cachekey.UserGlobalRecvMsgOptKey},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Local: config.Config.LocalCache.Group,
|
||||||
|
Keys: []string{cachekey.GroupMemberIDsKey, cachekey.GroupInfoKey, cachekey.GroupMemberInfoKey},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Local: config.Config.LocalCache.Friend,
|
||||||
|
Keys: []string{cachekey.FriendIDsKey, cachekey.BlackIDsKey},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Local: config.Config.LocalCache.Conversation,
|
||||||
|
Keys: []string{cachekey.ConversationKey, cachekey.ConversationIDsKey, cachekey.ConversationNotReceiveMessageUserIDsKey},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
subscribe = make(map[string][]string)
|
||||||
|
for _, v := range list {
|
||||||
|
if v.Local.Enable() {
|
||||||
|
subscribe[v.Local.Topic] = v.Keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
prefix, ok := subscribe[topic]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
res := make([]string, 0, len(key))
|
||||||
|
for _, k := range key {
|
||||||
|
var exist bool
|
||||||
|
for _, p := range prefix {
|
||||||
|
if strings.HasPrefix(k, p) {
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if exist {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
Vendored
+29
-22
@@ -16,6 +16,9 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -27,14 +30,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
conversationKey = "CONVERSATION:"
|
//conversationKey = "CONVERSATION:"
|
||||||
conversationIDsKey = "CONVERSATION_IDS:"
|
//conversationIDsKey = "CONVERSATION_IDS:"
|
||||||
conversationIDsHashKey = "CONVERSATION_IDS_HASH:"
|
//conversationIDsHashKey = "CONVERSATION_IDS_HASH:"
|
||||||
conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
|
//conversationHasReadSeqKey = "CONVERSATION_HAS_READ_SEQ:"
|
||||||
recvMsgOptKey = "RECV_MSG_OPT:"
|
//recvMsgOptKey = "RECV_MSG_OPT:"
|
||||||
superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
|
//superGroupRecvMsgNotNotifyUserIDsKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS:"
|
||||||
superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
|
//superGroupRecvMsgNotNotifyUserIDsHashKey = "SUPER_GROUP_RECV_MSG_NOT_NOTIFY_USER_IDS_HASH:"
|
||||||
conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:"
|
//conversationNotReceiveMessageUserIDsKey = "CONVERSATION_NOT_RECEIVE_MESSAGE_USER_IDS:"
|
||||||
|
|
||||||
conversationExpireTime = time.Second * 60 * 60 * 12
|
conversationExpireTime = time.Second * 60 * 60 * 12
|
||||||
)
|
)
|
||||||
@@ -81,10 +84,14 @@ type ConversationCache interface {
|
|||||||
|
|
||||||
func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache {
|
func NewConversationRedis(rdb redis.UniversalClient, opts rockscache.Options, db relationtb.ConversationModelInterface) ConversationCache {
|
||||||
rcClient := rockscache.NewClient(rdb, opts)
|
rcClient := rockscache.NewClient(rdb, opts)
|
||||||
|
mc := NewMetaCacheRedis(rcClient)
|
||||||
|
c := config.Config.LocalCache.Conversation
|
||||||
|
log.ZDebug(context.Background(), "black local cache init", "Topic", c.Topic, "SlotNum", c.SlotNum, "SlotSize", c.SlotSize, "enable", c.Enable())
|
||||||
|
mc.SetTopic(c.Topic)
|
||||||
|
mc.SetRawRedisClient(rdb)
|
||||||
return &ConversationRedisCache{
|
return &ConversationRedisCache{
|
||||||
rcClient: rcClient,
|
rcClient: rcClient,
|
||||||
metaCache: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
conversationDB: db,
|
conversationDB: db,
|
||||||
expireTime: conversationExpireTime,
|
expireTime: conversationExpireTime,
|
||||||
}
|
}
|
||||||
@@ -115,38 +122,42 @@ type ConversationRedisCache struct {
|
|||||||
func (c *ConversationRedisCache) NewCache() ConversationCache {
|
func (c *ConversationRedisCache) NewCache() ConversationCache {
|
||||||
return &ConversationRedisCache{
|
return &ConversationRedisCache{
|
||||||
rcClient: c.rcClient,
|
rcClient: c.rcClient,
|
||||||
metaCache: NewMetaCacheRedis(c.rcClient, c.metaCache.GetPreDelKeys()...),
|
metaCache: c.Copy(),
|
||||||
conversationDB: c.conversationDB,
|
conversationDB: c.conversationDB,
|
||||||
expireTime: c.expireTime,
|
expireTime: c.expireTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string {
|
func (c *ConversationRedisCache) getConversationKey(ownerUserID, conversationID string) string {
|
||||||
return conversationKey + ownerUserID + ":" + conversationID
|
return cachekey.GetConversationKey(ownerUserID, conversationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string {
|
func (c *ConversationRedisCache) getConversationIDsKey(ownerUserID string) string {
|
||||||
return conversationIDsKey + ownerUserID
|
return cachekey.GetConversationIDsKey(ownerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
|
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsKey(groupID string) string {
|
||||||
return superGroupRecvMsgNotNotifyUserIDsKey + groupID
|
return cachekey.GetSuperGroupRecvNotNotifyUserIDsKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string {
|
func (c *ConversationRedisCache) getRecvMsgOptKey(ownerUserID, conversationID string) string {
|
||||||
return recvMsgOptKey + ownerUserID + ":" + conversationID
|
return cachekey.GetRecvMsgOptKey(ownerUserID, conversationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
|
func (c *ConversationRedisCache) getSuperGroupRecvNotNotifyUserIDsHashKey(groupID string) string {
|
||||||
return superGroupRecvMsgNotNotifyUserIDsHashKey + groupID
|
return cachekey.GetSuperGroupRecvNotNotifyUserIDsHashKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string {
|
func (c *ConversationRedisCache) getConversationHasReadSeqKey(ownerUserID, conversationID string) string {
|
||||||
return conversationHasReadSeqKey + ownerUserID + ":" + conversationID
|
return cachekey.GetConversationHasReadSeqKey(ownerUserID, conversationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string {
|
func (c *ConversationRedisCache) getConversationNotReceiveMessageUserIDsKey(conversationID string) string {
|
||||||
return conversationNotReceiveMessageUserIDsKey + conversationID
|
return cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string {
|
||||||
|
return cachekey.GetUserConversationIDsHashKey(ownerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
|
func (c *ConversationRedisCache) GetUserConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
|
||||||
@@ -166,10 +177,6 @@ func (c *ConversationRedisCache) DelConversationIDs(userIDs ...string) Conversat
|
|||||||
return cache
|
return cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationRedisCache) getUserConversationIDsHashKey(ownerUserID string) string {
|
|
||||||
return conversationIDsHashKey + ownerUserID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) {
|
func (c *ConversationRedisCache) GetUserConversationIDsHash(ctx context.Context, ownerUserID string) (hash uint64, err error) {
|
||||||
return getCache(
|
return getCache(
|
||||||
ctx,
|
ctx,
|
||||||
|
|||||||
Vendored
+17
-9
@@ -16,6 +16,9 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/tools/utils"
|
"github.com/OpenIMSDK/tools/utils"
|
||||||
@@ -25,10 +28,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
friendExpireTime = time.Second * 60 * 60 * 12
|
friendExpireTime = time.Second * 60 * 60 * 12
|
||||||
friendIDsKey = "FRIEND_IDS:"
|
//friendIDsKey = "FRIEND_IDS:"
|
||||||
TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
|
//TwoWayFriendsIDsKey = "COMMON_FRIENDS_IDS:"
|
||||||
friendKey = "FRIEND_INFO:"
|
//friendKey = "FRIEND_INFO:"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FriendCache is an interface for caching friend-related data.
|
// FriendCache is an interface for caching friend-related data.
|
||||||
@@ -58,8 +61,13 @@ type FriendCacheRedis struct {
|
|||||||
func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface,
|
func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendModelInterface,
|
||||||
options rockscache.Options) FriendCache {
|
options rockscache.Options) FriendCache {
|
||||||
rcClient := rockscache.NewClient(rdb, options)
|
rcClient := rockscache.NewClient(rdb, options)
|
||||||
|
mc := NewMetaCacheRedis(rcClient)
|
||||||
|
f := config.Config.LocalCache.Friend
|
||||||
|
log.ZDebug(context.Background(), "friend local cache init", "Topic", f.Topic, "SlotNum", f.SlotNum, "SlotSize", f.SlotSize, "enable", f.Enable())
|
||||||
|
mc.SetTopic(f.Topic)
|
||||||
|
mc.SetRawRedisClient(rdb)
|
||||||
return &FriendCacheRedis{
|
return &FriendCacheRedis{
|
||||||
metaCache: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
friendDB: friendDB,
|
friendDB: friendDB,
|
||||||
expireTime: friendExpireTime,
|
expireTime: friendExpireTime,
|
||||||
rcClient: rcClient,
|
rcClient: rcClient,
|
||||||
@@ -70,7 +78,7 @@ func NewFriendCacheRedis(rdb redis.UniversalClient, friendDB relationtb.FriendMo
|
|||||||
func (f *FriendCacheRedis) NewCache() FriendCache {
|
func (f *FriendCacheRedis) NewCache() FriendCache {
|
||||||
return &FriendCacheRedis{
|
return &FriendCacheRedis{
|
||||||
rcClient: f.rcClient,
|
rcClient: f.rcClient,
|
||||||
metaCache: NewMetaCacheRedis(f.rcClient, f.metaCache.GetPreDelKeys()...),
|
metaCache: f.Copy(),
|
||||||
friendDB: f.friendDB,
|
friendDB: f.friendDB,
|
||||||
expireTime: f.expireTime,
|
expireTime: f.expireTime,
|
||||||
}
|
}
|
||||||
@@ -78,17 +86,17 @@ func (f *FriendCacheRedis) NewCache() FriendCache {
|
|||||||
|
|
||||||
// getFriendIDsKey returns the key for storing friend IDs in the cache.
|
// getFriendIDsKey returns the key for storing friend IDs in the cache.
|
||||||
func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string {
|
func (f *FriendCacheRedis) getFriendIDsKey(ownerUserID string) string {
|
||||||
return friendIDsKey + ownerUserID
|
return cachekey.GetFriendIDsKey(ownerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache.
|
// getTwoWayFriendsIDsKey returns the key for storing two-way friend IDs in the cache.
|
||||||
func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string {
|
func (f *FriendCacheRedis) getTwoWayFriendsIDsKey(ownerUserID string) string {
|
||||||
return TwoWayFriendsIDsKey + ownerUserID
|
return cachekey.GetTwoWayFriendsIDsKey(ownerUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFriendKey returns the key for storing friend info in the cache.
|
// getFriendKey returns the key for storing friend info in the cache.
|
||||||
func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string {
|
func (f *FriendCacheRedis) getFriendKey(ownerUserID, friendUserID string) string {
|
||||||
return friendKey + ownerUserID + "-" + friendUserID
|
return cachekey.GetFriendKey(ownerUserID, friendUserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFriendIDs retrieves friend IDs from the cache or the database if not found.
|
// GetFriendIDs retrieves friend IDs from the cache or the database if not found.
|
||||||
|
|||||||
Vendored
+24
-20
@@ -17,7 +17,8 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/constant"
|
"github.com/OpenIMSDK/protocol/constant"
|
||||||
@@ -30,15 +31,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
groupExpireTime = time.Second * 60 * 60 * 12
|
groupExpireTime = time.Second * 60 * 60 * 12
|
||||||
groupInfoKey = "GROUP_INFO:"
|
//groupInfoKey = "GROUP_INFO:"
|
||||||
groupMemberIDsKey = "GROUP_MEMBER_IDS:"
|
//groupMemberIDsKey = "GROUP_MEMBER_IDS:"
|
||||||
groupMembersHashKey = "GROUP_MEMBERS_HASH2:"
|
//groupMembersHashKey = "GROUP_MEMBERS_HASH2:"
|
||||||
groupMemberInfoKey = "GROUP_MEMBER_INFO:"
|
//groupMemberInfoKey = "GROUP_MEMBER_INFO:"
|
||||||
//groupOwnerInfoKey = "GROUP_OWNER_INFO:".
|
//joinedGroupsKey = "JOIN_GROUPS_KEY:"
|
||||||
joinedGroupsKey = "JOIN_GROUPS_KEY:"
|
//groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
|
||||||
groupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:"
|
//groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
|
||||||
groupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupHash interface {
|
type GroupHash interface {
|
||||||
@@ -101,12 +101,16 @@ func NewGroupCacheRedis(
|
|||||||
opts rockscache.Options,
|
opts rockscache.Options,
|
||||||
) GroupCache {
|
) GroupCache {
|
||||||
rcClient := rockscache.NewClient(rdb, opts)
|
rcClient := rockscache.NewClient(rdb, opts)
|
||||||
|
mc := NewMetaCacheRedis(rcClient)
|
||||||
|
g := config.Config.LocalCache.Group
|
||||||
|
mc.SetTopic(g.Topic)
|
||||||
|
log.ZDebug(context.Background(), "group local cache init", "Topic", g.Topic, "SlotNum", g.SlotNum, "SlotSize", g.SlotSize, "enable", g.Enable())
|
||||||
|
mc.SetRawRedisClient(rdb)
|
||||||
return &GroupCacheRedis{
|
return &GroupCacheRedis{
|
||||||
rcClient: rcClient, expireTime: groupExpireTime,
|
rcClient: rcClient, expireTime: groupExpireTime,
|
||||||
groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB,
|
groupDB: groupDB, groupMemberDB: groupMemberDB, groupRequestDB: groupRequestDB,
|
||||||
groupHash: hashCode,
|
groupHash: hashCode,
|
||||||
metaCache: NewMetaCacheRedis(rcClient),
|
metaCache: mc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,36 +121,36 @@ func (g *GroupCacheRedis) NewCache() GroupCache {
|
|||||||
groupDB: g.groupDB,
|
groupDB: g.groupDB,
|
||||||
groupMemberDB: g.groupMemberDB,
|
groupMemberDB: g.groupMemberDB,
|
||||||
groupRequestDB: g.groupRequestDB,
|
groupRequestDB: g.groupRequestDB,
|
||||||
metaCache: NewMetaCacheRedis(g.rcClient, g.metaCache.GetPreDelKeys()...),
|
metaCache: g.Copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupInfoKey(groupID string) string {
|
||||||
return groupInfoKey + groupID
|
return cachekey.GetGroupInfoKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
|
func (g *GroupCacheRedis) getJoinedGroupsKey(userID string) string {
|
||||||
return joinedGroupsKey + userID
|
return cachekey.GetJoinedGroupsKey(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupMembersHashKey(groupID string) string {
|
||||||
return groupMembersHashKey + groupID
|
return cachekey.GetGroupMembersHashKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupMemberIDsKey(groupID string) string {
|
||||||
return groupMemberIDsKey + groupID
|
return cachekey.GetGroupMemberIDsKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string {
|
func (g *GroupCacheRedis) getGroupMemberInfoKey(groupID, userID string) string {
|
||||||
return groupMemberInfoKey + groupID + "-" + userID
|
return cachekey.GetGroupMemberInfoKey(groupID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
|
func (g *GroupCacheRedis) getGroupMemberNumKey(groupID string) string {
|
||||||
return groupMemberNumKey + groupID
|
return cachekey.GetGroupMemberNumKey(groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
|
func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string {
|
||||||
return groupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel))
|
return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) {
|
func (g *GroupCacheRedis) GetGroupIndex(group *relationtb.GroupModel, keys []string) (int, error) {
|
||||||
|
|||||||
Vendored
+41
-24
@@ -18,6 +18,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -43,6 +44,9 @@ type metaCache interface {
|
|||||||
AddKeys(keys ...string)
|
AddKeys(keys ...string)
|
||||||
ClearKeys()
|
ClearKeys()
|
||||||
GetPreDelKeys() []string
|
GetPreDelKeys() []string
|
||||||
|
SetTopic(topic string)
|
||||||
|
SetRawRedisClient(cli redis.UniversalClient)
|
||||||
|
Copy() metaCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache {
|
func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache {
|
||||||
@@ -50,10 +54,36 @@ func NewMetaCacheRedis(rcClient *rockscache.Client, keys ...string) metaCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type metaCacheRedis struct {
|
type metaCacheRedis struct {
|
||||||
|
topic string
|
||||||
rcClient *rockscache.Client
|
rcClient *rockscache.Client
|
||||||
keys []string
|
keys []string
|
||||||
maxRetryTimes int
|
maxRetryTimes int
|
||||||
retryInterval time.Duration
|
retryInterval time.Duration
|
||||||
|
redisClient redis.UniversalClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metaCacheRedis) Copy() metaCache {
|
||||||
|
var keys []string
|
||||||
|
if len(m.keys) > 0 {
|
||||||
|
keys = make([]string, 0, len(m.keys)*2)
|
||||||
|
keys = append(keys, m.keys...)
|
||||||
|
}
|
||||||
|
return &metaCacheRedis{
|
||||||
|
topic: m.topic,
|
||||||
|
rcClient: m.rcClient,
|
||||||
|
keys: keys,
|
||||||
|
maxRetryTimes: m.maxRetryTimes,
|
||||||
|
retryInterval: m.retryInterval,
|
||||||
|
redisClient: redisClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metaCacheRedis) SetTopic(topic string) {
|
||||||
|
m.topic = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metaCacheRedis) SetRawRedisClient(cli redis.UniversalClient) {
|
||||||
|
m.redisClient = cli
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
|
func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
|
||||||
@@ -61,7 +91,7 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
|
|||||||
m.keys = utils.Distinct(m.keys)
|
m.keys = utils.Distinct(m.keys)
|
||||||
}
|
}
|
||||||
if len(m.keys) > 0 {
|
if len(m.keys) > 0 {
|
||||||
log.ZDebug(ctx, "delete cache", "keys", m.keys)
|
log.ZDebug(ctx, "delete cache", "topic", m.topic, "keys", m.keys)
|
||||||
for _, key := range m.keys {
|
for _, key := range m.keys {
|
||||||
for i := 0; i < m.maxRetryTimes; i++ {
|
for i := 0; i < m.maxRetryTimes; i++ {
|
||||||
if err := m.rcClient.TagAsDeleted(key); err != nil {
|
if err := m.rcClient.TagAsDeleted(key); err != nil {
|
||||||
@@ -71,31 +101,18 @@ func (m *metaCacheRedis) ExecDel(ctx context.Context, distinct ...bool) error {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//retryTimes := 0
|
if pk := getPublishKey(m.topic, m.keys); len(pk) > 0 {
|
||||||
//for {
|
data, err := json.Marshal(pk)
|
||||||
// m.rcClient.TagAsDeleted()
|
if err != nil {
|
||||||
// if err := m.rcClient.TagAsDeletedBatch2(ctx, []string{key}); err != nil {
|
log.ZError(ctx, "keys json marshal failed", err, "topic", m.topic, "keys", pk)
|
||||||
// if retryTimes >= m.maxRetryTimes {
|
} else {
|
||||||
// err = errs.ErrInternalServer.Wrap(
|
if err := m.redisClient.Publish(ctx, m.topic, string(data)).Err(); err != nil {
|
||||||
// fmt.Sprintf(
|
log.ZError(ctx, "redis publish cache delete error", err, "topic", m.topic, "keys", pk)
|
||||||
// "delete cache error: %v, keys: %v, retry times %d, please check redis server",
|
}
|
||||||
// err,
|
}
|
||||||
// key,
|
|
||||||
// retryTimes,
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
// log.ZWarn(ctx, "delete cache failed, please handle keys", err, "keys", key)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// retryTimes++
|
|
||||||
// } else {
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+10
-10
@@ -38,12 +38,12 @@ const (
|
|||||||
conversationUserMinSeq = "CON_USER_MIN_SEQ:"
|
conversationUserMinSeq = "CON_USER_MIN_SEQ:"
|
||||||
hasReadSeq = "HAS_READ_SEQ:"
|
hasReadSeq = "HAS_READ_SEQ:"
|
||||||
|
|
||||||
appleDeviceToken = "DEVICE_TOKEN"
|
//appleDeviceToken = "DEVICE_TOKEN"
|
||||||
getuiToken = "GETUI_TOKEN"
|
getuiToken = "GETUI_TOKEN"
|
||||||
getuiTaskID = "GETUI_TASK_ID"
|
getuiTaskID = "GETUI_TASK_ID"
|
||||||
signalCache = "SIGNAL_CACHE:"
|
//signalCache = "SIGNAL_CACHE:"
|
||||||
signalListCache = "SIGNAL_LIST_CACHE:"
|
//signalListCache = "SIGNAL_LIST_CACHE:"
|
||||||
FCM_TOKEN = "FCM_TOKEN:"
|
FCM_TOKEN = "FCM_TOKEN:"
|
||||||
|
|
||||||
messageCache = "MESSAGE_CACHE:"
|
messageCache = "MESSAGE_CACHE:"
|
||||||
messageDelUserList = "MESSAGE_DEL_USER_LIST:"
|
messageDelUserList = "MESSAGE_DEL_USER_LIST:"
|
||||||
@@ -143,6 +143,10 @@ func (c *msgCache) getHasReadSeqKey(conversationID string, userID string) string
|
|||||||
return hasReadSeq + userID + ":" + conversationID
|
return hasReadSeq + userID + ":" + conversationID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string {
|
||||||
|
return conversationUserMinSeq + conversationID + "u:" + userID
|
||||||
|
}
|
||||||
|
|
||||||
func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error {
|
func (c *msgCache) setSeq(ctx context.Context, conversationID string, seq int64, getkey func(conversationID string) string) error {
|
||||||
return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err())
|
return errs.Wrap(c.rdb.Set(ctx, getkey(conversationID), seq, 0).Err())
|
||||||
}
|
}
|
||||||
@@ -208,10 +212,6 @@ func (c *msgCache) GetMinSeq(ctx context.Context, conversationID string) (int64,
|
|||||||
return c.getSeq(ctx, conversationID, c.getMinSeqKey)
|
return c.getSeq(ctx, conversationID, c.getMinSeqKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *msgCache) getConversationUserMinSeqKey(conversationID, userID string) string {
|
|
||||||
return conversationUserMinSeq + conversationID + "u:" + userID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
|
func (c *msgCache) GetConversationUserMinSeq(ctx context.Context, conversationID string, userID string) (int64, error) {
|
||||||
val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64()
|
val, err := c.rdb.Get(ctx, c.getConversationUserMinSeqKey(conversationID, userID)).Int64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Vendored
+13
-8
@@ -18,6 +18,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -32,8 +34,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
userExpireTime = time.Second * 60 * 60 * 12
|
userExpireTime = time.Second * 60 * 60 * 12
|
||||||
userInfoKey = "USER_INFO:"
|
//userInfoKey = "USER_INFO:"
|
||||||
userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
|
userGlobalRecvMsgOptKey = "USER_GLOBAL_RECV_MSG_OPT_KEY:"
|
||||||
olineStatusKey = "ONLINE_STATUS:"
|
olineStatusKey = "ONLINE_STATUS:"
|
||||||
userOlineStatusExpireTime = time.Second * 60 * 60 * 24
|
userOlineStatusExpireTime = time.Second * 60 * 60 * 24
|
||||||
@@ -68,7 +70,11 @@ func NewUserCacheRedis(
|
|||||||
options rockscache.Options,
|
options rockscache.Options,
|
||||||
) UserCache {
|
) UserCache {
|
||||||
rcClient := rockscache.NewClient(rdb, options)
|
rcClient := rockscache.NewClient(rdb, options)
|
||||||
|
mc := NewMetaCacheRedis(rcClient)
|
||||||
|
u := config.Config.LocalCache.User
|
||||||
|
log.ZDebug(context.Background(), "user local cache init", "Topic", u.Topic, "SlotNum", u.SlotNum, "SlotSize", u.SlotSize, "enable", u.Enable())
|
||||||
|
mc.SetTopic(u.Topic)
|
||||||
|
mc.SetRawRedisClient(rdb)
|
||||||
return &UserCacheRedis{
|
return &UserCacheRedis{
|
||||||
rdb: rdb,
|
rdb: rdb,
|
||||||
metaCache: NewMetaCacheRedis(rcClient),
|
metaCache: NewMetaCacheRedis(rcClient),
|
||||||
@@ -81,7 +87,7 @@ func NewUserCacheRedis(
|
|||||||
func (u *UserCacheRedis) NewCache() UserCache {
|
func (u *UserCacheRedis) NewCache() UserCache {
|
||||||
return &UserCacheRedis{
|
return &UserCacheRedis{
|
||||||
rdb: u.rdb,
|
rdb: u.rdb,
|
||||||
metaCache: NewMetaCacheRedis(u.rcClient, u.metaCache.GetPreDelKeys()...),
|
metaCache: u.Copy(),
|
||||||
userDB: u.userDB,
|
userDB: u.userDB,
|
||||||
expireTime: u.expireTime,
|
expireTime: u.expireTime,
|
||||||
rcClient: u.rcClient,
|
rcClient: u.rcClient,
|
||||||
@@ -89,18 +95,17 @@ func (u *UserCacheRedis) NewCache() UserCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserCacheRedis) getUserInfoKey(userID string) string {
|
func (u *UserCacheRedis) getUserInfoKey(userID string) string {
|
||||||
return userInfoKey + userID
|
return cachekey.GetUserInfoKey(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string {
|
func (u *UserCacheRedis) getUserGlobalRecvMsgOptKey(userID string) string {
|
||||||
return userGlobalRecvMsgOptKey + userID
|
return cachekey.GetUserGlobalRecvMsgOptKey(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) {
|
func (u *UserCacheRedis) GetUserInfo(ctx context.Context, userID string) (userInfo *relationtb.UserModel, err error) {
|
||||||
return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) {
|
return getCache(ctx, u.rcClient, u.getUserInfoKey(userID), u.expireTime, func(ctx context.Context) (*relationtb.UserModel, error) {
|
||||||
return u.userDB.Take(ctx, userID)
|
return u.userDB.Take(ctx, userID)
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) {
|
func (u *UserCacheRedis) GetUsersInfo(ctx context.Context, userIDs []string) ([]*relationtb.UserModel, error) {
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
// 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 localcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/conversation"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ConversationLocalCache struct {
|
|
||||||
lock sync.Mutex
|
|
||||||
superGroupRecvMsgNotNotifyUserIDs map[string]Hash
|
|
||||||
conversationIDs map[string]Hash
|
|
||||||
client *rpcclient.ConversationRpcClient
|
|
||||||
}
|
|
||||||
|
|
||||||
type Hash struct {
|
|
||||||
hash uint64
|
|
||||||
ids []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConversationLocalCache(client *rpcclient.ConversationRpcClient) *ConversationLocalCache {
|
|
||||||
return &ConversationLocalCache{
|
|
||||||
superGroupRecvMsgNotNotifyUserIDs: make(map[string]Hash),
|
|
||||||
conversationIDs: make(map[string]Hash),
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *ConversationLocalCache) GetRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
|
|
||||||
resp, err := g.client.Client.GetRecvMsgNotNotifyUserIDs(ctx, &conversation.GetRecvMsgNotNotifyUserIDsReq{
|
|
||||||
GroupID: groupID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.UserIDs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *ConversationLocalCache) GetConversationIDs(ctx context.Context, userID string) ([]string, error) {
|
|
||||||
resp, err := g.client.Client.GetUserConversationIDsHash(ctx, &conversation.GetUserConversationIDsHashReq{
|
|
||||||
OwnerUserID: userID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
g.lock.Lock()
|
|
||||||
hash, ok := g.conversationIDs[userID]
|
|
||||||
g.lock.Unlock()
|
|
||||||
|
|
||||||
if !ok || hash.hash != resp.Hash {
|
|
||||||
conversationIDsResp, err := g.client.Client.GetConversationIDs(ctx, &conversation.GetConversationIDsReq{
|
|
||||||
UserID: userID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
g.lock.Lock()
|
|
||||||
defer g.lock.Unlock()
|
|
||||||
g.conversationIDs[userID] = Hash{
|
|
||||||
hash: resp.Hash,
|
|
||||||
ids: conversationIDsResp.ConversationIDs,
|
|
||||||
}
|
|
||||||
|
|
||||||
return conversationIDsResp.ConversationIDs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash.ids, nil
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// 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 localcache // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// 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 localcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/OpenIMSDK/protocol/group"
|
|
||||||
"github.com/OpenIMSDK/tools/errs"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GroupLocalCache struct {
|
|
||||||
lock sync.Mutex
|
|
||||||
cache map[string]GroupMemberIDsHash
|
|
||||||
client *rpcclient.GroupRpcClient
|
|
||||||
}
|
|
||||||
|
|
||||||
type GroupMemberIDsHash struct {
|
|
||||||
memberListHash uint64
|
|
||||||
userIDs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGroupLocalCache(client *rpcclient.GroupRpcClient) *GroupLocalCache {
|
|
||||||
return &GroupLocalCache{
|
|
||||||
cache: make(map[string]GroupMemberIDsHash, 0),
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GroupLocalCache) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) {
|
|
||||||
resp, err := g.client.Client.GetGroupAbstractInfo(ctx, &group.GetGroupAbstractInfoReq{
|
|
||||||
GroupIDs: []string{groupID},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(resp.GroupAbstractInfos) < 1 {
|
|
||||||
return nil, errs.ErrGroupIDNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
g.lock.Lock()
|
|
||||||
localHashInfo, ok := g.cache[groupID]
|
|
||||||
if ok && localHashInfo.memberListHash == resp.GroupAbstractInfos[0].GroupMemberListHash {
|
|
||||||
g.lock.Unlock()
|
|
||||||
return localHashInfo.userIDs, nil
|
|
||||||
}
|
|
||||||
g.lock.Unlock()
|
|
||||||
|
|
||||||
groupMembersResp, err := g.client.Client.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{
|
|
||||||
GroupID: groupID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
g.lock.Lock()
|
|
||||||
defer g.lock.Unlock()
|
|
||||||
g.cache[groupID] = GroupMemberIDsHash{
|
|
||||||
memberListHash: resp.GroupAbstractInfos[0].GroupMemberListHash,
|
|
||||||
userIDs: groupMembersResp.UserIDs,
|
|
||||||
}
|
|
||||||
return g.cache[groupID].userIDs, nil
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// 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 localcache
|
|
||||||
@@ -96,8 +96,14 @@ func (c *ConversationMgo) FindUserIDAllConversations(ctx context.Context, userID
|
|||||||
return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID})
|
return mgoutil.Find[*relation.ConversationModel](ctx, c.coll, bson.M{"owner_user_id": userID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationMgo) FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error) {
|
func (c *ConversationMgo) FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error) {
|
||||||
return mgoutil.Find[string](ctx, c.coll, bson.M{"group_id": groupID, "recv_msg_opt": constant.ReceiveNotNotifyMessage}, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}))
|
var filter any
|
||||||
|
if len(recvOpts) == 0 {
|
||||||
|
filter = bson.M{"conversation_id": conversationID}
|
||||||
|
} else {
|
||||||
|
filter = bson.M{"conversation_id": conversationID, "recv_msg_opt": bson.M{"$in": recvOpts}}
|
||||||
|
}
|
||||||
|
return mgoutil.Find[string](ctx, c.coll, filter, options.Find().SetProjection(bson.M{"_id": 0, "owner_user_id": 1}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConversationMgo) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) {
|
func (c *ConversationMgo) GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ type ConversationModelInterface interface {
|
|||||||
Take(ctx context.Context, userID, conversationID string) (conversation *ConversationModel, err error)
|
Take(ctx context.Context, userID, conversationID string) (conversation *ConversationModel, err error)
|
||||||
FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error)
|
FindConversationID(ctx context.Context, userID string, conversationIDs []string) (existConversationID []string, err error)
|
||||||
FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error)
|
FindUserIDAllConversations(ctx context.Context, userID string) (conversations []*ConversationModel, err error)
|
||||||
FindRecvMsgNotNotifyUserIDs(ctx context.Context, groupID string) ([]string, error)
|
FindRecvMsgUserIDs(ctx context.Context, conversationID string, recvOpts []int) ([]string, error)
|
||||||
GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error)
|
GetUserRecvMsgOpt(ctx context.Context, ownerUserID, conversationID string) (opt int, err error)
|
||||||
GetAllConversationIDs(ctx context.Context) ([]string, error)
|
GetAllConversationIDs(ctx context.Context) ([]string, error)
|
||||||
GetAllConversationIDsNumber(ctx context.Context) (int64, error)
|
GetAllConversationIDsNumber(ctx context.Context) (int64, error)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package redispubsub
|
||||||
|
|
||||||
|
import "github.com/redis/go-redis/v9"
|
||||||
|
|
||||||
|
type Publisher struct {
|
||||||
|
client redis.UniversalClient
|
||||||
|
channel string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPublisher(client redis.UniversalClient, channel string) *Publisher {
|
||||||
|
return &Publisher{client: client, channel: channel}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Publisher) Publish(message string) error {
|
||||||
|
return p.client.Publish(ctx, p.channel, message).Err()
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package redispubsub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ctx = context.Background()
|
||||||
|
|
||||||
|
type Subscriber struct {
|
||||||
|
client redis.UniversalClient
|
||||||
|
channel string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubscriber(client redis.UniversalClient, channel string) *Subscriber {
|
||||||
|
return &Subscriber{client: client, channel: channel}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subscriber) OnMessage(ctx context.Context, callback func(string)) error {
|
||||||
|
messageChannel := s.client.Subscribe(ctx, s.channel).Channel()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case msg := <-messageChannel:
|
||||||
|
callback(msg.Payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package localcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/localcache/link"
|
||||||
|
"github.com/openimsdk/localcache/lru"
|
||||||
|
"hash/fnv"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cache[V any] interface {
|
||||||
|
Get(ctx context.Context, key string, fetch func(ctx context.Context) (V, error)) (V, error)
|
||||||
|
GetLink(ctx context.Context, key string, fetch func(ctx context.Context) (V, error), link ...string) (V, error)
|
||||||
|
Del(ctx context.Context, key ...string)
|
||||||
|
DelLocal(ctx context.Context, key ...string)
|
||||||
|
Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func New[V any](opts ...Option) Cache[V] {
|
||||||
|
opt := defaultOption()
|
||||||
|
for _, o := range opts {
|
||||||
|
o(opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := cache[V]{opt: opt}
|
||||||
|
if opt.localSlotNum > 0 && opt.localSlotSize > 0 {
|
||||||
|
createSimpleLRU := func() lru.LRU[string, V] {
|
||||||
|
if opt.expirationEvict {
|
||||||
|
return lru.NewExpirationLRU[string, V](opt.localSlotSize, opt.localSuccessTTL, opt.localFailedTTL, opt.target, c.onEvict)
|
||||||
|
} else {
|
||||||
|
return lru.NewLayLRU[string, V](opt.localSlotSize, opt.localSuccessTTL, opt.localFailedTTL, opt.target, c.onEvict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if opt.localSlotNum == 1 {
|
||||||
|
c.local = createSimpleLRU()
|
||||||
|
} else {
|
||||||
|
c.local = lru.NewSlotLRU[string, V](opt.localSlotNum, func(key string) uint64 {
|
||||||
|
h := fnv.New64a()
|
||||||
|
h.Write(*(*[]byte)(unsafe.Pointer(&key)))
|
||||||
|
return h.Sum64()
|
||||||
|
}, createSimpleLRU)
|
||||||
|
}
|
||||||
|
if opt.linkSlotNum > 0 {
|
||||||
|
c.link = link.New(opt.linkSlotNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
type cache[V any] struct {
|
||||||
|
opt *option
|
||||||
|
link link.Link
|
||||||
|
local lru.LRU[string, V]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) onEvict(key string, value V) {
|
||||||
|
if c.link != nil {
|
||||||
|
lks := c.link.Del(key)
|
||||||
|
for k := range lks {
|
||||||
|
if key != k { // prevent deadlock
|
||||||
|
c.local.Del(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) del(key ...string) {
|
||||||
|
if c.local == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, k := range key {
|
||||||
|
c.local.Del(k)
|
||||||
|
if c.link != nil {
|
||||||
|
lks := c.link.Del(k)
|
||||||
|
for k := range lks {
|
||||||
|
c.local.Del(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) Get(ctx context.Context, key string, fetch func(ctx context.Context) (V, error)) (V, error) {
|
||||||
|
return c.GetLink(ctx, key, fetch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) GetLink(ctx context.Context, key string, fetch func(ctx context.Context) (V, error), link ...string) (V, error) {
|
||||||
|
if c.local != nil {
|
||||||
|
return c.local.Get(key, func() (V, error) {
|
||||||
|
if len(link) > 0 {
|
||||||
|
c.link.Link(key, link...)
|
||||||
|
}
|
||||||
|
return fetch(ctx)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return fetch(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) Del(ctx context.Context, key ...string) {
|
||||||
|
for _, fn := range c.opt.delFn {
|
||||||
|
fn(ctx, key...)
|
||||||
|
}
|
||||||
|
c.del(key...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) DelLocal(ctx context.Context, key ...string) {
|
||||||
|
c.del(key...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[V]) Stop() {
|
||||||
|
c.local.Stop()
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package localcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestName(t *testing.T) {
|
||||||
|
c := New[string](WithExpirationEvict())
|
||||||
|
//c := New[string]()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
const (
|
||||||
|
num = 10000
|
||||||
|
tNum = 10000
|
||||||
|
kNum = 100000
|
||||||
|
pNum = 100
|
||||||
|
)
|
||||||
|
|
||||||
|
getKey := func(v uint64) string {
|
||||||
|
return fmt.Sprintf("key_%d", v%kNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
t.Log("start", start)
|
||||||
|
|
||||||
|
var (
|
||||||
|
get atomic.Int64
|
||||||
|
del atomic.Int64
|
||||||
|
)
|
||||||
|
|
||||||
|
incrGet := func() {
|
||||||
|
if v := get.Add(1); v%pNum == 0 {
|
||||||
|
//t.Log("#get count", v/pNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incrDel := func() {
|
||||||
|
if v := del.Add(1); v%pNum == 0 {
|
||||||
|
//t.Log("@del count", v/pNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
for i := 0; i < tNum; i++ {
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
c.Get(ctx, getKey(rand.Uint64()), func(ctx context.Context) (string, error) {
|
||||||
|
return fmt.Sprintf("index_%d", i), nil
|
||||||
|
})
|
||||||
|
incrGet()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
time.Sleep(time.Second / 10)
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
c.Del(ctx, getKey(rand.Uint64()))
|
||||||
|
incrDel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
end := time.Now()
|
||||||
|
t.Log("end", end)
|
||||||
|
t.Log("time", end.Sub(start))
|
||||||
|
t.Log("get", get.Load())
|
||||||
|
t.Log("del", del.Load())
|
||||||
|
// 137.35s
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/openimsdk/localcache
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package link
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hash/fnv"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Link interface {
|
||||||
|
Link(key string, link ...string)
|
||||||
|
Del(key string) map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLinkKey() *linkKey {
|
||||||
|
return &linkKey{
|
||||||
|
data: make(map[string]map[string]struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type linkKey struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
data map[string]map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *linkKey) link(key string, link ...string) {
|
||||||
|
x.lock.Lock()
|
||||||
|
defer x.lock.Unlock()
|
||||||
|
v, ok := x.data[key]
|
||||||
|
if !ok {
|
||||||
|
v = make(map[string]struct{})
|
||||||
|
x.data[key] = v
|
||||||
|
}
|
||||||
|
for _, k := range link {
|
||||||
|
v[k] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *linkKey) del(key string) map[string]struct{} {
|
||||||
|
x.lock.Lock()
|
||||||
|
defer x.lock.Unlock()
|
||||||
|
ks, ok := x.data[key]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
delete(x.data, key)
|
||||||
|
return ks
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(n int) Link {
|
||||||
|
if n <= 0 {
|
||||||
|
panic("must be greater than 0")
|
||||||
|
}
|
||||||
|
slots := make([]*linkKey, n)
|
||||||
|
for i := 0; i < len(slots); i++ {
|
||||||
|
slots[i] = newLinkKey()
|
||||||
|
}
|
||||||
|
return &slot{
|
||||||
|
n: uint64(n),
|
||||||
|
slots: slots,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type slot struct {
|
||||||
|
n uint64
|
||||||
|
slots []*linkKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slot) index(s string) uint64 {
|
||||||
|
h := fnv.New64a()
|
||||||
|
_, _ = h.Write(*(*[]byte)(unsafe.Pointer(&s)))
|
||||||
|
return h.Sum64() % x.n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slot) Link(key string, link ...string) {
|
||||||
|
if len(link) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mk := key
|
||||||
|
lks := make([]string, len(link))
|
||||||
|
for i, k := range link {
|
||||||
|
lks[i] = k
|
||||||
|
}
|
||||||
|
x.slots[x.index(mk)].link(mk, lks...)
|
||||||
|
for _, lk := range lks {
|
||||||
|
x.slots[x.index(lk)].link(lk, mk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slot) Del(key string) map[string]struct{} {
|
||||||
|
return x.delKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slot) delKey(k string) map[string]struct{} {
|
||||||
|
del := make(map[string]struct{})
|
||||||
|
stack := []string{k}
|
||||||
|
for len(stack) > 0 {
|
||||||
|
curr := stack[len(stack)-1]
|
||||||
|
stack = stack[:len(stack)-1]
|
||||||
|
if _, ok := del[curr]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
del[curr] = struct{}{}
|
||||||
|
childKeys := x.slots[x.index(curr)].del(curr)
|
||||||
|
for ck := range childKeys {
|
||||||
|
stack = append(stack, ck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return del
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package link
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestName(t *testing.T) {
|
||||||
|
|
||||||
|
v := New(1)
|
||||||
|
|
||||||
|
//v.Link("a:1", "b:1", "c:1", "d:1")
|
||||||
|
v.Link("a:1", "b:1", "c:1")
|
||||||
|
v.Link("z:1", "b:1")
|
||||||
|
|
||||||
|
//v.DelKey("a:1")
|
||||||
|
v.Del("z:1")
|
||||||
|
|
||||||
|
t.Log(v)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import "github.com/hashicorp/golang-lru/v2/simplelru"
|
||||||
|
|
||||||
|
type EvictCallback[K comparable, V any] simplelru.EvictCallback[K, V]
|
||||||
|
|
||||||
|
type LRU[K comparable, V any] interface {
|
||||||
|
Get(key K, fetch func() (V, error)) (V, error)
|
||||||
|
Del(key K) bool
|
||||||
|
Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Target interface {
|
||||||
|
IncrGetHit()
|
||||||
|
IncrGetSuccess()
|
||||||
|
IncrGetFailed()
|
||||||
|
|
||||||
|
IncrDelHit()
|
||||||
|
IncrDelNotFound()
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewExpirationLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) LRU[K, V] {
|
||||||
|
var cb expirable.EvictCallback[K, *expirationLruItem[V]]
|
||||||
|
if onEvict != nil {
|
||||||
|
cb = func(key K, value *expirationLruItem[V]) {
|
||||||
|
onEvict(key, value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core := expirable.NewLRU[K, *expirationLruItem[V]](size, cb, successTTL)
|
||||||
|
return &ExpirationLRU[K, V]{
|
||||||
|
core: core,
|
||||||
|
successTTL: successTTL,
|
||||||
|
failedTTL: failedTTL,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type expirationLruItem[V any] struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
err error
|
||||||
|
value V
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExpirationLRU[K comparable, V any] struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
core *expirable.LRU[K, *expirationLruItem[V]]
|
||||||
|
successTTL time.Duration
|
||||||
|
failedTTL time.Duration
|
||||||
|
target Target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ExpirationLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
||||||
|
x.lock.Lock()
|
||||||
|
v, ok := x.core.Get(key)
|
||||||
|
if ok {
|
||||||
|
x.lock.Unlock()
|
||||||
|
x.target.IncrGetSuccess()
|
||||||
|
v.lock.RLock()
|
||||||
|
defer v.lock.RUnlock()
|
||||||
|
return v.value, v.err
|
||||||
|
} else {
|
||||||
|
v = &expirationLruItem[V]{}
|
||||||
|
x.core.Add(key, v)
|
||||||
|
v.lock.Lock()
|
||||||
|
x.lock.Unlock()
|
||||||
|
defer v.lock.Unlock()
|
||||||
|
v.value, v.err = fetch()
|
||||||
|
if v.err == nil {
|
||||||
|
x.target.IncrGetSuccess()
|
||||||
|
} else {
|
||||||
|
x.target.IncrGetFailed()
|
||||||
|
x.core.Remove(key)
|
||||||
|
}
|
||||||
|
return v.value, v.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ExpirationLRU[K, V]) Del(key K) bool {
|
||||||
|
x.lock.Lock()
|
||||||
|
ok := x.core.Remove(key)
|
||||||
|
x.lock.Unlock()
|
||||||
|
if ok {
|
||||||
|
x.target.IncrDelHit()
|
||||||
|
} else {
|
||||||
|
x.target.IncrDelNotFound()
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ExpirationLRU[K, V]) Stop() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type layLruItem[V any] struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
expires int64
|
||||||
|
err error
|
||||||
|
value V
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLayLRU[K comparable, V any](size int, successTTL, failedTTL time.Duration, target Target, onEvict EvictCallback[K, V]) *LayLRU[K, V] {
|
||||||
|
var cb simplelru.EvictCallback[K, *layLruItem[V]]
|
||||||
|
if onEvict != nil {
|
||||||
|
cb = func(key K, value *layLruItem[V]) {
|
||||||
|
onEvict(key, value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core, err := simplelru.NewLRU[K, *layLruItem[V]](size, cb)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return &LayLRU[K, V]{
|
||||||
|
core: core,
|
||||||
|
successTTL: successTTL,
|
||||||
|
failedTTL: failedTTL,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LayLRU[K comparable, V any] struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
core *simplelru.LRU[K, *layLruItem[V]]
|
||||||
|
successTTL time.Duration
|
||||||
|
failedTTL time.Duration
|
||||||
|
target Target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LayLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
||||||
|
x.lock.Lock()
|
||||||
|
v, ok := x.core.Get(key)
|
||||||
|
if ok {
|
||||||
|
x.lock.Unlock()
|
||||||
|
v.lock.Lock()
|
||||||
|
expires, value, err := v.expires, v.value, v.err
|
||||||
|
if expires != 0 && expires > time.Now().UnixMilli() {
|
||||||
|
v.lock.Unlock()
|
||||||
|
x.target.IncrGetHit()
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = &layLruItem[V]{}
|
||||||
|
x.core.Add(key, v)
|
||||||
|
v.lock.Lock()
|
||||||
|
x.lock.Unlock()
|
||||||
|
}
|
||||||
|
defer v.lock.Unlock()
|
||||||
|
if v.expires > time.Now().UnixMilli() {
|
||||||
|
return v.value, v.err
|
||||||
|
}
|
||||||
|
v.value, v.err = fetch()
|
||||||
|
if v.err == nil {
|
||||||
|
v.expires = time.Now().Add(x.successTTL).UnixMilli()
|
||||||
|
x.target.IncrGetSuccess()
|
||||||
|
} else {
|
||||||
|
v.expires = time.Now().Add(x.failedTTL).UnixMilli()
|
||||||
|
x.target.IncrGetFailed()
|
||||||
|
}
|
||||||
|
return v.value, v.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LayLRU[K, V]) Del(key K) bool {
|
||||||
|
x.lock.Lock()
|
||||||
|
ok := x.core.Remove(key)
|
||||||
|
x.lock.Unlock()
|
||||||
|
if ok {
|
||||||
|
x.target.IncrDelHit()
|
||||||
|
} else {
|
||||||
|
x.target.IncrDelNotFound()
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LayLRU[K, V]) Stop() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cacheTarget struct {
|
||||||
|
getHit int64
|
||||||
|
getSuccess int64
|
||||||
|
getFailed int64
|
||||||
|
delHit int64
|
||||||
|
delNotFound int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cacheTarget) IncrGetHit() {
|
||||||
|
atomic.AddInt64(&r.getHit, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cacheTarget) IncrGetSuccess() {
|
||||||
|
atomic.AddInt64(&r.getSuccess, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cacheTarget) IncrGetFailed() {
|
||||||
|
atomic.AddInt64(&r.getFailed, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cacheTarget) IncrDelHit() {
|
||||||
|
atomic.AddInt64(&r.delHit, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cacheTarget) IncrDelNotFound() {
|
||||||
|
atomic.AddInt64(&r.delNotFound, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *cacheTarget) String() string {
|
||||||
|
return fmt.Sprintf("getHit: %d, getSuccess: %d, getFailed: %d, delHit: %d, delNotFound: %d", r.getHit, r.getSuccess, r.getFailed, r.delHit, r.delNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestName(t *testing.T) {
|
||||||
|
target := &cacheTarget{}
|
||||||
|
l := NewSlotLRU[string, string](100, func(k string) uint64 {
|
||||||
|
h := fnv.New64a()
|
||||||
|
h.Write(*(*[]byte)(unsafe.Pointer(&k)))
|
||||||
|
return h.Sum64()
|
||||||
|
}, func() LRU[string, string] {
|
||||||
|
return NewExpirationLRU[string, string](100, time.Second*60, time.Second, target, nil)
|
||||||
|
})
|
||||||
|
//l := NewInertiaLRU[string, string](1000, time.Second*20, time.Second*5, target)
|
||||||
|
|
||||||
|
fn := func(key string, n int, fetch func() (string, error)) {
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
//v, err := l.Get(key, fetch)
|
||||||
|
//if err == nil {
|
||||||
|
// t.Log("key", key, "value", v)
|
||||||
|
//} else {
|
||||||
|
// t.Error("key", key, err)
|
||||||
|
//}
|
||||||
|
v, err := l.Get(key, fetch)
|
||||||
|
//time.Sleep(time.Second / 100)
|
||||||
|
func(v ...any) {}(v, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := make(map[string]struct{})
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < 10000; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
key := fmt.Sprintf("key_%d", i%200)
|
||||||
|
tmp[key] = struct{}{}
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
//t.Log(key)
|
||||||
|
fn(key, 10000, func() (string, error) {
|
||||||
|
//time.Sleep(time.Second * 3)
|
||||||
|
//t.Log(time.Now(), "key", key, "fetch")
|
||||||
|
//if rand.Uint32()%5 == 0 {
|
||||||
|
// return "value_" + key, nil
|
||||||
|
//}
|
||||||
|
//return "", errors.New("rand error")
|
||||||
|
return "value_" + key, nil
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
//wg.Add(1)
|
||||||
|
//go func() {
|
||||||
|
// defer wg.Done()
|
||||||
|
// for i := 0; i < 10; i++ {
|
||||||
|
// l.Del(key)
|
||||||
|
// time.Sleep(time.Second / 3)
|
||||||
|
// }
|
||||||
|
//}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
t.Log(len(tmp))
|
||||||
|
t.Log(target.String())
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
func NewSlotLRU[K comparable, V any](slotNum int, hash func(K) uint64, create func() LRU[K, V]) LRU[K, V] {
|
||||||
|
x := &slotLRU[K, V]{
|
||||||
|
n: uint64(slotNum),
|
||||||
|
slots: make([]LRU[K, V], slotNum),
|
||||||
|
hash: hash,
|
||||||
|
}
|
||||||
|
for i := 0; i < slotNum; i++ {
|
||||||
|
x.slots[i] = create()
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
type slotLRU[K comparable, V any] struct {
|
||||||
|
n uint64
|
||||||
|
slots []LRU[K, V]
|
||||||
|
hash func(k K) uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slotLRU[K, V]) getIndex(k K) uint64 {
|
||||||
|
return x.hash(k) % x.n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slotLRU[K, V]) Get(key K, fetch func() (V, error)) (V, error) {
|
||||||
|
return x.slots[x.getIndex(key)].Get(key, fetch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slotLRU[K, V]) Del(key K) bool {
|
||||||
|
return x.slots[x.getIndex(key)].Del(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *slotLRU[K, V]) Stop() {
|
||||||
|
for _, slot := range x.slots {
|
||||||
|
slot.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package localcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openimsdk/localcache/lru"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func defaultOption() *option {
|
||||||
|
return &option{
|
||||||
|
localSlotNum: 500,
|
||||||
|
localSlotSize: 20000,
|
||||||
|
linkSlotNum: 500,
|
||||||
|
expirationEvict: false,
|
||||||
|
localSuccessTTL: time.Minute,
|
||||||
|
localFailedTTL: time.Second * 5,
|
||||||
|
delFn: make([]func(ctx context.Context, key ...string), 0, 2),
|
||||||
|
target: emptyTarget{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type option struct {
|
||||||
|
localSlotNum int
|
||||||
|
localSlotSize int
|
||||||
|
linkSlotNum int
|
||||||
|
// expirationEvict: true means that the cache will be actively cleared when the timer expires,
|
||||||
|
// false means that the cache will be lazily deleted.
|
||||||
|
expirationEvict bool
|
||||||
|
localSuccessTTL time.Duration
|
||||||
|
localFailedTTL time.Duration
|
||||||
|
delFn []func(ctx context.Context, key ...string)
|
||||||
|
target lru.Target
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(o *option)
|
||||||
|
|
||||||
|
func WithExpirationEvict() Option {
|
||||||
|
return func(o *option) {
|
||||||
|
o.expirationEvict = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLazy() Option {
|
||||||
|
return func(o *option) {
|
||||||
|
o.expirationEvict = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLocalDisable() Option {
|
||||||
|
return WithLinkSlotNum(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLinkDisable() Option {
|
||||||
|
return WithLinkSlotNum(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLinkSlotNum(linkSlotNum int) Option {
|
||||||
|
return func(o *option) {
|
||||||
|
o.linkSlotNum = linkSlotNum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLocalSlotNum(localSlotNum int) Option {
|
||||||
|
return func(o *option) {
|
||||||
|
o.localSlotNum = localSlotNum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLocalSlotSize(localSlotSize int) Option {
|
||||||
|
return func(o *option) {
|
||||||
|
o.localSlotSize = localSlotSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLocalSuccessTTL(localSuccessTTL time.Duration) Option {
|
||||||
|
if localSuccessTTL < 0 {
|
||||||
|
panic("localSuccessTTL should be greater than 0")
|
||||||
|
}
|
||||||
|
return func(o *option) {
|
||||||
|
o.localSuccessTTL = localSuccessTTL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLocalFailedTTL(localFailedTTL time.Duration) Option {
|
||||||
|
if localFailedTTL < 0 {
|
||||||
|
panic("localFailedTTL should be greater than 0")
|
||||||
|
}
|
||||||
|
return func(o *option) {
|
||||||
|
o.localFailedTTL = localFailedTTL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithTarget(target lru.Target) Option {
|
||||||
|
if target == nil {
|
||||||
|
panic("target should not be nil")
|
||||||
|
}
|
||||||
|
return func(o *option) {
|
||||||
|
o.target = target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithDeleteKeyBefore(fn func(ctx context.Context, key ...string)) Option {
|
||||||
|
if fn == nil {
|
||||||
|
panic("fn should not be nil")
|
||||||
|
}
|
||||||
|
return func(o *option) {
|
||||||
|
o.delFn = append(o.delFn, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type emptyTarget struct{}
|
||||||
|
|
||||||
|
func (e emptyTarget) IncrGetHit() {}
|
||||||
|
|
||||||
|
func (e emptyTarget) IncrGetSuccess() {}
|
||||||
|
|
||||||
|
func (e emptyTarget) IncrGetFailed() {}
|
||||||
|
|
||||||
|
func (e emptyTarget) IncrDelHit() {}
|
||||||
|
|
||||||
|
func (e emptyTarget) IncrDelNotFound() {}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package localcache
|
||||||
|
|
||||||
|
func AnyValue[V any](v any, err error) (V, error) {
|
||||||
|
if err != nil {
|
||||||
|
var zero V
|
||||||
|
return zero, err
|
||||||
|
}
|
||||||
|
return v.(V), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package rpccache
|
||||||
|
|
||||||
|
func newListMap[V comparable](values []V, err error) (*listMap[V], error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lm := &listMap[V]{
|
||||||
|
List: values,
|
||||||
|
Map: make(map[V]struct{}, len(values)),
|
||||||
|
}
|
||||||
|
for _, value := range values {
|
||||||
|
lm.Map[value] = struct{}{}
|
||||||
|
}
|
||||||
|
return lm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type listMap[V comparable] struct {
|
||||||
|
List []V
|
||||||
|
Map map[V]struct{}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package rpccache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
pbconversation "github.com/OpenIMSDK/protocol/conversation"
|
||||||
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/localcache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewConversationLocalCache(client rpcclient.ConversationRpcClient, cli redis.UniversalClient) *ConversationLocalCache {
|
||||||
|
lc := config.Config.LocalCache.Conversation
|
||||||
|
log.ZDebug(context.Background(), "ConversationLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
|
||||||
|
x := &ConversationLocalCache{
|
||||||
|
client: client,
|
||||||
|
local: localcache.New[any](
|
||||||
|
localcache.WithLocalSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSlotSize(lc.SlotSize),
|
||||||
|
localcache.WithLinkSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSuccessTTL(lc.Success()),
|
||||||
|
localcache.WithLocalFailedTTL(lc.Failed()),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
if lc.Enable() {
|
||||||
|
go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConversationLocalCache struct {
|
||||||
|
client rpcclient.ConversationRpcClient
|
||||||
|
local localcache.Cache[any]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUserID string) (val []string, err error) {
|
||||||
|
log.ZDebug(ctx, "ConversationLocalCache GetConversationIDs req", "ownerUserID", ownerUserID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "ConversationLocalCache GetConversationIDs return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "ConversationLocalCache GetConversationIDs return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[[]string](c.local.Get(ctx, cachekey.GetConversationIDsKey(ownerUserID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "ConversationLocalCache GetConversationIDs rpc", "ownerUserID", ownerUserID)
|
||||||
|
return c.client.GetConversationIDs(ctx, ownerUserID)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, conversationID string) (val *pbconversation.Conversation, err error) {
|
||||||
|
log.ZDebug(ctx, "ConversationLocalCache GetConversation req", "userID", userID, "conversationID", conversationID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "ConversationLocalCache GetConversation return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "ConversationLocalCache GetConversation return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[*pbconversation.Conversation](c.local.Get(ctx, cachekey.GetConversationKey(userID, conversationID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "ConversationLocalCache GetConversation rpc", "userID", userID, "conversationID", conversationID)
|
||||||
|
return c.client.GetConversation(ctx, userID, conversationID)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) GetSingleConversationRecvMsgOpt(ctx context.Context, userID, conversationID string) (int32, error) {
|
||||||
|
conv, err := c.GetConversation(ctx, userID, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return conv.RecvMsgOpt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
|
||||||
|
conversations := make([]*pbconversation.Conversation, 0, len(conversationIDs))
|
||||||
|
for _, conversationID := range conversationIDs {
|
||||||
|
conversation, err := c.GetConversation(ctx, ownerUserID, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conversations = append(conversations, conversation)
|
||||||
|
}
|
||||||
|
return conversations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) (*listMap[string], error) {
|
||||||
|
return localcache.AnyValue[*listMap[string]](c.local.Get(ctx, cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID), func(ctx context.Context) (any, error) {
|
||||||
|
return newListMap(c.client.GetConversationNotReceiveMessageUserIDs(ctx, conversationID))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) {
|
||||||
|
res, err := c.getConversationNotReceiveMessageUserIDs(ctx, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.List, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConversationLocalCache) GetConversationNotReceiveMessageUserIDMap(ctx context.Context, conversationID string) (map[string]struct{}, error) {
|
||||||
|
res, err := c.getConversationNotReceiveMessageUserIDs(ctx, conversationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Map, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package rpccache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/localcache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewFriendLocalCache(client rpcclient.FriendRpcClient, cli redis.UniversalClient) *FriendLocalCache {
|
||||||
|
lc := config.Config.LocalCache.Friend
|
||||||
|
log.ZDebug(context.Background(), "FriendLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
|
||||||
|
x := &FriendLocalCache{
|
||||||
|
client: client,
|
||||||
|
local: localcache.New[any](
|
||||||
|
localcache.WithLocalSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSlotSize(lc.SlotSize),
|
||||||
|
localcache.WithLinkSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSuccessTTL(lc.Success()),
|
||||||
|
localcache.WithLocalFailedTTL(lc.Failed()),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
if lc.Enable() {
|
||||||
|
go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
type FriendLocalCache struct {
|
||||||
|
client rpcclient.FriendRpcClient
|
||||||
|
local localcache.Cache[any]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (val bool, err error) {
|
||||||
|
log.ZDebug(ctx, "FriendLocalCache IsFriend req", "possibleFriendUserID", possibleFriendUserID, "userID", userID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "FriendLocalCache IsFriend return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "FriendLocalCache IsFriend return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "FriendLocalCache IsFriend rpc", "possibleFriendUserID", possibleFriendUserID, "userID", userID)
|
||||||
|
return f.client.IsFriend(ctx, possibleFriendUserID, userID)
|
||||||
|
}, cachekey.GetFriendIDsKey(possibleFriendUserID)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlack possibleBlackUserID selfUserID
|
||||||
|
func (f *FriendLocalCache) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (val bool, err error) {
|
||||||
|
log.ZDebug(ctx, "FriendLocalCache IsBlack req", "possibleBlackUserID", possibleBlackUserID, "userID", userID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "FriendLocalCache IsBlack return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "FriendLocalCache IsBlack return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[bool](f.local.GetLink(ctx, cachekey.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "FriendLocalCache IsBlack rpc", "possibleBlackUserID", possibleBlackUserID, "userID", userID)
|
||||||
|
return f.client.IsBlack(ctx, possibleBlackUserID, userID)
|
||||||
|
}, cachekey.GetBlackIDsKey(userID)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package rpccache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/OpenIMSDK/protocol/sdkws"
|
||||||
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/localcache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewGroupLocalCache(client rpcclient.GroupRpcClient, cli redis.UniversalClient) *GroupLocalCache {
|
||||||
|
lc := config.Config.LocalCache.Group
|
||||||
|
log.ZDebug(context.Background(), "GroupLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
|
||||||
|
x := &GroupLocalCache{
|
||||||
|
client: client,
|
||||||
|
local: localcache.New[any](
|
||||||
|
localcache.WithLocalSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSlotSize(lc.SlotSize),
|
||||||
|
localcache.WithLinkSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSuccessTTL(lc.Success()),
|
||||||
|
localcache.WithLocalFailedTTL(lc.Failed()),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
if lc.Enable() {
|
||||||
|
go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupLocalCache struct {
|
||||||
|
client rpcclient.GroupRpcClient
|
||||||
|
local localcache.Cache[any]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string) (val *listMap[string], err error) {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs req", "groupID", groupID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "GroupLocalCache getGroupMemberIDs return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[*listMap[string]](g.local.Get(ctx, cachekey.GetGroupMemberIDsKey(groupID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs rpc", "groupID", groupID)
|
||||||
|
return newListMap(g.client.GetGroupMemberIDs(ctx, groupID))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupMember(ctx context.Context, groupID, userID string) (val *sdkws.GroupMemberFullInfo, err error) {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo req", "groupID", groupID, "userID", userID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "GroupLocalCache GetGroupInfo return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[*sdkws.GroupMemberFullInfo](g.local.Get(ctx, cachekey.GetGroupMemberInfoKey(groupID, userID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID, "userID", userID)
|
||||||
|
return g.client.GetGroupMemberCache(ctx, groupID, userID)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupInfo(ctx context.Context, groupID string) (val *sdkws.GroupInfo, err error) {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo req", "groupID", groupID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "GroupLocalCache GetGroupInfo return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[*sdkws.GroupInfo](g.local.Get(ctx, cachekey.GetGroupInfoKey(groupID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID)
|
||||||
|
return g.client.GetGroupInfoCache(ctx, groupID)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) {
|
||||||
|
res, err := g.getGroupMemberIDs(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.List, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupMemberIDMap(ctx context.Context, groupID string) (map[string]struct{}, error) {
|
||||||
|
res, err := g.getGroupMemberIDs(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Map, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupInfos(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) {
|
||||||
|
groupInfos := make([]*sdkws.GroupInfo, 0, len(groupIDs))
|
||||||
|
for _, groupID := range groupIDs {
|
||||||
|
groupInfo, err := g.GetGroupInfo(ctx, groupID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
groupInfos = append(groupInfos, groupInfo)
|
||||||
|
}
|
||||||
|
return groupInfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupMembers(ctx context.Context, groupID string, userIDs []string) ([]*sdkws.GroupMemberFullInfo, error) {
|
||||||
|
members := make([]*sdkws.GroupMemberFullInfo, 0, len(userIDs))
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
member, err := g.GetGroupMember(ctx, groupID, userID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
members = append(members, member)
|
||||||
|
}
|
||||||
|
return members, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupLocalCache) GetGroupMemberInfoMap(ctx context.Context, groupID string, userIDs []string) (map[string]*sdkws.GroupMemberFullInfo, error) {
|
||||||
|
members := make(map[string]*sdkws.GroupMemberFullInfo)
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
member, err := g.GetGroupMember(ctx, groupID, userID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
members[userID] = member
|
||||||
|
}
|
||||||
|
return members, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package rpccache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
func subscriberRedisDeleteCache(ctx context.Context, client redis.UniversalClient, channel string, del func(ctx context.Context, key ...string)) {
|
||||||
|
for message := range client.Subscribe(ctx, channel).Channel() {
|
||||||
|
log.ZDebug(ctx, "subscriberRedisDeleteCache", "channel", channel, "payload", message.Payload)
|
||||||
|
var keys []string
|
||||||
|
if err := json.Unmarshal([]byte(message.Payload), &keys); err != nil {
|
||||||
|
log.ZError(ctx, "subscriberRedisDeleteCache json.Unmarshal error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(keys) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
del(ctx, keys...)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package rpccache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/OpenIMSDK/protocol/sdkws"
|
||||||
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
|
"github.com/OpenIMSDK/tools/log"
|
||||||
|
"github.com/openimsdk/localcache"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/cachekey"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewUserLocalCache(client rpcclient.UserRpcClient, cli redis.UniversalClient) *UserLocalCache {
|
||||||
|
lc := config.Config.LocalCache.User
|
||||||
|
log.ZDebug(context.Background(), "UserLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
|
||||||
|
x := &UserLocalCache{
|
||||||
|
client: client,
|
||||||
|
local: localcache.New[any](
|
||||||
|
localcache.WithLocalSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSlotSize(lc.SlotSize),
|
||||||
|
localcache.WithLinkSlotNum(lc.SlotNum),
|
||||||
|
localcache.WithLocalSuccessTTL(lc.Success()),
|
||||||
|
localcache.WithLocalFailedTTL(lc.Failed()),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
if lc.Enable() {
|
||||||
|
go subscriberRedisDeleteCache(context.Background(), cli, lc.Topic, x.local.DelLocal)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserLocalCache struct {
|
||||||
|
client rpcclient.UserRpcClient
|
||||||
|
local localcache.Cache[any]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *sdkws.UserInfo, err error) {
|
||||||
|
log.ZDebug(ctx, "UserLocalCache GetUserInfo req", "userID", userID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "UserLocalCache GetUserInfo return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "UserLocalCache GetUserInfo return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[*sdkws.UserInfo](u.local.Get(ctx, cachekey.GetUserInfoKey(userID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "UserLocalCache GetUserInfo rpc", "userID", userID)
|
||||||
|
return u.client.GetUserInfo(ctx, userID)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserLocalCache) GetUserGlobalMsgRecvOpt(ctx context.Context, userID string) (val int32, err error) {
|
||||||
|
log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt req", "userID", userID)
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt return", "value", val)
|
||||||
|
} else {
|
||||||
|
log.ZError(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt return", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return localcache.AnyValue[int32](u.local.Get(ctx, cachekey.GetUserGlobalRecvMsgOptKey(userID), func(ctx context.Context) (any, error) {
|
||||||
|
log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt rpc", "userID", userID)
|
||||||
|
return u.client.GetUserGlobalMsgRecvOpt(ctx, userID)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserLocalCache) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) {
|
||||||
|
users := make([]*sdkws.UserInfo, 0, len(userIDs))
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
user, err := u.GetUserInfo(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserLocalCache) GetUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
|
||||||
|
users := make(map[string]*sdkws.UserInfo, len(userIDs))
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
user, err := u.GetUserInfo(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
if errs.ErrRecordNotFound.Is(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
users[userID] = user
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
@@ -114,6 +114,14 @@ func (c *ConversationRpcClient) GetConversationsByConversationID(ctx context.Con
|
|||||||
return resp.Conversations, nil
|
return resp.Conversations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ConversationRpcClient) GetConversationOfflinePushUserIDs(ctx context.Context, conversationID string, userIDs []string) ([]string, error) {
|
||||||
|
resp, err := c.Client.GetConversationOfflinePushUserIDs(ctx, &pbconversation.GetConversationOfflinePushUserIDsReq{ConversationID: conversationID, UserIDs: userIDs})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.UserIDs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
|
func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
|
||||||
if len(conversationIDs) == 0 {
|
if len(conversationIDs) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -127,3 +135,11 @@ func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserI
|
|||||||
}
|
}
|
||||||
return resp.Conversations, nil
|
return resp.Conversations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ConversationRpcClient) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) {
|
||||||
|
resp, err := c.Client.GetConversationNotReceiveMessageUserIDs(ctx, &pbconversation.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.UserIDs, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func (f *FriendRpcClient) GetFriendIDs(ctx context.Context, ownerUserID string)
|
|||||||
return resp.FriendIDs, nil
|
return resp.FriendIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *FriendRpcClient) IsBlocked(ctx context.Context, possibleBlackUserID, userID string) (bool, error) {
|
func (b *FriendRpcClient) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (bool, error) {
|
||||||
r, err := b.Client.IsBlack(ctx, &friend.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID})
|
r, err := b.Client.IsBlack(ctx, &friend.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
|||||||
@@ -26,11 +26,9 @@ import (
|
|||||||
"github.com/OpenIMSDK/tools/utils"
|
"github.com/OpenIMSDK/tools/utils"
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
|
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
conn grpc.ClientConnInterface
|
|
||||||
Client group.GroupClient
|
Client group.GroupClient
|
||||||
discov discoveryregistry.SvcDiscoveryRegistry
|
discov discoveryregistry.SvcDiscoveryRegistry
|
||||||
Config *config.GlobalConfig
|
Config *config.GlobalConfig
|
||||||
@@ -42,7 +40,7 @@ func NewGroup(discov discoveryregistry.SvcDiscoveryRegistry, config *config.Glob
|
|||||||
util.ExitWithError(err)
|
util.ExitWithError(err)
|
||||||
}
|
}
|
||||||
client := group.NewGroupClient(conn)
|
client := group.NewGroupClient(conn)
|
||||||
return &Group{discov: discov, conn: conn, Client: client, Config: config}
|
return &Group{discov: discov, Client: client, Config: config}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GroupRpcClient Group
|
type GroupRpcClient Group
|
||||||
|
|||||||
@@ -25,5 +25,5 @@ OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
|||||||
source "${OPENIM_ROOT}/scripts/install/common.sh"
|
source "${OPENIM_ROOT}/scripts/install/common.sh"
|
||||||
openim::log::info "\n# Use Docker to start all openim service"
|
openim::log::info "\n# Use Docker to start all openim service"
|
||||||
trap 'openim::util::onCtrlC' INT
|
trap 'openim::util::onCtrlC' INT
|
||||||
"${OPENIM_ROOT}"/scripts/start-all.sh
|
"${OPENIM_ROOT}"/scripts/start-all.sh 2>&1 &
|
||||||
tail -f ${DOCKER_LOG_FILE}
|
tail -f ${DOCKER_LOG_FILE}
|
||||||
|
|||||||
@@ -150,6 +150,12 @@ process_file() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ -n "${env_cmd}" ]]; then
|
if [[ -n "${env_cmd}" ]]; then
|
||||||
|
|
||||||
|
{
|
||||||
|
printf "debugggggggggggggggggggg file: %s template: %s\n" "${ENV_FILE}" "${template}"
|
||||||
|
} | tee /tmp/debug.log
|
||||||
|
|
||||||
|
|
||||||
eval "$env_cmd ${OPENIM_ROOT}/scripts/genconfig.sh '${ENV_FILE}' '${template}' > '${output_file}'" || {
|
eval "$env_cmd ${OPENIM_ROOT}/scripts/genconfig.sh '${ENV_FILE}' '${template}' > '${output_file}'" || {
|
||||||
openim::log::error "Error processing template file ${template}"
|
openim::log::error "Error processing template file ${template}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ openim::tools::pre_start_name() {
|
|||||||
local targets=(
|
local targets=(
|
||||||
ncpu
|
ncpu
|
||||||
component
|
component
|
||||||
up35
|
|
||||||
)
|
)
|
||||||
echo "${targets[@]}"
|
echo "${targets[@]}"
|
||||||
}
|
}
|
||||||
@@ -101,7 +100,13 @@ function openim::tools::start_service() {
|
|||||||
cmd="${cmd} --prometheus_port ${prometheus_port}"
|
cmd="${cmd} --prometheus_port ${prometheus_port}"
|
||||||
fi
|
fi
|
||||||
openim::log::status "Starting binary ${binary_name}..."
|
openim::log::status "Starting binary ${binary_name}..."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
${cmd}
|
${cmd}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local status=$?
|
local status=$?
|
||||||
|
|
||||||
if [ $status -eq 0 ]; then
|
if [ $status -eq 0 ]; then
|
||||||
|
|||||||
+2
-67
@@ -413,7 +413,7 @@ openim::util::check_process_names() {
|
|||||||
else
|
else
|
||||||
# If there are PIDs, loop through each one
|
# If there are PIDs, loop through each one
|
||||||
for pid in "${pids[@]}"; do
|
for pid in "${pids[@]}"; do
|
||||||
local command=$(ps -p $pid -o cmd=)
|
local command=$(ps -p $pid -o comm=)
|
||||||
local start_time=$(ps -p $pid -o lstart=)
|
local start_time=$(ps -p $pid -o lstart=)
|
||||||
local port=$(get_port $pid)
|
local port=$(get_port $pid)
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ openim::util::check_process_names_for_stop() {
|
|||||||
else
|
else
|
||||||
# If there are PIDs, loop through each one
|
# If there are PIDs, loop through each one
|
||||||
for pid in "${pids[@]}"; do
|
for pid in "${pids[@]}"; do
|
||||||
local command=$(ps -p $pid -o cmd=)
|
local command=$(ps -p $pid -o comm=)
|
||||||
local start_time=$(ps -p $pid -o lstart=)
|
local start_time=$(ps -p $pid -o lstart=)
|
||||||
local port=$(get_port $pid)
|
local port=$(get_port $pid)
|
||||||
|
|
||||||
@@ -1795,10 +1795,6 @@ openim::util::stop_services_on_ports() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
# nc -l -p 12345
|
|
||||||
# nc -l -p 123456
|
|
||||||
# ps -ef | grep "nc -l"
|
|
||||||
# openim::util::stop_services_on_ports 1234 12345
|
|
||||||
|
|
||||||
|
|
||||||
# The `openim::util::stop_services_with_name` function stops services with specified names.
|
# The `openim::util::stop_services_with_name` function stops services with specified names.
|
||||||
@@ -1808,68 +1804,7 @@ openim::util::stop_services_on_ports() {
|
|||||||
# Usage:
|
# Usage:
|
||||||
# openim::util::stop_services_with_name nginx apache
|
# openim::util::stop_services_with_name nginx apache
|
||||||
# The function returns a status of 1 if any service couldn't be stopped.
|
# The function returns a status of 1 if any service couldn't be stopped.
|
||||||
openim::util::stop_services_with_name() {
|
|
||||||
# An array to collect names of processes that couldn't be stopped.
|
|
||||||
local not_stopped=()
|
|
||||||
|
|
||||||
# An array to collect information about processes that were stopped.
|
|
||||||
local stopped=()
|
|
||||||
|
|
||||||
echo "Stopping services with names: $*"
|
|
||||||
# Iterate over each given service name.
|
|
||||||
for server_name in "$@"; do
|
|
||||||
# Use the `pgrep` command to find process IDs related to the given service name.
|
|
||||||
local pids=$(pgrep -f "$server_name")
|
|
||||||
|
|
||||||
# If no process was found with the name, add it to the not_stopped list
|
|
||||||
if [[ -z $pids ]]; then
|
|
||||||
not_stopped+=("$server_name")
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
local stopped_this_time=false
|
|
||||||
for pid in $pids; do
|
|
||||||
|
|
||||||
# Exclude the PID of the current script
|
|
||||||
if [[ "$pid" == "$$" ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If there's a Process ID, it means the service with the name is running.
|
|
||||||
if [[ -n $pid ]]; then
|
|
||||||
# Try to stop the service by killing its process.
|
|
||||||
if kill -10 $pid 2>/dev/null; then
|
|
||||||
stopped_this_time=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if $stopped_this_time; then
|
|
||||||
stopped+=("$server_name")
|
|
||||||
else
|
|
||||||
not_stopped+=("$server_name")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Print information about services whose processes couldn't be stopped.
|
|
||||||
if [[ ${#not_stopped[@]} -ne 0 ]]; then
|
|
||||||
echo "Services that couldn't be stopped:"
|
|
||||||
for name in "${not_stopped[@]}"; do
|
|
||||||
openim::log::status "Failed to stop the $name service."
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Print information about services whose processes were successfully stopped.
|
|
||||||
if [[ ${#stopped[@]} -ne 0 ]]; then
|
|
||||||
echo
|
|
||||||
echo "Stopped services:"
|
|
||||||
for name in "${stopped[@]}"; do
|
|
||||||
echo "Successfully stopped the $name service."
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
openim::log::success "All specified services were stopped."
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
# sleep 333333&
|
# sleep 333333&
|
||||||
# sleep 444444&
|
# sleep 444444&
|
||||||
# ps -ef | grep "sleep"
|
# ps -ef | grep "sleep"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ function execute_start_scripts() {
|
|||||||
|
|
||||||
|
|
||||||
if openim::util::is_running_in_container; then
|
if openim::util::is_running_in_container; then
|
||||||
exec > ${DOCKER_LOG_FILE} 2>&1
|
exec >> ${DOCKER_LOG_FILE} 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
# This script verifies whether codes follow golang convention.
|
|
||||||
# Usage: `scripts/verify-pkg-names.sh`.
|
|
||||||
|
|
||||||
set -o errexit
|
|
||||||
|
|
||||||
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
|
||||||
source "${OPENIM_ROOT}/scripts/lib/init.sh"
|
|
||||||
|
|
||||||
openim::golang::verify_go_version
|
|
||||||
|
|
||||||
openim::golang::verify_go_version
|
|
||||||
|
|
||||||
OPENIM_OUTPUT_HOSTBIN_TOOLS="${OPENIM_ROOT}/_output/bin/tools/linux/amd64"
|
|
||||||
CODESCAN_BINARY="${OPENIM_OUTPUT_HOSTBIN_TOOLS}/codescan"
|
|
||||||
|
|
||||||
if [[ ! -f "${CODESCAN_BINARY}" ]]; then
|
|
||||||
echo "codescan binary not found, building..."
|
|
||||||
pushd "${OPENIM_ROOT}" >/dev/null
|
|
||||||
make build BINS="codescan"
|
|
||||||
popd >/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f "${CODESCAN_BINARY}" ]]; then
|
|
||||||
echo "Failed to build codescan binary."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
CONFIG_PATH="${OPENIM_ROOT}/tools/codescan/config.yaml"
|
|
||||||
|
|
||||||
"${CODESCAN_BINARY}" -config "${CONFIG_PATH}"
|
|
||||||
@@ -87,6 +87,7 @@ disabled=(
|
|||||||
2178
|
2178
|
||||||
2064
|
2064
|
||||||
2260
|
2260
|
||||||
|
2261
|
||||||
2043
|
2043
|
||||||
2178
|
2178
|
||||||
2044
|
2044
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
// Copyright © 2024 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 checker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/tools/codescan/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CheckResult struct {
|
|
||||||
FilePath string
|
|
||||||
Lines []int
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkFileForChineseComments(filePath string) ([]CheckResult, error) {
|
|
||||||
file, err := os.Open(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
var results []CheckResult
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
reg := regexp.MustCompile(`[\p{Han}]+`)
|
|
||||||
lineNumber := 0
|
|
||||||
|
|
||||||
var linesWithChinese []int
|
|
||||||
for scanner.Scan() {
|
|
||||||
lineNumber++
|
|
||||||
if reg.FindString(scanner.Text()) != "" {
|
|
||||||
linesWithChinese = append(linesWithChinese, lineNumber)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(linesWithChinese) > 0 {
|
|
||||||
results = append(results, CheckResult{
|
|
||||||
FilePath: filePath,
|
|
||||||
Lines: linesWithChinese,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WalkDirAndCheckComments(cfg config.Config) error {
|
|
||||||
var allResults []CheckResult
|
|
||||||
err := filepath.Walk(cfg.Directory, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if info.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, fileType := range cfg.FileTypes {
|
|
||||||
if filepath.Ext(path) == fileType {
|
|
||||||
results, err := checkFileForChineseComments(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(results) > 0 {
|
|
||||||
allResults = append(allResults, results...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(allResults) > 0 {
|
|
||||||
var errMsg strings.Builder
|
|
||||||
errMsg.WriteString("Files containing Chinese comments:\n")
|
|
||||||
for _, result := range allResults {
|
|
||||||
errMsg.WriteString(fmt.Sprintf("%s: Lines %v\n", result.FilePath, result.Lines))
|
|
||||||
}
|
|
||||||
return fmt.Errorf(errMsg.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// Copyright © 2024 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 main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/tools/codescan/checker"
|
|
||||||
"github.com/openimsdk/open-im-server/tools/codescan/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cfg, err := config.ParseConfig()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error parsing config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = checker.WalkDirAndCheckComments(cfg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Copyright © 2024 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.
|
|
||||||
|
|
||||||
directory: ./
|
|
||||||
file_types:
|
|
||||||
- .go
|
|
||||||
- .yaml
|
|
||||||
- .yml
|
|
||||||
languages:
|
|
||||||
- Chinese
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// Copyright © 2024 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 config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Directory string `yaml:"directory"`
|
|
||||||
FileTypes []string `yaml:"file_types"`
|
|
||||||
Languages []string `yaml:"languages"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseConfig() (Config, error) {
|
|
||||||
var configPath string
|
|
||||||
flag.StringVar(&configPath, "config", "./", "Path to config file")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
var config Config
|
|
||||||
if configPath != "" {
|
|
||||||
configFile, err := os.ReadFile(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return Config{}, err
|
|
||||||
}
|
|
||||||
if err := yaml.Unmarshal(configFile, &config); err != nil {
|
|
||||||
return Config{}, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Fatal("Config file must be provided")
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module github.com/openimsdk/open-im-server/tools/codescan
|
|
||||||
|
|
||||||
go 1.19
|
|
||||||
@@ -31,7 +31,6 @@ import (
|
|||||||
"github.com/OpenIMSDK/tools/errs"
|
"github.com/OpenIMSDK/tools/errs"
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -66,6 +65,23 @@ type checkFunc struct {
|
|||||||
config *config.GlobalConfig
|
config *config.GlobalConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// colorErrPrint prints formatted string in red to stderr
|
||||||
|
func colorErrPrint(msg string) {
|
||||||
|
// ANSI escape code for red text
|
||||||
|
const redColor = "\033[31m"
|
||||||
|
// ANSI escape code to reset color
|
||||||
|
const resetColor = "\033[0m"
|
||||||
|
msg = redColor + msg + resetColor
|
||||||
|
// Print to stderr in red
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func colorSuccessPrint(format string, a ...interface{}) {
|
||||||
|
// ANSI escape code for green text is \033[32m
|
||||||
|
// \033[0m resets the color
|
||||||
|
fmt.Printf("\033[32m"+format+"\033[0m", a...)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -77,24 +93,25 @@ func main() {
|
|||||||
|
|
||||||
err = configGetEnv(conf)
|
err = configGetEnv(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("configGetEnv failed,err:%v", err)
|
fmt.Printf("configGetEnv failed, err:%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
checks := []checkFunc{
|
checks := []checkFunc{
|
||||||
//{name: "Mysql", function: checkMysql},
|
|
||||||
{name: "Mongo", function: checkMongo, config: conf},
|
{name: "Mongo", function: checkMongo, config: conf},
|
||||||
{name: "Redis", function: checkRedis, config: conf},
|
{name: "Redis", function: checkRedis, config: conf},
|
||||||
{name: "Minio", function: checkMinio, config: conf},
|
|
||||||
{name: "Zookeeper", function: checkZookeeper, config: conf},
|
{name: "Zookeeper", function: checkZookeeper, config: conf},
|
||||||
{name: "Kafka", function: checkKafka, config: conf},
|
{name: "Kafka", function: checkKafka, config: conf},
|
||||||
}
|
}
|
||||||
|
if conf.Object.Enable == "minio" {
|
||||||
|
checks = append(checks, checkFunc{name: "Minio", function: checkMinio, config: conf})
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < maxRetry; i++ {
|
for i := 0; i < maxRetry; i++ {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
fmt.Printf("Checking components Round %v...\n", i+1)
|
fmt.Printf("Checking components round %v...\n", i+1)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
allSuccess := true
|
allSuccess := true
|
||||||
@@ -102,33 +119,31 @@ func main() {
|
|||||||
if !check.flag {
|
if !check.flag {
|
||||||
err = check.function(check.config)
|
err = check.function(check.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, errMinioNotEnabled) {
|
allSuccess = false
|
||||||
fmt.Println(err.Error())
|
colorErrPrint(fmt.Sprintf("Check component: %s, failed: %v", check.name, err.Error()))
|
||||||
checks[index].flag = true
|
|
||||||
}
|
if check.name == "Minio" {
|
||||||
if errors.Is(err, errSignEndPoint) {
|
if errors.Is(err, errMinioNotEnabled) ||
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
errors.Is(err, errSignEndPoint) ||
|
||||||
checks[index].flag = true
|
errors.Is(err, errApiURL) {
|
||||||
}
|
checks[index].flag = true
|
||||||
component.ErrorPrint(fmt.Sprintf("Starting %s failed:%v.", check.name, errs.Unwrap(err).Error()))
|
continue
|
||||||
if !strings.Contains(errs.Unwrap(err).Error(), "connection refused") &&
|
}
|
||||||
!strings.Contains(errs.Unwrap(err).Error(), "timeout waiting") {
|
break
|
||||||
component.ErrorPrint("Some components started failed!")
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
checks[index].flag = true
|
checks[index].flag = true
|
||||||
component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name))
|
component.SuccessPrint(fmt.Sprintf("%s connected successfully", check.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
if allSuccess {
|
if allSuccess {
|
||||||
component.SuccessPrint("All components started successfully!")
|
component.SuccessPrint("All components started successfully!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
component.ErrorPrint("Some components started failed!")
|
component.ErrorPrint("Some components checked failed!")
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,13 +181,13 @@ func checkRedis(config *config.GlobalConfig) error {
|
|||||||
// checkMinio checks the MinIO connection
|
// checkMinio checks the MinIO connection
|
||||||
func checkMinio(config *config.GlobalConfig) error {
|
func checkMinio(config *config.GlobalConfig) error {
|
||||||
if strings.Contains(config.Object.ApiURL, "127.0.0.1") {
|
if strings.Contains(config.Object.ApiURL, "127.0.0.1") {
|
||||||
return errs.Wrap(errApiURL, "config.Object.ApiURL: "+config.Object.ApiURL)
|
return errs.Wrap(errApiURL)
|
||||||
}
|
}
|
||||||
if config.Object.Enable != "minio" {
|
if config.Object.Enable != "minio" {
|
||||||
return errs.Wrap(errMinioNotEnabled, "config.Object.Enable: "+config.Object.Enable)
|
return errs.Wrap(errMinioNotEnabled)
|
||||||
}
|
}
|
||||||
if strings.Contains(config.Object.Minio.Endpoint, "127.0.0.1") {
|
if strings.Contains(config.Object.Minio.Endpoint, "127.0.0.1") {
|
||||||
return errs.Wrap(errSignEndPoint, "config.Object.Minio.Endpoint: "+config.Object.Minio.Endpoint)
|
return errs.Wrap(errSignEndPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
minio := &component.Minio{
|
minio := &component.Minio{
|
||||||
@@ -258,13 +273,13 @@ func checkKafka(config *config.GlobalConfig) error {
|
|||||||
_, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
|
_, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
|
||||||
KafkaVersion: sarama.V2_0_0_0,
|
KafkaVersion: sarama.V2_0_0_0,
|
||||||
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
|
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
|
||||||
}, []string{config.Kafka.MsgToPush.Topic},
|
}, []string{config.Kafka.MsgToMongo.Topic},
|
||||||
config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToMongo, tlsConfig)
|
config.Kafka.Addr, config.Kafka.ConsumerGroupID.MsgToMongo, tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
|
_, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
|
||||||
KafkaVersion: sarama.V2_0_0_0,
|
KafkaVersion: sarama.V2_0_0_0,
|
||||||
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
|
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false,
|
||||||
}, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr,
|
}, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr,
|
||||||
@@ -292,15 +307,15 @@ func configGetEnv(config *config.GlobalConfig) error {
|
|||||||
config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Mongo.Password)
|
config.Mongo.Password = getEnv("MONGO_OPENIM_PASSWORD", config.Mongo.Password)
|
||||||
config.Mongo.Address = getArrEnv("MONGO_ADDRESS", "MONGO_PORT", config.Mongo.Address)
|
config.Mongo.Address = getArrEnv("MONGO_ADDRESS", "MONGO_PORT", config.Mongo.Address)
|
||||||
config.Mongo.Database = getEnv("MONGO_DATABASE", config.Mongo.Database)
|
config.Mongo.Database = getEnv("MONGO_DATABASE", config.Mongo.Database)
|
||||||
maxPoolSize, err := getEnvInt("MONGO_DATABASE", config.Mongo.MaxPoolSize)
|
maxPoolSize, err := getEnvInt("MONGO_MAX_POOL_SIZE", config.Mongo.MaxPoolSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return errs.Wrap(err, "MONGO_MAX_POOL_SIZE")
|
||||||
}
|
}
|
||||||
config.Mongo.MaxPoolSize = maxPoolSize
|
config.Mongo.MaxPoolSize = maxPoolSize
|
||||||
|
|
||||||
config.Redis.Username = getEnv("REDIS_USERNAME", config.Redis.Username)
|
config.Redis.Username = getEnv("REDIS_USERNAME", config.Redis.Username)
|
||||||
config.Redis.Password = getEnv("REDIS_PASSWORD", config.Redis.Password)
|
config.Redis.Password = getEnv("REDIS_PASSWORD", config.Redis.Password)
|
||||||
config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PASSWORD", config.Redis.Address)
|
config.Redis.Address = getArrEnv("REDIS_ADDRESS", "REDIS_PORT", config.Redis.Address)
|
||||||
|
|
||||||
config.Object.ApiURL = getEnv("OBJECT_APIURL", config.Object.ApiURL)
|
config.Object.ApiURL = getEnv("OBJECT_APIURL", config.Object.ApiURL)
|
||||||
config.Object.Minio.Endpoint = getEnv("MINIO_ENDPOINT", config.Object.Minio.Endpoint)
|
config.Object.Minio.Endpoint = getEnv("MINIO_ENDPOINT", config.Object.Minio.Endpoint)
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
# OpenIM V2 至 V3 数据迁移指南
|
|
||||||
|
|
||||||
该指南提供了从 OpenIM V2 迁移至 V3 的详细步骤。请确保在开始迁移过程之前,熟悉所有步骤,并按照指南准确执行。
|
|
||||||
|
|
||||||
+ [OpenIM Chat](https://github.com/OpenIMSDK/chat)
|
|
||||||
+ [OpenIM Server](https://github.com/OpenIMSDK/Open-IM-Server)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1. 数据备份
|
|
||||||
|
|
||||||
在开始数据迁移之前,强烈建议备份所有相关的数据以防止任何可能的数据丢失。
|
|
||||||
|
|
||||||
### 2. 迁移 OpenIM MySQL 数据
|
|
||||||
|
|
||||||
+ 位置: `open-im-server/tools/data-conversion/openim/cmd/conversion-mysql.go`
|
|
||||||
+ 配置 `conversion-mysql.go` 文件中的数据库信息。
|
|
||||||
+ 手动创建 V3 版本的数据库,并确保字符集为 `utf8mb4`。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
// V2 数据库配置
|
|
||||||
var (
|
|
||||||
usernameV2 = "root"
|
|
||||||
passwordV2 = "openIM"
|
|
||||||
addrV2 = "127.0.0.1:13306"
|
|
||||||
databaseV2 = "openIM_v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// V3 数据库配置
|
|
||||||
var (
|
|
||||||
usernameV3 = "root"
|
|
||||||
passwordV3 = "openIM123"
|
|
||||||
addrV3 = "127.0.0.1:13306"
|
|
||||||
databaseV3 = "openim_v3"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
**执行数据迁移命令:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make build BINS="conversion-mysql"
|
|
||||||
```
|
|
||||||
|
|
||||||
启动的二进制在 `_output/bin/tools` 中
|
|
||||||
|
|
||||||
|
|
||||||
### 3. 转换聊天消息(可选)
|
|
||||||
|
|
||||||
+ 只支持转换存储在 Kafka 中的消息。
|
|
||||||
+ 位置: `open-im-server/tools/data-conversion/openim/conversion-msg/conversion-msg.go`
|
|
||||||
+ 配置 `msg.go` 文件中的消息和服务器信息。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
var (
|
|
||||||
topic = "ws2ms_chat" // V2 版本 Kafka 主题
|
|
||||||
kafkaAddr = "127.0.0.1:9092" // V2 版本 Kafka 地址
|
|
||||||
rpcAddr = "127.0.0.1:10130" // V3 版本 RPC 地址
|
|
||||||
adminUserID = "openIM123456" // V3 版本管理员用户ID
|
|
||||||
concurrency = 4 // 并发数量
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
**执行数据迁移命令:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make build BINS="conversion-msg"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 转换业务服务器数据
|
|
||||||
|
|
||||||
+ 只支持转换存储在 Kafka 中的消息。
|
|
||||||
+ 位置: `open-im-server/tools/data-conversion/chat/cmd/conversion-chat/chat.go`
|
|
||||||
+ 需要手动创建 V3 版本的数据库,并确保字符集为 `utf8mb4`。
|
|
||||||
+ 配置 `main.go` 文件中的数据库信息。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
// V2 数据库配置
|
|
||||||
var (
|
|
||||||
usernameV2 = "root"
|
|
||||||
passwordV2 = "openIM"
|
|
||||||
addrV2 = "127.0.0.1:13306"
|
|
||||||
databaseV2 = "admin_chat"
|
|
||||||
)
|
|
||||||
|
|
||||||
// V3 数据库配置
|
|
||||||
var (
|
|
||||||
usernameV3 = "root"
|
|
||||||
passwordV3 = "openIM123"
|
|
||||||
addrV3 = "127.0.0.1:13306"
|
|
||||||
databaseV3 = "openim_enterprise"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
**执行数据迁移命令:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make build BINS="conversion-chat"
|
|
||||||
```
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// 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 main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"gorm.io/driver/mysql"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"gorm.io/gorm/logger"
|
|
||||||
|
|
||||||
"github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/conversion"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var (
|
|
||||||
usernameV2 = "root" // Username for MySQL v2 version
|
|
||||||
passwordV2 = "openIM" // Password for MySQL v2 version
|
|
||||||
addrV2 = "127.0.0.1:13306" // Address for MySQL v2 version
|
|
||||||
databaseV2 = "admin_chat" // Database name for MySQL v2 version
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
usernameV3 = "root" // Username for MySQL v3 version
|
|
||||||
passwordV3 = "openIM123" // Password for MySQL v3 version
|
|
||||||
addrV3 = "127.0.0.1:13306" // Address for MySQL v3 version
|
|
||||||
databaseV3 = "openim_enterprise" // Database name for MySQL v3 version
|
|
||||||
)
|
|
||||||
|
|
||||||
var concurrency = 1 // Concurrency quantity
|
|
||||||
|
|
||||||
log.SetFlags(log.LstdFlags | log.Llongfile)
|
|
||||||
dsnV2 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV2, passwordV2, addrV2, databaseV2)
|
|
||||||
dsnV3 := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", usernameV3, passwordV3, addrV3, databaseV3)
|
|
||||||
dbV2, err := gorm.Open(mysql.Open(dsnV2), &gorm.Config{Logger: logger.Discard})
|
|
||||||
if err != nil {
|
|
||||||
log.Println("open v2 db failed", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dbV3, err := gorm.Open(mysql.Open(dsnV3), &gorm.Config{Logger: logger.Discard})
|
|
||||||
if err != nil {
|
|
||||||
log.Println("open v3 db failed", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var tasks utils.TakeList
|
|
||||||
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Account) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Attribute) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Register) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.UserLoginRecord) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Admin) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.Applet) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.ForbiddenAccount) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.InvitationRegister) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.IPForbidden) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.LimitUserLoginIP) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.RegisterAddFriend) })
|
|
||||||
tasks.Append(func() (string, error) { return utils.FindAndInsert(dbV2, dbV3, conversion.RegisterAddGroup) })
|
|
||||||
|
|
||||||
utils.RunTask(concurrency, tasks)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
// 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 conversion
|
|
||||||
|
|
||||||
import (
|
|
||||||
v2 "github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/v2"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/v3/admin"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/tools/data-conversion/chat/v3/chat"
|
|
||||||
"github.com/openimsdk/open-im-server/v3/tools/data-conversion/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ########## chat ##########
|
|
||||||
|
|
||||||
func Account(v v2.Account) (chat.Account, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime, &v.ChangeTime)
|
|
||||||
return chat.Account{
|
|
||||||
UserID: v.UserID,
|
|
||||||
Password: v.Password,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
ChangeTime: v.ChangeTime,
|
|
||||||
OperatorUserID: v.OperatorUserID,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Attribute(v v2.Attribute) (chat.Attribute, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime, &v.ChangeTime, &v.BirthTime)
|
|
||||||
return chat.Attribute{
|
|
||||||
UserID: v.UserID,
|
|
||||||
Account: v.Account,
|
|
||||||
PhoneNumber: v.PhoneNumber,
|
|
||||||
AreaCode: v.AreaCode,
|
|
||||||
Email: v.Email,
|
|
||||||
Nickname: v.Nickname,
|
|
||||||
FaceURL: v.FaceURL,
|
|
||||||
Gender: v.Gender,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
ChangeTime: v.ChangeTime,
|
|
||||||
BirthTime: v.BirthTime,
|
|
||||||
Level: v.Level,
|
|
||||||
AllowVibration: v.AllowVibration,
|
|
||||||
AllowBeep: v.AllowBeep,
|
|
||||||
AllowAddFriend: v.AllowAddFriend,
|
|
||||||
GlobalRecvMsgOpt: 0,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Register(v v2.Register) (chat.Register, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return chat.Register{
|
|
||||||
UserID: v.UserID,
|
|
||||||
DeviceID: v.DeviceID,
|
|
||||||
IP: v.IP,
|
|
||||||
Platform: v.Platform,
|
|
||||||
AccountType: v.AccountType,
|
|
||||||
Mode: v.Mode,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func UserLoginRecord(v v2.UserLoginRecord) (chat.UserLoginRecord, bool) {
|
|
||||||
utils.InitTime(&v.LoginTime)
|
|
||||||
return chat.UserLoginRecord{
|
|
||||||
UserID: v.UserID,
|
|
||||||
LoginTime: v.LoginTime,
|
|
||||||
IP: v.IP,
|
|
||||||
DeviceID: v.DeviceID,
|
|
||||||
Platform: v.Platform,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ########## admin ##########
|
|
||||||
|
|
||||||
func Admin(v v2.Admin) (admin.Admin, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.Admin{
|
|
||||||
Account: v.Account,
|
|
||||||
Password: v.Password,
|
|
||||||
FaceURL: v.FaceURL,
|
|
||||||
Nickname: v.Nickname,
|
|
||||||
UserID: v.UserID,
|
|
||||||
Level: v.Level,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Applet(v v2.Applet) (admin.Applet, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.Applet{
|
|
||||||
ID: v.ID,
|
|
||||||
Name: v.Name,
|
|
||||||
AppID: v.AppID,
|
|
||||||
Icon: v.Icon,
|
|
||||||
URL: v.URL,
|
|
||||||
MD5: v.MD5,
|
|
||||||
Size: v.Size,
|
|
||||||
Version: v.Version,
|
|
||||||
Priority: v.Priority,
|
|
||||||
Status: v.Status,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func ForbiddenAccount(v v2.ForbiddenAccount) (admin.ForbiddenAccount, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.ForbiddenAccount{
|
|
||||||
UserID: v.UserID,
|
|
||||||
Reason: v.Reason,
|
|
||||||
OperatorUserID: v.OperatorUserID,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func InvitationRegister(v v2.InvitationRegister) (admin.InvitationRegister, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.InvitationRegister{
|
|
||||||
InvitationCode: v.InvitationCode,
|
|
||||||
UsedByUserID: v.UsedByUserID,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func IPForbidden(v v2.IPForbidden) (admin.IPForbidden, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.IPForbidden{
|
|
||||||
IP: v.IP,
|
|
||||||
LimitRegister: v.LimitRegister > 0,
|
|
||||||
LimitLogin: v.LimitLogin > 0,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func LimitUserLoginIP(v v2.LimitUserLoginIP) (admin.LimitUserLoginIP, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.LimitUserLoginIP{
|
|
||||||
UserID: v.UserID,
|
|
||||||
IP: v.IP,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterAddFriend(v v2.RegisterAddFriend) (admin.RegisterAddFriend, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.RegisterAddFriend{
|
|
||||||
UserID: v.UserID,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterAddGroup(v v2.RegisterAddGroup) (admin.RegisterAddGroup, bool) {
|
|
||||||
utils.InitTime(&v.CreateTime)
|
|
||||||
return admin.RegisterAddGroup{
|
|
||||||
GroupID: v.GroupID,
|
|
||||||
CreateTime: v.CreateTime,
|
|
||||||
}, true
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// 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 v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AppVersion manages PC client versions
|
|
||||||
type AppVersion struct {
|
|
||||||
Version string `gorm:"column:version;size:64" json:"version"`
|
|
||||||
Type int `gorm:"column:type;primary_key" json:"type"`
|
|
||||||
UpdateTime int `gorm:"column:update_time" json:"update_time"`
|
|
||||||
ForceUpdate bool `gorm:"column:force_update" json:"force_update"`
|
|
||||||
FileName string `gorm:"column:file_name" json:"file_name"`
|
|
||||||
YamlName string `gorm:"column:yaml_name" json:"yaml_name"`
|
|
||||||
UpdateLog string `gorm:"column:update_log" json:"update_log"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Admin manages backend administrators
|
|
||||||
type Admin struct {
|
|
||||||
Account string `gorm:"column:account;primary_key;type:char(64)" json:"account"`
|
|
||||||
Password string `gorm:"column:Password;type:char(64)" json:"password"`
|
|
||||||
FaceURL string `gorm:"column:FaceURL;type:char(64)" json:"faceURL"`
|
|
||||||
Nickname string `gorm:"column:Nickname;type:char(64)" json:"nickname"`
|
|
||||||
UserID string `gorm:"column:UserID;type:char(64)" json:"userID"` //openIM userID
|
|
||||||
Level int32 `gorm:"column:level;default:1" json:"level"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterAddFriend specifies default friends when registering
|
|
||||||
type RegisterAddFriend struct {
|
|
||||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterAddGroup specifies default groups when registering
|
|
||||||
type RegisterAddGroup struct {
|
|
||||||
GroupID string `gorm:"column:group_id;primary_key;type:char(64)" json:"userID"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientInitConfig contains system-related configuration items
|
|
||||||
type ClientInitConfig struct {
|
|
||||||
DiscoverPageURL string `gorm:"column:discover_page_url;size:128" json:"discoverPageURL"`
|
|
||||||
OrdinaryUserAddFriend int32 `gorm:"column:ordinary_user_add_friend; default:1" json:"ordinaryUserAddFriend"`
|
|
||||||
BossUserID string `gorm:"column:boss_user_id;type:char(64)" json:"bossUserID"`
|
|
||||||
AdminURL string `gorm:"column:admin_url;type:char(128)" json:"adminURL"`
|
|
||||||
AllowSendMsgNotFriend int32 `gorm:"column:allow_send_msg_not_friend;default:1" json:"allowSendMsgNotFriend"`
|
|
||||||
NeedInvitationCodeRegister int32 `gorm:"column:need_invitation_code_register;default:0" json:"needInvitationCodeRegister"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Applet struct {
|
|
||||||
ID string `gorm:"column:id;primary_key;size:64"`
|
|
||||||
Name string `gorm:"column:name;uniqueIndex;size:64"`
|
|
||||||
AppID string `gorm:"column:app_id;uniqueIndex;size:255"`
|
|
||||||
Icon string `gorm:"column:icon;size:255"`
|
|
||||||
URL string `gorm:"column:url;size:255"`
|
|
||||||
MD5 string `gorm:"column:md5;size:255"`
|
|
||||||
Size int64 `gorm:"column:size"`
|
|
||||||
Version string `gorm:"column:version;size:64"`
|
|
||||||
Priority uint32 `gorm:"column:priority;size:64"`
|
|
||||||
Status uint8 `gorm:"column:status"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time;autoCreateTime;size:64"`
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// 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 v2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Register Registration information sheet
|
|
||||||
type Register struct {
|
|
||||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
|
||||||
DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"`
|
|
||||||
IP string `gorm:"column:ip;type:varchar(32)" json:"ip"`
|
|
||||||
Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"`
|
|
||||||
AccountType string `gorm:"column:account_type;type:varchar(32)" json:"accountType"` //email phone account
|
|
||||||
Mode string `gorm:"column:mode;type:varchar(32)"` //user admin
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account username and password table
|
|
||||||
type Account struct {
|
|
||||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
|
||||||
Password string `gorm:"column:password;type:varchar(255)" json:"password"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
ChangeTime time.Time `gorm:"column:change_time" json:"changeTime"`
|
|
||||||
OperatorUserID string `gorm:"column:operator_user_id;type:varchar(64)" json:"operatorUserID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attribute user information table
|
|
||||||
type Attribute struct {
|
|
||||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
|
||||||
Account string `gorm:"column:account;type:char(64)" json:"account"`
|
|
||||||
PhoneNumber string `gorm:"column:phone_number;type:varchar(32)" json:"phoneNumber"`
|
|
||||||
AreaCode string `gorm:"column:area_code;type:varchar(8)" json:"areaCode"`
|
|
||||||
Email string `gorm:"column:email;type:varchar(64)" json:"email"`
|
|
||||||
Nickname string `gorm:"column:nickname;type:varchar(64)" json:"nickname"`
|
|
||||||
FaceURL string `gorm:"column:face_url;type:varchar(255)" json:"faceURL"`
|
|
||||||
Gender int32 `gorm:"column:gender" json:"gender"`
|
|
||||||
Birth uint32 `gorm:"column:birth" json:"birth"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
ChangeTime time.Time `gorm:"column:change_time" json:"changeTime"`
|
|
||||||
BirthTime time.Time `gorm:"column:birth_time" json:"birthTime"`
|
|
||||||
Level int32 `gorm:"column:level;default:1" json:"level"`
|
|
||||||
AllowVibration int32 `gorm:"column:allow_vibration;default:1" json:"allowVibration"`
|
|
||||||
AllowBeep int32 `gorm:"column:allow_beep;default:1" json:"allowBeep"`
|
|
||||||
AllowAddFriend int32 `gorm:"column:allow_add_friend;default:1" json:"allowAddFriend"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// User friend relationship table
|
|
||||||
type ForbiddenAccount struct {
|
|
||||||
UserID string `gorm:"column:user_id;index:userID;primary_key;type:char(64)" json:"userID"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
Reason string `gorm:"column:reason;type:varchar(255)" json:"reason"`
|
|
||||||
OperatorUserID string `gorm:"column:operator_user_id;type:varchar(255)" json:"operatorUserID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// user login record table
|
|
||||||
type UserLoginRecord struct {
|
|
||||||
UserID string `gorm:"column:user_id;size:64" json:"userID"`
|
|
||||||
LoginTime time.Time `gorm:"column:login_time" json:"loginTime"`
|
|
||||||
IP string `gorm:"column:ip;type:varchar(32)" json:"ip"`
|
|
||||||
DeviceID string `gorm:"column:device_id;type:varchar(255)" json:"deviceID"`
|
|
||||||
Platform string `gorm:"column:platform;type:varchar(32)" json:"platform"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ip login registration is prohibited
|
|
||||||
type IPForbidden struct {
|
|
||||||
IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"`
|
|
||||||
LimitRegister int32 `gorm:"column:limit_register" json:"limitRegister"`
|
|
||||||
LimitLogin int32 `gorm:"column:limit_login" json:"limitLogin"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict userids to certain ip addresses
|
|
||||||
type LimitUserLoginIP struct {
|
|
||||||
UserID string `gorm:"column:user_id;primary_key;type:char(64)" json:"userID"`
|
|
||||||
IP string `gorm:"column:ip;primary_key;type:char(32)" json:"ip"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// The invitation code is registered for use
|
|
||||||
type InvitationRegister struct {
|
|
||||||
InvitationCode string `gorm:"column:invitation_code;primary_key;type:char(32)" json:"invitationCode"`
|
|
||||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
|
|
||||||
UsedByUserID string `gorm:"column:user_id;index:userID;type:char(64)" json:"usedByUserID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignalRecord struct {
|
|
||||||
FileName string `gorm:"column:file_name;primary_key;type:char(128)" json:"fileName"`
|
|
||||||
MediaType string `gorm:"column:media_type;type:char(64);index:media_type_index" json:"mediaType"`
|
|
||||||
RoomType string `gorm:"column:room_type;type:char(20)" json:"roomType"`
|
|
||||||
SenderID string `gorm:"column:sender_id;type:char(64);index:sender_id_index" json:"senderID"`
|
|
||||||
RecvID string `gorm:"column:recv_id;type:char(64);index:recv_id_index" json:"recvID"`
|
|
||||||
GroupID string `gorm:"column:group_id;type:char(64)" json:"groupID"`
|
|
||||||
DownloadURL string `gorm:"column:download_url;type:text" json:"downloadURL"`
|
|
||||||
CreateTime time.Time `gorm:"create_time;index:create_time_index" json:"createTime"`
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user