Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot] 391eafb402 Update version to v3.8.3-patch.7 2025-07-29 09:07:09 +00:00
8 changed files with 77 additions and 170 deletions
+56 -100
View File
@@ -4,80 +4,45 @@ on:
push: push:
branches: branches:
- release-* - release-*
# tags:
# - 'v*'
release: release:
types: [published] types: [published]
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
description: "Tag version to be used for Docker image" description: "Tag version to be used for Docker image"
required: true required: true
default: "v3.8.3" default: "v3.8.0"
env:
GO_VERSION: "1.22"
IMAGE_NAME: "openim-server"
# IMAGE_NAME: ${{ github.event.repository.name }}
DOCKER_BUILDKIT: 1
jobs: jobs:
publish-docker-images: build-and-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.merged == false) }}
steps: steps:
- name: Checkout main repository - uses: actions/checkout@v4
uses: actions/checkout@v4
with: with:
path: main-repo path: main-repo
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3.3.0 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Build Docker image
id: build
uses: docker/build-push-action@v5
with: with:
driver-opts: network=host context: ./main-repo
load: true
tags: "openim/openim-server:local"
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Extract metadata for Docker - name: Save Docker image to file
id: meta run: docker save -o image.tar openim/openim-server:local
uses: docker/metadata-action@v5.6.0
with:
images: |
${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}
ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
registry.cn-hangzhou.aliyuncs.com/openimsdk/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Install skopeo
run: |
sudo apt-get update && sudo apt-get install -y skopeo
- name: Build multi-arch images as OCI
run: |
mkdir -p /tmp/oci-image /tmp/docker-cache
# Build multi-architecture image and save in OCI format
docker buildx build \
--platform linux/amd64,linux/arm64 \
--output type=oci,dest=/tmp/oci-image/multi-arch.tar \
--cache-to type=local,dest=/tmp/docker-cache \
--cache-from type=gha \
./main-repo
# Use skopeo to convert the amd64 image from OCI format to Docker format and load it
skopeo copy --override-arch amd64 oci-archive:/tmp/oci-image/multi-arch.tar docker-daemon:${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:local
# check image
docker image ls | grep openim
- name: Checkout compose repository - name: Checkout compose repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -90,19 +55,18 @@ jobs:
run: | run: |
IP=$(hostname -I | awk '{print $1}') IP=$(hostname -I | awk '{print $1}')
echo "The IP Address is: $IP" echo "The IP Address is: $IP"
echo "ip=$IP" >> $GITHUB_OUTPUT echo "::set-output name=ip::$IP"
- name: Update .env to use the local image - name: Update .env to use the local image
run: | run: |
sed -i 's|OPENIM_SERVER_IMAGE=.*|OPENIM_SERVER_IMAGE=${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:local|' ${{ github.workspace }}/compose-repo/.env sed -i 's|OPENIM_SERVER_IMAGE=.*|OPENIM_SERVER_IMAGE=openim/openim-server:local|' ${{ github.workspace }}/compose-repo/.env
sed -i 's|MINIO_EXTERNAL_ADDRESS=.*|MINIO_EXTERNAL_ADDRESS=http://${{ steps.get-ip.outputs.ip }}:10005|' ${{ github.workspace }}/compose-repo/.env sed -i 's|MINIO_EXTERNAL_ADDRESS=.*|MINIO_EXTERNAL_ADDRESS=http://${{ steps.get-ip.outputs.ip }}:10005|' ${{ github.workspace }}/compose-repo/.env
- name: Start services using Docker Compose - name: Start services using Docker Compose
run: | run: |
cd ${{ github.workspace }}/compose-repo cd ${{ github.workspace }}/compose-repo
docker compose up -d docker compose up -d
sleep 60
docker compose ps
# - name: Check openim-server health # - name: Check openim-server health
# run: | # run: |
@@ -133,62 +97,54 @@ jobs:
# exit 0 # exit 0
# fi # fi
- name: Load Docker image from file
run: docker load -i image.tar
- name: Extract metadata for Docker (tags, labels)
id: meta
uses: docker/metadata-action@v5.5.1
with:
images: |
openim/openim-server
ghcr.io/openimsdk/openim-server
registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-server
tags: |
type=ref,event=tag
type=schedule
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=semver,pattern=release-{{raw}}
type=sha
type=raw,value=${{ github.event.inputs.tag }}
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@v3.3.0 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to GitHub Container Registry - name: Log in to GitHub Container Registry
uses: docker/login-action@v3.3.0 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Aliyun Container Registry - name: Log in to Aliyun Container Registry
uses: docker/login-action@v3.3.0 uses: docker/login-action@v2
with: with:
registry: registry.cn-hangzhou.aliyuncs.com registry: registry.cn-hangzhou.aliyuncs.com
username: ${{ secrets.ALIREGISTRY_USERNAME }} username: ${{ secrets.ALIREGISTRY_USERNAME }}
password: ${{ secrets.ALIREGISTRY_TOKEN }} password: ${{ secrets.ALIREGISTRY_TOKEN }}
- name: Push multi-architecture images - name: Push Docker images
if: success() uses: docker/build-push-action@v5
run: | with:
docker buildx build \ context: ./main-repo
--platform linux/amd64,linux/arm64 \ push: true
$(echo "${{ steps.meta.outputs.tags }}" | sed 's/,/ --tag /g' | sed 's/^/--tag /') \ platforms: linux/amd64,linux/arm64
--cache-from type=local,src=/tmp/docker-cache \ tags: ${{ steps.meta.outputs.tags }}
--push \ labels: ${{ steps.meta.outputs.labels }}
./main-repo
- name: Verify multi-platform support
run: |
images=(
"${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}"
"ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}"
"registry.cn-hangzhou.aliyuncs.com/openimsdk/${{ env.IMAGE_NAME }}"
)
for image in "${images[@]}"; do
for tag in $(echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n' | cut -d':' -f2); do
echo "Verifying multi-arch support for $image:$tag"
manifest=$(docker manifest inspect "$image:$tag" || echo "error")
if [[ "$manifest" == "error" ]]; then
echo "Manifest not found for $image:$tag"
exit 1
fi
amd64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "amd64")')
arm64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "arm64")')
if [[ -z "$amd64_found" ]]; then
echo "Multi-platform support check failed for $image:$tag - missing amd64"
exit 1
fi
if [[ -z "$arm64_found" ]]; then
echo "Multi-platform support check failed for $image:$tag - missing arm64"
exit 1
fi
echo "✅ $image:$tag supports both amd64 and arm64 architectures"
done
done
+1 -6
View File
@@ -63,12 +63,7 @@ services:
restart: always restart: always
sysctls: sysctls:
net.core.somaxconn: 1024 net.core.somaxconn: 1024
command: > command: redis-server /usr/local/redis/config/redis.conf --requirepass openIM123 --appendonly yes
redis-server
--requirepass openIM123
--appendonly yes
--aof-use-rdb-preamble yes
--save ""
networks: networks:
- openim - openim
-1
View File
@@ -244,7 +244,6 @@ func (s *Server) MultiTerminalLoginCheck(ctx context.Context, req *msggateway.Mu
tempUserCtx.SetOperationID(mcontext.GetOperationID(ctx)) tempUserCtx.SetOperationID(mcontext.GetOperationID(ctx))
client := &Client{} client := &Client{}
client.ctx = tempUserCtx client.ctx = tempUserCtx
client.token = req.Token
client.UserID = req.UserID client.UserID = req.UserID
client.PlatformID = int(req.PlatformID) client.PlatformID = int(req.PlatformID)
i := &kickHandler{ i := &kickHandler{
+3 -38
View File
@@ -337,51 +337,17 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
} }
} }
// If reconnect: When multiple msgGateway instances are deployed, a client may disconnect from instance A and reconnect to instance B.
// During this process, instance A might still be executing, resulting in two clients with the same token existing simultaneously.
// This situation needs to be filtered to prevent duplicate clients.
checkSameTokenFunc := func(oldClients []*Client) []*Client {
var clientsNeedToKick []*Client
for _, c := range oldClients {
if c.token == newClient.token {
log.ZDebug(newClient.ctx, "token is same, not kick",
"userID", newClient.UserID,
"platformID", newClient.PlatformID,
"token", newClient.token)
continue
}
clientsNeedToKick = append(clientsNeedToKick, c)
}
return clientsNeedToKick
}
switch ws.msgGatewayConfig.Share.MultiLogin.Policy { switch ws.msgGatewayConfig.Share.MultiLogin.Policy {
case constant.DefalutNotKick: case constant.DefalutNotKick:
case constant.PCAndOther: case constant.PCAndOther:
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC { if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
return return
} }
clients, ok := ws.clients.GetAll(newClient.UserID)
clientOK = ok
oldClients = make([]*Client, 0, len(clients))
for _, c := range clients {
if constant.PlatformIDToClass(c.PlatformID) == constant.TerminalPC {
continue
}
oldClients = append(oldClients, c)
}
fallthrough fallthrough
case constant.AllLoginButSameTermKick: case constant.AllLoginButSameTermKick:
if !clientOK { if !clientOK {
return return
} }
oldClients = checkSameTokenFunc(oldClients)
ws.clients.DeleteClients(newClient.UserID, oldClients) ws.clients.DeleteClients(newClient.UserID, oldClients)
for _, c := range oldClients { for _, c := range oldClients {
err := c.KickOnlineMessage() err := c.KickOnlineMessage()
@@ -407,15 +373,14 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
if !ok { if !ok {
return return
} }
var (
var kickClients []*Client kickClients []*Client
)
for _, client := range clients { for _, client := range clients {
if constant.PlatformIDToClass(client.PlatformID) == constant.PlatformIDToClass(newClient.PlatformID) { if constant.PlatformIDToClass(client.PlatformID) == constant.PlatformIDToClass(newClient.PlatformID) {
kickClients = append(kickClients, client) kickClients = append(kickClients, client)
} }
} }
kickClients = checkSameTokenFunc(kickClients)
kickTokenFunc(kickClients) kickTokenFunc(kickClients)
} }
} }
+2 -9
View File
@@ -675,19 +675,12 @@ func (db *commonMsgDatabase) SearchMessage(ctx context.Context, req *pbmsg.Searc
func (db *commonMsgDatabase) FindOneByDocIDs(ctx context.Context, conversationIDs []string, seqs map[string]int64) (map[string]*sdkws.MsgData, error) { func (db *commonMsgDatabase) FindOneByDocIDs(ctx context.Context, conversationIDs []string, seqs map[string]int64) (map[string]*sdkws.MsgData, error) {
totalMsgs := make(map[string]*sdkws.MsgData) totalMsgs := make(map[string]*sdkws.MsgData)
for _, conversationID := range conversationIDs { for _, conversationID := range conversationIDs {
seq, ok := seqs[conversationID] seq := seqs[conversationID]
if !ok {
log.ZWarn(ctx, "seq not found for conversationID", errs.New("seq not found for conversation"), "conversationID", conversationID)
continue
}
docID := db.msgTable.GetDocID(conversationID, seq) docID := db.msgTable.GetDocID(conversationID, seq)
msgs, err := db.msgDocDatabase.FindOneByDocID(ctx, docID) msgs, err := db.msgDocDatabase.FindOneByDocID(ctx, docID)
if err != nil { if err != nil {
log.ZWarn(ctx, "FindOneByDocID failed", err, "conversationID", conversationID, "docID", docID, "seq", seq) return nil, err
continue
} }
index := db.msgTable.GetMsgIndex(seq) index := db.msgTable.GetMsgIndex(seq)
totalMsgs[conversationID] = convert.MsgDB2Pb(msgs.Msg[index].Msg) totalMsgs[conversationID] = convert.MsgDB2Pb(msgs.Msg[index].Msg)
} }
+6 -7
View File
@@ -5,11 +5,6 @@ import (
"fmt" "fmt"
"time" "time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
"github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/constant"
@@ -19,6 +14,10 @@ import (
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/tools/utils/jsonutil" "github.com/openimsdk/tools/utils/jsonutil"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
) )
func NewMsgMongo(db *mongo.Database) (database.Msg, error) { func NewMsgMongo(db *mongo.Database) (database.Msg, error) {
@@ -1150,7 +1149,7 @@ func (m *MsgMgo) findBeforeDocSendTime(ctx context.Context, docID string, limit
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
for i := len(res) - 1; i >= 0; i-- { for i := len(res) - 1; i > 0; i-- {
v := res[i] v := res[i]
if v.Msgs != nil && v.Msgs.Msg != nil && v.Msgs.Msg.SendTime > 0 { if v.Msgs != nil && v.Msgs.Msg != nil && v.Msgs.Msg.SendTime > 0 {
return v.Msgs.Msg.Seq, v.Msgs.Msg.SendTime, nil return v.Msgs.Msg.Seq, v.Msgs.Msg.SendTime, nil
@@ -1165,7 +1164,7 @@ func (m *MsgMgo) findBeforeSendTime(ctx context.Context, conversationID string,
limit := int64(-1) limit := int64(-1)
if first { if first {
first = false first = false
limit = m.model.GetLimitForSingleDoc(seq) limit = m.model.GetMsgIndex(seq)
} }
docID := m.model.BuildDocIDByIndex(conversationID, i) docID := m.model.BuildDocIDByIndex(conversationID, i)
msgSeq, msgSendTime, err := m.findBeforeDocSendTime(ctx, docID, limit) msgSeq, msgSendTime, err := m.findBeforeDocSendTime(ctx, docID, limit)
+8 -8
View File
@@ -120,11 +120,15 @@ func (m *MsgDocModel) GetDocID(conversationID string, seq int64) string {
func (m *MsgDocModel) GetDocIDSeqsMap(conversationID string, seqs []int64) map[string][]int64 { func (m *MsgDocModel) GetDocIDSeqsMap(conversationID string, seqs []int64) map[string][]int64 {
t := make(map[string][]int64) t := make(map[string][]int64)
for _, seq := range seqs { for i := 0; i < len(seqs); i++ {
docID := m.GetDocID(conversationID, seq) docID := m.GetDocID(conversationID, seqs[i])
t[docID] = append(t[docID], seq) if value, ok := t[docID]; !ok {
var temp []int64
t[docID] = append(temp, seqs[i])
} else {
t[docID] = append(value, seqs[i])
}
} }
return t return t
} }
@@ -132,10 +136,6 @@ func (*MsgDocModel) GetMsgIndex(seq int64) int64 {
return (seq - 1) % singleGocMsgNum return (seq - 1) % singleGocMsgNum
} }
func (*MsgDocModel) GetLimitForSingleDoc(seq int64) int64 {
return seq % singleGocMsgNum
}
func (*MsgDocModel) indexGen(conversationID string, seqSuffix int64) string { func (*MsgDocModel) indexGen(conversationID string, seqSuffix int64) string {
return conversationID + ":" + strconv.FormatInt(seqSuffix, 10) return conversationID + ":" + strconv.FormatInt(seqSuffix, 10)
} }
+1 -1
View File
@@ -1 +1 @@
v3.8.3-patch.10 v3.8.3-patch.7