Skip to content

Conversation

@Zdanquxunhuan
Copy link
Contributor

@Zdanquxunhuan Zdanquxunhuan commented May 16, 2025

Offline message -demo

Summary by CodeRabbit

  • New Features

    • Added offline message storage and retrieval, supporting Redis and MySQL backends.
    • Users receive messages sent while offline upon reconnection.
    • New configuration options to switch offline message storage modes.
    • Enhanced API endpoints to fetch and save offline messages.
    • Introduced unique ID generation for offline messages.
    • Added offline message persistence and delivery status tracking.
    • Improved client SDK to fetch offline messages after connection.
    • Added new test coverage for offline messaging with Redis and MySQL.
    • Added support for MySQL datasource and MyBatis ORM configuration.
    • Introduced wait-for-it.sh script for TCP service readiness checks.
  • Bug Fixes

    • Improved error handling for missing client instances during message processing.
  • Documentation

    • Simplified build instructions and updated configuration documentation.
  • Chores

    • Added new SQL schema for offline message tables.
    • Integrated MySQL test containers in automated tests.
    • Updated Dockerfile to copy local wait-for-it.sh script.

zhongcanyu and others added 30 commits April 29, 2025 10:43
This reverts commit 5f868b9.
…solve possible data inconsistency problems
…neMsg

# Conflicts:
#	cim-server/src/main/resources/application.yaml
@crossoverJie crossoverJie requested a review from Copilot June 4, 2025 05:04
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds support for offline message storage and retrieval across Redis and MySQL, updates client‐side logic to fetch and deliver those messages, and integrates necessary configuration and proto changes.

  • Introduces OfflineModel constants and conditional Spring beans for Redis/MySQL storage.
  • Extends client implementation with a scheduled task to pull offline messages after connection.
  • Updates the protocol definition, error codes, tests, and build configuration for offline messaging.

Reviewed Changes

Copilot reviewed 65 out of 65 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Constant.java Added OfflineModel inner class for storage modes
OfflineMsgStoreConfig.java Configures Redis/MySQL beans based on offline.store.mode
BeanConfig.java Added SnowflakeIdWorker bean (plus unused imports)
RouteApplication.java Excluded DataSource auto-config and adjusted component scan
pom.xml Added persistence and Testcontainers dependencies
cim-common/src/main/proto/cim.proto Added OFFLINE to BaseCommand enum
ClientImpl.java Instantiates RingBufferWheel for offline fetch
RouteManager.java Added fetchOfflineMsgs stub
OfflineMsgTest.java New end-to-end offline messaging test
README.md Simplified Maven build instructions
Comments suppressed due to low confidence (4)

README.md:128

  • [nitpick] The consolidated Maven command may not build all modules in multi-module setups; verify or split into explicit module build steps for clarity.
mvn clean install -DskipTests=true

cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java:32

  • [nitpick] Add JavaDoc for FETCH_OFFLINE_MSG_LIMIT (and related offline status constants) to explain their purpose, valid range, and usage context, or consider grouping them into an enum.
public static final Integer FETCH_OFFLINE_MSG_LIMIT = 100 ;

cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java:29

  • [nitpick] Consider renaming OfflineModel to OfflineStoreMode or OfflineStorageType to clarify that these constants represent storage backends.
public final static class OfflineModel {

cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java:103

  • The RingBufferWheel is instantiated and tasks are added but never started; add a call to ringBufferWheel.start() so the offline fetch job actually runs.
ringBufferWheel = new RingBufferWheel(Executors.newFixedThreadPool(1));

@coderabbitai
Copy link

coderabbitai bot commented Jun 5, 2025

Walkthrough

This update introduces a comprehensive offline messaging feature to the system. It adds support for offline message storage using both MySQL and Redis, with new persistence modules, configuration options, and database schemas. The client and route layers are extended to fetch, store, and deliver offline messages, and integration tests are provided for both storage modes. Supporting changes include protocol updates, new constants, and enhancements to configuration and test infrastructure.

Changes

File(s) / Group Change Summary
README.md Simplified local build instructions.
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/FetchOfflineMsgJob.java Added job class to trigger offline message fetching.
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java Added method to fetch offline messages by user ID.
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java Added offline message fetch scheduling and ring buffer cleanup.
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandle.java Added null-check for missing client instances.
cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java Updated route server startup to specify offline mode and ensured client cleanup.
cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java Added tests for P2P offline messaging with Redis and MySQL.
cim-client-sdk/src/test/resources/application-route.yaml Added offline store mode config and blank lines.
cim-client-sdk/src/test/resources/init.sql Added SQL for offline message and last send record tables.
cim-client/src/main/resources/application.yaml Updated user ID, username, and callback thread config.
cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java Added constants for offline message handling and types.
cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java Added enum values for offline message errors.
cim-common/src/main/java/com/crossoverjie/cim/common/util/RandomUtil.java Removed random integer utility class.
cim-common/src/main/java/com/crossoverjie/cim/common/util/SnowflakeIdWorker.java Added Snowflake-based unique ID generator.
cim-common/src/main/proto/cim.proto Added OFFLINE command to protocol enum.
cim-forward-route/pom.xml Added dependencies for persistence modules and MySQL testcontainers.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java Excluded datasource auto-configuration and expanded component scanning.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java Added SnowflakeIdWorker bean.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/MySqlPersistenceConfig.java Added MySQL persistence config, conditional on offline store mode.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/OfflineMsgStoreConfig.java Added beans for offline message store (MySQL or Redis).
cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java Added constants for offline store modes.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java Added endpoint and logic for fetching and saving offline messages.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/factory/OfflineMsgFactory.java Added factory for building offline message entities.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java Added import; no interface changes.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/OfflineMsgService.java Added interface for offline message service.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java Updated message command usage in pushMsg.
cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/OfflineMsgServiceImpl.java Implemented offline message fetch and save logic.
cim-forward-route/src/main/resources/application.yaml Added MySQL, MyBatis, and offline store mode configs.
cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AbstractBaseTest.java Added MySQL testcontainer and dynamic datasource config.
cim-forward-route/src/test/resources/application.yaml Added MySQL and MyBatis test configs; set offline store mode to MySQL.
cim-forward-route/src/test/resources/init.sql Added SQL for offline message and last send record tables.
cim-integration-test/pom.xml Added MySQL testcontainers dependency.
cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/AbstractRouteBaseTest.java Made application context protected; allowed offline mode parameter.
cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/OfflineMsgStoreRouteBaseTest.java Added base test for offline message store with MySQL/Redis switching.
cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/server/AbstractServerBaseTest.java Excluded datasource auto-config in server startup.
cim-integration-test/src/test/resources/application-route.yaml Added MySQL datasource config.
cim-persistence/pom.xml Added new persistence parent module with submodules.
cim-persistence/cim-persistence-api/pom.xml Added API module for persistence with Redis dependency.
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/config/BeanConfig.java Added RedisTemplate and Jackson2HashMapper beans.
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsg.java Added POJO for offline message entity.
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsgLastSendRecord.java Added POJO for last sent offline message record.
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/service/OfflineMsgStore.java Added interface for offline message storage operations.
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/vo/req/SaveOfflineMsgReqVO.java Added request VO for saving offline messages.
cim-persistence/cim-persistence-mysql/pom.xml Added MySQL persistence module with dependencies.
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/config/MyBatisConfig.java Added MyBatis config and custom type handler registration.
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/OfflineMsgDb.java Added MySQL-based offline message store implementation.
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java Added MyBatis mapper for last send record.
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgMapper.java Added MyBatis mapper for offline messages.
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java Added type handler for Map-to-JSON conversion.
cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgLastSendRecordMapper.xml Added MyBatis XML for last send record operations.
cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgMapper.xml Added MyBatis XML for offline message operations.
cim-persistence/cim-persistence-redis/pom.xml Added Redis persistence module with dependencies.
cim-persistence/cim-persistence-redis/src/main/java/com/crossoverjie/cim/persistence/redis/OfflineMsgBuffer.java Added Redis-based offline message buffer implementation.
cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java Added fetchOfflineMsgs method to API interface.
cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/OfflineMsgReqVO.java Added VO for offline message fetch requests.
cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java Added command field, builder, and constructor; updated to use Lombok.
cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/res/OfflineMsgResVO.java Added VO for offline message responses.
cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/res/SaveOfflineMsgResVO.java Added VO for save offline message responses.
cim-server/pom.xml Removed extraneous blank lines.
cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java Added ObjectMapper import.
cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java Changed command field in sendMsg to use request value.
cim-server/src/main/resources/application.yaml Whitespace adjustments only.
docker/allin1-ubuntu.Dockerfile Changed wait-for-it.sh to be copied from local context.
docker/wait-for-it.sh Added script to wait for TCP service readiness.
pom.xml Added cim-persistence module and MySQL testcontainers dependency.
sql/01schema.sql Added SQL to create cim-test database.
sql/offline_msg.sql Added SQL to create offline_msg table.
sql/offline_msg_last_send_record.sql Added SQL to create offline_msg_last_send_record table.
cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java Enhanced error message on HTTP POST failure.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant RouteManager
    participant RouteApi
    participant RouteController
    participant OfflineMsgService
    participant OfflineMsgStore (MySQL/Redis)
    participant ServerApi
    participant Server

    %% User goes offline and message is sent
    Client->>RouteManager: Send P2P message
    RouteManager->>RouteApi: p2pRoute(P2PReqVO)
    RouteApi->>RouteController: p2pRoute
    RouteController->>OfflineMsgService: saveOfflineMsg(P2PReqVO)
    OfflineMsgService->>OfflineMsgStore: save(OfflineMsg)
    OfflineMsgStore-->>OfflineMsgService: Ack
    OfflineMsgService-->>RouteController: Ack
    RouteController-->>RouteManager: User offline, message saved

    %% User comes online and fetches offline messages
    Client->>RouteManager: fetchOfflineMsgs(userId)
    RouteManager->>RouteApi: fetchOfflineMsgs(OfflineMsgReqVO)
    RouteApi->>RouteController: fetchOfflineMsgs
    RouteController->>OfflineMsgService: fetchOfflineMsgs(serverInfo, userId)
    OfflineMsgService->>OfflineMsgStore: fetch(userId)
    OfflineMsgStore-->>OfflineMsgService: List<OfflineMsg>
    OfflineMsgService->>ServerApi: send batch messages to user
    ServerApi->>Server: Deliver messages
    OfflineMsgService->>OfflineMsgStore: markDelivered(userId, messageIds)
    OfflineMsgStore-->>OfflineMsgService: Ack
    OfflineMsgService-->>RouteController: Ack
    RouteController-->>RouteManager: Success
Loading

Poem

🐇
Hopping through the code so bright,
Now messages wait through day and night.
MySQL or Redis, the choice is yours—
Offline or online, delivery ensures!
With snowflake IDs and tests that pass,
Offline chat is here at last.
📨✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc804bd and b71e776.

📒 Files selected for processing (1)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 27

♻️ Duplicate comments (9)
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java (1)

83-86: ⚠️ Potential issue

Handle the response payload for offline messages.

This implementation ignores the response from fetchOfflineMsgs, which means fetched offline messages are not processed or delivered to the client.

Implement proper response handling:

-public void fetchOfflineMsgs(Long userId){
+public void fetchOfflineMsgs(Long userId) {
     OfflineMsgReqVO offlineMsgReqVO = OfflineMsgReqVO.builder().receiveUserId(userId).build();
-    routeApi.fetchOfflineMsgs(offlineMsgReqVO);
+    try {
+        BaseResponse<Set<String>> response = routeApi.fetchOfflineMsgs(offlineMsgReqVO);
+        if (response.getCode().equals(StatusEnum.SUCCESS.getCode())) {
+            event.info("Fetched offline messages: {}", response.getDataBody());
+            // Process and deliver messages to client listener
+        } else {
+            event.warn("Failed to fetch offline messages: {}", response.getMessage());
+        }
+    } catch (Exception e) {
+        event.error("Error fetching offline messages", e);
+    }
 }
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java (1)

139-142: Address the hardcoded workerId configuration in SnowflakeIdWorker.

The bean definition is correct, but the underlying SnowflakeIdWorker has a hardcoded workerId = 1L which could cause ID collisions in a clustered environment where multiple instances generate IDs simultaneously.

Consider externalizing the workerId configuration:

 @Bean
 public SnowflakeIdWorker snowflakeIdWorker() {
-    return new SnowflakeIdWorker();
+    return new SnowflakeIdWorker(appConfiguration.getWorkerId());
 }

And update the SnowflakeIdWorker constructor to accept a configurable workerId parameter.

cim-forward-route/src/main/resources/application.yaml (1)

15-19: Remove hard-coded credentials even from commented sections.

Even though the datasource configuration is commented out, it still contains hard-coded credentials that could be accidentally exposed or committed to version control.

Apply this diff to remove the sensitive information:

-#    password: zcyzcy159162
+#    password: ${DB_PASSWORD}
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java (2)

34-34: 🛠️ Refactor suggestion

Address the wildcard import as previously suggested.

This duplicates a previous review comment about avoiding wildcard imports. Please use specific imports instead.

-import java.util.concurrent.*;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;

238-238: ⚠️ Potential issue

Add null check before stopping ringBufferWheel.

This addresses a previous review comment about preventing potential NullPointerException.

-        ringBufferWheel.stop(true);
+        if (ringBufferWheel != null) {
+            ringBufferWheel.stop(true);
+            ringBufferWheel = null;
+        }
cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java (1)

119-121: Review exception flow after offline message saving.

The current implementation saves the offline message but then immediately throws an exception. This could potentially cause issues with transaction rollback or downstream error handling, as noted in previous reviews.

Consider whether the exception should be thrown after successfully saving the offline message, or if a different response pattern would be more appropriate for offline scenarios.

cim-common/src/main/java/com/crossoverjie/cim/common/util/SnowflakeIdWorker.java (1)

8-46: Consider architectural placement based on past feedback.

Based on past review feedback, basic components in the common package should not be handed over to Spring management directly, but should be managed at the application layer (route module).

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/OfflineMsgServiceImpl.java (1)

46-63: ⚠️ Potential issue

Add safeguards to prevent infinite loop and CPU overuse.

This while(true) loop can cause busy spinning if messages continuously arrive or if there are issues with the persistence layer.

Apply this diff to add safeguards:

+    private static final int MAX_ITERATIONS = 1000;
+    private static final long LOOP_DELAY_MS = 100;
+
     @Override
     public void fetchOfflineMsgs(CIMServerResVO cimServerResVO, Long receiveUserId) {
         String url = "http://" + cimServerResVO.getIp() + ":" + cimServerResVO.getHttpPort();
-        while (true) {
+        int iterationCount = 0;
+        while (iterationCount < MAX_ITERATIONS) {
             List<OfflineMsg> offlineMsgs = offlineMsgStore.fetch(receiveUserId);
             if (offlineMsgs == null || offlineMsgs.isEmpty()) {
                 break;
             }
+            iterationCount++;
             // ... existing logic ...
             offlineMsgStore.markDelivered(receiveUserId, offlineMsgs.stream().map(OfflineMsg::getMessageId).toList());
+            
+            try {
+                Thread.sleep(LOOP_DELAY_MS);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                break;
+            }
         }
     }
cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgMapper.xml (1)

61-68: ⚠️ Potential issue

Add missing status filter for consistency.

This query is missing the status=0 condition that's present in fetchOfflineMsgsWithCursor, leading to inconsistent behavior.

Apply this diff to add the missing condition:

     <select id="fetchOfflineMsgIdsWithCursor" resultType="java.lang.Long" parameterType="java.lang.Long">
         SELECT
         message_id
         FROM offline_msg
-        WHERE receive_user_id = #{receiveUserId}
+        WHERE receive_user_id = #{receiveUserId} and status=0
         AND message_id &gt; (select last_message_id from offline_msg_last_send_record where receive_user_id = #{receiveUserId})
         ORDER BY message_id ASC
     </select>
🧹 Nitpick comments (42)
cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java (1)

9-9: Remove unused import.

The added import com.fasterxml.jackson.databind.ObjectMapper; is not referenced in this class, resulting in an unused import. Either remove this line or add a corresponding @Bean definition for ObjectMapper if it’s required.

cim-server/src/main/resources/application.yaml (1)

35-36: Excessive blank lines
YAMLlint flags two consecutive blank lines here. Please collapse them to at most one blank line to satisfy lint rules and maintain readability.

🧰 Tools
🪛 YAMLlint (1.37.1)

[warning] 36-36: too many blank lines

(2 > 0) (empty-lines)

docker/wait-for-it.sh (3)

36-40: Quote host/port expansions to avoid word-splitting.

Unquoted $WAITFORIT_HOST/$WAITFORIT_PORT could break on values with spaces or special chars. Wrap them in quotes:

-    nc -z $WAITFORIT_HOST $WAITFORIT_PORT
+    nc -z "$WAITFORIT_HOST" "$WAITFORIT_PORT"
...
-    (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
+    (echo -n > "/dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT") >/dev/null 2>&1

75-77: Robustly split host:port without word-splitting pitfalls.

Bash arrays for splitting can misbehave; use IFS and read instead:

-        WAITFORIT_hostport=(${1//:/ })
-        WAITFORIT_HOST=${WAITFORIT_hostport[0]}
-        WAITFORIT_PORT=${WAITFORIT_hostport[1]}
+        IFS=: read -r WAITFORIT_HOST WAITFORIT_PORT <<< "$1"
🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 75-75: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.

(SC2206)


174-174: Check for non-empty CLI array correctly.

[[ $WAITFORIT_CLI != "" ]] only inspects the first element. Use array length:

-    if [[ $WAITFORIT_CLI != "" ]]; then
+    if [[ ${#WAITFORIT_CLI[@]} -gt 0 ]]; then
🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 174-174: Expanding an array without an index only gives the first element.

(SC2128)

docker/allin1-ubuntu.Dockerfile (1)

28-29: Optional: Install script to a standard bin directory.

For consistency, consider copying to /usr/local/bin so it’s on PATH and not at root:

-COPY wait-for-it.sh /wait-for-it.sh
-RUN chmod +x /wait-for-it.sh
+COPY wait-for-it.sh /usr/local/bin/wait-for-it.sh
+RUN chmod +x /usr/local/bin/wait-for-it.sh
sql/offline_msg_last_send_record.sql (1)

1-6: Add default timestamp to updated_at Consider defining updated_at with NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP so the column auto-populates and updates on record changes.

sql/offline_msg.sql (1)

1-11: Define defaults and tighten constraints It’s advisable to add NOT NULL and default values, e.g.:

status TINYINT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

Also evaluate if content or properties should use TEXT instead of VARCHAR(2000) for larger payloads.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java (1)

6-6: Remove unused import P2PReqVO is imported but never referenced in this interface. Please remove it to avoid compiler warnings and improve clarity.

sql/01schema.sql (1)

2-2: Consider adding IF NOT EXISTS for idempotency.

The database creation with UTF8MB4 character set is appropriate for international support. However, consider adding IF NOT EXISTS to make the script idempotent.

-create database `cim-test` default character set utf8mb4 collate utf8mb4_general_ci;
+create database if not exists `cim-test` default character set utf8mb4 collate utf8mb4_general_ci;
cim-client/src/main/resources/application.yaml (1)

31-33: Review thread pool sizing.
Increasing the callback queue to 10 while reducing the pool size to 1 may create a processing bottleneck; confirm these settings meet your throughput and latency requirements.

cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/res/OfflineMsgResVO.java (2)

3-7: Provide meaningful class-level JavaDoc.
The current Javadoc block is empty; consider adding a description of the VO’s purpose or responsibilities.


10-18: Reduce boilerplate and fix formatting.
Consider using Lombok annotations (e.g., @Data) to generate getters/setters automatically and remove the extra space before the semicolon in private String msg ;.

cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java (1)

93-93: Good implementation of dynamic command support.

This change successfully addresses the past review feedback by making the command dynamic based on the SendMsgReqVO.cmd field, enabling differentiation between regular and offline messages.

Consider adding validation to ensure only valid commands are processed:

 Request.Builder requestBuilder = Request.newBuilder()
         .setRequestId(sendMsgReqVO.getUserId())
         .putAllProperties(sendMsgReqVO.getProperties())
+        .setCmd(sendMsgReqVO.getCmd() != null ? sendMsgReqVO.getCmd() : BaseCommand.MESSAGE);
-        .setCmd(sendMsgReqVO.getCmd());
cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java (1)

7-7: Consider specific imports over wildcard import.

While wildcard imports reduce clutter, they can hide unused imports and make dependencies less explicit.

cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/res/SaveOfflineMsgResVO.java (1)

1-15: Consider using Lombok for cleaner code.

The class follows standard VO patterns but could benefit from modern Java practices for better maintainability.

Apply Lombok annotations to reduce boilerplate:

+import lombok.Data;
+
+@Data
 public class SaveOfflineMsgResVO {
     private String msg;
-
-    public String getMsg() {
-        return msg;
-    }
-
-    public void setMsg(String msg) {
-        this.msg = msg;
-    }
 }
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/FetchOfflineMsgJob.java (1)

7-7: Consider externalizing the delay configuration.

The hardcoded 5-second delay might not be suitable for all environments. Consider making this configurable through application properties.

-private static final int INITIAL_DELAY_SECONDS = 5;
+private final int delaySeconds;

-public FetchOfflineMsgJob(RouteManager routeManager, ClientConfigurationData conf) {
+public FetchOfflineMsgJob(RouteManager routeManager, ClientConfigurationData conf, int delaySeconds) {
     this.routeManager = routeManager;
     this.conf = conf;
-    setKey(INITIAL_DELAY_SECONDS);
+    this.delaySeconds = delaySeconds;
+    setKey(delaySeconds);
 }
cim-integration-test/src/test/resources/application-route.yaml (1)

16-20: Validate MySQL Testcontainer configuration and credentials handling.

This hardcodes spring.datasource.url to localhost:3306 and expects ${DB_PASSWORD} to be set in the environment. Ensure your CI/Dev environments or Testcontainers override these properties (host, port, credentials) correctly. Consider externalizing or templating the URL/credentials so tests can spin up MySQL containers dynamically.

Would you like a helper script to inject Testcontainer‐driven properties in this YAML or examples for secure password management?

cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java (2)

31-33: Prefer primitive types for constants.

Using int instead of Integer avoids unnecessary boxing/unboxing and clarifies immutability:

-public static final Integer FETCH_OFFLINE_MSG_LIMIT = 100 ;
+public static final int FETCH_OFFLINE_MSG_LIMIT = 100;

31-41: Add documentation and grouping for offline-message constants.

The new constants lack Javadoc and are mixed in the root class. Consider extracting them into a nested OfflineMsg or MsgType inner class with proper Javadoc, e.g.:

public static class OfflineMsg {
    /** Maximum number of messages fetched per request. */
    public static final int FETCH_LIMIT = 100;
    /** Pending offline message status. */
    public static final int STATUS_PENDING = 0;
    // ...
}
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/service/OfflineMsgStore.java (1)

13-37: Well-designed interface with room for improvement.

The OfflineMsgStore interface provides a clean abstraction for offline message operations. The three core methods (save, fetch, markDelivered) cover the essential functionality needed.

However, consider these improvements:

  1. Enhanced Javadoc: Add parameter and return value descriptions:
 /**
  * Save offline message
  *
- * @param offlineMsg
+ * @param offlineMsg the offline message to save
  */
 void save(OfflineMsg offlineMsg);

 /**
  * Fetch offline messages for a user
  *
- * @param userId
- * @return
+ * @param userId the user ID to fetch messages for
+ * @return list of offline messages for the user
  */
 List<OfflineMsg> fetch(Long userId);
  1. Consider pagination: The fetch method might need pagination support for users with many offline messages to avoid memory issues and improve performance.
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsg.java (2)

24-25: Consider using enums for better type safety.

The integer constants for messageType and status could be replaced with enums to provide better type safety and clearer API contracts.

Example implementation:

public enum MessageType {
    TEXT(0), IMAGE(1);
    private final int value;
    MessageType(int value) { this.value = value; }
    public int getValue() { return value; }
}

public enum MessageStatus {
    PENDING(0), ACKED(1);
    private final int value;
    MessageStatus(int value) { this.value = value; }
    public int getValue() { return value; }
}

28-29: Consider using English for all comments.

For consistency with the rest of the codebase, consider using English for all comments.

Apply this diff:

-    /**
-     * 消息来源存储在这里
-     */
+    /**
+     * Message source properties are stored here
+     */
cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/OfflineMsgService.java (2)

11-16: Enhance JavaDoc with parameter descriptions.

The JavaDoc could be more helpful by describing the parameters and their purposes.

Apply this diff:

     /**
      * fetch offline messages
-     * @param cimServerResVO
-     * @param receiveUserId
+     * @param cimServerResVO the CIM server information where messages should be sent
+     * @param receiveUserId the ID of the user to fetch offline messages for
      */

18-22: Enhance JavaDoc with parameter description.

Add parameter description for better API documentation.

Apply this diff:

     /**
      * save offline message
-     * @param p2pRequest
+     * @param p2pRequest the peer-to-peer message request to save as offline message
      */
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java (1)

65-65: Initialize the field to prevent potential issues.

Consider initializing the field to avoid potential null pointer issues during the construction phase.

-private RingBufferWheel ringBufferWheel;
+private RingBufferWheel ringBufferWheel = null;
cim-forward-route/src/test/resources/application.yaml (1)

67-67: Add missing newline at end of file.

Static analysis correctly identified a missing newline character at the end of the file.

 offline:
   store:
     mode: mysql
+
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 67-67: no new line character at the end of file

(new-line-at-end-of-file)

cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/OfflineMsgStoreRouteBaseTest.java (1)

34-34: Reconsider container reuse policy for test isolation.

The withReuse(true) setting may cause issues in concurrent test execution or when tests need clean state. Container reuse can lead to test interdependencies and flaky tests.

Consider removing reuse for better test isolation:

-                    .withReuse(true);
+                    .withReuse(false);
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgMapper.java (1)

11-15: Add comprehensive Javadoc documentation.

The class lacks proper documentation describing its purpose, usage, and method behaviors. This is especially important for persistence layer interfaces that define the data access contract.

 /**
- * @author zhongcanyu
- * @date 2025/5/9
- * @description
+ * MyBatis mapper interface for offline message persistence operations.
+ * Provides CRUD operations for managing offline messages in MySQL database.
+ * 
+ * @author zhongcanyu
+ * @date 2025/5/9
  */
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/OfflineMsgStoreConfig.java (1)

12-16: Add comprehensive class documentation.

The configuration class lacks proper documentation explaining the conditional bean creation and property requirements.

 /**
- * @author zhongcanyu
- * @date 2025/5/18
- * @description
+ * Configuration class for offline message storage implementations.
+ * Conditionally creates beans based on the 'offline.store.mode' property:
+ * - 'mysql': Creates OfflineMsgDb for MySQL-based storage
+ * - 'redis': Creates OfflineMsgBuffer for Redis-based storage
+ * 
+ * @author zhongcanyu
+ * @date 2025/5/18
  */
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java (1)

6-10: Add proper Javadoc documentation.

The class and methods lack meaningful documentation. Add descriptions explaining the purpose and behavior of each method.

 /**
- * @author zhongcanyu
- * @date 2025/5/10
- * @description
+ * Mapper interface for tracking the last sent offline message ID per user.
+ * This helps determine which messages are new when fetching offline messages.
+ * 
+ * @author zhongcanyu
+ * @date 2025/5/10
  */
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/config/BeanConfig.java (2)

33-44: Replace Chinese comments with English for consistency.

The codebase appears to use English comments throughout. Please translate the Chinese comments to maintain consistency.

-        // 设置键的序列化器为字符串
+        // Set key serializer to string
         redisTemplate.setKeySerializer(new StringRedisSerializer());

-        // 设置值的序列化器为JSON,支持对象存储
+        // Set value serializer to JSON for object storage support
         redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

-        // 设置Hash键和值的序列化器(可选)
+        // Set hash key and value serializers (optional)
         redisTemplate.setHashKeySerializer(new StringRedisSerializer());
         redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

-        // 初始化属性
+        // Initialize properties
         redisTemplate.afterPropertiesSet();

50-51: Add documentation for the Jackson2HashMapper configuration.

The comment about @class information could be more explanatory for maintainability.

-        // false 表示不在 key 里加 @class 信息
+        // false means do not include @class type information in hash keys
+        // This prevents Jackson from adding type metadata to Redis hash keys
         return new Jackson2HashMapper(objectMapper, false);
cim-persistence/cim-persistence-redis/src/main/java/com/crossoverjie/cim/persistence/redis/OfflineMsgBuffer.java (2)

73-78: Simplify lambda expression.

The lambda can be simplified by removing unnecessary stream operations.

-        messageIds.stream().forEach(messageId -> {
+        messageIds.forEach(messageId -> {
             String key = MSG_KEY + messageId;
             if (Boolean.TRUE.equals(redis.hasKey(key))) {
                 redis.opsForHash().put(key, "status", OFFLINE_MSG_DELIVERED);
             }
         });

44-45: Address potential data consistency issues with dual storage approach.

Using both hash storage for messages and list storage for user indexes can lead to consistency issues if one operation fails while the other succeeds.

Consider using Redis transactions or Lua scripts to ensure atomicity:

// Example using Redis transaction
redis.multi();
redis.opsForHash().putAll(key, hashMap);
redis.opsForList().rightPush(USER_IDX + msg.getReceiveUserId(), msg.getMessageId().toString());
redis.exec();
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/vo/req/SaveOfflineMsgReqVO.java (2)

15-21: Consider improving field naming consistency.

The field names could be more consistent - msg uses abbreviation while receiveUserId is fully spelled out. Consider using either message and receiveUserId or msg and receiverId for consistency.

-    @NotNull(message = "msg 不能为空")
+    @NotNull(message = "message 不能为空")
     @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "msg", example = "hello")
-    private String msg ;
+    private String message;

23-25: Remove redundant Lombok annotations.

The @Setter and @Getter annotations on the properties field are redundant since @Data already provides getters and setters for all fields.

-    @Setter
-    @Getter
     private Map<String, String> properties;
cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java (1)

51-54: Consider more robust state checking approach.

The current approach captures the state once and then waits for it to become Ready. However, the state is captured before the asynchronous connection process completes. Consider checking the state dynamically within the Awaitility assertion.

-        TimeUnit.SECONDS.sleep(3);
-        ClientState.State state = client1.getState();
         Awaitility.await().atMost(10, TimeUnit.SECONDS)
-                .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+                .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, client1.getState()));

Also applies to: 70-73

cim-client-sdk/src/test/resources/init.sql (1)

2-27: Consider adding foreign key constraints and improving data types.

The offline_msg table design is generally good but could benefit from a few improvements:

  1. Consider adding a foreign key constraint on receive_user_id if there's a users table
  2. The properties field using VARCHAR(2000) might be better as JSON type in MySQL 8.0+
  3. Consider adding a composite index on (receive_user_id, status) for efficient querying of pending messages
 CREATE TABLE IF NOT EXISTS `offline_msg`
 (
     `id`               BIGINT PRIMARY KEY AUTO_INCREMENT,
     `message_id`       BIGINT NOT NULL,
     `receive_user_id`  BIGINT NOT NULL,
     `content`          VARCHAR(2000),
     `message_type`     INT,
     `status`           TINYINT COMMENT '0: Pending, 1: Acked',
     `created_at`       DATETIME,
-    `properties`       VARCHAR(2000),
+    `properties`       JSON,
     INDEX `idx_receive_user_id` (`receive_user_id`),
+    INDEX `idx_receive_user_status` (`receive_user_id`, `status`)
 );
cim-forward-route/src/test/resources/init.sql (2)

2-27: Fix formatting inconsistencies and add missing engine specification.

The offline_msg table definition has inconsistent formatting and lacks an explicit storage engine specification, unlike the second table.

Apply this diff to improve consistency:

-CREATE TABLE IF NOT EXISTS `offline_msg`
-(
-    `id`
-                   BIGINT
-        PRIMARY
-            KEY
-        AUTO_INCREMENT,
-    `message_id`
-                   BIGINT
-        NOT
-            NULL,
-    `receive_user_id`
-                   BIGINT
-        NOT
-            NULL,
-    `content`
-                   VARCHAR(2000),
-    `message_type` INT,
-    `status`       TINYINT COMMENT '0: Pending, 1: Acked',
-    `created_at`   DATETIME,
-    `properties`   VARCHAR(2000),
-    INDEX `idx_receive_user_id`
-        (
-         `receive_user_id`
-            )
-);
+CREATE TABLE IF NOT EXISTS `offline_msg`
+(
+    `id`              BIGINT PRIMARY KEY AUTO_INCREMENT,
+    `message_id`      BIGINT NOT NULL,
+    `receive_user_id` BIGINT NOT NULL,
+    `content`         VARCHAR(2000),
+    `message_type`    INT,
+    `status`          TINYINT COMMENT '0: Pending, 1: Acked',
+    `created_at`      DATETIME,
+    `properties`      VARCHAR(2000),
+    INDEX `idx_receive_user_id` (`receive_user_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4;

17-22: Consider adding NOT NULL constraints and default values.

The schema could benefit from more explicit constraints to ensure data integrity.

Consider these improvements:

-    `content`         VARCHAR(2000),
-    `message_type`    INT,
-    `status`          TINYINT COMMENT '0: Pending, 1: Acked',
-    `created_at`      DATETIME,
-    `properties`      VARCHAR(2000),
+    `content`         VARCHAR(2000) NOT NULL,
+    `message_type`    INT NOT NULL DEFAULT 0,
+    `status`          TINYINT NOT NULL DEFAULT 0 COMMENT '0: Pending, 1: Acked',
+    `created_at`      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    `properties`      VARCHAR(2000),
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java (1)

22-22: Consider thread safety and configurability of ObjectMapper.

The static ObjectMapper instance may need configuration for specific JSON handling requirements and thread safety considerations.

Consider making the ObjectMapper configurable:

-    private static final ObjectMapper objectMapper = new ObjectMapper();
+    private static final ObjectMapper objectMapper = createObjectMapper();
+    
+    private static ObjectMapper createObjectMapper() {
+        ObjectMapper mapper = new ObjectMapper();
+        // Add any specific configuration here
+        return mapper;
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80d9e53 and 99a63f3.

📒 Files selected for processing (68)
  • README.md (1 hunks)
  • cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/FetchOfflineMsgJob.java (1 hunks)
  • cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java (2 hunks)
  • cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java (5 hunks)
  • cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandle.java (1 hunks)
  • cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java (7 hunks)
  • cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java (1 hunks)
  • cim-client-sdk/src/test/resources/application-route.yaml (2 hunks)
  • cim-client-sdk/src/test/resources/init.sql (1 hunks)
  • cim-client/src/main/resources/application.yaml (1 hunks)
  • cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java (1 hunks)
  • cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java (1 hunks)
  • cim-common/src/main/java/com/crossoverjie/cim/common/util/RandomUtil.java (0 hunks)
  • cim-common/src/main/java/com/crossoverjie/cim/common/util/SnowflakeIdWorker.java (1 hunks)
  • cim-common/src/main/proto/cim.proto (1 hunks)
  • cim-forward-route/pom.xml (2 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java (1 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java (2 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/MySqlPersistenceConfig.java (1 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/OfflineMsgStoreConfig.java (1 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java (1 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java (4 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/factory/OfflineMsgFactory.java (1 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java (2 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/OfflineMsgService.java (1 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java (2 hunks)
  • cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/OfflineMsgServiceImpl.java (1 hunks)
  • cim-forward-route/src/main/resources/application.yaml (2 hunks)
  • cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AbstractBaseTest.java (3 hunks)
  • cim-forward-route/src/test/resources/application.yaml (2 hunks)
  • cim-forward-route/src/test/resources/init.sql (1 hunks)
  • cim-integration-test/pom.xml (1 hunks)
  • cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/AbstractRouteBaseTest.java (1 hunks)
  • cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/OfflineMsgStoreRouteBaseTest.java (1 hunks)
  • cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/server/AbstractServerBaseTest.java (4 hunks)
  • cim-integration-test/src/test/resources/application-route.yaml (1 hunks)
  • cim-persistence/cim-persistence-api/pom.xml (1 hunks)
  • cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/config/BeanConfig.java (1 hunks)
  • cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsg.java (1 hunks)
  • cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsgLastSendRecord.java (1 hunks)
  • cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/service/OfflineMsgStore.java (1 hunks)
  • cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/vo/req/SaveOfflineMsgReqVO.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/pom.xml (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/config/MyBatisConfig.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/OfflineMsgDb.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgMapper.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgLastSendRecordMapper.xml (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgMapper.xml (1 hunks)
  • cim-persistence/cim-persistence-redis/pom.xml (1 hunks)
  • cim-persistence/cim-persistence-redis/src/main/java/com/crossoverjie/cim/persistence/redis/OfflineMsgBuffer.java (1 hunks)
  • cim-persistence/pom.xml (1 hunks)
  • cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java (2 hunks)
  • cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/OfflineMsgReqVO.java (1 hunks)
  • cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java (4 hunks)
  • cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/res/OfflineMsgResVO.java (1 hunks)
  • cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/res/SaveOfflineMsgResVO.java (1 hunks)
  • cim-server/pom.xml (0 hunks)
  • cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java (1 hunks)
  • cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java (1 hunks)
  • cim-server/src/main/resources/application.yaml (2 hunks)
  • docker/allin1-ubuntu.Dockerfile (1 hunks)
  • docker/wait-for-it.sh (1 hunks)
  • pom.xml (2 hunks)
  • sql/01schema.sql (1 hunks)
  • sql/offline_msg.sql (1 hunks)
  • sql/offline_msg_last_send_record.sql (1 hunks)
💤 Files with no reviewable changes (2)
  • cim-server/pom.xml
  • cim-common/src/main/java/com/crossoverjie/cim/common/util/RandomUtil.java
🧰 Additional context used
🧬 Code Graph Analysis (12)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java (1)
cim-common/src/main/java/com/crossoverjie/cim/common/util/SnowflakeIdWorker.java (1)
  • SnowflakeIdWorker (8-46)
cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/OfflineMsgReqVO.java (1)
cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/LoginReqVO.java (1)
  • AllArgsConstructor (13-41)
cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/OfflineMsgStoreRouteBaseTest.java (1)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java (2)
  • Constant (10-42)
  • OfflineStoreMode (29-39)
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsgLastSendRecord.java (1)
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsg.java (1)
  • Data (16-32)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/factory/OfflineMsgFactory.java (3)
cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java (2)
  • Constants (10-42)
  • MetaKey (24-29)
cim-common/src/main/java/com/crossoverjie/cim/common/exception/CIMException.java (1)
  • CIMException (13-71)
cim-common/src/main/java/com/crossoverjie/cim/common/util/SnowflakeIdWorker.java (1)
  • SnowflakeIdWorker (8-46)
cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java (1)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java (2)
  • Constant (10-42)
  • OfflineStoreMode (29-39)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/MySqlPersistenceConfig.java (1)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/OfflineMsgStoreConfig.java (1)
  • Configuration (17-31)
cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/config/BeanConfig.java (2)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java (1)
  • Slf4j (13-29)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java (1)
  • Configuration (39-143)
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/OfflineMsgDb.java (1)
cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java (1)
  • Constants (10-42)
cim-persistence/cim-persistence-redis/src/main/java/com/crossoverjie/cim/persistence/redis/OfflineMsgBuffer.java (3)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java (1)
  • Slf4j (13-29)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java (1)
  • Slf4j (43-180)
cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java (1)
  • Constants (10-42)
cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java (2)
cim-common/src/main/java/com/crossoverjie/cim/common/req/BaseRequest.java (1)
  • BaseRequest (12-51)
cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/P2PReqVO.java (1)
  • Builder (20-89)
cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java (3)
cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/OfflineMsgStoreRouteBaseTest.java (1)
  • OfflineMsgStoreRouteBaseTest (15-66)
cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java (2)
  • Constant (10-42)
  • OfflineStoreMode (29-39)
cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientState.java (1)
  • ClientState (5-23)
🪛 YAMLlint (1.37.1)
cim-server/src/main/resources/application.yaml

[warning] 36-36: too many blank lines

(2 > 0) (empty-lines)

cim-forward-route/src/test/resources/application.yaml

[error] 67-67: no new line character at the end of file

(new-line-at-end-of-file)

🪛 Shellcheck (0.10.0)
docker/wait-for-it.sh

[warning] 61-61: Use single quotes, otherwise this expands now rather than when signalled.

(SC2064)


[warning] 75-75: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.

(SC2206)


[error] 153-153: This redirection overrides the output pipe. Use 'tee' to output to both.

(SC2260)


[warning] 174-174: Expanding an array without an index only gives the first element.

(SC2128)

🔇 Additional comments (62)
cim-server/src/main/resources/application.yaml (2)

18-18: No-op formatting change
Single blank line added to separate sections; this is harmless and improves readability.


34-34: Whitespace normalization
Trailing whitespace (if any) on the cim.heartbeat.time line is removed, which is a harmless cleanup.

docker/allin1-ubuntu.Dockerfile (1)

28-29: Use local wait-for-it script for deterministic builds.

Replacing the remote ADD with a local COPY ensures the script version is controlled and the build is repeatable.

cim-integration-test/pom.xml (1)

76-81: Ensure version management for Testcontainers modules The new MySQL Testcontainers dependency omits a <version>. Verify that a BOM or the parent POM manages org.testcontainers:mysql; otherwise, explicitly specify a version to prevent resolution errors.

cim-common/src/main/proto/cim.proto (1)

26-26: LGTM! Clean enum addition.

The OFFLINE = 3 command addition follows protobuf best practices with sequential numbering and descriptive naming. This properly supports the offline messaging feature.

cim-client-sdk/src/test/resources/application-route.yaml (1)

51-53:

Details

✅ Verification successful

Configuration addition supports offline messaging feature well.

The offline.store.mode: redis configuration properly enables backend selection for offline message storage. This aligns with the system's modular persistence approach.

Verify configuration consistency across environments:


🏁 Script executed:

#!/bin/bash
# Description: Check offline storage mode configuration across different environments

# Find all application YAML files and check offline storage configuration
fd "application.*\.ya?ml$" --type f -x echo "=== {} ===" \; -x grep -A 2 -B 2 "offline" {}

# Check for any hardcoded storage mode references
rg -i "offline.*store.*mode" --type java

Length of output: 3367


Configuration consistency verified across environments

Production defaults to offline.store.mode: redis, and test configurations explicitly override this to exercise both Redis and MySQL backends. No further changes are needed.

cim-client/src/main/resources/application.yaml (1)

26-27: Verify updated user identity.
Ensure the new id and userName values are intentional and align with your test or production environment settings, as they will affect authentication and offline message fetching.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java (2)

7-7: Import of BaseCommand added.
The new import supports the additional cmd parameter in SendMsgReqVO and aligns with updated request handling.


158-158: Set explicit command type in SendMsgReqVO.
Using BaseCommand.MESSAGE as the final argument ensures the server correctly interprets the message command; this change is consistent with the updated VO signature.

pom.xml (2)

42-42: Add cim-persistence module.
Confirm that the new module directory exists and is correctly configured in the reactor build.


201-206: Include Testcontainers MySQL dependency.
Verify that version 1.19.7 of org.testcontainers:mysql aligns with other Testcontainers modules and works with your integration tests.

cim-forward-route/pom.xml (2)

26-42: Add offline persistence dependencies.
The cim-persistence-api, cim-persistence-mysql, and cim-persistence-redis dependencies are added with the project version—this aligns the route module with the new persistence layer.


98-102: Validate Testcontainers MySQL dependency.
Ensure that including the MySQL container in this module’s test scope is necessary and consistent with the integration test strategy.

cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/config/MyBatisConfig.java (1)

15-20:

Details

✅ Verification successful

LGTM! Verify MapToJsonTypeHandler dependency.

The MyBatis configuration correctly registers the custom type handler using ConfigurationCustomizer. This is the standard approach for integrating custom type handlers in MyBatis Spring Boot applications.

Verify that the MapToJsonTypeHandler class exists and is properly implemented:


🏁 Script executed:

#!/bin/bash
# Check if MapToJsonTypeHandler exists and examine its implementation
fd -t f "MapToJsonTypeHandler.java" | head -5
ast-grep --pattern 'class MapToJsonTypeHandler extends $_ {
  $$$
}'

Length of output: 238


🏁 Script executed:

#!/bin/bash
# Inspect MapToJsonTypeHandler class signature and imports
rg -n "class MapToJsonTypeHandler" -A5 cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java

# Show the first 50 lines to verify correct BaseTypeHandler usage
sed -n '1,50p' cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java

Length of output: 2310


LGTM – Custom Type Handler Verified

The MapToJsonTypeHandler class exists at
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java
and correctly extends BaseTypeHandler<Map<String, String>>, serializing/deserializing via Jackson. The MyBatis ConfigurationCustomizer registration is appropriate and no further changes are needed.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/constant/Constant.java (1)

29-40: LGTM! Well-structured constant definitions.

The nested static class provides good namespace organization for offline store mode constants. The implementation follows Java constant naming conventions and provides clear documentation.

cim-persistence/cim-persistence-redis/pom.xml (3)

5-9: Parent POM inheritance is correctly configured.
Child modules will inherit groupId/artifactId/version from cim-persistence.


16-21: Redis persistence module correctly depends on the API.
Transitive inclusion of spring-boot-starter-data-redis via the API makes Redis client available here.


30-39: Spring Boot plugin configuration is appropriate.
Skipping Spring Boot packaging is correct for a library module.

cim-persistence/cim-persistence-mysql/pom.xml (3)

5-9: Parent POM reference is correct.
Module will inherit version and group coordinates from cim-persistence.


18-28: Dependencies are well-defined.
Includes MyBatis starter, MySQL Connector/J, and the API module.


38-46: Build plugin skip configuration is appropriate.
Skipping Spring Boot packaging for this library module is intentional.

cim-persistence/cim-persistence-api/pom.xml (3)

5-9: Parent POM inheritance is correct.
Aligns this API module under the cim-persistence aggregator.


18-21: Core Redis dependency is declared without version, leveraging Spring Boot’s dependency management.
This ensures compatibility with the parent’s Spring Boot BOM.


28-33: Spring Boot plugin skip is set correctly.
This is a library POM, skipping the Spring Boot repackage goal is desired.

cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java (3)

19-19: LGTM - Import added for offline store mode constants.

The import is properly used throughout the test file to specify the Redis offline store mode.


39-39: Excellent consistency in offline store mode configuration.

All test methods now consistently use Constant.OfflineStoreMode.REDIS when starting the route server, ensuring uniform test environment configuration across different test scenarios.

Also applies to: 114-114, 245-245, 331-331, 411-411, 441-441


107-108: Good practice - Explicit client resource cleanup.

The addition of explicit client.close() calls after stopping servers ensures proper resource cleanup and prevents potential resource leaks in tests. This improves test isolation and reliability.

Also applies to: 227-229, 324-325, 404-405

cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/server/AbstractServerBaseTest.java (2)

10-10: LGTM - Import added for DataSource exclusion.

The import is properly used in the server startup arguments.


34-38: Appropriate DataSource auto-configuration exclusion for tests.

Excluding DataSourceAutoConfiguration during server startup prevents unwanted database auto-configuration in integration tests, allowing for better control over test environment setup. The exclusion is consistently applied across all server startup scenarios.

Also applies to: 55-56, 66-67

cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/AbstractRouteBaseTest.java (2)

20-20: Appropriate visibility change for inheritance.

Changing the run field from private to protected allows subclasses to access the ApplicationContext, which is reasonable for extensible test base classes.


21-21: Well-designed parameterization for offline storage modes.

The modified startRoute(String offlineModel) method enables flexible testing of different offline storage backends (Redis/MySQL) by accepting the mode as a parameter and properly passing it to the Spring application arguments.

Also applies to: 28-28

cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/OfflineMsgReqVO.java (1)

19-25: LGTM! Clean and well-structured request VO.

The implementation follows established patterns, uses appropriate validation, and has clear Swagger documentation. The single-purpose design is appropriate for fetching offline messages.

cim-forward-route/src/main/resources/application.yaml (1)

57-68: LGTM! Configuration properly supports the offline messaging feature.

The MyBatis configuration enables proper ORM mapping, and the offline store mode configuration allows flexible switching between Redis and MySQL storage backends.

cim-persistence/pom.xml (1)

1-52: LGTM! Well-structured Maven module configuration.

The POM follows Maven best practices with proper parent-child relationships, clear module separation (API, MySQL, Redis), and appropriate dependencies for a persistence layer.

cim-persistence/cim-persistence-api/src/main/java/com/crossoverjie/cim/persistence/api/pojo/OfflineMsg.java (1)

20-31: LGTM! Well-designed entity with good extensibility.

The entity design appropriately captures all necessary offline message data with proper field types and extensible properties support.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/OfflineMsgService.java (1)

9-23: LGTM! Clean service interface design.

The interface properly abstracts offline message operations with appropriate method signatures and clear responsibilities.

cim-forward-route/src/test/resources/application.yaml (2)

15-19: LGTM! Secure configuration practices.

The datasource configuration follows security best practices by using an environment variable for the password and includes proper URL parameters for timezone and encoding.


56-63: LGTM! Standard MyBatis configuration.

The MyBatis configuration is properly set up with camel case conversion and appropriate package scanning.

cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java (1)

36-40: LGTM! Well-organized error codes for offline messaging.

The new offline message error constants follow the existing patterns with logical error code grouping (92xx range) and descriptive messages.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java (1)

14-18: LGTM! Proper configuration for conditional persistence.

The exclusion of DataSourceAutoConfiguration and explicit component scanning for persistence packages correctly supports the new offline message storage functionality with conditional MySQL/Redis configuration.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/MySqlPersistenceConfig.java (1)

14-20: LGTM! Configuration properly implements conditional MySQL persistence.

The configuration correctly uses @ConditionalOnProperty to activate MySQL persistence only when needed, properly scans the mapper package, and imports the necessary auto-configuration.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java (1)

63-67: LGTM! Clean dependency injection.

The new service dependencies are properly injected using Spring's @Resource annotation, following the existing pattern in the controller.

cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AbstractBaseTest.java (4)

10-10: LGTM: Proper imports for MySQL test container support.

The additional imports for MySQLContainer and MountableFile are correctly added to support the new MySQL test infrastructure.

Also applies to: 13-13


30-40: LGTM: Well-configured MySQL test container.

The MySQL container configuration is comprehensive and follows best practices:

  • Uses a specific, stable MySQL version (8.0.33)
  • Properly configures database credentials
  • Mounts the initialization script for schema setup
  • Enables container reuse for performance

53-59: LGTM: Dynamic Spring datasource configuration.

The dynamic system property setting for Spring datasource configuration is a clean approach for test integration. This allows the application to connect to the test MySQL container without hardcoded configuration.


66-66: LGTM: Proper container cleanup.

The MySQL container is correctly stopped in the cleanup method, ensuring proper test resource management.

cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java (1)

139-139: LGTM: Proper client cleanup verification.

The assertion ensuring all clients are properly cleaned up from the client map is a good practice for preventing test interference.

cim-client-sdk/src/test/resources/init.sql (1)

28-34: LGTM: Well-designed tracking table.

The offline_msg_last_send_record table design is appropriate for tracking the last sent message per user. The primary key on receive_user_id ensures efficient lookups and prevents duplicate records.

cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/OfflineMsgDb.java (2)

17-25: LGTM! Clean implementation following dependency injection pattern.

The constructor injection approach and interface implementation are well-structured.


27-35: LGTM! Methods delegate appropriately to mappers.

The save and fetch methods correctly delegate to the respective mappers with proper parameter passing.

cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java (5)

3-3: LGTM! Appropriate import for BaseCommand.

The import correctly brings in the BaseCommand enum/class needed for the cmd field.


12-13: LGTM! Proper Lombok annotations added.

The @Builder and @AllArgsConstructor annotations provide convenient object construction patterns.


38-43: LGTM! Clean field definition with Lombok getter.

The userId field now uses Lombok @Getter annotation and the new cmd field follows the same pattern with proper schema annotation.


52-57: LGTM! Constructor updated to match new field.

The constructor correctly includes the new cmd parameter and initializes the field appropriately.


74-74: LGTM! toString method includes new cmd field.

The toString method is properly updated to include the cmd field in the output.

cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/OfflineMsgServiceImpl.java (3)

1-24: LGTM! Clean imports and modern Jakarta EE usage.

The package structure and imports are well-organized, using modern Jakarta annotations.


25-39: LGTM! Proper Spring service structure with appropriate dependency injection.

The class follows Spring best practices with clean dependency injection using @resource annotations.


69-86: LGTM! Well-structured method with proper null handling.

The method follows good practices with Optional usage, factory pattern for entity creation, and appropriate metadata handling.

cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgMapper.xml (4)

1-4: LGTM! Standard MyBatis mapper structure.

Proper XML header and namespace declaration for the MyBatis mapper.


5-43: LGTM! Efficient insert operations with proper type handling.

Both single and batch insert operations are well-implemented with appropriate use of custom type handlers for JSON properties.


45-59: LGTM! Well-designed cursor-based pagination query.

The query properly implements cursor-based pagination with appropriate filtering for undelivered messages (status=0) and handles null cursor values with COALESCE.


70-81: LGTM! Flexible update operation with conditional filtering.

The status update operation is well-implemented with optional message ID filtering, allowing for both bulk and selective updates.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java (1)

46-48: 🛠️ Refactor suggestion

Apply consistent error reporting to the get method.

The get method still uses the old generic error message format, which is inconsistent with the improved error reporting in the post method. Apply the same enhancement for consistency.

-        if (!response.isSuccessful()) {
-            throw new IOException("Unexpected code " + response);
-        }
+        if (!response.isSuccessful()) {
+            throw new IOException("request url [" + url + "] failed, response code: " + response.code()
+                    + ", message: " + response.message());
+        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1466d1c and d286d66.

📒 Files selected for processing (2)
  • cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java (1 hunks)
  • cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/OfflineMsgTest.java

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgLastSendRecordMapper.xml (1)

5-13: Verify unique index exists for optimal performance.

The INSERT...ON DUPLICATE KEY UPDATE statement requires a unique index on receive_user_id for correct functionality and optimal performance.

#!/bin/bash
# Check for database schema or migration files that create the required index
fd -e sql | xargs grep -l "offline_msg_last_send_record" | head -5
🧹 Nitpick comments (2)
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java (2)

9-10: Empty JavaDoc description should be completed or removed.

The @description tag is empty. Either provide a meaningful description of this mapper's purpose or remove the empty tag.

 /**
  * @author zhongcanyu
  * @date 2025/5/10
- * @description
+ * @description Mapper for managing offline message last send records to track message delivery status
  */

14-14: Add space after comma in parameter list for better readability.

Missing space between parameters affects code readability.

-    void saveLatestMessageId(@Param("receiveUserId") Long receiveUserId,@Param("lastMessageId") Long lastMessageId);
+    void saveLatestMessageId(@Param("receiveUserId") Long receiveUserId, @Param("lastMessageId") Long lastMessageId);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d286d66 and cc804bd.

📒 Files selected for processing (4)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java (1 hunks)
  • cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgLastSendRecordMapper.xml (1 hunks)
  • cim-persistence/cim-persistence-redis/src/main/java/com/crossoverjie/cim/persistence/redis/OfflineMsgBuffer.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/util/MapToJsonTypeHandler.java
  • cim-persistence/cim-persistence-redis/src/main/java/com/crossoverjie/cim/persistence/redis/OfflineMsgBuffer.java
🔇 Additional comments (2)
cim-persistence/cim-persistence-mysql/src/main/java/com/crossoverjie/cim/persistence/mysql/offlinemsg/mapper/OfflineMsgLastSendRecordMapper.java (1)

12-16:

Details

❌ Incorrect review comment

Consider consolidating with existing offline message mappers.

Given the previous question about whether this function can be deleted, evaluate if this separate mapper is necessary or if the functionality could be consolidated into the main OfflineMsgMapper to reduce complexity.


🏁 Script executed:

#!/bin/bash
# Check if there are other offline message mappers that could accommodate this functionality
fd -e java -e xml | grep -i "offlinemsg.*mapper" | head -10

Length of output: 521


🏁 Script executed:

#!/bin/bash
# Show the contents of the LastSendRecord mapper XML
sed -n '1,200p' cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgLastSendRecordMapper.xml
echo "----"
# Show the contents of the main OfflineMsg mapper XML
sed -n '1,200p' cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgMapper.xml

Length of output: 3896


Separate mappers are intentional and should be kept as is

The two mappers target distinct tables—offline_msg vs. offline_msg_last_send_record—and contain no overlapping SQL. Consolidating them would blur table-level responsibilities and reduce clarity. Keeping one mapper per table aligns with the Single Responsibility Principle.

Likely an incorrect or invalid review comment.

cim-persistence/cim-persistence-mysql/src/main/resources/mapper/OfflineMsgLastSendRecordMapper.xml (1)

5-13: LGTM: Well-structured upsert operation.

The INSERT...ON DUPLICATE KEY UPDATE implementation correctly handles both insert and update scenarios with proper timestamp management using NOW().

Copy link
Owner

@crossoverJie crossoverJie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@crossoverJie
Copy link
Owner

Thank you for your contribution.

@crossoverJie crossoverJie merged commit 2188718 into crossoverJie:master Jun 6, 2025
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new features new features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants