mirror of
https://github.com/openimsdk/open-im-server.git
synced 2025-10-27 22:12:15 +08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
e601b5fca1
2
.github/workflows/bot-auto-cherry-pick.yml
vendored
2
.github/workflows/bot-auto-cherry-pick.yml
vendored
@ -25,6 +25,7 @@ jobs:
|
||||
- name: Comment cherry-pick command
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
if (!pr.merged) {
|
||||
@ -64,4 +65,3 @@ jobs:
|
||||
issue_number: pr.number,
|
||||
body: cherryPickCmd
|
||||
});
|
||||
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
40
.github/workflows/bot-cherry-pick.yml
vendored
40
.github/workflows/bot-cherry-pick.yml
vendored
@ -12,23 +12,57 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: Github Rebot for Cherry Pick On Comment
|
||||
name: Github Robot for Cherry Pick On Comment
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
cherry-pick:
|
||||
name: Cherry Pick
|
||||
# && github.event.comment.user.login=='kubbot'
|
||||
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/cherry-pick')
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
|
||||
fetch-depth: 0 # To ensure all history is available for cherry-picking
|
||||
|
||||
- name: Automatic Cherry Pick
|
||||
uses: vendoo/gha-cherry-pick@v1
|
||||
with:
|
||||
# Assuming the cherry-pick commit SHA is passed in the comment like '/cherry-pick sha'
|
||||
commit-sha: ${{ github.event.comment.body }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
|
||||
- name: Create a new branch for PR
|
||||
run: |
|
||||
PR_BRANCH="cherry-pick-${GITHUB_SHA}-to-${{ github.base_ref }}"
|
||||
git checkout -b $PR_BRANCH
|
||||
git push origin $PR_BRANCH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
script: |
|
||||
const prTitle = "Cherry-pick to ${{ github.base_ref }}"
|
||||
const prBody = "Automated cherry-pick of ${{ github.event.comment.body }}\n\n/cc @kubbot"
|
||||
const base = "${{ github.base_ref }}"
|
||||
const head = "cherry-pick-${{ github.sha }}-to-${{ github.base_ref }}"
|
||||
const createPr = await github.rest.pulls.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: prTitle,
|
||||
body: prBody,
|
||||
head: head,
|
||||
base: base,
|
||||
maintainer_can_modify: true, // Allows maintainers to edit the PR
|
||||
})
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
27
.github/workflows/code-language-detector.yml
vendored
Normal file
27
.github/workflows/code-language-detector.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# 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.
|
||||
|
||||
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
|
||||
14
.github/workflows/e2e-test.yml
vendored
14
.github/workflows/e2e-test.yml
vendored
@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: OpenIM Linux System E2E Test
|
||||
name: OpenIM E2E And API Test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@ -82,7 +82,7 @@ jobs:
|
||||
sudo make tidy
|
||||
sudo make tools.verify.go-gitlint
|
||||
|
||||
- name: Build, Start
|
||||
- name: Build, Start(make build && make start)
|
||||
run: |
|
||||
sudo ./scripts/install/install.sh -i
|
||||
|
||||
@ -90,9 +90,8 @@ jobs:
|
||||
run: |
|
||||
sudo ./scripts/install/install.sh -s
|
||||
|
||||
- name: Exec OpenIM API test
|
||||
- name: Exec OpenIM API test (make test-api)
|
||||
run: |
|
||||
sudo make test-api
|
||||
mkdir -p ./tmp
|
||||
touch ./tmp/test.md
|
||||
echo "# OpenIM Test" >> ./tmp/test.md
|
||||
@ -103,9 +102,10 @@ jobs:
|
||||
echo "</code></pre>" >> ./tmp/test.md
|
||||
echo "</details>" >> ./tmp/test.md
|
||||
|
||||
- name: Exec OpenIM E2E Test
|
||||
sudo make test-api
|
||||
|
||||
- name: Exec OpenIM E2E Test (make test-e2e)
|
||||
run: |
|
||||
sudo make test-e2e
|
||||
echo "" >> ./tmp/test.md
|
||||
echo "## OpenIM E2E Test" >> ./tmp/test.md
|
||||
echo "<details><summary>Command Output for OpenIM E2E Test</summary>" >> ./tmp/test.md
|
||||
@ -114,6 +114,8 @@ jobs:
|
||||
echo "</code></pre>" >> ./tmp/test.md
|
||||
echo "</details>" >> ./tmp/test.md
|
||||
|
||||
sudo make test-e2e
|
||||
|
||||
- name: Comment PR with file
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
|
||||
6
.github/workflows/milestone.yml
vendored
6
.github/workflows/milestone.yml
vendored
@ -41,6 +41,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/github-script@v7 # v6
|
||||
with:
|
||||
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
script: |
|
||||
if (!context.payload.pull_request.merged) {
|
||||
console.log('PR was not merged, skipping.');
|
||||
@ -56,9 +57,10 @@ jobs:
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
sort: 'due_on',
|
||||
direction: 'asc'
|
||||
sort: 'title',
|
||||
direction: 'desc'
|
||||
})
|
||||
|
||||
if (milestones.data.length === 0) {
|
||||
console.log('There are no milestones, skipping.');
|
||||
return;
|
||||
|
||||
@ -745,7 +745,7 @@ linters:
|
||||
- misspell # Spelling mistakes
|
||||
- staticcheck # Static analysis
|
||||
- unused # Checks for unused code
|
||||
- goimports # Checks if imports are correctly sorted and formatted
|
||||
# - goimports # Checks if imports are correctly sorted and formatted
|
||||
- godot # Checks for comment punctuation
|
||||
- bodyclose # Ensures HTTP response body is closed
|
||||
- stylecheck # Style checker for Go code
|
||||
|
||||
@ -11,6 +11,7 @@ ENV GOPROXY=$GOPROXY
|
||||
# Set up the working directory
|
||||
WORKDIR /openim/openim-server
|
||||
|
||||
|
||||
# Copy all files to the container
|
||||
ADD . .
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ KAFKA_LATESTMSG_REDIS_TOPIC=${KAFKA_LATESTMSG_REDIS_TOPIC}
|
||||
# MINIO_PORT
|
||||
# ----------
|
||||
# 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'
|
||||
# under the MinIO configuration.
|
||||
#
|
||||
|
||||
@ -186,23 +186,6 @@ services:
|
||||
# server:
|
||||
# ipv4_address: ${OPENIM_SERVER_NETWORK_ADDRESS:-172.28.0.8}
|
||||
|
||||
### TODO: mysql is required to deploy the openim-chat component
|
||||
# mysql:
|
||||
# image: mysql:${MYSQL_IMAGE_VERSION:-5.7}
|
||||
# platform: linux/amd64
|
||||
# ports:
|
||||
# - "${MYSQL_PORT:-13306}:3306"
|
||||
# container_name: mysql
|
||||
# volumes:
|
||||
# - "${DATA_DIR:-./}/components/mysql/data:/var/lib/mysql"
|
||||
# - "/etc/localtime:/etc/localtime"
|
||||
# environment:
|
||||
# MYSQL_ROOT_PASSWORD: "${MYSQL_PASSWORD:-openIM123}"
|
||||
# restart: always
|
||||
# networks:
|
||||
# server:
|
||||
# ipv4_address: ${MYSQL_NETWORK_ADDRESS:-172.28.0.15}
|
||||
|
||||
# openim-chat:
|
||||
# image: ${IMAGE_REGISTRY:-ghcr.io/openimsdk}/openim-chat:${CHAT_IMAGE_VERSION:-main}
|
||||
# container_name: openim-chat
|
||||
|
||||
@ -96,7 +96,6 @@ We reinforce our approach to branch management and versioning with stringent tes
|
||||
|
||||
This document describes the maximum version skew supported between various openim components. Specific cluster deployment tools may place additional restrictions on version skew.
|
||||
|
||||
|
||||
### Supported version skew
|
||||
|
||||
In highly-available (HA) clusters, the newest and oldest `openim-api` instances must be within one minor version.
|
||||
@ -210,6 +209,7 @@ git merge release-v3.1
|
||||
# Push the updates to the main branch
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Release Process
|
||||
|
||||
```
|
||||
@ -232,5 +232,7 @@ For more details on managing Docker image versions, visit [OpenIM Docker Images
|
||||
|
||||
More on multi-branch version management design and version management design at helm charts:
|
||||
|
||||
+ https://github.com/openimsdk/open-im-server/issues/1695
|
||||
+ https://github.com/openimsdk/open-im-server/issues/1662
|
||||
About Helm's version management strategy for Multiple Apps and multiple Services:
|
||||
|
||||
+ [中文版本管理文档](https://github.com/openimsdk/helm-charts/blob/main/docs/contrib/version-zh.md)
|
||||
+ [English version management documents](https://github.com/openimsdk/helm-charts/blob/main/docs/contrib/version.md)
|
||||
|
||||
1
go.work
1
go.work
@ -3,7 +3,6 @@ go 1.19
|
||||
use (
|
||||
.
|
||||
./test/typecheck
|
||||
./tools/codescan
|
||||
./tools/changelog
|
||||
./tools/component
|
||||
./tools/formitychecker
|
||||
|
||||
@ -215,25 +215,22 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
|
||||
// Set the receiver ID in the message data.
|
||||
sendMsgReq.MsgData.RecvID = req.RecvID
|
||||
|
||||
// Declare a variable to store the message sending status.
|
||||
var status int
|
||||
|
||||
// Attempt to send the message using the client.
|
||||
respPb, err := m.Client.SendMsg(c, sendMsgReq)
|
||||
if err != nil {
|
||||
// Set the status to failed and respond with an error if sending fails.
|
||||
status = constant.MsgSendFailed
|
||||
apiresp.GinError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the status to successful if the message is sent.
|
||||
status = constant.MsgSendSuccessed
|
||||
var status int = constant.MsgSendSuccessed
|
||||
|
||||
// Attempt to update the message sending status in the system.
|
||||
_, err = m.Client.SetSendMsgStatus(c, &msg.SetSendMsgStatusReq{
|
||||
Status: int32(status),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// Log the error if updating the status fails.
|
||||
apiresp.GinError(c, err)
|
||||
|
||||
@ -141,7 +141,6 @@ func (c *UserConnContext) GetBackground() bool {
|
||||
b, err := strconv.ParseBool(c.Req.URL.Query().Get(BackgroundStatus))
|
||||
if err != nil {
|
||||
return false
|
||||
} else {
|
||||
}
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
)
|
||||
|
||||
type UserMap struct {
|
||||
@ -71,48 +70,65 @@ func (u *UserMap) Set(key string, v *Client) {
|
||||
}
|
||||
|
||||
func (u *UserMap) delete(key string, connRemoteAddr string) (isDeleteUser bool) {
|
||||
// Attempt to load the clients associated with the key.
|
||||
allClients, existed := u.m.Load(key)
|
||||
if existed {
|
||||
oldClients := allClients.([]*Client)
|
||||
var a []*Client
|
||||
for _, client := range oldClients {
|
||||
if client.ctx.GetRemoteAddr() != connRemoteAddr {
|
||||
a = append(a, client)
|
||||
}
|
||||
}
|
||||
if len(a) == 0 {
|
||||
u.m.Delete(key)
|
||||
return true
|
||||
} else {
|
||||
u.m.Store(key, a)
|
||||
if !existed {
|
||||
// Return false immediately if the key does not exist.
|
||||
return false
|
||||
}
|
||||
}
|
||||
return existed
|
||||
}
|
||||
|
||||
func (u *UserMap) deleteClients(key string, clients []*Client) (isDeleteUser bool) {
|
||||
m := utils.SliceToMapAny(clients, func(c *Client) (string, struct{}) {
|
||||
return c.ctx.GetRemoteAddr(), struct{}{}
|
||||
})
|
||||
allClients, existed := u.m.Load(key)
|
||||
if existed {
|
||||
// Convert allClients to a slice of *Client.
|
||||
oldClients := allClients.([]*Client)
|
||||
var a []*Client
|
||||
var remainingClients []*Client
|
||||
for _, client := range oldClients {
|
||||
if _, ok := m[client.ctx.GetRemoteAddr()]; !ok {
|
||||
a = append(a, client)
|
||||
// Keep clients that do not match the connRemoteAddr.
|
||||
if client.ctx.GetRemoteAddr() != connRemoteAddr {
|
||||
remainingClients = append(remainingClients, client)
|
||||
}
|
||||
}
|
||||
if len(a) == 0 {
|
||||
|
||||
// If no clients remain after filtering, delete the key from the map.
|
||||
if len(remainingClients) == 0 {
|
||||
u.m.Delete(key)
|
||||
return true
|
||||
} else {
|
||||
u.m.Store(key, a)
|
||||
}
|
||||
|
||||
// Otherwise, update the key with the remaining clients.
|
||||
u.m.Store(key, remainingClients)
|
||||
return false
|
||||
}
|
||||
|
||||
func (u *UserMap) deleteClients(key string, clientsToDelete []*Client) (isDeleteUser bool) {
|
||||
// Convert the slice of clients to delete into a map for efficient lookup.
|
||||
deleteMap := make(map[string]struct{})
|
||||
for _, client := range clientsToDelete {
|
||||
deleteMap[client.ctx.GetRemoteAddr()] = struct{}{}
|
||||
}
|
||||
return existed
|
||||
|
||||
// Load the current clients associated with the key.
|
||||
allClients, existed := u.m.Load(key)
|
||||
if !existed {
|
||||
// If the key doesn't exist, return false.
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter out clients that are in the deleteMap.
|
||||
oldClients := allClients.([]*Client)
|
||||
var remainingClients []*Client
|
||||
for _, client := range oldClients {
|
||||
if _, shouldBeDeleted := deleteMap[client.ctx.GetRemoteAddr()]; !shouldBeDeleted {
|
||||
remainingClients = append(remainingClients, client)
|
||||
}
|
||||
}
|
||||
|
||||
// Update or delete the key based on the remaining clients.
|
||||
if len(remainingClients) == 0 {
|
||||
u.m.Delete(key)
|
||||
return true
|
||||
}
|
||||
|
||||
u.m.Store(key, remainingClients)
|
||||
return false
|
||||
}
|
||||
|
||||
func (u *UserMap) DeleteAll(key string) {
|
||||
|
||||
@ -184,13 +184,12 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList(
|
||||
options2 := msgprocessor.Options(msg.Options)
|
||||
if options2.IsHistory() {
|
||||
return true
|
||||
} else {
|
||||
}
|
||||
// if !(!options2.IsSenderSync() && conversationID == msg.MsgData.SendID) {
|
||||
// return false
|
||||
// }
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, v := range totalMsgs {
|
||||
options := msgprocessor.Options(v.message.Options)
|
||||
if !options.IsNotNotification() {
|
||||
|
||||
@ -90,9 +90,8 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri
|
||||
for i, v := range s.GetSplitResult() {
|
||||
go func(index int, userIDs []string) {
|
||||
defer wg.Done()
|
||||
if err := g.batchPush(ctx, token, userIDs, pushReq); err != nil {
|
||||
if err = g.batchPush(ctx, token, userIDs, pushReq); err != nil {
|
||||
log.ZError(ctx, "batchPush failed", err, "index", index, "token", token, "req", pushReq)
|
||||
err = err
|
||||
}
|
||||
}(i, v.Item)
|
||||
}
|
||||
|
||||
@ -90,9 +90,8 @@ func (r *pushServer) PushMsg(ctx context.Context, pbData *pbpush.PushMsgReq) (re
|
||||
if err != nil {
|
||||
if err != errNoOfflinePusher {
|
||||
return nil, err
|
||||
} else {
|
||||
log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String())
|
||||
}
|
||||
log.ZWarn(ctx, "offline push failed", err, "msg", pbData.String())
|
||||
}
|
||||
return &pbpush.PushMsgResp{}, nil
|
||||
}
|
||||
|
||||
@ -26,7 +26,6 @@ func GetContent(msg *sdkws.MsgData) string {
|
||||
_ = proto.Unmarshal(msg.Content, &tips)
|
||||
content := tips.JsonDetail
|
||||
return content
|
||||
} else {
|
||||
}
|
||||
return string(msg.Content)
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,9 +79,14 @@ func (s *friendServer) AddBlack(ctx context.Context, req *pbfriend.AddBlackReq)
|
||||
CreateTime: time.Now(),
|
||||
Ex: req.Ex,
|
||||
}
|
||||
|
||||
if err := s.blackDatabase.Create(ctx, []*relation.BlackModel{&black}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.notificationSender.BlackAddedNotification(ctx, req)
|
||||
|
||||
if err := s.notificationSender.BlackAddedNotification(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pbfriend.AddBlackResp{}, nil
|
||||
}
|
||||
|
||||
@ -114,26 +114,36 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
|
||||
if err := authverify.CheckAccessV3(ctx, req.FromUserID, s.config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.ToUserID == req.FromUserID {
|
||||
return nil, errs.ErrCanNotAddYourself.Wrap("req.ToUserID", req.ToUserID)
|
||||
}
|
||||
|
||||
if err = CallbackBeforeAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
in1, in2, err := s.friendDatabase.CheckIn(ctx, req.FromUserID, req.ToUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if in1 && in2 {
|
||||
return nil, errs.ErrRelationshipAlready.Wrap()
|
||||
}
|
||||
|
||||
if err = s.friendDatabase.AddFriendRequest(ctx, req.FromUserID, req.ToUserID, req.ReqMsg, req.Ex); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.notificationSender.FriendApplicationAddNotification(ctx, req)
|
||||
|
||||
if err = s.notificationSender.FriendApplicationAddNotification(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = CallbackAfterAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
|
||||
return nil, err
|
||||
}
|
||||
@ -197,7 +207,9 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.notificationSender.FriendApplicationAgreedNotification(ctx, req)
|
||||
if err := s.notificationSender.FriendApplicationAgreedNotification(ctx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
if req.HandleResult == constant.FriendResponseRefuse {
|
||||
|
||||
@ -33,10 +33,7 @@ func (s *groupServer) GetGroupInfoCache(
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *groupServer) GetGroupMemberCache(
|
||||
ctx context.Context,
|
||||
req *pbgroup.GetGroupMemberCacheReq,
|
||||
) (resp *pbgroup.GetGroupMemberCacheResp, err error) {
|
||||
func (s *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (resp *pbgroup.GetGroupMemberCacheResp, err error) {
|
||||
members, err := s.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -637,6 +637,7 @@ func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbgroup.GetG
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetGroupApplicationList handles functions that get a list of group requests.
|
||||
func (s *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.GetGroupApplicationListReq) (*pbgroup.GetGroupApplicationListResp, error) {
|
||||
groupIDs, err := s.db.FindUserManagedGroupID(ctx, req.FromUserID)
|
||||
if err != nil {
|
||||
@ -951,6 +952,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
|
||||
return nil, errs.Wrap(errs.ErrDismissedAlready)
|
||||
}
|
||||
resp := &pbgroup.SetGroupInfoResp{}
|
||||
|
||||
count, err := s.db.FindGroupMemberNum(ctx, group.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1077,6 +1079,7 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq)
|
||||
total, group, err = s.db.SearchGroup(ctx, req.GroupName, req.Pagination)
|
||||
resp.Total = uint32(total)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1084,10 +1087,12 @@ func (s *groupServer) GetGroups(ctx context.Context, req *pbgroup.GetGroupsReq)
|
||||
groupIDs := utils.Slice(group, func(e *relationtb.GroupModel) string {
|
||||
return e.GroupID
|
||||
})
|
||||
|
||||
ownerMembers, err := s.db.FindGroupsOwner(ctx, groupIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ownerMemberMap := utils.SliceToMap(ownerMembers, func(e *relationtb.GroupMemberModel) string {
|
||||
return e.GroupID
|
||||
})
|
||||
|
||||
@ -156,27 +156,27 @@ func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, m
|
||||
return nil
|
||||
}
|
||||
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
|
||||
}
|
||||
req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand
|
||||
|
||||
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 nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
req.CallbackCommand = cbapi.CallbackSingleMsgRead
|
||||
|
||||
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 nil
|
||||
|
||||
@ -137,6 +137,7 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
||||
groupIDs = append(groupIDs, chatLog.GroupID)
|
||||
}
|
||||
}
|
||||
// Retrieve sender and receiver information
|
||||
if len(sendIDs) != 0 {
|
||||
sendInfos, err := m.UserLocalCache.GetUsersInfo(ctx, sendIDs)
|
||||
if err != nil {
|
||||
@ -155,6 +156,8 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
||||
recvMap[recvInfo.UserID] = recvInfo.Nickname
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve group information including member counts
|
||||
if len(groupIDs) != 0 {
|
||||
groupInfos, err := m.GroupLocalCache.GetGroupInfos(ctx, groupIDs)
|
||||
if err != nil {
|
||||
@ -162,8 +165,14 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
||||
}
|
||||
for _, groupInfo := range groupInfos {
|
||||
groupMap[groupInfo.GroupID] = groupInfo
|
||||
// Get actual member count
|
||||
memberIDs, err := m.GroupLocalCache.GetGroupMemberIDs(ctx, groupInfo.GroupID)
|
||||
if err == nil {
|
||||
groupInfo.MemberCount = uint32(len(memberIDs)) // Update the member count with actual number
|
||||
}
|
||||
}
|
||||
}
|
||||
// Construct response with updated information
|
||||
for _, chatLog := range chatLogs {
|
||||
pbchatLog := &msg.ChatLog{}
|
||||
utils.CopyStructFields(pbchatLog, chatLog)
|
||||
@ -175,14 +184,14 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
|
||||
switch chatLog.SessionType {
|
||||
case constant.SingleChatType, constant.NotificationChatType:
|
||||
pbchatLog.RecvNickname = recvMap[chatLog.RecvID]
|
||||
|
||||
case constant.GroupChatType, constant.SuperGroupChatType:
|
||||
pbchatLog.SenderFaceURL = groupMap[chatLog.GroupID].FaceURL
|
||||
pbchatLog.GroupMemberCount = groupMap[chatLog.GroupID].MemberCount
|
||||
pbchatLog.RecvID = groupMap[chatLog.GroupID].GroupID
|
||||
pbchatLog.GroupName = groupMap[chatLog.GroupID].GroupName
|
||||
pbchatLog.GroupOwner = groupMap[chatLog.GroupID].OwnerUserID
|
||||
pbchatLog.GroupType = groupMap[chatLog.GroupID].GroupType
|
||||
groupInfo := groupMap[chatLog.GroupID]
|
||||
pbchatLog.SenderFaceURL = groupInfo.FaceURL
|
||||
pbchatLog.GroupMemberCount = groupInfo.MemberCount // Reflects actual member count
|
||||
pbchatLog.RecvID = groupInfo.GroupID
|
||||
pbchatLog.GroupName = groupInfo.GroupName
|
||||
pbchatLog.GroupOwner = groupInfo.OwnerUserID
|
||||
pbchatLog.GroupType = groupInfo.GroupType
|
||||
}
|
||||
resp.ChatLogs = append(resp.ChatLogs, pbchatLog)
|
||||
}
|
||||
|
||||
@ -158,9 +158,6 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) {
|
||||
case constant.Custom:
|
||||
fallthrough
|
||||
case constant.Quote:
|
||||
utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, true)
|
||||
utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, true)
|
||||
utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, true)
|
||||
case constant.Revoke:
|
||||
utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false)
|
||||
utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false)
|
||||
|
||||
@ -60,6 +60,7 @@ func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error {
|
||||
}
|
||||
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx)))
|
||||
}
|
||||
|
||||
func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error {
|
||||
if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
|
||||
return nil
|
||||
|
||||
@ -16,9 +16,9 @@ package mgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/mgoutil"
|
||||
"github.com/OpenIMSDK/tools/pagination"
|
||||
@ -70,8 +70,12 @@ func (g *GroupMgo) Take(ctx context.Context, groupID string) (group *relation.Gr
|
||||
}
|
||||
|
||||
func (g *GroupMgo) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (total int64, groups []*relation.GroupModel, err error) {
|
||||
return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{"group_name": bson.M{"$regex": keyword},
|
||||
"status": bson.M{"$ne": constant.GroupStatusDismissed}}, pagination)
|
||||
opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}})
|
||||
|
||||
return mgoutil.FindPage[*relation.GroupModel](ctx, g.coll, bson.M{
|
||||
"group_name": bson.M{"$regex": keyword},
|
||||
"status": bson.M{"$ne": constant.GroupStatusDismissed},
|
||||
}, pagination, opts)
|
||||
}
|
||||
|
||||
func (g *GroupMgo) CountTotal(ctx context.Context, before *time.Time) (count int64, err error) {
|
||||
|
||||
@ -49,11 +49,7 @@ func NewGroupRpcClient(discov discoveryregistry.SvcDiscoveryRegistry, config *co
|
||||
return GroupRpcClient(*NewGroup(discov, config))
|
||||
}
|
||||
|
||||
func (g *GroupRpcClient) GetGroupInfos(
|
||||
ctx context.Context,
|
||||
groupIDs []string,
|
||||
complete bool,
|
||||
) ([]*sdkws.GroupInfo, error) {
|
||||
func (g *GroupRpcClient) GetGroupInfos(ctx context.Context, groupIDs []string, complete bool) ([]*sdkws.GroupInfo, error) {
|
||||
resp, err := g.Client.GetGroupsInfo(ctx, &group.GetGroupsInfoReq{
|
||||
GroupIDs: groupIDs,
|
||||
})
|
||||
@ -184,11 +180,7 @@ func (g *GroupRpcClient) GetGroupInfoCache(ctx context.Context, groupID string)
|
||||
return resp.GroupInfo, nil
|
||||
}
|
||||
|
||||
func (g *GroupRpcClient) GetGroupMemberCache(
|
||||
ctx context.Context,
|
||||
groupID string,
|
||||
groupMemberID string,
|
||||
) (*sdkws.GroupMemberFullInfo, error) {
|
||||
func (g *GroupRpcClient) GetGroupMemberCache(ctx context.Context, groupID string, groupMemberID string) (*sdkws.GroupMemberFullInfo, error) {
|
||||
resp, err := g.Client.GetGroupMemberCache(ctx, &group.GetGroupMemberCacheReq{
|
||||
GroupID: groupID,
|
||||
GroupMemberID: groupMemberID,
|
||||
|
||||
@ -126,10 +126,7 @@ func (f *FriendNotificationSender) UserInfoUpdatedNotification(ctx context.Conte
|
||||
return f.Notification(ctx, mcontext.GetOpUserID(ctx), changedUserID, constant.UserInfoUpdatedNotification, &tips)
|
||||
}
|
||||
|
||||
func (f *FriendNotificationSender) FriendApplicationAddNotification(
|
||||
ctx context.Context,
|
||||
req *pbfriend.ApplyToAddFriendReq,
|
||||
) error {
|
||||
func (f *FriendNotificationSender) FriendApplicationAddNotification(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error {
|
||||
tips := sdkws.FriendApplicationTips{FromToUserID: &sdkws.FromToUserID{
|
||||
FromUserID: req.FromUserID,
|
||||
ToUserID: req.ToUserID,
|
||||
|
||||
@ -932,7 +932,7 @@ openim::test::set_group_info() {
|
||||
{
|
||||
"groupInfoForSet": {
|
||||
"groupID": "${1}",
|
||||
"groupName": "new-name",
|
||||
"groupName": "new group name",
|
||||
"notification": "new notification",
|
||||
"introduction": "new introduction",
|
||||
"faceURL": "www.newfaceURL.com",
|
||||
@ -1076,6 +1076,7 @@ function openim::test::group() {
|
||||
|
||||
local GROUP_ID=$RANDOM
|
||||
local GROUP_ID2=$RANDOM
|
||||
|
||||
# Assumes that TEST_GROUP_ID, USER_ID, and other necessary IDs are set as environment variables before running this suite.
|
||||
# 0. Register a friend user.
|
||||
openim::test::user_register "${USER_ID}" "group00" "new_face_url"
|
||||
|
||||
@ -413,7 +413,7 @@ openim::util::check_process_names() {
|
||||
else
|
||||
# If there are PIDs, loop through each one
|
||||
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 port=$(get_port $pid)
|
||||
|
||||
@ -489,7 +489,7 @@ openim::util::check_process_names_for_stop() {
|
||||
else
|
||||
# If there are PIDs, loop through each one
|
||||
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 port=$(get_port $pid)
|
||||
|
||||
|
||||
@ -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}"
|
||||
@ -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,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
|
||||
Loading…
x
Reference in New Issue
Block a user