Compare commits

..

14 Commits

Author SHA1 Message Date
Xinwei Xiong(cubxxw-openim) 062aa5766e style: Formatting code make lint path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 20:16:36 +08:00
Xinwei Xiong(cubxxw-openim) 9cf3fcb1fc style: Formatting code make lint path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 20:06:06 +08:00
Xinwei Xiong(cubxxw-openim) 2e08746f3f style: Formatting code make lint path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 20:05:37 +08:00
Xinwei Xiong(cubxxw-openim) 08ccf7c318 style: Formatting code make lint path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 18:39:11 +08:00
Xinwei Xiong(cubxxw-openim) ca4bfde2aa feat: add scripts cross ower
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 15:40:16 +08:00
Xinwei Xiong(cubxxw-openim) bc8702749f ci: add go-docs file and copyright scripts
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 15:12:21 +08:00
Xinwei Xiong(cubxxw-openim) 9e14c92933 ci: add copyright scripts
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 15:07:23 +08:00
Xinwei Xiong(cubxxw-openim) 0a6f10a7cc feat: add lib and start scripts
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 14:53:36 +08:00
Xinwei Xiong(cubxxw-openim) bce5cdf746 feat: sync script code
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 12:17:24 +08:00
Xinwei Xiong(cubxxw-openim) 18728fc993 fix: fix scripts path module
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-09 11:40:06 +08:00
Xinwei Xiong(cubxxw-openim) be6f189365 fix: fix scripts and optimize
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-08 22:44:15 +08:00
Xinwei Xiong(cubxxw-openim) da1316af2a fix: fix golang release file path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-08 18:00:23 +08:00
Xinwei Xiong(cubxxw-openim) b759f8b5cc fix: fix golang release file path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-08 17:59:45 +08:00
Xinwei Xiong(cubxxw-openim) c1f6fc4e63 fix: fix bin tools path
Signed-off-by: Xinwei Xiong(cubxxw-openim) <3293172751nss@gmail.com>
2023-08-08 17:34:06 +08:00
155 changed files with 3425 additions and 1815 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ CHANGELOG/
# LICENSE
# Ignore testing and linting configuration
.golangci.yml
scripts/golangci.yml
# Ignore deployment-related files
docker-compose.yaml
+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
#
# Note: by default the `.golangci.yml` file should be at the root of the repository.
# The location of the configuration file can be changed by using `--config=`
# args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0
args: --timeout=30m --config=/scripts/golangci.yml # --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
+2 -1
View File
@@ -43,7 +43,8 @@ jobs:
# either 'goreleaser' (default) or 'goreleaser-pro':
distribution: goreleaser
version: latest
args: release --clean
workdir: .
args: release -f ./build/goreleaser.yaml --rm-dist --clean --release-footer-tmpl=scripts/template/footer.md.tmpl --release-header-tmpl=scripts/template/head.md.tmpl
env:
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro'
+2 -3
View File
@@ -10,8 +10,8 @@ ENV GOPROXY=$GOPROXY
# Set up the working directory
WORKDIR /openim/openim-server
COPY go.mod go.sum go.work go.work.sum ./
#RUN go mod download
COPY go.mod go.sum ./
RUN go mod download
# Copy all files to the container
ADD . .
@@ -27,6 +27,5 @@ WORKDIR ${SERVER_WORKDIR}
COPY --from=builder ${OPENIM_SERVER_CMDDIR} /openim/openim-server/scripts
COPY --from=builder ${SERVER_WORKDIR}/config /openim/openim-server/config
COPY --from=builder ${SERVER_WORKDIR}/_output/bin/platforms /openim/openim-server/_output/bin/platforms
COPY --from=builder ${SERVER_WORKDIR}/_output/bin-tools/platforms /openim/openim-server/_output/bin-tools/platforms
CMD ["bash","-c","${OPENIM_SERVER_CMDDIR}/docker_start_all.sh"]
+6 -1
View File
@@ -12,7 +12,7 @@ all: tidy gen add-copyright format lint cover build
# Build set
ROOT_PACKAGE=github.com/OpenIMSDK/Open-IM-Server
# TODO: This is version control for the future
# TODO: This is version control for the future https://github.com/OpenIMSDK/Open-IM-Server/issues/574
VERSION_PACKAGE=github.com/OpenIMSDK/Open-IM-Server/pkg/version
# ==============================================================================
@@ -191,6 +191,11 @@ advertise:
release: release.verify release.ensure-tag
@scripts/release.sh
## demo: Run demo ✨
.PHONY: demo
demo:
@$(MAKE) go.demo
## help: Show this help info. ✨
.PHONY: help
help: Makefile
+1 -50
View File
@@ -479,53 +479,4 @@ checksum:
algorithm: sha256
release:
prerelease: auto
footer: |
## Welcome to the {{ .Tag }} release of [chat](https://github.com/OpenIMSDK/chat)!🎉🎉!
**Full Changelog**: https://github.com/OpenIMSDK/Open-IM-Server/compare/{{ .PreviousTag }}...{{ .Tag }}
## Helping out
+ We release logs are recorded on [✨CHANGELOG](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/CHANGELOG/CHANGELOG.md)
+ For information on versions of OpenIM and how to maintain branches, read [📚this article](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/conversions/version.md)
+ If you wish to use mirroring, read OpenIM's [image management policy](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/conversions/images.md)
**Want to be one of them 😘?**
<p align="center">
<a href="https://github.com/kubbot" style="float: left; margin-right: 10px;">
<img src="https://github.com/openimbot/openimbot/blob/main/assets/icon/blue%E9%80%8F%E6%98%8E.png" width="50" height="50" />
</a>
<a href="https://www.openim.online">
<img src="https://github.com/OpenIMSDK/Open-IM-Server/blob/main/assets/logo/openim-logo.png" />
</a>
<a href="https://github.com/openimbot" style="float: right; margin-left: 10px;">
<img src="https://github.com/openimbot/openimbot/blob/main/assets/icon/red%E9%80%8F%E6%98%8E.png" width="50" height="50" />
</a>
</p>
> **Note**
> @openimbot and @kubbot have made great contributions to the community as community 🤖robots(@openimsdk/bot), respectively.
> Thanks to the @openimsdk/openim team for all their hard work on this release.
> Thank you to all the [💕developers and contributors](https://github.com/OpenIMSDK/Open-IM-Server/graphs/contributors), people from all over the world, OpenIM brings us together
> Contributions to this project are welcome! Please see [CONTRIBUTING.md](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/CONTRIBUTING.md) for details.
## Get Involved with OpenIM!
**Here are some ways to get involved with the OpenIM community:**
📢 **Slack Channel**: Join our Slack channels for discussions, communication, and support. Click [here](https://join.slack.com/t/openimsdk/shared_invite/zt-1tmoj26uf-_FDy3dowVHBiGvLk9e5Xkg) to join the Open-IM-Server Slack team channel.
📧 **Gmail Contact**: If you have any questions, suggestions, or feedback for our open-source projects, please feel free to [contact us via email](https://mail.google.com/mail/?view=cm&fs=1&tf=1&to=winxu81@gmail.com).
📖 **Blog**: Stay up-to-date with OpenIM-Server projects and trends by reading our [blog](https://doc.rentsoft.cn/). We share the latest developments, tech trends, and other interesting information related to OpenIM.
📱 **WeChat**: Add us on WeChat (QR Code) and indicate that you are a user or developer of Open-IM-Server. We'll process your request as soon as possible.
Remember, your contributions play a vital role in making OpenIM successful, and we look forward to your active participation in our community! 🙌
prerelease: auto
+1 -1
View File
@@ -21,7 +21,7 @@ import (
func main() {
cronTaskCmd := cmd.NewCronTaskCmd()
if err := cronTaskCmd.Exec(tools.StartTask); err != nil {
if err := cronTaskCmd.Exec(tools.StartCronTask); err != nil {
panic(err.Error())
}
}
+39 -43
View File
@@ -24,10 +24,10 @@
# Zookeeper username
# Zookeeper password
zookeeper:
schema: openim
address: [ 127.0.0.1:2181 ]
username:
password:
schema: openim
address: [ 127.0.0.1:2181 ]
username:
password:
###################### Mysql ######################
# MySQL configuration
@@ -42,12 +42,12 @@ mysql:
address: [ 127.0.0.1:13306 ]
username: root
password: openIM123
database: openIM_v3
maxOpenConn: 1000
maxIdleConn: 100
maxLifeTime: 60
logLevel: 4
slowThreshold: 500
database: openIM_v3
maxOpenConn: 1000
maxIdleConn: 100
maxLifeTime: 60
logLevel: 4
slowThreshold: 500
###################### Mongo ######################
# MongoDB configuration
@@ -62,7 +62,7 @@ mongo:
database: openIM_v3
username: root
password: openIM123
maxPoolSize: 100
maxPoolSize: 100
###################### Redis ######################
# Redis configuration
@@ -70,7 +70,7 @@ mongo:
# Username is required only for Redis version 6.0+
redis:
address: [ 127.0.0.1:16379 ]
username:
username:
password: openIM123
###################### Kafka ######################
@@ -81,13 +81,13 @@ redis:
# It's not recommended to modify this topic name
# Consumer group ID, it's not recommended to modify
kafka:
username:
password:
username:
password:
addr: [ 127.0.0.1:9092 ]
latestMsgToRedis:
topic: "latestMsgToRedis"
topic: "latestMsgToRedis"
offlineMsgToMongo:
topic: "offlineMsgToMongoMysql"
topic: "offlineMsgToMongoMysql"
msgToPush:
topic: "msgToPush"
consumerGroupID:
@@ -111,8 +111,8 @@ rpc:
# API service port
# Default listen IP is 0.0.0.0
api:
openImApiPort: [ 10002 ]
listenIP: 0.0.0.0
openImApiPort: [ 10002 ]
listenIP: 0.0.0.0
###################### Gateway ######################
# Object storage configuration
@@ -124,29 +124,25 @@ api:
# Session token
# Configuration for Tencent COS
# Configuration for Aliyun OSS
# apiURL is the address of the api, the access address of the app, use s3 must be configured
# minio.endpoint can be configured as an intranet address,
# minio.signEndpoint is minio public network address
object:
enable: "minio"
apiURL: "http://127.0.0.1:10002"
enable: "minio"
apiURL: http://127.0.0.1:10002/object/
minio:
bucket: "openim"
endpoint: "http://127.0.0.1:10005"
accessKeyID: "root"
secretAccessKey: "openIM123"
sessionToken: ""
signEndpoint: "http://127.0.0.1:10005"
cos:
bucket: "openim"
endpoint: http://127.0.0.1:10005
accessKeyID: root
secretAccessKey: openIM123
sessionToken: ""
cos:
bucketURL: "https://temp-1252357374.cos.ap-chengdu.myqcloud.com"
secretID: ""
secretKey: ""
sessionToken: ""
oss:
oss:
endpoint: "https://oss-cn-chengdu.aliyuncs.com"
bucket: "demo-9999999"
bucketURL: "https://demo-9999999.oss-cn-chengdu.aliyuncs.com"
accessKeyID: ""
accessKeyID: root
accessKeySecret: ""
sessionToken: ""
@@ -154,7 +150,7 @@ object:
# These ports are passed into the program by the script and are not recommended to modify
# For launching multiple programs, just fill in multiple ports separated by commas
# For example, [10110, 10111]
rpcPort:
rpcPort:
openImUserPort: [ 10110 ]
openImFriendPort: [ 10120 ]
openImMessagePort: [ 10130 ]
@@ -187,12 +183,12 @@ rpcRegisterName:
# Whether to output in json format
# Whether to include stack trace in logs
log:
storageLocation: ../../../../../logs/
rotationTime: 24
remainRotationCount: 2
remainLogLevel: 6
isStdout: false
isJson: false
storageLocation: ../../../../../logs/
rotationTime: 24
remainRotationCount: 2
remainLogLevel: 6
isStdout: false
isJson: false
withStack: false
# Long connection server configuration
@@ -202,10 +198,10 @@ log:
# Maximum length of websocket request package
# Websocket connection handshake timeout
longConnSvr:
openImWsPort: [ 10001 ]
websocketMaxConnNum: 100000
websocketMaxMsgLen: 4096
websocketTimeout: 10
openImWsPort: [ 10001 ]
websocketMaxConnNum: 100000
websocketMaxMsgLen: 4096
websocketTimeout: 10
# Push notification service configuration
#
+2 -5
View File
@@ -62,7 +62,6 @@ services:
environment:
TZ: Asia/Shanghai
restart: always
network_mode: "host"
kafka:
image: wurstmeister/kafka
@@ -73,7 +72,7 @@ services:
environment:
TZ: Asia/Shanghai
KAFKA_BROKER_ID: 0
KAFKA_ZOOKEEPER_CONNECT: 127.0.0.1:2181
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_CREATE_TOPICS: "latestMsgToRedis:8:1,msgToPush:8:1,offlineMsgToMongoMysql:8:1"
KAFKA_ADVERTISED_LISTENERS: INSIDE://127.0.0.1:9092,OUTSIDE://103.116.45.174:9092
KAFKA_LISTENERS: INSIDE://:9092,OUTSIDE://:9093
@@ -81,7 +80,6 @@ services:
KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
depends_on:
- zookeeper
network_mode: "host"
minio:
image: minio/minio
@@ -100,7 +98,6 @@ services:
openim-server:
image: ghcr.io/openimsdk/openim-server:latest
#build: .
container_name: openim-server
volumes:
- ./logs:/openim/openim-server/logs
@@ -150,7 +147,7 @@ services:
# ports:
# - 9091:9091
depends_on:
- openim-server
- openim-server
command: --web.listen-address=:9091 --config.file="/etc/prometheus/prometheus.yml"
network_mode: "host"
+1 -1
View File
@@ -77,7 +77,7 @@ logs/* @skiffer-git @FGadvancer
pkg/a2r @openimsdk/openim @skiffer-git @cubxxw @openimsdk/bot
# scripts directory
scripts/LICENSE/* @openimsdk/openim @cubxxw @skiffer-git @FGadvancer
scripts/template/* @openimsdk/openim @cubxxw @skiffer-git @FGadvancer
scripts/enterprise/* @openimsdk/openim @FGadvancer @cubxxw @skiffer-git @openimsdk/bot
scripts/githooks/* @openimsdk/openim @cubxxw @skiffer-git @FGadvancer
scripts/lib/* @openimsdk/openim @FGadvancer @cubxxw @skiffer-git @openimsdk/bot
+43 -54
View File
@@ -1,88 +1,76 @@
# OpenIM Branch Management and Versioning: A Blueprint for High-Grade Software Development
# OpenIM Branch Management and Versioning
[📚 **OpenIM TOC**](#openim-branch-management-and-versioning-a-blueprint-for-high-grade-software-development)
- [Unfolding the Mechanism of OpenIM Version Maintenance](#unfolding-the-mechanism-of-openim-version-maintenance)
- [Main Branch: The Heart of OpenIM Development](#main-branch-the-heart-of-openim-development)
- [Release Branch: The Beacon of Stability](#release-branch-the-beacon-of-stability)
- [Tag Management: The Cornerstone of Version Control](#tag-management-the-cornerstone-of-version-control)
- [Release Management: A Guided Tour](#release-management-a-guided-tour)
- [Milestones, Branching, and Addressing Major Bugs](#milestones-branching-and-addressing-major-bugs)
- [Applying Principles: A Git Workflow Example](#applying-principles-a-git-workflow-example)
- [Docker Images Version Management](#docker-images-version-management)
Our project, OpenIM, follows the [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/) standards.
OpenIM, the open source project, employs a comprehensive version management system to ensure the reliability and traceability of our software. Our version management consists of three main components: the `main` branch, the `release` branch, and `tag` management.
At OpenIM, we acknowledge the profound impact of implementing a robust and efficient version management system, hence we abide by the established standards of [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/).
## Main Branch
Our software blueprint orchestrates a tripartite version management system that integrates the `main` branch, the `release` branch, and `tag` management. These constituents operate in synchrony to preserve the reliability and traceability of our software across various stages of development.
The `main` branch is where all the latest code resides. It's the hub of activity, embodying all the cutting-edge features that are currently being developed or updated. However, since it's subject to frequent changes and updates, it may not always represent the most stable version of the software. Access the `main` branch [here](https://github.com/OpenIMSDK/Open-IM-Server/tree/main).
## Unfolding the Mechanism of OpenIM Version Maintenance
## Release Branch
Our version maintenance protocol revolves around two primary branches, namely: `main` and `release`. We resort to Semantic Versioning 2.0.0 for marking distinctive versions of our software, representing substantial milestones in its evolution.
On the other hand, we have the `release` branch. For instance, in the context of version 3.1, we maintain a `release-v3.1` branch. Unlike the `main` branch, the release branch is designed to be a continuously stable and updated version of the software. This provides a reliable option for users who prefer stability over the latest, but potentially unstable, features. Access the `release-v3.1` branch [here](https://github.com/OpenIMSDK/Open-IM-Server/tree/release-v3.1).
In the OpenIM repository, version identification strictly complies with the `MAJOR.MINOR.PATCH` protocol. Herein:
## Tag Management
- The `MAJOR` version indicates a shift arising from incompatible changes to the API.
- The `MINOR` version suggests the addition of features in a backward-compatible manner.
- The `PATCH` version flags backward-compatible bug fixes.
In addition to the `main` and `release` branches, `tag` also plays a pivotal role in version control. Tags are immutable, meaning once they're created, they remain unchanged. Therefore, if you need a specific version of the software, you can use the corresponding tag. All of our available tags can be viewed [here](https://github.com/OpenIMSDK/Open-IM-Server/tags).
## Main Branch: The Heart of OpenIM Development
Moreover, our Docker image versions are closely tied with these three components. For example, a tag might correspond to the Docker image `ghcr.io/openimsdk/openim-server:v3.1.0`, a release might be represented as `ghcr.io/openimsdk/openim-server:release-v3.0`, and the main branch could be represented as `ghcr.io/openimsdk/openim-server:main` or `ghcr.io/openimsdk/openim-server:latest`.
The `main` branch is the operational heart of our development process. Housing the most recent and advanced features, this branch serves as the nerve center for all enhancements and updates. It encapsulates the freshest, though possibly unstable, facets of the software. Visit our `main` branch [here](https://github.com/OpenIMSDK/Open-IM-Server/tree/main).
Here is the specification of our version numbers:
## Release Branch: The Beacon of Stability
- **Revision version number**: The third digit of the version number, representing bug fixes or code optimizations, usually no new features are added and it is backward compatible with older versions.
For every major release, we curate a corresponding `release` branch, e.g., `release-v3.1`. This branch symbolizes an embodiment of stability and ensures an updated version of the software, providing a dependable option for users favoring stability over nascent, yet possibly unstable, features. Visit the `release-v3.1` branch [here](https://github.com/OpenIMSDK/Open-IM-Server/tree/release-v3.1).
- **Build version number**: Usually automatically generated by the system, every code submission will result in an automatic increment by 1.
## Tag Management: The Cornerstone of Version Control
- Version modifiers
In OpenIM's version control system, the role of `tags` stands paramount. Owing to their immutable nature, tags can be effectively utilized to retrieve a specific version of the software. Explore our library of tags [here](https://github.com/OpenIMSDK/Open-IM-Server/tags).
: These can represent the development stage and stability of the software. Common ones include:
Our Docker image versions are intimately entwined with these tripartite components. For instance, a Docker image tag may correspond to `ghcr.io/openimsdk/openim-server:v3.1.0`, a release to `ghcr.io/openimsdk/openim-server:release-v3.0`, and the main branch to `ghcr.io/openimsdk/openim-server:main` or `ghcr.io/openimsdk/openim-server:latest`.
To further clarify, the semantics of our version numbers are as follows:
- **Revision version number**: This represents bug fixes or code optimizations. Typically, it entails no new feature additions and ensures backward compatibility.
- **Build version number**: Auto-generated by the system, each code submission prompts an automatic increment by 1.
- **Version modifiers**: These hint at the software's development stage and stability. Some commonly used modifiers are `alpha`, `beta`, `rc`, `ga`, `r/release/or nothing`, and `lts`.
- `alpha`: An internal testing version with numerous bugs, typically used for communication among developers.
- `beta`: A test version with numerous bugs, generally used for testing by eager community members, who provide feedback to the developers.
- `rc`: Release candidate, which is to be released as the official version. It's the last test version before the official version.
- `alpha`: An internal testing version with many bugs, generally used for communication among developers.
- `beta`: A test version with many bugs, generally used for testing by eager community members, who provide feedback to the developers.
- `rc`: Release candidate, to be released as the official version, it's the last test version before the official version.
- `ga`: General Availability, the first stable release.
- `r/release/or nothing`: The final release version, intended for general users.
- `lts`: Long Term Support, the official will specify the maintenance year for this version and will fix all bugs discovered in this version.
- `lts`: Long Term Support, the official will specify the maintenance year for this version and will fix all bugs found in this version.
Whenever a project undergoes a partial functional addition, the minor version number increments by 1, resetting the revision version number to 0. In contrast, any major project overhaul results in an increment by 1 in the major version number. The build number, typically auto-generated during the compilation process, only requires format definition, thereby eliminating manual control.
When adding partial functions to the project, the minor version number increases by 1, and the revision version number resets to 0. When there are major changes in the project, the major version number increases by 1. The build number is generally automatically generated by the compiler during the compilation process, only the format needs to be defined, and it does not need to be manually controlled.
## Release Management: A Guided Tour
## OpenIM version
Our GitHub repository at https://github.com/OpenIMSDK/Open-IM-Server/releases associates a release with each tag, with a distinction between Pre-release and Latest, determined by the branch source. Every significant feature launch prompts the issue of a `release` branch, such as `release-v3.2`, as a beacon of stability and Latest release.
OpenIM manages two primary branches: `main` and `release`. The project uses Semantic Versioning 2.0.0 to tag different versions of the software, each indicating a significant milestone in the software's development.
Pre-releases correspond to releases from the `main` branch, denoting tags with Version modifiers such as `v3.2.1-beta.0`, `v3.2.1-rc.1`, etc. If you are seeking the most recent, albeit possibly unstable, release with new features, these tags, originating from the latest `main` branch code, are your go-to.
In the OpenIM repository, the versioning adheres to the `MAJOR.MINOR.PATCH` format, where:
Conversely, if stability is your primary concern, you should opt for the release tagged Latest, denoted by tags without Version modifiers, such as `v3.2.1`, `v3.2.2` etc. These tags are linked to the latest stable maintenance branch, like `release-v3.2`.
- `MAJOR` version changes when there are incompatible changes to the API,
- `MINOR` version changes when features are added in a backward-compatible manner, and
- `PATCH` version changes when backward-compatible bugs are fixed.
## Milestones, Branching, and Addressing Major Bugs
**About:**
## Milestones and Branching
+ [OpenIM Milestones](https://github.com/OpenIMSDK/Open-IM-Server/milestones)
+ [OpenIM Tags](https://github.com/OpenIMSDK/Open-IM-Server/tags)
+ [OpenIM Branches](https://github.com/OpenIMSDK/Open-IM-Server/branches)
We create a new branch, such as `release-v3.1`, for each significant milestone (e.g., v3.1.0), housing all relevant code for that release. All enhancements and bug fixes targeting the subsequent version (e.g., v3.2.0) are integrated into this branch.
When a significant milestone like v3.1.0 is achieved, a new branch `release-v3.1` is created. This branch contains all the code pertaining to this stable release. All bug fixes and features intended for the next version, v3.2.0, are merged into this branch.
`PATCH` versions (represented by Z in `X.Y.Z`) are primarily propelled by bug fixes, and their release may be either priority-driven or scheduled. In contrast, `MINOR` versions (represented by Y in `X.Y.Z`) are contingent upon the project's roadmap, milestone completion, or a pre-established timeline, always maintaining backward-compatible APIs.
The release of `PATCH` versions (Z in `X.Y.Z`) are driven by bug fixes, and these can be rolled out depending on the bug's priority or over a scheduled time. On the other hand, `MINOR` versions (Y in `X.Y.Z`) are released based on the project's roadmap, milestone completion, or on a scheduled timeline. Importantly, the API of minor versions is always backward-compatible.
When dealing with major bugs, we selectively merge the fix into the affected version (e.g., v3.1 or the `release-v3.1` branch), as well as the `main` branch. This dual pronged strategy ensures that users on older versions receive crucial bug fixes, while also keeping the `main` branch updated.
## Dealing with Major Bugs
We reinforce our approach to branch management and versioning with stringent testing protocols. Automated tests and code review sessions form vital components of maintaining a robust and reliable codebase.
In the event of a major bug discovery, the fix would selectively be merged into the previous version (e.g., v3.1 or the `release-v3.1` branch), as well as into the `main` branch. This is to ensure that users relying on the older version can still receive important bug fixes, while also keeping the main branch updated.
## Applying Principles: A Git Workflow Example
It's worth noting that a robust testing regime should be in place to ensure the integrity of all branches at any given time. Automated tests and code review sessions are crucial components of maintaining a healthy codebase.
The workflow to address a bug fix might follow these steps:
To summarize, OpenIM's approach to branch management and versioning ensures a balance between introducing new features, fixing bugs, and maintaining backward compatibility. This strategy is vital for managing user expectations, supporting older versions, and paving the way for the project's continuous growth.
```bash
bashCopy codebashCopy code# Checkout the branch for the version that needs the bug fix
## Git Workflow Example
To put the above principles into practice, here's a Git workflow example that you might follow when working on a bug fix:
```
bashCopy code# Checkout the branch for the version that needs the bug fix
git checkout release-v3.1
# Create a new branch for the bug fix
@@ -105,8 +93,9 @@ git merge release-v3.1
git push origin main
```
Throughout this process, active communication within the team is pivotal to maintaining transparency and consensus on changes.
Remember, communication with your team is key throughout this process, keeping everyone up-to-date with the changes being made.
## Docker Images Version Management
For more details on managing Docker image versions, visit [OpenIM Docker Images Administration](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/conversions/images.md).
## Docker images version management
+ [OpenIM Docker Images Administration](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/conversions/images.md)
+14 -14
View File
@@ -25,13 +25,13 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.8.4
go.mongodb.org/mongo-driver v1.12.1
golang.org/x/image v0.11.0
google.golang.org/api v0.136.0
golang.org/x/image v0.9.0 // indirect
google.golang.org/api v0.135.0
google.golang.org/grpc v1.57.0
google.golang.org/protobuf v1.31.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.1
gorm.io/gorm v1.25.3
gorm.io/gorm v1.25.2
)
require github.com/google/uuid v1.3.0
@@ -47,11 +47,11 @@ require (
)
require (
cloud.google.com/go v0.110.6 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go v0.110.4 // indirect
cloud.google.com/go/compute v1.20.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/firestore v1.11.0 // indirect
cloud.google.com/go/iam v1.1.1 // indirect
cloud.google.com/go/iam v1.1.0 // indirect
cloud.google.com/go/longrunning v0.5.1 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -117,17 +117,17 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/oauth2 v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect
)
require (
@@ -138,6 +138,6 @@ require (
github.com/spf13/cobra v1.7.0
github.com/ugorji/go/codec v1.2.11 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
+28 -28
View File
@@ -1,15 +1,15 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q=
cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk=
cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/firestore v1.11.0 h1:PPgtwcYUOXV2jFe1bV3nda3RCrOa8cvBjTOn2MQVfW8=
cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4=
cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y=
cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94=
cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
@@ -361,11 +361,11 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -394,12 +394,12 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -430,8 +430,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -442,8 +442,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -463,8 +463,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.136.0 h1:e/6enzUE1s4tGPa6Q3ZYShKTtvRc+1Jq0rrafhppmOs=
google.golang.org/api v0.136.0/go.mod h1:XtJfF+V2zgUxelOn5Zs3kECtluMxneJG8ZxUTlLNTPA=
google.golang.org/api v0.135.0 h1:6Vgfj6uPMXcyy66waYWBwmkeNB+9GmUlJDOzkukPQYQ=
google.golang.org/api v0.135.0/go.mod h1:Bp77uRFgwsSKI0BWH573F5Q6wSlznwI2NFayLOp/7mQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
@@ -473,12 +473,12 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44=
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y=
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU=
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e h1:S83+ibolgyZ0bqz7KEsUOPErxcv4VzlszxY+31OfB/E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@@ -523,8 +523,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.3 h1:zi4rHZj1anhZS2EuEODMhDisGy+Daq9jtPrNGgbQYD8=
gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+2 -1
View File
@@ -2,7 +2,8 @@ go 1.20
use (
.
./tools/component
./tools/changelog
./tools/infra
./tools/ncpu
./tools/yamlfmt
)
+4 -1
View File
@@ -1,6 +1,9 @@
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+1 -8
View File
@@ -83,14 +83,7 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
operationID = strconv.Itoa(rand.Int())
}
ctx := mcontext.SetOperationID(c, operationID)
query := make(map[string]string)
for key, values := range c.Request.URL.Query() {
if len(values) == 0 {
continue
}
query[key] = values[0]
}
resp, err := o.Client.AccessURL(ctx, &third.AccessURLReq{Name: name, Query: query})
resp, err := o.Client.AccessURL(ctx, &third.AccessURLReq{Name: name})
if err != nil {
if errs.ErrArgs.Is(err) {
c.String(http.StatusBadRequest, err.Error())
-1
View File
@@ -88,7 +88,6 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
log.ZWarn(c, "GetUsersOnlineStatus rpc err", err)
parseError := apiresp.ParseError(err)
log.ZDebug(c, "errcode bantanger", "errcode", parseError.ErrCode)
if parseError.ErrCode == errs.NoPermissionError {
apiresp.GinError(c, err)
return
+2 -14
View File
@@ -40,13 +40,7 @@ type Req struct {
}
func (r *Req) String() string {
var tReq Req
tReq.ReqIdentifier = r.ReqIdentifier
tReq.Token = r.Token
tReq.SendID = r.SendID
tReq.OperationID = r.OperationID
tReq.MsgIncr = r.MsgIncr
return utils.StructToJsonString(tReq)
return utils.StructToJsonString(r)
}
type Resp struct {
@@ -59,13 +53,7 @@ type Resp struct {
}
func (r *Resp) String() string {
var tResp Resp
tResp.ReqIdentifier = r.ReqIdentifier
tResp.MsgIncr = r.MsgIncr
tResp.OperationID = r.OperationID
tResp.ErrCode = r.ErrCode
tResp.ErrMsg = r.ErrMsg
return utils.StructToJsonString(tResp)
return utils.StructToJsonString(r)
}
type MessageHandler interface {
@@ -145,7 +145,7 @@ func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
len(modifyMsgList),
)
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message)
conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message)
conversationIDNotification := msgprocessor.GetNotificationConversationID(ctxMsgList[0].message)
och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList)
och.handleNotification(
ctx,
+6 -11
View File
@@ -161,9 +161,6 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbGroup.CreateGroupR
if req.OwnerUserID == "" {
return nil, errs.ErrArgs.Wrap("no group owner")
}
if req.GroupInfo.GroupType != constant.WorkingGroup {
return nil, errs.ErrArgs.Wrap(fmt.Sprintf("group type %d not support", req.GroupInfo.GroupType))
}
if err := authverify.CheckAccessV3(ctx, req.OwnerUserID); err != nil {
return nil, err
}
@@ -693,7 +690,8 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup
return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed")
}
var inGroup bool
if _, err := s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil {
_, err = s.GroupDatabase.TakeGroupMember(ctx, req.GroupID, req.FromUserID)
if err == nil {
inGroup = true // 已经在群里了
} else if !s.IsNotFound(err) {
return nil, err
@@ -720,7 +718,6 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup
return nil, err
}
}
log.ZDebug(ctx, "GroupApplicationResponse", "inGroup", inGroup, "HandleResult", req.HandleResult, "member", member)
if err := s.GroupDatabase.HandlerGroupRequest(ctx, req.GroupID, req.FromUserID, req.HandledMsg, req.HandleResult, member); err != nil {
return nil, err
}
@@ -730,14 +727,12 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbGroup
return nil, err
}
s.Notification.GroupApplicationAcceptedNotification(ctx, req)
if member == nil {
log.ZDebug(ctx, "GroupApplicationResponse", "member is nil")
} else {
s.Notification.MemberEnterNotification(ctx, req.GroupID, req.FromUserID)
}
case constant.GroupResponseRefuse:
s.Notification.GroupApplicationRejectedNotification(ctx, req)
}
if member != nil {
s.Notification.MemberEnterNotification(ctx, req)
}
return &pbGroup.GroupApplicationResponseResp{}, nil
}
@@ -783,7 +778,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbGroup.JoinGroupReq)
if err := s.conversationRpcClient.GroupChatFirstCreateConversation(ctx, req.GroupID, []string{req.InviterUserID}); err != nil {
return nil, err
}
s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID)
s.Notification.MemberEnterDirectlyNotification(ctx, req.GroupID, req.InviterUserID)
return resp, nil
}
groupRequest := relationTb.GroupRequestModel{
+21 -55
View File
@@ -116,75 +116,41 @@ func (m *msgServer) SearchMessage(ctx context.Context, req *msg.SearchMessageReq
if total, chatLogs, err = m.MsgDatabase.SearchMessage(ctx, req); err != nil {
return nil, err
}
var (
sendIDs []string
recvIDs []string
groupIDs []string
sendMap = make(map[string]string)
recvMap = make(map[string]string)
groupMap = make(map[string]*sdkws.GroupInfo)
)
for _, chatLog := range chatLogs {
if chatLog.SenderNickname == "" {
sendIDs = append(sendIDs, chatLog.SendID)
}
switch chatLog.SessionType {
case constant.SingleChatType:
recvIDs = append(recvIDs, chatLog.RecvID)
case constant.GroupChatType, constant.SuperGroupChatType:
groupIDs = append(groupIDs, chatLog.GroupID)
}
}
if len(sendIDs) != 0 {
sendInfos, err := m.User.GetUsersInfo(ctx, sendIDs)
if err != nil {
return nil, err
}
for _, sendInfo := range sendInfos {
sendMap[sendInfo.UserID] = sendInfo.Nickname
}
}
if len(recvIDs) != 0 {
recvInfos, err := m.User.GetUsersInfo(ctx, recvIDs)
if err != nil {
return nil, err
}
for _, recvInfo := range recvInfos {
recvMap[recvInfo.UserID] = recvInfo.Nickname
}
}
if len(groupIDs) != 0 {
groupInfos, err := m.Group.GetGroupInfos(ctx, groupIDs, true)
if err != nil {
return nil, err
}
for _, groupInfo := range groupInfos {
groupMap[groupInfo.GroupID] = groupInfo
}
}
for _, chatLog := range chatLogs {
pbChatLog := &msg.ChatLog{}
utils.CopyStructFields(pbChatLog, chatLog)
pbChatLog.SendTime = chatLog.SendTime
pbChatLog.CreateTime = chatLog.CreateTime
if chatLog.SenderNickname == "" {
pbChatLog.SenderNickname = sendMap[chatLog.SendID]
sendUser, err := m.User.GetUserInfo(ctx, chatLog.SendID)
if err != nil {
return nil, err
}
pbChatLog.SenderNickname = sendUser.Nickname
}
switch chatLog.SessionType {
case constant.SingleChatType:
pbChatLog.RecvNickname = recvMap[chatLog.RecvID]
recvUser, err := m.User.GetUserInfo(ctx, chatLog.RecvID)
if err != nil {
return nil, err
}
pbChatLog.RecvNickname = recvUser.Nickname
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
group, err := m.Group.GetGroupInfo(ctx, chatLog.GroupID)
if err != nil {
return nil, err
}
pbChatLog.SenderFaceURL = group.FaceURL
pbChatLog.GroupMemberCount = group.MemberCount
pbChatLog.RecvID = group.GroupID
pbChatLog.GroupName = group.GroupName
pbChatLog.GroupOwner = group.OwnerUserID
pbChatLog.GroupType = group.GroupType
}
resp.ChatLogs = append(resp.ChatLogs, pbChatLog)
}
resp.ChatLogsNum = total
return resp, nil
}
+1 -18
View File
@@ -16,11 +16,8 @@ package third
import (
"context"
"strconv"
"time"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3"
"github.com/OpenIMSDK/protocol/third"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
@@ -155,21 +152,7 @@ func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.Co
}
func (t *thirdServer) AccessURL(ctx context.Context, req *third.AccessURLReq) (*third.AccessURLResp, error) {
opt := &s3.AccessURLOption{}
if len(req.Query) > 0 {
switch req.Query["type"] {
case "":
case "image":
opt.Image = &s3.Image{}
opt.Image.Format = req.Query["format"]
opt.Image.Width, _ = strconv.Atoi(req.Query["width"])
opt.Image.Height, _ = strconv.Atoi(req.Query["height"])
log.ZDebug(ctx, "AccessURL image", "name", req.Name, "option", opt.Image)
default:
return nil, errs.ErrArgs.Wrap("invalid query type")
}
}
expireTime, rawURL, err := t.s3dataBase.AccessURL(ctx, req.Name, t.defaultExpire, opt)
expireTime, rawURL, err := t.s3dataBase.AccessURL(ctx, req.Name, t.defaultExpire)
if err != nil {
return nil, err
}
-1
View File
@@ -49,7 +49,6 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
if apiURL[len(apiURL)-1] != '/' {
apiURL += "/"
}
apiURL += "object/"
rdb, err := cache.NewRedis()
if err != nil {
return err
+7 -6
View File
@@ -20,16 +20,17 @@ import (
"strings"
"time"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/Open-IM-Server/pkg/authverify"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/unrelation"
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws"
pbuser "github.com/OpenIMSDK/protocol/user"
registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/convert"
@@ -40,9 +41,9 @@ import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient"
"github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient/notification"
pbuser "github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/utils"
"google.golang.org/grpc"
"github.com/OpenIMSDK/tools/utils"
)
type userServer struct {
+1 -2
View File
@@ -26,13 +26,12 @@ import (
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
)
func StartTask() error {
func StartCronTask() error {
fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime)
msgTool, err := InitMsgTool()
if err != nil {
return err
}
msgTool.ConvertTools()
c := cron.New()
var wg sync.WaitGroup
wg.Add(1)
-33
View File
@@ -1,33 +0,0 @@
package tools
import (
"github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/Open-IM-Server/pkg/msgprocessor"
)
func (c *MsgTool) ConvertTools() {
ctx := mcontext.NewCtx("convert")
conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx)
if err != nil {
log.ZError(ctx, "get all conversation ids failed", err)
return
}
for _, conversationID := range conversationIDs {
conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationIDByConversationID(conversationID))
}
userIDs, err := c.userDatabase.GetAllUserID(ctx, 0, 0)
if err != nil {
log.ZError(ctx, "get all user ids failed", err)
return
}
log.ZDebug(ctx, "all userIDs", "len userIDs", len(userIDs))
for _, userID := range userIDs {
conversationIDs = append(conversationIDs, msgprocessor.GetConversationIDBySessionType(constant.SingleChatType, userID, userID))
conversationIDs = append(conversationIDs, msgprocessor.GetNotificationConversationID(constant.SingleChatType, userID, userID))
}
log.ZDebug(ctx, "all conversationIDs", "len userIDs", len(conversationIDs))
c.msgDatabase.ConvertMsgsDocLen(ctx, conversationIDs)
}
+15
View File
@@ -0,0 +1,15 @@
// 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 apistruct // import "github.com/OpenIMSDK/Open-IM-Server/pkg/apistruct"
+15
View File
@@ -0,0 +1,15 @@
// 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 authverify // import "github.com/OpenIMSDK/Open-IM-Server/pkg/authverify"
+15
View File
@@ -0,0 +1,15 @@
// 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 callbackstruct // import "github.com/OpenIMSDK/Open-IM-Server/pkg/callbackstruct"
+15
View File
@@ -0,0 +1,15 @@
// 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 cmd // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/cmd"
-1
View File
@@ -120,7 +120,6 @@ type configStruct struct {
AccessKeyID string `yaml:"accessKeyID"`
SecretAccessKey string `yaml:"secretAccessKey"`
SessionToken string `yaml:"sessionToken"`
SignEndpoint string `yaml:"signEndpoint"`
} `yaml:"minio"`
Cos struct {
BucketURL string `yaml:"bucketURL"`
+15
View File
@@ -0,0 +1,15 @@
// 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 config // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/config"
+15
View File
@@ -0,0 +1,15 @@
// 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 convert // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/convert"
+15
View File
@@ -0,0 +1,15 @@
// 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 cache // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/cache"
+15
View File
@@ -0,0 +1,15 @@
// 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 controller // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/controller"
-1
View File
@@ -209,7 +209,6 @@ func (f *friendDatabase) RefuseFriendRequest(
if fr.HandleResult != 0 {
return errs.ErrArgs.Wrap("the friend request has been processed")
}
log.ZDebug(ctx, "refuse friend request", "friendRequest db", fr, "friendRequest arg", friendRequest)
friendRequest.HandleResult = constant.FriendResponseRefuse
friendRequest.HandleTime = time.Now()
err = f.friendRequest.Update(ctx, friendRequest)
+7 -22
View File
@@ -386,24 +386,8 @@ func (g *groupDatabase) HandlerGroupRequest(
handleResult int32,
member *relationTb.GroupMemberModel,
) error {
//cache := g.cache.NewCache()
//if err := g.tx.Transaction(func(tx any) error {
// if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
// return err
// }
// if member != nil {
// if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationTb.GroupMemberModel{member}); err != nil {
// return err
// }
// cache = cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID)
// }
// return nil
//}); err != nil {
// return err
//}
//return cache.ExecDel(ctx)
return g.tx.Transaction(func(tx any) error {
cache := g.cache.NewCache()
if err := g.tx.Transaction(func(tx any) error {
if err := g.groupRequestDB.NewTx(tx).UpdateHandler(ctx, groupID, userID, handledMsg, handleResult); err != nil {
return err
}
@@ -411,12 +395,13 @@ func (g *groupDatabase) HandlerGroupRequest(
if err := g.groupMemberDB.NewTx(tx).Create(ctx, []*relationTb.GroupMemberModel{member}); err != nil {
return err
}
if err := g.cache.NewCache().DelGroupMembersHash(groupID).DelGroupMembersInfo(groupID, member.UserID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID).ExecDel(ctx); err != nil {
return err
}
cache = cache.DelGroupMembersHash(groupID).DelGroupMemberIDs(groupID).DelGroupsMemberNum(groupID).DelJoinedGroupID(member.UserID)
}
return nil
})
}); err != nil {
return err
}
return cache.ExecDel(ctx)
}
func (g *groupDatabase) DeleteGroupMember(ctx context.Context, groupID string, userIDs []string) error {
+19 -14
View File
@@ -118,7 +118,6 @@ type CommonMsgDatabase interface {
pageNumber int32,
showNumber int32,
) (msgCount int64, userCount int64, groups []*unRelationTb.GroupCount, dateCount map[string]int64, err error)
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
}
func NewCommonMsgDatabase(msgDocModel unRelationTb.MsgDocModelInterface, cacheModel cache.MsgModel) CommonMsgDatabase {
@@ -731,21 +730,34 @@ func (db *commonMsgDatabase) deleteMsgRecursion(ctx context.Context, conversatio
delStruct.delDocIDs = append(delStruct.delDocIDs, msgDocModel.DocID)
delStruct.minSeq = msgDocModel.Msg[len(msgDocModel.Msg)-1].Msg.Seq
} else {
var hasMarkDelFlag bool
var delMsgIndexs []int
for i, MsgInfoModel := range msgDocModel.Msg {
if MsgInfoModel != nil && MsgInfoModel.Msg != nil {
if utils.GetCurrentTimestampByMill() > MsgInfoModel.Msg.SendTime+(remainTime*1000) {
delMsgIndexs = append(delMsgIndexs, i)
hasMarkDelFlag = true
} else {
// 到本条消息不需要删除, minSeq置为这条消息的seq
if len(delStruct.delDocIDs) > 0 {
log.ZDebug(ctx, "delete docs", "delDocIDs", delStruct.delDocIDs)
}
if err := db.msgDocDatabase.DeleteDocs(ctx, delStruct.delDocIDs); err != nil {
return 0, err
}
if hasMarkDelFlag {
log.ZDebug(ctx, "delete msg by index", "delMsgIndexs", delMsgIndexs, "docID", msgDocModel.DocID)
// mark del all delMsgIndexs
if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil {
return delStruct.getSetMinSeq(), err
}
}
return MsgInfoModel.Msg.Seq, nil
}
}
}
if len(delMsgIndexs) > 0 {
if err := db.msgDocDatabase.DeleteMsgsInOneDocByIndex(ctx, msgDocModel.DocID, delMsgIndexs); err != nil {
log.ZError(ctx, "deleteMsgRecursion DeleteMsgsInOneDocByIndex failed", err, "conversationID", conversationID, "index", index)
}
delStruct.minSeq = int64(msgDocModel.Msg[delMsgIndexs[len(delMsgIndexs)-1]].Msg.Seq)
}
}
// 继续递归 index+1
seq, err := db.deleteMsgRecursion(ctx, conversationID, index+1, delStruct, remainTime)
return seq, err
}
@@ -949,14 +961,7 @@ func (db *commonMsgDatabase) SearchMessage(ctx context.Context, req *pbMsg.Searc
return 0, nil, err
}
for _, msg := range msgs {
if msg.IsRead {
msg.Msg.IsRead = true
}
totalMsgs = append(totalMsgs, convert.MsgDB2Pb(msg.Msg))
}
return total, totalMsgs, nil
}
func (db *commonMsgDatabase) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) {
db.msgDocDatabase.ConvertMsgsDocLen(ctx, conversationIDs)
}
+5 -10
View File
@@ -30,7 +30,7 @@ type S3Database interface {
AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error)
InitiateMultipartUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*cont.InitiateUploadResult, error)
CompleteMultipartUpload(ctx context.Context, uploadID string, parts []string) (*cont.UploadResult, error)
AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error)
AccessURL(ctx context.Context, name string, expire time.Duration) (time.Time, string, error)
SetObject(ctx context.Context, info *relation.ObjectModel) error
}
@@ -70,19 +70,14 @@ func (s *s3Database) SetObject(ctx context.Context, info *relation.ObjectModel)
return s.obj.SetObject(ctx, info)
}
func (s *s3Database) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (time.Time, string, error) {
func (s *s3Database) AccessURL(ctx context.Context, name string, expire time.Duration) (time.Time, string, error) {
obj, err := s.obj.Take(ctx, name)
if err != nil {
return time.Time{}, "", err
}
if opt == nil {
opt = &s3.AccessURLOption{}
}
if opt.ContentType == "" {
opt.ContentType = obj.ContentType
}
if opt.Filename == "" {
opt.Filename = filepath.Base(obj.Name)
opt := &s3.AccessURLOption{
ContentType: obj.ContentType,
Filename: filepath.Base(obj.Name),
}
expireTime := time.Now().Add(expire)
rawURL, err := s.s3.AccessURL(ctx, obj.Key, expire, opt)
+4 -5
View File
@@ -18,9 +18,8 @@ import (
"context"
"time"
"github.com/OpenIMSDK/protocol/user"
unRelationTb "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/tx"
@@ -53,7 +52,7 @@ type UserDatabase interface {
CountTotal(ctx context.Context, before *time.Time) (int64, error)
// CountRangeEverydayTotal Get the user increment in the range
CountRangeEverydayTotal(ctx context.Context, start time.Time, end time.Time) (map[string]int64, error)
//SubscribeUsersStatus Subscribe a user's presence status
// SubscribeUsersStatus Subscribe a user's presence status
SubscribeUsersStatus(ctx context.Context, userID string, userIDs []string) error
// UnsubscribeUsersStatus unsubscribe a user's presence status
UnsubscribeUsersStatus(ctx context.Context, userID string, userIDs []string) error
@@ -180,13 +179,13 @@ func (u *userDatabase) CountRangeEverydayTotal(ctx context.Context, start time.T
return u.userDB.CountRangeEverydayTotal(ctx, start, end)
}
// SubscribeUsersStatus Subscribe or unsubscribe a user's presence status
// SubscribeUsersStatus Subscribe or unsubscribe a user's presence status.
func (u *userDatabase) SubscribeUsersStatus(ctx context.Context, userID string, userIDs []string) error {
err := u.mongoDB.AddSubscriptionList(ctx, userID, userIDs)
return err
}
// UnsubscribeUsersStatus unsubscribe a user's presence status
// UnsubscribeUsersStatus unsubscribe a user's presence status.
func (u *userDatabase) UnsubscribeUsersStatus(ctx context.Context, userID string, userIDs []string) error {
err := u.mongoDB.UnsubscriptionList(ctx, userID, userIDs)
return err
+15
View File
@@ -0,0 +1,15 @@
// 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/pkg/common/db/localcache"
+15
View File
@@ -0,0 +1,15 @@
// 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 relation // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/relation"
@@ -71,13 +71,10 @@ func (f *FriendRequestGorm) UpdateByMap(
// 更新记录 (非零值).
func (f *FriendRequestGorm) Update(ctx context.Context, friendRequest *relation.FriendRequestModel) (err error) {
fr2 := *friendRequest
fr2.FromUserID = ""
fr2.ToUserID = ""
return utils.Wrap(
f.db(ctx).
Where("from_user_id = ? AND to_user_id =?", friendRequest.FromUserID, friendRequest.ToUserID).
Updates(fr2).
Updates(friendRequest).
Error,
"",
)
+1 -2
View File
@@ -33,6 +33,5 @@ func NewMetaDB(db *gorm.DB, table any) *MetaDB {
}
func (g *MetaDB) db(ctx context.Context) *gorm.DB {
db := g.DB.WithContext(ctx).Model(g.table)
return db
return g.DB.WithContext(ctx).Model(g.table)
}
+1 -5
View File
@@ -86,11 +86,7 @@ func (u *UserGorm) Page(
// 获取所有用户ID.
func (u *UserGorm) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (userIDs []string, err error) {
if pageNumber == 0 || showNumber == 0 {
return userIDs, errs.Wrap(u.db(ctx).Pluck("user_id", &userIDs).Error)
} else {
return userIDs, errs.Wrap(u.db(ctx).Limit(int(showNumber)).Offset(int((pageNumber-1)*showNumber)).Pluck("user_id", &userIDs).Error)
}
return userIDs, errs.Wrap(u.db(ctx).Limit(int(showNumber)).Offset(int((pageNumber-1)*showNumber)).Pluck("user_id", &userIDs).Error)
}
func (u *UserGorm) GetUserGlobalRecvMsgOpt(ctx context.Context, userID string) (opt int, err error) {
-4
View File
@@ -257,9 +257,5 @@ func (c *Controller) IsNotFound(err error) bool {
}
func (c *Controller) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
if opt.Image != nil {
opt.Filename = ""
opt.ContentType = ""
}
return c.impl.AccessURL(ctx, name, expire, opt)
}
+15
View File
@@ -0,0 +1,15 @@
// 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 cont // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3/cont"
+7 -49
View File
@@ -36,19 +36,6 @@ const (
maxNumSize = 1000
)
const (
imagePng = "png"
imageJpg = "jpg"
imageJpeg = "jpeg"
imageGif = "gif"
imageWebp = "webp"
)
const (
videoSnapshotImagePng = "png"
videoSnapshotImageJpg = "jpg"
)
func NewCos() (s3.Interface, error) {
conf := config.Config.Object.Cos
u, err := url.Parse(conf.BucketURL)
@@ -261,44 +248,19 @@ func (c *Cos) ListUploadedParts(ctx context.Context, uploadID string, name strin
}
func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
var imageMogr string
var option cos.PresignedURLOptions
var option *cos.PresignedURLOptions
if opt != nil {
query := make(url.Values)
if opt.Image != nil {
// https://cloud.tencent.com/document/product/436/44880
style := make([]string, 0, 2)
wh := make([]string, 2)
if opt.Image.Width > 0 {
wh[0] = strconv.Itoa(opt.Image.Width)
}
if opt.Image.Height > 0 {
wh[1] = strconv.Itoa(opt.Image.Height)
}
if opt.Image.Width > 0 || opt.Image.Height > 0 {
style = append(style, strings.Join(wh, "x"))
}
switch opt.Image.Format {
case
imagePng,
imageJpg,
imageJpeg,
imageGif,
imageWebp:
style = append(style, "format/"+opt.Image.Format)
}
if len(style) > 0 {
imageMogr = "&imageMogr2/thumbnail/" + strings.Join(style, "/") + "/ignore-error/1"
}
}
if opt.ContentType != "" {
query.Set("response-content-type", opt.ContentType)
}
if opt.Filename != "" {
query.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename))
query.Set("response-content-disposition", `attachment; filename="`+opt.Filename+`"`)
}
if len(query) > 0 {
option.Query = &query
option = &cos.PresignedURLOptions{
Query: &query,
}
}
}
if expire <= 0 {
@@ -306,13 +268,9 @@ func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration,
} else if expire < time.Second {
expire = time.Second
}
rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, &option)
rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, option)
if err != nil {
return "", err
}
urlStr := rawURL.String()
if imageMogr != "" {
urlStr += imageMogr
}
return urlStr, nil
return rawURL.String(), nil
}
+15
View File
@@ -0,0 +1,15 @@
// 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 cos // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3/cos"
+15
View File
@@ -0,0 +1,15 @@
// 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 s3 // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3"
+15
View File
@@ -0,0 +1,15 @@
// 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 minio // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3/minio"
-106
View File
@@ -1,106 +0,0 @@
package minio
import (
"image"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"io"
_ "golang.org/x/image/bmp"
_ "golang.org/x/image/tiff"
_ "golang.org/x/image/webp"
)
const (
formatPng = "png"
formatJpeg = "jpeg"
formatJpg = "jpg"
formatGif = "gif"
)
func ImageStat(reader io.Reader) (image.Image, string, error) {
return image.Decode(reader)
}
func ImageWidthHeight(img image.Image) (int, int) {
bounds := img.Bounds().Max
return bounds.X, bounds.Y
}
func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image {
bounds := img.Bounds()
imgWidth := bounds.Max.X
imgHeight := bounds.Max.Y
// 计算缩放比例
scaleWidth := float64(maxWidth) / float64(imgWidth)
scaleHeight := float64(maxHeight) / float64(imgHeight)
// 如果都为0,则不缩放,返回原始图片
if maxWidth == 0 && maxHeight == 0 {
return img
}
// 如果宽度和高度都大于0,则选择较小的缩放比例,以保持宽高比
if maxWidth > 0 && maxHeight > 0 {
scale := scaleWidth
if scaleHeight < scaleWidth {
scale = scaleHeight
}
// 计算缩略图尺寸
thumbnailWidth := int(float64(imgWidth) * scale)
thumbnailHeight := int(float64(imgHeight) * scale)
// 使用"image"库的Resample方法生成缩略图
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
for y := 0; y < thumbnailHeight; y++ {
for x := 0; x < thumbnailWidth; x++ {
srcX := int(float64(x) / scale)
srcY := int(float64(y) / scale)
thumbnail.Set(x, y, img.At(srcX, srcY))
}
}
return thumbnail
}
// 如果只指定了宽度或高度,则根据最大不超过的规则生成缩略图
if maxWidth > 0 {
thumbnailWidth := maxWidth
thumbnailHeight := int(float64(imgHeight) * scaleWidth)
// 使用"image"库的Resample方法生成缩略图
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
for y := 0; y < thumbnailHeight; y++ {
for x := 0; x < thumbnailWidth; x++ {
srcX := int(float64(x) / scaleWidth)
srcY := int(float64(y) / scaleWidth)
thumbnail.Set(x, y, img.At(srcX, srcY))
}
}
return thumbnail
}
if maxHeight > 0 {
thumbnailWidth := int(float64(imgWidth) * scaleHeight)
thumbnailHeight := maxHeight
// 使用"image"库的Resample方法生成缩略图
thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight))
for y := 0; y < thumbnailHeight; y++ {
for x := 0; x < thumbnailWidth; x++ {
srcX := int(float64(x) / scaleHeight)
srcY := int(float64(y) / scaleHeight)
thumbnail.Set(x, y, img.At(srcX, srcY))
}
}
return thumbnail
}
// 默认情况下,返回原始图片
return img
}
+12 -195
View File
@@ -15,28 +15,16 @@
package minio
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
"net/http"
"net/url"
"path"
"path/filepath"
"reflect"
"strconv"
"strings"
"sync"
"time"
"unsafe"
"github.com/OpenIMSDK/tools/log"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/minio/minio-go/v7/pkg/signer"
@@ -55,13 +43,6 @@ const (
maxNumSize = 10000
)
const (
maxImageWidth = 1024
maxImageHeight = 1024
maxImageSize = 1024 * 1024 * 50
pathInfo = "openim/thumbnail"
)
func NewMinio() (s3.Interface, error) {
conf := config.Config.Object.Minio
u, err := url.Parse(conf.Endpoint)
@@ -79,26 +60,11 @@ func NewMinio() (s3.Interface, error) {
m := &Minio{
bucket: conf.Bucket,
bucketURL: conf.Endpoint + "/" + conf.Bucket + "/",
opts: opts,
core: &minio.Core{Client: client},
lock: &sync.Mutex{},
init: false,
}
if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
m.sign = m.core.Client
} else {
su, err := url.Parse(conf.SignEndpoint)
if err != nil {
return nil, err
}
m.opts = &minio.Options{
Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken),
Secure: su.Scheme == "https",
}
m.sign, err = minio.New(su.Host, m.opts)
if err != nil {
return nil, err
}
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := m.initMinio(ctx); err != nil {
@@ -110,10 +76,8 @@ func NewMinio() (s3.Interface, error) {
type Minio struct {
bucket string
bucketURL string
location string
opts *minio.Options
core *minio.Core
sign *minio.Client
lock sync.Locker
init bool
}
@@ -127,43 +91,15 @@ func (m *Minio) initMinio(ctx context.Context) error {
if m.init {
return nil
}
conf := config.Config.Object.Minio
exists, err := m.core.Client.BucketExists(ctx, conf.Bucket)
exists, err := m.core.Client.BucketExists(ctx, config.Config.Object.Minio.Bucket)
if err != nil {
return fmt.Errorf("check bucket exists error: %w", err)
}
if !exists {
if err := m.core.Client.MakeBucket(ctx, conf.Bucket, minio.MakeBucketOptions{}); err != nil {
if err := m.core.Client.MakeBucket(ctx, config.Config.Object.Minio.Bucket, minio.MakeBucketOptions{}); err != nil {
return fmt.Errorf("make bucket error: %w", err)
}
}
m.location, err = m.core.Client.GetBucketLocation(ctx, conf.Bucket)
if err != nil {
return err
}
func() {
if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint {
return
}
defer func() {
if r := recover(); r != nil {
m.sign = m.core.Client
log.ZWarn(
context.Background(),
"set sign bucket location cache panic",
errors.New("failed to get private field value"),
"recover",
fmt.Sprintf("%+v", r),
"development version",
"github.com/minio/minio-go/v7 v7.0.61",
)
}
}()
blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache")
vblc := reflect.New(reflect.PtrTo(blc.Type()))
*(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr())
vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(conf.Bucket, m.location)
}()
m.init = true
return nil
}
@@ -255,7 +191,7 @@ func (m *Minio) AuthSign(ctx context.Context, uploadID string, name string, expi
return nil, err
}
request.Header.Set("X-Amz-Content-Sha256", unsignedPayload)
request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, m.location, nil)
request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, "us-east-1", nil)
result.Parts[i] = s3.SignPart{
PartNumber: partNumber,
URL: request.URL.String(),
@@ -270,7 +206,7 @@ func (m *Minio) PresignedPutObject(ctx context.Context, name string, expire time
if err := m.initMinio(ctx); err != nil {
return "", err
}
rawURL, err := m.sign.PresignedPutObject(ctx, m.bucket, name, expire)
rawURL, err := m.core.Client.PresignedPutObject(ctx, m.bucket, name, expire)
if err != nil {
return "", err
}
@@ -367,19 +303,6 @@ func (m *Minio) ListUploadedParts(ctx context.Context, uploadID string, name str
return res, nil
}
func (m *Minio) presignedGetObject(ctx context.Context, name string, expire time.Duration, query url.Values) (string, error) {
if expire <= 0 {
expire = time.Hour * 24 * 365 * 99 // 99 years
} else if expire < time.Second {
expire = time.Second
}
rawURL, err := m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query)
if err != nil {
return "", err
}
return rawURL.String(), nil
}
func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
if err := m.initMinio(ctx); err != nil {
return "", err
@@ -390,123 +313,17 @@ func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration
reqParams.Set("response-content-type", opt.ContentType)
}
if opt.Filename != "" {
reqParams.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename))
reqParams.Set("response-content-disposition", `attachment; filename="`+opt.Filename+`"`)
}
}
if opt.Image == nil || (opt.Image.Width < 0 && opt.Image.Height < 0 && opt.Image.Format == "") || (opt.Image.Width > maxImageWidth || opt.Image.Height > maxImageHeight) {
return m.presignedGetObject(ctx, name, expire, reqParams)
if expire <= 0 {
expire = time.Hour * 24 * 365 * 99 // 99 years
} else if expire < time.Second {
expire = time.Second
}
fileInfo, err := m.StatObject(ctx, name)
u, err := m.core.Client.PresignedGetObject(ctx, m.bucket, name, expire, reqParams)
if err != nil {
return "", err
}
if fileInfo.Size > maxImageSize {
return "", errors.New("file size too large")
}
objectInfoPath := path.Join(pathInfo, fileInfo.ETag, "image.json")
var (
img image.Image
info minioImageInfo
)
data, err := m.getObjectData(ctx, objectInfoPath, 1024)
if err == nil {
if err := json.Unmarshal(data, &info); err != nil {
return "", fmt.Errorf("unmarshal minio image info.json error: %w", err)
}
if info.NotImage {
return "", errors.New("not image")
}
} else if m.IsNotFound(err) {
reader, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
if err != nil {
return "", err
}
defer reader.Close()
imageInfo, format, err := ImageStat(reader)
if err == nil {
info.NotImage = false
info.Format = format
info.Width, info.Height = ImageWidthHeight(imageInfo)
img = imageInfo
} else {
info.NotImage = true
}
data, err := json.Marshal(&info)
if err != nil {
return "", err
}
if _, err := m.core.Client.PutObject(ctx, m.bucket, objectInfoPath, bytes.NewReader(data), int64(len(data)), minio.PutObjectOptions{}); err != nil {
return "", err
}
} else {
return "", err
}
if opt.Image.Width > info.Width || opt.Image.Width <= 0 {
opt.Image.Width = info.Width
}
if opt.Image.Height > info.Height || opt.Image.Height <= 0 {
opt.Image.Height = info.Height
}
opt.Image.Format = strings.ToLower(opt.Image.Format)
if opt.Image.Format == formatJpg {
opt.Image.Format = formatJpeg
}
switch opt.Image.Format {
case formatPng:
case formatJpeg:
case formatGif:
default:
if info.Format == formatGif {
opt.Image.Format = formatGif
} else {
opt.Image.Format = formatJpeg
}
}
reqParams.Set("response-content-type", "image/"+opt.Image.Format)
if opt.Image.Width == info.Width && opt.Image.Height == info.Height && opt.Image.Format == info.Format {
return m.presignedGetObject(ctx, name, expire, reqParams)
}
cacheKey := filepath.Join(pathInfo, fileInfo.ETag, fmt.Sprintf("image_w%d_h%d.%s", opt.Image.Width, opt.Image.Height, opt.Image.Format))
if _, err := m.core.Client.StatObject(ctx, m.bucket, cacheKey, minio.StatObjectOptions{}); err == nil {
return m.presignedGetObject(ctx, cacheKey, expire, reqParams)
} else if !m.IsNotFound(err) {
return "", err
}
if img == nil {
reader, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
if err != nil {
return "", err
}
defer reader.Close()
img, _, err = ImageStat(reader)
if err != nil {
return "", err
}
}
thumbnail := resizeImage(img, opt.Image.Width, opt.Image.Height)
buf := bytes.NewBuffer(nil)
switch opt.Image.Format {
case formatPng:
err = png.Encode(buf, thumbnail)
case formatJpeg:
err = jpeg.Encode(buf, thumbnail, nil)
case formatGif:
err = gif.Encode(buf, thumbnail, nil)
}
if _, err := m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil {
return "", err
}
return m.presignedGetObject(ctx, cacheKey, expire, reqParams)
}
func (m *Minio) getObjectData(ctx context.Context, name string, limit int64) ([]byte, error) {
object, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{})
if err != nil {
return nil, err
}
defer object.Close()
if limit < 0 {
return io.ReadAll(object)
}
return io.ReadAll(io.LimitReader(object, 1024))
return u.String(), nil
}
-8
View File
@@ -1,8 +0,0 @@
package minio
type minioImageInfo struct {
NotImage bool `json:"notImage,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
Format string `json:"format,omitempty"`
}
+15
View File
@@ -0,0 +1,15 @@
// 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 oss // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/s3/oss"
+8 -41
View File
@@ -36,19 +36,6 @@ const (
maxNumSize = 10000
)
const (
imagePng = "png"
imageJpg = "jpg"
imageJpeg = "jpeg"
imageGif = "gif"
imageWebp = "webp"
)
const (
videoSnapshotImagePng = "png"
videoSnapshotImageJpg = "jpg"
)
func NewOSS() (s3.Interface, error) {
conf := config.Config.Object.Oss
if conf.BucketURL == "" {
@@ -152,7 +139,7 @@ func (o *OSS) AuthSign(ctx context.Context, uploadID string, name string, expire
}
for i, partNumber := range partNumbers {
rawURL := fmt.Sprintf(`%s%s?partNumber=%d&uploadId=%s`, o.bucketURL, name, partNumber, uploadID)
request, err := http.NewRequest(http.MethodPut, rawURL, nil)
request, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, nil)
if err != nil {
return nil, err
}
@@ -163,7 +150,12 @@ func (o *OSS) AuthSign(ctx context.Context, uploadID string, name string, expire
request.Header.Set(oss.HTTPHeaderHost, request.Host)
request.Header.Set(oss.HTTPHeaderDate, now)
request.Header.Set(oss.HttpHeaderOssDate, now)
ossSignHeader(o.bucket.Client.Conn, request, fmt.Sprintf(`/%s/%s?partNumber=%d&uploadId=%s`, o.bucket.BucketName, name, partNumber, uploadID))
authorization := fmt.Sprintf(
`OSS %s:%s`,
o.credentials.GetAccessKeyID(),
o.getSignedStr(request, fmt.Sprintf(`/%s/%s?partNumber=%d&uploadId=%s`, o.bucket.BucketName, name, partNumber, uploadID), o.credentials.GetAccessKeySecret()),
)
request.Header.Set(oss.HTTPHeaderAuthorization, authorization)
delete(request.Header, oss.HTTPHeaderDate)
result.Parts[i] = s3.SignPart{
PartNumber: partNumber,
@@ -274,36 +266,11 @@ func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name strin
func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) {
var opts []oss.Option
if opt != nil {
if opt.Image != nil {
// 文档地址: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji
var format string
switch opt.Image.Format {
case
imagePng,
imageJpg,
imageJpeg,
imageGif,
imageWebp:
format = opt.Image.Format
default:
opt.Image.Format = imageJpg
}
// https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,h_100,m_lfit
process := "image/resize,m_lfit"
if opt.Image.Width > 0 {
process += ",w_" + strconv.Itoa(opt.Image.Width)
}
if opt.Image.Height > 0 {
process += ",h_" + strconv.Itoa(opt.Image.Height)
}
process += ",format," + format
opts = append(opts, oss.Process(process))
}
if opt.ContentType != "" {
opts = append(opts, oss.ResponseContentType(opt.ContentType))
}
if opt.Filename != "" {
opts = append(opts, oss.ResponseContentDisposition(`attachment; filename=`+strconv.Quote(opt.Filename)))
opts = append(opts, oss.ResponseContentDisposition(`attachment; filename="`+opt.Filename+`"`))
}
}
if expire <= 0 {
+88 -3
View File
@@ -1,11 +1,96 @@
// 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 oss
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"hash"
"io"
"net/http"
_ "unsafe"
"sort"
"strings"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
//go:linkname ossSignHeader github.com/aliyun/aliyun-oss-go-sdk/oss.(*Conn).signHeader
func ossSignHeader(c *oss.Conn, req *http.Request, canonicalizedResource string)
func (o *OSS) getAdditionalHeaderKeys(req *http.Request) ([]string, map[string]string) {
var keysList []string
keysMap := make(map[string]string)
srcKeys := make(map[string]string)
for k := range req.Header {
srcKeys[strings.ToLower(k)] = ""
}
for _, v := range o.bucket.Client.Config.AdditionalHeaders {
if _, ok := srcKeys[strings.ToLower(v)]; ok {
keysMap[strings.ToLower(v)] = ""
}
}
for k := range keysMap {
keysList = append(keysList, k)
}
sort.Strings(keysList)
return keysList, keysMap
}
func (o *OSS) getSignedStr(req *http.Request, canonicalizedResource string, keySecret string) string {
// Find out the "x-oss-"'s address in header of the request
ossHeadersMap := make(map[string]string)
additionalList, additionalMap := o.getAdditionalHeaderKeys(req)
for k, v := range req.Header {
if strings.HasPrefix(strings.ToLower(k), "x-oss-") {
ossHeadersMap[strings.ToLower(k)] = v[0]
} else if o.bucket.Client.Config.AuthVersion == oss.AuthV2 {
if _, ok := additionalMap[strings.ToLower(k)]; ok {
ossHeadersMap[strings.ToLower(k)] = v[0]
}
}
}
hs := newHeaderSorter(ossHeadersMap)
// Sort the ossHeadersMap by the ascending order
hs.Sort()
// Get the canonicalizedOSSHeaders
canonicalizedOSSHeaders := ""
for i := range hs.Keys {
canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
}
// Give other parameters values
// when sign URL, date is expires
date := req.Header.Get(oss.HTTPHeaderDate)
contentType := req.Header.Get(oss.HTTPHeaderContentType)
contentMd5 := req.Header.Get(oss.HTTPHeaderContentMD5)
// default is v1 signature
signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret))
// v2 signature
if o.bucket.Client.Config.AuthVersion == oss.AuthV2 {
signStr = req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + strings.Join(additionalList, ";") + "\n" + canonicalizedResource
h = hmac.New(func() hash.Hash { return sha256.New() }, []byte(keySecret))
}
_, _ = io.WriteString(h, signStr)
signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
return signedStr
}
+61
View File
@@ -0,0 +1,61 @@
// 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 oss
import (
"bytes"
"sort"
)
// headerSorter defines the key-value structure for storing the sorted data in signHeader.
type headerSorter struct {
Keys []string
Vals []string
}
// newHeaderSorter is an additional function for function SignHeader.
func newHeaderSorter(m map[string]string) *headerSorter {
hs := &headerSorter{
Keys: make([]string, 0, len(m)),
Vals: make([]string, 0, len(m)),
}
for k, v := range m {
hs.Keys = append(hs.Keys, k)
hs.Vals = append(hs.Vals, v)
}
return hs
}
// Sort is an additional function for function SignHeader.
func (hs *headerSorter) Sort() {
sort.Sort(hs)
}
// Len is an additional function for function SignHeader.
func (hs *headerSorter) Len() int {
return len(hs.Vals)
}
// Less is an additional function for function SignHeader.
func (hs *headerSorter) Less(i, j int) bool {
return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
}
// Swap is an additional function for function SignHeader.
func (hs *headerSorter) Swap(i, j int) {
hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
}
-7
View File
@@ -116,16 +116,9 @@ type ListUploadedPartsResult struct {
UploadedParts []UploadedPart `xml:"Part"`
}
type Image struct {
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
}
type AccessURLOption struct {
ContentType string `json:"contentType"`
Filename string `json:"filename"`
Image *Image `json:"image"`
}
type Interface interface {
+15
View File
@@ -0,0 +1,15 @@
// 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 relation // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/relation"
+15
View File
@@ -0,0 +1,15 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package unrelation // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
+4 -10
View File
@@ -27,11 +27,10 @@ import (
)
const (
singleGocMsgNum = 100
singleGocMsgNum5000 = 5000
Msg = "msg"
OldestList = 0
NewestList = -1
singleGocMsgNum = 5000
Msg = "msg"
OldestList = 0
NewestList = -1
)
type MsgDocModel struct {
@@ -129,7 +128,6 @@ type MsgDocModelInterface interface {
pageNumber int32,
showNumber int32,
) (msgCount int64, userCount int64, groups []*GroupCount, dateCount map[string]int64, err error)
ConvertMsgsDocLen(ctx context.Context, conversationIDs []string)
}
func (MsgDocModel) TableName() string {
@@ -140,10 +138,6 @@ func (MsgDocModel) GetSingleGocMsgNum() int64 {
return singleGocMsgNum
}
func (MsgDocModel) GetSingleGocMsgNum5000() int64 {
return singleGocMsgNum5000
}
func (m *MsgDocModel) IsFull() bool {
return m.Msg[len(m.Msg)-1].Msg != nil
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package unrelation // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/unrelation"
+41 -43
View File
@@ -1073,6 +1073,11 @@ func (m *MsgMongoDriver) SearchMessage(ctx context.Context, req *msg.SearchMessa
if err != nil {
return 0, nil, err
}
for _, msg1 := range msgs {
if msg1.IsRead {
msg1.Msg.IsRead = true
}
}
return total, msgs, nil
}
@@ -1146,22 +1151,13 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
{"doc_id", 1},
}},
},
{
{"$unwind", bson.M{"path": "$msgs"}},
},
{
{"$sort", bson.M{"msgs.msg.send_time": -1}},
},
}
cursor, err := m.MsgCollection.Aggregate(ctx, pipe)
if err != nil {
return 0, nil, err
}
type docModel struct {
DocID string `bson:"doc_id"`
Msg *table.MsgInfoModel `bson:"msgs"`
}
var msgsDocs []docModel
var msgsDocs []table.MsgDocModel
err = cursor.All(ctx, &msgsDocs)
if err != nil {
return 0, nil, err
@@ -1171,39 +1167,41 @@ func (m *MsgMongoDriver) searchMessage(ctx context.Context, req *msg.SearchMessa
}
msgs := make([]*table.MsgInfoModel, 0)
for index := range msgsDocs {
msgInfo := msgsDocs[index].Msg
if msgInfo == nil || msgInfo.Msg == nil {
continue
for i := range msgsDocs[index].Msg {
msg := msgsDocs[index].Msg[i]
if msg == nil || msg.Msg == nil {
continue
}
if msg.Revoke != nil {
revokeContent := sdkws.MessageRevokedContent{
RevokerID: msg.Revoke.UserID,
RevokerRole: msg.Revoke.Role,
ClientMsgID: msg.Msg.ClientMsgID,
RevokerNickname: msg.Revoke.Nickname,
RevokeTime: msg.Revoke.Time,
SourceMessageSendTime: msg.Msg.SendTime,
SourceMessageSendID: msg.Msg.SendID,
SourceMessageSenderNickname: msg.Msg.SenderNickname,
SessionType: msg.Msg.SessionType,
Seq: msg.Msg.Seq,
Ex: msg.Msg.Ex,
}
data, err := json.Marshal(&revokeContent)
if err != nil {
return 0, nil, err
}
elem := sdkws.NotificationElem{
Detail: string(data),
}
content, err := json.Marshal(&elem)
if err != nil {
return 0, nil, err
}
msg.Msg.ContentType = constant.MsgRevokeNotification
msg.Msg.Content = string(content)
}
msgs = append(msgs, msg)
}
if msgInfo.Revoke != nil {
revokeContent := sdkws.MessageRevokedContent{
RevokerID: msgInfo.Revoke.UserID,
RevokerRole: msgInfo.Revoke.Role,
ClientMsgID: msgInfo.Msg.ClientMsgID,
RevokerNickname: msgInfo.Revoke.Nickname,
RevokeTime: msgInfo.Revoke.Time,
SourceMessageSendTime: msgInfo.Msg.SendTime,
SourceMessageSendID: msgInfo.Msg.SendID,
SourceMessageSenderNickname: msgInfo.Msg.SenderNickname,
SessionType: msgInfo.Msg.SessionType,
Seq: msgInfo.Msg.Seq,
Ex: msgInfo.Msg.Ex,
}
data, err := json.Marshal(&revokeContent)
if err != nil {
return 0, nil, err
}
elem := sdkws.NotificationElem{
Detail: string(data),
}
content, err := json.Marshal(&elem)
if err != nil {
return 0, nil, err
}
msgInfo.Msg.ContentType = constant.MsgRevokeNotification
msgInfo.Msg.Content = string(content)
}
msgs = append(msgs, msgInfo)
}
start := (req.Pagination.PageNumber - 1) * req.Pagination.ShowNumber
n := int32(len(msgs))
-68
View File
@@ -1,68 +0,0 @@
package unrelation
import (
"context"
"fmt"
"github.com/OpenIMSDK/tools/log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
table "github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
)
func (m *MsgMongoDriver) ConvertMsgsDocLen(ctx context.Context, conversationIDs []string) {
for _, conversationID := range conversationIDs {
regex := primitive.Regex{Pattern: fmt.Sprintf("^%s:", conversationID)}
cursor, err := m.MsgCollection.Find(ctx, bson.M{"doc_id": regex})
if err != nil {
log.ZError(ctx, "convertAll find msg doc failed", err, "conversationID", conversationID)
continue
}
var msgDocs []table.MsgDocModel
err = cursor.All(ctx, &msgDocs)
if err != nil {
log.ZError(ctx, "convertAll cursor all failed", err, "conversationID", conversationID)
continue
}
if len(msgDocs) < 1 {
continue
}
log.ZInfo(ctx, "msg doc convert", "conversationID", conversationID, "len(msgDocs)", len(msgDocs))
if len(msgDocs[0].Msg) == int(m.model.GetSingleGocMsgNum5000()) {
if _, err := m.MsgCollection.DeleteMany(ctx, bson.M{"doc_id": regex}); err != nil {
log.ZError(ctx, "convertAll delete many failed", err, "conversationID", conversationID)
continue
}
var newMsgDocs []interface{}
for _, msgDoc := range msgDocs {
if int64(len(msgDoc.Msg)) == m.model.GetSingleGocMsgNum() {
continue
}
var index int64
for index < int64(len(msgDoc.Msg)) {
msg := msgDoc.Msg[index]
if msg != nil && msg.Msg != nil {
msgDocModel := table.MsgDocModel{DocID: m.model.GetDocID(conversationID, msg.Msg.Seq)}
end := index + m.model.GetSingleGocMsgNum()
if int(end) >= len(msgDoc.Msg) {
msgDocModel.Msg = msgDoc.Msg[index:]
} else {
msgDocModel.Msg = msgDoc.Msg[index:end]
}
newMsgDocs = append(newMsgDocs, msgDocModel)
index = end
} else {
break
}
}
}
_, err = m.MsgCollection.InsertMany(ctx, newMsgDocs)
if err != nil {
log.ZError(ctx, "convertAll insert many failed", err, "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs))
} else {
log.ZInfo(ctx, "msg doc convert", "conversationID", conversationID, "len(newMsgDocs)", len(newMsgDocs))
}
}
}
}
+3 -4
View File
@@ -17,13 +17,12 @@ package unrelation
import (
"context"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/OpenIMSDK/Open-IM-Server/pkg/common/db/table/unrelation"
)
// prefixes and suffixes.
@@ -155,7 +154,7 @@ func (u *UserMongoDriver) RemoveSubscribedListFromUser(ctx context.Context, user
return errs.Wrap(err)
}
// GetAllSubscribeList Get all users subscribed by this user
// GetAllSubscribeList Get all users subscribed by this user.
func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string) (userIDList []string, err error) {
var user unrelation.UserModel
cursor := u.userCollection.FindOne(
@@ -168,7 +167,7 @@ func (u *UserMongoDriver) GetAllSubscribeList(ctx context.Context, userID string
return user.UserIDList, nil
}
// GetSubscribedList Get the user subscribed by those users
// GetSubscribedList Get the user subscribed by those users.
func (u *UserMongoDriver) GetSubscribedList(ctx context.Context, userID string) (userIDList []string, err error) {
var user unrelation.UserModel
cursor := u.userCollection.FindOne(
+15
View File
@@ -0,0 +1,15 @@
// 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 http // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/http"
+15
View File
@@ -0,0 +1,15 @@
// 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 kafka // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/kafka"
+15
View File
@@ -0,0 +1,15 @@
// 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 locker // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/locker"
+15
View File
@@ -0,0 +1,15 @@
// 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 prome // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/prome"
+15
View File
@@ -0,0 +1,15 @@
// 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 startrpc // import "github.com/OpenIMSDK/Open-IM-Server/pkg/common/startrpc"
+1 -25
View File
@@ -23,7 +23,7 @@ import (
"google.golang.org/protobuf/proto"
)
func GetNotificationConversationIDByMsg(msg *sdkws.MsgData) string {
func GetNotificationConversationID(msg *sdkws.MsgData) string {
switch msg.SessionType {
case constant.SingleChatType:
l := []string{msg.SendID, msg.RecvID}
@@ -114,30 +114,6 @@ func GetConversationIDBySessionType(sessionType int, ids ...string) string {
return ""
}
func GetNotificationConversationIDByConversationID(conversationID string) string {
l := strings.Split(conversationID, "_")
if len(l) > 1 {
l[0] = "n"
return strings.Join(l, "_")
} else {
return ""
}
}
func GetNotificationConversationID(sessionType int, ids ...string) string {
sort.Strings(ids)
if len(ids) > 2 || len(ids) < 1 {
return ""
}
switch sessionType {
case constant.SingleChatType:
return "n_" + strings.Join(ids, "_") // single chat
case constant.SuperGroupChatType:
return "n_" + ids[0] // super group chat
}
return ""
}
func IsNotification(conversationID string) bool {
return strings.HasPrefix(conversationID, "n_")
}
+15
View File
@@ -0,0 +1,15 @@
// 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 msgprocessor // import "github.com/OpenIMSDK/Open-IM-Server/pkg/msgprocessor"
+15
View File
@@ -0,0 +1,15 @@
// 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 rpcclient // import "github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient"
+15
View File
@@ -0,0 +1,15 @@
// 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 notification // import "github.com/OpenIMSDK/Open-IM-Server/pkg/rpcclient/notification"
+23 -118
View File
@@ -220,13 +220,7 @@ func (g *GroupNotificationSender) getUsersInfoMap(ctx context.Context, userIDs [
return result, nil
}
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws.GroupMemberFullInfo, groupID string) error {
if opUser == nil {
return errs.ErrInternalServer.Wrap("**sdkws.GroupMemberFullInfo is nil")
}
@@ -266,12 +260,6 @@ func (g *GroupNotificationSender) fillOpUser(ctx context.Context, opUser **sdkws
}
func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context, tips *sdkws.GroupCreatedTips) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
@@ -279,12 +267,6 @@ func (g *GroupNotificationSender) GroupCreatedNotification(ctx context.Context,
}
func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context, tips *sdkws.GroupInfoSetTips) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
@@ -292,12 +274,6 @@ func (g *GroupNotificationSender) GroupInfoSetNotification(ctx context.Context,
}
func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Context, tips *sdkws.GroupInfoSetNameTips) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
@@ -305,12 +281,6 @@ func (g *GroupNotificationSender) GroupInfoSetNameNotification(ctx context.Conte
}
func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx context.Context, tips *sdkws.GroupInfoSetAnnouncementTips) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
@@ -318,12 +288,6 @@ func (g *GroupNotificationSender) GroupInfoSetAnnouncementNotification(ctx conte
}
func (g *GroupNotificationSender) JoinGroupApplicationNotification(ctx context.Context, req *pbGroup.JoinGroupReq) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, req.GroupID)
if err != nil {
return err
@@ -391,12 +355,6 @@ func (g *GroupNotificationSender) GroupApplicationAcceptedNotification(ctx conte
}
func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx context.Context, req *pbGroup.GroupApplicationResponseReq) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, req.GroupID)
if err != nil {
return err
@@ -419,12 +377,6 @@ func (g *GroupNotificationSender) GroupApplicationRejectedNotification(ctx conte
}
func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.Context, req *pbGroup.TransferGroupOwnerReq) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, req.GroupID)
if err != nil {
return err
@@ -442,12 +394,6 @@ func (g *GroupNotificationSender) GroupOwnerTransferredNotification(ctx context.
}
func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context, tips *sdkws.MemberKickedTips) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
@@ -455,12 +401,6 @@ func (g *GroupNotificationSender) MemberKickedNotification(ctx context.Context,
}
func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context, groupID, reason string, invitedUserIDList []string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -479,18 +419,12 @@ func (g *GroupNotificationSender) MemberInvitedNotification(ctx context.Context,
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberInvitedNotification, tips)
}
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, groupID string, entrantUserID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, req *pbGroup.GroupApplicationResponseReq) (err error) {
group, err := g.getGroupInfo(ctx, req.GroupID)
if err != nil {
return err
}
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
user, err := g.getGroupMember(ctx, req.GroupID, req.FromUserID)
if err != nil {
return err
}
@@ -499,12 +433,6 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, g
}
func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context, tips *sdkws.GroupDismissedTips) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
if err := g.fillOpUser(ctx, &tips.OpUser, tips.Group.GroupID); err != nil {
return err
}
@@ -512,12 +440,6 @@ func (g *GroupNotificationSender) GroupDismissedNotification(ctx context.Context
}
func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Context, groupID, groupMemberUserID string, mutedSeconds uint32) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -537,12 +459,6 @@ func (g *GroupNotificationSender) GroupMemberMutedNotification(ctx context.Conte
}
func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -559,12 +475,6 @@ func (g *GroupNotificationSender) GroupMemberCancelMutedNotification(ctx context
}
func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, groupID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -584,12 +494,6 @@ func (g *GroupNotificationSender) GroupMutedNotification(ctx context.Context, gr
}
func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Context, groupID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -609,12 +513,6 @@ func (g *GroupNotificationSender) GroupCancelMutedNotification(ctx context.Conte
}
func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -631,12 +529,6 @@ func (g *GroupNotificationSender) GroupMemberInfoSetNotification(ctx context.Con
}
func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -653,12 +545,6 @@ func (g *GroupNotificationSender) GroupMemberSetToAdminNotification(ctx context.
}
func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
@@ -674,6 +560,25 @@ func (g *GroupNotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx c
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToOrdinaryUserNotification, tips)
}
func (g *GroupNotificationSender) MemberEnterDirectlyNotification(ctx context.Context, groupID string, entrantUserID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
if err != nil {
log.ZError(ctx, utils.GetFuncName(1)+" failed", err)
}
}()
group, err := g.getGroupInfo(ctx, groupID)
if err != nil {
return err
}
user, err := g.getGroupMember(ctx, groupID, entrantUserID)
if err != nil {
return err
}
tips := &sdkws.MemberEnterTips{Group: group, EntrantUser: user}
return g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.MemberEnterNotification, tips)
}
func (g *GroupNotificationSender) SuperGroupNotification(ctx context.Context, sendID, recvID string) (err error) {
defer log.ZDebug(ctx, "return")
defer func() {
+15
View File
@@ -0,0 +1,15 @@
// 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 statistics // import "github.com/OpenIMSDK/Open-IM-Server/pkg/statistics"
+31 -1
View File
@@ -84,7 +84,37 @@ Each directory and script in the structure should be understood as a part of a l
- Linux MIPS64LE (linux_mips64le) : Suitable for 64-bit Linux systems with little endian MIPS architecture.
## Get started quickly - demo.sh
Is the `demo.sh` script teaching you how to quickly get started with OpenIM development and use
Steps to run demo:
```sh
make demo
```
Instructions for producing the demo movie:
```bash
# Create temporary directory
mkdir /tmp/kb-demo
cd /tmp/kb-demo
asciinema rec
<path-to-KB-repo>/scripts/demo/run.sh
<CTRL-C> to terminate the script
<CTRL-D> to terminate the asciinema recording
<CTRL-C> to save the recording locally
# Edit the recorded file by editing the controller-gen path
# Once you are happy with the recording, use svg-term program to generate the svg
svg-term --cast=<movie-id> --out _output/demo.svg --window
```
## examples
Scripts to perform various build, install, analysis, etc operations.
+3 -18
View File
@@ -17,6 +17,8 @@
set -e
set -o pipefail
. $(dirname ${BASH_SOURCE})/lib/init.sh
trap 'echo "Script interrupted."; exit 1' INT
# Function for colored echo
@@ -26,24 +28,6 @@ function color_echo() {
echo -e "${COLOR}===> $* ${COLOR_SUFFIX}"
}
# Color definitions
function openim_color() {
COLOR_SUFFIX="\033[0m" # End all colors and special effects
BLACK_PREFIX="\033[30m" # Black prefix
RED_PREFIX="\033[31m" # Red prefix
GREEN_PREFIX="\033[32m" # Green prefix
YELLOW_PREFIX="\033[33m" # Yellow prefix
BLUE_PREFIX="\033[34m" # Blue prefix
SKY_BLUE_PREFIX="\033[36m" # Sky blue prefix
WHITE_PREFIX="\033[37m" # White prefix
BOLD_PREFIX="\033[1m" # Bold prefix
UNDERLINE_PREFIX="\033[4m" # Underline prefix
ITALIC_PREFIX="\033[3m" # Italic prefix
CYAN_PREFIX="\033[0;36m" # Cyan prefix
}
function print_with_delay() {
text="$1"
delay="$2"
@@ -68,6 +52,7 @@ function print_progress() {
done
printf "]${COLOR_SUFFIX}\n"
}
function openim_logo() {
# Set text color to cyan for header and URL
echo -e "\033[0;36m"
+1 -2
View File
@@ -21,9 +21,8 @@ SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
#Include shell font styles and some basic information
source $SCRIPTS_ROOT/style_info.sh
source $SCRIPTS_ROOT/lib/init.sh
source $SCRIPTS_ROOT/path_info.sh
source $SCRIPTS_ROOT/function.sh
cd $SCRIPTS_ROOT
+2 -51
View File
@@ -19,21 +19,8 @@ SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
#Include shell font styles and some basic information
source $SCRIPTS_ROOT/style_info.sh
source $SCRIPTS_ROOT/path_info.sh
source $SCRIPTS_ROOT/function.sh
echo -e "${YELLOW_PREFIX}=======>SCRIPTS_ROOT=$SCRIPTS_ROOT${COLOR_SUFFIX}"
echo -e "${YELLOW_PREFIX}=======>OPENIM_ROOT=$OPENIM_ROOT${COLOR_SUFFIX}"
echo -e "${YELLOW_PREFIX}=======>pwd=$PWD${COLOR_SUFFIX}"
echo -e ""
echo -e "${BACKGROUND_BLUE}===============> Building all using make build binary files ${COLOR_SUFFIX}"
echo -e ""
echo -e "${BOLD_PREFIX}____________________________________________________________ ${COLOR_SUFFIX}"
source $SCRIPTS_ROOT/lib/init.sh
bin_dir="$BIN_DIR"
logs_dir="$OPENIM_ROOT/logs"
@@ -68,43 +55,7 @@ if [ $? -ne 0 ]; then
exit 1
fi
# Get the current operating system and architecture
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
# Select the repository home directory based on the operating system and architecture
if [[ "$OS" == "darwin" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
REPO_DIR="darwin/amd64"
else
REPO_DIR="darwin/386"
fi
elif [[ "$OS" == "linux" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
REPO_DIR="linux/amd64"
elif [[ "$ARCH" == "arm64" ]]; then
REPO_DIR="linux/arm64"
elif [[ "$ARCH" == "mips64" ]]; then
REPO_DIR="linux/mips64"
elif [[ "$ARCH" == "mips64le" ]]; then
REPO_DIR="linux/mips64le"
elif [[ "$ARCH" == "ppc64le" ]]; then
REPO_DIR="linux/ppc64le"
elif [[ "$ARCH" == "s390x" ]]; then
REPO_DIR="linux/s390x"
else
REPO_DIR="linux/386"
fi
elif [[ "$OS" == "windows" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
REPO_DIR="windows/amd64"
else
REPO_DIR="windows/386"
fi
else
echo -e "${RED_PREFIX}Unsupported OS: $OS${COLOR_SUFFIX}"
exit 1
fi
openim::util::gen_os_arch
# Determine if all scripts were successfully built
BUILD_SUCCESS=true
+2 -3
View File
@@ -18,9 +18,8 @@ SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
#Include shell font styles and some basic information
source $SCRIPTS_ROOT/style_info.sh
source $SCRIPTS_ROOT/lib/init.sh
source $SCRIPTS_ROOT/path_info.sh
source $SCRIPTS_ROOT/function.sh
cd $SCRIPTS_ROOT
@@ -43,7 +42,7 @@ service_port_name=(
)
for i in ${service_port_name[*]}; do
list=$(cat $config_path | grep -w ${i} | awk -F '[:]' '{print $NF}')
list_to_string $list
openim::util::list-to-string $list
for j in ${ports_array}; do
port=$(ss -tunlp| grep openim | awk '{print $5}' | grep -w ${j} | awk -F '[:]' '{print $NF}')
if [[ ${port} -ne ${j} ]]; then
+83
View File
@@ -0,0 +1,83 @@
#!/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.
clear
. $(dirname ${BASH_SOURCE})/lib/util.sh
openim::util::desc "========> Welcome to the OpenIM Demo"
openim::util::desc "========> We'll help you get started with OpenIM quickly"
openim::util::desc "========> Press Enter to continue...."
openim::util::run "make advertise"
clear
openim::util::desc "You can learn a lot about automation using make help"
openim::util::run "make help"
clear
openim::util::desc "You can learn a lot about automation using make help-all"
openim::util::run "make help-all"
clear
openim::util::desc "How did we teach you how to build OpenIM"
openim::util::desc "A full build startup check"
openim::util::run "make all"
openim::util::desc "Build one OpenIM binary"
openim::util::desc "BINS: openim-api openim-cmdutils openim-crontask openim-msggateway openim-msgtransfer openim-push openim-rpc changelog infra ncpu yamlfmt"
openim::util::run "make build BINS=openim-api"
openim::util::desc "Build binaries for all platforms"
openim::util::run "make multiarch -j BINS=openim-api PLATFORMS='linux_arm64 linux_amd64' "
openim::util::desc "If you wish to use dlv for debugging, either binary or process"
openim::util::desc "You need to enable debug mode"
openim::util::run "make build BINS=openim-api DEBUG=1"
clear
openim::util::desc "Run tidy to format and fix imports"
openim::util::run "make tidy"
clear
openim::util::desc "Vendor go.mod dependencies"
openim::util::run "make vendor"
clear
openim::util::desc "Run unit tests"
openim::util::run "make test"
clear
openim::util::desc "Run unit tests and get test coverage"
openim::util::run "make cover"
clear
openim::util::desc "Check for updates to go.mod dependencies"
openim::util::run "make updates"
clear
openim::util::desc "Clean all generated files"
openim::util::run "make clean"
clear
openim::util::desc "Generate all necessary files"
openim::util::run "make gen"
clear
openim::util::desc "Verify the license headers for all files"
openim::util::run "make verify-copyright"
clear
openim::util::desc "Add copyright"
openim::util::run "make add-copyright"
clear
-9
View File
@@ -30,15 +30,6 @@ need_to_start_server_shell=(
${SCRIPTS_ROOT}/start_cron.sh
)
component_check=start_component_check.sh
chmod +x $SCRIPTS_ROOT/$component_check
$SCRIPTS_ROOT/$component_check
if [ $? -ne 0 ]; then
# Print error message and exit
echo "${BOLD_PREFIX}${RED_PREFIX}Error executing ${component_check}. Exiting...${COLOR_SUFFIX}"
exit -1
fi
#fixme The 10 second delay to start the project is for the docker-compose one-click to start openIM when the infrastructure dependencies are not started
sleep 10
+2 -3
View File
@@ -18,9 +18,8 @@ SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
#Include shell font styles and some basic information
source $SCRIPTS_ROOT/style_info.sh
source $SCRIPTS_ROOT/lib/init.sh
source $SCRIPTS_ROOT/path_info.sh
source $SCRIPTS_ROOT/function.sh
cd $SCRIPTS_ROOT
@@ -38,7 +37,7 @@ service_port_name=(
for i in ${service_port_name[*]}; do
list=$(cat $config_path | grep -w ${i} | awk -F '[:]' '{print $NF}')
list_to_string $list
openim::util::list-to-string $list
for j in ${ports_array}; do
port=$(ss -tunlp| grep openim | awk '{print $5}' | grep -w ${j} | awk -F '[:]' '{print $NF}')
if [[ ${port} -ne ${j} ]]; then
+2 -2
View File
@@ -15,7 +15,7 @@
#input:[10023,2323,3434]
#output:10023 2323 3434
list_to_string(){
openim::util::list-to-string(){
ports_list=$*
sub_s1=`echo $ports_list | sed 's/ //g'`
sub_s2=${sub_s1//,/ }
@@ -23,7 +23,7 @@ list_to_string(){
sub_s4=${sub_s3%]*}
ports_array=$sub_s4
}
remove_space(){
openim::util::remove_space(){
value=$*
result=`echo $value | sed 's/ //g'`
}
+1 -2
View File
@@ -19,9 +19,8 @@ SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
OPENIM_ROOT=$(dirname "${SCRIPTS_ROOT}")/..
#Include shell font styles and some basic information
source $SCRIPTS_ROOT/style_info.sh
source $SCRIPTS_ROOT/path_info.sh
source $SCRIPTS_ROOT/function.sh
source $SCRIPTS_ROOT/lib/init.sh
cd $SCRIPTS_ROOT
-34
View File
@@ -1,34 +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.
# input: [10023, 2323, 3434]
# output: 10023 2323 3434
# 函数功能:将列表转换为字符串,去除空格和括号
list_to_string() {
ports_list=$* # 获取传入的参数列表
sub_s1=$(echo $ports_list | sed 's/ //g') # 去除空格
sub_s2=${sub_s1//,/ } # 将逗号替换为空格
sub_s3=${sub_s2#*[} # 去除左括号及其之前的内容
sub_s4=${sub_s3%]*} # 去除右括号及其之后的内容
ports_array=$sub_s4 # 将处理后的字符串赋值给变量 ports_array
}
# 函数功能:去除字符串中的空格
remove_space() {
value=$* # 获取传入的参数
result=$(echo $value | sed 's/ //g') # 去除空格
}
+73
View File
@@ -0,0 +1,73 @@
#!/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.
# Script to generate docs from the latest swagger spec.
set -o errexit
set -o nounset
set -o pipefail
# The root of the build/dist directory
OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
source ${OPENIM_ROOT}/scripts/lib/util.sh
mkdir -p ${OPENIM_OUTPUT_TMP}
cd ${OPENIM_OUTPUT_TMP}
# gendocs takes "input.json" as the input swagger spec.
# $1 is expected to be <group>_<version>
cp ${OPENIM_OUTPUT_TMP}/swagger-source/"$1".json ${OPENIM_OUTPUT_TMP}/input.json
./gradle-2.5/bin/gradle gendocs --info
#insert a TOC for top level API objects
buf="== Top Level API Objects\n\n"
top_level_models=$(grep '&[A-Za-z]*{},' /register.go | sed 's/.*&//;s/{},//')
# check if the top level models exist in the definitions.adoc. If they exist,
# their name will be <version>.<model_name>
VERSION="${1#*_}"
for m in ${top_level_models}
do
if grep -xq "=== ${VERSION}.${m}" ./definitions.adoc
then
buf+="* <<${VERSION}.${m}>>\n"
fi
done
sed -i "1i ${buf}" ./definitions.adoc
# fix the links in .adoc, replace <<x.y>> with link:definitions.html#_x_y[x.y], and lowercase the _x_y part
sed -i -e 's|<<\(.*\)\.\(.*\)>>|link:#_\L\1_\2\E[\1.\2]|g' ./definitions.adoc
sed -i -e 's|<<\(.*\)\.\(.*\)>>|link:../definitions#_\L\1_\2\E[\1.\2]|g' ./paths.adoc
# fix the link to <<any>>
sed -i -e 's|<<any>>|link:#_any[any]|g' ./definitions.adoc
sed -i -e 's|<<any>>|link:../definitions#_any[any]|g' ./paths.adoc
# change the title of paths.adoc from "paths" to "operations"
sed -i 's|== Paths|== Operations|g' ./paths.adoc
# $$ has special meaning in asciidoc, we need to escape it
sed -i 's|\$\$|+++$$+++|g' ./definitions.adoc
echo -e "=== any\nRepresents an untyped JSON map - see the description of the field for more info about the structure of this object." >> ./definitions.adoc
asciidoctor definitions.adoc
asciidoctor paths.adoc
cp ${OPENIM_OUTPUT_TMP}/definitions.html ${OPENIM_OUTPUT_TMP}/_output/
cp ${OPENIM_OUTPUT_TMP}/paths.html ${OPENIM_OUTPUT_TMP}/_output/operations.html
success "SUCCESS"
+5 -5
View File
@@ -5,17 +5,17 @@
# license that can be found in the LICENSE file.
# 本脚本功能:根据 scripts/environment.sh 配置,生成 OPENIM 组件 YAML 配置文件。
# 示例:genconfig.sh scripts/environment.sh configs/openim-apiserver.yaml
# 示例:genconfig.sh scripts/environment.sh configs/openim-api.yaml
# Path to the original script file
env_file="$1"
# Path to the generated config file
template_file="$2"
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${OPENIM_ROOT}/scripts/lib/init.sh"
. $(dirname ${BASH_SOURCE})/lib/init.sh
if [ $# -ne 2 ];then
openim::log::error "Usage: genconfig.sh scripts/environment.sh configs/openim-apiserver.yaml"
openim::log::error "Usage: genconfig.sh scripts/environment.sh configs/openim-api.yaml"
exit 1
fi
+37
View File
@@ -0,0 +1,37 @@
#!/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.
# Iterates over two directories: 'pkg' and 'internal/pkg'.
for top in pkg internal/pkg tools
do
# Finds all subdirectories (including nested ones) under the current directory in the iteration ('pkg' or 'internal/pkg').
for d in $(find $top -type d)
do
# Checks if 'doc.go' doesn't exist in the current subdirectory.
if [ ! -f $d/doc.go ]; then
# Checks if there are any '.go' files in the current subdirectory.
if ls $d/*.go > /dev/null 2>&1; then
# Echoes the path of the 'doc.go' file to the terminal.
# This is likely for debugging or information purposes.
echo $d/doc.go
# Writes the package declaration and import comment to the 'doc.go' file in the current subdirectory.
# 'basename $d' retrieves the name of the current directory (last part of the path).
# The import comment is constructed based on a static base URL and the directory path.
echo "package $(basename $d) // import \"github.com/OpenIMSDK/Open-IM-Server/$d\"" > $d/doc.go
fi
fi
done
done
+1 -1
View File
@@ -26,7 +26,7 @@
LC_ALL=C
local_branch="$(git rev-parse --abbrev-ref HEAD)"
valid_branch_regex="^(main|master|develop|release(-[a-zA-Z0-9._-]+)?)$|(feature|feat|openim|hotfix|test|bug|bot|ci|cicd|style|)\/[a-z0-9._-]+$|^HEAD$"
valid_branch_regex="^(main|master|develop|release(-[a-zA-Z0-9._-]+)?)$|(feature|feat|openim|hotfix|test|bug|bot|refactor|revert|ci|cicd|style|)\/[a-z0-9._-]+$|^HEAD$"
YELLOW="\e[93m"
GREEN="\e[32m"
+1 -2
View File
@@ -19,9 +19,8 @@ SCRIPTS_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
OPENIM_ROOT=$(dirname "${SCRIPTS_ROOT}")/..
#Include shell font styles and some basic information
source $SCRIPTS_ROOT/style_info.sh
source $SCRIPTS_ROOT/lib/init.sh
source $SCRIPTS_ROOT/path_info.sh
source $SCRIPTS_ROOT/function.sh
cd $SCRIPTS_ROOT
+178
View File
@@ -0,0 +1,178 @@
# 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.
# A set of helpers for starting/running chat for tests
CHAT_VERSION=${CHAT_VERSION:-1.1.0}
CHAT_HOST=${CHAT_HOST:-127.0.0.1}
CHAT_PORT=${CHAT_PORT:-2379}
# This is intentionally not called CHAT_LOG_LEVEL:
# chat checks that and compains when it is set in addition
# to the command line argument, even when both have the same value.
CHAT_LOGLEVEL=${CHAT_LOGLEVEL:-warn}
export OPENIM_INTEGRATION_CHAT_URL="http://${CHAT_HOST}:${CHAT_PORT}"
openim::chat::validate() {
# validate if in path
command -v chat >/dev/null || {
openim::log::usage "chat must be in your PATH"
openim::log::info "You can use 'hack/install-chat.sh' to install a copy in third_party/."
exit 1
}
# validate chat port is free
local port_check_command
if command -v ss &> /dev/null && ss -Version | grep 'iproute2' &> /dev/null; then
port_check_command="ss"
elif command -v netstat &>/dev/null; then
port_check_command="netstat"
else
openim::log::usage "unable to identify if chat is bound to port ${CHAT_PORT}. unable to find ss or netstat utilities."
exit 1
fi
if ${port_check_command} -nat | grep "LISTEN" | grep "[\.:]${CHAT_PORT:?}" >/dev/null 2>&1; then
openim::log::usage "unable to start chat as port ${CHAT_PORT} is in use. please stop the process listening on this port and retry."
openim::log::usage "$(${port_check_command} -nat | grep "LISTEN" | grep "[\.:]${CHAT_PORT:?}")"
exit 1
fi
# need set the env of "CHAT_UNSUPPORTED_ARCH" on unstable arch.
arch=$(uname -m)
if [[ $arch =~ arm* ]]; then
export CHAT_UNSUPPORTED_ARCH=arm
fi
# validate installed version is at least equal to minimum
version=$(chat --version | grep Version | head -n 1 | cut -d " " -f 3)
if [[ $(openim::chat::version "${CHAT_VERSION}") -gt $(openim::chat::version "${version}") ]]; then
export PATH=${OPENIM_ROOT}/third_party/chat:${PATH}
hash chat
echo "${PATH}"
version=$(chat --version | grep Version | head -n 1 | cut -d " " -f 3)
if [[ $(openim::chat::version "${CHAT_VERSION}") -gt $(openim::chat::version "${version}") ]]; then
openim::log::usage "chat version ${CHAT_VERSION} or greater required."
openim::log::info "You can use 'hack/install-chat.sh' to install a copy in third_party/."
exit 1
fi
fi
}
openim::chat::version() {
printf '%s\n' "${@}" | awk -F . '{ printf("%d%03d%03d\n", $1, $2, $3) }'
}
openim::chat::start() {
# validate before running
openim::chat::validate
# Start chat
CHAT_DIR=${CHAT_DIR:-$(mktemp -d 2>/dev/null || mktemp -d -t test-chat.XXXXXX)}
if [[ -d "${ARTIFACTS:-}" ]]; then
CHAT_LOGFILE="${ARTIFACTS}/chat.$(uname -n).$(id -un).log.DEBUG.$(date +%Y%m%d-%H%M%S).$$"
else
CHAT_LOGFILE=${CHAT_LOGFILE:-"/dev/null"}
fi
openim::log::info "chat --advertise-client-urls ${OPENIM_INTEGRATION_CHAT_URL} --data-dir ${CHAT_DIR} --listen-client-urls http://${CHAT_HOST}:${CHAT_PORT} --log-level=${CHAT_LOGLEVEL} 2> \"${CHAT_LOGFILE}\" >/dev/null"
chat --advertise-client-urls "${OPENIM_INTEGRATION_CHAT_URL}" --data-dir "${CHAT_DIR}" --listen-client-urls "${OPENIM_INTEGRATION_CHAT_URL}" --log-level="${CHAT_LOGLEVEL}" 2> "${CHAT_LOGFILE}" >/dev/null &
CHAT_PID=$!
echo "Waiting for chat to come up."
openim::util::wait_for_url "${OPENIM_INTEGRATION_CHAT_URL}/health" "chat: " 0.25 80
curl -fs -X POST "${OPENIM_INTEGRATION_CHAT_URL}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}'
}
openim::chat::start_scraping() {
if [[ -d "${ARTIFACTS:-}" ]]; then
CHAT_SCRAPE_DIR="${ARTIFACTS}/chat-scrapes"
else
CHAT_SCRAPE_DIR=$(mktemp -d -t test.XXXXXX)/chat-scrapes
fi
openim::log::info "Periodically scraping chat to ${CHAT_SCRAPE_DIR} ."
mkdir -p "${CHAT_SCRAPE_DIR}"
(
while sleep 30; do
openim::chat::scrape
done
) &
CHAT_SCRAPE_PID=$!
}
openim::chat::scrape() {
curl -s -S "${OPENIM_INTEGRATION_CHAT_URL}/metrics" > "${CHAT_SCRAPE_DIR}/next" && mv "${CHAT_SCRAPE_DIR}/next" "${CHAT_SCRAPE_DIR}/$(date +%s).scrape"
}
openim::chat::stop() {
if [[ -n "${CHAT_SCRAPE_PID:-}" ]] && [[ -n "${CHAT_SCRAPE_DIR:-}" ]] ; then
kill "${CHAT_SCRAPE_PID}" &>/dev/null || :
wait "${CHAT_SCRAPE_PID}" &>/dev/null || :
openim::chat::scrape || :
(
# shellcheck disable=SC2015
cd "${CHAT_SCRAPE_DIR}"/.. && \
tar czf chat-scrapes.tgz chat-scrapes && \
rm -rf chat-scrapes || :
)
fi
if [[ -n "${CHAT_PID-}" ]]; then
kill "${CHAT_PID}" &>/dev/null || :
wait "${CHAT_PID}" &>/dev/null || :
fi
}
openim::chat::clean_chat_dir() {
if [[ -n "${CHAT_DIR-}" ]]; then
rm -rf "${CHAT_DIR}"
fi
}
openim::chat::cleanup() {
openim::chat::stop
openim::chat::clean_chat_dir
}
openim::chat::install() {
(
local os
local arch
os=$(openim::util::host_os)
arch=$(openim::util::host_arch)
cd "${OPENIM_ROOT}/third_party" || return 1
if [[ $(readlink chat) == chat-v${CHAT_VERSION}-${os}-* ]]; then
openim::log::info "chat v${CHAT_VERSION} already installed. To use:"
openim::log::info "export PATH=\"$(pwd)/chat:\${PATH}\""
return #already installed
fi
if [[ ${os} == "darwin" ]]; then
download_file="chat-v${CHAT_VERSION}-${os}-${arch}.zip"
url="https://github.com/chat-io/chat/releases/download/v${CHAT_VERSION}/${download_file}"
openim::util::download_file "${url}" "${download_file}"
unzip -o "${download_file}"
ln -fns "chat-v${CHAT_VERSION}-${os}-${arch}" chat
rm "${download_file}"
elif [[ ${os} == "linux" ]]; then
url="https://github.com/coreos/chat/releases/download/v${CHAT_VERSION}/chat-v${CHAT_VERSION}-${os}-${arch}.tar.gz"
download_file="chat-v${CHAT_VERSION}-${os}-${arch}.tar.gz"
openim::util::download_file "${url}" "${download_file}"
tar xzf "${download_file}"
ln -fns "chat-v${CHAT_VERSION}-${os}-${arch}" chat
rm "${download_file}"
else
openim::log::info "${os} is NOT supported."
fi
openim::log::info "chat v${CHAT_VERSION} installed. To use:"
openim::log::info "export PATH=\"$(pwd)/chat:\${PATH}\""
)
}
+43 -21
View File
@@ -14,58 +14,80 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# this script is used to install the dependencies of the project
#
# Usage: `scripts/color.sh`.
################################################################################
# Define color variables
# Feature
# --- Feature ---
COLOR_NORMAL='\033[0m';COLOR_BOLD='\033[1m';COLOR_DIM='\033[2m';COLOR_UNDER='\033[4m';
COLOR_ITALIC='\033[3m';COLOR_NOITALIC='\033[23m';COLOR_BLINK='\033[5m';
COLOR_REVERSE='\033[7m';COLOR_CONCEAL='\033[8m';COLOR_NOBOLD='\033[22m';
COLOR_NOUNDER='\033[24m';COLOR_NOBLINK='\033[25m';
# Front color
# --- Front color ---
COLOR_BLACK='\033[30m';COLOR_RED='\033[31m';COLOR_GREEN='\033[32m';COLOR_YELLOW='\033[33m';
COLOR_BLUE='\033[34m';COLOR_MAGENTA='\033[35m';COLOR_CYAN='\033[36m';COLOR_WHITE='\033[37m';
# background color
# --- background color ---
COLOR_BBLACK='\033[40m';COLOR_BRED='\033[41m';
COLOR_BGREEN='\033[42m';COLOR_BYELLOW='\033[43m';
COLOR_BBLUE='\033[44m';COLOR_BMAGENTA='\033[45m';
COLOR_BCYAN='\033[46m';COLOR_BWHITE='\033[47m';
# --- make demo (run demo) ---
reset=$(tput sgr0)
bold=$(tput bold)
black=$(tput setaf 0)
red=$(tput setaf 1)
green=$(tput bold; tput setaf 2)
yellow=$(tput bold; tput setaf 3)
blue=$(tput bold; tput setaf 6)
timeout=$(if [ "$(uname)" == "Darwin" ]; then echo "1"; else echo "0.1"; fi)
# --- Color definitions ---
# Color definitions
COLOR_SUFFIX="\033[0m" # End all colors and special effects
BLACK_PREFIX="\033[30m" # Black prefix
RED_PREFIX="\033[31m" # Red prefix
GREEN_PREFIX="\033[32m" # Green prefix
YELLOW_PREFIX="\033[33m" # Yellow prefix
BLUE_PREFIX="\033[34m" # Blue prefix
SKY_BLUE_PREFIX="\033[36m" # Sky blue prefix
WHITE_PREFIX="\033[37m" # White prefix
BOLD_PREFIX="\033[1m" # Bold prefix
UNDERLINE_PREFIX="\033[4m" # Underline prefix
ITALIC_PREFIX="\033[3m" # Italic prefix
BRIGHT_GREEN_PREFIX='\033[1;32m' # Bright green prefix
CYAN_PREFIX="\033[0;36m" # Cyan prefix
function openim_color() {
COLOR_SUFFIX="\033[0m" # End all colors and special effects
BLACK_PREFIX="\033[30m" # Black prefix
RED_PREFIX="\033[31m" # Red prefix
GREEN_PREFIX="\033[32m" # Green prefix
YELLOW_PREFIX="\033[33m" # Yellow prefix
BLUE_PREFIX="\033[34m" # Blue prefix
SKY_BLUE_PREFIX="\033[36m" # Sky blue prefix
WHITE_PREFIX="\033[37m" # White prefix
BOLD_PREFIX="\033[1m" # Bold prefix
UNDERLINE_PREFIX="\033[4m" # Underline prefix
ITALIC_PREFIX="\033[3m" # Italic prefix
CYAN_PREFIX="\033[0;36m" # Cyan prefix
}
# --- helper functions for logs ---
info()
function info()
{
echo -e "[${GREEN_PREFIX}INFO${COLOR_SUFFIX}] " "$@"
}
warn()
function warn()
{
echo -e "[${YELLOW_PREFIX}WARN${COLOR_SUFFIX}] " "$@" >&2
}
fatal()
function fatal()
{
echo -e "[${RED_PREFIX}ERROR${COLOR_SUFFIX}] " "$@" >&2
exit 1
}
debug()
function debug()
{
echo -e "[${BLUE_PREFIX}DEBUG${COLOR_SUFFIX}]===> " "$@"
}
success()
function success()
{
echo -e "${BRIGHT_GREEN_PREFIX}===> [SUCCESS] <===${COLOR_SUFFIX}\n=> " "$@"
}
+171 -7
View File
@@ -13,25 +13,189 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set +o nounset
set -o pipefail
# Short-circuit if init.sh has already been sourced
[[ $(type -t openim::init::loaded) == function ]] && return 0
# Unset CDPATH so that path interpolation can work correctly
unset CDPATH
# Default use go modules
# Until all GOPATH references are removed from all build scripts as well,
# explicitly disable module mode to avoid picking up user-set GO111MODULE preferences.
# As individual scripts (like hack/update-vendor.sh) make use of go modules,
# they can explicitly set GO111MODULE=on
export GO111MODULE=on
# The root of the build/dist directory
OPENIM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"
source "${OPENIM_ROOT}/scripts/lib/util.sh"
source "${OPENIM_ROOT}/scripts/lib/logging.sh"
source "${OPENIM_ROOT}/scripts/lib/color.sh"
OPENIM_OUTPUT_SUBPATH="${OPENIM_OUTPUT_SUBPATH:-_output}"
OPENIM_OUTPUT="${OPENIM_ROOT}/${OPENIM_OUTPUT_SUBPATH}"
OPENIM_OUTPUT_BINPATH="${OPENIM_OUTPUT}/bin/platforms"
OPENIM_OUTPUT_BINTOOLPATH="${OPENIM_OUTPUT}/bin-tools"
OPENIM_OUTPUT_TOOLS="${OPENIM_OUTPUT}/tools"
OPENIM_OUTPUT_TMP="${OPENIM_OUTPUT}/tmp"
# This controls rsync compression. Set to a value > 0 to enable rsync
# compression for build container
OPENIM_RSYNC_COMPRESS="${KUBE_RSYNC_COMPRESS:-0}"
# Set no_proxy for localhost if behind a proxy, otherwise,
# the connections to localhost in scripts will time out
export no_proxy="127.0.0.1,localhost${no_proxy:+,${no_proxy}}"
# This is a symlink to binaries for "this platform", e.g. build tools.
export THIS_PLATFORM_BIN="${OPENIM_ROOT}/_output/bin/platforms"
. $(dirname ${BASH_SOURCE})/color.sh
. $(dirname ${BASH_SOURCE})/util.sh
. $(dirname ${BASH_SOURCE})/logging.sh
openim::log::install_errexit
openim::util::ensure-bash-version
source "${OPENIM_ROOT}/scripts/lib/version.sh"
source "${OPENIM_ROOT}/scripts/lib/golang.sh"
. $(dirname ${BASH_SOURCE})/version.sh
. $(dirname ${BASH_SOURCE})/golang.sh
. $(dirname ${BASH_SOURCE})/test.sh
. $(dirname ${BASH_SOURCE})/release.sh
. $(dirname ${BASH_SOURCE})/chat.sh
OPENIM_OUTPUT_HOSTBIN="${OPENIM_OUTPUT_BINPATH}/$(openim::util::host_platform)"
export OPENIM_OUTPUT_HOSTBIN
export OPENIM_NONSERVER_GROUP_VERSIONS
# This emulates "readlink -f" which is not available on MacOS X.
# Test:
# T=/tmp/$$.$RANDOM
# mkdir $T
# touch $T/file
# mkdir $T/dir
# ln -s $T/file $T/linkfile
# ln -s $T/dir $T/linkdir
# function testone() {
# X=$(readlink -f $1 2>&1)
# Y=$(kube::readlinkdashf $1 2>&1)
# if [ "$X" != "$Y" ]; then
# echo readlinkdashf $1: expected "$X", got "$Y"
# fi
# }
# testone /
# testone /tmp
# testone $T
# testone $T/file
# testone $T/dir
# testone $T/linkfile
# testone $T/linkdir
# testone $T/nonexistant
# testone $T/linkdir/file
# testone $T/linkdir/dir
# testone $T/linkdir/linkfile
# testone $T/linkdir/linkdir
function openim::readlinkdashf {
# run in a subshell for simpler 'cd'
(
if [[ -d "${1}" ]]; then # This also catch symlinks to dirs.
cd "${1}"
pwd -P
else
cd "$(dirname "${1}")"
local f
f=$(basename "${1}")
if [[ -L "${f}" ]]; then
readlink "${f}"
else
echo "$(pwd -P)/${f}"
fi
fi
)
}
# This emulates "readlink -f" which is not available on MacOS X.
# Test:
# T=/tmp/$$.$RANDOM
# mkdir $T
# touch $T/file
# mkdir $T/dir
# ln -s $T/file $T/linkfile
# ln -s $T/dir $T/linkdir
# function testone() {
# X=$(readlink -f $1 2>&1)
# Y=$(kube::readlinkdashf $1 2>&1)
# if [ "$X" != "$Y" ]; then
# echo readlinkdashf $1: expected "$X", got "$Y"
# fi
# }
# testone /
# testone /tmp
# testone $T
# testone $T/file
# testone $T/dir
# testone $T/linkfile
# testone $T/linkdir
# testone $T/nonexistant
# testone $T/linkdir/file
# testone $T/linkdir/dir
# testone $T/linkdir/linkfile
# testone $T/linkdir/linkdir
function openim::readlinkdashf {
# run in a subshell for simpler 'cd'
(
if [[ -d "${1}" ]]; then # This also catch symlinks to dirs.
cd "${1}"
pwd -P
else
cd "$(dirname "${1}")"
local f
f=$(basename "${1}")
if [[ -L "${f}" ]]; then
readlink "${f}"
else
echo "$(pwd -P)/${f}"
fi
fi
)
}
# This emulates "realpath" which is not available on MacOS X
# Test:
# T=/tmp/$$.$RANDOM
# mkdir $T
# touch $T/file
# mkdir $T/dir
# ln -s $T/file $T/linkfile
# ln -s $T/dir $T/linkdir
# function testone() {
# X=$(realpath $1 2>&1)
# Y=$(kube::realpath $1 2>&1)
# if [ "$X" != "$Y" ]; then
# echo realpath $1: expected "$X", got "$Y"
# fi
# }
# testone /
# testone /tmp
# testone $T
# testone $T/file
# testone $T/dir
# testone $T/linkfile
# testone $T/linkdir
# testone $T/nonexistant
# testone $T/linkdir/file
# testone $T/linkdir/dir
# testone $T/linkdir/linkfile
# testone $T/linkdir/linkdir
openim::realpath() {
if [[ ! -e "${1}" ]]; then
echo "${1}: No such file or directory" >&2
return 1
fi
openim::readlinkdashf "${1}"
}
# Marker function to indicate init.sh has been fully sourced
openim::init::loaded() {
return 0
}
+3 -2
View File
@@ -38,6 +38,7 @@ readonly RELEASE_IMAGES="${LOCAL_OUTPUT_ROOT}/release-images"
# OpenIM github account info
readonly OPENIM_GITHUB_ORG=OpenIMSDK
readonly OPENIM_GITHUB_REPO=Open-IM-Server
readonly CHAT_GITHUB_REPO=chat
readonly ARTIFACT=openim.tar.gz
readonly CHECKSUM=${ARTIFACT}.sha1sum
@@ -143,8 +144,8 @@ function openim::release::package_src_tarball() {
-path "${OPENIM_ROOT}"/.config\* -o \
-path "${OPENIM_ROOT}"/.chglog\* -o \
-path "${OPENIM_ROOT}"/.gitlint -o \
-path "${OPENIM_ROOT}"/.golangci.yml -o \
-path "${OPENIM_ROOT}"/.goreleaser.yml -o \
-path "${OPENIM_ROOT}"/scripts/golangci.yml -o \
-path "${OPENIM_ROOT}"/build/goreleaser.yaml -o \
-path "${OPENIM_ROOT}"/.note.md -o \
-path "${OPENIM_ROOT}"/.todo.md \
\) -prune \
+561
View File
@@ -0,0 +1,561 @@
#!/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.
# A set of helpers for tests
openim::test::clear_all() {
if openim::test::if_supports_resource "rc" ; then
# shellcheck disable=SC2154
# Disabling because "kube_flags" is set in a parent script
kubectl delete "${kube_flags[@]}" rc --all --grace-period=0 --force
fi
if openim::test::if_supports_resource "pods" ; then
kubectl delete "${kube_flags[@]}" pods --all --grace-period=0 --force
fi
}
# Prints the calling file and line number $1 levels deep
# Defaults to 2 levels so you can call this to find your own caller
openim::test::get_caller() {
local levels=${1:-2}
local caller_file="${BASH_SOURCE[${levels}]}"
local caller_line="${BASH_LINENO[${levels}-1]}"
echo "$(basename "${caller_file}"):${caller_line}"
}
# Force exact match of a returned result for a object query. Wrap this with || to support multiple
# valid return types.
# This runs `kubectl get` once and asserts that the result is as expected.
# $1: Object on which get should be run
# $2: The go-template to run on the result
# $3: The expected output
# $4: Additional args to be passed to kubectl
openim::test::get_object_assert() {
openim::test::object_assert 1 "$@"
}
# Asserts that the output of a given get query is as expected.
# Runs the query multiple times before failing it.
# $1: Object on which get should be run
# $2: The go-template to run on the result
# $3: The expected output
# $4: Additional args to be passed to kubectl
openim::test::wait_object_assert() {
openim::test::object_assert 10 "$@"
}
# Asserts that the output of a given get query is as expected.
# Can run the query multiple times before failing it.
# $1: Number of times the query should be run before failing it.
# $2: Object on which get should be run
# $3: The go-template to run on the result
# $4: The expected output
# $5: Additional args to be passed to kubectl
openim::test::object_assert() {
local tries=$1
local object=$2
local request=$3
local expected=$4
local args=${5:-}
for j in $(seq 1 "${tries}"); do
# shellcheck disable=SC2086
# Disabling because to allow for expansion here
res=$(kubectl get "${kube_flags[@]}" ${args} ${object} -o go-template="${request}")
if [[ "${res}" =~ ^$expected$ ]]; then
echo -n "${green}"
echo "$(openim::test::get_caller 3): Successful get ${object} ${request}: ${res}"
echo -n "${reset}"
return 0
fi
echo "Waiting for Get ${object} ${request} ${args}: expected: ${expected}, got: ${res}"
sleep $((j-1))
done
echo "${bold}${red}"
echo "$(openim::test::get_caller 3): FAIL!"
echo "Get ${object} ${request}"
echo " Expected: ${expected}"
echo " Got: ${res}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
}
openim::test::get_object_jsonpath_assert() {
local object=$1
local request=$2
local expected=$3
# shellcheck disable=SC2086
# Disabling to allow for expansion here
res=$(kubectl get "${kube_flags[@]}" ${object} -o jsonpath=${request})
if [[ "${res}" =~ ^$expected$ ]]; then
echo -n "${green}"
echo "$(openim::test::get_caller): Successful get ${object} ${request}: ${res}"
echo -n "${reset}"
return 0
else
echo "${bold}${red}"
echo "$(openim::test::get_caller): FAIL!"
echo "Get ${object} ${request}"
echo " Expected: ${expected}"
echo " Got: ${res}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
}
openim::test::describe_object_assert() {
local resource=$1
local object=$2
local matches=( "${@:3}" )
# shellcheck disable=SC2086
# Disabling to allow for expansion here
result=$(kubectl describe "${kube_flags[@]}" ${resource} ${object})
for match in "${matches[@]}"; do
if grep -q "${match}" <<< "${result}"; then
echo "matched ${match}"
else
echo "${bold}${red}"
echo "$(openim::test::get_caller): FAIL!"
echo "Describe ${resource} ${object}"
echo " Expected Match: ${match}"
echo " Not found in:"
echo "${result}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
done
echo -n "${green}"
echo "$(openim::test::get_caller): Successful describe ${resource} ${object}:"
echo "${result}"
echo -n "${reset}"
return 0
}
openim::test::describe_object_events_assert() {
local resource=$1
local object=$2
local showevents=${3:-"true"}
# shellcheck disable=SC2086
# Disabling to allow for expansion here
if [[ -z "${3:-}" ]]; then
result=$(kubectl describe "${kube_flags[@]}" ${resource} ${object})
else
result=$(kubectl describe "${kube_flags[@]}" "--show-events=${showevents}" ${resource} ${object})
fi
if grep -q "No events.\|Events:" <<< "${result}"; then
local has_events="true"
else
local has_events="false"
fi
if [[ "${showevents}" == "${has_events}" ]]; then
echo -n "${green}"
echo "$(openim::test::get_caller): Successful describe"
echo "${result}"
echo "${reset}"
return 0
else
echo "${bold}${red}"
echo "$(openim::test::get_caller): FAIL"
if [[ "${showevents}" == "false" ]]; then
echo " Events information should not be described in:"
else
echo " Events information not found in:"
fi
echo "${result}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
}
openim::test::describe_resource_assert() {
local resource=$1
local matches=( "${@:2}" )
# shellcheck disable=SC2086
# Disabling to allow for expansion here
result=$(kubectl describe "${kube_flags[@]}" ${resource})
for match in "${matches[@]}"; do
if grep -q "${match}" <<< "${result}"; then
echo "matched ${match}"
else
echo "${bold}${red}"
echo "FAIL!"
echo "Describe ${resource}"
echo " Expected Match: ${match}"
echo " Not found in:"
echo "${result}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
done
echo -n "${green}"
echo "Successful describe ${resource}:"
echo "${result}"
echo -n "${reset}"
return 0
}
openim::test::describe_resource_events_assert() {
local resource=$1
local showevents=${2:-"true"}
# shellcheck disable=SC2086
# Disabling to allow for expansion here
result=$(kubectl describe "${kube_flags[@]}" "--show-events=${showevents}" ${resource})
if grep -q "No events.\|Events:" <<< "${result}"; then
local has_events="true"
else
local has_events="false"
fi
if [[ "${showevents}" == "${has_events}" ]]; then
echo -n "${green}"
echo "Successful describe"
echo "${result}"
echo -n "${reset}"
return 0
else
echo "${bold}${red}"
echo "FAIL"
if [[ "${showevents}" == "false" ]]; then
echo " Events information should not be described in:"
else
echo " Events information not found in:"
fi
echo "${result}"
caller
echo "${reset}"
return 1
fi
}
openim::test::describe_resource_chunk_size_assert() {
# $1: the target resource
local resource=$1
# $2: comma-separated list of additional resources that will be listed
local additionalResources=${2:-}
# Remaining args are flags to pass to kubectl
local args=${3:-}
# Expect list requests for the target resource and the additional resources
local expectLists
IFS="," read -r -a expectLists <<< "${resource},${additionalResources}"
# shellcheck disable=SC2086
# Disabling to allow for expansion here
defaultResult=$(kubectl describe ${resource} --show-events=true -v=6 ${args} "${kube_flags[@]}" 2>&1 >/dev/null)
for r in "${expectLists[@]}"; do
if grep -q "${r}?.*limit=500" <<< "${defaultResult}"; then
echo "query for ${r} had limit param"
else
echo "${bold}${red}"
echo "FAIL!"
echo "Describe ${resource}"
echo " Expected limit param on request for: ${r}"
echo " Not found in:"
echo "${defaultResult}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
done
# shellcheck disable=SC2086
# Disabling to allow for expansion here
# Try a non-default chunk size
customResult=$(kubectl describe ${resource} --show-events=false --chunk-size=10 -v=6 ${args} "${kube_flags[@]}" 2>&1 >/dev/null)
if grep -q "${resource}?limit=10" <<< "${customResult}"; then
echo "query for ${resource} had user-specified limit param"
else
echo "${bold}${red}"
echo "FAIL!"
echo "Describe ${resource}"
echo " Expected limit param on request for: ${r}"
echo " Not found in:"
echo "${customResult}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
echo -n "${green}"
echo "Successful describe ${resource} verbose logs:"
echo "${defaultResult}"
echo -n "${reset}"
return 0
}
# Compare sort-by resource name output (first column, skipping first line) with expected order specify in the last parameter
openim::test::if_sort_by_has_correct_order() {
local var
var="$(echo "$1" | awk '{if(NR!=1) print $1}' | tr '\n' ':')"
openim::test::if_has_string "${var}" "${@:$#}"
}
openim::test::if_has_string() {
local message=$1
local match=$2
if grep -q "${match}" <<< "${message}"; then
echo -n "${green}"
echo "Successful"
echo -n "${reset}"
echo "message:${message}"
echo "has:${match}"
return 0
else
echo -n "${bold}${red}"
echo "FAIL!"
echo -n "${reset}"
echo "message:${message}"
echo "has not:${match}"
caller
return 1
fi
}
openim::test::if_has_not_string() {
local message=$1
local match=$2
if grep -q "${match}" <<< "${message}"; then
echo -n "${bold}${red}"
echo "FAIL!"
echo -n "${reset}"
echo "message:${message}"
echo "has:${match}"
caller
return 1
else
echo -n "${green}"
echo "Successful"
echo -n "${reset}"
echo "message:${message}"
echo "has not:${match}"
return 0
fi
}
openim::test::if_empty_string() {
local match=$1
if [ -n "${match}" ]; then
echo -n "${bold}${red}"
echo "FAIL!"
echo "${match} is not empty"
echo -n "${reset}"
caller
return 1
else
echo -n "${green}"
echo "Successful"
echo -n "${reset}"
return 0
fi
}
# Returns true if the required resource is part of supported resources.
# Expects env vars:
# SUPPORTED_RESOURCES: Array of all resources supported by the apiserver. "*"
# means it supports all resources. For ex: ("*") or ("rc" "*") both mean that
# all resources are supported.
# $1: Name of the resource to be tested.
openim::test::if_supports_resource() {
SUPPORTED_RESOURCES=${SUPPORTED_RESOURCES:-""}
REQUIRED_RESOURCE=${1:-""}
for r in "${SUPPORTED_RESOURCES[@]}"; do
if [[ "${r}" == "*" || "${r}" == "${REQUIRED_RESOURCE}" ]]; then
return 0
fi
done
return 1
}
openim::test::version::object_to_file() {
name=$1
flags=${2:-""}
file=$3
# shellcheck disable=SC2086
# Disabling because "flags" needs to allow for expansion here
kubectl version ${flags} | grep "${name} Version:" | sed -e s/"${name} Version: "/""/g > "${file}"
}
openim::test::version::json_object_to_file() {
flags=$1
file=$2
# shellcheck disable=SC2086
# Disabling because "flags" needs to allow for expansion here
kubectl version ${flags} --output json | sed -e s/' '/''/g -e s/'\"'/''/g -e s/'}'/''/g -e s/'{'/''/g -e s/'clientVersion:'/'clientVersion:,'/ -e s/'serverVersion:'/'serverVersion:,'/ | tr , '\n' > "${file}"
}
openim::test::version::json_client_server_object_to_file() {
flags=$1
name=$2
file=$3
# shellcheck disable=SC2086
# Disabling because "flags" needs to allow for expansion here
kubectl version ${flags} --output json | jq -r ".${name}" | sed -e s/'\"'/''/g -e s/'}'/''/g -e s/'{'/''/g -e /^$/d -e s/','/''/g -e s/':'/'='/g > "${file}"
}
openim::test::version::yaml_object_to_file() {
flags=$1
file=$2
# shellcheck disable=SC2086
# Disabling because "flags" needs to allow for expansion here
kubectl version ${flags} --output yaml | sed -e s/' '/''/g -e s/'\"'/''/g -e /^$/d > "${file}"
}
openim::test::version::diff_assert() {
local original=$1
local comparator=${2:-"eq"}
local latest=$3
local diff_msg=${4:-""}
local res=""
if [ ! -f "${original}" ]; then
echo "${bold}${red}"
echo "FAIL! ${diff_msg}"
echo "the file '${original}' does not exit"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
if [ ! -f "${latest}" ]; then
echo "${bold}${red}"
echo "FAIL! ${diff_msg}"
echo "the file '${latest}' does not exit"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
if [ "${comparator}" == "exact" ]; then
# Skip sorting of file content for exact comparison.
cp "${original}" "${original}.sorted"
cp "${latest}" "${latest}.sorted"
else
sort "${original}" > "${original}.sorted"
sort "${latest}" > "${latest}.sorted"
fi
if [ "${comparator}" == "eq" ] || [ "${comparator}" == "exact" ]; then
if [ "$(diff -iwB "${original}".sorted "${latest}".sorted)" == "" ] ; then
echo -n "${green}"
echo "Successful: ${diff_msg}"
echo -n "${reset}"
return 0
else
echo "${bold}${red}"
echo "FAIL! ${diff_msg}"
echo " Expected: "
cat "${original}"
echo " Got: "
cat "${latest}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
else
if [ -n "$(diff -iwB "${original}".sorted "${latest}".sorted)" ] ; then
echo -n "${green}"
echo "Successful: ${diff_msg}"
echo -n "${reset}"
return 0
else
echo "${bold}${red}"
echo "FAIL! ${diff_msg}"
echo " Expected: "
cat "${original}"
echo " Got: "
cat "${latest}"
echo "${reset}${red}"
caller
echo "${reset}"
return 1
fi
fi
}
# Force exact match of kubectl stdout, stderr, and return code.
# $1: file with actual stdout
# $2: file with actual stderr
# $3: the actual return code
# $4: file with expected stdout
# $5: file with expected stderr
# $6: expected return code
# $7: additional message describing the invocation
openim::test::results::diff() {
local actualstdout=$1
local actualstderr=$2
local actualcode=$3
local expectedstdout=$4
local expectedstderr=$5
local expectedcode=$6
local message=$7
local result=0
if ! openim::test::version::diff_assert "${expectedstdout}" "exact" "${actualstdout}" "stdout for ${message}"; then
result=1
fi
if ! openim::test::version::diff_assert "${expectedstderr}" "exact" "${actualstderr}" "stderr for ${message}"; then
result=1
fi
if [ "${actualcode}" -ne "${expectedcode}" ]; then
echo "${bold}${red}"
echo "$(openim::test::get_caller): FAIL!"
echo "Return code for ${message}"
echo " Expected: ${expectedcode}"
echo " Got: ${actualcode}"
echo "${reset}${red}"
caller
echo "${reset}"
result=1
fi
if [ "${result}" -eq 0 ]; then
echo -n "${green}"
echo "$(openim::test::get_caller): Successful: ${message}"
echo -n "${reset}"
fi
return "$result"
}
+228 -3
View File
@@ -13,6 +13,70 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# this script is used to check whether the code is formatted by gofmt or not
#
# Usage: source scripts/lib/util.sh
################################################################################
#1、将IP写在一个文件里,比如文件名为hosts_file,一行一个IP地址。
#2、修改ssh-mutual-trust.sh里面的用户名及密码,默认为root用户及密码123。
# hosts_file_path="path/to/your/hosts/file"
# openim:util::setup_ssh_key_copy "$hosts_file_path" "root" "123"
function openim:util::setup_ssh_key_copy() {
local hosts_file="$1"
local username="${2:-root}"
local password="${3:-123}"
local sshkey_file=~/.ssh/id_rsa.pub
# check sshkey file
if [[ ! -e $sshkey_file ]]; then
expect -c "
spawn ssh-keygen -t rsa
expect \"Enter*\" { send \"\n\"; exp_continue; }
"
fi
# get hosts list
local hosts=$(awk '/^[^#]/ {print $1}' "${hosts_file}")
ssh_key_copy() {
local target=$1
# delete history
sed -i "/$target/d" ~/.ssh/known_hosts
# copy key
expect -c "
set timeout 100
spawn ssh-copy-id $username@$target
expect {
\"yes/no\" { send \"yes\n\"; exp_continue; }
\"*assword\" { send \"$password\n\"; }
\"already exist on the remote system\" { exit 1; }
}
expect eof
"
}
# auto sshkey pair
for host in $hosts; do
if ! ping -i 0.2 -c 3 -W 1 "$host" > /dev/null 2>&1; then
echo "[ERROR]: Can't connect $host"
continue
fi
local host_entry=$(awk "/$host/"'{print $1, $2}' /etc/hosts)
if [[ $host_entry ]]; then
local hostaddr=$(echo "$host_entry" | awk '{print $1}')
local hostname=$(echo "$host_entry" | awk '{print $2}')
ssh_key_copy "$hostaddr"
ssh_key_copy "$hostname"
else
ssh_key_copy "$host"
fi
done
}
function openim::util::sourced_variable {
# Call this function to tell shellcheck that a variable is supposed to
@@ -616,6 +680,50 @@ function openim::util::ensure-cfssl {
popd > /dev/null || return 1
}
# openim::util::ensure-docker-buildx
# Check if we have "docker buildx" commands available
#
function openim::util::ensure-docker-buildx {
# podman returns 0 on `docker buildx version`, docker on `docker buildx`. One of them must succeed.
if docker buildx version >/dev/null 2>&1 || docker buildx >/dev/null 2>&1; then
return 0
else
echo "ERROR: docker buildx not available. Docker 19.03 or higher is required with experimental features enabled"
exit 1
fi
}
# openim::util::ensure-bash-version
# Check if we are using a supported bash version
#
function openim::util::ensure-bash-version {
# shellcheck disable=SC2004
if ((${BASH_VERSINFO[0]}<4)) || ( ((${BASH_VERSINFO[0]}==4)) && ((${BASH_VERSINFO[1]}<2)) ); then
echo "ERROR: This script requires a minimum bash version of 4.2, but got version of ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"
if [ "$(uname)" = 'Darwin' ]; then
echo "On macOS with homebrew 'brew install bash' is sufficient."
fi
exit 1
fi
}
# openim::util::ensure-install-nginx
# Check if nginx is installed
#
function openim::util::ensure-install-nginx {
if ! command -v nginx &>/dev/null; then
echo "ERROR: nginx not found. Please install nginx."
exit 1
fi
for port in 80
do
if echo |telnet 127.0.0.1 $port 2>&1|grep refused &>/dev/null;then
exit 1
fi
done
}
# openim::util::ensure-gnu-sed
# Determines which sed binary is gnu-sed on linux/darwin
#
@@ -637,6 +745,26 @@ function openim::util::ensure-gnu-sed {
openim::util::sourced_variable "${SED}"
}
# openim::util::ensure-gnu-date
# Determines which date binary is gnu-date on linux/darwin
#
# Sets:
# DATE: The name of the gnu-date binary
#
function openim::util::ensure-gnu-date {
# NOTE: the echo below is a workaround to ensure date is executed before the grep.
date_help="$(LANG=C date --help 2>&1 || true)"
if echo "${date_help}" | grep -q "GNU\|BusyBox"; then
DATE="date"
elif command -v gdate &>/dev/null; then
DATE="gdate"
else
openim::log::error "Failed to find GNU date as date or gdate. If you are on Mac: brew install coreutils." >&2
return 1
fi
openim::util::sourced_variable "${DATE}"
}
# openim::util::check-file-in-alphabetical-order <file>
# Check that the file is in alphabetical order
#
@@ -710,12 +838,69 @@ fi
# ex: ts=2 sw=2 et filetype=sh
function openim::util::desc() {
openim::util:run::maybe_first_prompt
rate=25
if [ -n "$DEMO_RUN_FAST" ]; then
rate=1000
fi
echo "$blue# $@$reset" | pv -qL $rate
openim::util:run::prompt
}
function openim::util:run::prompt() {
echo -n "$yellow\$ $reset"
}
started=""
function openim::util:run::maybe_first_prompt() {
if [ -z "$started" ]; then
openim::util:run::prompt
started=true
fi
}
# After a `run` this variable will hold the stdout of the command that was run.
# If the command was interactive, this will likely be garbage.
DEMO_RUN_STDOUT=""
function openim::util::run() {
openim::util:run::maybe_first_prompt
rate=25
if [ -n "$DEMO_RUN_FAST" ]; then
rate=1000
fi
echo "$green$1$reset" | pv -qL $rate
if [ -n "$DEMO_RUN_FAST" ]; then
sleep 0.5
fi
OFILE="$(mktemp -t $(basename $0).XXXXXX)"
if [ "$(uname)" == "Darwin" ]; then
script -q "$OFILE" $1
else
script -eq -c "$1" -f "$OFILE"
fi
r=$?
read -d '' -t "${timeout}" -n 10000 # clear stdin
openim::util:run::prompt
if [ -z "$DEMO_AUTO_RUN" ]; then
read -s
fi
DEMO_RUN_STDOUT="$(tail -n +2 $OFILE | sed 's/\r//g')"
return $r
}
function openim::util::run::relative() {
for arg; do
echo "$(realpath $(dirname $(which $0)))/$arg" | sed "s|$(realpath $(pwd))|.|"
done
}
# input: [10023, 2323, 3434]
# output: 10023 2323 3434
# Function function: Converts a list to a string, removing Spaces and parentheses
function list_to_string() {
function openim::util::list-to-string() {
ports_list=$* # 获取传入的参数列表
sub_s1=$(echo $ports_list | sed 's/ //g') # 去除空格
sub_s2=${sub_s1//,/ } # 将逗号替换为空格
@@ -725,7 +910,47 @@ function list_to_string() {
}
# Function Function: Remove Spaces in the string
function remove_space() {
function openim::util::remove_space() {
value=$* # 获取传入的参数
result=$(echo $value | sed 's/ //g') # 去除空格
}
function openim::util::gen_os_arch() {
# Get the current operating system and architecture
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
# Select the repository home directory based on the operating system and architecture
if [[ "$OS" == "darwin" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
REPO_DIR="darwin/amd64"
else
REPO_DIR="darwin/386"
fi
elif [[ "$OS" == "linux" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
REPO_DIR="linux/amd64"
elif [[ "$ARCH" == "arm64" ]]; then
REPO_DIR="linux/arm64"
elif [[ "$ARCH" == "mips64" ]]; then
REPO_DIR="linux/mips64"
elif [[ "$ARCH" == "mips64le" ]]; then
REPO_DIR="linux/mips64le"
elif [[ "$ARCH" == "ppc64le" ]]; then
REPO_DIR="linux/ppc64le"
elif [[ "$ARCH" == "s390x" ]]; then
REPO_DIR="linux/s390x"
else
REPO_DIR="linux/386"
fi
elif [[ "$OS" == "windows" ]]; then
if [[ "$ARCH" == "x86_64" ]]; then
REPO_DIR="windows/amd64"
else
REPO_DIR="windows/386"
fi
else
echo -e "${RED_PREFIX}Unsupported OS: $OS${COLOR_SUFFIX}"
exit 1
fi
}

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