diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 000000000..b97036d91 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,78 @@ +name: Release Changelog + +on: + release: + types: [released] + +permissions: + contents: write + pull-requests: write + +jobs: + update-changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Go Changelog Generator + run: | + # Run the Go changelog generator, passing the release tag if available + if [ "${{ github.event.release.tag_name }}" = "latest" ]; then + go run tools/changelog/changelog.go > "${{ github.event.release.tag_name }}-changelog.md" + else + go run tools/changelog/changelog.go "${{ github.event.release.tag_name }}" > "${{ github.event.release.tag_name }}-changelog.md" + fi + + - name: Handle changelog files + run: | + # Ensure that the CHANGELOG directory exists + mkdir -p CHANGELOG + + # Extract Major.Minor version by removing the 'v' prefix from the tag name + TAG_NAME=${{ github.event.release.tag_name }} + CHANGELOG_VERSION_NUMBER=$(echo "$TAG_NAME" | sed 's/^v//' | grep -oP '^\d+\.\d+') + + # Define the new changelog file path + CHANGELOG_FILENAME="CHANGELOG-$CHANGELOG_VERSION_NUMBER.md" + CHANGELOG_PATH="CHANGELOG/$CHANGELOG_FILENAME" + + # Check if the changelog file for the current release already exists + if [ -f "$CHANGELOG_PATH" ]; then + # If the file exists, append the new changelog to the existing one + cat "$CHANGELOG_PATH" >> "${TAG_NAME}-changelog.md" + # Overwrite the existing changelog with the updated content + mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH" + else + # If the changelog file doesn't exist, rename the temp changelog file to the new changelog file + mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH" + + # Ensure that README.md exists + if [ ! -f "CHANGELOG/README.md" ]; then + echo -e "# CHANGELOGs\n\n" > CHANGELOG/README.md + fi + + # Add the new changelog entry at the top of the README.md + if ! grep -q "\[$CHANGELOG_FILENAME\]" CHANGELOG/README.md; then + sed -i "3i- [$CHANGELOG_FILENAME](./$CHANGELOG_FILENAME)" CHANGELOG/README.md + # Remove the extra newline character added by sed + # sed -i '4d' CHANGELOG/README.md + fi + fi + + - name: Clean up + run: | + # Remove any temporary files that were created during the process + rm -f "${{ github.event.release.tag_name }}-changelog.md" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" + title: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" + body: "This PR updates the CHANGELOG files for release ${{ github.event.release.tag_name }}" + branch: changelog-${{ github.event.release.tag_name }} + base: main + delete-branch: true + labels: changelog diff --git a/.github/workflows/cleanup-after-milestone-prs-merged.yml b/.github/workflows/cleanup-after-milestone-prs-merged.yml new file mode 100644 index 000000000..4e9cc403d --- /dev/null +++ b/.github/workflows/cleanup-after-milestone-prs-merged.yml @@ -0,0 +1,65 @@ +name: Cleanup After Milestone PRs Merged + +on: + pull_request: + types: + - closed + +jobs: + handle_pr: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Get the PR title and extract PR numbers + id: extract_pr_numbers + run: | + # Get the PR title + PR_TITLE="${{ github.event.pull_request.title }}" + + echo "PR Title: $PR_TITLE" + + # Extract PR numbers from the title + PR_NUMBERS=$(echo "$PR_TITLE" | grep -oE "#[0-9]+" | tr -d '#' | tr '\n' ' ') + echo "Extracted PR Numbers: $PR_NUMBERS" + + # Save PR numbers to a file + echo "$PR_NUMBERS" > pr_numbers.txt + echo "Saved PR Numbers to pr_numbers.txt" + + # Check if the title matches a specific pattern + if echo "$PR_TITLE" | grep -qE "^deps: Merge( #[0-9]+)+ PRs into .+"; then + echo "proceed=true" >> $GITHUB_OUTPUT + else + echo "proceed=false" >> $GITHUB_OUTPUT + fi + + - name: Delete branch after PR close + if: steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge') + run: | + BRANCH_NAME="${{ github.event.pull_request.head.ref }}" + echo "Branch to delete: $BRANCH_NAME" + git push origin --delete "$BRANCH_NAME" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Use extracted PR numbers and label PRs + if: (steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge')) && github.event.pull_request.merged == true + run: | + # Read the previously saved PR numbers + PR_NUMBERS=$(cat pr_numbers.txt) + echo "Using extracted PR Numbers: $PR_NUMBERS" + + # Loop through each PR number and add label + for PR_NUMBER in $PR_NUMBERS; do + echo "Adding 'cherry-picked' label to PR #$PR_NUMBER" + curl -X POST \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels \ + -d '{"labels":["cherry-picked"]}' + done + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/merge-from-milestone.yml b/.github/workflows/merge-from-milestone.yml new file mode 100644 index 000000000..d9110b0c3 --- /dev/null +++ b/.github/workflows/merge-from-milestone.yml @@ -0,0 +1,221 @@ +name: Create Pre-Release PR from Milestone + +permissions: + contents: write + pull-requests: write + issues: write + +on: + workflow_dispatch: + inputs: + milestone_name: + description: 'Milestone name to collect closed PRs from' + required: true + default: 'v3.8.2' + target_branch: + description: 'Target branch to merge the consolidated PR' + required: true + default: 'pre-release-v3.8.2' + + schedule: + - cron: '0 2 * * 0' + +env: + MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v3.8.2' }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v3.8.2' }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + LABEL_NAME: cherry-picked + TEMP_DIR: /tmp # Using /tmp as the temporary directory + +jobs: + cherry_pick_milestone_prs: + runs-on: ubuntu-latest + steps: + - name: Setup temp directory + run: | + # Create the temporary directory and initialize necessary files + mkdir -p ${{ env.TEMP_DIR }} + touch ${{ env.TEMP_DIR }}/pr_numbers.txt + touch ${{ env.TEMP_DIR }}/commit_hashes.txt + touch ${{ env.TEMP_DIR }}/pr_title.txt + touch ${{ env.TEMP_DIR }}/pr_body.txt + touch ${{ env.TEMP_DIR }}/created_pr_number.txt + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.BOT_TOKEN }} + + - name: Setup Git User for OpenIM-Robot + run: | + # Set up Git credentials for the bot + git config --global user.email "OpenIM-Robot@users.noreply.github.com" + git config --global user.name "OpenIM-Robot" + + - name: Fetch Milestone ID and Filter PR Numbers + env: + MILESTONE_NAME: ${{ env.MILESTONE_NAME }} + run: | + # Fetch milestone details and extract milestone ID + milestones=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/milestones") + milestone_id=$(echo "$milestones" | grep -B3 "\"title\": \"$MILESTONE_NAME\"" | grep '"number":' | head -n1 | grep -o '[0-9]\+') + if [ -z "$milestone_id" ]; then + echo "Milestone '$MILESTONE_NAME' not found. Exiting." + exit 1 + fi + echo "Milestone ID: $milestone_id" + echo "MILESTONE_ID=$milestone_id" >> $GITHUB_ENV + + # Fetch issues for the milestone + issues=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/issues?milestone=$milestone_id&state=closed&per_page=100") + + > ${{ env.TEMP_DIR }}/pr_numbers.txt + + # Filter PRs that do not have the 'cherry-picked' label + for pr_number in $(echo "$issues" | jq -r '.[] | select(.pull_request != null) | .number'); do + labels=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" | jq -r '.[].name') + + if ! echo "$labels" | grep -q "${LABEL_NAME}"; then + echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list." + echo "$pr_number" >> ${{ env.TEMP_DIR }}/pr_numbers.txt + else + echo "PR #$pr_number already has the 'cherry-picked' label. Skipping." + fi + done + + # Sort the filtered PR numbers + sort -n ${{ env.TEMP_DIR }}/pr_numbers.txt -o ${{ env.TEMP_DIR }}/pr_numbers.txt + + echo "Filtered and sorted PR numbers:" + cat ${{ env.TEMP_DIR }}/pr_numbers.txt || echo "No closed PR numbers found for milestone." + + - name: Fetch Merge Commits for PRs and Generate Title and Body + run: | + # Ensure the files are initialized + > ${{ env.TEMP_DIR }}/commit_hashes.txt + > ${{ env.TEMP_DIR }}/pr_title.txt + > ${{ env.TEMP_DIR }}/pr_body.txt + + # Write description to the PR body + echo "### Description:" >> ${{ env.TEMP_DIR }}/pr_body.txt + echo "Merging PRs from milestone \`$MILESTONE_NAME\` into target branch \`$TARGET_BRANCH\`." >> ${{ env.TEMP_DIR }}/pr_body.txt + echo "" >> ${{ env.TEMP_DIR }}/pr_body.txt + echo "### Need Merge PRs:" >> ${{ env.TEMP_DIR }}/pr_body.txt + + pr_numbers_in_title="" + + # Process sorted PR numbers and generate commit hashes + for pr_number in $(cat ${{ env.TEMP_DIR }}/pr_numbers.txt); do + echo "Processing PR #$pr_number" + pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number") + pr_title=$(echo "$pr_details" | jq -r '.title') + merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha') + short_commit_hash=$(echo "$merge_commit" | cut -c 1-7) + + # Append PR details to the body + echo "- $pr_title: (#$pr_number) ($short_commit_hash)" >> ${{ env.TEMP_DIR }}/pr_body.txt + + if [ "$merge_commit" != "null" ];then + echo "$merge_commit" >> ${{ env.TEMP_DIR }}/commit_hashes.txt + echo "#$pr_number" >> ${{ env.TEMP_DIR }}/pr_title.txt + pr_numbers_in_title="$pr_numbers_in_title #$pr_number" + fi + done + + commit_hashes=$(cat ${{ env.TEMP_DIR }}/commit_hashes.txt | tr '\n' ' ') + first_commit_hash=$(head -n 1 ${{ env.TEMP_DIR }}/commit_hashes.txt) + cherry_pick_branch="cherry-pick-${first_commit_hash:0:7}" + echo "COMMIT_HASHES=$commit_hashes" >> $GITHUB_ENV + echo "CHERRY_PICK_BRANCH=$cherry_pick_branch" >> $GITHUB_ENV + echo "pr_numbers_in_title=$pr_numbers_in_title" >> $GITHUB_ENV + + - name: Pull and Cherry-pick Commits, Then Push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + # Fetch and pull the latest changes from the target branch + git fetch origin + git checkout $TARGET_BRANCH + git pull origin $TARGET_BRANCH + + # Create a new branch for cherry-picking + git checkout -b $CHERRY_PICK_BRANCH + + # Cherry-pick the commits and handle conflicts + for commit_hash in $COMMIT_HASHES; do + echo "Attempting to cherry-pick commit $commit_hash" + if ! git cherry-pick "$commit_hash" --strategy=recursive -X theirs; then + echo "Conflict detected for $commit_hash. Resolving with incoming changes." + conflict_files=$(git diff --name-only --diff-filter=U) + echo "Conflicting files:" + echo "$conflict_files" + + for file in $conflict_files; do + if [ -f "$file" ]; then + echo "Resolving conflict for $file" + git add "$file" + else + echo "File $file has been deleted. Skipping." + git rm "$file" + fi + done + + echo "Conflicts resolved. Continuing cherry-pick." + git cherry-pick --continue + else + echo "Cherry-pick successful for commit $commit_hash." + fi + done + + # Push the cherry-pick branch to the repository + git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git" + git push origin $CHERRY_PICK_BRANCH --force + + - name: Create Pull Request + run: | + # Prepare and create the PR + pr_title="deps: Merge ${{ env.pr_numbers_in_title }} PRs into $TARGET_BRANCH" + pr_body=$(cat ${{ env.TEMP_DIR }}/pr_body.txt) + + echo "Prepared PR title:" + echo "$pr_title" + echo "Prepared PR body:" + echo "$pr_body" + + # Create the PR using the GitHub API + response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pulls \ + -d "$(jq -n --arg title "$pr_title" \ + --arg head "$CHERRY_PICK_BRANCH" \ + --arg base "$TARGET_BRANCH" \ + --arg body "$pr_body" \ + '{title: $title, head: $head, base: $base, body: $body}')") + + pr_number=$(echo "$response" | jq -r '.number') + echo "$pr_number" > ${{ env.TEMP_DIR }}/created_pr_number.txt + echo "Created PR #$pr_number" + + - name: Add Label to Created Pull Request + run: | + # Add 'milestone-merge' label to the created PR + pr_number=$(cat ${{ env.TEMP_DIR }}/created_pr_number.txt) + echo "Adding label to PR #$pr_number" + + curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -d '{"labels": ["milestone-merge"]}' \ + "https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" + + echo "Added 'milestone-merge' label to PR #$pr_number." diff --git a/.gitignore b/.gitignore index 30e85d286..dff4f47e1 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,6 @@ deploy/Open-IM-SDK-Core # Dependency directories (remove the comment below to include it) vendor/ bin/ -tools/ tmp/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 6209f7dd9..142dd6237 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -8,7 +8,6 @@ before: - go generate ./... - git: # What should be used to sort tags when gathering the current and previous # tags if there are more than one tag in the same commit. @@ -37,7 +36,7 @@ report_sizes: true builds: - id: openIM.wasm main: wasm/cmd/main.go # Specify the path to the main WASM file - binary: openIM.wasm + binary: openIM ldflags: "-s -w" goos: - js @@ -88,39 +87,39 @@ archives: - goos: windows format: zip -changelog: - sort: asc - use: github - filters: - exclude: - - "^test:" - - "^chore" - - "merge conflict" - - Merge pull request - - Merge remote-tracking branch - - Merge branch - - go mod tidy - groups: - - title: Dependency updates - regexp: '^.*?(feat|fix)\(deps\)!?:.+$' - order: 300 - - title: "New Features" - regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$' - order: 100 - - title: "Security updates" - regexp: '^.*?sec(\([[:word:]]+\))??!?:.+$' - order: 150 - - title: "Bug fixes" - regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$' - order: 200 - - title: "Documentation updates" - regexp: ^.*?doc(\([[:word:]]+\))??!?:.+$ - order: 400 - - title: "Build process updates" - regexp: ^.*?build(\([[:word:]]+\))??!?:.+$ - order: 400 - - title: Other work - order: 9999 +# changelog: +# sort: asc +# use: github +# filters: +# exclude: +# - "^test:" +# - "^chore" +# - "merge conflict" +# - Merge pull request +# - Merge remote-tracking branch +# - Merge branch +# - go mod tidy +# groups: +# - title: Dependency updates +# regexp: '^.*?(feat|fix)\(deps\)!?:.+$' +# order: 300 +# - title: "New Features" +# regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$' +# order: 100 +# - title: "Security updates" +# regexp: '^.*?sec(\([[:word:]]+\))??!?:.+$' +# order: 150 +# - title: "Bug fixes" +# regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$' +# order: 200 +# - title: "Documentation updates" +# regexp: ^.*?doc(\([[:word:]]+\))??!?:.+$ +# order: 400 +# - title: "Build process updates" +# regexp: ^.*?build(\([[:word:]]+\))??!?:.+$ +# order: 400 +# - title: Other work +# order: 9999 # nfpms: @@ -167,22 +166,5 @@ dist: ./_output/dist # # Default: '{{ .Tag }}' # name_template: "Current Release" -# publishers: -# - name: "fury.io" -# ids: -# - packages -# dir: "{{ dir .ArtifactPath }}" -# cmd: | -# bash -c ' -# if [[ "{{ .Tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then -# curl -F package=@{{ .ArtifactName }} https://{{ .Env.FURY_TOKEN }}@push.fury.io/{{ .Env.USERNAME }}/ -# else -# echo "Skipping deployment: Non-production release detected" -# fi' - -checksum: - name_template: "{{ .ProjectName }}_checksums.txt" - algorithm: sha256 - release: prerelease: auto diff --git a/CHANGELOG/.chglog/CHANGELOG.tpl.md b/CHANGELOG/.chglog/CHANGELOG.tpl.md deleted file mode 100644 index 100a29ed8..000000000 --- a/CHANGELOG/.chglog/CHANGELOG.tpl.md +++ /dev/null @@ -1,62 +0,0 @@ -# Version logging for OpenIM - - - - - -{{ if .Versions -}} - -## [Unreleased] - -{{ if .Unreleased.CommitGroups -}} -{{ range .Unreleased.CommitGroups -}} -### {{ .Title }} -{{ range .Commits -}} -- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} -{{ end }} -{{ end -}} -{{ end -}} -{{ end -}} - -{{ range .Versions }} - -## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} -{{ range .CommitGroups -}} -### {{ .Title }} -{{ range .Commits -}} -- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} -{{ end }} -{{ end -}} - -{{- if .RevertCommits -}} -### Reverts -{{ range .RevertCommits -}} -- {{ .Revert.Header }} -{{ end }} -{{ end -}} - -{{- if .MergeCommits -}} -### Pull Requests -{{ range .MergeCommits -}} -- {{ .Header }} -{{ end }} -{{ end -}} - -{{- if .NoteGroups -}} -{{ range .NoteGroups -}} -### {{ .Title }} -{{ range .Notes }} -{{ .Body }} -{{ end }} -{{ end -}} -{{ end -}} -{{ end -}} - -{{- if .Versions }} -[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD -{{ range .Versions -}} -{{ if .Tag.Previous -}} -[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} -{{ end -}} -{{ end -}} -{{ end -}} \ No newline at end of file diff --git a/CHANGELOG/.chglog/config.yml b/CHANGELOG/.chglog/config.yml deleted file mode 100644 index 290193082..000000000 --- a/CHANGELOG/.chglog/config.yml +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright © 2023 OpenIM SDK. 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. - -bin: git -style: github -template: CHANGELOG.tpl.md -info: - title: CHANGELOG - repository_url: https://github.com/openimsdk/openim-sdk-core -options: - tag_filter_pattern: '^v' - sort: "date" - - commits: - filters: - Type: - - feat - - fix - - perf - - refactor - - docs - - test - - chore - - ci - - build - sort_by: Scope - - commit_groups: - group_by: Type - sort_by: Title - title_order: - - feat - - fix - - perf - - refactor - - docs - - test - - chore - - ci - - build - title_maps: - feat: Features - - header: - pattern: "" - pattern_maps: - - PropName - - issues: - prefix: - - # - - refs: - actions: - - Closes - - Fixes - - merges: - pattern: "^Merge branch '(\\w+)'$" - pattern_maps: - - Source - - reverts: - pattern: "^Revert \"([\\s\\S]*)\"$" - pattern_maps: - - Header - - notes: - keywords: - - BREAKING CHANGE \ No newline at end of file diff --git a/CHANGELOG/CHANGELOG-1.0.md b/CHANGELOG/CHANGELOG-1.0.md deleted file mode 100644 index 52983b359..000000000 --- a/CHANGELOG/CHANGELOG-1.0.md +++ /dev/null @@ -1,42 +0,0 @@ -# Version logging for OpenIM - - - - - - -## [Unreleased] - - - -## [v1.0.7] - 2021-12-10 - - -## [v1.0.6] - 2021-12-03 - - -## [v1.0.5] - 2021-11-25 - - -## [v1.0.4] - 2021-11-12 - - -## [v1.0.3] - 2021-11-05 - - -## [v1.0.2] - 2021-11-04 - - -## [v1.0.1] - 2021-11-03 - - -## v1.0.0 - 2021-10-28 - -[Unreleased]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.7...HEAD -[v1.0.7]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.6...v1.0.7 -[v1.0.6]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.5...v1.0.6 -[v1.0.5]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.4...v1.0.5 -[v1.0.4]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.3...v1.0.4 -[v1.0.3]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.2...v1.0.3 -[v1.0.2]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.1...v1.0.2 -[v1.0.1]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.0...v1.0.1 diff --git a/CHANGELOG/CHANGELOG-1.1.md b/CHANGELOG/CHANGELOG-1.1.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/CHANGELOG/CHANGELOG-2.0.md b/CHANGELOG/CHANGELOG-2.0.md deleted file mode 100644 index 76bef9093..000000000 --- a/CHANGELOG/CHANGELOG-2.0.md +++ /dev/null @@ -1,92 +0,0 @@ -# Version logging for OpenIM - - - - - - -## [Unreleased] - - - -## [v2.3.3] - 2022-09-16 - - -## [v2.3.2] - 2022-09-09 - - -## [v2.3.0-rc0] - 2022-07-15 - - -## [v2.2.0] - 2022-07-01 -### Pull Requests -- Merge branch 'tuoyun' - - - -## [v2.1.0] - 2022-06-17 - - -## [v2.0.9] - 2022-05-11 - - -## [v2.0.8] - 2022-04-29 -### Pull Requests -- Merge branch 'tuoyun' - - - -## [v2.0.7] - 2022-04-22 - - -## [v2.0.6] - 2022-04-08 - - -## [v2.0.5] - 2022-04-01 -### Pull Requests -- Merge branch 'tuoyun' - - - -## [v2.0.4] - 2022-03-25 - - -## [v2.0.3] - 2022-03-18 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - - -## [v2.0.2] - 2022-02-24 - - -## [v2.0.1] - 2022-02-24 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - - -## v2.0.0 - 2022-02-23 - -[Unreleased]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.3...HEAD -[v2.3.3]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.2...v2.3.3 -[v2.3.2]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.0-rc0...v2.3.2 -[v2.3.0-rc0]: https://github.com/openimsdk/openim-sdk-core/compare/v2.2.0...v2.3.0-rc0 -[v2.2.0]: https://github.com/openimsdk/openim-sdk-core/compare/v2.1.0...v2.2.0 -[v2.1.0]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.9...v2.1.0 -[v2.0.9]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.8...v2.0.9 -[v2.0.8]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.7...v2.0.8 -[v2.0.7]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.6...v2.0.7 -[v2.0.6]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.5...v2.0.6 -[v2.0.5]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.4...v2.0.5 -[v2.0.4]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.3...v2.0.4 -[v2.0.3]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.2...v2.0.3 -[v2.0.2]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.1...v2.0.2 -[v2.0.1]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.0...v2.0.1 diff --git a/CHANGELOG/CHANGELOG-2.1.md b/CHANGELOG/CHANGELOG-2.1.md deleted file mode 100644 index 83a4cda9d..000000000 --- a/CHANGELOG/CHANGELOG-2.1.md +++ /dev/null @@ -1,23 +0,0 @@ -# Version logging for OpenIM - - - - - - -## [Unreleased] - - - -## v2.1.0 - 2022-06-17 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - -[Unreleased]: https://github.com/openimsdk/openim-sdk-core/compare/v2.1.0...HEAD diff --git a/CHANGELOG/CHANGELOG-2.2.md b/CHANGELOG/CHANGELOG-2.2.md deleted file mode 100644 index 7cd31b116..000000000 --- a/CHANGELOG/CHANGELOG-2.2.md +++ /dev/null @@ -1,24 +0,0 @@ -# Version logging for OpenIM - - - - - - -## [Unreleased] - - - -## v2.2.0 - 2022-07-01 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - -[Unreleased]: https://github.com/openimsdk/openim-sdk-core/compare/v2.2.0...HEAD diff --git a/CHANGELOG/CHANGELOG-2.3.md b/CHANGELOG/CHANGELOG-2.3.md deleted file mode 100644 index 77833bf47..000000000 --- a/CHANGELOG/CHANGELOG-2.3.md +++ /dev/null @@ -1,32 +0,0 @@ -# Version logging for OpenIM - - - - - - -## [Unreleased] - - - -## [v2.3.3] - 2022-09-16 - - -## [v2.3.2] - 2022-09-09 - - -## v2.3.0-rc0 - 2022-07-15 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - -[Unreleased]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.3...HEAD -[v2.3.3]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.2...v2.3.3 -[v2.3.2]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.0-rc0...v2.3.2 diff --git a/CHANGELOG/CHANGELOG-2.9.md b/CHANGELOG/CHANGELOG-2.9.md deleted file mode 100644 index 1463f52dc..000000000 --- a/CHANGELOG/CHANGELOG-2.9.md +++ /dev/null @@ -1,52 +0,0 @@ -# Version logging for OpenIM - - - -- [Version logging for OpenIM](#version-logging-for-openim) - - [Unreleased](#unreleased) - - [v2.9.0+1.839643f - 2023-07-07](#v2901839643f---2023-07-07) - - [v2.9.0+2.35f07fe - 2023-07-06](#v290235f07fe---2023-07-06) - - [v2.9.0+1.b5072b1 - 2023-07-05](#v2901b5072b1---2023-07-05) - - [v2.9.0+3.2667a3a - 2023-07-05](#v29032667a3a---2023-07-05) - - [v2.9.0+7.04818ca - 2023-07-05](#v290704818ca---2023-07-05) - - [v2.9.0 - 2023-07-04](#v290---2023-07-04) - - [Reverts](#reverts) - - [Pull Requests](#pull-requests) - - - - - -## [Unreleased] - - - -## [v2.9.0+1.839643f] - 2023-07-07 - - -## [v2.9.0+2.35f07fe] - 2023-07-06 - - -## [v2.9.0+1.b5072b1] - 2023-07-05 - - -## [v2.9.0+3.2667a3a] - 2023-07-05 - - -## [v2.9.0+7.04818ca] - 2023-07-05 - - -## v2.9.0 - 2023-07-04 -### Reverts -- update etcd to v3.5.2 ([#206](https://github.com/openimsdk/Open-IM-Server/issues/206)) - -### Pull Requests -- Merge branch 'tuoyun' - - -[Unreleased]: https://github.com/openimsdk/Open-IM-Server/compare/v2.9.0+1.839643f...HEAD -[v2.9.0+1.839643f]: https://github.com/openimsdk/Open-IM-Server/compare/v2.9.0+2.35f07fe...v2.9.0+1.839643f -[v2.9.0+2.35f07fe]: https://github.com/openimsdk/Open-IM-Server/compare/v2.9.0+1.b5072b1...v2.9.0+2.35f07fe -[v2.9.0+1.b5072b1]: https://github.com/openimsdk/Open-IM-Server/compare/v2.9.0+3.2667a3a...v2.9.0+1.b5072b1 -[v2.9.0+3.2667a3a]: https://github.com/openimsdk/Open-IM-Server/compare/v2.9.0+7.04818ca...v2.9.0+3.2667a3a -[v2.9.0+7.04818ca]: https://github.com/openimsdk/Open-IM-Server/compare/v2.9.0...v2.9.0+7.04818ca diff --git a/CHANGELOG/CHANGELOG-3.0.md b/CHANGELOG/CHANGELOG-3.0.md deleted file mode 100644 index 4b1279302..000000000 --- a/CHANGELOG/CHANGELOG-3.0.md +++ /dev/null @@ -1,128 +0,0 @@ -# Version logging for OpenIM - - - - - - -## [Unreleased] - - - -## [v3.0.0-rc.1] - 2023-07-13 - - -## [v2.3.3] - 2022-09-16 - - -## [v2.3.2] - 2022-09-09 - - -## [v2.3.0-rc0] - 2022-07-15 - - -## [v2.2.0] - 2022-07-01 -### Pull Requests -- Merge branch 'tuoyun' - - - -## [v2.1.0] - 2022-06-17 - - -## [v2.0.9] - 2022-05-11 - - -## [v2.0.8] - 2022-04-29 -### Pull Requests -- Merge branch 'tuoyun' - - - -## [v2.0.7] - 2022-04-22 - - -## [v2.0.6] - 2022-04-08 - - -## [v2.0.5] - 2022-04-01 -### Pull Requests -- Merge branch 'tuoyun' - - - -## [v2.0.4] - 2022-03-25 - - -## [v2.0.3] - 2022-03-18 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - - -## [v2.0.2] - 2022-02-24 - - -## [v2.0.1] - 2022-02-24 -### Pull Requests -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' -- Merge branch 'tuoyun' - - - -## [v2.0.0] - 2022-02-23 - - -## [v1.0.7] - 2021-12-10 - - -## [v1.0.6] - 2021-12-03 - - -## [v1.0.5] - 2021-11-25 - - -## [v1.0.4] - 2021-11-12 - - -## [v1.0.3] - 2021-11-05 - - -## [v1.0.2] - 2021-11-04 - - -## [v1.0.1] - 2021-11-03 - - -## v1.0.0 - 2021-10-28 - -[Unreleased]: https://github.com/openimsdk/openim-sdk-core/compare/v3.0.0-rc.1...HEAD -[v3.0.0-rc.1]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.3...v3.0.0-rc.1 -[v2.3.3]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.2...v2.3.3 -[v2.3.2]: https://github.com/openimsdk/openim-sdk-core/compare/v2.3.0-rc0...v2.3.2 -[v2.3.0-rc0]: https://github.com/openimsdk/openim-sdk-core/compare/v2.2.0...v2.3.0-rc0 -[v2.2.0]: https://github.com/openimsdk/openim-sdk-core/compare/v2.1.0...v2.2.0 -[v2.1.0]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.9...v2.1.0 -[v2.0.9]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.8...v2.0.9 -[v2.0.8]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.7...v2.0.8 -[v2.0.7]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.6...v2.0.7 -[v2.0.6]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.5...v2.0.6 -[v2.0.5]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.4...v2.0.5 -[v2.0.4]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.3...v2.0.4 -[v2.0.3]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.2...v2.0.3 -[v2.0.2]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.1...v2.0.2 -[v2.0.1]: https://github.com/openimsdk/openim-sdk-core/compare/v2.0.0...v2.0.1 -[v2.0.0]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.7...v2.0.0 -[v1.0.7]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.6...v1.0.7 -[v1.0.6]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.5...v1.0.6 -[v1.0.5]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.4...v1.0.5 -[v1.0.4]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.3...v1.0.4 -[v1.0.3]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.2...v1.0.3 -[v1.0.2]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.1...v1.0.2 -[v1.0.1]: https://github.com/openimsdk/openim-sdk-core/compare/v1.0.0...v1.0.1 diff --git a/Makefile b/Makefile index 07f5103cf..4105ab18e 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,6 @@ ROOT_PACKAGE=github.com/openimsdk/Open-IM-SDK-Core -# Copyright 2023 OpenIM. All rights reserved. -# Use of this source code is governed by a MIT style -# license that can be found in the LICENSE file. - ###################################=> common commands <=############################################# # ========================== Capture Environment =============================== # get the repo root and output path diff --git a/CHANGELOG/CHANGELOG.md b/docs/CHANGELOG.md similarity index 100% rename from CHANGELOG/CHANGELOG.md rename to docs/CHANGELOG.md diff --git a/go.mod b/go.mod index 14cc65992..f3535b30d 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/jinzhu/copier v0.4.0 github.com/pkg/errors v0.9.1 - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.33.0 gorm.io/driver/sqlite v1.5.5 nhooyr.io/websocket v1.8.10 ) @@ -17,23 +17,44 @@ require golang.org/x/net v0.22.0 // indirect require ( github.com/google/go-cmp v0.6.0 github.com/openimsdk/protocol v0.0.72 - github.com/openimsdk/tools v0.0.50-alpha.16 + github.com/openimsdk/tools v0.0.50-alpha.21 github.com/patrickmn/go-cache v2.1.0+incompatible golang.org/x/image v0.15.0 golang.org/x/sync v0.6.0 + google.golang.org/grpc v1.62.1 gorm.io/gorm v1.25.10 ) require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.62.1 // indirect ) diff --git a/go.sum b/go.sum index c906a8ba8..f113489b5 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,37 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= @@ -17,28 +42,56 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.50-alpha.16 h1:bC1AQvJMuOHtZm8LZRvN8L5mH1Ws2VYdL+TLTs1iGSc= -github.com/openimsdk/tools v0.0.50-alpha.16/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4= +github.com/openimsdk/tools v0.0.50-alpha.21 h1:ZKgSFkiBjz6KcNZlNwvrSoUYJ7K5Flan8wHuRBH3VqY= +github.com/openimsdk/tools v0.0.50-alpha.21/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -47,12 +100,19 @@ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -63,6 +123,9 @@ google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= @@ -71,3 +134,4 @@ gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/integration_test/internal/pkg/reerrgroup/errgroup.go b/integration_test/internal/pkg/reerrgroup/errgroup.go index c9849006c..723803466 100644 --- a/integration_test/internal/pkg/reerrgroup/errgroup.go +++ b/integration_test/internal/pkg/reerrgroup/errgroup.go @@ -1,7 +1,3 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - // Package reerrgroup is a rewrite of errgroup package reerrgroup diff --git a/internal/conversation_msg/api.go b/internal/conversation_msg/api.go index 4992a7ee8..282c739cd 100644 --- a/internal/conversation_msg/api.go +++ b/internal/conversation_msg/api.go @@ -832,6 +832,19 @@ func (c *Conversation) MarkConversationMessageAsRead(ctx context.Context, conver return c.markConversationMessageAsRead(ctx, conversationID) } +func (c *Conversation) MarkAllConversationMessageAsRead(ctx context.Context) error { + conversationIDs, err := c.db.FindAllUnreadConversationConversationID(ctx) + if err != nil { + return err + } + for _, conversationID := range conversationIDs { + if err = c.markConversationMessageAsRead(ctx, conversationID); err != nil { + return err + } + } + return nil +} + // deprecated func (c *Conversation) MarkMessagesAsReadByMsgID(ctx context.Context, conversationID string, clientMsgIDs []string) error { return c.markMessagesAsReadByMsgID(ctx, conversationID, clientMsgIDs) diff --git a/internal/conversation_msg/conversation.go b/internal/conversation_msg/conversation.go index b514b46b9..814babab9 100644 --- a/internal/conversation_msg/conversation.go +++ b/internal/conversation_msg/conversation.go @@ -110,6 +110,76 @@ func (c *Conversation) getAdvancedHistoryMessageList(ctx context.Context, req sd } log.ZDebug(ctx, "pull message", "pull cost time", time.Since(t)) t = time.Now() + //var thisMinSeq int64 + //for _, v := range list { + // if v.Seq != 0 && thisMinSeq == 0 { + // thisMinSeq = v.Seq + // } + // if v.Seq < thisMinSeq && v.Seq != 0 { + // thisMinSeq = v.Seq + // } + // if v.Status >= constant.MsgStatusHasDeleted { + // log.ZDebug(ctx, "this message has been deleted or exception message", "msg", v) + // continue + // } + // temp := sdk_struct.MsgStruct{} + // temp.ClientMsgID = v.ClientMsgID + // temp.ServerMsgID = v.ServerMsgID + // temp.CreateTime = v.CreateTime + // temp.SendTime = v.SendTime + // temp.SessionType = v.SessionType + // temp.SendID = v.SendID + // temp.RecvID = v.RecvID + // temp.MsgFrom = v.MsgFrom + // temp.ContentType = v.ContentType + // temp.SenderPlatformID = v.SenderPlatformID + // temp.SenderNickname = v.SenderNickname + // temp.SenderFaceURL = v.SenderFaceURL + // temp.Content = v.Content + // temp.Seq = v.Seq + // temp.IsRead = v.IsRead + // temp.Status = v.Status + // var attachedInfo sdk_struct.AttachedInfoElem + // _ = utils.JsonStringToStruct(v.AttachedInfo, &attachedInfo) + // temp.AttachedInfoElem = &attachedInfo + // temp.Ex = v.Ex + // temp.LocalEx = v.LocalEx + // err := c.msgHandleByContentType(&temp) + // if err != nil { + // log.ZError(ctx, "Parsing data error", err, "temp", temp) + // continue + // } + // switch sessionType { + // case constant.WriteGroupChatType: + // fallthrough + // case constant.ReadGroupChatType: + // temp.GroupID = temp.RecvID + // temp.RecvID = c.loginUserID + // } + // if attachedInfo.IsPrivateChat && temp.SendTime+int64(attachedInfo.BurnDuration) < time.Now().Unix() { + // continue + // } + // messageList = append(messageList, &temp) + //} + var thisMinSeq int64 + thisMinSeq, messageList = c.LocalChatLog2MsgStruct(ctx, list, sessionType) + log.ZDebug(ctx, "message convert and unmarshal", "unmarshal cost time", time.Since(t)) + t = time.Now() + if !isReverse { + sort.Sort(messageList) + } + log.ZDebug(ctx, "sort", "sort cost time", time.Since(t)) + messageListCallback.MessageList = messageList + if thisMinSeq == 0 { + thisMinSeq = req.LastMinSeq + } + messageListCallback.LastMinSeq = thisMinSeq + return &messageListCallback, nil + +} + +func (c *Conversation) LocalChatLog2MsgStruct(ctx context.Context, list []*model_struct.LocalChatLog, sessionType int) (int64, []*sdk_struct.MsgStruct) { + messageList := make([]*sdk_struct.MsgStruct, 0, len(list)) var thisMinSeq int64 for _, v := range list { if v.Seq != 0 && thisMinSeq == 0 { @@ -161,19 +231,7 @@ func (c *Conversation) getAdvancedHistoryMessageList(ctx context.Context, req sd } messageList = append(messageList, &temp) } - log.ZDebug(ctx, "message convert and unmarshal", "unmarshal cost time", time.Since(t)) - t = time.Now() - if !isReverse { - sort.Sort(messageList) - } - log.ZDebug(ctx, "sort", "sort cost time", time.Since(t)) - messageListCallback.MessageList = messageList - if thisMinSeq == 0 { - thisMinSeq = req.LastMinSeq - } - messageListCallback.LastMinSeq = thisMinSeq - return &messageListCallback, nil - + return thisMinSeq, messageList } func (c *Conversation) typingStatusUpdate(ctx context.Context, recvID, msgTip string) error { diff --git a/internal/conversation_msg/conversation_msg.go b/internal/conversation_msg/conversation_msg.go index 492070000..dc85c0a48 100644 --- a/internal/conversation_msg/conversation_msg.go +++ b/internal/conversation_msg/conversation_msg.go @@ -8,6 +8,8 @@ import ( "math" "sync" + sdk "github.com/openimsdk/openim-sdk-core/v3/pkg/sdk_params_callback" + "github.com/openimsdk/openim-sdk-core/v3/pkg/api" "github.com/openimsdk/openim-sdk-core/v3/pkg/cache" "github.com/openimsdk/tools/utils/stringutil" @@ -923,6 +925,7 @@ func (c *Conversation) batchAddFaceURLAndName(ctx context.Context, conversations if err != nil { return err } + groups := datautil.SliceToMap(groupInfoList, func(groupInfo *model_struct.LocalGroup) string { return groupInfo.GroupID }) @@ -934,8 +937,10 @@ func (c *Conversation) batchAddFaceURLAndName(ctx context.Context, conversations conversation.FaceURL = v.FaceURL conversation.ShowName = v.Nickname } else { - log.ZWarn(ctx, "user info not found", errors.New("user not found"), - "userID", conversation.UserID) + log.ZWarn(ctx, "user info not found", errors.New("user not found"),"userID", conversation.UserID) + + conversation.FaceURL = "" + conversation.ShowName = "UserNotFound" } } else if conversation.ConversationType == constant.ReadGroupChatType { if v, ok := groups[conversation.GroupID]; ok { @@ -948,6 +953,7 @@ func (c *Conversation) batchAddFaceURLAndName(ctx context.Context, conversations } } + return nil } @@ -978,10 +984,12 @@ func (c *Conversation) batchGetUserNameAndFaceURL(ctx context.Context, userIDs . } m[localFriend.FriendUserID] = userInfo } + usersInfo, err := c.user.GetUsersInfoWithCache(ctx, notInFriend) if err != nil { return nil, err } + for _, userInfo := range usersInfo { m[userInfo.UserID] = userInfo } @@ -1013,3 +1021,53 @@ func (c *Conversation) GetInputStates(ctx context.Context, conversationID string func (c *Conversation) ChangeInputStates(ctx context.Context, conversationID string, focus bool) error { return c.typing.ChangeInputStates(ctx, conversationID, focus) } + +func (c *Conversation) FetchSurroundingMessages(ctx context.Context, conversationID string, seq int64, before int64, after int64) ([]*sdk_struct.MsgStruct, error) { + lc, err := c.db.GetConversation(ctx, conversationID) + if err != nil { + return nil, err + } + c.pullMessageAndReGetHistoryMessages(ctx, conversationID, []int64{seq}, false, false, 0, 0, &[]*model_struct.LocalChatLog{}, &sdk.GetAdvancedHistoryMessageListCallback{}) + res, err := c.db.GetMessagesBySeqs(ctx, conversationID, []int64{seq}) + if err != nil { + return nil, err + } + if len(res) == 0 { + return []*sdk_struct.MsgStruct{}, nil + } + _, msgList := c.LocalChatLog2MsgStruct(ctx, []*model_struct.LocalChatLog{res[0]}, int(lc.ConversationType)) + if len(msgList) == 0 { + return []*sdk_struct.MsgStruct{}, nil + } + msg := msgList[0] + result := make([]*sdk_struct.MsgStruct, 0, before+after+1) + if before > 0 { + req := sdk.GetAdvancedHistoryMessageListParams{ + LastMinSeq: msg.Seq, + ConversationID: conversationID, + Count: int(before), + StartClientMsgID: msg.ClientMsgID, + } + val, err := c.getAdvancedHistoryMessageList(ctx, req, false) + if err != nil { + return nil, err + } + result = append(result, val.MessageList...) + } + result = append(result, msg) + if after > 0 { + req := sdk.GetAdvancedHistoryMessageListParams{ + LastMinSeq: msg.Seq, + ConversationID: conversationID, + Count: int(after), + StartClientMsgID: msg.ClientMsgID, + } + val, err := c.getAdvancedHistoryMessageList(ctx, req, true) + if err != nil { + return nil, err + } + result = append(result, val.MessageList...) + } + sort.Sort(sdk_struct.NewMsgList(result)) + return result, nil +} diff --git a/internal/conversation_msg/entering.go b/internal/conversation_msg/entering.go index 0ef604343..4ea296207 100644 --- a/internal/conversation_msg/entering.go +++ b/internal/conversation_msg/entering.go @@ -165,10 +165,7 @@ func (e *typing) onNewMsg(ctx context.Context, msg *sdkws.MsgData) { return } now := time.Now().UnixMilli() - expirationTimestamp := msg.SendTime + int64(inputStatesSendTime/time.Millisecond) - if msg.SendTime > now || expirationTimestamp <= now { - return - } + expirationTimestamp := now + int64(inputStatesSendTime/time.Millisecond) var sourceID string if msg.GroupID == "" { sourceID = msg.SendID diff --git a/internal/conversation_msg/notification.go b/internal/conversation_msg/notification.go index 0ffed6a79..96aa1c874 100644 --- a/internal/conversation_msg/notification.go +++ b/internal/conversation_msg/notification.go @@ -203,7 +203,6 @@ func (c *Conversation) doUpdateConversation(c2v common.Cmd2Value) { lc := node.Args.(model_struct.LocalConversation) oc, err := c.db.GetConversation(ctx, lc.ConversationID) if err == nil { - // log.Info("this is old conversation", *oc) if lc.LatestMsgSendTime >= oc.LatestMsgSendTime || c.getConversationLatestMsgClientID(lc.LatestMsg) == c.getConversationLatestMsgClientID(oc.LatestMsg) { // The session update of asynchronous messages is subject to the latest sending time err := c.db.UpdateColumnsConversation(ctx, node.ConID, map[string]interface{}{"latest_msg_send_time": lc.LatestMsgSendTime, "latest_msg": lc.LatestMsg}) if err != nil { @@ -269,7 +268,7 @@ func (c *Conversation) doUpdateConversation(c2v common.Cmd2Value) { } c.doUpdateConversation(common.Cmd2Value{Value: common.UpdateConNode{ConID: lc.ConversationID, Action: constant.ConChange, Args: []string{lc.ConversationID}}}) - case constant.UpdateLatestMessageChange: + case constant.UpdateLatestMessageReadState: conversationID := node.ConID var latestMsg sdk_struct.MsgStruct l, err := c.db.GetConversation(ctx, conversationID) @@ -288,6 +287,43 @@ func (c *Conversation) doUpdateConversation(c2v common.Cmd2Value) { } } } + case constant.UpdateLatestMessageFaceUrlAndNickName: + args := node.Args.(common.UpdateMessageInfo) + switch args.SessionType { + case constant.ReadGroupChatType: + conversationID := c.getConversationIDBySessionType(args.GroupID, constant.ReadGroupChatType) + lc, err := c.db.GetConversation(ctx, conversationID) + if err != nil { + log.ZWarn(ctx, "getConversation err", err) + return + } + var latestMsg sdk_struct.MsgStruct + err = json.Unmarshal([]byte(lc.LatestMsg), &latestMsg) + if err != nil { + log.ZError(ctx, "latestMsg,Unmarshal err", err) + } else { + //If the sender of the latest message in the conversation + //happens to be a member of the group whose status has changed, + //then update the sender's avatar and nickname for the latest message. + if latestMsg.SendID == args.UserID { + latestMsg.SenderFaceURL = args.FaceURL + latestMsg.SenderNickname = args.Nickname + newLatestMessage := utils.StructToJsonString(latestMsg) + lc.LatestMsg = newLatestMessage + err = c.db.UpdateColumnsConversation(ctx, conversationID, map[string]interface{}{"latest_msg": newLatestMessage}) + if err != nil { + log.ZError(ctx, "updateConversationLatestMsgModel err", err) + } else { + var cList []*model_struct.LocalConversation + cList = append(cList, lc) + data := utils.StructToJsonStringDefault(cList) + c.ConversationListener().OnConversationChanged(data) + } + + } + } + } + case constant.ConChange: conversationIDs := node.Args.([]string) conversations, err := c.db.GetMultipleConversationDB(ctx, conversationIDs) @@ -325,43 +361,59 @@ func (c *Conversation) doUpdateConversation(c2v common.Cmd2Value) { log.ZDebug(ctx, "NewConversation", "cidList", cidList) c.ConversationListener().OnNewConversation(cidList) - case constant.ConversationLatestMsgHasRead: - hasReadMsgList := node.Args.(map[string][]string) - var result []*model_struct.LocalConversation - var latestMsg sdk_struct.MsgStruct - var lc model_struct.LocalConversation - for conversationID, msgIDList := range hasReadMsgList { - LocalConversation, err := c.db.GetConversation(ctx, conversationID) - if err != nil { - log.ZWarn(ctx, "get conversation err", err, "conversationID", conversationID) - continue - } - err = utils.JsonStringToStruct(LocalConversation.LatestMsg, &latestMsg) - if err != nil { - log.ZWarn(ctx, "JsonStringToStruct err", err, "conversationID", conversationID) - continue - } - if utils.IsContain(latestMsg.ClientMsgID, msgIDList) { - latestMsg.IsRead = true - lc.ConversationID = conversationID - lc.LatestMsg = utils.StructToJsonString(latestMsg) - LocalConversation.LatestMsg = utils.StructToJsonString(latestMsg) - err := c.db.UpdateConversation(ctx, &lc) + } +} + +func (c *Conversation) doUpdateMessage(c2v common.Cmd2Value) { + node := c2v.Value.(common.UpdateMessageNode) + ctx := c2v.Ctx + switch node.Action { + case constant.UpdateMsgFaceUrlAndNickName: + args := node.Args.(common.UpdateMessageInfo) + switch args.SessionType { + case constant.SingleChatType: + if args.UserID == c.loginUserID { + conversationIDList, err := c.db.GetAllSingleConversationIDList(ctx) if err != nil { - log.ZWarn(ctx, "UpdateConversation err", err) - continue + log.ZError(ctx, "GetAllSingleConversationIDList err", err) + return } else { - result = append(result, LocalConversation) + log.ZDebug(ctx, "get single conversationID list", "conversationIDList", conversationIDList) + for _, conversationID := range conversationIDList { + err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) + if err != nil { + log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) + continue + } + } + } + } else { + conversationID := c.getConversationIDBySessionType(args.UserID, constant.SingleChatType) + err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) + if err != nil { + log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) + } + } + case constant.ReadGroupChatType: + conversationID := c.getConversationIDBySessionType(args.GroupID, constant.ReadGroupChatType) + err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) + if err != nil { + log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) + } + case constant.NotificationChatType: + conversationID := c.getConversationIDBySessionType(args.UserID, constant.NotificationChatType) + err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) + if err != nil { + log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) + } + default: + log.ZError(ctx, "not support sessionType", nil, "args", args) + return } - if result != nil { - log.ZDebug(ctx, "getMultipleConversationModel success", "result", result) - c.ConversationListener().OnNewConversation(utils.StructToJsonString(result)) - } - case constant.SyncConversation: - } + } func (c *Conversation) syncData(c2v common.Cmd2Value) { @@ -433,58 +485,6 @@ func executeSyncFunction(ctx context.Context, fn func(c context.Context) error, } } -func (c *Conversation) doUpdateMessage(c2v common.Cmd2Value) { - node := c2v.Value.(common.UpdateMessageNode) - ctx := c2v.Ctx - switch node.Action { - case constant.UpdateMsgFaceUrlAndNickName: - args := node.Args.(common.UpdateMessageInfo) - switch args.SessionType { - case constant.SingleChatType: - if args.UserID == c.loginUserID { - conversationIDList, err := c.db.GetAllSingleConversationIDList(ctx) - if err != nil { - log.ZError(ctx, "GetAllSingleConversationIDList err", err) - return - } else { - log.ZDebug(ctx, "get single conversationID list", "conversationIDList", conversationIDList) - for _, conversationID := range conversationIDList { - err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) - if err != nil { - log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) - continue - } - } - - } - } else { - conversationID := c.getConversationIDBySessionType(args.UserID, constant.SingleChatType) - err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) - if err != nil { - log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) - } - - } - case constant.ReadGroupChatType: - conversationID := c.getConversationIDBySessionType(args.GroupID, constant.ReadGroupChatType) - err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) - if err != nil { - log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) - } - case constant.NotificationChatType: - conversationID := c.getConversationIDBySessionType(args.UserID, constant.NotificationChatType) - err := c.db.UpdateMsgSenderFaceURLAndSenderNickname(ctx, conversationID, args.UserID, args.FaceURL, args.Nickname) - if err != nil { - log.ZError(ctx, "UpdateMsgSenderFaceURLAndSenderNickname err", err) - } - default: - log.ZError(ctx, "not support sessionType", nil, "args", args) - return - } - } - -} - func (c *Conversation) DoConversationChangedNotification(ctx context.Context, msg *sdkws.MsgData) error { c.conversationSyncMutex.Lock() defer c.conversationSyncMutex.Unlock() diff --git a/internal/conversation_msg/read_drawing.go b/internal/conversation_msg/read_drawing.go index d9abf2e0b..b015461cb 100644 --- a/internal/conversation_msg/read_drawing.go +++ b/internal/conversation_msg/read_drawing.go @@ -162,7 +162,7 @@ func (c *Conversation) getAsReadMsgMapAndList(ctx context.Context, func (c *Conversation) unreadChangeTrigger(ctx context.Context, conversationID string, latestMsgIsRead bool) { if latestMsgIsRead { c.doUpdateConversation(common.Cmd2Value{Value: common.UpdateConNode{ConID: conversationID, - Action: constant.UpdateLatestMessageChange, Args: []string{conversationID}}, Ctx: ctx}) + Action: constant.UpdateLatestMessageReadState, Args: []string{conversationID}}, Ctx: ctx}) } c.doUpdateConversation(common.Cmd2Value{Value: common.UpdateConNode{ConID: conversationID, Action: constant.ConChange, Args: []string{conversationID}}, Ctx: ctx}) @@ -210,7 +210,7 @@ func (c *Conversation) doUnreadCount(ctx context.Context, conversation *model_st } if (!latestMsg.IsRead) && datautil.Contain(latestMsg.Seq, seqs...) { c.doUpdateConversation(common.Cmd2Value{Value: common.UpdateConNode{ConID: conversation.ConversationID, - Action: constant.UpdateLatestMessageChange, Args: []string{conversation.ConversationID}}, Ctx: ctx}) + Action: constant.UpdateLatestMessageReadState, Args: []string{conversation.ConversationID}}, Ctx: ctx}) } } else { if err := c.db.UpdateColumnsConversation(ctx, conversation.ConversationID, map[string]interface{}{"unread_count": 0}); err != nil { diff --git a/internal/group/group.go b/internal/group/group.go index e19ade5a2..36d7248ad 100644 --- a/internal/group/group.go +++ b/internal/group/group.go @@ -187,6 +187,10 @@ func (g *Group) initSyncer() { Nickname: server.Nickname, GroupID: server.GroupID, }, }, g.conversationCh) + _ = common.TriggerCmdUpdateConversation(ctx, common.UpdateConNode{Action: constant.UpdateLatestMessageFaceUrlAndNickName, Args: common.UpdateMessageInfo{ + SessionType: constant.ReadGroupChatType, UserID: server.UserID, FaceURL: server.FaceURL, + Nickname: server.Nickname, GroupID: server.GroupID, + }}, g.conversationCh) } } return nil diff --git a/internal/group/notification.go b/internal/group/notification.go index 020f9f539..64fca4219 100644 --- a/internal/group/notification.go +++ b/internal/group/notification.go @@ -224,7 +224,11 @@ func (g *Group) doNotification(ctx context.Context, msg *sdkws.MsgData) error { if err := utils.UnmarshalNotificationElem(msg.Content, &detail); err != nil { return err } - + if detail.ChangedUser.RoleLevel < constant.GroupAdmin && detail.ChangedUser.UserID == g.loginUserID { + if err := g.delLocalGroupRequest(ctx, detail.Group.GroupID, g.loginUserID); err != nil { + return err + } + } return g.onlineSyncGroupAndMember(ctx, detail.Group.GroupID, nil, []*sdkws.GroupMemberFullInfo{detail.ChangedUser}, nil, nil, detail.GroupSortVersion, detail.GroupMemberVersion, detail.GroupMemberVersionID) diff --git a/internal/relation/relation.go b/internal/relation/relation.go index 1974965c0..a05869a25 100644 --- a/internal/relation/relation.go +++ b/internal/relation/relation.go @@ -62,6 +62,27 @@ func (r *Relation) initSyncer() { switch state { case syncer.Insert: r.friendshipListener.OnFriendAdded(*server) + if server.Remark != "" { + server.Nickname = server.Remark + } + _ = common.TriggerCmdUpdateConversation(ctx, common.UpdateConNode{ + Action: constant.UpdateConFaceUrlAndNickName, + Args: common.SourceIDAndSessionType{ + SourceID: server.FriendUserID, + SessionType: constant.SingleChatType, + FaceURL: server.FaceURL, + Nickname: server.Nickname, + }, + }, r.conversationCh) + _ = common.TriggerCmdUpdateMessage(ctx, common.UpdateMessageNode{ + Action: constant.UpdateMsgFaceUrlAndNickName, + Args: common.UpdateMessageInfo{ + SessionType: constant.SingleChatType, + UserID: server.FriendUserID, + FaceURL: server.FaceURL, + Nickname: server.Nickname, + }, + }, r.conversationCh) case syncer.Delete: log.ZDebug(ctx, "syncer OnFriendDeleted", "local", local) r.friendshipListener.OnFriendDeleted(*local) diff --git a/internal/user/api.go b/internal/user/api.go index 6fef37300..77877b344 100644 --- a/internal/user/api.go +++ b/internal/user/api.go @@ -16,9 +16,9 @@ import ( "github.com/openimsdk/tools/utils/datautil" ) -// GetSingleUserFromSvr retrieves user information from the server. -func (u *User) GetSingleUserFromSvr(ctx context.Context, userID string) (*model_struct.LocalUser, error) { - users, err := u.GetUsersInfoFromSvr(ctx, []string{userID}) +// GetSingleUserFromServer retrieves user information from the server. +func (u *User) GetSingleUserFromServer(ctx context.Context, userID string) (*model_struct.LocalUser, error) { + users, err := u.GetUsersInfoFromServer(ctx, []string{userID}) if err != nil { return nil, err } @@ -125,10 +125,18 @@ func (u *User) ProcessUserCommandUpdate(ctx context.Context, userCommand *userPb // GetUserInfoFromServer retrieves user information from the server. func (u *User) GetUserInfoFromServer(ctx context.Context, userIDs []string) ([]*model_struct.LocalUser, error) { + var err error + serverUsersInfo, err := u.getUsersInfo(ctx, userIDs) if err != nil { return nil, err } + + if len(serverUsersInfo) == 0 { + log.ZError(ctx, "serverUsersInfo is empty", err, "userIDs", userIDs) + return nil, err + } + return datautil.Batch(ServerUserToLocalUser, serverUsersInfo), nil } @@ -171,11 +179,11 @@ func (u *User) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdk_struc return res, nil } -// GetUsersInfoFromSvr retrieves user information from the server. -func (u *User) GetUsersInfoFromSvr(ctx context.Context, userIDs []string) ([]*model_struct.LocalUser, error) { +// GetUsersInfoFromServer retrieves user information from the server. +func (u *User) GetUsersInfoFromServer(ctx context.Context, userIDs []string) ([]*model_struct.LocalUser, error) { users, err := u.getUsersInfo(ctx, userIDs) if err != nil { - return nil, sdkerrs.WrapMsg(err, "GetUsersInfoFromSvr failed") + return nil, sdkerrs.WrapMsg(err, "GetUsersInfoFromServer failed") } return datautil.Batch(ServerUserToLocalUser, users), nil } diff --git a/internal/user/full_sync.go b/internal/user/full_sync.go index a3646b9f2..e4fbe5d37 100644 --- a/internal/user/full_sync.go +++ b/internal/user/full_sync.go @@ -3,6 +3,7 @@ package user import ( "context" "errors" + "github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct" userPb "github.com/openimsdk/protocol/user" "github.com/openimsdk/tools/errs" @@ -11,7 +12,7 @@ import ( ) func (u *User) SyncLoginUserInfo(ctx context.Context) error { - remoteUser, err := u.GetSingleUserFromSvr(ctx, u.loginUserID) + remoteUser, err := u.GetSingleUserFromServer(ctx, u.loginUserID) if err != nil { return err } @@ -28,7 +29,7 @@ func (u *User) SyncLoginUserInfo(ctx context.Context) error { } func (u *User) SyncLoginUserInfoWithoutNotice(ctx context.Context) error { - remoteUser, err := u.GetSingleUserFromSvr(ctx, u.loginUserID) + remoteUser, err := u.GetSingleUserFromServer(ctx, u.loginUserID) if err != nil { return err } diff --git a/open_im_sdk/caller.go b/open_im_sdk/caller.go index 222a9daa5..14ac96545 100644 --- a/open_im_sdk/caller.go +++ b/open_im_sdk/caller.go @@ -17,18 +17,20 @@ package open_im_sdk import ( "context" "encoding/json" - "errors" "fmt" "reflect" "runtime" "runtime/debug" "time" + "github.com/pkg/errors" + "github.com/openimsdk/openim-sdk-core/v3/open_im_sdk_callback" "github.com/openimsdk/openim-sdk-core/v3/pkg/ccontext" "github.com/openimsdk/openim-sdk-core/v3/pkg/sdkerrs" "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/mw" "github.com/openimsdk/tools/errs" ) @@ -98,31 +100,36 @@ func call_(operationID string, fn any, args ...any) (res any, err error) { return nil, sdkerrs.ErrResourceLoad.WrapMsg("not load resource") } ctx := ccontext.WithOperationID(UserForSDK.Context(), operationID) + defer func(start time.Time) { if r := recover(); r != nil { - fmt.Sprintf("panic: %+v\n%s", r, debug.Stack()) - err = fmt.Errorf("call panic: %+v", r) + p := fmt.Sprintf("panic: %+v\n%s", r, debug.Stack()) + err = fmt.Errorf("call panic: %+v", p) } else { elapsed := time.Since(start).Milliseconds() if err == nil { log.ZInfo(ctx, "fn call success", "function name", funcName, "cost time", fmt.Sprintf("%d ms", elapsed), "resp", res) } else { - log.ZError(ctx, "fn call error", err, "function name", funcName, "cost time", fmt.Sprintf("%d ms", elapsed)) + log.ZError(ctx, "fn call error", mw.FormatError(err), "function name", funcName, "cost time", fmt.Sprintf("%d ms", elapsed)) } } }(t) + log.ZInfo(ctx, "func call req", "function name", funcName, "args", args) fnv := reflect.ValueOf(fn) if fnv.Kind() != reflect.Func { return nil, sdkerrs.ErrSdkInternal.WrapMsg(fmt.Sprintf("call function fn is not function, is %T", fn)) } + fnt := fnv.Type() nin := fnt.NumIn() + if len(args)+1 != nin { - return nil, sdkerrs.ErrSdkInternal.WrapMsg(fmt.Sprintf("go code error: fn in args num is not match")) + return nil, sdkerrs.ErrSdkInternal.WrapMsg("go code error: fn in args num is not match") } + ins := make([]reflect.Value, 0, nin) ins = append(ins, reflect.ValueOf(ctx)) for i := 0; i < len(args); i++ { @@ -157,18 +164,22 @@ func call_(operationID string, fn any, args ...any) (res any, err error) { continue } } + //if isNumeric(arg.Kind()) && isNumeric(inFnField.Kind()) { // v := reflect.Zero(inFnField).Interface() // setNumeric(args[i], &v) // ins = append(ins, reflect.ValueOf(v)) // continue //} - return nil, sdkerrs.ErrSdkInternal.WrapMsg(fmt.Sprintf("go code error: fn in args type is not match")) + + return nil, sdkerrs.ErrSdkInternal.WrapMsg("go code error: fn in args type is not match") } + outs := fnv.Call(ins) if len(outs) == 0 { return "", nil } + if fnt.Out(len(outs) - 1).Implements(reflect.ValueOf(new(error)).Elem().Type()) { if errValueOf := outs[len(outs)-1]; !errValueOf.IsNil() { return nil, errValueOf.Interface().(error) @@ -178,6 +189,7 @@ func call_(operationID string, fn any, args ...any) (res any, err error) { } outs = outs[:len(outs)-1] } + for i := 0; i < len(outs); i++ { out := outs[i] switch out.Kind() { @@ -191,13 +203,16 @@ func call_(operationID string, fn any, args ...any) (res any, err error) { } } } + if len(outs) == 1 { return outs[0].Interface(), nil } + val := make([]any, 0, len(outs)) for i := range outs { val = append(val, outs[i].Interface()) } + return val, nil } diff --git a/open_im_sdk/conversation_msg.go b/open_im_sdk/conversation_msg.go index 8d14a5c87..34bf1b4e2 100644 --- a/open_im_sdk/conversation_msg.go +++ b/open_im_sdk/conversation_msg.go @@ -160,6 +160,10 @@ func MarkConversationMessageAsRead(callback open_im_sdk_callback.Base, operation call(callback, operationID, UserForSDK.Conversation().MarkConversationMessageAsRead, conversationID) } +func MarkAllConversationMessageAsRead(callback open_im_sdk_callback.Base, operationID string) { + call(callback, operationID, UserForSDK.Conversation().MarkAllConversationMessageAsRead) +} + func MarkMessagesAsReadByMsgID(callback open_im_sdk_callback.Base, operationID string, conversationID string, clientMsgIDs string) { call(callback, operationID, UserForSDK.Conversation().MarkMessagesAsReadByMsgID, conversationID, clientMsgIDs) } @@ -218,3 +222,7 @@ func ChangeInputStates(callback open_im_sdk_callback.Base, operationID string, c func GetInputStates(callback open_im_sdk_callback.Base, operationID string, conversationID string, userID string) { call(callback, operationID, UserForSDK.Conversation().GetInputStates, conversationID, userID) } + +func FetchSurroundingMessages(callback open_im_sdk_callback.Base, operationID string, conversationID string, seq int64, before int64, after int64) { + call(callback, operationID, UserForSDK.Conversation().FetchSurroundingMessages, conversationID, seq, before, after) +} diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index 580dde808..3b62a6141 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -178,17 +178,16 @@ const ( ) const ( - AddConOrUpLatMsg = 1 - TotalUnreadMessageChanged = 2 - UpdateConFaceUrlAndNickName = 3 - UpdateLatestMessageChange = 4 - ConChange = 5 - NewCon = 6 - ConChangeDirect = 7 - NewConDirect = 8 - ConversationLatestMsgHasRead = 9 - UpdateMsgFaceUrlAndNickName = 10 - SyncConversation = 11 + AddConOrUpLatMsg = 1 + TotalUnreadMessageChanged = 2 + UpdateConFaceUrlAndNickName = 3 + UpdateLatestMessageReadState = 4 + UpdateLatestMessageFaceUrlAndNickName = 5 + ConChange = 6 + NewCon = 7 + ConChangeDirect = 8 + NewConDirect = 9 + UpdateMsgFaceUrlAndNickName = 10 HasRead = 1 NotRead = 0 diff --git a/pkg/db/conversation_model.go b/pkg/db/conversation_model.go index 7ac25ee26..6aa7927e2 100644 --- a/pkg/db/conversation_model.go +++ b/pkg/db/conversation_model.go @@ -62,6 +62,12 @@ func (d *DataBase) FindAllConversationConversationID(ctx context.Context) (conve return conversationIDs, errs.WrapMsg(d.conn.WithContext(ctx).Model(&model_struct.LocalConversation{}).Where("latest_msg_send_time > ?", 0).Pluck("conversation_id", &conversationIDs).Error, "") } +func (d *DataBase) FindAllUnreadConversationConversationID(ctx context.Context) (conversationIDs []string, err error) { + d.mRWMutex.RLock() + defer d.mRWMutex.RUnlock() + return conversationIDs, errs.WrapMsg(d.conn.WithContext(ctx).Model(&model_struct.LocalConversation{}).Where("unread_count > ?", 0).Pluck("conversation_id", &conversationIDs).Error, "") +} + func (d *DataBase) GetHiddenConversationList(ctx context.Context) ([]*model_struct.LocalConversation, error) { d.mRWMutex.RLock() defer d.mRWMutex.RUnlock() diff --git a/pkg/db/db_interface/databse.go b/pkg/db/db_interface/databse.go index 1ed8f5cbd..b85921e8f 100644 --- a/pkg/db/db_interface/databse.go +++ b/pkg/db/db_interface/databse.go @@ -103,6 +103,7 @@ type MessageModel interface { type ConversationModel interface { GetConversationByUserID(ctx context.Context, userID string) (*model_struct.LocalConversation, error) GetAllConversationListDB(ctx context.Context) ([]*model_struct.LocalConversation, error) + FindAllUnreadConversationConversationID(ctx context.Context) ([]string, error) GetHiddenConversationList(ctx context.Context) ([]*model_struct.LocalConversation, error) GetAllConversations(ctx context.Context) ([]*model_struct.LocalConversation, error) GetAllSingleConversationIDList(ctx context.Context) (result []string, err error) diff --git a/test/config.go b/test/config.go index fb0a3c7a3..755c5bc49 100644 --- a/test/config.go +++ b/test/config.go @@ -19,7 +19,7 @@ import "github.com/openimsdk/protocol/constant" const ( APIADDR = "http://127.0.0.1:10002" WSADDR = "ws://127.0.0.1:10001" - UserID = "3717417654" + UserID = "2237746339" ) const ( diff --git a/test/conversation_test.go b/test/conversation_test.go index f188403d3..7d6419ab8 100644 --- a/test/conversation_test.go +++ b/test/conversation_test.go @@ -232,6 +232,13 @@ func Test_MarkConversationMessageAsRead(t *testing.T) { } } +func Test_MarkAllConversationMessageAsRead(t *testing.T) { + err := open_im_sdk.UserForSDK.Conversation().MarkAllConversationMessageAsRead(ctx) + if err != nil { + t.Fatal(err) + } +} + func Test_MarkMsgsAsRead(t *testing.T) { err := open_im_sdk.UserForSDK.Conversation().MarkMessagesAsReadByMsgID(ctx, "si_2688118337_7249315132", []string{"fb56ed151b675e0837ed3af79dbf66b1", diff --git a/test/create_msg_test.go b/test/create_msg_test.go index b4a44bac8..7542acbf2 100644 --- a/test/create_msg_test.go +++ b/test/create_msg_test.go @@ -184,3 +184,16 @@ func Test_CreateForwardMessage(t *testing.T) { } t.Log(message) } + +func Test_FetchSurroundingMessages(t *testing.T) { + msgs, err := open_im_sdk.UserForSDK.Conversation().FetchSurroundingMessages(ctx, "sg_3559850526", 15, 14, 8) + if err != nil { + t.Error(err) + return + } + t.Log(len(msgs)) + for _, msg := range msgs { + t.Logf("[%d] %#v", msg.Seq, msg.TextElem) + } + t.Log(msgs) +} diff --git a/test/init.go b/test/init.go index 657206f33..db0432850 100644 --- a/test/init.go +++ b/test/init.go @@ -55,11 +55,15 @@ func init() { if err := open_im_sdk.UserForSDK.Login(ctx, UserID, token); err != nil { panic(err) } - open_im_sdk.UserForSDK.SetConversationListener(&onConversationListener{ctx: ctx}) + ch := make(chan error) + open_im_sdk.UserForSDK.SetConversationListener(&onConversationListener{ctx: ctx, ch: ch}) open_im_sdk.UserForSDK.SetGroupListener(&onGroupListener{ctx: ctx}) open_im_sdk.UserForSDK.SetAdvancedMsgListener(&onAdvancedMsgListener{ctx: ctx}) open_im_sdk.UserForSDK.SetFriendshipListener(&onFriendshipListener{ctx: ctx}) open_im_sdk.UserForSDK.SetUserListener(&onUserListener{ctx: ctx}) + if err := <-ch; err != nil { + panic(err) + } } func getConf(APIADDR, WSADDR string) sdk_struct.IMConfig { diff --git a/test/listener.go b/test/listener.go index 94c0d8ab7..ac8159079 100644 --- a/test/listener.go +++ b/test/listener.go @@ -16,6 +16,7 @@ package test import ( "context" + "fmt" "github.com/openimsdk/tools/log" ) @@ -45,6 +46,7 @@ func (c *OnConnListener) OnUserTokenExpired() { type onConversationListener struct { ctx context.Context + ch chan error } func (o *onConversationListener) OnSyncServerStart(reinstalled bool) { @@ -53,10 +55,12 @@ func (o *onConversationListener) OnSyncServerStart(reinstalled bool) { func (o *onConversationListener) OnSyncServerFinish(reinstalled bool) { log.ZInfo(o.ctx, "OnSyncServerFinish") + o.ch <- nil } func (o *onConversationListener) OnSyncServerFailed(reinstalled bool) { log.ZInfo(o.ctx, "OnSyncServerFailed") + o.ch <- fmt.Errorf("OnSyncServerFailed") } func (o *onConversationListener) OnSyncServerProgress(progress int) { diff --git a/tools/changelog/changelog.go b/tools/changelog/changelog.go new file mode 100644 index 000000000..845a3d821 --- /dev/null +++ b/tools/changelog/changelog.go @@ -0,0 +1,193 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "regexp" + "strings" +) + +// You can specify a tag as a command line argument to generate the changelog for a specific version. +// Example: go run tools/changelog/changelog.go v0.0.33 +// If no tag is provided, the latest release will be used. + +// Setting repo owner and repo name by generate changelog +const ( + repoOwner = "openimsdk" + repoName = "openim-sdk-core" +) + +// GitHubRepo struct represents the repo details. +type GitHubRepo struct { + Owner string + Repo string + FullChangelog string +} + +// ReleaseData represents the JSON structure for release data. +type ReleaseData struct { + TagName string `json:"tag_name"` + Body string `json:"body"` + HtmlUrl string `json:"html_url"` + Published string `json:"published_at"` +} + +// Method to classify and format release notes. +func (g *GitHubRepo) classifyReleaseNotes(body string) map[string][]string { + result := map[string][]string{ + "feat": {}, + "fix": {}, + "chore": {}, + "refactor": {}, + "build": {}, + "other": {}, + } + + // Regular expression to extract PR number and URL (case insensitive) + rePR := regexp.MustCompile(`(?i)in (https://github\.com/[^\s]+/pull/(\d+))`) + + // Split the body into individual lines. + lines := strings.Split(body, "\n") + + for _, line := range lines { + // Use a regular expression to extract Full Changelog link and its title (case insensitive). + if strings.Contains(strings.ToLower(line), "**full changelog**") { + matches := regexp.MustCompile(`(?i)\*\*full changelog\*\*: (https://github\.com/[^\s]+/compare/([^\s]+))`).FindStringSubmatch(line) + if len(matches) > 2 { + // Format the Full Changelog link with title + g.FullChangelog = fmt.Sprintf("[%s](%s)", matches[2], matches[1]) + } + continue // Skip further processing for this line. + } + + if strings.HasPrefix(line, "*") { + var category string + + // Use strings.ToLower to make the matching case insensitive + lowerLine := strings.ToLower(line) + + // Determine the category based on the prefix (case insensitive). + if strings.HasPrefix(lowerLine, "* feat") { + category = "feat" + } else if strings.HasPrefix(lowerLine, "* fix") { + category = "fix" + } else if strings.HasPrefix(lowerLine, "* chore") { + category = "chore" + } else if strings.HasPrefix(lowerLine, "* refactor") { + category = "refactor" + } else if strings.HasPrefix(lowerLine, "* build") { + category = "build" + } else { + category = "other" + } + + // Extract PR number and URL (case insensitive) + matches := rePR.FindStringSubmatch(line) + if len(matches) == 3 { + prURL := matches[1] + prNumber := matches[2] + // Format the line with the PR link and use original content for the final result + formattedLine := fmt.Sprintf("* %s [#%s](%s)", strings.Split(line, " by ")[0][2:], prNumber, prURL) + result[category] = append(result[category], formattedLine) + } else { + // If no PR link is found, just add the line as is + result[category] = append(result[category], line) + } + } + } + + return result +} + +// Method to generate the final changelog. +func (g *GitHubRepo) generateChangelog(tag, date, htmlURL, body string) string { + sections := g.classifyReleaseNotes(body) + + // Convert ISO 8601 date to simpler format (YYYY-MM-DD) + formattedDate := date[:10] + + // Changelog header with tag, date, and links. + changelog := fmt.Sprintf("## [%s](%s) \t(%s)\n\n", tag, htmlURL, formattedDate) + + if len(sections["feat"]) > 0 { + changelog += "### New Features\n" + strings.Join(sections["feat"], "\n") + "\n\n" + } + if len(sections["fix"]) > 0 { + changelog += "### Bug Fixes\n" + strings.Join(sections["fix"], "\n") + "\n\n" + } + if len(sections["chore"]) > 0 { + changelog += "### Chores\n" + strings.Join(sections["chore"], "\n") + "\n\n" + } + if len(sections["refactor"]) > 0 { + changelog += "### Refactors\n" + strings.Join(sections["refactor"], "\n") + "\n\n" + } + if len(sections["build"]) > 0 { + changelog += "### Builds\n" + strings.Join(sections["build"], "\n") + "\n\n" + } + if len(sections["other"]) > 0 { + changelog += "### Others\n" + strings.Join(sections["other"], "\n") + "\n\n" + } + + if g.FullChangelog != "" { + changelog += fmt.Sprintf("**Full Changelog**: %s\n", g.FullChangelog) + } + + return changelog +} + +// Method to fetch release data from GitHub API. +func (g *GitHubRepo) fetchReleaseData(version string) (*ReleaseData, error) { + var apiURL string + + if version == "" { + // Fetch the latest release. + apiURL = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", g.Owner, g.Repo) + } else { + // Fetch a specific version. + apiURL = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version) + } + + resp, err := http.Get(apiURL) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var releaseData ReleaseData + err = json.Unmarshal(body, &releaseData) + if err != nil { + return nil, err + } + + return &releaseData, nil +} + +func main() { + repo := &GitHubRepo{Owner: repoOwner, Repo: repoName} + + // Get the version from command line arguments, if provided + var version string // Default is use latest + + if len(os.Args) > 1 { + version = os.Args[1] // Use the provided version + } + + // Fetch release data (either for latest or specific version) + releaseData, err := repo.fetchReleaseData(version) + if err != nil { + fmt.Println("Error fetching release data:", err) + return + } + + // Generate and print the formatted changelog + changelog := repo.generateChangelog(releaseData.TagName, releaseData.Published, releaseData.HtmlUrl, releaseData.Body) + fmt.Println(changelog) +} diff --git a/version/version.go b/version/version.go index 23b3a82f5..32ad27808 100644 --- a/version/version.go +++ b/version/version.go @@ -1,6 +1,14 @@ package version -import _ "embed" +import ( + _ "embed" + "strings" +) //go:embed version var Version string + +func init() { + Version = strings.Trim(Version, "\n") + Version = strings.TrimSpace(Version) +} diff --git a/wasm/cmd/main.go b/wasm/cmd/main.go index 13898f9db..efe7e5efc 100644 --- a/wasm/cmd/main.go +++ b/wasm/cmd/main.go @@ -82,6 +82,7 @@ func registerFunc() { js.Global().Set("createImageMessageFromFullPath", js.FuncOf(wrapperConMsg.CreateImageMessageFromFullPath)) js.Global().Set("getAtAllTag", js.FuncOf(wrapperConMsg.GetAtAllTag)) js.Global().Set("markConversationMessageAsRead", js.FuncOf(wrapperConMsg.MarkConversationMessageAsRead)) + js.Global().Set("markAllConversationMessageAsRead", js.FuncOf(wrapperConMsg.MarkAllConversationMessageAsRead)) js.Global().Set("markMessagesAsReadByMsgID", js.FuncOf(wrapperConMsg.MarkMessagesAsReadByMsgID)) js.Global().Set("sendMessage", js.FuncOf(wrapperConMsg.SendMessage)) js.Global().Set("sendMessageNotOss", js.FuncOf(wrapperConMsg.SendMessageNotOss)) @@ -120,6 +121,7 @@ func registerFunc() { js.Global().Set("changeInputStates", js.FuncOf(wrapperConMsg.ChangeInputStates)) js.Global().Set("getInputStates", js.FuncOf(wrapperConMsg.GetInputStates)) + js.Global().Set("fetchSurroundingMessages", js.FuncOf(wrapperConMsg.FetchSurroundingMessages)) //register group func wrapperGroup := wasm_wrapper.NewWrapperGroup(globalFuc) diff --git a/wasm/cmd/static/wasm_exec.js b/wasm/cmd/static/wasm_exec.js index e6c892109..4bb58a9d9 100644 --- a/wasm/cmd/static/wasm_exec.js +++ b/wasm/cmd/static/wasm_exec.js @@ -1,7 +1,3 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - "use strict"; (() => { diff --git a/wasm/indexdb/conversation_model.go b/wasm/indexdb/conversation_model.go index ef9dccba0..e5a817fd7 100644 --- a/wasm/indexdb/conversation_model.go +++ b/wasm/indexdb/conversation_model.go @@ -56,6 +56,23 @@ func (i *LocalConversations) GetAllConversationListDB(ctx context.Context) (resu } } +func (i *LocalConversations) FindAllUnreadConversationConversationID(ctx context.Context) (result []string, err error) { + cList, err := exec.Exec() + if err != nil { + return nil, err + } else { + if v, ok := cList.(string); ok { + err := utils.JsonStringToStruct(v, &result) + if err != nil { + return nil, err + } + return result, nil + } else { + return nil, exec.ErrType + } + } +} + func (i *LocalConversations) GetConversation(ctx context.Context, conversationID string) (*model_struct.LocalConversation, error) { c, err := exec.Exec(conversationID) if err != nil { diff --git a/wasm/wasm_wrapper/wasm_conversation_msg.go b/wasm/wasm_wrapper/wasm_conversation_msg.go index 49256fbf4..de19706e2 100644 --- a/wasm/wasm_wrapper/wasm_conversation_msg.go +++ b/wasm/wasm_wrapper/wasm_conversation_msg.go @@ -122,6 +122,12 @@ func (w *WrapperConMsg) MarkConversationMessageAsRead(_ js.Value, args []js.Valu callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) return event_listener.NewCaller(open_im_sdk.MarkConversationMessageAsRead, callback, &args).AsyncCallWithCallback() } + +func (w *WrapperConMsg) MarkAllConversationMessageAsRead(_ js.Value, args []js.Value) interface{} { + callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) + return event_listener.NewCaller(open_im_sdk.MarkAllConversationMessageAsRead, callback, &args).AsyncCallWithCallback() +} + func (w *WrapperConMsg) MarkMessagesAsReadByMsgID(_ js.Value, args []js.Value) interface{} { callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) return event_listener.NewCaller(open_im_sdk.MarkMessagesAsReadByMsgID, callback, &args).AsyncCallWithCallback() @@ -295,3 +301,8 @@ func (w *WrapperConMsg) GetInputStates(_ js.Value, args []js.Value) interface{} callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) return event_listener.NewCaller(open_im_sdk.GetInputStates, callback, &args).AsyncCallWithCallback() } + +func (w *WrapperConMsg) FetchSurroundingMessages(_ js.Value, args []js.Value) interface{} { + callback := event_listener.NewBaseCallback(utils.FirstLower(utils.GetSelfFuncName()), w.commonFunc) + return event_listener.NewCaller(open_im_sdk.FetchSurroundingMessages, callback, &args).AsyncCallWithCallback() +}